kimaki 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/bot.d.ts +3 -5
  2. package/dist/bot.js +3 -9
  3. package/dist/bot.js.map +1 -1
  4. package/dist/builtin-skills.d.ts +3 -0
  5. package/dist/builtin-skills.js +29 -0
  6. package/dist/builtin-skills.js.map +1 -1
  7. package/dist/builtin-skills.test.js +73 -1
  8. package/dist/builtin-skills.test.js.map +1 -1
  9. package/dist/cli/bot.d.ts +1 -1
  10. package/dist/cli/bot.js +8 -4
  11. package/dist/cli/bot.js.map +1 -1
  12. package/dist/cli-lock.e2e.test.js +1 -1
  13. package/dist/event-loop.d.ts +1 -2
  14. package/dist/event-loop.js +2 -2
  15. package/dist/event-loop.js.map +1 -1
  16. package/dist/main.d.ts +2 -1
  17. package/dist/main.js +2 -2
  18. package/dist/main.js.map +1 -1
  19. package/dist/markdown/markdown.test.js +10 -0
  20. package/dist/markdown/markdown.test.js.map +1 -1
  21. package/dist/markdown/render-markdown.js +3 -1
  22. package/dist/markdown/render-markdown.js.map +1 -1
  23. package/dist/plugin/index.js +17 -44
  24. package/dist/plugin/index.js.map +1 -1
  25. package/dist/session-events.js +9 -5
  26. package/dist/session-events.js.map +1 -1
  27. package/dist/sessions.js +4 -3
  28. package/dist/sessions.js.map +1 -1
  29. package/dist/system-prompt.d.ts +3 -15
  30. package/dist/system-prompt.js +52 -77
  31. package/dist/system-prompt.js.map +1 -1
  32. package/dist/test/harness.d.ts +1 -2
  33. package/dist/test/harness.js +1 -2
  34. package/dist/test/harness.js.map +1 -1
  35. package/dist/test/replay.js +0 -1
  36. package/dist/test/replay.js.map +1 -1
  37. package/dist/thread-reducer.d.ts +0 -3
  38. package/dist/thread-reducer.fixtures.test.js +2 -2
  39. package/dist/thread-reducer.fixtures.test.js.map +1 -1
  40. package/dist/thread-reducer.js +4 -32
  41. package/dist/thread-reducer.js.map +1 -1
  42. package/dist/thread-reducer.test.js +0 -31
  43. package/dist/thread-reducer.test.js.map +1 -1
  44. package/dist/tunnel.d.ts +9 -0
  45. package/dist/tunnel.js +117 -28
  46. package/dist/tunnel.js.map +1 -1
  47. package/dist/tunnel.test.js +81 -5
  48. package/dist/tunnel.test.js.map +1 -1
  49. package/package.json +4 -4
  50. package/skills/kimaki-tunnel/SKILL.md +3 -2
  51. package/src/bot.ts +7 -14
  52. package/src/builtin-skills.test.ts +74 -1
  53. package/src/builtin-skills.ts +33 -0
  54. package/src/cli/bot.ts +7 -5
  55. package/src/cli-lock.e2e.test.ts +1 -1
  56. package/src/event-loop.ts +1 -4
  57. package/src/main.ts +5 -4
  58. package/src/markdown/markdown.test.ts +11 -0
  59. package/src/markdown/render-markdown.ts +3 -1
  60. package/src/plugin/index.ts +18 -44
  61. package/src/session-events.ts +8 -4
  62. package/src/sessions.ts +3 -3
  63. package/src/system-prompt.ts +56 -80
  64. package/src/test/harness.ts +0 -3
  65. package/src/test/replay.ts +0 -1
  66. package/src/thread-reducer.fixtures.test.ts +2 -2
  67. package/src/thread-reducer.test.ts +0 -31
  68. package/src/thread-reducer.ts +4 -36
  69. package/src/tunnel.test.ts +81 -5
  70. package/src/tunnel.ts +124 -25
  71. package/src/message-tool.e2e.test.ts +0 -45
package/dist/tunnel.js CHANGED
@@ -4,14 +4,13 @@
4
4
  // profile in $XDG_DATA_HOME/opentunnel, shared with the opentunnel CLI.
5
5
  import crypto from 'node:crypto';
6
6
  import { execFile, spawn } from 'node:child_process';
7
+ import http from 'node:http';
7
8
  import net from 'node:net';
8
9
  import { setTimeout as sleep } from 'node:timers/promises';
9
10
  import { promisify, stripVTControlCharacters } from 'node:util';
10
- import { create as createOpenTunnel } from '@opentunnel/client';
11
+ import { create as createOpenTunnel, isValidRouteName, OpenTunnelClientError, publicUrl, } from '@opentunnel/client';
11
12
  const execFileAsync = promisify(execFile);
