codebase-cli 2.0.0-pre.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 +266 -0
- package/bin/codebase +2 -0
- package/dist/agent/agent.js +198 -0
- package/dist/agent/agent.js.map +1 -0
- package/dist/agent/config.js +117 -0
- package/dist/agent/config.js.map +1 -0
- package/dist/agent/events.js +153 -0
- package/dist/agent/events.js.map +1 -0
- package/dist/agent/router.js +35 -0
- package/dist/agent/router.js.map +1 -0
- package/dist/agent/system-prompt.js +21 -0
- package/dist/agent/system-prompt.js.map +1 -0
- package/dist/auth/cli.js +138 -0
- package/dist/auth/cli.js.map +1 -0
- package/dist/auth/credentials.js +105 -0
- package/dist/auth/credentials.js.map +1 -0
- package/dist/auth/flow.js +222 -0
- package/dist/auth/flow.js.map +1 -0
- package/dist/auth/pkce.js +46 -0
- package/dist/auth/pkce.js.map +1 -0
- package/dist/cli.js +69 -0
- package/dist/cli.js.map +1 -0
- package/dist/clipboard/copy.js +106 -0
- package/dist/clipboard/copy.js.map +1 -0
- package/dist/commands/builtins.js +203 -0
- package/dist/commands/builtins.js.map +1 -0
- package/dist/commands/registry.js +65 -0
- package/dist/commands/registry.js.map +1 -0
- package/dist/commands/types.js +2 -0
- package/dist/commands/types.js.map +1 -0
- package/dist/compaction/engine.js +209 -0
- package/dist/compaction/engine.js.map +1 -0
- package/dist/compaction/tokens.js +79 -0
- package/dist/compaction/tokens.js.map +1 -0
- package/dist/compaction/types.js +2 -0
- package/dist/compaction/types.js.map +1 -0
- package/dist/diagnostics/checkers.js +211 -0
- package/dist/diagnostics/checkers.js.map +1 -0
- package/dist/diagnostics/engine.js +71 -0
- package/dist/diagnostics/engine.js.map +1 -0
- package/dist/diagnostics/types.js +2 -0
- package/dist/diagnostics/types.js.map +1 -0
- package/dist/dotenv/loader.js +115 -0
- package/dist/dotenv/loader.js.map +1 -0
- package/dist/glue/client.js +47 -0
- package/dist/glue/client.js.map +1 -0
- package/dist/glue/intent.js +78 -0
- package/dist/glue/intent.js.map +1 -0
- package/dist/glue/narration.js +55 -0
- package/dist/glue/narration.js.map +1 -0
- package/dist/headless/run.js +89 -0
- package/dist/headless/run.js.map +1 -0
- package/dist/hooks/manager.js +158 -0
- package/dist/hooks/manager.js.map +1 -0
- package/dist/hooks/runner.js +70 -0
- package/dist/hooks/runner.js.map +1 -0
- package/dist/hooks/types.js +2 -0
- package/dist/hooks/types.js.map +1 -0
- package/dist/memory/inject.js +12 -0
- package/dist/memory/inject.js.map +1 -0
- package/dist/memory/store.js +178 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/memory/types.js +10 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/permissions/store.js +172 -0
- package/dist/permissions/store.js.map +1 -0
- package/dist/plan/flow.js +214 -0
- package/dist/plan/flow.js.map +1 -0
- package/dist/plan/prompts.js +69 -0
- package/dist/plan/prompts.js.map +1 -0
- package/dist/plan/store.js +37 -0
- package/dist/plan/store.js.map +1 -0
- package/dist/plan/types.js +3 -0
- package/dist/plan/types.js.map +1 -0
- package/dist/sessions/store.js +105 -0
- package/dist/sessions/store.js.map +1 -0
- package/dist/skills/loader.js +41 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/skills/platform-loader.js +63 -0
- package/dist/skills/platform-loader.js.map +1 -0
- package/dist/skills/types.js +21 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/tools/ask-user.js +61 -0
- package/dist/tools/ask-user.js.map +1 -0
- package/dist/tools/dispatch-agent.js +178 -0
- package/dist/tools/dispatch-agent.js.map +1 -0
- package/dist/tools/edit-file.js +80 -0
- package/dist/tools/edit-file.js.map +1 -0
- package/dist/tools/errors.js +89 -0
- package/dist/tools/errors.js.map +1 -0
- package/dist/tools/file-ops.js +136 -0
- package/dist/tools/file-ops.js.map +1 -0
- package/dist/tools/file-state-cache.js +92 -0
- package/dist/tools/file-state-cache.js.map +1 -0
- package/dist/tools/git/branch.js +84 -0
- package/dist/tools/git/branch.js.map +1 -0
- package/dist/tools/git/commit.js +83 -0
- package/dist/tools/git/commit.js.map +1 -0
- package/dist/tools/git/diff.js +72 -0
- package/dist/tools/git/diff.js.map +1 -0
- package/dist/tools/git/git-helpers.js +58 -0
- package/dist/tools/git/git-helpers.js.map +1 -0
- package/dist/tools/git/log.js +70 -0
- package/dist/tools/git/log.js.map +1 -0
- package/dist/tools/git/status.js +97 -0
- package/dist/tools/git/status.js.map +1 -0
- package/dist/tools/git/worktree.js +132 -0
- package/dist/tools/git/worktree.js.map +1 -0
- package/dist/tools/glob.js +128 -0
- package/dist/tools/glob.js.map +1 -0
- package/dist/tools/grep.js +199 -0
- package/dist/tools/grep.js.map +1 -0
- package/dist/tools/list-files.js +120 -0
- package/dist/tools/list-files.js.map +1 -0
- package/dist/tools/memory-tools.js +127 -0
- package/dist/tools/memory-tools.js.map +1 -0
- package/dist/tools/multi-edit.js +87 -0
- package/dist/tools/multi-edit.js.map +1 -0
- package/dist/tools/notebook-edit.js +147 -0
- package/dist/tools/notebook-edit.js.map +1 -0
- package/dist/tools/permission.js +168 -0
- package/dist/tools/permission.js.map +1 -0
- package/dist/tools/plan-mode.js +76 -0
- package/dist/tools/plan-mode.js.map +1 -0
- package/dist/tools/read-file.js +135 -0
- package/dist/tools/read-file.js.map +1 -0
- package/dist/tools/registry.js +52 -0
- package/dist/tools/registry.js.map +1 -0
- package/dist/tools/shell.js +216 -0
- package/dist/tools/shell.js.map +1 -0
- package/dist/tools/task-store.js +70 -0
- package/dist/tools/task-store.js.map +1 -0
- package/dist/tools/tasks.js +131 -0
- package/dist/tools/tasks.js.map +1 -0
- package/dist/tools/types.js +2 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/web-fetch.js +152 -0
- package/dist/tools/web-fetch.js.map +1 -0
- package/dist/tools/web-search.js +169 -0
- package/dist/tools/web-search.js.map +1 -0
- package/dist/tools/write-file.js +70 -0
- package/dist/tools/write-file.js.map +1 -0
- package/dist/types.js +9 -0
- package/dist/types.js.map +1 -0
- package/dist/ui/App.js +216 -0
- package/dist/ui/App.js.map +1 -0
- package/dist/ui/Input.js +90 -0
- package/dist/ui/Input.js.map +1 -0
- package/dist/ui/Message.js +89 -0
- package/dist/ui/Message.js.map +1 -0
- package/dist/ui/MessageList.js +35 -0
- package/dist/ui/MessageList.js.map +1 -0
- package/dist/ui/Permission.js +39 -0
- package/dist/ui/Permission.js.map +1 -0
- package/dist/ui/Status.js +34 -0
- package/dist/ui/Status.js.map +1 -0
- package/dist/ui/TaskPanel.js +43 -0
- package/dist/ui/TaskPanel.js.map +1 -0
- package/dist/ui/Throbber.js +20 -0
- package/dist/ui/Throbber.js.map +1 -0
- package/dist/ui/ToolPanel.js +83 -0
- package/dist/ui/ToolPanel.js.map +1 -0
- package/dist/ui/UserQuery.js +38 -0
- package/dist/ui/UserQuery.js.map +1 -0
- package/dist/ui/input-state.js +210 -0
- package/dist/ui/input-state.js.map +1 -0
- package/dist/ui/wrap.js +30 -0
- package/dist/ui/wrap.js.map +1 -0
- package/dist/user-queries/store.js +60 -0
- package/dist/user-queries/store.js.map +1 -0
- package/package.json +76 -0
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { copyToClipboard, extractLastCodeBlock } from "../clipboard/copy.js";
|
|
2
|
+
const help = {
|
|
3
|
+
name: "help",
|
|
4
|
+
description: "List available slash commands.",
|
|
5
|
+
handler: (_args, ctx) => {
|
|
6
|
+
const lines = ["available slash commands:"];
|
|
7
|
+
const reg = ctx.registry;
|
|
8
|
+
// builtins() is built before registry is constructed, so the registry
|
|
9
|
+
// reference is injected via ctx by the App. If absent (e.g. in tests),
|
|
10
|
+
// we print just this message.
|
|
11
|
+
if (reg) {
|
|
12
|
+
for (const cmd of reg.list()) {
|
|
13
|
+
const aliasPart = cmd.aliases?.length ? ` (${cmd.aliases.map((a) => `/${a}`).join(", ")})` : "";
|
|
14
|
+
lines.push(` /${cmd.name}${aliasPart} — ${cmd.description}`);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
ctx.emit(lines.join("\n"));
|
|
18
|
+
return { handled: true };
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
const clear = {
|
|
22
|
+
name: "clear",
|
|
23
|
+
description: "Clear the on-screen chat history. (Agent context is preserved.)",
|
|
24
|
+
mutates: true,
|
|
25
|
+
handler: (_args, ctx) => {
|
|
26
|
+
ctx.clearDisplay();
|
|
27
|
+
return { handled: true };
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
const compact = {
|
|
31
|
+
name: "compact",
|
|
32
|
+
description: "Force a compaction pass on the running transcript.",
|
|
33
|
+
mutates: true,
|
|
34
|
+
handler: async (_args, ctx) => {
|
|
35
|
+
const messages = ctx.bundle.agent.state.messages;
|
|
36
|
+
const result = await ctx.bundle.compaction.compact(messages);
|
|
37
|
+
if (result.details.collapsedMessageCount === 0) {
|
|
38
|
+
ctx.emit("nothing to compact yet — transcript is short.");
|
|
39
|
+
return { handled: true };
|
|
40
|
+
}
|
|
41
|
+
ctx.bundle.agent.state.messages = result.messages;
|
|
42
|
+
ctx.emit(`compacted ${result.details.collapsedMessageCount} messages (~${result.details.truncatedTokens} tokens). ` +
|
|
43
|
+
`${result.details.modifiedFiles.length} files modified, ${result.details.readFiles.length} read are preserved in the summary.`);
|
|
44
|
+
return { handled: true };
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
const session = {
|
|
48
|
+
name: "session",
|
|
49
|
+
aliases: ["info"],
|
|
50
|
+
description: "Show session stats (model, usage, message count).",
|
|
51
|
+
handler: (_args, ctx) => {
|
|
52
|
+
const { state, bundle } = ctx;
|
|
53
|
+
const u = state.usage;
|
|
54
|
+
const lines = [
|
|
55
|
+
`model: ${state.model.provider}/${state.model.id} (${state.model.name})`,
|
|
56
|
+
`messages: ${state.messages.length}`,
|
|
57
|
+
`usage: ↓${u.input} ↑${u.output} cache ↓${u.cacheRead}/↑${u.cacheWrite}`,
|
|
58
|
+
`cost: $${u.cost.total.toFixed(4)}`,
|
|
59
|
+
`source: ${bundle.source}`,
|
|
60
|
+
];
|
|
61
|
+
ctx.emit(lines.join("\n"));
|
|
62
|
+
return { handled: true };
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
const cost = {
|
|
66
|
+
name: "cost",
|
|
67
|
+
description: "Detailed token + cost breakdown for the current session, including cache hit rate.",
|
|
68
|
+
handler: (_args, ctx) => {
|
|
69
|
+
const { state, bundle } = ctx;
|
|
70
|
+
const u = state.usage;
|
|
71
|
+
const turns = state.messages.filter((m) => m.role === "assistant").length;
|
|
72
|
+
const promptTokens = u.input + u.cacheRead;
|
|
73
|
+
const hitRate = promptTokens > 0 ? `${((u.cacheRead / promptTokens) * 100).toFixed(0)}%` : "—";
|
|
74
|
+
const turnAvg = turns > 0 ? u.cost.total / turns : 0;
|
|
75
|
+
const proxyNote = bundle.source === "proxy" ? " (proxied via codebase.foundation)" : "";
|
|
76
|
+
const lines = [
|
|
77
|
+
`Session cost: $${u.cost.total.toFixed(4)}${proxyNote}`,
|
|
78
|
+
"",
|
|
79
|
+
"Tokens:",
|
|
80
|
+
` Input ${padNum(u.input, 8)} ($${u.cost.input.toFixed(4)})`,
|
|
81
|
+
` Output ${padNum(u.output, 8)} ($${u.cost.output.toFixed(4)})`,
|
|
82
|
+
` Cache read ${padNum(u.cacheRead, 8)} ($${u.cost.cacheRead.toFixed(4)}) ${hitRate} hit rate`,
|
|
83
|
+
` Cache write ${padNum(u.cacheWrite, 8)} ($${u.cost.cacheWrite.toFixed(4)})`,
|
|
84
|
+
"",
|
|
85
|
+
turns > 0
|
|
86
|
+
? `Turn average: $${turnAvg.toFixed(4)} (${turns} turn${turns === 1 ? "" : "s"})`
|
|
87
|
+
: "No assistant turns yet.",
|
|
88
|
+
];
|
|
89
|
+
ctx.emit(lines.join("\n"));
|
|
90
|
+
return { handled: true };
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
function padNum(n, width) {
|
|
94
|
+
return n.toLocaleString().padStart(width, " ");
|
|
95
|
+
}
|
|
96
|
+
const modelCmd = {
|
|
97
|
+
name: "model",
|
|
98
|
+
description: "Show the current model.",
|
|
99
|
+
handler: (_args, ctx) => {
|
|
100
|
+
const m = ctx.state.model;
|
|
101
|
+
ctx.emit(`${m.provider}/${m.id} (${m.name})`);
|
|
102
|
+
return { handled: true };
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
const whoami = {
|
|
106
|
+
name: "whoami",
|
|
107
|
+
aliases: ["status"],
|
|
108
|
+
description: "Show current sign-in status.",
|
|
109
|
+
handler: (_args, ctx) => {
|
|
110
|
+
const source = ctx.bundle.source;
|
|
111
|
+
ctx.emit(source === "proxy"
|
|
112
|
+
? "signed in via codebase.foundation (inference proxy)"
|
|
113
|
+
: source === "explicit"
|
|
114
|
+
? "using model selected via CODEBASE_PROVIDER + CODEBASE_MODEL"
|
|
115
|
+
: "using auto-detected provider from env");
|
|
116
|
+
return { handled: true };
|
|
117
|
+
},
|
|
118
|
+
};
|
|
119
|
+
const exit = {
|
|
120
|
+
name: "exit",
|
|
121
|
+
aliases: ["quit"],
|
|
122
|
+
description: "Quit codebase.",
|
|
123
|
+
handler: (_args, ctx) => {
|
|
124
|
+
ctx.exit();
|
|
125
|
+
return { handled: true };
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
const copy = {
|
|
129
|
+
name: "copy",
|
|
130
|
+
description: "Copy text to the system clipboard. /copy = last assistant message; /copy code = last code block; /copy <N> = message N.",
|
|
131
|
+
handler: async (args, ctx) => {
|
|
132
|
+
const messages = ctx.state.messages;
|
|
133
|
+
const target = resolveCopyTarget(args, messages);
|
|
134
|
+
if (target === null) {
|
|
135
|
+
ctx.emit("no assistant messages yet to copy.");
|
|
136
|
+
return { handled: true };
|
|
137
|
+
}
|
|
138
|
+
if (!target.text) {
|
|
139
|
+
ctx.emit("could not find text to copy. Try /copy, /copy code, or /copy <N>.");
|
|
140
|
+
return { handled: true };
|
|
141
|
+
}
|
|
142
|
+
try {
|
|
143
|
+
const result = await copyToClipboard(target.text);
|
|
144
|
+
const truncatedNote = result.truncated ? `, truncated to ${result.bytes}` : ` (${result.bytes} bytes)`;
|
|
145
|
+
ctx.emit(`copied ${target.label} via ${result.method}${truncatedNote}`);
|
|
146
|
+
}
|
|
147
|
+
catch (err) {
|
|
148
|
+
ctx.emit(`/copy failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
149
|
+
}
|
|
150
|
+
return { handled: true };
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
function resolveCopyTarget(args, messages) {
|
|
154
|
+
const trimmed = args.trim().toLowerCase();
|
|
155
|
+
if (trimmed === "code") {
|
|
156
|
+
const last = lastAssistantText(messages);
|
|
157
|
+
if (!last)
|
|
158
|
+
return null;
|
|
159
|
+
const block = extractLastCodeBlock(last);
|
|
160
|
+
if (!block)
|
|
161
|
+
return { text: "", label: "" };
|
|
162
|
+
return { text: block, label: "last code block" };
|
|
163
|
+
}
|
|
164
|
+
if (/^\d+$/.test(trimmed)) {
|
|
165
|
+
const idx = Number.parseInt(trimmed, 10) - 1;
|
|
166
|
+
if (idx < 0 || idx >= messages.length)
|
|
167
|
+
return { text: "", label: "" };
|
|
168
|
+
const msg = messages[idx];
|
|
169
|
+
const text = extractText(msg);
|
|
170
|
+
if (!text)
|
|
171
|
+
return { text: "", label: "" };
|
|
172
|
+
return { text, label: `message ${idx + 1}` };
|
|
173
|
+
}
|
|
174
|
+
const last = lastAssistantText(messages);
|
|
175
|
+
if (!last)
|
|
176
|
+
return null;
|
|
177
|
+
return { text: last, label: "last assistant message" };
|
|
178
|
+
}
|
|
179
|
+
function lastAssistantText(messages) {
|
|
180
|
+
for (let i = messages.length - 1; i >= 0; i--) {
|
|
181
|
+
const m = messages[i];
|
|
182
|
+
if (m.role !== "assistant")
|
|
183
|
+
continue;
|
|
184
|
+
const text = extractText(m);
|
|
185
|
+
if (text)
|
|
186
|
+
return text;
|
|
187
|
+
}
|
|
188
|
+
return "";
|
|
189
|
+
}
|
|
190
|
+
function extractText(message) {
|
|
191
|
+
if (typeof message.content === "string")
|
|
192
|
+
return message.content;
|
|
193
|
+
if (!Array.isArray(message.content))
|
|
194
|
+
return "";
|
|
195
|
+
const parts = [];
|
|
196
|
+
for (const block of message.content) {
|
|
197
|
+
if (block.type === "text" && typeof block.text === "string")
|
|
198
|
+
parts.push(block.text);
|
|
199
|
+
}
|
|
200
|
+
return parts.join("");
|
|
201
|
+
}
|
|
202
|
+
export const BUILTIN_COMMANDS = [help, clear, compact, session, cost, modelCmd, whoami, copy, exit];
|
|
203
|
+
//# sourceMappingURL=builtins.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"builtins.js","sourceRoot":"","sources":["../../src/commands/builtins.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slash-command registry. Stable, name-keyed, with optional aliases.
|
|
3
|
+
* App.tsx forwards every user input that starts with "/" through here;
|
|
4
|
+
* unrecognized commands fall through to the agent so a stray `/` in a
|
|
5
|
+
* code snippet doesn't get hijacked.
|
|
6
|
+
*/
|
|
7
|
+
export class CommandRegistry {
|
|
8
|
+
commands = new Map();
|
|
9
|
+
register(command) {
|
|
10
|
+
const names = [command.name, ...(command.aliases ?? [])];
|
|
11
|
+
for (const name of names) {
|
|
12
|
+
const normalized = normalize(name);
|
|
13
|
+
if (this.commands.has(normalized)) {
|
|
14
|
+
throw new Error(`command ${name} already registered`);
|
|
15
|
+
}
|
|
16
|
+
this.commands.set(normalized, command);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
registerAll(commands) {
|
|
20
|
+
for (const command of commands)
|
|
21
|
+
this.register(command);
|
|
22
|
+
}
|
|
23
|
+
get(name) {
|
|
24
|
+
return this.commands.get(normalize(name));
|
|
25
|
+
}
|
|
26
|
+
/** All registered commands, deduplicated by primary name. Sorted alphabetically. */
|
|
27
|
+
list() {
|
|
28
|
+
const seen = new Set();
|
|
29
|
+
const out = [];
|
|
30
|
+
for (const cmd of this.commands.values()) {
|
|
31
|
+
if (seen.has(cmd.name))
|
|
32
|
+
continue;
|
|
33
|
+
seen.add(cmd.name);
|
|
34
|
+
out.push(cmd);
|
|
35
|
+
}
|
|
36
|
+
out.sort((a, b) => a.name.localeCompare(b.name));
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Try to dispatch user input as a slash command. Returns
|
|
41
|
+
* { handled: false } if the input doesn't start with "/" or names an
|
|
42
|
+
* unknown command — caller should pass it on to the agent in either
|
|
43
|
+
* case.
|
|
44
|
+
*/
|
|
45
|
+
async dispatch(input, ctx) {
|
|
46
|
+
if (!input.startsWith("/"))
|
|
47
|
+
return { handled: false };
|
|
48
|
+
const trimmed = input.slice(1).trim();
|
|
49
|
+
if (!trimmed)
|
|
50
|
+
return { handled: false };
|
|
51
|
+
const splitIdx = trimmed.search(/\s/);
|
|
52
|
+
const name = splitIdx === -1 ? trimmed : trimmed.slice(0, splitIdx);
|
|
53
|
+
const args = splitIdx === -1 ? "" : trimmed.slice(splitIdx + 1).trim();
|
|
54
|
+
const command = this.get(name);
|
|
55
|
+
if (!command) {
|
|
56
|
+
ctx.emit(`unknown command: /${name}. Try /help.`);
|
|
57
|
+
return { handled: true };
|
|
58
|
+
}
|
|
59
|
+
return command.handler(args, ctx);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function normalize(name) {
|
|
63
|
+
return name.replace(/^\/+/, "").trim().toLowerCase();
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../src/commands/registry.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/commands/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
import { contextWindow, estimateMessageTokens, estimateTotalTokens } from "./tokens.js";
|
|
2
|
+
const DEFAULT_THRESHOLD = 0.75;
|
|
3
|
+
const DEFAULT_KEEP_RECENT = 8;
|
|
4
|
+
const SUMMARY_SYSTEM_PROMPT = `Summarize the prior conversation between a user and a coding agent in tight markdown. Output structure:
|
|
5
|
+
|
|
6
|
+
## Progress
|
|
7
|
+
What concrete work has happened so far. File changes, decisions made.
|
|
8
|
+
|
|
9
|
+
## Context
|
|
10
|
+
Background or constraints introduced earlier that still matter.
|
|
11
|
+
|
|
12
|
+
## Current state
|
|
13
|
+
Where things stand right now. Pending work, error states, half-finished tasks.
|
|
14
|
+
|
|
15
|
+
## Next steps
|
|
16
|
+
What was queued or implied to come next, if anything.
|
|
17
|
+
|
|
18
|
+
Be concrete. Reference paths, function names, commit subjects when you have them. Skip pleasantries. Keep it under ~500 words.`;
|
|
19
|
+
export class CompactionEngine {
|
|
20
|
+
glue;
|
|
21
|
+
modelId;
|
|
22
|
+
thresholdRatio;
|
|
23
|
+
keepRecent;
|
|
24
|
+
constructor(options) {
|
|
25
|
+
this.glue = options.glue;
|
|
26
|
+
this.modelId = options.modelId;
|
|
27
|
+
this.thresholdRatio = options.thresholdRatio ?? DEFAULT_THRESHOLD;
|
|
28
|
+
this.keepRecent = options.keepRecent ?? DEFAULT_KEEP_RECENT;
|
|
29
|
+
}
|
|
30
|
+
threshold() {
|
|
31
|
+
return Math.floor(contextWindow(this.modelId) * this.thresholdRatio);
|
|
32
|
+
}
|
|
33
|
+
needsCompaction(messages) {
|
|
34
|
+
return estimateTotalTokens(messages) >= this.threshold();
|
|
35
|
+
}
|
|
36
|
+
async compact(messages, signal) {
|
|
37
|
+
if (messages.length <= this.keepRecent) {
|
|
38
|
+
return {
|
|
39
|
+
messages,
|
|
40
|
+
details: { readFiles: [], modifiedFiles: [], summary: "", truncatedTokens: 0, collapsedMessageCount: 0 },
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
const splitIdx = findSafeSplit(messages, messages.length - this.keepRecent);
|
|
44
|
+
if (splitIdx <= 0) {
|
|
45
|
+
return {
|
|
46
|
+
messages,
|
|
47
|
+
details: { readFiles: [], modifiedFiles: [], summary: "", truncatedTokens: 0, collapsedMessageCount: 0 },
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
const older = messages.slice(0, splitIdx);
|
|
51
|
+
const recent = messages.slice(splitIdx);
|
|
52
|
+
const truncatedTokens = older.reduce((sum, m) => sum + estimateMessageTokens(m), 0);
|
|
53
|
+
const details = extractFileOps(older);
|
|
54
|
+
details.truncatedTokens = truncatedTokens;
|
|
55
|
+
details.collapsedMessageCount = older.length;
|
|
56
|
+
details.summary = await this.summarize(older, signal);
|
|
57
|
+
const summaryMessage = {
|
|
58
|
+
role: "user",
|
|
59
|
+
content: [
|
|
60
|
+
{
|
|
61
|
+
type: "text",
|
|
62
|
+
text: `[Conversation compacted — summary of previous work follows]\n\n${details.summary}\n\nFiles read earlier: ${details.readFiles.join(", ") || "(none)"}\nFiles modified earlier: ${details.modifiedFiles.join(", ") || "(none)"}`,
|
|
63
|
+
},
|
|
64
|
+
],
|
|
65
|
+
timestamp: Date.now(),
|
|
66
|
+
};
|
|
67
|
+
const ackMessage = {
|
|
68
|
+
role: "assistant",
|
|
69
|
+
content: [{ type: "text", text: "Got it — I have the context summary. Continuing from there." }],
|
|
70
|
+
api: "compaction",
|
|
71
|
+
provider: "compaction",
|
|
72
|
+
model: this.modelId,
|
|
73
|
+
usage: {
|
|
74
|
+
input: 0,
|
|
75
|
+
output: 0,
|
|
76
|
+
cacheRead: 0,
|
|
77
|
+
cacheWrite: 0,
|
|
78
|
+
totalTokens: 0,
|
|
79
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },
|
|
80
|
+
},
|
|
81
|
+
stopReason: "stop",
|
|
82
|
+
timestamp: Date.now(),
|
|
83
|
+
};
|
|
84
|
+
return { messages: [summaryMessage, ackMessage, ...recent], details };
|
|
85
|
+
}
|
|
86
|
+
async summarize(older, signal) {
|
|
87
|
+
const transcript = older.map(serializeForSummary).join("\n\n");
|
|
88
|
+
try {
|
|
89
|
+
const out = await this.glue.smart(transcript, SUMMARY_SYSTEM_PROMPT, signal);
|
|
90
|
+
return out.trim();
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
94
|
+
return `(summarization failed: ${reason}; transcript truncated without a summary)`;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Walk backwards from `desired` to find a split point where the tail of
|
|
100
|
+
* `older` is a "boundary" — a user message or an assistant message with
|
|
101
|
+
* no tool calls. Splitting between an assistant-with-toolCalls and its
|
|
102
|
+
* toolResults would orphan the results in `recent` (their parent call
|
|
103
|
+
* is summarized away), which providers reject.
|
|
104
|
+
*/
|
|
105
|
+
export function findSafeSplit(messages, desired) {
|
|
106
|
+
let idx = Math.min(Math.max(desired, 0), messages.length);
|
|
107
|
+
while (idx > 0) {
|
|
108
|
+
const prev = messages[idx - 1];
|
|
109
|
+
if (prev.role === "user")
|
|
110
|
+
return idx;
|
|
111
|
+
if (prev.role === "assistant" && !messageHasToolCalls(prev))
|
|
112
|
+
return idx;
|
|
113
|
+
idx--;
|
|
114
|
+
}
|
|
115
|
+
return 0;
|
|
116
|
+
}
|
|
117
|
+
function messageHasToolCalls(message) {
|
|
118
|
+
if (!Array.isArray(message.content))
|
|
119
|
+
return false;
|
|
120
|
+
return message.content.some((block) => block.type === "toolCall");
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Walk the truncated messages and extract the file paths the agent
|
|
124
|
+
* touched. Mirrors pi-mono's CompactionDetails so the post-summary
|
|
125
|
+
* model still has structured access to "what files mattered earlier".
|
|
126
|
+
*/
|
|
127
|
+
export function extractFileOps(messages) {
|
|
128
|
+
const reads = new Set();
|
|
129
|
+
const writes = new Set();
|
|
130
|
+
const writeTools = new Set(["write_file", "edit_file", "multi_edit", "notebook_edit"]);
|
|
131
|
+
const readTools = new Set(["read_file"]);
|
|
132
|
+
for (const message of messages) {
|
|
133
|
+
if (message.role !== "assistant")
|
|
134
|
+
continue;
|
|
135
|
+
if (!Array.isArray(message.content))
|
|
136
|
+
continue;
|
|
137
|
+
for (const block of message.content) {
|
|
138
|
+
if (block.type !== "toolCall")
|
|
139
|
+
continue;
|
|
140
|
+
const name = block.name ?? "";
|
|
141
|
+
const path = block.arguments?.path;
|
|
142
|
+
if (typeof path !== "string")
|
|
143
|
+
continue;
|
|
144
|
+
if (writeTools.has(name))
|
|
145
|
+
writes.add(path);
|
|
146
|
+
else if (readTools.has(name))
|
|
147
|
+
reads.add(path);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
readFiles: Array.from(reads).sort(),
|
|
152
|
+
modifiedFiles: Array.from(writes).sort(),
|
|
153
|
+
summary: "",
|
|
154
|
+
truncatedTokens: 0,
|
|
155
|
+
collapsedMessageCount: 0,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
function serializeForSummary(message) {
|
|
159
|
+
const role = message.role;
|
|
160
|
+
if (role === "user") {
|
|
161
|
+
const text = typeof message.content === "string" ? message.content : extractText(message.content);
|
|
162
|
+
return `USER: ${text}`;
|
|
163
|
+
}
|
|
164
|
+
if (role === "assistant") {
|
|
165
|
+
const parts = [];
|
|
166
|
+
if (Array.isArray(message.content)) {
|
|
167
|
+
for (const block of message.content) {
|
|
168
|
+
if (block.type === "text" && typeof block.text === "string")
|
|
169
|
+
parts.push(block.text);
|
|
170
|
+
else if (block.type === "toolCall")
|
|
171
|
+
parts.push(`${block.name ?? "?"}(${shortArgs(block.arguments)})`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
return `ASSISTANT: ${parts.join("\n")}`;
|
|
175
|
+
}
|
|
176
|
+
if (role === "toolResult") {
|
|
177
|
+
const text = typeof message.content === "string" ? message.content : extractText(message.content);
|
|
178
|
+
const toolName = message.toolName ?? "tool";
|
|
179
|
+
return `[TOOL RESULT] ${toolName}: ${truncate(text, 500)}`;
|
|
180
|
+
}
|
|
181
|
+
return "";
|
|
182
|
+
}
|
|
183
|
+
function extractText(content) {
|
|
184
|
+
if (!Array.isArray(content))
|
|
185
|
+
return "";
|
|
186
|
+
const parts = [];
|
|
187
|
+
for (const block of content) {
|
|
188
|
+
if (block.type === "text" && typeof block.text === "string")
|
|
189
|
+
parts.push(block.text);
|
|
190
|
+
}
|
|
191
|
+
return parts.join("");
|
|
192
|
+
}
|
|
193
|
+
function shortArgs(args) {
|
|
194
|
+
if (!args || typeof args !== "object")
|
|
195
|
+
return "";
|
|
196
|
+
const entries = Object.entries(args).slice(0, 3);
|
|
197
|
+
return entries
|
|
198
|
+
.map(([k, v]) => {
|
|
199
|
+
const s = typeof v === "string" ? `"${truncate(v, 30)}"` : JSON.stringify(v);
|
|
200
|
+
return `${k}=${s}`;
|
|
201
|
+
})
|
|
202
|
+
.join(", ");
|
|
203
|
+
}
|
|
204
|
+
function truncate(s, max) {
|
|
205
|
+
if (s.length <= max)
|
|
206
|
+
return s;
|
|
207
|
+
return `${s.slice(0, max - 1)}…`;
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/compaction/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
const CHARS_PER_TOKEN = 3.8;
|
|
2
|
+
const PER_MESSAGE_OVERHEAD = 4;
|
|
3
|
+
/**
|
|
4
|
+
* Rough token estimate from message length. Used to decide whether to
|
|
5
|
+
* compact. We deliberately don't reach for a real tokenizer here:
|
|
6
|
+
* - Real tokenizers are slow on every turn.
|
|
7
|
+
* - The agent doesn't need exact counts to make a binary trigger
|
|
8
|
+
* decision; the 75% threshold has plenty of slack.
|
|
9
|
+
*
|
|
10
|
+
* Assistant messages emitted by pi-agent-core carry a `usage` block
|
|
11
|
+
* with the provider-reported `totalTokens`. When that's present we
|
|
12
|
+
* trust it over the chars/3.8 heuristic — this gives accurate
|
|
13
|
+
* accounting on assistant turns and keeps the heuristic only for the
|
|
14
|
+
* user/tool messages we have no real token count for.
|
|
15
|
+
*/
|
|
16
|
+
export function estimateMessageTokens(message) {
|
|
17
|
+
const usage = message.usage;
|
|
18
|
+
if (usage && typeof usage.totalTokens === "number" && usage.totalTokens > 0) {
|
|
19
|
+
return usage.totalTokens;
|
|
20
|
+
}
|
|
21
|
+
const body = serialize(message);
|
|
22
|
+
return Math.ceil(body.length / CHARS_PER_TOKEN) + PER_MESSAGE_OVERHEAD;
|
|
23
|
+
}
|
|
24
|
+
export function estimateTotalTokens(messages) {
|
|
25
|
+
let total = 0;
|
|
26
|
+
for (const m of messages)
|
|
27
|
+
total += estimateMessageTokens(m);
|
|
28
|
+
return total;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Best-effort context-window lookup. Map covers the common cases used
|
|
32
|
+
* by the v2 cli; unknown models fall back to 128K which matches the
|
|
33
|
+
* majority of currently shipping APIs.
|
|
34
|
+
*/
|
|
35
|
+
const CONTEXT_WINDOWS = [
|
|
36
|
+
{ match: /^claude-(opus|sonnet)-4/, window: 200_000 },
|
|
37
|
+
{ match: /^claude-(opus|sonnet)-3/, window: 200_000 },
|
|
38
|
+
{ match: /^claude-haiku-4/, window: 200_000 },
|
|
39
|
+
{ match: /^claude-haiku-3-5/, window: 200_000 },
|
|
40
|
+
{ match: /^gpt-5/, window: 400_000 },
|
|
41
|
+
{ match: /^gpt-4o/, window: 128_000 },
|
|
42
|
+
{ match: /^gpt-4-turbo/, window: 128_000 },
|
|
43
|
+
{ match: /^o3/, window: 200_000 },
|
|
44
|
+
{ match: /^o4/, window: 200_000 },
|
|
45
|
+
{ match: /^gemini-2/, window: 1_000_000 },
|
|
46
|
+
{ match: /^llama-3-3-70b/, window: 128_000 },
|
|
47
|
+
{ match: /^mistral-large/, window: 131_000 },
|
|
48
|
+
];
|
|
49
|
+
export function contextWindow(modelId) {
|
|
50
|
+
const id = modelId.toLowerCase();
|
|
51
|
+
for (const entry of CONTEXT_WINDOWS) {
|
|
52
|
+
if (entry.match.test(id))
|
|
53
|
+
return entry.window;
|
|
54
|
+
}
|
|
55
|
+
return 128_000;
|
|
56
|
+
}
|
|
57
|
+
function serialize(message) {
|
|
58
|
+
if (typeof message.content === "string")
|
|
59
|
+
return message.content;
|
|
60
|
+
if (!Array.isArray(message.content))
|
|
61
|
+
return "";
|
|
62
|
+
const parts = [];
|
|
63
|
+
for (const block of message.content) {
|
|
64
|
+
if (block.type === "text" && typeof block.text === "string")
|
|
65
|
+
parts.push(block.text);
|
|
66
|
+
else if (block.type === "thinking" && typeof block.thinking === "string")
|
|
67
|
+
parts.push(block.thinking);
|
|
68
|
+
else if (block.type === "toolCall" && block.arguments !== undefined) {
|
|
69
|
+
try {
|
|
70
|
+
parts.push(JSON.stringify(block.arguments));
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
/* skip un-serializable */
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return parts.join("\n");
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=tokens.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tokens.js","sourceRoot":"","sources":["../../src/compaction/tokens.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/compaction/types.ts"],"names":[],"mappings":""}
|