Skip to content

Commit f8787f7

Browse files
authored
Merge branch 'main' into session/agent_47b6a9f5-5868-4d11-8937-7643a3cdcebc
2 parents 3552dea + b6ca683 commit f8787f7

File tree

37 files changed

+18413
-34
lines changed

37 files changed

+18413
-34
lines changed

kiloclaw/.dev.vars.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,7 @@ NEXT_PUBLIC_POSTHOG_KEY=phc_GK2Pxl0HPj5ZPfwhLRjXrtdz8eD7e9MKnXiFrOqnB6z
7676
# In wrangler dev, it connects to the remote Postgres via the Hyperdrive service.
7777
# To use a local Postgres instead, add "localConnectionString" to the hyperdrive
7878
# config in wrangler.jsonc (see https://developers.cloudflare.com/hyperdrive/configuration/local-development/).
79+
80+
# StreamChat API Key
81+
STREAM_CHAT_API_KEY=...
82+
STREAM_CHAT_API_SECRET=...

kiloclaw/AGENTS.md

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -229,27 +229,31 @@ User config is transported to the machine via environment variables set in the F
229229

230230
**Encrypted (stored as `KILOCLAW_ENC_{name}`, decrypted to `{name}` at boot):**
231231

232-
| Env var (after decrypt) | Source | Purpose |
233-
| ------------------------ | ---------------------------- | --------------------------- |
234-
| `KILOCODE_API_KEY` | User config (DO) | KiloCode API authentication |
235-
| `OPENCLAW_GATEWAY_TOKEN` | Derived from sandboxId | Per-user gateway auth |
236-
| `TELEGRAM_BOT_TOKEN` | Decrypted channel token | Telegram channel |
237-
| `DISCORD_BOT_TOKEN` | Decrypted channel token | Discord channel |
238-
| `SLACK_BOT_TOKEN` | Decrypted channel token | Slack channel |
239-
| `SLACK_APP_TOKEN` | Decrypted channel token | Slack channel |
240-
| User encrypted secrets | Decrypted from RSA envelopes | User-provided credentials |
232+
| Env var (after decrypt) | Source | Purpose |
233+
| ---------------------------- | --------------------------------- | ------------------------------ |
234+
| `KILOCODE_API_KEY` | User config (DO) | KiloCode API authentication |
235+
| `OPENCLAW_GATEWAY_TOKEN` | Derived from sandboxId | Per-user gateway auth |
236+
| `TELEGRAM_BOT_TOKEN` | Decrypted channel token | Telegram channel |
237+
| `DISCORD_BOT_TOKEN` | Decrypted channel token | Discord channel |
238+
| `SLACK_BOT_TOKEN` | Decrypted channel token | Slack channel |
239+
| `SLACK_APP_TOKEN` | Decrypted channel token | Slack channel |
240+
| `STREAM_CHAT_BOT_USER_TOKEN` | Auto-provisioned (Stream Chat DO) | Stream Chat bot authentication |
241+
| User encrypted secrets | Decrypted from RSA envelopes | User-provided credentials |
241242

242243
**Plaintext (stored as-is in config.env):**
243244

