( env: EnvLike, configPath = DEFAULT_CONFIG_PATH, deps: ConfigWriterDeps = defaultDeps )
| 862 | // Only seed allowFrom on first boot so user edits are preserved. |
| 863 | if (!('allowFrom' in config.channels.discord.dm)) { |
| 864 | config.channels.discord.dm.allowFrom = dmPolicy === 'open' ? ['*'] : []; |
| 865 | } |
| 866 | |
| 867 | config.plugins = config.plugins ?? {}; |
| 868 | config.plugins.entries = config.plugins.entries ?? {}; |
| 869 | config.plugins.entries.discord = config.plugins.entries.discord ?? {}; |
| 870 | config.plugins.entries.discord.enabled = true; |
| 871 | } |
| 872 | |
| 873 | // Slack |
| 874 | if (env.SLACK_BOT_TOKEN && env.SLACK_APP_TOKEN) { |
| 875 | config.channels.slack = config.channels.slack ?? {}; |
| 876 | config.channels.slack.botToken = env.SLACK_BOT_TOKEN; |
| 877 | config.channels.slack.appToken = env.SLACK_APP_TOKEN; |
| 878 | config.channels.slack.enabled = true; |
| 879 | |
| 880 | config.plugins = config.plugins ?? {}; |
| 881 | config.plugins.entries = config.plugins.entries ?? {}; |
| 882 | config.plugins.entries.slack = config.plugins.entries.slack ?? {}; |
| 883 | config.plugins.entries.slack.enabled = true; |
| 884 | } |
| 885 | |
| 886 | // Composio Connect — a remote MCP server operated by Composio. Nothing is |
| 887 | // installed in the container: OpenClaw dials the URL over streamable HTTP |
| 888 | // and forwards the consumer key as a header, so the whole integration is |
| 889 | // this config block. Toolkit connections (Gmail, Calendar, ...) are made by |
| 890 | // the user in the Composio dashboard and never touch KiloClaw. |
| 891 | applyComposioConnectConfig(config, env.COMPOSIO_CONSUMER_KEY); |
| 892 | |
| 893 | // Session — default DM scope to per-channel-peer so each channel+peer |
| 894 | // combination gets its own session. OpenClaw's onboard sets this for new |
| 895 | // instances, but legacy instances may not have it. |
| 896 | config.session = config.session ?? {}; |
| 897 | config.session.dmScope = config.session.dmScope ?? 'per-channel-peer'; |
| 898 | |
| 899 | // Kilo Chat — always enabled. The plugin's outbound path reaches |
| 900 | // kilo-chat via controller proxy → kilo-chat Worker directly. |
| 901 | config.channels['kilo-chat'] = config.channels['kilo-chat'] ?? {}; |
| 902 | config.channels['kilo-chat'].enabled = true; |
| 903 | // Load-bearing: _configured is the marker key for OpenClaw's |
| 904 | // hasMeaningfulChannelConfig gate — without a non-`enabled` key the |
| 905 | // plugin loads in setup-runtime mode instead of full. |
| 906 | config.channels['kilo-chat']._configured = true; |
| 907 | |
| 908 | config.plugins = config.plugins ?? {}; |
| 909 | config.plugins.load = config.plugins.load ?? {}; |
| 910 | config.plugins.load.paths = Array.isArray(config.plugins.load.paths) |
| 911 | ? config.plugins.load.paths |
| 912 | : []; |
| 913 | if (!(config.plugins.load.paths as string[]).includes(KILO_CHAT_PLUGIN_PATH)) { |
| 914 | (config.plugins.load.paths as string[]).push(KILO_CHAT_PLUGIN_PATH); |
| 915 | } |
| 916 | if (Array.isArray(config.plugins.allow) && !config.plugins.allow.includes(KILO_CHAT_PLUGIN_ID)) { |
| 917 | config.plugins.allow.push(KILO_CHAT_PLUGIN_ID); |
| 918 | } |
| 919 | |
| 920 | config.plugins.entries = config.plugins.entries ?? {}; |
| 921 | config.plugins.entries[KILO_CHAT_PLUGIN_ID] = config.plugins.entries[KILO_CHAT_PLUGIN_ID] ?? {}; |
no test coverage detected