mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-07-10 01:39:25 +00:00
* feat(agent-core): re-export wire record types for in-monorepo consumers * chore(vis): purge legacy wire protocol code * feat(vis): introduce single-source agent-record types * test(vis): add fixture session and builder helper * feat(vis): implement new session store reader * feat(vis): wire new session list/detail routes * refactor(vis): drop legacy path config * feat(vis): adapt session list page to new DTO * feat(vis): implement per-agent wire reader * feat(vis): rewrite wire route for new protocol * feat(vis): rewrite wire type metadata for new protocol * feat(vis): rewrite wire row + headline for new record union * feat(vis): wire tab detail panel + multi-agent selector * feat(vis): rebuild wire issues detection for new protocol * feat(vis): implement context projector * feat(vis): rewrite context route on projector * feat(vis): rebuild context tab for new ContextMessage shape * feat(vis): implement agent tree builder * feat(vis): rewrite agents route * feat(vis): rebuild subagents tab around state.json.agents * feat(vis): rebuild state tab on raw state.json * chore(vis): purge residual legacy field references * vis: rewrite complete on new agent-core protocol * fix(vis): adapt to wire protocol 1.1 with flattened tool calls * fix(vis): populate workDir from session index * fix(vis): return broken-state sessions from detail lookup * fix(vis): tolerate per-session wire read failures during listing * fix(vis): read wire files from canonical session path * feat(vis): restore session detail page with full tab layout * feat(vis): wire subagent context tab to real ContextTab * fix(vis): sync wire and context tab agentId with prop changes * feat(vis): auto-pick a free dev port when 3001 is busy * feat(vis): accept v1.0 wire files via agent-core migration chain * refactor(vis): default API to 5174 and pick a non-colliding vite port * feat(vis): make long strings expandable with copy in JsonViewer * fix(vis): stop gating session health on protocol version * refactor(vis): split wire records into raw + projected; best-effort unknown protocol * feat(vis): pair tool.call with tool.result via inline cross-reference and hover highlight * feat(vis): open session folder and copy its path from the detail header * fix(vis): reconstruct assistant and tool messages from loop events * fix(vis): keep system prompt bubble within the message column width * feat(vis): collapse tool result bubble by default in context view * feat(vis): expose broken_main_wire in the session health filter * fix(vis): reset wire and context tab agent when navigating sessions * fix(vis): fall back to a generic headline for unknown wire record types * fix(vis): emit compaction summary as an assistant message with origin * fix(vis): harden session-store reads for broken wires, broken state, and path-traversal agent ids * feat(vis): inline image previews for image_url content parts
70 lines
2.1 KiB
JavaScript
70 lines
2.1 KiB
JavaScript
#!/usr/bin/env node
|
|
// Wraps `concurrently` so the vis-server (API) and vite (web) each pick a
|
|
// free port and agree on each other's, even when the defaults are taken by
|
|
// a previous dev session or another local app.
|
|
|
|
import { spawn } from 'node:child_process';
|
|
import net from 'node:net';
|
|
|
|
const DEFAULT_API_PORT = 5174;
|
|
const DEFAULT_WEB_PORT = 5173;
|
|
const MAX_PROBE = 50;
|
|
|
|
async function isFree(port) {
|
|
return new Promise((resolve) => {
|
|
const srv = net.createServer();
|
|
srv.unref();
|
|
srv.once('error', () => {
|
|
resolve(false);
|
|
});
|
|
srv.once('listening', () => {
|
|
srv.close(() => {
|
|
resolve(true);
|
|
});
|
|
});
|
|
srv.listen({ port, host: '127.0.0.1', exclusive: true });
|
|
});
|
|
}
|
|
|
|
async function pickPort(startPort, exclude = new Set()) {
|
|
for (let port = startPort; port < startPort + MAX_PROBE; port += 1) {
|
|
if (exclude.has(port)) continue;
|
|
// eslint-disable-next-line no-await-in-loop
|
|
if (await isFree(port)) return port;
|
|
}
|
|
throw new Error(
|
|
`no free port in [${startPort}, ${startPort + MAX_PROBE}); something is hogging the range`,
|
|
);
|
|
}
|
|
|
|
const requestedApi = Number(process.env.PORT) || DEFAULT_API_PORT;
|
|
const apiPort = await pickPort(requestedApi);
|
|
if (apiPort !== requestedApi) {
|
|
process.stdout.write(`[vis] api port ${requestedApi} busy, using ${apiPort} instead\n`);
|
|
}
|
|
|
|
const requestedWeb = Number(process.env.WEB_PORT) || DEFAULT_WEB_PORT;
|
|
const webPort = await pickPort(requestedWeb, new Set([apiPort]));
|
|
if (webPort !== requestedWeb) {
|
|
process.stdout.write(`[vis] web port ${requestedWeb} busy, using ${webPort} instead\n`);
|
|
}
|
|
|
|
process.stdout.write(`[vis] web → http://localhost:${webPort} (api on ${apiPort})\n`);
|
|
|
|
const env = { ...process.env, PORT: String(apiPort), WEB_PORT: String(webPort) };
|
|
const child = spawn(
|
|
'concurrently',
|
|
[
|
|
'-k',
|
|
'-n', 'server,web',
|
|
'-c', 'cyan,magenta',
|
|
'pnpm --filter @moonshot-ai/vis-server dev',
|
|
'pnpm --filter @moonshot-ai/vis-web dev',
|
|
],
|
|
{ stdio: 'inherit', env, shell: false },
|
|
);
|
|
|
|
child.on('exit', (code, signal) => {
|
|
if (signal !== null) process.kill(process.pid, signal);
|
|
else process.exit(code ?? 0);
|
|
});
|