244-
| Env var | Source | Purpose |
245-
| -------------------------- | --------------------------------- | ------------------------------------ |
246-
| `KILOCODE_DEFAULT_MODEL` | User config (DO) | Default model for agents |
247-
| `KILOCODE_MODELS_JSON` | User config (DO), JSON-serialized | Available model list |
248-
| `KILOCODE_API_BASE_URL` | Worker env | API base URL override |
249-
| `AUTO_APPROVE_DEVICES` | Hardcoded `true` | Skip device pairing |
250-
| `TELEGRAM_DM_POLICY` | Worker env | Telegram DM policy |
251-
| `DISCORD_DM_POLICY` | Worker env | Discord DM policy |
252-
| `OPENCLAW_ALLOWED_ORIGINS` | Worker env | Control UI WebSocket allowed origins |
245+
| Env var | Source | Purpose |
246+
| -------------------------------- | --------------------------------- | ------------------------------------ |
247+
| `KILOCODE_DEFAULT_MODEL` | User config (DO) | Default model for agents |
248+
| `KILOCODE_MODELS_JSON` | User config (DO), JSON-serialized | Available model list |
249+
| `KILOCODE_API_BASE_URL` | Worker env | API base URL override |
250+
| `AUTO_APPROVE_DEVICES` | Hardcoded `true` | Skip device pairing |
251+
| `TELEGRAM_DM_POLICY` | Worker env | Telegram DM policy |
252+
| `DISCORD_DM_POLICY` | Worker env | Discord DM policy |
253+
| `OPENCLAW_ALLOWED_ORIGINS` | Worker env | Control UI WebSocket allowed origins |
254+
| `STREAM_CHAT_API_KEY` | Auto-provisioned (Stream Chat DO) | Stream Chat app key |
255+
| `STREAM_CHAT_BOT_USER_ID` | Auto-provisioned (Stream Chat DO) | Per-user bot identifier |
256+
| `STREAM_CHAT_DEFAULT_CHANNEL_ID` | Auto-provisioned (Stream Chat DO) | Default channel ID for the user |
253257

254258
### AI Provider Selection
255259

kiloclaw/Dockerfile

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,10 +54,12 @@ RUN npm install -g mcporter@0.7.3
5454
# Install summarize (web page summarization CLI)
5555
RUN npm install -g @steipete/summarize@0.12.0
5656

57+
# Install Stream Chat channel plugin for OpenClaw (installed from GitHub, not npm)
58+
RUN npm install -g github:Kilo-Org/openclaw-channel-streamchat#catrielmuller/attach-support
59+
5760
# Install Kilo CLI (agentic coding assistant for the terminal)
5861
RUN npm install -g @kilocode/cli@7.0.46
5962

60-
6163
# Install Go (available at runtime for users to `go install` additional tools)
6264
ENV GO_VERSION=1.26.0
6365
RUN ARCH="$(dpkg --print-architecture)" \