12
- const ROUTE_NAME = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
13
13
  const PORT_WAIT_MS = 30_000;
14
- const ATTACH_TIMEOUT_MS = 60_000;
15
14
  const CHILD_KILL_GRACE_MS = 5_000;
16
15
  // Only lines with host:port, so "Port 5173 is in use" does not match.
17
16
  const LOCAL_PORT_PATTERN = /(?:https?:\/\/)?(?:localhost|127\.0\.0\.1|0\.0\.0\.0|\[::\]):(\d{1,5})/i;
@@ -27,14 +26,29 @@ export function detectPortFromText(text) {
27
26
  }
28
27
  return null;
29
28
  }
29
+ // Traforo accepted any tunnel ID, so map it to a DNS label instead of failing: `My_App` becomes `my-app`.
30
+ function toRouteLabel(raw) {
31
+ const label = raw.toLowerCase().replace(/[^a-z0-9-]+/g, '-').replace(/^-+|-+$/g, '').slice(0, 63).replace(/-+$/, '');
32
+ return isValidRouteName(label) ? label : '';
33
+ }
30
34
  // Explicit name, then the tuistory session ID (stable URL across restarts of one session), then random.
31
35
  export function routeName({ name, tuistorySessionId }) {
32
36
  if (name)
33
- return ROUTE_NAME.test(name) ? name : new Error(`Invalid tunnel ID ${JSON.stringify(name)}: use lowercase letters, digits and dashes`);
34
- const fromSession = tuistorySessionId?.toLowerCase();
35
- if (fromSession && ROUTE_NAME.test(fromSession))
36
- return fromSession;
37
- return crypto.randomBytes(8).toString('hex');
37
+ return toRouteLabel(name) || new Error(`Invalid tunnel ID ${JSON.stringify(name)}: use letters, digits and dashes`);
38
+ return toRouteLabel(tuistorySessionId ?? '') || crypto.randomBytes(8).toString('hex');
39
+ }
40
+ // Parses `netstat -ano` output on Windows: `TCP 0.0.0.0:5173 0.0.0.0:0 LISTENING 1234`.
41
+ export function parseNetstatListeningPids({ stdout, port }) {
42
+ const pids = new Set();
43
+ for (const line of stdout.split('\n')) {
44
+ const [protocol, local, , state, pid] = line.trim().split(/\s+/);
45
+ if (protocol !== 'TCP' || state !== 'LISTENING' || !local?.endsWith(`:${port}`))
46
+ continue;
47
+ const parsed = Number(pid);
48
+ if (Number.isInteger(parsed) && parsed > 0)
49
+ pids.add(parsed);
50
+ }
51
+ return [...pids];
38
52
  }
39
53
  function isPortInUse({ port, host }) {
40
54
  return new Promise((resolve) => {
@@ -51,6 +65,10 @@ async function waitForPort({ port, host, signal }) {
51
65
  }
52
66
  }
53
67
  async function listeningPids(port) {
68
+ if (process.platform === 'win32') {
69
+ const { stdout } = await execFileAsync('netstat', ['-ano'], { timeout: 5_000 }).catch(() => ({ stdout: '' }));
70
+ return parseNetstatListeningPids({ stdout, port });
71
+ }
54
72
  const { stdout } = await execFileAsync('lsof', ['-ti', `tcp:${port}`, '-sTCP:LISTEN'], { timeout: 5_000 }).catch(() => ({ stdout: '' }));
55
73
  return stdout.split('\n').map(Number).filter((pid) => Number.isInteger(pid) && pid > 0);
56
74
  }
@@ -104,6 +122,69 @@ function killChild(child, signal = 'SIGTERM') {
104
122
  });
105
123
  }
106
124
  const log = (line) => process.stderr.write(`${line}\n`);
