thebird 1.2.80 → 1.2.81
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/docs/kilo-fs-mirror.js +15 -0
- package/docs/kilo-http-stream.js +27 -4
- package/package.json +1 -1
- package/start-kilo.js +40 -12
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export async function mirrorFromSandbox(fsBase, _touchedPaths) {
|
|
2
|
+
const listRes = await fetch(fsBase + '/__list');
|
|
3
|
+
if (!listRes.ok) return [];
|
|
4
|
+
const relFiles = await listRes.json();
|
|
5
|
+
const snap = window.__debug.idbSnapshot || (window.__debug.idbSnapshot = {});
|
|
6
|
+
const mirrored = [];
|
|
7
|
+
for (const rel of relFiles) {
|
|
8
|
+
const r = await fetch(fsBase + '/' + rel);
|
|
9
|
+
if (!r.ok) continue;
|
|
10
|
+
const content = await r.text();
|
|
11
|
+
if (snap[rel] !== content) { snap[rel] = content; mirrored.push(rel); }
|
|
12
|
+
}
|
|
13
|
+
if (mirrored.length) { window.__debug.idbPersist?.(); window.__debug.shell?.onPreviewWrite?.(); }
|
|
14
|
+
return mirrored;
|
|
15
|
+
}
|
package/docs/kilo-http-stream.js
CHANGED
|
@@ -1,24 +1,47 @@
|
|
|
1
|
+
import { mirrorFromSandbox } from './kilo-fs-mirror.js';
|
|
2
|
+
|
|
1
3
|
export async function* streamKiloHTTP({ url, model, messages }) {
|
|
2
4
|
yield { type: 'start-step' };
|
|
3
5
|
const base = (url || 'http://localhost:4780').replace(/\/$/, '');
|
|
6
|
+
const fsBase = base.replace(/:\d+$/, ':4781');
|
|
4
7
|
let sessRes;
|
|
5
8
|
try { sessRes = await fetch(base + '/session', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' }); }
|
|
6
|
-
catch (e) { throw new Error('kilo serve not reachable at ' + base + ' — start it with: kilo
|
|
9
|
+
catch (e) { throw new Error('kilo serve not reachable at ' + base + ' — start it with: node start-kilo.js --origin ' + location.origin); }
|
|
7
10
|
if (!sessRes.ok) throw new Error('kilo /session ' + sessRes.status + ': ' + await sessRes.text());
|
|
8
11
|
const { id: sessionId } = await sessRes.json();
|
|
9
|
-
Object.assign(window.__debug = window.__debug || {}, { kilo: { sessionId, url: base, lastStatus: null } });
|
|
12
|
+
Object.assign(window.__debug = window.__debug || {}, { kilo: { sessionId, url: base, fsBase, writes: [], lastStatus: null } });
|
|
13
|
+
|
|
14
|
+
const es = new EventSource(base + '/event');
|
|
15
|
+
const pendingWrites = new Set();
|
|
16
|
+
es.onmessage = (ev) => {
|
|
17
|
+
try {
|
|
18
|
+
const msg = JSON.parse(ev.data);
|
|
19
|
+
if (msg.type === 'message.part.updated') {
|
|
20
|
+
const part = msg.properties?.part;
|
|
21
|
+
if (part?.type === 'tool' && part.state?.status === 'completed' && (part.tool === 'write' || part.tool === 'edit')) {
|
|
22
|
+
const abs = part.state.input?.filePath;
|
|
23
|
+
if (abs) pendingWrites.add(abs);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
} catch (_) {}
|
|
27
|
+
};
|
|
10
28
|
|
|
11
29
|
const userText = messages.filter(m => m.role === 'user').map(m =>
|
|
12
30
|
typeof m.content === 'string' ? m.content : (m.content || []).filter(b => b.type === 'text').map(b => b.text).join('')
|
|
13
31
|
).join('\n');
|
|
14
32
|
|
|
15
|
-
const body = { parts: [{ type: 'text', text: userText }], providerID: 'kilo', modelID: model || 'x-ai/grok-code-fast-1:optimized:free'
|
|
33
|
+
const body = { parts: [{ type: 'text', text: userText }], providerID: 'kilo', modelID: model || 'x-ai/grok-code-fast-1:optimized:free' };
|
|
16
34
|
const msgRes = await fetch(base + '/session/' + sessionId + '/message', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body) });
|
|
17
35
|
window.__debug.kilo.lastStatus = msgRes.status;
|
|
18
|
-
if (!msgRes.ok) throw new Error('kilo message ' + msgRes.status + ': ' + await msgRes.text());
|
|
36
|
+
if (!msgRes.ok) { es.close(); throw new Error('kilo message ' + msgRes.status + ': ' + await msgRes.text()); }
|
|
19
37
|
const result = await msgRes.json();
|
|
20
38
|
window.__debug.kilo.lastResult = result;
|
|
39
|
+
es.close();
|
|
40
|
+
const mirrored = await mirrorFromSandbox(fsBase, [...pendingWrites]);
|
|
41
|
+
window.__debug.kilo.writes = mirrored;
|
|
42
|
+
if (mirrored.length) window.refreshPreview?.();
|
|
21
43
|
const textParts = (result.parts || []).filter(p => p.type === 'text');
|
|
22
44
|
for (const tp of textParts) yield { type: 'text-delta', textDelta: tp.text };
|
|
45
|
+
if (mirrored.length) yield { type: 'text-delta', textDelta: '\n\n[mirrored to preview: ' + mirrored.join(', ') + ']' };
|
|
23
46
|
yield { type: 'finish-step', finishReason: result.info?.finish || 'stop' };
|
|
24
47
|
}
|
package/package.json
CHANGED
package/start-kilo.js
CHANGED
|
@@ -1,17 +1,45 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// thebird — start local Kilo Code backend for docs/ page
|
|
3
|
-
// usage: node start-kilo.js [--port 4780] [--origin http://localhost:8787]
|
|
4
2
|
const { spawn } = require('child_process');
|
|
3
|
+
const http = require('http');
|
|
4
|
+
const fs = require('fs');
|
|
5
|
+
const path = require('path');
|
|
5
6
|
const os = require('os');
|
|
6
7
|
const args = process.argv.slice(2);
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
const origin =
|
|
11
|
-
const
|
|
8
|
+
const get = (f, d) => { const i = args.indexOf(f); return i >= 0 ? args[i + 1] : d; };
|
|
9
|
+
const kiloPort = get('--port', '4780');
|
|
10
|
+
const fsPort = get('--fs-port', '4781');
|
|
11
|
+
const origin = get('--origin', 'http://localhost:8787');
|
|
12
|
+
const sandbox = path.resolve(get('--sandbox', '.sandbox'));
|
|
13
|
+
fs.mkdirSync(sandbox, { recursive: true });
|
|
12
14
|
const kiloWin = process.env.USERPROFILE + '\\AppData\\Roaming\\npm\\node_modules\\@kilocode\\cli\\node_modules\\@kilocode\\cli-windows-x64\\bin\\kilo.exe';
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
const bin = os.platform() === 'win32' && fs.existsSync(kiloWin) ? kiloWin : 'kilo';
|
|
16
|
+
const kilo = spawn(bin, ['serve', '--port', kiloPort, '--hostname', '127.0.0.1', '--cors', origin], { stdio: 'inherit', env: process.env, cwd: sandbox });
|
|
17
|
+
const cors = { 'Access-Control-Allow-Origin': origin, 'Access-Control-Allow-Methods': 'GET,OPTIONS', 'Access-Control-Allow-Headers': 'content-type' };
|
|
18
|
+
const srv = http.createServer((req, res) => {
|
|
19
|
+
if (req.method === 'OPTIONS') { res.writeHead(204, cors); res.end(); return; }
|
|
20
|
+
const rel = decodeURIComponent(req.url.replace(/^\/+/, '').split('?')[0]);
|
|
21
|
+
if (rel === '__list') {
|
|
22
|
+
const out = [];
|
|
23
|
+
const walk = d => { for (const e of fs.readdirSync(d, { withFileTypes: true })) {
|
|
24
|
+
if (e.name.startsWith('.')) continue;
|
|
25
|
+
const full = path.join(d, e.name);
|
|
26
|
+
if (e.isDirectory()) walk(full);
|
|
27
|
+
else out.push(path.relative(sandbox, full).replace(/\\/g, '/'));
|
|
28
|
+
}};
|
|
29
|
+
try { walk(sandbox); } catch (e) {}
|
|
30
|
+
res.writeHead(200, { ...cors, 'Content-Type': 'application/json' });
|
|
31
|
+
res.end(JSON.stringify(out));
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const full = path.resolve(path.join(sandbox, rel));
|
|
35
|
+
if (!full.startsWith(sandbox)) { res.writeHead(403, cors); res.end('forbidden'); return; }
|
|
36
|
+
fs.readFile(full, (err, data) => {
|
|
37
|
+
if (err) { res.writeHead(404, cors); res.end('not found'); return; }
|
|
38
|
+
const ct = { '.html': 'text/html', '.js': 'application/javascript', '.css': 'text/css', '.json': 'application/json', '.svg': 'image/svg+xml', '.png': 'image/png', '.md': 'text/plain' }[path.extname(rel)] || 'application/octet-stream';
|
|
39
|
+
res.writeHead(200, { ...cors, 'Content-Type': ct });
|
|
40
|
+
res.end(data);
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
srv.listen(fsPort, '127.0.0.1', () => console.log('[fs-bridge] sandbox=' + sandbox + ' serving http://127.0.0.1:' + fsPort));
|
|
44
|
+
kilo.on('exit', c => { srv.close(); process.exit(c || 0); });
|
|
45
|
+
process.on('SIGINT', () => { kilo.kill(); srv.close(); });
|