kiloclaw/Dockerfile.local

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ RUN apt-get update \
3030
&& curl -fsSL https://downloads.1password.com/linux/keys/1password.asc \
3131
| gpg --dearmor --output /usr/share/debsig/keyrings/AC2D62742012EA22/debsig.gpg \
3232
&& apt-get update \
33-
&& apt-get install -y --no-install-recommends gh 1password-cli=2.32.1-1 \
33+
&& apt-get install -y --no-install-recommends gh 1password-cli=2.33.0-1 \
3434
&& apt-get purge -y xz-utils \
3535
&& apt-get autoremove -y \
3636
&& rm -rf /var/lib/apt/lists/* \
@@ -49,14 +49,17 @@ RUN npm install -g /tmp/openclaw.tgz \
4949
# Install ClawHub CLI
5050
RUN npm install -g clawhub
5151

52-
# Install QMD
53-
RUN npm install -g @tobilu/qmd
54-
5552
# Install mcporter (MCP server tooling)
5653
RUN npm install -g mcporter@0.7.3
5754

5855
# Install summarize (web page summarization CLI)
59-
RUN npm install -g @steipete/summarize@0.11.1
56+
RUN npm install -g @steipete/summarize@0.12.0
57+
58+
# Install Stream Chat channel plugin for OpenClaw (installed from GitHub, not npm)
59+
RUN npm install -g github:Kilo-Org/openclaw-channel-streamchat#catrielmuller/attach-support
60+
61+
# Install Kilo CLI (agentic coding assistant for the terminal)
62+
RUN npm install -g @kilocode/cli@7.0.46
6063

6164
# Install Go (available at runtime for users to `go install` additional tools)
6265
ENV GO_VERSION=1.26.0
@@ -73,7 +76,7 @@ RUN ARCH="$(dpkg --print-architecture)" \
7376
# so user-installed tools persist across restarts and are included in snapshots.
7477
# - npm/Node (installed to /usr/local) and apt packages (/usr/bin) are unaffected.
7578
ENV PATH="/usr/local/go/bin:/root/go/bin:$PATH"
76-
RUN GOBIN=/usr/local/bin go install github.com/steipete/gogcli/cmd/gog@v0.11.0 \
79+
RUN GOBIN=/usr/local/bin go install github.com/steipete/gogcli/cmd/gog@v0.12.0 \
7780
&& GOBIN=/usr/local/bin go install github.com/steipete/goplaces/cmd/goplaces@v0.3.0 \
7881
&& GOBIN=/usr/local/bin go install github.com/Hyaxia/blogwatcher/cmd/blogwatcher@v0.0.2 \
7982
&& GOBIN=/usr/local/bin go install github.com/xdevplatform/xurl@v1.0.3 \
@@ -111,7 +114,7 @@ RUN mkdir -p /root/.openclaw \
111114

112115
# Copy helper scripts (used at runtime by the controller/gateway)
113116
# Build cache bust: 2026-03-17-v65-remove-startup-script
114-
RUN echo "9"
117+
RUN echo "10"
115118
COPY openclaw-pairing-list.js /usr/local/bin/openclaw-pairing-list.js
116119
COPY openclaw-device-pairing-list.js /usr/local/bin/openclaw-device-pairing-list.js
117120

@@ -126,4 +129,6 @@ COPY container/TOOLS.md /usr/local/share/kiloclaw/TOOLS.md
126129
EXPOSE 18789
127130

128131
# Entrypoint: start the KiloClaw controller daemon directly.
132+
# All bootstrap logic (env decryption, onboard/doctor, config patching,
133+
# feature flags) lives in the controller's bootstrap module — no shell wrapper needed.
129134
CMD ["node", "/usr/local/bin/kiloclaw-controller.js"]

kiloclaw/controller/src/config-writer.test.ts

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,68 @@ describe('generateBaseConfig', () => {
437437
expect(config.channels.slack).toBeUndefined();
438438
});
439439

440+
// ─── Stream Chat (default channel) ───────────────────────────────────────
441+
442+
it('configures Stream Chat channel and plugin when all three vars are set', () => {
443+
const { deps } = fakeDeps();
444+
const env = {
445+
...minimalEnv(),
446+
STREAM_CHAT_API_KEY: 'sc-api-key',
447+
STREAM_CHAT_BOT_USER_ID: 'bot-sandbox-abc',
448+
STREAM_CHAT_BOT_USER_TOKEN: 'sc-bot-token',
449+
};
450+
const config = generateBaseConfig(env, '/tmp/openclaw.json', deps);
451+
452+
expect(config.channels.streamchat.apiKey).toBe('sc-api-key');
453+
expect(config.channels.streamchat.botUserId).toBe('bot-sandbox-abc');
454+
expect(config.channels.streamchat.botUserToken).toBe('sc-bot-token');
455+
expect(config.channels.streamchat.botUserName).toBe('KiloClaw');
456+
expect(config.channels.streamchat.enabled).toBe(true);
457+
expect(config.plugins.entries.streamchat.enabled).toBe(true);
458+
expect(config.plugins.load.paths).toContain(
459+
'/usr/local/lib/node_modules/@wunderchat/openclaw-channel-streamchat'
460+
);
461+
});
462+
463+
it('does not configure Stream Chat when any of the three required vars is missing', () => {
464+
const cases = [
465+
{ STREAM_CHAT_API_KEY: 'key', STREAM_CHAT_BOT_USER_ID: 'bot' },
466+
{ STREAM_CHAT_API_KEY: 'key', STREAM_CHAT_BOT_USER_TOKEN: 'token' },
467+
{ STREAM_CHAT_BOT_USER_ID: 'bot', STREAM_CHAT_BOT_USER_TOKEN: 'token' },
468+
];
469+
470+
for (const partial of cases) {
471+
const { deps } = fakeDeps();
472+
const env = { ...minimalEnv(), ...partial };
473+
const config = generateBaseConfig(env, '/tmp/openclaw.json', deps);
474+
expect(config.channels.streamchat).toBeUndefined();
475+
}
476+
});
477+
478+
it('does not duplicate the plugin path on repeated generateBaseConfig calls', () => {
479+
const existing = JSON.stringify({
480+
channels: { streamchat: { apiKey: 'old-key', enabled: true } },
481+
plugins: {
482+
load: {
483+
paths: ['/usr/local/lib/node_modules/@wunderchat/openclaw-channel-streamchat'],
484+
},
485+
entries: { streamchat: { enabled: true } },
486+
},
487+
});
488+
const { deps } = fakeDeps(existing);
489+
const env = {
490+
...minimalEnv(),
491+
STREAM_CHAT_API_KEY: 'sc-api-key',
492+
STREAM_CHAT_BOT_USER_ID: 'bot-sandbox-abc',
493+
STREAM_CHAT_BOT_USER_TOKEN: 'sc-bot-token',
494+
};
495+
const config = generateBaseConfig(env, '/tmp/openclaw.json', deps);
496+
497+
const pluginPath = '/usr/local/lib/node_modules/@wunderchat/openclaw-channel-streamchat';
498+
const paths = config.plugins.load.paths as string[];
499+
expect(paths.filter(p => p === pluginPath)).toHaveLength(1);
500+
});
501+
440502
it('does not set gateway auth when OPENCLAW_GATEWAY_TOKEN is missing', () => {
441503
const { deps } = fakeDeps();
442504
const env = { ...minimalEnv() };

kiloclaw/controller/src/config-writer.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,30 @@ export function generateBaseConfig(
279279
config.plugins.entries.slack.enabled = true;
280280
}
281281

282+
// Stream Chat default channel (auto-provisioned at provision time)
283+
if (env.STREAM_CHAT_API_KEY && env.STREAM_CHAT_BOT_USER_ID && env.STREAM_CHAT_BOT_USER_TOKEN) {
284+
config.channels.streamchat = config.channels.streamchat ?? {};
285+
config.channels.streamchat.apiKey = env.STREAM_CHAT_API_KEY;
286+
config.channels.streamchat.botUserId = env.STREAM_CHAT_BOT_USER_ID;
287+
config.channels.streamchat.botUserToken = env.STREAM_CHAT_BOT_USER_TOKEN;
288+
config.channels.streamchat.botUserName = 'KiloClaw';
289+
config.channels.streamchat.enabled = true;
290+
291+
config.plugins = config.plugins ?? {};
292+
config.plugins.load = config.plugins.load ?? {};
293+
config.plugins.load.paths = Array.isArray(config.plugins.load.paths)
294+
? config.plugins.load.paths
295+
: [];
296+
const pluginPath = '/usr/local/lib/node_modules/@wunderchat/openclaw-channel-streamchat';
297+
if (!(config.plugins.load.paths as string[]).includes(pluginPath)) {
298+
(config.plugins.load.paths as string[]).push(pluginPath);
299+
}
300+
301+
config.plugins.entries = config.plugins.entries ?? {};
302+
config.plugins.entries.streamchat = config.plugins.entries.streamchat ?? {};
303+
config.plugins.entries.streamchat.enabled = true;
304+
}
305+
282306
// Webhook hooks configuration (required for Gmail push notifications via gog).
283307
// hooks.token authenticates incoming hook requests from gog's --hook-token.
284308
// The gmail preset maps gog's gmailHookPayload into OpenClaw's expected format.

0 commit comments

Comments
 (0)