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,211 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { join, relative } from "node:path";
|
|
4
|
+
const CHECKER_TIMEOUT_MS = 15_000;
|
|
5
|
+
function runChild(cmd, args, cwd, signal, envOverlay = {}) {
|
|
6
|
+
return new Promise((resolve) => {
|
|
7
|
+
const child = spawn(cmd, args, {
|
|
8
|
+
cwd,
|
|
9
|
+
env: { ...process.env, NO_COLOR: "1", ...envOverlay },
|
|
10
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
11
|
+
});
|
|
12
|
+
let timedOut = false;
|
|
13
|
+
const timer = setTimeout(() => {
|
|
14
|
+
timedOut = true;
|
|
15
|
+
child.kill("SIGTERM");
|
|
16
|
+
}, CHECKER_TIMEOUT_MS);
|
|
17
|
+
const onAbort = () => child.kill("SIGTERM");
|
|
18
|
+
signal?.addEventListener("abort", onAbort);
|
|
19
|
+
const out = [];
|
|
20
|
+
const err = [];
|
|
21
|
+
child.stdout?.on("data", (b) => out.push(b));
|
|
22
|
+
child.stderr?.on("data", (b) => err.push(b));
|
|
23
|
+
child.on("error", (e) => {
|
|
24
|
+
clearTimeout(timer);
|
|
25
|
+
signal?.removeEventListener("abort", onAbort);
|
|
26
|
+
resolve({ stdout: "", stderr: e.message, exitCode: 1 });
|
|
27
|
+
});
|
|
28
|
+
child.on("close", (code) => {
|
|
29
|
+
clearTimeout(timer);
|
|
30
|
+
signal?.removeEventListener("abort", onAbort);
|
|
31
|
+
resolve({
|
|
32
|
+
stdout: Buffer.concat(out).toString("utf8"),
|
|
33
|
+
stderr: Buffer.concat(err).toString("utf8"),
|
|
34
|
+
exitCode: timedOut ? -1 : (code ?? 1),
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
async function commandExists(cmd) {
|
|
40
|
+
const which = process.platform === "win32" ? "where" : "which";
|
|
41
|
+
const result = await runChild(which, [cmd], process.cwd());
|
|
42
|
+
return result.exitCode === 0;
|
|
43
|
+
}
|
|
44
|
+
// ─── Go ───────────────────────────────────────────────────────
|
|
45
|
+
export const goVetChecker = {
|
|
46
|
+
name: "go vet",
|
|
47
|
+
extensions: [".go"],
|
|
48
|
+
detect: async (cwd) => existsSync(join(cwd, "go.mod")),
|
|
49
|
+
run: async (cwd, _files, signal) => {
|
|
50
|
+
const r = await runChild("go", ["vet", "./..."], cwd, signal);
|
|
51
|
+
return parseGoVet(r.stderr || r.stdout, cwd);
|
|
52
|
+
},
|
|
53
|
+
};
|
|
54
|
+
export function parseGoVet(output, cwd) {
|
|
55
|
+
const diags = [];
|
|
56
|
+
for (const raw of output.split("\n")) {
|
|
57
|
+
const line = raw.trim();
|
|
58
|
+
if (!line || line.startsWith("# "))
|
|
59
|
+
continue;
|
|
60
|
+
// Format: "path/to/file.go:LINE:COL: message" or "path/to/file.go:LINE: message"
|
|
61
|
+
const match = /^(.+?\.go):(\d+):(?:(\d+):)?\s*(.+)$/.exec(line);
|
|
62
|
+
if (!match)
|
|
63
|
+
continue;
|
|
64
|
+
const [, file, lineStr, colStr, message] = match;
|
|
65
|
+
diags.push({
|
|
66
|
+
file: toRelative(cwd, file),
|
|
67
|
+
line: Number.parseInt(lineStr, 10),
|
|
68
|
+
column: colStr ? Number.parseInt(colStr, 10) : undefined,
|
|
69
|
+
severity: "error",
|
|
70
|
+
message,
|
|
71
|
+
source: "go vet",
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
return diags;
|
|
75
|
+
}
|
|
76
|
+
// ─── TypeScript (tsc) ─────────────────────────────────────────
|
|
77
|
+
export const tscChecker = {
|
|
78
|
+
name: "tsc",
|
|
79
|
+
extensions: [".ts", ".tsx"],
|
|
80
|
+
detect: async (cwd) => existsSync(join(cwd, "tsconfig.json")),
|
|
81
|
+
run: async (cwd, _files, signal) => {
|
|
82
|
+
const tscBin = await resolveTsc(cwd);
|
|
83
|
+
if (!tscBin)
|
|
84
|
+
return [];
|
|
85
|
+
const r = await runChild(tscBin.cmd, [...tscBin.args, "--noEmit", "--pretty", "false"], cwd, signal);
|
|
86
|
+
return parseTsc(r.stdout, cwd);
|
|
87
|
+
},
|
|
88
|
+
};
|
|
89
|
+
async function resolveTsc(cwd) {
|
|
90
|
+
const local = join(cwd, "node_modules", ".bin", "tsc");
|
|
91
|
+
if (existsSync(local))
|
|
92
|
+
return { cmd: local, args: [] };
|
|
93
|
+
if (await commandExists("tsc"))
|
|
94
|
+
return { cmd: "tsc", args: [] };
|
|
95
|
+
if (await commandExists("npx"))
|
|
96
|
+
return { cmd: "npx", args: ["--no-install", "tsc"] };
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
export function parseTsc(output, cwd) {
|
|
100
|
+
const diags = [];
|
|
101
|
+
// Format: "path/to/file.ts(LINE,COL): error TSxxxx: message"
|
|
102
|
+
const pattern = /^(.+?\.tsx?)\((\d+),(\d+)\):\s+(error|warning)\s+(TS\d+):\s+(.+)$/;
|
|
103
|
+
for (const raw of output.split("\n")) {
|
|
104
|
+
const line = raw.trim();
|
|
105
|
+
if (!line)
|
|
106
|
+
continue;
|
|
107
|
+
const match = pattern.exec(line);
|
|
108
|
+
if (!match)
|
|
109
|
+
continue;
|
|
110
|
+
const [, file, lineStr, colStr, sev, code, message] = match;
|
|
111
|
+
diags.push({
|
|
112
|
+
file: toRelative(cwd, file),
|
|
113
|
+
line: Number.parseInt(lineStr, 10),
|
|
114
|
+
column: Number.parseInt(colStr, 10),
|
|
115
|
+
severity: sev === "warning" ? "warning" : "error",
|
|
116
|
+
message: `${code}: ${message}`,
|
|
117
|
+
source: "tsc",
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return diags;
|
|
121
|
+
}
|
|
122
|
+
// ─── Pyright ──────────────────────────────────────────────────
|
|
123
|
+
export const pyrightChecker = {
|
|
124
|
+
name: "pyright",
|
|
125
|
+
extensions: [".py"],
|
|
126
|
+
detect: async () => commandExists("pyright"),
|
|
127
|
+
run: async (cwd, files, signal) => {
|
|
128
|
+
if (files.length === 0)
|
|
129
|
+
return [];
|
|
130
|
+
const r = await runChild("pyright", ["--outputjson", ...files], cwd, signal);
|
|
131
|
+
return parsePyright(r.stdout, cwd);
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
export function parsePyright(output, cwd) {
|
|
135
|
+
if (!output.trim())
|
|
136
|
+
return [];
|
|
137
|
+
let parsed;
|
|
138
|
+
try {
|
|
139
|
+
parsed = JSON.parse(output);
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return [];
|
|
143
|
+
}
|
|
144
|
+
const diags = [];
|
|
145
|
+
for (const d of parsed.generalDiagnostics ?? []) {
|
|
146
|
+
// pyright uses 0-based line/column; bump to 1-based for consistency.
|
|
147
|
+
diags.push({
|
|
148
|
+
file: toRelative(cwd, d.file),
|
|
149
|
+
line: (d.range?.start.line ?? 0) + 1,
|
|
150
|
+
column: (d.range?.start.character ?? 0) + 1,
|
|
151
|
+
severity: d.severity === "warning" ? "warning" : d.severity === "information" ? "info" : "error",
|
|
152
|
+
message: d.message,
|
|
153
|
+
source: "pyright",
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return diags;
|
|
157
|
+
}
|
|
158
|
+
// ─── ESLint ───────────────────────────────────────────────────
|
|
159
|
+
export const eslintChecker = {
|
|
160
|
+
name: "eslint",
|
|
161
|
+
extensions: [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"],
|
|
162
|
+
detect: async (cwd) => existsSync(join(cwd, "eslint.config.js")) ||
|
|
163
|
+
existsSync(join(cwd, "eslint.config.mjs")) ||
|
|
164
|
+
existsSync(join(cwd, ".eslintrc.js")) ||
|
|
165
|
+
existsSync(join(cwd, ".eslintrc.json")) ||
|
|
166
|
+
existsSync(join(cwd, ".eslintrc.cjs")),
|
|
167
|
+
run: async (cwd, files, signal) => {
|
|
168
|
+
if (files.length === 0)
|
|
169
|
+
return [];
|
|
170
|
+
const local = join(cwd, "node_modules", ".bin", "eslint");
|
|
171
|
+
const cmd = existsSync(local) ? local : "eslint";
|
|
172
|
+
const r = await runChild(cmd, ["--format", "json", ...files], cwd, signal);
|
|
173
|
+
return parseEslint(r.stdout, cwd);
|
|
174
|
+
},
|
|
175
|
+
};
|
|
176
|
+
export function parseEslint(output, cwd) {
|
|
177
|
+
if (!output.trim())
|
|
178
|
+
return [];
|
|
179
|
+
let parsed;
|
|
180
|
+
try {
|
|
181
|
+
parsed = JSON.parse(output);
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return [];
|
|
185
|
+
}
|
|
186
|
+
const diags = [];
|
|
187
|
+
for (const file of parsed) {
|
|
188
|
+
for (const m of file.messages) {
|
|
189
|
+
diags.push({
|
|
190
|
+
file: toRelative(cwd, file.filePath),
|
|
191
|
+
line: m.line ?? 1,
|
|
192
|
+
column: m.column,
|
|
193
|
+
severity: m.severity === 2 ? "error" : "warning",
|
|
194
|
+
message: m.ruleId ? `${m.ruleId}: ${m.message}` : m.message,
|
|
195
|
+
source: "eslint",
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
return diags;
|
|
200
|
+
}
|
|
201
|
+
// ─── helpers ──────────────────────────────────────────────────
|
|
202
|
+
function toRelative(cwd, file) {
|
|
203
|
+
if (!file)
|
|
204
|
+
return "";
|
|
205
|
+
const rel = relative(cwd, file);
|
|
206
|
+
if (rel.startsWith(".."))
|
|
207
|
+
return file;
|
|
208
|
+
return rel;
|
|
209
|
+
}
|
|
210
|
+
export const ALL_CHECKERS = [tscChecker, goVetChecker, pyrightChecker, eslintChecker];
|
|
211
|
+
//# sourceMappingURL=checkers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checkers.js","sourceRoot":"","sources":["../../src/diagnostics/checkers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { extname } from "node:path";
|
|
2
|
+
import { ALL_CHECKERS } from "./checkers.js";
|
|
3
|
+
/**
|
|
4
|
+
* Runs language checkers against files the agent just touched and returns
|
|
5
|
+
* the diagnostics to inject. Detection is cached per project so we don't
|
|
6
|
+
* re-stat go.mod / tsconfig.json on every call.
|
|
7
|
+
*/
|
|
8
|
+
export class DiagnosticsEngine {
|
|
9
|
+
cwd;
|
|
10
|
+
checkers;
|
|
11
|
+
detectCache = new Map();
|
|
12
|
+
constructor(options) {
|
|
13
|
+
this.cwd = options.cwd;
|
|
14
|
+
this.checkers = options.checkers ?? ALL_CHECKERS;
|
|
15
|
+
}
|
|
16
|
+
/** Run every applicable checker for the supplied files, in parallel. */
|
|
17
|
+
async forFiles(files, signal) {
|
|
18
|
+
if (files.length === 0)
|
|
19
|
+
return [];
|
|
20
|
+
const byChecker = new Map();
|
|
21
|
+
for (const file of files) {
|
|
22
|
+
const ext = extname(file).toLowerCase();
|
|
23
|
+
for (const checker of this.checkers) {
|
|
24
|
+
if (!checker.extensions.includes(ext))
|
|
25
|
+
continue;
|
|
26
|
+
if (!(await this.detect(checker)))
|
|
27
|
+
continue;
|
|
28
|
+
const list = byChecker.get(checker) ?? [];
|
|
29
|
+
list.push(file);
|
|
30
|
+
byChecker.set(checker, list);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const runs = Array.from(byChecker.entries()).map(([checker, list]) => checker.run(this.cwd, list, signal).catch(() => []));
|
|
34
|
+
const results = await Promise.all(runs);
|
|
35
|
+
return results.flat();
|
|
36
|
+
}
|
|
37
|
+
detect(checker) {
|
|
38
|
+
const cached = this.detectCache.get(checker.name);
|
|
39
|
+
if (cached)
|
|
40
|
+
return cached;
|
|
41
|
+
const promise = checker.detect(this.cwd);
|
|
42
|
+
this.detectCache.set(checker.name, promise);
|
|
43
|
+
return promise;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Format a diagnostic batch as a steering message body — grouped by file,
|
|
48
|
+
* one line per finding. Intended to be appended verbatim to a "post-edit"
|
|
49
|
+
* system reminder so the model sees them on its next turn.
|
|
50
|
+
*/
|
|
51
|
+
export function formatDiagnostics(diags) {
|
|
52
|
+
if (diags.length === 0)
|
|
53
|
+
return "";
|
|
54
|
+
const byFile = new Map();
|
|
55
|
+
for (const d of diags) {
|
|
56
|
+
const list = byFile.get(d.file) ?? [];
|
|
57
|
+
list.push(d);
|
|
58
|
+
byFile.set(d.file, list);
|
|
59
|
+
}
|
|
60
|
+
const lines = [`${diags.length} diagnostic${diags.length === 1 ? "" : "s"} after the last edit:`, ""];
|
|
61
|
+
for (const [file, fileDiags] of byFile) {
|
|
62
|
+
lines.push(file === "" ? "(unknown file):" : `${file}:`);
|
|
63
|
+
for (const d of fileDiags) {
|
|
64
|
+
const loc = d.column ? `${d.line}:${d.column}` : `${d.line}`;
|
|
65
|
+
lines.push(` Line ${loc} [${d.severity}] (${d.source}): ${d.message}`);
|
|
66
|
+
}
|
|
67
|
+
lines.push("");
|
|
68
|
+
}
|
|
69
|
+
return lines.join("\n").trimEnd();
|
|
70
|
+
}
|
|
71
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"engine.js","sourceRoot":"","sources":["../../src/diagnostics/engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/diagnostics/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
/**
|
|
5
|
+
* Auto-load `.env` (cwd) then `~/.codebase/.env` into `process.env`.
|
|
6
|
+
*
|
|
7
|
+
* Real env vars always win — a value already present in process.env
|
|
8
|
+
* is never clobbered. This means CI configs (set via the CI's secrets
|
|
9
|
+
* mechanism) override what's in a checked-in .env file, which is the
|
|
10
|
+
* sensible precedence and matches the Go v1 dotenv loader.
|
|
11
|
+
*
|
|
12
|
+
* Returns the list of variables that were actually applied, for
|
|
13
|
+
* telemetry / "auth status"-style reporting.
|
|
14
|
+
*/
|
|
15
|
+
export function loadDotEnv(cwd = process.cwd()) {
|
|
16
|
+
const applied = [];
|
|
17
|
+
const candidates = [join(cwd, ".env"), join(homedir(), ".codebase", ".env")];
|
|
18
|
+
for (const path of candidates) {
|
|
19
|
+
if (!existsSync(path))
|
|
20
|
+
continue;
|
|
21
|
+
let raw;
|
|
22
|
+
try {
|
|
23
|
+
raw = readFileSync(path, "utf8");
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
for (const [key, value] of parseDotEnv(raw)) {
|
|
29
|
+
if (process.env[key] !== undefined)
|
|
30
|
+
continue;
|
|
31
|
+
process.env[key] = value;
|
|
32
|
+
applied.push(key);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return applied;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Parse a .env body into key/value pairs. Supports:
|
|
39
|
+
* - `KEY=value` and `export KEY=value`
|
|
40
|
+
* - Single- and double-quoted values (quotes stripped)
|
|
41
|
+
* - Backslash-escapes inside double-quoted values
|
|
42
|
+
* - `# comment` lines and trailing comments after unquoted values
|
|
43
|
+
* - Blank lines
|
|
44
|
+
*/
|
|
45
|
+
export function parseDotEnv(body) {
|
|
46
|
+
const out = new Map();
|
|
47
|
+
const lines = body.split(/\r?\n/);
|
|
48
|
+
for (const line of lines) {
|
|
49
|
+
const trimmed = line.trimStart();
|
|
50
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
51
|
+
continue;
|
|
52
|
+
const stripped = trimmed.replace(/^export\s+/, "");
|
|
53
|
+
const eq = stripped.indexOf("=");
|
|
54
|
+
if (eq === -1)
|
|
55
|
+
continue;
|
|
56
|
+
const key = stripped.slice(0, eq).trim();
|
|
57
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(key))
|
|
58
|
+
continue;
|
|
59
|
+
const rest = stripped.slice(eq + 1).trim();
|
|
60
|
+
out.set(key, parseValue(rest));
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
function parseValue(raw) {
|
|
65
|
+
if (raw.length === 0)
|
|
66
|
+
return "";
|
|
67
|
+
const quote = raw[0];
|
|
68
|
+
if (quote === '"' || quote === "'") {
|
|
69
|
+
const end = findClosingQuote(raw, quote);
|
|
70
|
+
if (end === -1)
|
|
71
|
+
return raw.slice(1);
|
|
72
|
+
const body = raw.slice(1, end);
|
|
73
|
+
return quote === '"' ? unescapeDouble(body) : body;
|
|
74
|
+
}
|
|
75
|
+
// Unquoted: strip trailing comment / inline whitespace
|
|
76
|
+
const hashIdx = raw.indexOf(" #");
|
|
77
|
+
const stop = hashIdx === -1 ? raw.length : hashIdx;
|
|
78
|
+
return raw.slice(0, stop).trim();
|
|
79
|
+
}
|
|
80
|
+
function findClosingQuote(raw, quote) {
|
|
81
|
+
let escaped = false;
|
|
82
|
+
for (let i = 1; i < raw.length; i++) {
|
|
83
|
+
const ch = raw[i];
|
|
84
|
+
if (escaped) {
|
|
85
|
+
escaped = false;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
if (ch === "\\" && quote === '"') {
|
|
89
|
+
escaped = true;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (ch === quote)
|
|
93
|
+
return i;
|
|
94
|
+
}
|
|
95
|
+
return -1;
|
|
96
|
+
}
|
|
97
|
+
function unescapeDouble(body) {
|
|
98
|
+
return body.replace(/\\(.)/g, (_, ch) => {
|
|
99
|
+
switch (ch) {
|
|
100
|
+
case "n":
|
|
101
|
+
return "\n";
|
|
102
|
+
case "t":
|
|
103
|
+
return "\t";
|
|
104
|
+
case "r":
|
|
105
|
+
return "\r";
|
|
106
|
+
case "\\":
|
|
107
|
+
return "\\";
|
|
108
|
+
case '"':
|
|
109
|
+
return '"';
|
|
110
|
+
default:
|
|
111
|
+
return ch;
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
}
|
|
115
|
+
//# sourceMappingURL=loader.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/dotenv/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { completeSimple, getModel } from "@earendil-works/pi-ai";
|
|
2
|
+
export class GlueClient {
|
|
3
|
+
options;
|
|
4
|
+
constructor(options) {
|
|
5
|
+
this.options = options;
|
|
6
|
+
}
|
|
7
|
+
fast(prompt, system, signal) {
|
|
8
|
+
return this.complete(this.options.fastModel, prompt, system, signal);
|
|
9
|
+
}
|
|
10
|
+
smart(prompt, system, signal) {
|
|
11
|
+
return this.complete(this.options.smartModel, prompt, system, signal);
|
|
12
|
+
}
|
|
13
|
+
async complete(model, prompt, system, signal) {
|
|
14
|
+
const message = await completeSimple(model, {
|
|
15
|
+
systemPrompt: system,
|
|
16
|
+
messages: [{ role: "user", content: prompt, timestamp: Date.now() }],
|
|
17
|
+
}, {
|
|
18
|
+
apiKey: this.options.apiKey,
|
|
19
|
+
signal,
|
|
20
|
+
maxTokens: this.options.maxTokens ?? 8000,
|
|
21
|
+
});
|
|
22
|
+
return message.content
|
|
23
|
+
.filter((b) => b.type === "text")
|
|
24
|
+
.map((b) => b.text)
|
|
25
|
+
.join("");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export function resolveGlueModels(opts) {
|
|
29
|
+
const env = opts.env ?? process.env;
|
|
30
|
+
const fast = env.GLUE_FAST_MODEL ? parseGlueRef(env.GLUE_FAST_MODEL, opts.parentModel) : opts.parentModel;
|
|
31
|
+
const smart = env.GLUE_SMART_MODEL ? parseGlueRef(env.GLUE_SMART_MODEL, opts.parentModel) : opts.parentModel;
|
|
32
|
+
return { fast, smart, apiKey: opts.parentApiKey };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Accept either a "modelId" (resolved against the parent provider) or
|
|
36
|
+
* "provider:modelId" (cross-provider). Falls back to the parent on any
|
|
37
|
+
* lookup miss so a typo doesn't kill the agent.
|
|
38
|
+
*/
|
|
39
|
+
export function parseGlueRef(ref, fallback) {
|
|
40
|
+
const trimmed = ref.trim();
|
|
41
|
+
if (!trimmed)
|
|
42
|
+
return fallback;
|
|
43
|
+
const [maybeProvider, maybeId] = trimmed.includes(":") ? trimmed.split(":", 2) : [fallback.provider, trimmed];
|
|
44
|
+
const found = getModel(maybeProvider, maybeId);
|
|
45
|
+
return found ?? fallback;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/glue/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAkC,MAAM,uBAAuB,CAAC;AAyBjG,MAAM,OAAO,UAAU;IACO;IAA7B,YAA6B,OAAoB;QAApB,YAAO,GAAP,OAAO,CAAa;IAAG,CAAC;IAErD,IAAI,CAAC,MAAc,EAAE,MAAe,EAAE,MAAoB;QACzD,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACtE,CAAC;IAED,KAAK,CAAC,MAAc,EAAE,MAAe,EAAE,MAAoB;QAC1D,OAAO,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IACvE,CAAC;IAEO,KAAK,CAAC,QAAQ,CACrB,KAAoB,EACpB,MAAc,EACd,MAA0B,EAC1B,MAA+B;QAE/B,MAAM,OAAO,GAAG,MAAM,cAAc,CACnC,KAAK,EACL;YACC,YAAY,EAAE,MAAM;YACpB,QAAQ,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;SACpE,EACD;YACC,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;YAC3B,MAAM;YACN,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,IAAI;SACzC,CACD,CAAC;QACF,OAAO,OAAO,CAAC,OAAO;aACpB,MAAM,CAAC,CAAC,CAAC,EAAuC,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;aACrE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;aAClB,IAAI,CAAC,EAAE,CAAC,CAAC;IACZ,CAAC;CACD;AAaD,MAAM,UAAU,iBAAiB,CAAC,IAAwB;IAKzD,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACpC,MAAM,IAAI,GAAG,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;IAC1G,MAAM,KAAK,GAAG,GAAG,CAAC,gBAAgB,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,CAAC;IAC7G,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC;AACnD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,GAAW,EAAE,QAAuB;IAChE,MAAM,OAAO,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3B,IAAI,CAAC,OAAO;QAAE,OAAO,QAAQ,CAAC;IAE9B,MAAM,CAAC,aAAa,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC9G,MAAM,KAAK,GAAG,QAAQ,CAAC,aAA8B,EAAE,OAAgB,CAAC,CAAC;IACzE,OAAQ,KAAmC,IAAI,QAAQ,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const INTENT_SYSTEM_PROMPT = `You classify the user's message into ONE of these intents:
|
|
2
|
+
|
|
3
|
+
- agent: a coding/automation/build/fix request. Run-the-tools work. (Default for anything actionable.)
|
|
4
|
+
- plan: a complex multi-step ask that benefits from upfront planning before code is written ("add auth to my Next app", "rewrite the worker as a state machine").
|
|
5
|
+
- chat: small talk, gratitude, greetings, meta-questions about the agent itself.
|
|
6
|
+
- clarify: ambiguous request where the agent couldn't act productively without more info.
|
|
7
|
+
|
|
8
|
+
Output exactly one word: agent | plan | chat | clarify. No prose.`;
|
|
9
|
+
const GREETING_PATTERNS = [
|
|
10
|
+
/^h(i|ello|ey)\b/i,
|
|
11
|
+
/^howdy\b/i,
|
|
12
|
+
/^thanks?\b/i,
|
|
13
|
+
/^thank you\b/i,
|
|
14
|
+
/^ty\b/i,
|
|
15
|
+
/^ok\b/i,
|
|
16
|
+
/^okay\b/i,
|
|
17
|
+
/^nice\b/i,
|
|
18
|
+
/^cool\b/i,
|
|
19
|
+
/^great\b/i,
|
|
20
|
+
/^good (morning|afternoon|evening|night)\b/i,
|
|
21
|
+
];
|
|
22
|
+
/**
|
|
23
|
+
* Decide whether the user's message should run the main agent (tool
|
|
24
|
+
* work), enter plan mode (Q&A → reviewable plan), be answered as chat
|
|
25
|
+
* (no agent run), or trigger a clarifying question.
|
|
26
|
+
*
|
|
27
|
+
* Fast-tracks:
|
|
28
|
+
* - First message in a session: default to "agent" for anything
|
|
29
|
+
* non-trivial (history-less context biases toward action).
|
|
30
|
+
* - Continuations starting with greetings/thanks: short-circuit to
|
|
31
|
+
* "chat" without an LLM call.
|
|
32
|
+
*
|
|
33
|
+
* On LLM error or unparseable output, defaults to "agent" — failing
|
|
34
|
+
* open is preferable to silently dropping a real request.
|
|
35
|
+
*/
|
|
36
|
+
export async function classifyIntent(glue, message, opts) {
|
|
37
|
+
const trimmed = message.trim();
|
|
38
|
+
if (!trimmed)
|
|
39
|
+
return "clarify";
|
|
40
|
+
if (opts.hasHistory && isGreeting(trimmed)) {
|
|
41
|
+
return "chat";
|
|
42
|
+
}
|
|
43
|
+
let raw;
|
|
44
|
+
try {
|
|
45
|
+
raw = await glue.fast(trimmed, INTENT_SYSTEM_PROMPT, opts.signal);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return "agent";
|
|
49
|
+
}
|
|
50
|
+
return parseIntent(raw) ?? "agent";
|
|
51
|
+
}
|
|
52
|
+
export function isGreeting(message) {
|
|
53
|
+
if (message.split(/\s+/).length > 4)
|
|
54
|
+
return false;
|
|
55
|
+
return GREETING_PATTERNS.some((re) => re.test(message));
|
|
56
|
+
}
|
|
57
|
+
export function parseIntent(raw) {
|
|
58
|
+
const word = raw
|
|
59
|
+
.trim()
|
|
60
|
+
.toLowerCase()
|
|
61
|
+
.replace(/[^a-z]/g, "");
|
|
62
|
+
if (word === "agent")
|
|
63
|
+
return "agent";
|
|
64
|
+
if (word === "plan")
|
|
65
|
+
return "plan";
|
|
66
|
+
if (word === "chat")
|
|
67
|
+
return "chat";
|
|
68
|
+
if (word === "clarify")
|
|
69
|
+
return "clarify";
|
|
70
|
+
// Be lenient: take the first matching token from a longer reply.
|
|
71
|
+
for (const candidate of raw.toLowerCase().split(/[^a-z]+/)) {
|
|
72
|
+
if (candidate === "agent" || candidate === "plan" || candidate === "chat" || candidate === "clarify") {
|
|
73
|
+
return candidate;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=intent.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"intent.js","sourceRoot":"","sources":["../../src/glue/intent.ts"],"names":[],"mappings":"AAIA,MAAM,oBAAoB,GAAG;;;;;;;kEAOqC,CAAC;AAEnE,MAAM,iBAAiB,GAAG;IACzB,kBAAkB;IAClB,WAAW;IACX,aAAa;IACb,eAAe;IACf,QAAQ;IACR,QAAQ;IACR,UAAU;IACV,UAAU;IACV,UAAU;IACV,WAAW;IACX,4CAA4C;CAC5C,CAAC;AAOF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAgB,EAAE,OAAe,EAAE,IAAqB;IAC5F,MAAM,OAAO,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAC/B,IAAI,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAE/B,IAAI,IAAI,CAAC,UAAU,IAAI,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5C,OAAO,MAAM,CAAC;IACf,CAAC;IAED,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACJ,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,oBAAoB,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACnE,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,OAAO,CAAC;IAChB,CAAC;IAED,OAAO,WAAW,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,OAAe;IACzC,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IAClD,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;AACzD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW;IACtC,MAAM,IAAI,GAAG,GAAG;SACd,IAAI,EAAE;SACN,WAAW,EAAE;SACb,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IACzB,IAAI,IAAI,KAAK,OAAO;QAAE,OAAO,OAAO,CAAC;IACrC,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IACnC,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,MAAM,CAAC;IACnC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACzC,iEAAiE;IACjE,KAAK,MAAM,SAAS,IAAI,GAAG,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;QAC5D,IAAI,SAAS,KAAK,OAAO,IAAI,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,MAAM,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YACtG,OAAO,SAAmB,CAAC;QAC5B,CAAC;IACF,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
const TITLE_SYSTEM_PROMPT = "Summarize the user's request as a 2-6 word title. Return only the title, no quotes or punctuation.";
|
|
2
|
+
const NARRATE_SYSTEM_PROMPT = "Write a one-line status describing what just happened (≤80 chars). Past tense, terse, no punctuation at the end.";
|
|
3
|
+
const FOLLOWUP_SYSTEM_PROMPT = `Based on what was just done, suggest 1-3 short follow-up actions the user might want next. Return them as a bullet list, each line starting with "- " and ≤60 chars.`;
|
|
4
|
+
const TITLE_MAX_CHARS = 50;
|
|
5
|
+
const NARRATION_MAX_CHARS = 80;
|
|
6
|
+
/** Generate a 2-6 word title for a user request. Falls back to a truncated request. */
|
|
7
|
+
export async function generateTitle(glue, userMessage, signal) {
|
|
8
|
+
const fallback = clamp(userMessage.replace(/\s+/g, " ").trim(), TITLE_MAX_CHARS);
|
|
9
|
+
try {
|
|
10
|
+
const raw = await glue.fast(userMessage, TITLE_SYSTEM_PROMPT, signal);
|
|
11
|
+
const title = clamp(stripQuotes(raw.trim()), TITLE_MAX_CHARS);
|
|
12
|
+
return title || fallback;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return fallback;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
/** Generate a one-line "what's happening now" narration. Falls back to a generic message. */
|
|
19
|
+
export async function narrate(glue, recentActions, signal) {
|
|
20
|
+
if (!recentActions.trim())
|
|
21
|
+
return "Working";
|
|
22
|
+
try {
|
|
23
|
+
const raw = await glue.fast(recentActions, NARRATE_SYSTEM_PROMPT, signal);
|
|
24
|
+
return clamp(raw.trim().replace(/[.!]+$/, ""), NARRATION_MAX_CHARS) || "Working";
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
return "Working";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
/** Suggest 1-3 follow-up actions after a task completes. Falls back to []. */
|
|
31
|
+
export async function suggestFollowUps(glue, taskSummary, filesChanged, signal) {
|
|
32
|
+
const prompt = filesChanged.length
|
|
33
|
+
? `${taskSummary}\n\nFiles changed:\n${filesChanged.slice(0, 10).join("\n")}`
|
|
34
|
+
: taskSummary;
|
|
35
|
+
try {
|
|
36
|
+
const raw = await glue.fast(prompt, FOLLOWUP_SYSTEM_PROMPT, signal);
|
|
37
|
+
return raw
|
|
38
|
+
.split("\n")
|
|
39
|
+
.map((line) => line.replace(/^[-*•]\s*/, "").trim())
|
|
40
|
+
.filter((line) => line.length > 0)
|
|
41
|
+
.slice(0, 3);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
function clamp(s, max) {
|
|
48
|
+
if (s.length <= max)
|
|
49
|
+
return s;
|
|
50
|
+
return `${s.slice(0, max - 1)}…`;
|
|
51
|
+
}
|
|
52
|
+
function stripQuotes(s) {
|
|
53
|
+
return s.replace(/^["'`]+|["'`]+$/g, "");
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=narration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"narration.js","sourceRoot":"","sources":["../../src/glue/narration.ts"],"names":[],"mappings":"AAEA,MAAM,mBAAmB,GACxB,oGAAoG,CAAC;AAEtG,MAAM,qBAAqB,GAC1B,kHAAkH,CAAC;AAEpH,MAAM,sBAAsB,GAAG,sKAAsK,CAAC;AAEtM,MAAM,eAAe,GAAG,EAAE,CAAC;AAC3B,MAAM,mBAAmB,GAAG,EAAE,CAAC;AAE/B,uFAAuF;AACvF,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAgB,EAAE,WAAmB,EAAE,MAAoB;IAC9F,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,eAAe,CAAC,CAAC;IACjF,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,mBAAmB,EAAE,MAAM,CAAC,CAAC;QACtE,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,eAAe,CAAC,CAAC;QAC9D,OAAO,KAAK,IAAI,QAAQ,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,QAAQ,CAAC;IACjB,CAAC;AACF,CAAC;AAED,6FAA6F;AAC7F,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAgB,EAAE,aAAqB,EAAE,MAAoB;IAC1F,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE;QAAE,OAAO,SAAS,CAAC;IAC5C,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,aAAa,EAAE,qBAAqB,EAAE,MAAM,CAAC,CAAC;QAC1E,OAAO,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC,EAAE,mBAAmB,CAAC,IAAI,SAAS,CAAC;IAClF,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;AACF,CAAC;AAED,8EAA8E;AAC9E,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACrC,IAAgB,EAChB,WAAmB,EACnB,YAAsB,EACtB,MAAoB;IAEpB,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM;QACjC,CAAC,CAAC,GAAG,WAAW,uBAAuB,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;QAC7E,CAAC,CAAC,WAAW,CAAC;IACf,IAAI,CAAC;QACJ,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,sBAAsB,EAAE,MAAM,CAAC,CAAC;QACpE,OAAO,GAAG;aACR,KAAK,CAAC,IAAI,CAAC;aACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;aACnD,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC;aACjC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACf,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,EAAE,CAAC;IACX,CAAC;AACF,CAAC;AAED,SAAS,KAAK,CAAC,CAAS,EAAE,GAAW;IACpC,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG;QAAE,OAAO,CAAC,CAAC;IAC9B,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,GAAG,CAAC,CAAC,GAAG,CAAC;AAClC,CAAC;AAED,SAAS,WAAW,CAAC,CAAS;IAC7B,OAAO,CAAC,CAAC,OAAO,CAAC,kBAAkB,EAAE,EAAE,CAAC,CAAC;AAC1C,CAAC"}
|