diff --git a/kiloclaw/controller/src/config-writer.test.ts b/kiloclaw/controller/src/config-writer.test.ts index ab1d43fc8..e36702e26 100644 --- a/kiloclaw/controller/src/config-writer.test.ts +++ b/kiloclaw/controller/src/config-writer.test.ts @@ -144,6 +144,38 @@ describe('generateBaseConfig', () => { expect(config.tools.profile).toBe('full'); }); + it('sets session.dmScope to main on fresh install', () => { + const { deps } = fakeDeps(); + const env = { ...minimalEnv(), KILOCLAW_FRESH_INSTALL: 'true' }; + const config = generateBaseConfig(env, '/tmp/openclaw.json', deps); + + expect(config.session.dmScope).toBe('main'); + }); + + it('does not set session.dmScope on non-fresh boot', () => { + const { deps } = fakeDeps(); + const config = generateBaseConfig(minimalEnv(), '/tmp/openclaw.json', deps); + + expect(config.session?.dmScope).toBeUndefined(); + }); + + it('preserves user session.dmScope on non-fresh boot', () => { + const existing = JSON.stringify({ session: { dmScope: 'custom' } }); + const { deps } = fakeDeps(existing); + const config = generateBaseConfig(minimalEnv(), '/tmp/openclaw.json', deps); + + expect(config.session.dmScope).toBe('custom'); + }); + + it('overrides session.dmScope to main on fresh install even if previously set', () => { + const existing = JSON.stringify({ session: { dmScope: 'custom' } }); + const { deps } = fakeDeps(existing); + const env = { ...minimalEnv(), KILOCLAW_FRESH_INSTALL: 'true' }; + const config = generateBaseConfig(env, '/tmp/openclaw.json', deps); + + expect(config.session.dmScope).toBe('main'); + }); + it('preserves existing config keys not touched by the patch', () => { const existing = JSON.stringify({ custom: { key: 'value' }, gateway: { extra: true } }); const { deps } = fakeDeps(existing); diff --git a/kiloclaw/controller/src/config-writer.ts b/kiloclaw/controller/src/config-writer.ts index 5f8d3aaa3..3db60ff13 100644 --- a/kiloclaw/controller/src/config-writer.ts +++ b/kiloclaw/controller/src/config-writer.ts @@ -204,6 +204,13 @@ export function generateBaseConfig( config.tools.profile = 'full'; } + // Session DM scope: on fresh install, default to 'main' so DMs are routed + // to the main session. On subsequent boots, leave the user's choice untouched. + if (env.KILOCLAW_FRESH_INSTALL === 'true') { + config.session = config.session ?? {}; + config.session.dmScope = 'main'; + } + // Exec: KiloClaw machines have no Docker sandbox, so exec must target the // gateway host directly. Security and ask are user-configurable via the // provisioning preset, persisted in DO state and transported as env vars.