125
+ function logTunnelEvent(event) {
126
+ if (event.type === 'disconnected')
127
+ log(`Tunnel disconnected: ${event.reason}`);
128
+ if (event.type === 'connected')
129
+ log('Tunnel connected');
130
+ }
131
+ function forwardedHeaders({ headers, target }) {
132
+ return {
133
+ ...headers,
134
+ host: target,
135
+ 'x-forwarded-host': headers['x-forwarded-host'] ?? headers.host,
136
+ 'x-forwarded-proto': headers['x-forwarded-proto'] ?? 'https',
137
+ };
138
+ }
139
+ function rawResponseHead(response) {
140
+ let head = `HTTP/1.1 ${response.statusCode} ${response.statusMessage}\r\n`;
141
+ for (let i = 0; i < response.rawHeaders.length; i += 2)
142
+ head += `${response.rawHeaders[i]}: ${response.rawHeaders[i + 1]}\r\n`;
143
+ return `${head}\r\n`;
144
+ }
145
+ // opentunnel forwards the raw bytes, so the app would see the public Host header. Vite and other dev
146
+ // servers reject unknown hosts (DNS rebinding protection) with 403. This loopback proxy sends
147
+ // Host: localhost:<port> and keeps the public host in X-Forwarded-Host, like traforo did.
148
+ export function startHostProxy({ host, port }) {
149
+ const target = `${host}:${port}`;
150
+ const server = http.createServer((req, res) => {
151
+ const upstream = http.request({ host, port, method: req.method, path: req.url, headers: forwardedHeaders({ headers: req.headers, target }) }, (response) => {
152
+ res.writeHead(response.statusCode ?? 502, response.statusMessage, response.rawHeaders);
153
+ response.pipe(res);
154
+ });
155
+ upstream.on('error', () => {
156
+ if (!res.headersSent)
157
+ res.writeHead(502);
158
+ res.end();
159
+ });
160
+ req.pipe(upstream);
161
+ });
162
+ // WebSocket upgrades (Vite HMR): replay the handshake upstream, then pipe both sockets.
163
+ server.on('upgrade', (req, socket, head) => {
164
+ const upstream = http.request({ host, port, method: req.method, path: req.url, headers: forwardedHeaders({ headers: req.headers, target }) });
165
+ upstream.on('upgrade', (response, upstreamSocket, upstreamHead) => {
166
+ socket.write(rawResponseHead(response));
167
+ if (upstreamHead.length > 0)
168
+ socket.write(upstreamHead);
169
+ if (head.length > 0)
170
+ upstreamSocket.write(head);
171
+ upstreamSocket.on('error', () => socket.destroy());
172
+ socket.on('error', () => upstreamSocket.destroy());
173
+ upstreamSocket.pipe(socket).pipe(upstreamSocket);
174
+ });
175
+ upstream.on('response', (response) => {
176
+ socket.write(rawResponseHead(response));
177
+ response.pipe(socket);
178
+ });
179
+ upstream.on('error', () => socket.destroy());
180
+ socket.on('error', () => upstream.destroy());
181
+ upstream.end();
182
+ });
183
+ return new Promise((resolve) => {
184
+ server.once('error', (cause) => resolve(new Error('Could not start the tunnel proxy', { cause })));
185
+ server.listen(0, '127.0.0.1', () => resolve(server));
186
+ });
187
+ }
107
188
  export async function runTunnel(options) {
108
189
  const host = options.host ?? 'localhost';
109
190
  const route = routeName({ name: options.name, tuistorySessionId: process.env['TUISTORY_SESSION_ID'] });
@@ -120,13 +201,20 @@ export async function runTunnel(options) {
120
201
  return new Error(`Port ${options.port} is already in use. Pass --kill to stop the process on it first`);
121
202
  }
122
203
  const client = createOpenTunnel();
123
- const existing = await client.tunnel.get().catch(() => undefined);
124
- if (!existing)
125
- log('Creating the opentunnel.xyz tunnel of this machine (waits for a certificate, up to a minute)...');
126
- const identity = await client.tunnel.ensure().catch((cause) => new Error('Could not create the opentunnel tunnel', { cause }));
204
+ let waitLogged = false;
205
+ const identity = await client.tunnel
206
+ .ensure({
207
+ onProgress: (stage) => {
208
+ if (waitLogged || stage === 'checking-certificate' || stage === 'ready')
209
+ return;
210
+ waitLogged = true;
211
+ log('Getting a certificate for the opentunnel.xyz tunnel of this machine (up to a minute)...');
212
+ },
213
+ })
214
+ .catch((cause) => new Error('Could not create the opentunnel tunnel', { cause }));
127
215
  if (identity instanceof Error)
128
216
  return identity;
129
- const url = `https://${route}.${identity.hostname}`;
217
+ const url = publicUrl(route, identity.hostname);
130
218
  let child;
131
219
  let connection;
132
220
  // Set before we kill the child ourselves, so its exit does not end the process first.
@@ -183,24 +271,25 @@ export async function runTunnel(options) {
183
271
  const ready = await waitForPort({ port, host, signal: portSignal });
184
272
  if (ready instanceof Error)
185
273
  return fail(ready);
186
- // connect retries route_conflict forever, so a route held by another process would hang here.
187
- const connecting = client.tunnel.connect({ routes: { [route]: `${host}:${port}` } });
188
- const timeout = sleep(ATTACH_TIMEOUT_MS, null, { ref: false });
189
- const attached = await Promise.race([connecting, timeout]).catch((cause) => new Error('Could not connect the tunnel', { cause }));
274
+ const proxy = await startHostProxy({ host, port });
275
+ if (proxy instanceof Error)
276
+ return fail(proxy);
277
+ const proxyAddress = proxy.address();
278
+ if (!proxyAddress || typeof proxyAddress === 'string')
279
+ return fail(new Error('Tunnel proxy has no TCP address'));
280
+ const attached = await client.tunnel
281
+ .connect({ routes: { [route]: `127.0.0.1:${proxyAddress.port}` }, onRouteConflict: 'fail', onEvent: logTunnelEvent })
282
+ .catch((cause) => {
283
+ if (cause instanceof OpenTunnelClientError && cause.code === 'route_conflict') {
284
+ return new Error(`Tunnel ID ${route} is already used by another process. Pass a different -t`, { cause });
285
+ }
286
+ return new Error('Could not connect the tunnel', { cause });
287
+ });
190
288
  if (attached instanceof Error)
191
289
  return fail(attached);
192
- if (!attached)
193
- return fail(new Error(`Tunnel did not attach in ${ATTACH_TIMEOUT_MS / 1000}s. Another process may use the tunnel ID ${route}`));
194
290
  connection = attached;
195
- process.stdout.write(`\nLocal: http://${host}:${port}\nTunnel: ${url}\n\n`);
196
- void (async () => {
197
- for await (const event of attached.events) {
198
- if (event.type === 'disconnected')
199
- log(`Tunnel disconnected: ${event.reason}`);
200
- if (event.type === 'connected')
201
- log('Tunnel connected');
202
- }
203
- })();
291
+ process.stdout.write(`\nLocal: http://${host}:${port}\nTunnel: ${url}\n` +
292
+ `Agents: validate with the Local URL (playwriter, curl), it is much faster. The Tunnel URL is for the user.\n\n`);
204
293
  const closed = await attached.closed.then(() => undefined, (cause) => new Error('Tunnel stopped', { cause }));
205
294
  return fail(closed ?? new Error('Tunnel stopped'));
206
295
  }
@@ -1 +1 @@
1
- {"version":3,"file":"tunnel.js","sourceRoot":"","sources":["../src/tunnel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tunnel.js","sourceRoot":"","sources":["../src/tunnel.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,10 @@
1
+ import fs from 'node:fs';
2
+ import http from 'node:http';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { createServer } from 'vite';
1
6
  import { expect, test } from 'vitest';
2
- import { detectPortFromText, routeName } from "./tunnel.js";
7
+ import { detectPortFromText, parseNetstatListeningPids, routeName, startHostProxy } from "./tunnel.js";
3
8
  test('detects the dev server port and skips noise lines', () => {
4
9
  const vite = '\u001b[33mPort 5173 is in use, trying another one...\u001b[39m\n ➜ Local: \u001b[36mhttp://localhost:\u001b[1m5174\u001b[22m/\u001b[39m\n';
5
10
  expect({
@@ -23,16 +28,87 @@ test('detects the dev server port and skips noise lines', () => {
23
28
  test('route name: explicit, then tuistory session, then random', () => {
24
29
  expect({
25
30
  explicit: routeName({ name: 'docs', tuistorySessionId: 'abc123' }),
26
- invalid: String(routeName({ name: 'Bad_Name' })),
27
- tuistory: routeName({ tuistorySessionId: 'ABC123' }),
31
+ normalized: routeName({ name: '_My_App.dev_' }),
32
+ invalid: String(routeName({ name: '___' })),
33
+ tuistory: routeName({ tuistorySessionId: 'Holocron_Dev' }),
34
+ tuistoryInvalid: String(routeName({ tuistorySessionId: '___' })).length,
28
35
  random: String(routeName({})).length,
29
36
  }).toMatchInlineSnapshot(`
30
37
  {
31
38
  "explicit": "docs",
32
- "invalid": "Error: Invalid tunnel ID "Bad_Name": use lowercase letters, digits and dashes",
39
+ "invalid": "Error: Invalid tunnel ID "___": use letters, digits and dashes",
40
+ "normalized": "my-app-dev",
33
41
  "random": 16,
34
- "tuistory": "abc123",
42
+ "tuistory": "holocron-dev",
43
+ "tuistoryInvalid": 16,
35
44
  }
36
45
  `);
37
46
  });
47
+ test('netstat listening pids on Windows', () => {
48
+ const stdout = [
49
+ 'Active Connections',
50
+ ' Proto Local Address Foreign Address State PID',
51
+ ' TCP 0.0.0.0:5173 0.0.0.0:0 LISTENING 1234',
52
+ ' TCP [::]:5173 [::]:0 LISTENING 1234',
53
+ ' TCP 127.0.0.1:51730 0.0.0.0:0 LISTENING 999',
54
+ ' TCP 127.0.0.1:5173 127.0.0.1:60000 ESTABLISHED 777',
55
+ ' UDP 0.0.0.0:5173 *:* 555',
56
+ ].join('\r\n');
57
+ expect(parseNetstatListeningPids({ stdout, port: 5173 })).toMatchInlineSnapshot(`
58
+ [
59
+ 1234,
60
+ ]
61
+ `);
62
+ });
63
+ function request({ port, headers }) {
64
+ return new Promise((resolve, reject) => {
65
+ const req = http.request({ host: '127.0.0.1', port, path: '/', headers });
66
+ req.on('response', (res) => {
67
+ res.resume();
68
+ resolve(String(res.statusCode));
69
+ req.destroy();
70
+ });
71
+ req.on('upgrade', (res, socket) => {
72
+ resolve(`${res.statusCode} ${res.headers['sec-websocket-protocol']}`);
73
+ socket.destroy();
74
+ });
75
+ req.on('error', reject);
76
+ req.end();
77
+ });
78
+ }
79
+ test('host proxy lets the public tunnel host through Vite host check, HMR included', async () => {
80
+ const root = fs.mkdtempSync(path.join(os.tmpdir(), 'kimaki-tunnel-'));
81
+ fs.writeFileSync(path.join(root, 'index.html'), '<p>hi</p>');
82
+ const vite = await createServer({ root, configFile: false, logLevel: 'silent', server: { host: '127.0.0.1', port: 0 } });
83
+ await vite.listen();
84
+ const address = vite.httpServer.address();
85
+ if (!address || typeof address === 'string')
86
+ throw new Error('no vite address');
87
+ const proxy = await startHostProxy({ host: '127.0.0.1', port: address.port });
88
+ if (proxy instanceof Error)
89
+ throw proxy;
90
+ const proxyAddress = proxy.address();
91
+ if (!proxyAddress || typeof proxyAddress === 'string')
92
+ throw new Error('no proxy address');
93
+ const publicHost = { host: 'docs.abc.opentunnel.xyz' };
94
+ const hmr = { ...publicHost, connection: 'Upgrade', upgrade: 'websocket', 'sec-websocket-version': '13', 'sec-websocket-key': 'dGhlIHNhbXBsZSBub25jZQ==', 'sec-websocket-protocol': 'vite-hmr' };
95
+ try {
96
+ expect({
97
+ direct: await request({ port: address.port, headers: publicHost }),
98
+ proxied: await request({ port: proxyAddress.port, headers: publicHost }),
99
+ proxiedHmr: await request({ port: proxyAddress.port, headers: hmr }),
100
+ }).toMatchInlineSnapshot(`
101
+ {
102
+ "direct": "403",
103
+ "proxied": "200",
104
+ "proxiedHmr": "101 vite-hmr",
105
+ }
106
+ `);
107
+ }
108
+ finally {
109
+ proxy.close();
110
+ await vite.close();
111
+ fs.rmSync(root, { recursive: true, force: true });
112
+ }
113
+ });
38
114
  //# sourceMappingURL=tunnel.test.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"tunnel.test.js","sourceRoot":"","sources":["../src/tunnel.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAA;AACrC,OAAO,EAAE,kBAAkB,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAE3D,IAAI,CAAC,mDAAmD,EAAE,GAAG,EAAE;IAC7D,MAAM,IAAI,GAAG,+IAA+I,CAAA;IAC5J,MAAM,CAAC;QACL,IAAI,EAAE,kBAAkB,CAAC,IAAI,CAAC;QAC9B,IAAI,EAAE,kBAAkB,CAAC,0CAA0C,CAAC;QACpE,IAAI,EAAE,kBAAkB,CAAC,gCAAgC,CAAC;QAC1D,SAAS,EAAE,kBAAkB,CAAC,+EAA+E,CAAC;QAC9G,UAAU,EAAE,kBAAkB,CAAC,8BAA8B,CAAC;QAC9D,QAAQ,EAAE,kBAAkB,CAAC,qBAAqB,CAAC;KACpD,CAAC,CAAC,qBAAqB,CAAC;;;;;;;;;GASxB,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA;AAEF,IAAI,CAAC,0DAA0D,EAAE,GAAG,EAAE;IACpE,MAAM,CAAC;QACL,QAAQ,EAAE,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC;QAClE,OAAO,EAAE,MAAM,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QAChD,QAAQ,EAAE,SAAS,CAAC,EAAE,iBAAiB,EAAE,QAAQ,EAAE,CAAC;QACpD,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM;KACrC,CAAC,CAAC,qBAAqB,CAAC;;;;;;;GAOxB,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
1
+ {"version":3,"file":"tunnel.test.js","sourceRoot":"","sources":["../src/tunnel.test.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kimaki",
3
- "version": "1.3.0",
3
+ "version": "1.4.0",
4
4
  "description": "A collaborative agent orchestrator for OpenCode, inside Discord",
5
5
  "repository": "https://github.com/remorses/kimaki",
6
6
  "type": "module",
@@ -20,7 +20,7 @@
20
20
  "@libsql/client": "^0.17.2",
21
21
  "@opencode/client": "2.0.29",
22
22
  "@opencode/plugin": "2.0.29",
23
- "@opentunnel/client": "0.5.2",
23
+ "@opentunnel/client": "0.6.0",
24
24
  "@strada.sh/sdk": "^0.8.0",
25
25
  "cron-parser": "^5.5.0",
26
26
  "discord-api-types": "^0.38.40",
@@ -52,8 +52,8 @@
52
52
  "typescript": "^5.9.2",
53
53
  "vitest": "^3.2.4",
54
54
  "ws": "^8.18.0",
55
- "discord-digital-twin": "^0.1.2",
56
- "opencode-deterministic-provider": "^0.0.1"
55
+ "opencode-deterministic-provider": "^0.0.1",
56
+ "discord-digital-twin": "^0.1.2"
57
57
  },
58
58
  "scripts": {
59
59
  "build": "tsc",
@@ -1,16 +1,17 @@
1
1
  ---
2
2
  name: kimaki-tunnel
3
- description: Share a local dev server with the user through a public URL. Use when the user should open a localhost app in a browser, test a webhook or OAuth callback against a local server, or preview a dev server from Discord. Runs `kimaki tunnel` in a named background tuistory session. ALWAYS load before starting a dev server the user must open. Only for Kimaki Discord sessions.
3
+ description: Share a local dev server with the user through a public URL. Localhost URLs are useless from Discord. Use when the user should open a localhost app in a browser, test a webhook or OAuth callback against a local server, or preview a dev server from Discord. Runs `kimaki tunnel` in a named background tuistory session. ALWAYS load before starting a dev server the user must open. Only for Kimaki Discord sessions.
4
4
  ---
5
5
 
6
6
  # Dev servers with tunnel access
7
7
 
8
8
  Localhost URLs are useless from Discord. Wrap the dev server in `kimaki tunnel` to get a public `https://<name>.<id>.opentunnel.xyz` URL, and run it in a named background `tuistory` session so you can wait for output, read logs and stop it later. Name the session descriptively (e.g. `projectname-dev`) and reuse it. Run `tuistory --help` first (or `bunx tuistory` when it is not installed). Invoke `kimaki` directly, not via `npx` or `bunx`.
9
9
 
10
+ - **Validate on localhost.** The agent runs on the same machine as the server, so playwriter, curl and tests must use the `Local:` URL. It is much faster. The tunnel URL is only for the user.
10
11
  - Use random names by default. Pass `-t <name>` only for services that are safe to be publicly discoverable.
11
12
  - `kimaki tunnel` detects the local port from the child output. Pass `--port` only when the server prints no detectable localhost URL.
12
13
  - `kimaki tunnel` injects `KIMAKI_TUNNEL_URL` into the child process. Wire the app to it so OAuth callbacks, webhook URLs and absolute links use the public URL.
13
- - TLS ends on this machine and the request reaches the app unchanged. Dev servers that check the `Host` header (Vite) must allow it, e.g. `server.allowedHosts: true` or `['.opentunnel.xyz']`.
14
+ - The app gets `Host: localhost:<port>` and the public host in `X-Forwarded-Host`, so Vite needs no `allowedHosts` config.
14
15
  - The first run on a machine creates the tunnel and waits up to a minute for its certificate.
15
16
 
16
17
  ```bash
package/src/bot.ts CHANGED
@@ -11,6 +11,7 @@ import { ChannelType, type Client, type TextChannel, type ThreadChannel } from '
11
11
 
12
12
  import type { AgentUi } from './agent-ui.ts'
13
13
  import type { Analytics } from './analytics.ts'
14
+ import type { PromptSection } from './builtin-skills.ts'
14
15
  import type { KimakiDb } from './db.ts'
15
16
  import type { EffectsRunner } from './effects.ts'
16
17
  import { ConfigError, DbError, DiscordError, OpenCodeError, OpenCodeUnavailableError } from './errors.ts'
@@ -69,8 +70,8 @@ export type Bot = {
69
70
  allowAllUsers: boolean
70
71
  // Built-in skill ids (builtin-skills.ts) denied through the permissions of new sessions.
71
72
  disabledSkills: readonly string[]
72
- // `kimaki --message-tool`: root sessions also reply through send_message; Discord hides their plain text.
73
- messageTool: boolean
73
+ // `kimaki --disable-prompt`: static instruction parts left out of new sessions.
74
+ disabledPrompt: readonly PromptSection[]
74
75
  features: BotFeatures
75
76
  }
76
77
 
@@ -136,7 +137,6 @@ export type SessionMarker = {
136
137
  fields: { readonly [key: string]: JsonValue }
137
138
  dataDir: string | null
138
139
  lockPort: number | null
139
- messageTool: boolean
140
140
  // Explicit `kimaki send --parent-session`, so /resume keeps the instruction line.
141
141
  parentSessionId: string | null
142
142
  // The scheduled run stored at session.create, so /resume keeps the same instruction section.
@@ -150,7 +150,7 @@ function jsonObject(value: JsonValue | undefined): { readonly [key: string]: Jso
150
150
  export function readMarker(metadata: SessionMetadata | undefined): SessionMarker | null {
151
151
  const fields = jsonObject(metadata?.['kimaki'])
152
152
  if (!fields) return null
153
- const { dataDir, lockPort, messageTool, parentSessionId } = fields
153
+ const { dataDir, lockPort, parentSessionId } = fields
154
154
  const task = jsonObject(fields['task'])
155
155
  const taskId = task?.['id']
156
156
  const cronExpr = task?.['cronExpr']
@@ -159,7 +159,6 @@ export function readMarker(metadata: SessionMetadata | undefined): SessionMarker
159
159
  fields,
160
160
  dataDir: typeof dataDir === 'string' ? dataDir : null,
161
161
  lockPort: typeof lockPort === 'number' ? lockPort : null,
162
- messageTool: messageTool === true,
163
162
  parentSessionId: typeof parentSessionId === 'string' ? parentSessionId : null,
164
163
  task: typeof taskId === 'number'
165
164
  ? { id: taskId, cronExpr: typeof cronExpr === 'string' ? cronExpr : null, timezone: typeof timezone === 'string' ? timezone : null }
@@ -167,15 +166,9 @@ export function readMarker(metadata: SessionMetadata | undefined): SessionMarker
167
166
  }
168
167
  }
169
168
 
170
- // The marker fields that follow this bot run: where the agent's `kimaki` calls
171
- // go, and whether the plugin gives the session send_message.
172
- export function cliContext(bot: Pick<Bot, 'dataDir' | 'lockPort' | 'messageTool'>) {
173
- return { dataDir: bot.dataDir, lockPort: bot.lockPort, messageTool: bot.messageTool }
174
- }
175
-
176
- // False when the session marker was written by another bot run or with another --message-tool.
177
- export function markerIsCurrent(bot: Pick<Bot, 'dataDir' | 'lockPort' | 'messageTool'>, marker: SessionMarker): boolean {
178
- return marker.dataDir === bot.dataDir && marker.lockPort === bot.lockPort && marker.messageTool === bot.messageTool
169
+ // The marker fields that point the agent's `kimaki` calls at this bot.
170
+ export function cliContext(bot: Bot) {
171
+ return { dataDir: bot.dataDir, lockPort: bot.lockPort }
179
172
  }
180
173
 
181
174
  // Default model of new sessions in channels without their own (/model "All channels").
@@ -1,6 +1,7 @@
1
1
  import { expect, test } from 'vitest'
2
2
 
3
- import { BUILTIN_SKILL_IDS, disabledSkillRules, parseDisabledSkills, readBuiltinSkills } from './builtin-skills.ts'
3
+ import { BUILTIN_SKILL_IDS, disabledSkillRules, parseDisabledPromptSections, parseDisabledSkills, PROMPT_SECTIONS, readBuiltinSkills } from './builtin-skills.ts'
4
+ import { baseInstructions } from './system-prompt.ts'
4
5
 
5
6
  test('every built-in skill file parses', async () => {
6
7
  const skills = await readBuiltinSkills()
@@ -27,3 +28,75 @@ test('--disable-skills accepts all, a list, and rejects unknown ids', () => {
27
28
  ]
28
29
  `)
29
30
  })
31
+
32
+ test('--disable-prompt removes exactly the headings of each section', () => {
33
+ expect(parseDisabledPromptSections(['critique-diffs,discord-callouts', 'search-result-urls'])).toEqual(['critique-diffs', 'discord-callouts', 'search-result-urls'])
34
+ expect(parseDisabledPromptSections(['critique'])).toBeInstanceOf(Error)
35
+ const input = { sessionId: 'ses_1', threadId: '2', channelId: '3', guildId: '4', userId: '5', dataDir: '/data', channelTopic: null, agents: [], parentSessionId: null }
36
+ const headings = (text: string) => text.split('\n').filter((line) => line.startsWith('## '))
37
+ const full = headings(baseInstructions(input))
38
+ const removed = Object.fromEntries(PROMPT_SECTIONS.map((section) => {
39
+ const kept = new Set(headings(baseInstructions({ ...input, disabled: [section] })))
40
+ return [section, full.filter((heading) => !kept.has(heading))]
41
+ }))
42
+ expect(removed).toMatchInlineSnapshot(`
43
+ {
44
+ "action-buttons": [
45
+ "## action buttons",
46
+ "## ending conversations with options",
47
+ ],
48
+ "ascii-diagrams": [
49
+ "## diagrams",
50
+ ],
51
+ "critique-diffs": [
52
+ "## showing diffs",
53
+ ],
54
+ "cross-project-commands": [
55
+ "## cross-project commands",
56
+ ],
57
+ "discord-callouts": [
58
+ "## Callouts in Kimaki Discord",
59
+ "## Tests not fully green",
60
+ ],
61
+ "discord-permissions": [
62
+ "## permissions",
63
+ ],
64
+ "file-upload-requests": [
65
+ "## requesting files from the user",
66
+ ],
67
+ "kimaki-debugging": [
68
+ "## debugging kimaki issues",
69
+ ],
70
+ "markdown-formatting": [
71
+ "## markdown formatting",
72
+ ],
73
+ "search-result-urls": [
74
+ "## URLs in search results",
75
+ ],
76
+ "session-abort": [
77
+ "## aborting a session",
78
+ ],
79
+ "session-sleep": [
80
+ "## sleeping the session",
81
+ ],
82
+ "waiting-sessions": [
83
+ "## waiting for a session to finish",
84
+ ],
85
+ }
86
+ `)
87
+ expect(headings(baseInstructions({ ...input, disabled: [...PROMPT_SECTIONS] }))).toMatchInlineSnapshot(`
88
+ [
89
+ "## Discord output",
90
+ "## shell tool",
91
+ "## commit messages",
92
+ "## uploading files to discord",
93
+ "## generating audio from text",
94
+ "## archiving the current thread",
95
+ "## updating the session title",
96
+ "## discord user mentions",
97
+ "## starting new sessions from CLI",
98
+ "## scheduled sends and routines",
99
+ "## reading other sessions",
100
+ ]
101
+ `)
102
+ })
@@ -53,6 +53,39 @@ export function parseDisabledSkills(value: string | undefined): ConfigError | Bu
53
53
  return items as BuiltinSkillId[]
54
54
  }
55
55
 
56
+ // Static parts of the session instructions (system-prompt.ts) that
57
+ // `kimaki --disable-prompt <section>` removes. Here, not in system-prompt.ts,
58
+ // so the CLI help can list them without loading zod.
59
+ export const PROMPT_SECTIONS = [
60
+ 'discord-permissions',
61
+ 'kimaki-debugging',
62
+ 'file-upload-requests',
63
+ 'action-buttons',
64
+ 'session-sleep',
65
+ 'session-abort',
66
+ 'cross-project-commands',
67
+ 'waiting-sessions',
68
+ 'critique-diffs',
69
+ 'markdown-formatting',
70
+ 'discord-callouts',
71
+ 'search-result-urls',
72
+ 'ascii-diagrams',
73
+ ] as const
74
+
75
+ export type PromptSection = (typeof PROMPT_SECTIONS)[number]
76
+
77
+ function isPromptSection(item: string): item is PromptSection {
78
+ return PROMPT_SECTIONS.some((section) => section === item)
79
+ }
80
+
81
+ // Repeatable flag; each value can also be a comma separated list.
82
+ export function parseDisabledPromptSections(values: readonly string[] | undefined): ConfigError | PromptSection[] {
83
+ const items = (values ?? []).flatMap((value) => value.split(',')).map((item) => item.trim()).filter(Boolean)
84
+ const unknown = items.filter((item) => !isPromptSection(item))
85
+ if (unknown.length > 0) return new ConfigError({ reason: `Unknown prompt section ${unknown.join(', ')}. Choose from: ${PROMPT_SECTIONS.join(', ')}` })
86
+ return items.filter(isPromptSection)
87
+ }
88
+
56
89
  // OpenCode hides a skill from the model and the skill tool when its permission is denied.
57
90
  export function disabledSkillRules(disabled: readonly string[]) {
58
91
  return disabled.map((id) => ({ action: 'skill', resource: id, effect: 'deny' }) as const)