c0de-agent 0.0.0 → 1.1.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/LICENSE +21 -0
- package/README.md +101 -0
- package/dist/cli/commands/acp.d.ts +19 -0
- package/dist/cli/commands/acp.js +50 -0
- package/dist/cli/commands/chat.d.ts +13 -0
- package/dist/cli/commands/chat.js +26 -0
- package/dist/cli/commands/config.d.ts +17 -0
- package/dist/cli/commands/config.js +77 -0
- package/dist/cli/commands/init.d.ts +9 -0
- package/dist/cli/commands/init.js +14 -0
- package/dist/cli/commands/plugin.d.ts +11 -0
- package/dist/cli/commands/plugin.js +31 -0
- package/dist/cli/commands/serve.d.ts +18 -0
- package/dist/cli/commands/serve.js +35 -0
- package/dist/cli/commands/update.d.ts +24 -0
- package/dist/cli/commands/update.js +40 -0
- package/dist/cli/deps.d.ts +30 -0
- package/dist/cli/deps.js +70 -0
- package/dist/cli/index.d.ts +8 -0
- package/dist/cli/index.js +155 -0
- package/dist/cli/modes/acp.d.ts +18 -0
- package/dist/cli/modes/acp.js +57 -0
- package/dist/cli/modes/print.d.ts +16 -0
- package/dist/cli/modes/print.js +30 -0
- package/dist/cli/parser.d.ts +19 -0
- package/dist/cli/parser.js +28 -0
- package/dist/cli/utils/output.d.ts +11 -0
- package/dist/cli/utils/output.js +23 -0
- package/dist/cli/utils/prompt.d.ts +12 -0
- package/dist/cli/utils/prompt.js +18 -0
- package/dist/core/agent.d.ts +12 -0
- package/dist/core/agent.js +100 -0
- package/dist/core/agents/builtin.d.ts +6 -0
- package/dist/core/agents/builtin.js +76 -0
- package/dist/core/agents/discovery.d.ts +6 -0
- package/dist/core/agents/discovery.js +96 -0
- package/dist/core/agents/index.d.ts +6 -0
- package/dist/core/agents/index.js +4 -0
- package/dist/core/agents/parallel.d.ts +13 -0
- package/dist/core/agents/parallel.js +37 -0
- package/dist/core/agents/registry.d.ts +4 -0
- package/dist/core/agents/registry.js +23 -0
- package/dist/core/agents/types.d.ts +37 -0
- package/dist/core/agents/types.js +1 -0
- package/dist/core/compact.d.ts +11 -0
- package/dist/core/compact.js +31 -0
- package/dist/core/config.d.ts +7 -0
- package/dist/core/config.js +85 -0
- package/dist/core/context.d.ts +23 -0
- package/dist/core/context.js +93 -0
- package/dist/core/index.d.ts +13 -0
- package/dist/core/index.js +11 -0
- package/dist/core/loop.d.ts +35 -0
- package/dist/core/loop.js +915 -0
- package/dist/core/metrics.d.ts +27 -0
- package/dist/core/metrics.js +94 -0
- package/dist/core/prompt-registry.d.ts +21 -0
- package/dist/core/prompt-registry.js +200 -0
- package/dist/core/prompt.d.ts +11 -0
- package/dist/core/prompt.js +13 -0
- package/dist/core/secret.d.ts +12 -0
- package/dist/core/secret.js +51 -0
- package/dist/core/slash.d.ts +15 -0
- package/dist/core/slash.js +113 -0
- package/dist/core/steering.d.ts +8 -0
- package/dist/core/steering.js +15 -0
- package/dist/core/title.d.ts +42 -0
- package/dist/core/title.js +116 -0
- package/dist/core/tool-exec.d.ts +20 -0
- package/dist/core/tool-exec.js +64 -0
- package/dist/core/types.d.ts +97 -0
- package/dist/core/types.js +1 -0
- package/dist/core/worktree.d.ts +24 -0
- package/dist/core/worktree.js +70 -0
- package/dist/dap/index.d.ts +6 -0
- package/dist/dap/index.js +4 -0
- package/dist/dap/protocol.d.ts +40 -0
- package/dist/dap/protocol.js +132 -0
- package/dist/dap/session.d.ts +23 -0
- package/dist/dap/session.js +130 -0
- package/dist/dap/transport.d.ts +8 -0
- package/dist/dap/transport.js +30 -0
- package/dist/dap/types.d.ts +50 -0
- package/dist/dap/types.js +2 -0
- package/dist/db/client.d.ts +22 -0
- package/dist/db/client.js +39 -0
- package/dist/db/index.d.ts +6 -0
- package/dist/db/index.js +4 -0
- package/dist/db/migrate.d.ts +9 -0
- package/dist/db/migrate.js +15 -0
- package/dist/db/schema.d.ts +965 -0
- package/dist/db/schema.js +112 -0
- package/dist/db/types.d.ts +11 -0
- package/dist/db/types.js +1 -0
- package/dist/llm/index.d.ts +13 -0
- package/dist/llm/index.js +8 -0
- package/dist/llm/protocols/openai-compat.d.ts +139 -0
- package/dist/llm/protocols/openai-compat.js +214 -0
- package/dist/llm/protocols/utils/index.d.ts +2 -0
- package/dist/llm/protocols/utils/index.js +2 -0
- package/dist/llm/protocols/utils/lifecycle.d.ts +23 -0
- package/dist/llm/protocols/utils/lifecycle.js +46 -0
- package/dist/llm/protocols/utils/tool-stream.d.ts +46 -0
- package/dist/llm/protocols/utils/tool-stream.js +94 -0
- package/dist/llm/provider-error.d.ts +5 -0
- package/dist/llm/provider-error.js +33 -0
- package/dist/llm/provider.d.ts +32 -0
- package/dist/llm/provider.js +195 -0
- package/dist/llm/registry.d.ts +44 -0
- package/dist/llm/registry.js +107 -0
- package/dist/llm/retry.d.ts +37 -0
- package/dist/llm/retry.js +82 -0
- package/dist/llm/routing.d.ts +36 -0
- package/dist/llm/routing.js +53 -0
- package/dist/llm/schema/errors.d.ts +88 -0
- package/dist/llm/schema/errors.js +33 -0
- package/dist/llm/schema/events.d.ts +135 -0
- package/dist/llm/schema/events.js +35 -0
- package/dist/llm/schema/ids.d.ts +22 -0
- package/dist/llm/schema/ids.js +3 -0
- package/dist/llm/schema/index.d.ts +5 -0
- package/dist/llm/schema/index.js +5 -0
- package/dist/llm/schema/messages.d.ts +97 -0
- package/dist/llm/schema/messages.js +18 -0
- package/dist/llm/schema/options.d.ts +54 -0
- package/dist/llm/schema/options.js +54 -0
- package/dist/llm/token.d.ts +2 -0
- package/dist/llm/token.js +13 -0
- package/dist/llm/transport.d.ts +31 -0
- package/dist/llm/transport.js +165 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.js +3 -0
- package/dist/plugins/builtin.d.ts +6 -0
- package/dist/plugins/builtin.js +54 -0
- package/dist/plugins/hooks.d.ts +3 -0
- package/dist/plugins/hooks.js +79 -0
- package/dist/plugins/index.d.ts +9 -0
- package/dist/plugins/index.js +8 -0
- package/dist/plugins/init.d.ts +23 -0
- package/dist/plugins/init.js +30 -0
- package/dist/plugins/lifecycle.d.ts +6 -0
- package/dist/plugins/lifecycle.js +74 -0
- package/dist/plugins/loader.d.ts +16 -0
- package/dist/plugins/loader.js +69 -0
- package/dist/plugins/logger.d.ts +4 -0
- package/dist/plugins/logger.js +31 -0
- package/dist/plugins/registry.d.ts +7 -0
- package/dist/plugins/registry.js +24 -0
- package/dist/plugins/types.d.ts +113 -0
- package/dist/plugins/types.js +1 -0
- package/dist/project/detect.d.ts +4 -0
- package/dist/project/detect.js +131 -0
- package/dist/project/index.d.ts +4 -0
- package/dist/project/index.js +2 -0
- package/dist/project/project.d.ts +23 -0
- package/dist/project/project.js +87 -0
- package/dist/project/resolve.d.ts +8 -0
- package/dist/project/resolve.js +81 -0
- package/dist/server/agent-manager.d.ts +34 -0
- package/dist/server/agent-manager.js +62 -0
- package/dist/server/app.d.ts +5 -0
- package/dist/server/app.js +78 -0
- package/dist/server/context.d.ts +20 -0
- package/dist/server/context.js +49 -0
- package/dist/server/dev.d.ts +14 -0
- package/dist/server/dev.js +148 -0
- package/dist/server/index.d.ts +11 -0
- package/dist/server/index.js +7 -0
- package/dist/server/middleware/auth.d.ts +15 -0
- package/dist/server/middleware/auth.js +29 -0
- package/dist/server/middleware/cors.d.ts +16 -0
- package/dist/server/middleware/cors.js +44 -0
- package/dist/server/middleware/error.d.ts +15 -0
- package/dist/server/middleware/error.js +11 -0
- package/dist/server/permission/interactive.d.ts +24 -0
- package/dist/server/permission/interactive.js +56 -0
- package/dist/server/permission/store.d.ts +32 -0
- package/dist/server/permission/store.js +56 -0
- package/dist/server/routes/agent.d.ts +4 -0
- package/dist/server/routes/agent.js +19 -0
- package/dist/server/routes/catalog.d.ts +42 -0
- package/dist/server/routes/catalog.js +194 -0
- package/dist/server/routes/chat.d.ts +8 -0
- package/dist/server/routes/chat.js +318 -0
- package/dist/server/routes/commands.d.ts +5 -0
- package/dist/server/routes/commands.js +17 -0
- package/dist/server/routes/config.d.ts +4 -0
- package/dist/server/routes/config.js +27 -0
- package/dist/server/routes/files.d.ts +4 -0
- package/dist/server/routes/files.js +183 -0
- package/dist/server/routes/filesystem.d.ts +29 -0
- package/dist/server/routes/filesystem.js +108 -0
- package/dist/server/routes/health.d.ts +3 -0
- package/dist/server/routes/health.js +13 -0
- package/dist/server/routes/permissions.d.ts +5 -0
- package/dist/server/routes/permissions.js +23 -0
- package/dist/server/routes/project.d.ts +4 -0
- package/dist/server/routes/project.js +51 -0
- package/dist/server/routes/provider.d.ts +16 -0
- package/dist/server/routes/provider.js +66 -0
- package/dist/server/routes/session.d.ts +4 -0
- package/dist/server/routes/session.js +204 -0
- package/dist/server/routes/terminal.d.ts +5 -0
- package/dist/server/routes/terminal.js +66 -0
- package/dist/server/routes/tool.d.ts +4 -0
- package/dist/server/routes/tool.js +28 -0
- package/dist/server/routes/update.d.ts +14 -0
- package/dist/server/routes/update.js +49 -0
- package/dist/server/server.d.ts +56 -0
- package/dist/server/server.js +269 -0
- package/dist/server/terminal/pty-manager.d.ts +53 -0
- package/dist/server/terminal/pty-manager.js +160 -0
- package/dist/server/types.d.ts +76 -0
- package/dist/server/types.js +2 -0
- package/dist/server/util/safe-path.d.ts +7 -0
- package/dist/server/util/safe-path.js +7 -0
- package/dist/session/archive.d.ts +15 -0
- package/dist/session/archive.js +129 -0
- package/dist/session/branch.d.ts +9 -0
- package/dist/session/branch.js +63 -0
- package/dist/session/compaction.d.ts +33 -0
- package/dist/session/compaction.js +261 -0
- package/dist/session/context.d.ts +16 -0
- package/dist/session/context.js +173 -0
- package/dist/session/index.d.ts +10 -0
- package/dist/session/index.js +10 -0
- package/dist/session/message.d.ts +22 -0
- package/dist/session/message.js +145 -0
- package/dist/session/session.d.ts +37 -0
- package/dist/session/session.js +144 -0
- package/dist/session/shake.d.ts +66 -0
- package/dist/session/shake.js +304 -0
- package/dist/session/snapshot.d.ts +11 -0
- package/dist/session/snapshot.js +60 -0
- package/dist/session/squash.d.ts +9 -0
- package/dist/session/squash.js +88 -0
- package/dist/session/token.d.ts +10 -0
- package/dist/session/token.js +33 -0
- package/dist/session/types.d.ts +122 -0
- package/dist/session/types.js +1 -0
- package/dist/shared/index.d.ts +2 -0
- package/dist/shared/index.js +1 -0
- package/dist/shared/types/agent.d.ts +229 -0
- package/dist/shared/types/agent.js +1 -0
- package/dist/shared/types/base.d.ts +32 -0
- package/dist/shared/types/base.js +1 -0
- package/dist/shared/types/config.d.ts +114 -0
- package/dist/shared/types/config.js +1 -0
- package/dist/shared/types/index.d.ts +6 -0
- package/dist/shared/types/index.js +1 -0
- package/dist/shared/types/llm.d.ts +123 -0
- package/dist/shared/types/llm.js +1 -0
- package/dist/shared/types/message.d.ts +71 -0
- package/dist/shared/types/message.js +1 -0
- package/dist/shared/types/tool.d.ts +137 -0
- package/dist/shared/types/tool.js +1 -0
- package/dist/shared/utils/path.d.ts +15 -0
- package/dist/shared/utils/path.js +23 -0
- package/dist/shared/utils.d.ts +5 -0
- package/dist/shared/utils.js +10 -0
- package/dist/tools/builtin/bash.d.ts +12 -0
- package/dist/tools/builtin/bash.js +121 -0
- package/dist/tools/builtin/dap.d.ts +23 -0
- package/dist/tools/builtin/dap.js +231 -0
- package/dist/tools/builtin/edit.d.ts +12 -0
- package/dist/tools/builtin/edit.js +151 -0
- package/dist/tools/builtin/glob.d.ts +11 -0
- package/dist/tools/builtin/glob.js +120 -0
- package/dist/tools/builtin/grep.d.ts +6 -0
- package/dist/tools/builtin/grep.js +141 -0
- package/dist/tools/builtin/read.d.ts +6 -0
- package/dist/tools/builtin/read.js +73 -0
- package/dist/tools/builtin/resolvers.d.ts +12 -0
- package/dist/tools/builtin/resolvers.js +79 -0
- package/dist/tools/builtin/task.d.ts +9 -0
- package/dist/tools/builtin/task.js +100 -0
- package/dist/tools/builtin/write.d.ts +6 -0
- package/dist/tools/builtin/write.js +36 -0
- package/dist/tools/builtin/yield.d.ts +9 -0
- package/dist/tools/builtin/yield.js +40 -0
- package/dist/tools/executor.d.ts +9 -0
- package/dist/tools/executor.js +54 -0
- package/dist/tools/hashline/index.d.ts +2 -0
- package/dist/tools/hashline/index.js +3 -0
- package/dist/tools/hashline/patch.d.ts +48 -0
- package/dist/tools/hashline/patch.js +201 -0
- package/dist/tools/index.d.ts +30 -0
- package/dist/tools/index.js +55 -0
- package/dist/tools/permission.d.ts +13 -0
- package/dist/tools/permission.js +39 -0
- package/dist/tools/registry.d.ts +15 -0
- package/dist/tools/registry.js +54 -0
- package/dist/tools/resolver.d.ts +15 -0
- package/dist/tools/resolver.js +47 -0
- package/dist/tools/truncate.d.ts +8 -0
- package/dist/tools/truncate.js +50 -0
- package/dist/tools/types.d.ts +101 -0
- package/dist/tools/types.js +1 -0
- package/dist/tools/validate.d.ts +8 -0
- package/dist/tools/validate.js +130 -0
- package/dist/tools/websearch/fetch.d.ts +11 -0
- package/dist/tools/websearch/fetch.js +21 -0
- package/dist/tools/websearch/index.d.ts +19 -0
- package/dist/tools/websearch/index.js +78 -0
- package/dist/tools/websearch/providers/brave.d.ts +5 -0
- package/dist/tools/websearch/providers/brave.js +53 -0
- package/dist/tools/websearch/providers/duckduckgo.d.ts +3 -0
- package/dist/tools/websearch/providers/duckduckgo.js +75 -0
- package/dist/tools/websearch/providers/tavily.d.ts +11 -0
- package/dist/tools/websearch/providers/tavily.js +89 -0
- package/dist/tools/websearch/types.d.ts +51 -0
- package/dist/tools/websearch/types.js +18 -0
- package/dist/tools/websearch/websearch.d.ts +10 -0
- package/dist/tools/websearch/websearch.js +48 -0
- package/dist/update/index.d.ts +10 -0
- package/dist/update/index.js +6 -0
- package/dist/update/ipc.d.ts +15 -0
- package/dist/update/ipc.js +41 -0
- package/dist/update/scheduler.d.ts +34 -0
- package/dist/update/scheduler.js +57 -0
- package/dist/update/snapshot.d.ts +39 -0
- package/dist/update/snapshot.js +99 -0
- package/dist/update/updater.d.ts +48 -0
- package/dist/update/updater.js +83 -0
- package/dist/update/version.d.ts +18 -0
- package/dist/update/version.js +49 -0
- package/drizzle/0000_magical_nightshade.sql +55 -0
- package/drizzle/0001_chemical_doctor_faustus.sql +13 -0
- package/drizzle/0002_amusing_micromacro.sql +12 -0
- package/drizzle/0003_regular_purifiers.sql +2 -0
- package/drizzle/meta/0000_snapshot.json +448 -0
- package/drizzle/meta/0001_snapshot.json +539 -0
- package/drizzle/meta/0002_snapshot.json +633 -0
- package/drizzle/meta/0003_snapshot.json +645 -0
- package/drizzle/meta/_journal.json +34 -0
- package/package.json +108 -8
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { createSummarizer, runCompaction } from '../../core/compact.js';
|
|
3
|
+
import { fromDirectory } from '../../project/index.js';
|
|
4
|
+
import { archiveOriginalEntries } from '../../session/archive.js';
|
|
5
|
+
import { forkSession, getBranches, getTree } from '../../session/branch.js';
|
|
6
|
+
import { deleteEntriesByIds, getMessages, insertEntry } from '../../session/message.js';
|
|
7
|
+
import { createSession, deleteSession, getLLMSegments, getSession, listSessions, listSessionsByProject, } from '../../session/session.js';
|
|
8
|
+
import { applyShakeRegions, collectShakeRegions, DEFAULT_SHAKE_CONFIG, toRegionViews, } from '../../session/shake.js';
|
|
9
|
+
import { estimateMessageTokens } from '../../session/token.js';
|
|
10
|
+
import { generateId } from '../../shared/index.js';
|
|
11
|
+
import { apiError } from '../middleware/error.js';
|
|
12
|
+
function createSessionRoute(ctx) {
|
|
13
|
+
const app = new Hono();
|
|
14
|
+
// 创建会话
|
|
15
|
+
app.post('/', async (c) => {
|
|
16
|
+
const body = await c.req.json().catch(() => ({}));
|
|
17
|
+
const title = body.title ?? 'New Session';
|
|
18
|
+
const directory = body.directory;
|
|
19
|
+
const explicitProjectId = body.projectId;
|
|
20
|
+
let projectId;
|
|
21
|
+
if (directory) {
|
|
22
|
+
const project = await fromDirectory(ctx.db, directory);
|
|
23
|
+
projectId = project.id;
|
|
24
|
+
}
|
|
25
|
+
else if (explicitProjectId) {
|
|
26
|
+
projectId = explicitProjectId;
|
|
27
|
+
}
|
|
28
|
+
const session = await createSession(ctx.db, title, projectId);
|
|
29
|
+
return c.json(session, 201);
|
|
30
|
+
});
|
|
31
|
+
// 列出会话
|
|
32
|
+
app.get('/', async (c) => {
|
|
33
|
+
const projectId = c.req.query('projectId');
|
|
34
|
+
const sessions = projectId
|
|
35
|
+
? await listSessionsByProject(ctx.db, projectId)
|
|
36
|
+
: await listSessions(ctx.db);
|
|
37
|
+
return c.json(sessions);
|
|
38
|
+
});
|
|
39
|
+
// 会话树
|
|
40
|
+
app.get('/tree', async (c) => {
|
|
41
|
+
const tree = await getTree(ctx.db);
|
|
42
|
+
return c.json(tree);
|
|
43
|
+
});
|
|
44
|
+
// 获取会话详情
|
|
45
|
+
app.get('/:id', async (c) => {
|
|
46
|
+
try {
|
|
47
|
+
const session = await getSession(ctx.db, c.req.param('id'));
|
|
48
|
+
if (!session) {
|
|
49
|
+
return apiError(c, 404, 'NOT_FOUND', 'Session not found');
|
|
50
|
+
}
|
|
51
|
+
return c.json(session);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return apiError(c, 404, 'NOT_FOUND', 'Session not found');
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
// 分支会话
|
|
58
|
+
app.post('/:id/fork', async (c) => {
|
|
59
|
+
const id = c.req.param('id');
|
|
60
|
+
const body = await c.req.json().catch(() => ({}));
|
|
61
|
+
const messageIndex = body.messageIndex ?? 0;
|
|
62
|
+
try {
|
|
63
|
+
const forked = await forkSession(ctx.db, id, messageIndex);
|
|
64
|
+
return c.json(forked, 201);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return apiError(c, 404, 'NOT_FOUND', 'Session not found');
|
|
68
|
+
}
|
|
69
|
+
});
|
|
70
|
+
// 删除会话
|
|
71
|
+
app.delete('/:id', async (c) => {
|
|
72
|
+
await deleteSession(ctx.db, c.req.param('id'));
|
|
73
|
+
return c.body(null, 204);
|
|
74
|
+
});
|
|
75
|
+
// 获取消息列表
|
|
76
|
+
app.get('/:id/messages', async (c) => {
|
|
77
|
+
const messages = await getMessages(ctx.db, c.req.param('id'));
|
|
78
|
+
return c.json(messages);
|
|
79
|
+
});
|
|
80
|
+
// 获取 LLM 调用分段(段首快照 + 段内轻量 calls):优先取活跃 run 的内存记录(实时),回退 DB 持久化
|
|
81
|
+
app.get('/:id/llm-details', async (c) => {
|
|
82
|
+
const run = ctx.agentManager.get(c.req.param('id'));
|
|
83
|
+
if (run)
|
|
84
|
+
return c.json(run.state.segments);
|
|
85
|
+
const persisted = await getLLMSegments(ctx.db, c.req.param('id'));
|
|
86
|
+
return c.json(persisted);
|
|
87
|
+
});
|
|
88
|
+
// 手动触发会话压缩(段切换确认弹窗「顺便压缩」调用)。用末段的 provider/model 构建摘要器。
|
|
89
|
+
app.post('/:id/compact', async (c) => {
|
|
90
|
+
const id = c.req.param('id');
|
|
91
|
+
let session;
|
|
92
|
+
try {
|
|
93
|
+
session = await getSession(ctx.db, id);
|
|
94
|
+
}
|
|
95
|
+
catch {
|
|
96
|
+
return apiError(c, 404, 'NOT_FOUND', 'Session not found');
|
|
97
|
+
}
|
|
98
|
+
if (!session)
|
|
99
|
+
return apiError(c, 404, 'NOT_FOUND', 'Session not found');
|
|
100
|
+
const segs = await getLLMSegments(ctx.db, id);
|
|
101
|
+
const lastSeg = segs[segs.length - 1];
|
|
102
|
+
const provider = lastSeg?.provider ?? ctx.config.defaultProvider;
|
|
103
|
+
const model = lastSeg?.model ?? ctx.config.defaultModel;
|
|
104
|
+
try {
|
|
105
|
+
const summarizer = createSummarizer(ctx.llmRegistry, provider, model, {});
|
|
106
|
+
const result = await runCompaction(ctx.db, id, summarizer, {
|
|
107
|
+
keepRecentTokens: ctx.config.compaction.keepRecentTokens,
|
|
108
|
+
});
|
|
109
|
+
return c.json(result);
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
return apiError(c, 500, 'COMPACTION_FAILED', e instanceof Error ? e.message : 'Compaction failed');
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
// 获取会话状态:内存有活跃 run → 返回其 status;否则查 DB lastRun。
|
|
116
|
+
// lastRun.status='running' 但无活跃 run → 服务重启被中断。
|
|
117
|
+
app.get('/:id/status', async (c) => {
|
|
118
|
+
const run = ctx.agentManager.get(c.req.param('id'));
|
|
119
|
+
if (run)
|
|
120
|
+
return c.json(run.state.status);
|
|
121
|
+
const session = await getSession(ctx.db, c.req.param('id'));
|
|
122
|
+
if (session?.metadata.lastRun?.status === 'running') {
|
|
123
|
+
return c.json({ _tag: 'interrupted' });
|
|
124
|
+
}
|
|
125
|
+
return c.json({ _tag: 'idle' });
|
|
126
|
+
});
|
|
127
|
+
// shake preview:返回可 shake 的区域列表
|
|
128
|
+
app.post('/:id/shake/preview', async (c) => {
|
|
129
|
+
const id = c.req.param('id');
|
|
130
|
+
let session;
|
|
131
|
+
try {
|
|
132
|
+
session = await getSession(ctx.db, id);
|
|
133
|
+
}
|
|
134
|
+
catch {
|
|
135
|
+
return apiError(c, 404, 'NOT_FOUND', 'Session not found');
|
|
136
|
+
}
|
|
137
|
+
if (!session)
|
|
138
|
+
return apiError(c, 404, 'NOT_FOUND', 'Session not found');
|
|
139
|
+
const messages = await getMessages(ctx.db, id);
|
|
140
|
+
// Manual shake: show ALL candidates (protectTokens=0, minSavings=0).
|
|
141
|
+
// toRegionViews still marks isAfterProtectWindow using the real config.
|
|
142
|
+
const manualConfig = { ...DEFAULT_SHAKE_CONFIG, protectTokens: 0, minSavings: 0 };
|
|
143
|
+
const regions = collectShakeRegions(messages, manualConfig);
|
|
144
|
+
const views = toRegionViews(regions, DEFAULT_SHAKE_CONFIG, messages);
|
|
145
|
+
return c.json({ regions: views });
|
|
146
|
+
});
|
|
147
|
+
// shake apply:归档原始内容 + 原位替换
|
|
148
|
+
app.post('/:id/shake/apply', async (c) => {
|
|
149
|
+
const id = c.req.param('id');
|
|
150
|
+
let session;
|
|
151
|
+
try {
|
|
152
|
+
session = await getSession(ctx.db, id);
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return apiError(c, 404, 'NOT_FOUND', 'Session not found');
|
|
156
|
+
}
|
|
157
|
+
if (!session)
|
|
158
|
+
return apiError(c, 404, 'NOT_FOUND', 'Session not found');
|
|
159
|
+
const body = await c.req.json().catch(() => ({}));
|
|
160
|
+
const regionIds = body.regionIds ?? [];
|
|
161
|
+
const messages = await getMessages(ctx.db, id);
|
|
162
|
+
const manualConfig = { ...DEFAULT_SHAKE_CONFIG, protectTokens: 0, minSavings: 0 };
|
|
163
|
+
const regions = collectShakeRegions(messages, manualConfig);
|
|
164
|
+
// 校验:所有 regionIds 必须命中当前 preview 结果(原子性)
|
|
165
|
+
const availableIds = new Set(regions.map((r) => r.id));
|
|
166
|
+
const unknownIds = regionIds.filter((rid) => !availableIds.has(rid));
|
|
167
|
+
if (unknownIds.length > 0) {
|
|
168
|
+
return apiError(c, 400, 'INVALID_REGIONS', '消息已变化,请重新预览');
|
|
169
|
+
}
|
|
170
|
+
const selectedSet = new Set(regionIds);
|
|
171
|
+
const selected = regions.filter((r) => selectedSet.has(r.id));
|
|
172
|
+
if (selected.length === 0) {
|
|
173
|
+
return c.json({ shaken: 0, archiveId: '' });
|
|
174
|
+
}
|
|
175
|
+
const affectedIds = [...new Set(selected.map((r) => r.messageId))];
|
|
176
|
+
const originalMessages = messages.filter((m) => affectedIds.includes(m.id));
|
|
177
|
+
const archiveId = generateId();
|
|
178
|
+
const totalTokens = selected.reduce((sum, r) => sum + r.tokens, 0);
|
|
179
|
+
await archiveOriginalEntries(ctx.db, id, originalMessages, 'shake', `Shaken ${selected.length} regions, saved ${totalTokens} tokens`, archiveId);
|
|
180
|
+
const shakenMessages = applyShakeRegions(messages, selected);
|
|
181
|
+
await deleteEntriesByIds(ctx.db, affectedIds);
|
|
182
|
+
for (const msg of shakenMessages) {
|
|
183
|
+
if (!affectedIds.includes(msg.id))
|
|
184
|
+
continue;
|
|
185
|
+
await insertEntry(ctx.db, {
|
|
186
|
+
id: msg.id,
|
|
187
|
+
sessionId: id,
|
|
188
|
+
tag: 'message',
|
|
189
|
+
role: msg.role,
|
|
190
|
+
content: msg.content,
|
|
191
|
+
tokenCount: estimateMessageTokens(msg.content),
|
|
192
|
+
createdAt: new Date(msg.createdAt),
|
|
193
|
+
});
|
|
194
|
+
}
|
|
195
|
+
return c.json({ shaken: selected.length, archiveId });
|
|
196
|
+
});
|
|
197
|
+
// 获取分支
|
|
198
|
+
app.get('/:id/branches', async (c) => {
|
|
199
|
+
const branches = await getBranches(ctx.db, c.req.param('id'));
|
|
200
|
+
return c.json(branches);
|
|
201
|
+
});
|
|
202
|
+
return app;
|
|
203
|
+
}
|
|
204
|
+
export { createSessionRoute };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
// src/server/routes/terminal.ts
|
|
2
|
+
import { Hono } from 'hono';
|
|
3
|
+
import { apiError } from '../middleware/error.js';
|
|
4
|
+
/** 创建终端路由(REST 部分;WebSocket 升级在 server.ts 中处理)。 */
|
|
5
|
+
function createTerminalRoute(ctx) {
|
|
6
|
+
const app = new Hono();
|
|
7
|
+
const mgr = ctx.ptyManager;
|
|
8
|
+
// 列出所有活跃 PTY
|
|
9
|
+
app.get('/', (c) => {
|
|
10
|
+
return c.json({ terminals: mgr.list() });
|
|
11
|
+
});
|
|
12
|
+
// 创建新 PTY 会话
|
|
13
|
+
app.post('/', async (c) => {
|
|
14
|
+
const body = await c.req.json().catch(() => ({}));
|
|
15
|
+
const cwd = typeof body.cwd === 'string' && body.cwd.length > 0 ? body.cwd : ctx.cwd;
|
|
16
|
+
const cols = Number.isFinite(body.cols) ? Number(body.cols) : undefined;
|
|
17
|
+
const rows = Number.isFinite(body.rows) ? Number(body.rows) : undefined;
|
|
18
|
+
const title = typeof body.title === 'string' ? body.title : undefined;
|
|
19
|
+
const shell = typeof body.shell === 'string' && body.shell.length > 0 ? body.shell : undefined;
|
|
20
|
+
try {
|
|
21
|
+
const info = mgr.create({ cwd, cols, rows, title, shell });
|
|
22
|
+
return c.json(info, 201);
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
const message = err instanceof Error ? err.message : 'Failed to create terminal';
|
|
26
|
+
return apiError(c, 500, 'PTY_CREATE_FAILED', message);
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
// 获取单个 PTY 信息
|
|
30
|
+
app.get('/:id', (c) => {
|
|
31
|
+
const info = mgr.get(c.req.param('id'));
|
|
32
|
+
if (!info)
|
|
33
|
+
return apiError(c, 404, 'PTY_NOT_FOUND', 'Terminal not found');
|
|
34
|
+
return c.json(info);
|
|
35
|
+
});
|
|
36
|
+
// 调整尺寸 / 更新标题
|
|
37
|
+
app.put('/:id', async (c) => {
|
|
38
|
+
const id = c.req.param('id');
|
|
39
|
+
const info = mgr.get(id);
|
|
40
|
+
if (!info)
|
|
41
|
+
return apiError(c, 404, 'PTY_NOT_FOUND', 'Terminal not found');
|
|
42
|
+
const body = await c.req.json().catch(() => ({}));
|
|
43
|
+
if (body.cols != null && body.rows != null) {
|
|
44
|
+
const cols = Number(body.cols);
|
|
45
|
+
const rows = Number(body.rows);
|
|
46
|
+
if (!Number.isFinite(cols) || !Number.isFinite(rows)) {
|
|
47
|
+
return apiError(c, 400, 'INVALID_SIZE', 'cols and rows must be numbers');
|
|
48
|
+
}
|
|
49
|
+
mgr.resize(id, cols, rows);
|
|
50
|
+
}
|
|
51
|
+
if (typeof body.title === 'string') {
|
|
52
|
+
mgr.setTitle(id, body.title);
|
|
53
|
+
}
|
|
54
|
+
return c.json(mgr.get(id));
|
|
55
|
+
});
|
|
56
|
+
// 终止 PTY
|
|
57
|
+
app.delete('/:id', (c) => {
|
|
58
|
+
const id = c.req.param('id');
|
|
59
|
+
if (!mgr.get(id))
|
|
60
|
+
return apiError(c, 404, 'PTY_NOT_FOUND', 'Terminal not found');
|
|
61
|
+
mgr.kill(id);
|
|
62
|
+
return c.json({ ok: true });
|
|
63
|
+
});
|
|
64
|
+
return app;
|
|
65
|
+
}
|
|
66
|
+
export { createTerminalRoute };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { listTools } from '../../tools/registry.js';
|
|
3
|
+
import { apiError } from '../middleware/error.js';
|
|
4
|
+
function createToolRoute(ctx) {
|
|
5
|
+
const app = new Hono();
|
|
6
|
+
// 列出可用工具(不含 execute 函数)
|
|
7
|
+
app.get('/', (c) => {
|
|
8
|
+
const tools = listTools(ctx.toolRegistry, { config: {}, cwd: ctx.cwd });
|
|
9
|
+
const serializable = tools.map((t) => ({
|
|
10
|
+
name: t.name,
|
|
11
|
+
description: t.description,
|
|
12
|
+
parameters: t.parameters,
|
|
13
|
+
permission: t.permission,
|
|
14
|
+
}));
|
|
15
|
+
return c.json(serializable);
|
|
16
|
+
});
|
|
17
|
+
// 确认工具执行权限
|
|
18
|
+
app.post('/confirm', async (c) => {
|
|
19
|
+
const body = await c.req.json();
|
|
20
|
+
const ok = ctx.permissionStore.resolve(body.toolCallId, body.approved);
|
|
21
|
+
if (!ok) {
|
|
22
|
+
return apiError(c, 404, 'NOT_FOUND', 'No pending permission for this tool call');
|
|
23
|
+
}
|
|
24
|
+
return c.json({ confirmed: true });
|
|
25
|
+
});
|
|
26
|
+
return app;
|
|
27
|
+
}
|
|
28
|
+
export { createToolRoute };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import type { ServerContext } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* GET /api/update — 返回后台调度器缓存的版本检查结果(spec §18.1)。
|
|
5
|
+
* 路由本身不触发 npm registry 请求;调度器周期性 checkNow 写入缓存,
|
|
6
|
+
* 路由读缓存(避免每个前端轮询都打外网)。
|
|
7
|
+
*
|
|
8
|
+
* POST /api/update/apply — 手动触发热更新(spec §18.2):
|
|
9
|
+
* 序列化当前会话 → performHotUpdate(npm install -g + spawn 新实例 + handoffPort)。
|
|
10
|
+
* 旧实例通过 handoff 端点优雅退出,新实例 restore 快照并接管端口。
|
|
11
|
+
* 响应立即返回(不阻塞 spawn),实际接管由 handoff IPC 异步完成。
|
|
12
|
+
*/
|
|
13
|
+
declare function createUpdateRoute(ctx: ServerContext): Hono;
|
|
14
|
+
export { createUpdateRoute };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Hono } from 'hono';
|
|
2
|
+
import { performHotUpdate, serializeSessions } from '../../update/index.js';
|
|
3
|
+
import { apiError } from '../middleware/error.js';
|
|
4
|
+
/**
|
|
5
|
+
* GET /api/update — 返回后台调度器缓存的版本检查结果(spec §18.1)。
|
|
6
|
+
* 路由本身不触发 npm registry 请求;调度器周期性 checkNow 写入缓存,
|
|
7
|
+
* 路由读缓存(避免每个前端轮询都打外网)。
|
|
8
|
+
*
|
|
9
|
+
* POST /api/update/apply — 手动触发热更新(spec §18.2):
|
|
10
|
+
* 序列化当前会话 → performHotUpdate(npm install -g + spawn 新实例 + handoffPort)。
|
|
11
|
+
* 旧实例通过 handoff 端点优雅退出,新实例 restore 快照并接管端口。
|
|
12
|
+
* 响应立即返回(不阻塞 spawn),实际接管由 handoff IPC 异步完成。
|
|
13
|
+
*/
|
|
14
|
+
function createUpdateRoute(ctx) {
|
|
15
|
+
const app = new Hono();
|
|
16
|
+
app.get('/', (c) => {
|
|
17
|
+
const cached = ctx.updateScheduler.getLastResult();
|
|
18
|
+
if (cached)
|
|
19
|
+
return c.json(cached);
|
|
20
|
+
// 无缓存(首次启动延迟未到):同步触发一次,避免前端首屏空。
|
|
21
|
+
// 不 await——保持 GET 语义非阻塞;前端下次轮询拿到结果。
|
|
22
|
+
void ctx.updateScheduler.checkNow();
|
|
23
|
+
return c.json({
|
|
24
|
+
hasUpdate: false,
|
|
25
|
+
currentVersion: '0.0.0',
|
|
26
|
+
latestVersion: '0.0.0',
|
|
27
|
+
});
|
|
28
|
+
});
|
|
29
|
+
app.post('/apply', async (c) => {
|
|
30
|
+
const result = await ctx.updateScheduler.checkNow();
|
|
31
|
+
if (!result.hasUpdate) {
|
|
32
|
+
return apiError(c, 409, 'NO_UPDATE', '已是最新版本,无需热更新');
|
|
33
|
+
}
|
|
34
|
+
const snapshot = await serializeSessions(ctx.db, ctx.config);
|
|
35
|
+
const r = await performHotUpdate(snapshot, {
|
|
36
|
+
handoffPort: ctx.handoff?.port,
|
|
37
|
+
});
|
|
38
|
+
if (r._tag === 'success') {
|
|
39
|
+
return c.json({
|
|
40
|
+
ok: true,
|
|
41
|
+
snapshotPath: r.snapshotPath,
|
|
42
|
+
latestVersion: result.latestVersion,
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
return apiError(c, 500, 'HOT_UPDATE_FAILED', `${r._tag}: ${'error' in r ? r.error : 'unknown'}`);
|
|
46
|
+
});
|
|
47
|
+
return app;
|
|
48
|
+
}
|
|
49
|
+
export { createUpdateRoute };
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { Hono } from 'hono';
|
|
2
|
+
import type { DB } from '../db/client.js';
|
|
3
|
+
import type { Registry } from '../llm/registry.js';
|
|
4
|
+
import type { Config } from '../shared/types/config.js';
|
|
5
|
+
import { checkForUpdate, createHandoffServer } from '../update/index.js';
|
|
6
|
+
import type { ServerContext } from './types.js';
|
|
7
|
+
type StartServerOptions = {
|
|
8
|
+
port?: number;
|
|
9
|
+
cwd?: string;
|
|
10
|
+
/** 注入已有 DB(测试用)。 */
|
|
11
|
+
db?: DB;
|
|
12
|
+
/** 热更新新实例启动时从此快照文件恢复会话状态。 */
|
|
13
|
+
restoreFrom?: string;
|
|
14
|
+
/** 新实例启动时提供:请求旧实例 handoff 后再绑端口(spec §18.3)。 */
|
|
15
|
+
handoffPort?: number;
|
|
16
|
+
/** 测试注入:跳过 handoff 请求与重试绑端口。 */
|
|
17
|
+
skipHandoff?: boolean;
|
|
18
|
+
/** 测试注入:覆盖 checkForUpdate(默认走真实 npm registry)。 */
|
|
19
|
+
checkForUpdateFn?: typeof checkForUpdate;
|
|
20
|
+
/** 测试注入:覆盖 createHandoffServer。 */
|
|
21
|
+
createHandoffFn?: typeof createHandoffServer;
|
|
22
|
+
};
|
|
23
|
+
type RunningServer = {
|
|
24
|
+
app: Hono;
|
|
25
|
+
port: number;
|
|
26
|
+
close(): Promise<void>;
|
|
27
|
+
};
|
|
28
|
+
type BootstrappedServer = {
|
|
29
|
+
ctx: ServerContext;
|
|
30
|
+
close(): Promise<void>;
|
|
31
|
+
};
|
|
32
|
+
/** 把 config.providers 注册到新建的 LLM registry(修复此前空 registry 的遗漏)。 */
|
|
33
|
+
declare function buildRegistryFromConfig(config: Config): Registry;
|
|
34
|
+
/**
|
|
35
|
+
* config 变更后原地同步 registry(清空旧路由 + 重新注册),
|
|
36
|
+
* 使运行中的 ServerContext 立即生效,无需重启。
|
|
37
|
+
*/
|
|
38
|
+
declare function syncRegistryFromConfig(registry: Registry, config: Config): void;
|
|
39
|
+
/**
|
|
40
|
+
* 围绕已有 DB handle 组装 ServerContext(不建/不关闭 DB)。
|
|
41
|
+
*
|
|
42
|
+
* dev 热重载重建复用此函数:PGLite 单写者约束下 DB handle 必须跨重载存活,
|
|
43
|
+
* 但 ctx 其余资源(agentManager/permissionStore/registries/plugins)全部重建为新实例。
|
|
44
|
+
* 返回的 dispose 清理 ctx 资源但**不 close db**——db 由调用方持有。
|
|
45
|
+
*/
|
|
46
|
+
declare function buildServerContext(db: DB, opts?: StartServerOptions): Promise<{
|
|
47
|
+
ctx: ServerContext;
|
|
48
|
+
dispose: () => Promise<void>;
|
|
49
|
+
}>;
|
|
50
|
+
/** dev 专用:创建 + migrate PGLite,跨热重载复用(单写者,只建一次)。 */
|
|
51
|
+
declare function createDevDb(cwd: string): Promise<DB>;
|
|
52
|
+
/** 初始化 DB + 配置 + 注册表,返回 ServerContext + 清理函数(dev 与独立后端共用)。 */
|
|
53
|
+
declare function bootstrapServerContext(opts?: StartServerOptions): Promise<BootstrappedServer>;
|
|
54
|
+
declare function startServer(opts?: StartServerOptions): Promise<RunningServer>;
|
|
55
|
+
export type { BootstrappedServer, RunningServer, StartServerOptions };
|
|
56
|
+
export { bootstrapServerContext, buildRegistryFromConfig, buildServerContext, createDevDb, startServer, syncRegistryFromConfig, };
|