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,89 @@
|
|
|
1
|
+
import { createAgent } from "../agent/agent.js";
|
|
2
|
+
import { ConfigError } from "../agent/config.js";
|
|
3
|
+
/**
|
|
4
|
+
* Run a single prompt without the TUI: stream assistant text to stdout,
|
|
5
|
+
* tool activity to stderr (for diagnostic visibility without polluting
|
|
6
|
+
* piped output), exit on agent_end. Designed for CI / scripting use:
|
|
7
|
+
* `codebase run "summarize this repo" > out.md`.
|
|
8
|
+
*/
|
|
9
|
+
export async function runHeadless(opts) {
|
|
10
|
+
const out = opts.stdout ?? ((c) => process.stdout.write(c));
|
|
11
|
+
const err = opts.stderr ?? ((c) => process.stderr.write(c));
|
|
12
|
+
let bundle;
|
|
13
|
+
try {
|
|
14
|
+
bundle = createAgent({ resume: opts.resume });
|
|
15
|
+
}
|
|
16
|
+
catch (e) {
|
|
17
|
+
const msg = e instanceof ConfigError ? e.message : e instanceof Error ? e.message : String(e);
|
|
18
|
+
err(`error: ${msg}\n`);
|
|
19
|
+
return 1;
|
|
20
|
+
}
|
|
21
|
+
let lastStreamLen = 0;
|
|
22
|
+
let aborted = false;
|
|
23
|
+
let errored = false;
|
|
24
|
+
const onSigInt = () => {
|
|
25
|
+
aborted = true;
|
|
26
|
+
bundle.agent.abort();
|
|
27
|
+
};
|
|
28
|
+
process.on("SIGINT", onSigInt);
|
|
29
|
+
const unsubscribe = bundle.subscribe((event) => {
|
|
30
|
+
switch (event.type) {
|
|
31
|
+
case "tool_execution_start":
|
|
32
|
+
err(`[${event.toolName}…]\n`);
|
|
33
|
+
return;
|
|
34
|
+
case "tool_execution_end":
|
|
35
|
+
if (event.isError)
|
|
36
|
+
err(`[${event.toolName} ERROR]\n`);
|
|
37
|
+
return;
|
|
38
|
+
case "message_update": {
|
|
39
|
+
if (event.message.role !== "assistant")
|
|
40
|
+
return;
|
|
41
|
+
const text = extractText(event.message);
|
|
42
|
+
if (text.length > lastStreamLen) {
|
|
43
|
+
out(text.slice(lastStreamLen));
|
|
44
|
+
lastStreamLen = text.length;
|
|
45
|
+
}
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
case "message_end": {
|
|
49
|
+
if (event.message.role !== "assistant")
|
|
50
|
+
return;
|
|
51
|
+
const text = extractText(event.message);
|
|
52
|
+
if (text.length > lastStreamLen)
|
|
53
|
+
out(text.slice(lastStreamLen));
|
|
54
|
+
lastStreamLen = 0;
|
|
55
|
+
out("\n");
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
case "agent_end":
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
try {
|
|
63
|
+
await bundle.agent.prompt(opts.prompt);
|
|
64
|
+
}
|
|
65
|
+
catch (e) {
|
|
66
|
+
errored = true;
|
|
67
|
+
err(`agent error: ${e instanceof Error ? e.message : String(e)}\n`);
|
|
68
|
+
}
|
|
69
|
+
finally {
|
|
70
|
+
unsubscribe();
|
|
71
|
+
process.off("SIGINT", onSigInt);
|
|
72
|
+
}
|
|
73
|
+
if (aborted)
|
|
74
|
+
return 130;
|
|
75
|
+
return errored ? 1 : 0;
|
|
76
|
+
}
|
|
77
|
+
function extractText(message) {
|
|
78
|
+
if (typeof message.content === "string")
|
|
79
|
+
return message.content;
|
|
80
|
+
if (!Array.isArray(message.content))
|
|
81
|
+
return "";
|
|
82
|
+
const parts = [];
|
|
83
|
+
for (const block of message.content) {
|
|
84
|
+
if (block.type === "text" && typeof block.text === "string")
|
|
85
|
+
parts.push(block.text);
|
|
86
|
+
}
|
|
87
|
+
return parts.join("");
|
|
88
|
+
}
|
|
89
|
+
//# sourceMappingURL=run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/headless/run.ts"],"names":[],"mappings":"AACA,OAAO,EAAoB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AASjD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAqB;IACtD,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAE5D,IAAI,MAAmB,CAAC;IACxB,IAAI,CAAC;QACJ,MAAM,GAAG,WAAW,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;IAC/C,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,CAAC,YAAY,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;QAC9F,GAAG,CAAC,UAAU,GAAG,IAAI,CAAC,CAAC;QACvB,OAAO,CAAC,CAAC;IACV,CAAC;IAED,IAAI,aAAa,GAAG,CAAC,CAAC;IACtB,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,IAAI,OAAO,GAAG,KAAK,CAAC;IAEpB,MAAM,QAAQ,GAAG,GAAG,EAAE;QACrB,OAAO,GAAG,IAAI,CAAC;QACf,MAAM,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;IACtB,CAAC,CAAC;IACF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IAE/B,MAAM,WAAW,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,KAAiB,EAAE,EAAE;QAC1D,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;YACpB,KAAK,sBAAsB;gBAC1B,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,MAAM,CAAC,CAAC;gBAC9B,OAAO;YACR,KAAK,oBAAoB;gBACxB,IAAI,KAAK,CAAC,OAAO;oBAAE,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,WAAW,CAAC,CAAC;gBACtD,OAAO;YACR,KAAK,gBAAgB,CAAC,CAAC,CAAC;gBACvB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW;oBAAE,OAAO;gBAC/C,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACxC,IAAI,IAAI,CAAC,MAAM,GAAG,aAAa,EAAE,CAAC;oBACjC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;oBAC/B,aAAa,GAAG,IAAI,CAAC,MAAM,CAAC;gBAC7B,CAAC;gBACD,OAAO;YACR,CAAC;YACD,KAAK,aAAa,CAAC,CAAC,CAAC;gBACpB,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,KAAK,WAAW;oBAAE,OAAO;gBAC/C,MAAM,IAAI,GAAG,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBACxC,IAAI,IAAI,CAAC,MAAM,GAAG,aAAa;oBAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC;gBAChE,aAAa,GAAG,CAAC,CAAC;gBAClB,GAAG,CAAC,IAAI,CAAC,CAAC;gBACV,OAAO;YACR,CAAC;YACD,KAAK,WAAW;gBACf,OAAO;QACT,CAAC;IACF,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC;QACJ,MAAM,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACxC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACZ,OAAO,GAAG,IAAI,CAAC;QACf,GAAG,CAAC,gBAAgB,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;IACrE,CAAC;YAAS,CAAC;QACV,WAAW,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,OAAO;QAAE,OAAO,GAAG,CAAC;IACxB,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;AACxB,CAAC;AAED,SAAS,WAAW,CAAC,OAA8B;IAClD,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC;IAChE,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,CAAC;IAC/C,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,OAAO,CAAC,OAAiD,EAAE,CAAC;QAC/E,IAAI,KAAK,CAAC,IAAI,KAAK,MAAM,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACrF,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACvB,CAAC"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
import { runHook } from "./runner.js";
|
|
3
|
+
/**
|
|
4
|
+
* User-defined hook engine. Loads hook config from one or more JSON
|
|
5
|
+
* files (typically `~/.codebase/hooks.json` and `.codebase/hooks.json`)
|
|
6
|
+
* and dispatches matching hooks for each agent event.
|
|
7
|
+
*
|
|
8
|
+
* Exit code 2 from a synchronous hook blocks the in-flight tool call —
|
|
9
|
+
* pi-agent-core converts that block into an error tool-result so the
|
|
10
|
+
* model gets the hook's stderr as feedback.
|
|
11
|
+
*/
|
|
12
|
+
export class HookManager {
|
|
13
|
+
configs = [];
|
|
14
|
+
/**
|
|
15
|
+
* Load and append hook configs from the given file paths in order.
|
|
16
|
+
* Missing files are silently skipped; malformed JSON is logged but
|
|
17
|
+
* non-fatal so a typo in one project's hooks.json doesn't break the
|
|
18
|
+
* agent.
|
|
19
|
+
*/
|
|
20
|
+
loadFrom(...paths) {
|
|
21
|
+
for (const path of paths) {
|
|
22
|
+
if (!path)
|
|
23
|
+
continue;
|
|
24
|
+
let body;
|
|
25
|
+
try {
|
|
26
|
+
body = readFileSync(path, "utf8");
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
const code = err.code;
|
|
30
|
+
if (code !== "ENOENT") {
|
|
31
|
+
console.warn(`hooks: could not read ${path}: ${err.message}`);
|
|
32
|
+
}
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
let parsed;
|
|
36
|
+
try {
|
|
37
|
+
parsed = JSON.parse(body);
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
console.warn(`hooks: ${path} is not valid JSON: ${err.message}`);
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (!Array.isArray(parsed.hooks)) {
|
|
44
|
+
console.warn(`hooks: ${path} missing top-level "hooks" array`);
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
for (const config of parsed.hooks) {
|
|
48
|
+
if (validateHook(config, path))
|
|
49
|
+
this.configs.push(config);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/** Hooks visible to the manager. Mainly for tests. */
|
|
54
|
+
all() {
|
|
55
|
+
return this.configs;
|
|
56
|
+
}
|
|
57
|
+
matching(event, context) {
|
|
58
|
+
return this.configs.filter((h) => h.event === event && hookMatches(h.matcher, context));
|
|
59
|
+
}
|
|
60
|
+
async dispatch(event, context, signal) {
|
|
61
|
+
const matching = this.matching(event, context);
|
|
62
|
+
let ranCount = 0;
|
|
63
|
+
for (const config of matching) {
|
|
64
|
+
if (config.async) {
|
|
65
|
+
runHook(config, context, signal).catch(() => {
|
|
66
|
+
// fire-and-forget; nothing to do on failure
|
|
67
|
+
});
|
|
68
|
+
ranCount++;
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
const result = await runHook(config, context, signal);
|
|
72
|
+
ranCount++;
|
|
73
|
+
if (result.exitCode === 2) {
|
|
74
|
+
return {
|
|
75
|
+
blocked: true,
|
|
76
|
+
reason: result.stderr.trim() || `blocked by hook (event=${event})`,
|
|
77
|
+
ranCount,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return { blocked: false, ranCount };
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
function validateHook(config, source) {
|
|
85
|
+
if (!config || typeof config !== "object") {
|
|
86
|
+
console.warn(`hooks: ${source} contains a non-object hook entry, skipping`);
|
|
87
|
+
return false;
|
|
88
|
+
}
|
|
89
|
+
const c = config;
|
|
90
|
+
if (!c.event) {
|
|
91
|
+
console.warn(`hooks: ${source} hook missing "event", skipping`);
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
if (!c.command || typeof c.command !== "string") {
|
|
95
|
+
console.warn(`hooks: ${source} hook ${c.event} missing "command", skipping`);
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Matcher syntax:
|
|
102
|
+
* undefined or "" → match anything
|
|
103
|
+
* "tool" → exact tool name
|
|
104
|
+
* "toolA|toolB" → either
|
|
105
|
+
* "tool:pathPattern" → tool name AND filePath matches pathPattern
|
|
106
|
+
* "*:pathPattern" → any tool whose filePath matches pathPattern
|
|
107
|
+
*
|
|
108
|
+
* Pattern segments support `*` (any chars, no separator) and `**` (any
|
|
109
|
+
* chars including separators) — same as gitignore-style globs but
|
|
110
|
+
* minimal.
|
|
111
|
+
*/
|
|
112
|
+
export function hookMatches(matcher, context) {
|
|
113
|
+
if (!matcher)
|
|
114
|
+
return true;
|
|
115
|
+
const [toolPart, pathPart] = matcher.split(":", 2);
|
|
116
|
+
if (toolPart && toolPart !== "*") {
|
|
117
|
+
const alternatives = toolPart.split("|").map((s) => s.trim());
|
|
118
|
+
if (!alternatives.includes(context.toolName ?? ""))
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
if (pathPart) {
|
|
122
|
+
if (!context.filePath)
|
|
123
|
+
return false;
|
|
124
|
+
if (!globMatches(pathPart, context.filePath))
|
|
125
|
+
return false;
|
|
126
|
+
}
|
|
127
|
+
return true;
|
|
128
|
+
}
|
|
129
|
+
function globMatches(pattern, value) {
|
|
130
|
+
const re = new RegExp(`^${globToRegex(pattern)}$`);
|
|
131
|
+
return re.test(value);
|
|
132
|
+
}
|
|
133
|
+
function globToRegex(pattern) {
|
|
134
|
+
let out = "";
|
|
135
|
+
for (let i = 0; i < pattern.length; i++) {
|
|
136
|
+
const ch = pattern[i];
|
|
137
|
+
if (ch === "*") {
|
|
138
|
+
if (pattern[i + 1] === "*") {
|
|
139
|
+
out += ".*";
|
|
140
|
+
i++;
|
|
141
|
+
}
|
|
142
|
+
else {
|
|
143
|
+
out += "[^/]*";
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else if (ch === "?") {
|
|
147
|
+
out += "[^/]";
|
|
148
|
+
}
|
|
149
|
+
else if (/[\\^$+.()|{}[\]]/.test(ch)) {
|
|
150
|
+
out += `\\${ch}`;
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
out += ch;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return out;
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=manager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/hooks/manager.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
3
|
+
/**
|
|
4
|
+
* Run a single hook command. Sends the event payload as JSON on stdin so
|
|
5
|
+
* shell hooks can `jq` whatever fields they care about. Never throws —
|
|
6
|
+
* spawn/timeout failures come back as a non-zero exit code with stderr
|
|
7
|
+
* populated, so the manager can decide how to react.
|
|
8
|
+
*/
|
|
9
|
+
export function runHook(config, context, signal) {
|
|
10
|
+
return new Promise((resolve) => {
|
|
11
|
+
const timeoutMs = config.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
12
|
+
let settled = false;
|
|
13
|
+
const finish = (result) => {
|
|
14
|
+
if (settled)
|
|
15
|
+
return;
|
|
16
|
+
settled = true;
|
|
17
|
+
resolve(result);
|
|
18
|
+
};
|
|
19
|
+
let child;
|
|
20
|
+
try {
|
|
21
|
+
child = spawn(config.command, {
|
|
22
|
+
shell: true,
|
|
23
|
+
cwd: context.workingDir,
|
|
24
|
+
env: process.env,
|
|
25
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
const reason = err instanceof Error ? err.message : String(err);
|
|
30
|
+
finish({ exitCode: 1, stdout: "", stderr: `hook spawn failed: ${reason}` });
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const timer = setTimeout(() => {
|
|
34
|
+
child.kill("SIGTERM");
|
|
35
|
+
finish({
|
|
36
|
+
exitCode: 1,
|
|
37
|
+
stdout: "",
|
|
38
|
+
stderr: `hook timed out after ${Math.round(timeoutMs / 1000)}s`,
|
|
39
|
+
});
|
|
40
|
+
}, timeoutMs);
|
|
41
|
+
const onAbort = () => child.kill("SIGTERM");
|
|
42
|
+
signal?.addEventListener("abort", onAbort);
|
|
43
|
+
try {
|
|
44
|
+
child.stdin?.write(JSON.stringify(context));
|
|
45
|
+
child.stdin?.end();
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// stdin already closed by a fast exit — that's fine
|
|
49
|
+
}
|
|
50
|
+
const out = [];
|
|
51
|
+
const err = [];
|
|
52
|
+
child.stdout?.on("data", (b) => out.push(b));
|
|
53
|
+
child.stderr?.on("data", (b) => err.push(b));
|
|
54
|
+
child.on("error", (e) => {
|
|
55
|
+
clearTimeout(timer);
|
|
56
|
+
signal?.removeEventListener("abort", onAbort);
|
|
57
|
+
finish({ exitCode: 1, stdout: "", stderr: e.message });
|
|
58
|
+
});
|
|
59
|
+
child.on("close", (code) => {
|
|
60
|
+
clearTimeout(timer);
|
|
61
|
+
signal?.removeEventListener("abort", onAbort);
|
|
62
|
+
finish({
|
|
63
|
+
exitCode: code ?? 1,
|
|
64
|
+
stdout: Buffer.concat(out).toString("utf8"),
|
|
65
|
+
stderr: Buffer.concat(err).toString("utf8"),
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=runner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/hooks/runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/hooks/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build the MEMORY.md system-prompt addendum. Returns "" when the
|
|
3
|
+
* project has no memories yet — callers concat unconditionally so a
|
|
4
|
+
* fresh project's prompt isn't littered with empty headings.
|
|
5
|
+
*/
|
|
6
|
+
export function buildMemoryAddendum(store) {
|
|
7
|
+
const truncated = store.truncatedIndex();
|
|
8
|
+
if (!truncated.trim())
|
|
9
|
+
return "";
|
|
10
|
+
return `\n\n# Project memory\n\n${truncated.trim()}\n`;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=inject.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inject.js","sourceRoot":"","sources":["../../src/memory/inject.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAkB;IACrD,MAAM,SAAS,GAAG,KAAK,CAAC,cAAc,EAAE,CAAC;IACzC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC;IACjC,OAAO,2BAA2B,SAAS,CAAC,IAAI,EAAE,IAAI,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import { MEMORY_TYPES, parseMemoryType } from "./types.js";
|
|
6
|
+
const MAX_INDEX_LINES = 200;
|
|
7
|
+
const MAX_INDEX_BYTES = 25_000;
|
|
8
|
+
const FILENAME_PATTERN = /^[a-z0-9_-]{1,80}\.md$/;
|
|
9
|
+
/**
|
|
10
|
+
* Per-project memory: one directory at `~/.codebase/projects/{hash}/memory/`
|
|
11
|
+
* keyed off cwd. MEMORY.md is the index injected into the agent's system
|
|
12
|
+
* prompt; per-type *.md files hold full bodies. The 4-type taxonomy
|
|
13
|
+
* (user/feedback/project/reference) is enforced at write time so a typo
|
|
14
|
+
* doesn't silently land an entry of the wrong kind.
|
|
15
|
+
*/
|
|
16
|
+
export class MemoryStore {
|
|
17
|
+
cwd;
|
|
18
|
+
dir;
|
|
19
|
+
constructor(options) {
|
|
20
|
+
this.cwd = options.cwd;
|
|
21
|
+
const dataRoot = options.dataRoot ?? join(homedir(), ".codebase");
|
|
22
|
+
const projectHash = createHash("sha256").update(this.cwd).digest("hex").slice(0, 8);
|
|
23
|
+
this.dir = join(dataRoot, "projects", projectHash, "memory");
|
|
24
|
+
}
|
|
25
|
+
get directory() {
|
|
26
|
+
return this.dir;
|
|
27
|
+
}
|
|
28
|
+
/** Read a single record by filename (e.g. "user_role.md"). Returns null if missing. */
|
|
29
|
+
read(filename) {
|
|
30
|
+
const safe = sanitizeFilename(filename);
|
|
31
|
+
if (!safe)
|
|
32
|
+
return null;
|
|
33
|
+
const path = join(this.dir, safe);
|
|
34
|
+
if (!existsSync(path))
|
|
35
|
+
return null;
|
|
36
|
+
const raw = readFileSync(path, "utf8");
|
|
37
|
+
const stat = statSync(path);
|
|
38
|
+
const parsed = parseMemoryFile(raw);
|
|
39
|
+
if (!parsed)
|
|
40
|
+
return null;
|
|
41
|
+
return { filename: safe, ...parsed.frontmatter, body: parsed.body, updatedAt: stat.mtimeMs };
|
|
42
|
+
}
|
|
43
|
+
list(typeFilter) {
|
|
44
|
+
if (!existsSync(this.dir))
|
|
45
|
+
return [];
|
|
46
|
+
const out = [];
|
|
47
|
+
for (const name of readdirSync(this.dir)) {
|
|
48
|
+
if (name === "MEMORY.md")
|
|
49
|
+
continue;
|
|
50
|
+
if (!name.endsWith(".md"))
|
|
51
|
+
continue;
|
|
52
|
+
const record = this.read(name);
|
|
53
|
+
if (!record)
|
|
54
|
+
continue;
|
|
55
|
+
if (typeFilter && record.type !== typeFilter)
|
|
56
|
+
continue;
|
|
57
|
+
out.push(record);
|
|
58
|
+
}
|
|
59
|
+
out.sort((a, b) => a.filename.localeCompare(b.filename));
|
|
60
|
+
return out;
|
|
61
|
+
}
|
|
62
|
+
save(input) {
|
|
63
|
+
const safe = sanitizeFilename(input.filename);
|
|
64
|
+
if (!safe) {
|
|
65
|
+
throw new Error(`memory filename must match ${FILENAME_PATTERN}; got "${input.filename}"`);
|
|
66
|
+
}
|
|
67
|
+
if (!parseMemoryType(input.type)) {
|
|
68
|
+
throw new Error(`memory type must be one of ${MEMORY_TYPES.join(", ")}; got "${input.type}"`);
|
|
69
|
+
}
|
|
70
|
+
mkdirSync(this.dir, { recursive: true });
|
|
71
|
+
const body = serializeMemoryFile({
|
|
72
|
+
frontmatter: { name: input.name, description: input.description, type: input.type },
|
|
73
|
+
body: input.body,
|
|
74
|
+
});
|
|
75
|
+
const path = join(this.dir, safe);
|
|
76
|
+
writeFileSync(path, body, { mode: 0o644 });
|
|
77
|
+
return {
|
|
78
|
+
filename: safe,
|
|
79
|
+
name: input.name,
|
|
80
|
+
description: input.description,
|
|
81
|
+
type: input.type,
|
|
82
|
+
body: input.body,
|
|
83
|
+
updatedAt: statSync(path).mtimeMs,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
delete(filename) {
|
|
87
|
+
const safe = sanitizeFilename(filename);
|
|
88
|
+
if (!safe)
|
|
89
|
+
return false;
|
|
90
|
+
const path = join(this.dir, safe);
|
|
91
|
+
if (!existsSync(path))
|
|
92
|
+
return false;
|
|
93
|
+
unlinkSync(path);
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
/** Read MEMORY.md verbatim. Returns "" when no index exists. */
|
|
97
|
+
index() {
|
|
98
|
+
const path = join(this.dir, "MEMORY.md");
|
|
99
|
+
if (!existsSync(path))
|
|
100
|
+
return "";
|
|
101
|
+
return readFileSync(path, "utf8");
|
|
102
|
+
}
|
|
103
|
+
writeIndex(content) {
|
|
104
|
+
mkdirSync(this.dir, { recursive: true });
|
|
105
|
+
writeFileSync(join(this.dir, "MEMORY.md"), content, { mode: 0o644 });
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* MEMORY.md content trimmed to fit a system-prompt injection budget.
|
|
109
|
+
* Line cut first (≤200 lines), then byte cut at the next newline so
|
|
110
|
+
* we never split a list entry mid-line. Mirrors Claude Code's
|
|
111
|
+
* truncateEntrypointContent() so injection plays nice with prompt
|
|
112
|
+
* cache boundaries.
|
|
113
|
+
*/
|
|
114
|
+
truncatedIndex() {
|
|
115
|
+
const raw = this.index();
|
|
116
|
+
if (!raw)
|
|
117
|
+
return "";
|
|
118
|
+
const lines = raw.split("\n");
|
|
119
|
+
const lineLimited = lines.length > MAX_INDEX_LINES ? lines.slice(0, MAX_INDEX_LINES).join("\n") : raw;
|
|
120
|
+
if (Buffer.byteLength(lineLimited, "utf8") <= MAX_INDEX_BYTES)
|
|
121
|
+
return lineLimited;
|
|
122
|
+
// Byte cut at the previous newline boundary.
|
|
123
|
+
const buf = Buffer.from(lineLimited, "utf8");
|
|
124
|
+
let cut = MAX_INDEX_BYTES;
|
|
125
|
+
while (cut > 0 && buf[cut] !== 0x0a)
|
|
126
|
+
cut--;
|
|
127
|
+
return buf.subarray(0, cut).toString("utf8");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// ─── helpers ─────────────────────────────────────────────────
|
|
131
|
+
function sanitizeFilename(filename) {
|
|
132
|
+
const trimmed = filename.trim();
|
|
133
|
+
if (!FILENAME_PATTERN.test(trimmed))
|
|
134
|
+
return null;
|
|
135
|
+
return trimmed;
|
|
136
|
+
}
|
|
137
|
+
function parseMemoryFile(raw) {
|
|
138
|
+
if (!raw.startsWith("---"))
|
|
139
|
+
return null;
|
|
140
|
+
const closeIdx = raw.indexOf("\n---", 3);
|
|
141
|
+
if (closeIdx === -1)
|
|
142
|
+
return null;
|
|
143
|
+
const fmRaw = raw.slice(3, closeIdx).trim();
|
|
144
|
+
const body = raw.slice(closeIdx + 4).replace(/^\n/, "");
|
|
145
|
+
const fields = {};
|
|
146
|
+
for (const line of fmRaw.split("\n")) {
|
|
147
|
+
const idx = line.indexOf(":");
|
|
148
|
+
if (idx === -1)
|
|
149
|
+
continue;
|
|
150
|
+
const key = line.slice(0, idx).trim();
|
|
151
|
+
const value = line
|
|
152
|
+
.slice(idx + 1)
|
|
153
|
+
.trim()
|
|
154
|
+
.replace(/^["']|["']$/g, "");
|
|
155
|
+
fields[key] = value;
|
|
156
|
+
}
|
|
157
|
+
const type = fields.type ? parseMemoryType(fields.type) : null;
|
|
158
|
+
if (!type || !fields.name || !fields.description)
|
|
159
|
+
return null;
|
|
160
|
+
return {
|
|
161
|
+
frontmatter: { name: fields.name, description: fields.description, type },
|
|
162
|
+
body,
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
function serializeMemoryFile(input) {
|
|
166
|
+
const lines = [
|
|
167
|
+
"---",
|
|
168
|
+
`name: ${input.frontmatter.name}`,
|
|
169
|
+
`description: ${input.frontmatter.description}`,
|
|
170
|
+
`type: ${input.frontmatter.type}`,
|
|
171
|
+
"---",
|
|
172
|
+
"",
|
|
173
|
+
input.body.replace(/\n+$/, ""),
|
|
174
|
+
"",
|
|
175
|
+
];
|
|
176
|
+
return lines.join("\n");
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/memory/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const MEMORY_TYPES = ["user", "feedback", "project", "reference"];
|
|
2
|
+
export function parseMemoryType(raw) {
|
|
3
|
+
const normalized = raw.trim().toLowerCase();
|
|
4
|
+
for (const t of MEMORY_TYPES) {
|
|
5
|
+
if (t === normalized)
|
|
6
|
+
return t;
|
|
7
|
+
}
|
|
8
|
+
return null;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/memory/types.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,YAAY,GAA0B,CAAC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,CAAC,CAAC;AAchG,MAAM,UAAU,eAAe,CAAC,GAAW;IAC1C,MAAM,UAAU,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IAC5C,KAAK,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC;QAC9B,IAAI,CAAC,KAAK,UAAU;YAAE,OAAO,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,IAAI,CAAC;AACb,CAAC"}
|