kimaki 1.2.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.
- package/dist/bot.d.ts +4 -2
- package/dist/bot.js.map +1 -1
- package/dist/builtin-skills.d.ts +3 -0
- package/dist/builtin-skills.js +29 -0
- package/dist/builtin-skills.js.map +1 -1
- package/dist/builtin-skills.test.js +73 -1
- package/dist/builtin-skills.test.js.map +1 -1
- package/dist/cli/bot.d.ts +1 -1
- package/dist/cli/bot.js +15 -6
- package/dist/cli/bot.js.map +1 -1
- package/dist/cli-lock.e2e.test.js +3 -2
- package/dist/cli-lock.e2e.test.js.map +1 -1
- package/dist/commands/login-commands.d.ts +1 -1
- package/dist/commands/preference-commands.d.ts +1 -1
- package/dist/commands/worktree-commands.d.ts +1 -1
- package/dist/hello-thread.e2e.test.js +31 -0
- package/dist/hello-thread.e2e.test.js.map +1 -1
- package/dist/ingress.js +11 -6
- package/dist/ingress.js.map +1 -1
- package/dist/lock-routes.d.ts +14 -14
- package/dist/main.d.ts +2 -0
- package/dist/main.js +1 -0
- package/dist/main.js.map +1 -1
- package/dist/markdown/markdown.test.js +10 -0
- package/dist/markdown/markdown.test.js.map +1 -1
- package/dist/markdown/render-markdown.js +3 -1
- package/dist/markdown/render-markdown.js.map +1 -1
- package/dist/plugin/index.js +8 -2
- package/dist/plugin/index.js.map +1 -1
- package/dist/prompt.d.ts +6 -6
- package/dist/scheduler.d.ts +1 -1
- package/dist/session-events.js +9 -5
- package/dist/session-events.js.map +1 -1
- package/dist/sessions.d.ts +10 -10
- package/dist/sessions.js +1 -0
- package/dist/sessions.js.map +1 -1
- package/dist/system-prompt.d.ts +3 -1
- package/dist/system-prompt.js +52 -43
- package/dist/system-prompt.js.map +1 -1
- package/dist/tunnel.d.ts +21 -0
- package/dist/tunnel.js +296 -0
- package/dist/tunnel.js.map +1 -0
- package/dist/tunnel.test.d.ts +1 -0
- package/dist/tunnel.test.js +114 -0
- package/dist/tunnel.test.js.map +1 -0
- package/package.json +3 -3
- package/skills/kimaki-tunnel/SKILL.md +16 -11
- package/src/bot.ts +3 -0
- package/src/builtin-skills.test.ts +74 -1
- package/src/builtin-skills.ts +33 -0
- package/src/cli/bot.ts +13 -7
- package/src/cli-lock.e2e.test.ts +3 -2
- package/src/hello-thread.e2e.test.ts +35 -0
- package/src/ingress.ts +9 -5
- package/src/main.ts +4 -0
- package/src/markdown/markdown.test.ts +11 -0
- package/src/markdown/render-markdown.ts +3 -1
- package/src/plugin/index.ts +9 -2
- package/src/session-events.ts +8 -4
- package/src/sessions.ts +1 -0
- package/src/system-prompt.ts +56 -42
- package/src/tunnel.test.ts +115 -0
- package/src/tunnel.ts +308 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../src/system-prompt.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,8EAA8E;AAC9E,4EAA4E;AAE5E,OAAO,MAAM,MAAM,eAAe,CAAA;AAClC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;
|
|
1
|
+
{"version":3,"file":"system-prompt.js","sourceRoot":"","sources":["../src/system-prompt.ts"],"names":[],"mappings":"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"}
|
package/dist/tunnel.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
export declare function detectPortFromText(text: string): number | null;
|
|
3
|
+
export declare function routeName({ name, tuistorySessionId }: {
|
|
4
|
+
name?: string;
|
|
5
|
+
tuistorySessionId?: string;
|
|
6
|
+
}): string | Error;
|
|
7
|
+
export declare function parseNetstatListeningPids({ stdout, port }: {
|
|
8
|
+
stdout: string;
|
|
9
|
+
port: number;
|
|
10
|
+
}): number[];
|
|
11
|
+
export declare function startHostProxy({ host, port }: {
|
|
12
|
+
host: string;
|
|
13
|
+
port: number;
|
|
14
|
+
}): Promise<http.Server | Error>;
|
|
15
|
+
export declare function runTunnel(options: {
|
|
16
|
+
port?: number;
|
|
17
|
+
command?: string[];
|
|
18
|
+
name?: string;
|
|
19
|
+
host?: string;
|
|
20
|
+
kill?: boolean;
|
|
21
|
+
}): Promise<void | Error>;
|
package/dist/tunnel.js
ADDED
|
@@ -0,0 +1,296 @@
|
|
|
1
|
+
// `kimaki tunnel`: run a command, find the local port it listens on, and expose
|
|
2
|
+
// it at https://<route>.<id>.opentunnel.xyz. TLS ends in this process, so the
|
|
3
|
+
// relay never sees plaintext. The tunnel identity is the default opentunnel
|
|
4
|
+
// profile in $XDG_DATA_HOME/opentunnel, shared with the opentunnel CLI.
|
|
5
|
+
import crypto from 'node:crypto';
|
|
6
|
+
import { execFile, spawn } from 'node:child_process';
|
|
7
|
+
import http from 'node:http';
|
|
8
|
+
import net from 'node:net';
|
|
9
|
+
import { setTimeout as sleep } from 'node:timers/promises';
|
|
10
|
+
import { promisify, stripVTControlCharacters } from 'node:util';
|
|
11
|
+
import { create as createOpenTunnel, isValidRouteName, OpenTunnelClientError, publicUrl, } from '@opentunnel/client';
|
|
12
|
+
const execFileAsync = promisify(execFile);
|
|
13
|
+
const PORT_WAIT_MS = 30_000;
|
|
14
|
+
const CHILD_KILL_GRACE_MS = 5_000;
|
|
15
|
+
// Only lines with host:port, so "Port 5173 is in use" does not match.
|
|
16
|
+
const LOCAL_PORT_PATTERN = /(?:https?:\/\/)?(?:localhost|127\.0\.0\.1|0\.0\.0\.0|\[::\]):(\d{1,5})/i;
|
|
17
|
+
const IGNORED_LINE_PATTERNS = [/\bdebugger (?:listening|attached)\b/i, /\bdevtools listening\b/i];
|
|
18
|
+
export function detectPortFromText(text) {
|
|
19
|
+
// Vite colors the port separately, so strip ANSI before matching.
|
|
20
|
+
for (const line of stripVTControlCharacters(text).split('\n')) {
|
|
21
|
+
if (IGNORED_LINE_PATTERNS.some((pattern) => pattern.test(line)))
|
|
22
|
+
continue;
|
|
23
|
+
const port = Number(line.match(LOCAL_PORT_PATTERN)?.[1]);
|
|
24
|
+
if (port >= 1 && port <= 65_535)
|
|
25
|
+
return port;
|
|
26
|
+
}
|
|
27
|
+
return null;
|
|
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
|
+
}
|
|
34
|
+
// Explicit name, then the tuistory session ID (stable URL across restarts of one session), then random.
|
|
35
|
+
export function routeName({ name, tuistorySessionId }) {
|
|
36
|
+
if (name)
|
|
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];
|
|
52
|
+
}
|
|
53
|
+
function isPortInUse({ port, host }) {
|
|
54
|
+
return new Promise((resolve) => {
|
|
55
|
+
const socket = net.connect({ port, host });
|
|
56
|
+
socket.once('connect', () => { socket.destroy(); resolve(true); });
|
|
57
|
+
socket.once('error', () => { socket.destroy(); resolve(false); });
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
async function waitForPort({ port, host, signal }) {
|
|
61
|
+
while (!(await isPortInUse({ port, host }))) {
|
|
62
|
+
if (signal.aborted)
|
|
63
|
+
return new Error(`Timed out waiting for ${host}:${port} to accept connections`);
|
|
64
|
+
await sleep(300);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
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
|
+
}
|
|
72
|
+
const { stdout } = await execFileAsync('lsof', ['-ti', `tcp:${port}`, '-sTCP:LISTEN'], { timeout: 5_000 }).catch(() => ({ stdout: '' }));
|
|
73
|
+
return stdout.split('\n').map(Number).filter((pid) => Number.isInteger(pid) && pid > 0);
|
|
74
|
+
}
|
|
75
|
+
async function killProcessOnPort({ port, host }) {
|
|
76
|
+
for (const signal of ['SIGTERM', 'SIGKILL']) {
|
|
77
|
+
for (const pid of await listeningPids(port)) {
|
|
78
|
+
try {
|
|
79
|
+
process.kill(pid, signal);
|
|
80
|
+
}
|
|
81
|
+
catch { }
|
|
82
|
+
}
|
|
83
|
+
for (let waited = 0; waited < 3_000; waited += 200) {
|
|
84
|
+
if (!(await isPortInUse({ port, host })))
|
|
85
|
+
return;
|
|
86
|
+
await sleep(200);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return new Error(`Port ${port} is still in use after --kill`);
|
|
90
|
+
}
|
|
91
|
+
function detectPortFromOutput({ child, signal }) {
|
|
92
|
+
return new Promise((resolve) => {
|
|
93
|
+
let buffer = '';
|
|
94
|
+
const finish = (result) => {
|
|
95
|
+
child.stdout?.off('data', onData);
|
|
96
|
+
child.stderr?.off('data', onData);
|
|
97
|
+
child.off('exit', onExit);
|
|
98
|
+
signal.removeEventListener('abort', onAbort);
|
|
99
|
+
resolve(result);
|
|
100
|
+
};
|
|
101
|
+
const onData = (chunk) => {
|
|
102
|
+
buffer = (buffer + chunk.toString()).slice(-8_000);
|
|
103
|
+
const port = detectPortFromText(buffer);
|
|
104
|
+
if (port)
|
|
105
|
+
finish(port);
|
|
106
|
+
};
|
|
107
|
+
const onExit = (code) => finish(new Error(`Command exited with code ${code} before printing a localhost URL. Pass --port`));
|
|
108
|
+
const onAbort = () => finish(new Error(`No localhost URL in the command output after ${PORT_WAIT_MS / 1000}s. Pass --port`));
|
|
109
|
+
child.stdout?.on('data', onData);
|
|
110
|
+
child.stderr?.on('data', onData);
|
|
111
|
+
child.once('exit', onExit);
|
|
112
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
function killChild(child, signal = 'SIGTERM') {
|
|
116
|
+
if (!child || child.exitCode !== null || child.signalCode !== null)
|
|
117
|
+
return Promise.resolve();
|
|
118
|
+
return new Promise((resolve) => {
|
|
119
|
+
const timer = setTimeout(() => { child.kill('SIGKILL'); resolve(); }, CHILD_KILL_GRACE_MS);
|
|
120
|
+
child.once('exit', () => { clearTimeout(timer); resolve(); });
|
|
121
|
+
child.kill(signal);
|
|
122
|
+
});
|
|
123
|
+
}
|
|
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
|
+
}
|
|
188
|
+
export async function runTunnel(options) {
|
|
189
|
+
const host = options.host ?? 'localhost';
|
|
190
|
+
const route = routeName({ name: options.name, tuistorySessionId: process.env['TUISTORY_SESSION_ID'] });
|
|
191
|
+
if (route instanceof Error)
|
|
192
|
+
return route;
|
|
193
|
+
if (options.kill && !options.port)
|
|
194
|
+
return new Error('--kill needs --port');
|
|
195
|
+
if (options.port && options.kill) {
|
|
196
|
+
const killed = await killProcessOnPort({ port: options.port, host });
|
|
197
|
+
if (killed instanceof Error)
|
|
198
|
+
return killed;
|
|
199
|
+
}
|
|
200
|
+
else if (options.port && options.command && (await isPortInUse({ port: options.port, host }))) {
|
|
201
|
+
return new Error(`Port ${options.port} is already in use. Pass --kill to stop the process on it first`);
|
|
202
|
+
}
|
|
203
|
+
const client = createOpenTunnel();
|
|
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 }));
|
|
215
|
+
if (identity instanceof Error)
|
|
216
|
+
return identity;
|
|
217
|
+
const url = publicUrl(route, identity.hostname);
|
|
218
|
+
let child;
|
|
219
|
+
let connection;
|
|
220
|
+
// Set before we kill the child ourselves, so its exit does not end the process first.
|
|
221
|
+
let stopping = false;
|
|
222
|
+
const shutdown = async (signal) => {
|
|
223
|
+
if (stopping)
|
|
224
|
+
return;
|
|
225
|
+
stopping = true;
|
|
226
|
+
log('Shutting down...');
|
|
227
|
+
await connection?.close().catch(() => undefined);
|
|
228
|
+
await killChild(child, signal);
|
|
229
|
+
process.exit(0);
|
|
230
|
+
};
|
|
231
|
+
for (const signal of ['SIGINT', 'SIGTERM', 'SIGHUP'])
|
|
232
|
+
process.once(signal, () => void shutdown(signal));
|
|
233
|
+
if (options.command) {
|
|
234
|
+
const [cmd, ...args] = options.command;
|
|
235
|
+
child = spawn(cmd, args, {
|
|
236
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
237
|
+
env: {
|
|
238
|
+
...process.env,
|
|
239
|
+
...(options.port && { PORT: String(options.port) }),
|
|
240
|
+
KIMAKI_TUNNEL_URL: url,
|
|
241
|
+
// Old name from traforo, kept so existing app configs still work.
|
|
242
|
+
TRAFORO_URL: url,
|
|
243
|
+
// wrangler dev passes parent env vars as worker bindings, so workers can read KIMAKI_TUNNEL_URL.
|
|
244
|
+
CLOUDFLARE_INCLUDE_PROCESS_ENV: 'true',
|
|
245
|
+
FORCE_COLOR: '1',
|
|
246
|
+
VITE_CLS: 'false',
|
|
247
|
+
NEXT_TELEMETRY_DISABLED: '1',
|
|
248
|
+
},
|
|
249
|
+
});
|
|
250
|
+
child.stdout?.pipe(process.stdout);
|
|
251
|
+
child.stderr?.pipe(process.stderr);
|
|
252
|
+
child.on('error', (error) => { log(`Failed to start command: ${error.message}`); process.exit(1); });
|
|
253
|
+
child.on('exit', (code, signal) => {
|
|
254
|
+
if (stopping)
|
|
255
|
+
return;
|
|
256
|
+
log(`Command exited with ${signal ?? `code ${code}`}`);
|
|
257
|
+
process.exit(code ?? 1);
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
const fail = async (error) => { stopping = true; await killChild(child); return error; };
|
|
261
|
+
let port = options.port;
|
|
262
|
+
const portSignal = AbortSignal.timeout(PORT_WAIT_MS);
|
|
263
|
+
if (!port && child) {
|
|
264
|
+
const detected = await detectPortFromOutput({ child, signal: portSignal });
|
|
265
|
+
if (detected instanceof Error)
|
|
266
|
+
return fail(detected);
|
|
267
|
+
port = detected;
|
|
268
|
+
}
|
|
269
|
+
if (!port)
|
|
270
|
+
return fail(new Error('Could not find the local port. Pass --port'));
|
|
271
|
+
const ready = await waitForPort({ port, host, signal: portSignal });
|
|
272
|
+
if (ready instanceof Error)
|
|
273
|
+
return fail(ready);
|
|
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
|
+
});
|
|
288
|
+
if (attached instanceof Error)
|
|
289
|
+
return fail(attached);
|
|
290
|
+
connection = attached;
|
|
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`);
|
|
293
|
+
const closed = await attached.closed.then(() => undefined, (cause) => new Error('Tunnel stopped', { cause }));
|
|
294
|
+
return fail(closed ?? new Error('Tunnel stopped'));
|
|
295
|
+
}
|
|
296
|
+
//# sourceMappingURL=tunnel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tunnel.js","sourceRoot":"","sources":["../src/tunnel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,114 @@
|
|
|
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';
|
|
6
|
+
import { expect, test } from 'vitest';
|
|
7
|
+
import { detectPortFromText, parseNetstatListeningPids, routeName, startHostProxy } from "./tunnel.js";
|
|
8
|
+
test('detects the dev server port and skips noise lines', () => {
|
|
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';
|
|
10
|
+
expect({
|
|
11
|
+
vite: detectPortFromText(vite),
|
|
12
|
+
next: detectPortFromText(' - Local: http://127.0.0.1:3000'),
|
|
13
|
+
bare: detectPortFromText('Server running at 0.0.0.0:4321'),
|
|
14
|
+
inspector: detectPortFromText('Debugger listening on ws://127.0.0.1:9229/abc\nready on http://localhost:4173'),
|
|
15
|
+
outOfRange: detectPortFromText('listening on localhost:70000'),
|
|
16
|
+
portOnly: detectPortFromText('Port 5173 is in use'),
|
|
17
|
+
}).toMatchInlineSnapshot(`
|
|
18
|
+
{
|
|
19
|
+
"bare": 4321,
|
|
20
|
+
"inspector": 4173,
|
|
21
|
+
"next": 3000,
|
|
22
|
+
"outOfRange": null,
|
|
23
|
+
"portOnly": null,
|
|
24
|
+
"vite": 5174,
|
|
25
|
+
}
|
|
26
|
+
`);
|
|
27
|
+
});
|
|
28
|
+
test('route name: explicit, then tuistory session, then random', () => {
|
|
29
|
+
expect({
|
|
30
|
+
explicit: routeName({ name: 'docs', 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,
|
|
35
|
+
random: String(routeName({})).length,
|
|
36
|
+
}).toMatchInlineSnapshot(`
|
|
37
|
+
{
|
|
38
|
+
"explicit": "docs",
|
|
39
|
+
"invalid": "Error: Invalid tunnel ID "___": use letters, digits and dashes",
|
|
40
|
+
"normalized": "my-app-dev",
|
|
41
|
+
"random": 16,
|
|
42
|
+
"tuistory": "holocron-dev",
|
|
43
|
+
"tuistoryInvalid": 16,
|
|
44
|
+
}
|
|
45
|
+
`);
|
|
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
|
+
});
|
|
114
|
+
//# sourceMappingURL=tunnel.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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
|
+
"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,6 +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.6.0",
|
|
23
24
|
"@strada.sh/sdk": "^0.8.0",
|
|
24
25
|
"cron-parser": "^5.5.0",
|
|
25
26
|
"discord-api-types": "^0.38.40",
|
|
@@ -39,8 +40,7 @@
|
|
|
39
40
|
"werift": "^0.25.0",
|
|
40
41
|
"zod": "^4.4.3",
|
|
41
42
|
"zustand": "^5.0.14",
|
|
42
|
-
"errore": "^0.14.1"
|
|
43
|
-
"traforo": "^0.7.2"
|
|
43
|
+
"errore": "^0.14.1"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@opencode/cli": "2.0.29",
|
|
@@ -1,30 +1,35 @@
|
|
|
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
|
-
Localhost URLs are useless from Discord. Wrap the dev server in `kimaki tunnel` to get a public 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`.
|
|
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
|
-
-
|
|
11
|
-
-
|
|
12
|
-
- `kimaki tunnel`
|
|
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.
|
|
11
|
+
- Use random names by default. Pass `-t <name>` only for services that are safe to be publicly discoverable.
|
|
12
|
+
- `kimaki tunnel` detects the local port from the child output. Pass `--port` only when the server prints no detectable localhost URL.
|
|
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.
|
|
14
|
+
- The app gets `Host: localhost:<port>` and the public host in `X-Forwarded-Host`, so Vite needs no `allowedHosts` config.
|
|
15
|
+
- The first run on a machine creates the tunnel and waits up to a minute for its certificate.
|
|
13
16
|
|
|
14
17
|
```bash
|
|
15
18
|
# start in a named background session, wait for output, then read the tunnel URL
|
|
16
19
|
tuistory launch "kimaki tunnel -- pnpm dev" -s myapp-dev
|
|
17
|
-
tuistory -s myapp-dev wait "/
|
|
20
|
+
tuistory -s myapp-dev wait "/Tunnel: https/" --timeout 90000
|
|
18
21
|
tuistory read -s myapp-dev
|
|
19
22
|
|
|
20
|
-
# pass the public URL to the app (better-auth, Next.js, Vite; node reads process.env.
|
|
21
|
-
tuistory launch "kimaki tunnel -- sh -c 'BETTER_AUTH_URL
|
|
22
|
-
tuistory launch "kimaki tunnel -- sh -c 'APP_URL
|
|
23
|
-
tuistory launch "kimaki tunnel -- sh -c 'VITE_BASE_URL=$TRAFORO_URL exec pnpm dev'" -s myapp-dev
|
|
23
|
+
# pass the public URL to the app (better-auth, Next.js, Vite; node reads process.env.KIMAKI_TUNNEL_URL)
|
|
24
|
+
tuistory launch "kimaki tunnel -- sh -c 'BETTER_AUTH_URL=\$KIMAKI_TUNNEL_URL exec pnpm dev'" -s myapp-dev
|
|
25
|
+
tuistory launch "kimaki tunnel -- sh -c 'APP_URL=\$KIMAKI_TUNNEL_URL exec pnpm dev'" -s myapp-dev
|
|
24
26
|
|
|
25
|
-
#
|
|
27
|
+
# fixed name (only for intentionally public-safe services)
|
|
26
28
|
tuistory launch "kimaki tunnel -t holocron -- pnpm dev" -s holocron-dev
|
|
27
29
|
|
|
30
|
+
# restart the server on a known port and keep the URL
|
|
31
|
+
tuistory launch "kimaki tunnel -t holocron -p 5173 --kill -- pnpm dev --port 5173" -s holocron-dev
|
|
32
|
+
|
|
28
33
|
# list sessions; stop with Ctrl+C, then close
|
|
29
34
|
tuistory sessions
|
|
30
35
|
tuistory -s myapp-dev press ctrl c
|
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,6 +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[]
|
|
73
|
+
// `kimaki --disable-prompt`: static instruction parts left out of new sessions.
|
|
74
|
+
disabledPrompt: readonly PromptSection[]
|
|
72
75
|
features: BotFeatures
|
|
73
76
|
}
|
|
74
77
|
|