@orquentra/codebuddy 2.9.0 → 2.14.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/CLAUDE_CODEX.md +33 -0
- package/README.md +27 -3
- package/dist/{adapters-S4HHTWJW.js → adapters-OJRSVFV3.js} +2 -2
- package/dist/{chunk-GKNYMNFM.js → chunk-4DKYKDHI.js} +6 -1
- package/dist/chunk-4DKYKDHI.js.map +1 -0
- package/dist/{chunk-SRA4MDVG.js → chunk-7QMHIJBA.js} +30 -3
- package/dist/chunk-7QMHIJBA.js.map +1 -0
- package/dist/{chunk-6NZEZJYD.js → chunk-ESC4Y3L7.js} +3 -5
- package/dist/{chunk-6NZEZJYD.js.map → chunk-ESC4Y3L7.js.map} +1 -1
- package/dist/chunk-GQKWUHMA.js +20 -0
- package/dist/chunk-GQKWUHMA.js.map +1 -0
- package/dist/{chunk-J4T6HHI4.js → chunk-L6BRYZ6G.js} +537 -316
- package/dist/chunk-L6BRYZ6G.js.map +1 -0
- package/dist/{chunk-UK6XTS2Y.js → chunk-LRQNPYCK.js} +13 -19
- package/dist/chunk-LRQNPYCK.js.map +1 -0
- package/dist/{chunk-GXOML4UZ.js → chunk-LW75SKZR.js} +2 -2
- package/dist/{chunk-ENKDFLOO.js → chunk-UOTKHSQ5.js} +25 -8
- package/dist/chunk-UOTKHSQ5.js.map +1 -0
- package/dist/{chunk-W7GAXL6C.js → chunk-V7PT6ER5.js} +6 -5
- package/dist/chunk-V7PT6ER5.js.map +1 -0
- package/dist/{chunk-F4BJ3DXW.js → chunk-XSNW6Y3X.js} +1253 -315
- package/dist/chunk-XSNW6Y3X.js.map +1 -0
- package/dist/{chunk-2WH2Q4TA.js → chunk-YJPCS2GP.js} +256 -68
- package/dist/chunk-YJPCS2GP.js.map +1 -0
- package/dist/{chunk-TLWGZVPC.js → chunk-YNSTIMCF.js} +746 -66
- package/dist/chunk-YNSTIMCF.js.map +1 -0
- package/dist/{chunk-QN76UJP7.js → chunk-YWDH6DQ6.js} +70 -4
- package/dist/chunk-YWDH6DQ6.js.map +1 -0
- package/dist/cli/index.js +23 -9
- package/dist/cli/index.js.map +1 -1
- package/dist/{codebuddy-DO7ZhoWn.d.ts → codebuddy-CHqMptZB.d.ts} +35 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +8 -8
- package/dist/install-EU35ERK5.js +30 -0
- package/dist/langgraph/index.d.ts +1 -1
- package/dist/lean-43ADYTBW.js +28 -0
- package/dist/{main-YJKSYFPT.js → main-SFC5LV4E.js} +704 -242
- package/dist/main-SFC5LV4E.js.map +1 -0
- package/dist/{operations-OG4ISWIM.js → operations-6Z6ZDVBP.js} +3 -3
- package/dist/{pretool-command-PRFOIHMW.js → pretool-command-B5GY5T6E.js} +2 -2
- package/dist/prompt-gate-TDTFFQW2.js +8 -0
- package/dist/{runtime-GCSEIAVD.js → runtime-W5AW32SD.js} +14 -6
- package/dist/{summaries-ML53R7EL.js → summaries-32PHOB6L.js} +3 -4
- package/dist/{zvec-XDZNZ2OL.js → zvec-24HLAFGN.js} +3 -4
- package/dist/zvec-24HLAFGN.js.map +1 -0
- package/package.json +11 -2
- package/dist/chunk-2WH2Q4TA.js.map +0 -1
- package/dist/chunk-ENKDFLOO.js.map +0 -1
- package/dist/chunk-F4BJ3DXW.js.map +0 -1
- package/dist/chunk-GKNYMNFM.js.map +0 -1
- package/dist/chunk-ITQO632W.js +0 -673
- package/dist/chunk-ITQO632W.js.map +0 -1
- package/dist/chunk-J4T6HHI4.js.map +0 -1
- package/dist/chunk-QN76UJP7.js.map +0 -1
- package/dist/chunk-SRA4MDVG.js.map +0 -1
- package/dist/chunk-TLWGZVPC.js.map +0 -1
- package/dist/chunk-UK6XTS2Y.js.map +0 -1
- package/dist/chunk-W7GAXL6C.js.map +0 -1
- package/dist/install-BXM56QCD.js +0 -19
- package/dist/lean-command-7DFW32MA.js +0 -19
- package/dist/main-YJKSYFPT.js.map +0 -1
- /package/dist/{adapters-S4HHTWJW.js.map → adapters-OJRSVFV3.js.map} +0 -0
- /package/dist/{chunk-GXOML4UZ.js.map → chunk-LW75SKZR.js.map} +0 -0
- /package/dist/{install-BXM56QCD.js.map → install-EU35ERK5.js.map} +0 -0
- /package/dist/{lean-command-7DFW32MA.js.map → lean-43ADYTBW.js.map} +0 -0
- /package/dist/{operations-OG4ISWIM.js.map → operations-6Z6ZDVBP.js.map} +0 -0
- /package/dist/{pretool-command-PRFOIHMW.js.map → pretool-command-B5GY5T6E.js.map} +0 -0
- /package/dist/{runtime-GCSEIAVD.js.map → prompt-gate-TDTFFQW2.js.map} +0 -0
- /package/dist/{summaries-ML53R7EL.js.map → runtime-W5AW32SD.js.map} +0 -0
- /package/dist/{zvec-XDZNZ2OL.js.map → summaries-32PHOB6L.js.map} +0 -0
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
isDockerDaemonRunning,
|
|
3
|
+
tryStartDockerDesktop,
|
|
4
|
+
waitForDockerDaemon
|
|
5
|
+
} from "./chunk-5UH3BEQR.js";
|
|
6
|
+
import {
|
|
7
|
+
postgresDown,
|
|
8
|
+
postgresStatus,
|
|
9
|
+
postgresUp
|
|
10
|
+
} from "./chunk-CSRD5OQA.js";
|
|
5
11
|
import {
|
|
6
12
|
runPreToolHookCommand
|
|
7
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-UOTKHSQ5.js";
|
|
8
14
|
import {
|
|
9
15
|
failSoft,
|
|
10
16
|
readHookInput,
|
|
@@ -13,6 +19,7 @@ import {
|
|
|
13
19
|
import {
|
|
14
20
|
WORKFLOW_CLIENTS,
|
|
15
21
|
clientDisplayName,
|
|
22
|
+
clientHookCapabilities,
|
|
16
23
|
clientHooksInstalled,
|
|
17
24
|
defaultRulesMode,
|
|
18
25
|
detectClient,
|
|
@@ -29,10 +36,12 @@ import {
|
|
|
29
36
|
removeCodexEntry,
|
|
30
37
|
renderManagedBlock,
|
|
31
38
|
renderWorkflowTemplate,
|
|
39
|
+
runBridgeHook,
|
|
40
|
+
runCodexHook,
|
|
32
41
|
setHooks,
|
|
33
42
|
uninstallClient,
|
|
34
43
|
writeProjectMcpConfig
|
|
35
|
-
} from "./chunk-
|
|
44
|
+
} from "./chunk-L6BRYZ6G.js";
|
|
36
45
|
import {
|
|
37
46
|
AUTOMATION_MODES,
|
|
38
47
|
CLIENT_ADAPTERS,
|
|
@@ -42,19 +51,14 @@ import {
|
|
|
42
51
|
parseClient,
|
|
43
52
|
parseMode,
|
|
44
53
|
supportedModes
|
|
45
|
-
} from "./chunk-
|
|
46
|
-
import {
|
|
47
|
-
isDockerDaemonRunning,
|
|
48
|
-
tryStartDockerDesktop,
|
|
49
|
-
waitForDockerDaemon
|
|
50
|
-
} from "./chunk-5UH3BEQR.js";
|
|
54
|
+
} from "./chunk-V7PT6ER5.js";
|
|
51
55
|
import {
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
} from "./chunk-CSRD5OQA.js";
|
|
56
|
+
renderLeanBlock,
|
|
57
|
+
runLeanHook
|
|
58
|
+
} from "./chunk-LRQNPYCK.js";
|
|
56
59
|
import {
|
|
57
60
|
TELEMETRY_NOTICE,
|
|
61
|
+
findReuse,
|
|
58
62
|
flushTelemetry,
|
|
59
63
|
generateSuggestions,
|
|
60
64
|
migrateMemoryToFiles,
|
|
@@ -68,13 +72,14 @@ import {
|
|
|
68
72
|
traceCliCommand,
|
|
69
73
|
watchRepository,
|
|
70
74
|
writeTelemetryState
|
|
71
|
-
} from "./chunk-
|
|
75
|
+
} from "./chunk-YJPCS2GP.js";
|
|
72
76
|
import {
|
|
73
77
|
DEFAULT_ZVEC_MODEL,
|
|
74
78
|
buildZvecIndex,
|
|
75
79
|
zvecStatus
|
|
76
|
-
} from "./chunk-
|
|
80
|
+
} from "./chunk-LW75SKZR.js";
|
|
77
81
|
import {
|
|
82
|
+
HookStagingStore,
|
|
78
83
|
PlanFileStore,
|
|
79
84
|
PlanLifecycle,
|
|
80
85
|
ReviewStore,
|
|
@@ -83,28 +88,40 @@ import {
|
|
|
83
88
|
assessRisk,
|
|
84
89
|
buildBeforeEditContext,
|
|
85
90
|
buildBootstrapContext,
|
|
91
|
+
findCodexRollouts,
|
|
92
|
+
forgetJournal,
|
|
93
|
+
importCodexRollout,
|
|
94
|
+
journalLag,
|
|
95
|
+
latestUnfinished,
|
|
96
|
+
listJournals,
|
|
86
97
|
openHookSemantics,
|
|
98
|
+
readCheckpoint,
|
|
99
|
+
renderCheckpointNow,
|
|
87
100
|
renderContextBlock,
|
|
88
101
|
resolveRiskPaths,
|
|
89
102
|
runCaptureHook,
|
|
103
|
+
runCheckpointHook,
|
|
90
104
|
runContextHook,
|
|
91
105
|
runResetHook,
|
|
106
|
+
runResumeHook,
|
|
92
107
|
runStageHook,
|
|
93
|
-
runSyncHook
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
SessionCapsuleLedger,
|
|
97
|
-
detectTestCommand,
|
|
98
|
-
estimateTokens
|
|
99
|
-
} from "./chunk-GKNYMNFM.js";
|
|
108
|
+
runSyncHook,
|
|
109
|
+
syncReuseVectors
|
|
110
|
+
} from "./chunk-XSNW6Y3X.js";
|
|
100
111
|
import {
|
|
101
112
|
parseTraceLines,
|
|
102
113
|
readTraces,
|
|
103
114
|
tracePath
|
|
104
115
|
} from "./chunk-YN7TEIUH.js";
|
|
116
|
+
import {
|
|
117
|
+
SessionCapsuleLedger,
|
|
118
|
+
detectTestCommand,
|
|
119
|
+
estimateTokens
|
|
120
|
+
} from "./chunk-4DKYKDHI.js";
|
|
105
121
|
import {
|
|
106
122
|
hookRoot
|
|
107
123
|
} from "./chunk-TGFTKWOR.js";
|
|
124
|
+
import "./chunk-GQKWUHMA.js";
|
|
108
125
|
import "./chunk-DFV2SK6C.js";
|
|
109
126
|
import {
|
|
110
127
|
bootstrapDatabase,
|
|
@@ -117,11 +134,11 @@ import {
|
|
|
117
134
|
pingDatabase,
|
|
118
135
|
runDoctor,
|
|
119
136
|
runMigrations
|
|
120
|
-
} from "./chunk-
|
|
137
|
+
} from "./chunk-YWDH6DQ6.js";
|
|
121
138
|
import {
|
|
122
139
|
MemoryFileStore,
|
|
123
140
|
VERSION
|
|
124
|
-
} from "./chunk-
|
|
141
|
+
} from "./chunk-7QMHIJBA.js";
|
|
125
142
|
import {
|
|
126
143
|
computeFactHash,
|
|
127
144
|
generateEntityId
|
|
@@ -134,25 +151,24 @@ import {
|
|
|
134
151
|
import {
|
|
135
152
|
loadLlmSummaries,
|
|
136
153
|
summarizeRepository
|
|
137
|
-
} from "./chunk-
|
|
154
|
+
} from "./chunk-ESC4Y3L7.js";
|
|
138
155
|
import {
|
|
139
156
|
chatJson,
|
|
140
157
|
coolingDown,
|
|
141
158
|
usageToday
|
|
142
159
|
} from "./chunk-ESZXCZIN.js";
|
|
143
|
-
import {
|
|
144
|
-
generateGraphifyGraph,
|
|
145
|
-
loadGraphifyMap,
|
|
146
|
-
setupGraphify,
|
|
147
|
-
syncFileVectors
|
|
148
|
-
} from "./chunk-TLWGZVPC.js";
|
|
149
160
|
import {
|
|
150
161
|
buildArchitectureMap,
|
|
162
|
+
generateGraphifyGraph,
|
|
151
163
|
indexRepository,
|
|
152
164
|
loadFreshIndex,
|
|
165
|
+
loadGraphifyMap,
|
|
166
|
+
loadProjectArchitectureMap,
|
|
153
167
|
neighbours,
|
|
154
|
-
queryMap
|
|
155
|
-
|
|
168
|
+
queryMap,
|
|
169
|
+
setupGraphify,
|
|
170
|
+
syncFileVectors
|
|
171
|
+
} from "./chunk-YNSTIMCF.js";
|
|
156
172
|
import {
|
|
157
173
|
extractSymbolTable,
|
|
158
174
|
supportsSymbols
|
|
@@ -187,12 +203,14 @@ import {
|
|
|
187
203
|
setZvecEnabled,
|
|
188
204
|
writeConfigFile
|
|
189
205
|
} from "./chunk-KNR2P2UY.js";
|
|
190
|
-
import
|
|
206
|
+
import {
|
|
207
|
+
writeAtomic
|
|
208
|
+
} from "./chunk-CG5B3LYG.js";
|
|
191
209
|
import "./chunk-PZ5AY32C.js";
|
|
192
210
|
|
|
193
211
|
// src/cli/main.ts
|
|
194
212
|
import { Command } from "commander";
|
|
195
|
-
import
|
|
213
|
+
import pc25 from "picocolors";
|
|
196
214
|
|
|
197
215
|
// src/integrations/github.ts
|
|
198
216
|
import { constants } from "fs";
|
|
@@ -770,6 +788,7 @@ var CONFORMANCE = {
|
|
|
770
788
|
const servers = json(result.stdout);
|
|
771
789
|
if (!Array.isArray(servers)) return [fail("mcp", "codex mcp list --json returned no JSON")];
|
|
772
790
|
return [
|
|
791
|
+
await clientHooksInstalled(root, "codex") ? pass("hooks", ".codex/hooks.json is installed; review trust in Codex /hooks") : skip("hooks", "not installed in this repo"),
|
|
773
792
|
servers.some((server) => server.name === name2) ? pass("mcp", `codex mcp list has ${name2}`) : skip("mcp", `no ${name2} entry (clients install codex --global adds it)`)
|
|
774
793
|
];
|
|
775
794
|
},
|
|
@@ -863,7 +882,7 @@ function registerClientsCommands(program, runSafely2) {
|
|
|
863
882
|
console.log(pc2.dim("Per-turn token cost per client: codebuddy clients cost"));
|
|
864
883
|
});
|
|
865
884
|
});
|
|
866
|
-
clients.command("install").argument("<client>", `One of: ${CLIENT_IDS.join(", ")}.`).requiredOption("--mode <mode>", `One of: ${AUTOMATION_MODES.join(", ")}.`).option("--namespace <name>", "Namespace for the MCP entry (defaults to config/folder).").option("--global", "Also add the MCP entry to the global config (Codex, Hermes).").description("Apply one automation mode: rules block, hooks, and MCP config.").action(
|
|
885
|
+
clients.command("install").argument("<client>", `One of: ${CLIENT_IDS.join(", ")}.`).requiredOption("--mode <mode>", `One of: ${AUTOMATION_MODES.join(", ")}.`).option("--namespace <name>", "Namespace for the MCP entry (defaults to config/folder).").option("--global", "Also add the MCP entry to the global config (Codex, Hermes).").option("--capture", "Capture turns into memory even in lean mode (Claude Code).").option("--no-capture", "Inject context without capturing turns (Claude Code).").description("Apply one automation mode: rules block, hooks, and MCP config.").action(
|
|
867
886
|
async (client, opts) => {
|
|
868
887
|
await runSafely2(async () => {
|
|
869
888
|
const mode = parseMode(opts.mode);
|
|
@@ -871,7 +890,8 @@ function registerClientsCommands(program, runSafely2) {
|
|
|
871
890
|
client: parseClient(client),
|
|
872
891
|
mode,
|
|
873
892
|
...opts.namespace ? { namespace: opts.namespace } : {},
|
|
874
|
-
...opts.global ? { global: true } : {}
|
|
893
|
+
...opts.global ? { global: true } : {},
|
|
894
|
+
...opts.capture !== void 0 ? { capture: opts.capture } : {}
|
|
875
895
|
});
|
|
876
896
|
printReport2(report, `${MODE_LABELS[mode]} mode`);
|
|
877
897
|
});
|
|
@@ -983,6 +1003,30 @@ function registerContextCommands(program, runSafely2) {
|
|
|
983
1003
|
printBootstrap(result);
|
|
984
1004
|
});
|
|
985
1005
|
});
|
|
1006
|
+
context.command("reuse").argument("<task...>", "What you are about to implement.").option("--json", "Print machine-readable JSON.").description(
|
|
1007
|
+
"Existing helpers to reuse for a task: signature, a call site and the covering test."
|
|
1008
|
+
).action(async (taskParts, opts) => {
|
|
1009
|
+
await runSafely2(async () => {
|
|
1010
|
+
const root = process.cwd();
|
|
1011
|
+
const { manifest } = await loadFreshIndex(root);
|
|
1012
|
+
const picks = await findReuse(
|
|
1013
|
+
root,
|
|
1014
|
+
taskParts.join(" "),
|
|
1015
|
+
manifest,
|
|
1016
|
+
await loadProjectArchitectureMap(root, manifest)
|
|
1017
|
+
);
|
|
1018
|
+
if (opts.json) {
|
|
1019
|
+
console.log(JSON.stringify(picks, null, 2));
|
|
1020
|
+
return;
|
|
1021
|
+
}
|
|
1022
|
+
if (picks.length === 0) console.log(pc3.dim("no existing helper clearly matches"));
|
|
1023
|
+
for (const pick of picks) {
|
|
1024
|
+
console.log(`${pick.path}:${pick.startLine}-${pick.endLine} ${pick.signature}`);
|
|
1025
|
+
if (pick.usage) console.log(pc3.dim(` used at ${pick.usage}`));
|
|
1026
|
+
if (pick.test) console.log(pc3.dim(` test ${pick.test}`));
|
|
1027
|
+
}
|
|
1028
|
+
});
|
|
1029
|
+
});
|
|
986
1030
|
context.command("preview").argument("[task...]", "The task you are about to work on.").option("--paths <paths>", "Comma-separated repo-relative paths to target.").option("--plan <id>", "Resolve target files from a CodeBuddy plan.").option("--git", "Resolve target files from current git changes.").option("--json", "Print machine-readable JSON.").description("Show the context CodeBuddy would assemble before editing the given files.").action(
|
|
987
1031
|
async (taskParts, opts) => {
|
|
988
1032
|
await runSafely2(async () => {
|
|
@@ -1720,15 +1764,22 @@ function registerGitHubCommands(program, runSafely2) {
|
|
|
1720
1764
|
import { execFile as execFile2, spawn as spawn3 } from "child_process";
|
|
1721
1765
|
import { relative as relative2 } from "path";
|
|
1722
1766
|
import pc7 from "picocolors";
|
|
1767
|
+
|
|
1768
|
+
// src/hooks/lean-command.ts
|
|
1769
|
+
async function runLeanHookCommand() {
|
|
1770
|
+
await failSoft(async () => {
|
|
1771
|
+
await runLeanHook(await readHookInput(), writeStdout);
|
|
1772
|
+
});
|
|
1773
|
+
}
|
|
1774
|
+
|
|
1775
|
+
// src/cli/commands/hooks.ts
|
|
1723
1776
|
function registerHooksCommands(program, runSafely2) {
|
|
1724
1777
|
const hooks = program.command("hooks").description("Enforce automatic recall/capture via client lifecycle hooks.");
|
|
1725
1778
|
hooks.command("install").option(
|
|
1726
1779
|
"--client <client>",
|
|
1727
|
-
"Client with a CodeBuddy hook adapter (claude, opencode, hermes).",
|
|
1780
|
+
"Client with a CodeBuddy hook adapter (claude, codex, opencode, hermes).",
|
|
1728
1781
|
"claude"
|
|
1729
|
-
).description(
|
|
1730
|
-
"Add CodeBuddy's recall/capture hooks (.claude/settings.json, .opencode/plugins/codebuddy.js or .hermes/plugins/codebuddy/)."
|
|
1731
|
-
).action(async (opts) => {
|
|
1782
|
+
).description("Add CodeBuddy's recall/capture hooks for the selected client.").action(async (opts) => {
|
|
1732
1783
|
await runSafely2(async () => {
|
|
1733
1784
|
const client = assertHookClient(opts.client);
|
|
1734
1785
|
const step = await setHooks(process.cwd(), true, client);
|
|
@@ -1750,7 +1801,7 @@ function registerHooksCommands(program, runSafely2) {
|
|
|
1750
1801
|
});
|
|
1751
1802
|
hooks.command("uninstall").option(
|
|
1752
1803
|
"--client <client>",
|
|
1753
|
-
"Client with a CodeBuddy hook adapter (claude, opencode, hermes).",
|
|
1804
|
+
"Client with a CodeBuddy hook adapter (claude, codex, opencode, hermes).",
|
|
1754
1805
|
"claude"
|
|
1755
1806
|
).description("Remove CodeBuddy's hooks for a client (user hooks untouched).").action(async (opts) => {
|
|
1756
1807
|
await runSafely2(async () => {
|
|
@@ -1764,15 +1815,44 @@ function registerHooksCommands(program, runSafely2) {
|
|
|
1764
1815
|
});
|
|
1765
1816
|
hooks.command("status").option(
|
|
1766
1817
|
"--client <client>",
|
|
1767
|
-
"Client with a CodeBuddy hook adapter (claude, opencode, hermes).",
|
|
1818
|
+
"Client with a CodeBuddy hook adapter (claude, codex, opencode, hermes).",
|
|
1768
1819
|
"claude"
|
|
1769
|
-
).description("Report
|
|
1820
|
+
).description("Report which CodeBuddy hooks are installed and what they do.").action(async (opts) => {
|
|
1770
1821
|
await runSafely2(async () => {
|
|
1771
|
-
const
|
|
1822
|
+
const caps = await clientHookCapabilities(process.cwd(), parseClient(opts.client));
|
|
1823
|
+
if (!caps?.injection) {
|
|
1824
|
+
console.log(pc7.dim("CodeBuddy hooks: not installed"));
|
|
1825
|
+
return;
|
|
1826
|
+
}
|
|
1827
|
+
console.log(pc7.green("CodeBuddy hooks: installed"));
|
|
1828
|
+
console.log(` injection: ${caps.injection}`);
|
|
1829
|
+
console.log(
|
|
1830
|
+
` capture: ${caps.capture ? "on (edits staged, turn end captured)" : "off (turns are not captured into memory)"}`
|
|
1831
|
+
);
|
|
1772
1832
|
console.log(
|
|
1773
|
-
|
|
1833
|
+
` recovery: ${caps.recovery ? "on (pre-compaction checkpoint, unfinished-task resume)" : "off"}`
|
|
1834
|
+
);
|
|
1835
|
+
console.log(` compaction reset: ${caps.reset ? "on" : "off"}`);
|
|
1836
|
+
console.log(` read guard: ${caps.guard ? "on" : "off"}`);
|
|
1837
|
+
});
|
|
1838
|
+
});
|
|
1839
|
+
hooks.command("codex").option("--injection <mode>", "full or lean", "full").option("--capture", "Capture visible lifecycle events", false).description("[hook] Native Codex event adapter (JSON output, no permission changes).").action(async (opts) => {
|
|
1840
|
+
let result = {};
|
|
1841
|
+
await failSoft(async () => {
|
|
1842
|
+
if (opts.injection !== "full" && opts.injection !== "lean")
|
|
1843
|
+
throw new Error("injection must be full or lean");
|
|
1844
|
+
result = await runCodexHook(
|
|
1845
|
+
await readHookInput(),
|
|
1846
|
+
opts.injection,
|
|
1847
|
+
opts.capture
|
|
1774
1848
|
);
|
|
1775
1849
|
});
|
|
1850
|
+
await writeStdout(JSON.stringify(result));
|
|
1851
|
+
});
|
|
1852
|
+
hooks.command("bridge").description("[hook] Capture normalized host events and restore checkpoint context.").action(async () => {
|
|
1853
|
+
await failSoft(async () => {
|
|
1854
|
+
await runBridgeHook(await readHookInput(), writeStdout);
|
|
1855
|
+
});
|
|
1776
1856
|
});
|
|
1777
1857
|
hooks.command("context").description("[hook] Emit compact project context for injection at prompt submit.").action(async () => {
|
|
1778
1858
|
await failSoft(async () => {
|
|
@@ -1824,6 +1904,16 @@ function registerHooksCommands(program, runSafely2) {
|
|
|
1824
1904
|
await runResetHook(await readHookInput(), writeStdout);
|
|
1825
1905
|
});
|
|
1826
1906
|
});
|
|
1907
|
+
hooks.command("checkpoint").description("[hook] Journal the transcript before compaction (PreCompact).").action(async () => {
|
|
1908
|
+
await failSoft(async () => {
|
|
1909
|
+
await runCheckpointHook(await readHookInput());
|
|
1910
|
+
});
|
|
1911
|
+
});
|
|
1912
|
+
hooks.command("resume").description("[hook] Print another session's unfinished task checkpoint, if any.").action(async () => {
|
|
1913
|
+
await failSoft(async () => {
|
|
1914
|
+
await runResumeHook(await readHookInput(), writeStdout);
|
|
1915
|
+
});
|
|
1916
|
+
});
|
|
1827
1917
|
}
|
|
1828
1918
|
function assertHookClient(value) {
|
|
1829
1919
|
const client = parseClient(value);
|
|
@@ -2010,9 +2100,21 @@ function registerIndexCommands(program, runSafely2) {
|
|
|
2010
2100
|
await runSafely2(async () => {
|
|
2011
2101
|
const result = await indexRepository({ ...opts.full ? { full: true } : {} });
|
|
2012
2102
|
const local = opts.vectors && (await loadRuntimeConfig(process.cwd(), { requireDatabase: false }).catch(() => null))?.provider.type === "local";
|
|
2103
|
+
const vectorStarted = Date.now();
|
|
2013
2104
|
const vectors = local ? await syncFileVectors(process.cwd(), VECTOR_BUDGET_MS) : null;
|
|
2105
|
+
const reuseVectors = local ? await syncReuseVectors(process.cwd(), VECTOR_BUDGET_MS - (Date.now() - vectorStarted)) : null;
|
|
2014
2106
|
if (opts.json) {
|
|
2015
|
-
console.log(
|
|
2107
|
+
console.log(
|
|
2108
|
+
JSON.stringify(
|
|
2109
|
+
{
|
|
2110
|
+
...result,
|
|
2111
|
+
...vectors ? { vectors } : {},
|
|
2112
|
+
...reuseVectors ? { reuseVectors } : {}
|
|
2113
|
+
},
|
|
2114
|
+
null,
|
|
2115
|
+
2
|
|
2116
|
+
)
|
|
2117
|
+
);
|
|
2016
2118
|
return;
|
|
2017
2119
|
}
|
|
2018
2120
|
printResult(result);
|
|
@@ -2202,8 +2304,59 @@ async function runInitWizard() {
|
|
|
2202
2304
|
}
|
|
2203
2305
|
}
|
|
2204
2306
|
|
|
2205
|
-
// src/cli/commands/
|
|
2307
|
+
// src/cli/commands/journal.ts
|
|
2206
2308
|
import pc10 from "picocolors";
|
|
2309
|
+
function registerJournalCommands(program, runSafely2) {
|
|
2310
|
+
const journal = program.command("journal").description("Inspect or delete session journals and active-task checkpoints.");
|
|
2311
|
+
journal.command("list", { isDefault: true }).description("List sessions with a checkpoint, newest first.").action(async () => {
|
|
2312
|
+
await runSafely2(async () => {
|
|
2313
|
+
const sessions = await listJournals(process.cwd());
|
|
2314
|
+
if (sessions.length === 0) console.log(pc10.dim("no session journals yet"));
|
|
2315
|
+
for (const { session, updatedAt } of sessions) console.log(`${updatedAt} ${session}`);
|
|
2316
|
+
});
|
|
2317
|
+
});
|
|
2318
|
+
journal.command("show").argument("<session>").description("Print a session's active-task checkpoint as JSON.").action(async (session) => {
|
|
2319
|
+
await runSafely2(async () => {
|
|
2320
|
+
const checkpoint = await readCheckpoint(process.cwd(), session);
|
|
2321
|
+
console.log(checkpoint ? JSON.stringify(checkpoint, null, 2) : pc10.dim("no checkpoint"));
|
|
2322
|
+
});
|
|
2323
|
+
});
|
|
2324
|
+
journal.command("resume").description("Print the newest unfinished task checkpoint (any session or agent).").action(async () => {
|
|
2325
|
+
await runSafely2(async () => {
|
|
2326
|
+
const checkpoint = await latestUnfinished(process.cwd(), void 0);
|
|
2327
|
+
console.log(
|
|
2328
|
+
checkpoint ? await renderCheckpointNow(
|
|
2329
|
+
process.cwd(),
|
|
2330
|
+
checkpoint,
|
|
2331
|
+
`unfinished, from session ${checkpoint.session}`
|
|
2332
|
+
) : pc10.dim("no unfinished task in the last 3 days")
|
|
2333
|
+
);
|
|
2334
|
+
});
|
|
2335
|
+
});
|
|
2336
|
+
journal.command("import-codex").option("--all", "Import every Codex rollout for this repository, not only the newest.").description("Journal Codex rollouts (~/.codex/sessions) whose working directory is this repo.").action(async (opts) => {
|
|
2337
|
+
await runSafely2(async () => {
|
|
2338
|
+
const rollouts = await findCodexRollouts(process.cwd());
|
|
2339
|
+
if (rollouts.length === 0) {
|
|
2340
|
+
console.log(pc10.dim("no Codex rollout for this repository"));
|
|
2341
|
+
return;
|
|
2342
|
+
}
|
|
2343
|
+
for (const rollout of opts.all ? rollouts : rollouts.slice(0, 1)) {
|
|
2344
|
+
const result = await importCodexRollout(process.cwd(), rollout);
|
|
2345
|
+
console.log(`codex-${rollout.id}: ${result ? `${result.added} new events` : "busy"}`);
|
|
2346
|
+
}
|
|
2347
|
+
});
|
|
2348
|
+
});
|
|
2349
|
+
journal.command("forget").argument("[session]").option("--all", "Delete every session's journal.").description("Delete a session's journal, cursor and checkpoint.").action(async (session, opts) => {
|
|
2350
|
+
await runSafely2(async () => {
|
|
2351
|
+
if (!session && !opts.all) throw new Error("Name a session or pass --all.");
|
|
2352
|
+
await forgetJournal(process.cwd(), opts.all ? void 0 : session);
|
|
2353
|
+
console.log(pc10.yellow(opts.all ? "deleted all session journals" : `deleted ${session}`));
|
|
2354
|
+
});
|
|
2355
|
+
});
|
|
2356
|
+
}
|
|
2357
|
+
|
|
2358
|
+
// src/cli/commands/learn.ts
|
|
2359
|
+
import pc11 from "picocolors";
|
|
2207
2360
|
|
|
2208
2361
|
// src/learning/outcomes.ts
|
|
2209
2362
|
async function recordChangeOutcome(input) {
|
|
@@ -2264,15 +2417,15 @@ function registerLearnCommand(program, runSafely2) {
|
|
|
2264
2417
|
...opts.commit ? { commit: opts.commit } : {},
|
|
2265
2418
|
...opts.plan ? { planId: opts.plan } : {}
|
|
2266
2419
|
});
|
|
2267
|
-
console.log(`${
|
|
2268
|
-
console.log(
|
|
2420
|
+
console.log(`${pc11.green("recorded")} ${result.id} (${result.category})`);
|
|
2421
|
+
console.log(pc11.dim(result.path));
|
|
2269
2422
|
});
|
|
2270
2423
|
}
|
|
2271
2424
|
);
|
|
2272
2425
|
}
|
|
2273
2426
|
|
|
2274
2427
|
// src/cli/commands/map.ts
|
|
2275
|
-
import
|
|
2428
|
+
import pc12 from "picocolors";
|
|
2276
2429
|
function registerMapCommands(program, runSafely2) {
|
|
2277
2430
|
const map = program.command("map").description("Query the lightweight architecture map.");
|
|
2278
2431
|
map.command("build").description("Scan the current repository and summarize the module graph.").action(async () => {
|
|
@@ -2292,7 +2445,7 @@ function registerMapCommands(program, runSafely2) {
|
|
|
2292
2445
|
return;
|
|
2293
2446
|
}
|
|
2294
2447
|
if (edges.length === 0) {
|
|
2295
|
-
console.log(
|
|
2448
|
+
console.log(pc12.dim("no dependencies found"));
|
|
2296
2449
|
return;
|
|
2297
2450
|
}
|
|
2298
2451
|
for (const edge of edges) console.log(`${edge.from} -> ${edge.to}`);
|
|
@@ -2307,7 +2460,7 @@ function registerMapCommands(program, runSafely2) {
|
|
|
2307
2460
|
return;
|
|
2308
2461
|
}
|
|
2309
2462
|
if (result.edges.length === 0) {
|
|
2310
|
-
console.log(
|
|
2463
|
+
console.log(pc12.dim("no dependents found"));
|
|
2311
2464
|
return;
|
|
2312
2465
|
}
|
|
2313
2466
|
for (const edge of result.edges) console.log(`${edge.from} -> ${edge.to}`);
|
|
@@ -2318,7 +2471,7 @@ function registerMapCommands(program, runSafely2) {
|
|
|
2318
2471
|
// src/cli/commands/memory-review.ts
|
|
2319
2472
|
import { spawn as spawn4 } from "child_process";
|
|
2320
2473
|
import { relative as relative3 } from "path";
|
|
2321
|
-
import
|
|
2474
|
+
import pc13 from "picocolors";
|
|
2322
2475
|
function registerMemoryCommands(program, runSafely2) {
|
|
2323
2476
|
const memory = program.command("memory").description("Inspect and curate CodeBuddy memory.");
|
|
2324
2477
|
const review = memory.command("review").description("Review memory candidates captured automatically after turns.");
|
|
@@ -2330,11 +2483,11 @@ function registerMemoryCommands(program, runSafely2) {
|
|
|
2330
2483
|
return;
|
|
2331
2484
|
}
|
|
2332
2485
|
if (items.length === 0) {
|
|
2333
|
-
console.log(
|
|
2486
|
+
console.log(pc13.dim("no pending review items"));
|
|
2334
2487
|
return;
|
|
2335
2488
|
}
|
|
2336
2489
|
for (const item of items) console.log(renderRow(item));
|
|
2337
|
-
console.log(
|
|
2490
|
+
console.log(pc13.dim(`
|
|
2338
2491
|
${items.length} pending. approve <id> | reject <id> | show <id>`));
|
|
2339
2492
|
});
|
|
2340
2493
|
});
|
|
@@ -2348,7 +2501,7 @@ ${items.length} pending. approve <id> | reject <id> | show <id>`));
|
|
|
2348
2501
|
const factId = await approveReviewItem(id, {
|
|
2349
2502
|
...opts.incident !== void 0 ? { incidentId: opts.incident } : {}
|
|
2350
2503
|
});
|
|
2351
|
-
console.log(`${
|
|
2504
|
+
console.log(`${pc13.green("approved")} ${id} \u2192 ${factId}`);
|
|
2352
2505
|
});
|
|
2353
2506
|
});
|
|
2354
2507
|
review.command("reject").argument("<id>").description("Discard a review candidate without saving it.").action(async (id) => {
|
|
@@ -2356,7 +2509,7 @@ ${items.length} pending. approve <id> | reject <id> | show <id>`));
|
|
|
2356
2509
|
const store = new ReviewStore();
|
|
2357
2510
|
await store.read(id);
|
|
2358
2511
|
await store.delete(id);
|
|
2359
|
-
console.log(`${
|
|
2512
|
+
console.log(`${pc13.yellow("rejected")} ${id}`);
|
|
2360
2513
|
});
|
|
2361
2514
|
});
|
|
2362
2515
|
review.command("edit").argument("<id>").description("Open a review candidate in $EDITOR and re-validate on save.").action(async (id) => {
|
|
@@ -2365,44 +2518,44 @@ ${items.length} pending. approve <id> | reject <id> | show <id>`));
|
|
|
2365
2518
|
const item = await store.read(id);
|
|
2366
2519
|
await openEditor(item.path);
|
|
2367
2520
|
await store.read(id);
|
|
2368
|
-
console.log(
|
|
2521
|
+
console.log(pc13.dim("saved and validated"));
|
|
2369
2522
|
});
|
|
2370
2523
|
});
|
|
2371
2524
|
}
|
|
2372
2525
|
function renderRow(item) {
|
|
2373
|
-
const flag = item.sensitive ?
|
|
2374
|
-
return `${classColor(item.class)} ${
|
|
2526
|
+
const flag = item.sensitive ? pc13.red(" \u26A0 sensitive") : "";
|
|
2527
|
+
return `${classColor(item.class)} ${pc13.dim(item.id)} ${truncate(item.content, 70)}${flag}`;
|
|
2375
2528
|
}
|
|
2376
2529
|
function renderItem(item) {
|
|
2377
2530
|
const lines = [
|
|
2378
|
-
`${classColor(item.class)} ${
|
|
2379
|
-
`${
|
|
2380
|
-
`${
|
|
2381
|
-
`${
|
|
2531
|
+
`${classColor(item.class)} ${pc13.dim(item.id)}`,
|
|
2532
|
+
`${pc13.bold("reason:")} ${item.reason}`,
|
|
2533
|
+
`${pc13.bold("confidence:")} ${item.confidence.toFixed(2)}`,
|
|
2534
|
+
`${pc13.bold("triple:")} ${item.subject} \xB7 ${item.predicate} \xB7 ${item.object}`
|
|
2382
2535
|
];
|
|
2383
|
-
if (item.paths.length > 0) lines.push(`${
|
|
2384
|
-
if (item.severity) lines.push(`${
|
|
2536
|
+
if (item.paths.length > 0) lines.push(`${pc13.bold("paths:")} ${item.paths.join(", ")}`);
|
|
2537
|
+
if (item.severity) lines.push(`${pc13.bold("severity:")} ${item.severity}`);
|
|
2385
2538
|
if (item.resolvesIncidents) {
|
|
2386
2539
|
lines.push(
|
|
2387
|
-
`${
|
|
2540
|
+
`${pc13.bold("resolves:")} ${item.resolvesIncidents.join(", ") || "(no candidate; approve with --incident <id>)"}`
|
|
2388
2541
|
);
|
|
2389
2542
|
}
|
|
2390
|
-
if (item.sensitive) lines.push(
|
|
2391
|
-
lines.push("", item.content, "",
|
|
2543
|
+
if (item.sensitive) lines.push(pc13.red(`\u26A0 sensitive: ${item.sensitiveReasons.join(", ")}`));
|
|
2544
|
+
lines.push("", item.content, "", pc13.dim(relative3(process.cwd(), item.path)));
|
|
2392
2545
|
return lines.join("\n");
|
|
2393
2546
|
}
|
|
2394
2547
|
function classColor(memoryClass) {
|
|
2395
2548
|
switch (memoryClass) {
|
|
2396
2549
|
case "incident":
|
|
2397
|
-
return
|
|
2550
|
+
return pc13.red(memoryClass);
|
|
2398
2551
|
case "decision":
|
|
2399
|
-
return
|
|
2552
|
+
return pc13.cyan(memoryClass);
|
|
2400
2553
|
case "fact":
|
|
2401
|
-
return
|
|
2554
|
+
return pc13.green(memoryClass);
|
|
2402
2555
|
case "note":
|
|
2403
|
-
return
|
|
2556
|
+
return pc13.yellow(memoryClass);
|
|
2404
2557
|
default:
|
|
2405
|
-
return
|
|
2558
|
+
return pc13.dim(memoryClass);
|
|
2406
2559
|
}
|
|
2407
2560
|
}
|
|
2408
2561
|
function truncate(value, max) {
|
|
@@ -2422,7 +2575,7 @@ function openEditor(path) {
|
|
|
2422
2575
|
import { existsSync } from "fs";
|
|
2423
2576
|
import { join as join5 } from "path";
|
|
2424
2577
|
import { spinner as spinner2 } from "@clack/prompts";
|
|
2425
|
-
import
|
|
2578
|
+
import pc14 from "picocolors";
|
|
2426
2579
|
|
|
2427
2580
|
// evals/fact-relevance.json
|
|
2428
2581
|
var fact_relevance_default = {
|
|
@@ -2686,9 +2839,9 @@ async function calibrateEmbedder(embed) {
|
|
|
2686
2839
|
var EMBEDDERS = ["local", "huggingface", "openrouter"];
|
|
2687
2840
|
var RERANKERS = ["off", "local", "huggingface", "openrouter"];
|
|
2688
2841
|
var KEY_ENV2 = { huggingface: "HF_TOKEN", openrouter: "OPENROUTER_API_KEY" };
|
|
2689
|
-
var ok = (text3) => `${
|
|
2690
|
-
var warn = (text3) => `${
|
|
2691
|
-
var row = (label, value) => ` ${
|
|
2842
|
+
var ok = (text3) => `${pc14.green("\u2713")} ${text3}`;
|
|
2843
|
+
var warn = (text3) => `${pc14.yellow("!")} ${text3}`;
|
|
2844
|
+
var row = (label, value) => ` ${pc14.dim(label.padEnd(11))}${value}`;
|
|
2692
2845
|
async function withSpinner(label, work, done) {
|
|
2693
2846
|
const progress = spinner2();
|
|
2694
2847
|
progress.start(label);
|
|
@@ -2697,7 +2850,7 @@ async function withSpinner(label, work, done) {
|
|
|
2697
2850
|
progress.stop(done(value));
|
|
2698
2851
|
return value;
|
|
2699
2852
|
} catch (error) {
|
|
2700
|
-
progress.error(
|
|
2853
|
+
progress.error(pc14.red(`\u2717 ${label}`));
|
|
2701
2854
|
throw error;
|
|
2702
2855
|
}
|
|
2703
2856
|
}
|
|
@@ -2736,8 +2889,8 @@ async function printStatus() {
|
|
|
2736
2889
|
const model = provider.type === "local" ? LOCAL_EMBEDDING_MODEL.id : provider.model ?? DEFAULT_CLOUD_EMBEDDING_MODELS[provider.type];
|
|
2737
2890
|
const floor = provider.relevanceFloor ?? getModelDefinition(model)?.relevanceFloor;
|
|
2738
2891
|
const next = [];
|
|
2739
|
-
console.log(
|
|
2740
|
-
console.log(row("provider", `${provider.type} ${
|
|
2892
|
+
console.log(pc14.bold("Embeddings"));
|
|
2893
|
+
console.log(row("provider", `${provider.type} ${pc14.dim(model)}`));
|
|
2741
2894
|
if (provider.type === "local" && !localRuntimeInstalled()) {
|
|
2742
2895
|
console.log(
|
|
2743
2896
|
row("runtime", warn("@huggingface/transformers is not installed: dense recall is off"))
|
|
@@ -2748,7 +2901,7 @@ async function printStatus() {
|
|
|
2748
2901
|
console.log(
|
|
2749
2902
|
row(
|
|
2750
2903
|
"model",
|
|
2751
|
-
ready ? ok(`downloaded ${
|
|
2904
|
+
ready ? ok(`downloaded ${pc14.dim(modelCacheDir())}`) : warn("not downloaded yet (~90 MB)")
|
|
2752
2905
|
)
|
|
2753
2906
|
);
|
|
2754
2907
|
if (!ready) next.push("codebuddy models pull");
|
|
@@ -2765,21 +2918,21 @@ async function printStatus() {
|
|
|
2765
2918
|
console.log(
|
|
2766
2919
|
row(
|
|
2767
2920
|
"floor",
|
|
2768
|
-
floor !== void 0 ? `${floor} ${
|
|
2921
|
+
floor !== void 0 ? `${floor} ${pc14.dim(provider.relevanceFloor !== void 0 ? "(calibrated for this project)" : "(built-in)")}` : warn("not calibrated: dense recall is off for this model")
|
|
2769
2922
|
)
|
|
2770
2923
|
);
|
|
2771
2924
|
if (floor === void 0) next.push("codebuddy models calibrate");
|
|
2772
2925
|
const rerank = file.rerank?.provider ?? "off";
|
|
2773
|
-
console.log(
|
|
2926
|
+
console.log(pc14.bold("Reranker"));
|
|
2774
2927
|
if (rerank === "off") {
|
|
2775
2928
|
console.log(
|
|
2776
|
-
row("provider", `off ${
|
|
2929
|
+
row("provider", `off ${pc14.dim("(default: no reranker beat dense order in evals)")}`)
|
|
2777
2930
|
);
|
|
2778
2931
|
} else {
|
|
2779
2932
|
console.log(
|
|
2780
2933
|
row(
|
|
2781
2934
|
"provider",
|
|
2782
|
-
`${rerank} ${
|
|
2935
|
+
`${rerank} ${pc14.dim(file.rerank?.model ?? DEFAULT_RERANK_MODELS[rerank].id)}`
|
|
2783
2936
|
)
|
|
2784
2937
|
);
|
|
2785
2938
|
if (rerank !== "local") {
|
|
@@ -2792,7 +2945,7 @@ async function printStatus() {
|
|
|
2792
2945
|
);
|
|
2793
2946
|
}
|
|
2794
2947
|
}
|
|
2795
|
-
console.log(
|
|
2948
|
+
console.log(pc14.bold("Memory index"));
|
|
2796
2949
|
if (process.env.CODEBUDDY_SEMANTIC === "0") {
|
|
2797
2950
|
console.log(row("recall", warn("CODEBUDDY_SEMANTIC=0: lexical only")));
|
|
2798
2951
|
}
|
|
@@ -2813,7 +2966,7 @@ async function printStatus() {
|
|
|
2813
2966
|
console.log(
|
|
2814
2967
|
row(
|
|
2815
2968
|
"vectors",
|
|
2816
|
-
`${counts.ready} ready` + (counts.pending ? `, ${counts.pending} pending` : "") + (counts.failed ?
|
|
2969
|
+
`${counts.ready} ready` + (counts.pending ? `, ${counts.pending} pending` : "") + (counts.failed ? pc14.red(`, ${counts.failed} failed`) : "") + (counts.other ? pc14.yellow(`, ${counts.other} from another model`) : "")
|
|
2817
2970
|
)
|
|
2818
2971
|
);
|
|
2819
2972
|
if (counts.pending || counts.other)
|
|
@@ -2822,9 +2975,9 @@ async function printStatus() {
|
|
|
2822
2975
|
}
|
|
2823
2976
|
console.log(
|
|
2824
2977
|
next.length > 0 ? `
|
|
2825
|
-
${
|
|
2826
|
-
${next.map((step) => ` ${
|
|
2827
|
-
${ok("Semantic recall is ready.")} ${
|
|
2978
|
+
${pc14.bold("Next")}
|
|
2979
|
+
${next.map((step) => ` ${pc14.cyan(step)}`).join("\n")}` : `
|
|
2980
|
+
${ok("Semantic recall is ready.")} ${pc14.dim('Try: codebuddy context preview "<task>"')}`
|
|
2828
2981
|
);
|
|
2829
2982
|
}
|
|
2830
2983
|
function registerModelsCommands(program, runSafely2) {
|
|
@@ -2861,27 +3014,27 @@ Examples:
|
|
|
2861
3014
|
...opts.floor !== void 0 ? { relevanceFloor: opts.floor } : {}
|
|
2862
3015
|
});
|
|
2863
3016
|
const model = type === "local" ? LOCAL_EMBEDDING_MODEL.id : opts.model ?? DEFAULT_CLOUD_EMBEDDING_MODELS[type];
|
|
2864
|
-
console.log(ok(`Embeddings: ${type} ${
|
|
3017
|
+
console.log(ok(`Embeddings: ${type} ${pc14.dim(model)}`));
|
|
2865
3018
|
const missingKey = type !== "local" && !keyPresent(type, current?.apiKey);
|
|
2866
3019
|
if (missingKey) {
|
|
2867
3020
|
console.log(
|
|
2868
3021
|
warn(
|
|
2869
|
-
`Set ${KEY_ENV2[type]} in your shell (keys are never stored in config), then run ${
|
|
3022
|
+
`Set ${KEY_ENV2[type]} in your shell (keys are never stored in config), then run ${pc14.cyan("codebuddy hooks sync")}.`
|
|
2870
3023
|
)
|
|
2871
3024
|
);
|
|
2872
|
-
console.log(
|
|
3025
|
+
console.log(pc14.dim(" Existing vectors keep working until the new model can embed."));
|
|
2873
3026
|
}
|
|
2874
3027
|
if (opts.floor === void 0 && getModelDefinition(model)?.relevanceFloor === void 0) {
|
|
2875
3028
|
console.log(
|
|
2876
3029
|
warn(
|
|
2877
|
-
`No floor for ${model} yet: run ${
|
|
3030
|
+
`No floor for ${model} yet: run ${pc14.cyan("codebuddy models calibrate")} to turn on dense recall.`
|
|
2878
3031
|
)
|
|
2879
3032
|
);
|
|
2880
3033
|
}
|
|
2881
3034
|
if (!missingKey) {
|
|
2882
3035
|
syncInBackground(process.cwd(), true);
|
|
2883
3036
|
console.log(
|
|
2884
|
-
|
|
3037
|
+
pc14.dim(" Re-embedding existing memory in the background (codebuddy hooks sync).")
|
|
2885
3038
|
);
|
|
2886
3039
|
}
|
|
2887
3040
|
});
|
|
@@ -2908,13 +3061,13 @@ before keeping one on. A reranker never admits a fact, it only orders them.`
|
|
|
2908
3061
|
}
|
|
2909
3062
|
const reranker = choice;
|
|
2910
3063
|
console.log(
|
|
2911
|
-
ok(`Reranker: ${reranker} ${
|
|
3064
|
+
ok(`Reranker: ${reranker} ${pc14.dim(opts.model ?? DEFAULT_RERANK_MODELS[reranker].id)}`)
|
|
2912
3065
|
);
|
|
2913
3066
|
if (reranker !== "local" && !keyPresent(reranker, (await readConfigFile()).provider?.apiKey)) {
|
|
2914
3067
|
console.log(warn(`Set ${KEY_ENV2[reranker]}; without it reranking is skipped.`));
|
|
2915
3068
|
}
|
|
2916
3069
|
if (reranker === "local")
|
|
2917
|
-
console.log(
|
|
3070
|
+
console.log(pc14.dim(" Run codebuddy models pull to download it now."));
|
|
2918
3071
|
});
|
|
2919
3072
|
});
|
|
2920
3073
|
models.command("pull").description("Download the local models now instead of on first use.").action(async () => {
|
|
@@ -2925,7 +3078,7 @@ before keeping one on. A reranker never admits a fact, it only orders them.`
|
|
|
2925
3078
|
await withSpinner(
|
|
2926
3079
|
`Downloading ${LOCAL_EMBEDDING_MODEL.id}`,
|
|
2927
3080
|
() => new LocalModelProvider().embed({ input: "warm up" }),
|
|
2928
|
-
() => ok(`${LOCAL_EMBEDDING_MODEL.id} ready ${
|
|
3081
|
+
() => ok(`${LOCAL_EMBEDDING_MODEL.id} ready ${pc14.dim(`${Date.now() - started} ms`)}`)
|
|
2929
3082
|
);
|
|
2930
3083
|
if (file.rerank?.provider === "local") {
|
|
2931
3084
|
const id = file.rerank.model ?? DEFAULT_RERANK_MODELS.local.id;
|
|
@@ -2934,10 +3087,10 @@ before keeping one on. A reranker never admits a fact, it only orders them.`
|
|
|
2934
3087
|
await withSpinner(
|
|
2935
3088
|
`Downloading ${id}`,
|
|
2936
3089
|
() => rerankLocally({ id, ...revision ? { revision } : {} }, "warm", ["up"]),
|
|
2937
|
-
() => ok(`${id} ready ${
|
|
3090
|
+
() => ok(`${id} ready ${pc14.dim(`${Date.now() - started} ms`)}`)
|
|
2938
3091
|
);
|
|
2939
3092
|
}
|
|
2940
|
-
console.log(
|
|
3093
|
+
console.log(pc14.dim(` Cache: ${modelCacheDir()}`));
|
|
2941
3094
|
});
|
|
2942
3095
|
});
|
|
2943
3096
|
models.command("calibrate").option("--dry-run", "Measure only; do not save the floor.").description(
|
|
@@ -2955,19 +3108,19 @@ before keeping one on. A reranker never admits a fact, it only orders them.`
|
|
|
2955
3108
|
console.log(
|
|
2956
3109
|
row(
|
|
2957
3110
|
"ranking",
|
|
2958
|
-
`AUC ${result.auc.toFixed(3)} \xB7 right fact first ${pct(result.recallAt1)} ${
|
|
3111
|
+
`AUC ${result.auc.toFixed(3)} \xB7 right fact first ${pct(result.recallAt1)} ${pc14.dim("(held-out tasks)")}`
|
|
2959
3112
|
)
|
|
2960
3113
|
);
|
|
2961
3114
|
console.log(
|
|
2962
3115
|
row(
|
|
2963
3116
|
"floor",
|
|
2964
|
-
`${result.best.floor}: precision ${pct(result.test.precision)}, recall ${pct(result.test.recall)}, silent on ${pct(result.test.abstain)} of unrelated tasks ${
|
|
3117
|
+
`${result.best.floor}: precision ${pct(result.test.precision)}, recall ${pct(result.test.recall)}, silent on ${pct(result.test.abstain)} of unrelated tasks ${pc14.dim("(chosen on dev, measured on test)")}`
|
|
2965
3118
|
)
|
|
2966
3119
|
);
|
|
2967
3120
|
console.log(
|
|
2968
3121
|
row(
|
|
2969
3122
|
"recall floor",
|
|
2970
|
-
`${result.recall.dev.floor}: precision ${pct(result.recall.test.precision)}, recall ${pct(result.recall.test.recall)} ` +
|
|
3123
|
+
`${result.recall.dev.floor}: precision ${pct(result.recall.test.precision)}, recall ${pct(result.recall.test.recall)} ` + pc14.dim("(explicit recall: best F2 on dev, measured on test)")
|
|
2971
3124
|
)
|
|
2972
3125
|
);
|
|
2973
3126
|
if (opts.dryRun) return;
|
|
@@ -2986,10 +3139,238 @@ before keeping one on. A reranker never admits a fact, it only orders them.`
|
|
|
2986
3139
|
});
|
|
2987
3140
|
}
|
|
2988
3141
|
|
|
2989
|
-
// src/cli/commands/
|
|
3142
|
+
// src/cli/commands/output.ts
|
|
2990
3143
|
import { spawn as spawn5 } from "child_process";
|
|
3144
|
+
import { constants as constants2 } from "os";
|
|
3145
|
+
import pc15 from "picocolors";
|
|
3146
|
+
|
|
3147
|
+
// src/output/reduce.ts
|
|
3148
|
+
import { createHash } from "crypto";
|
|
3149
|
+
import { mkdir as mkdir2, readdir, readFile as readFile3, rm as rm2 } from "fs/promises";
|
|
3150
|
+
import { join as join6 } from "path";
|
|
3151
|
+
var OUTPUT_LIMITS = {
|
|
3152
|
+
/** At or below either, output is never reduced. */
|
|
3153
|
+
minLines: 80,
|
|
3154
|
+
minBytes: 6e3,
|
|
3155
|
+
head: 20,
|
|
3156
|
+
tail: 30,
|
|
3157
|
+
contextBefore: 2,
|
|
3158
|
+
contextAfter: 4,
|
|
3159
|
+
/** A reduction must save at least this share, or the original is printed. */
|
|
3160
|
+
minSaving: 0.3,
|
|
3161
|
+
/** Stored bytes per run; beyond this the stored copy says it was cut. */
|
|
3162
|
+
storeBytes: 2e7,
|
|
3163
|
+
retentionDays: 7,
|
|
3164
|
+
/** Lines one `output show` may print. */
|
|
3165
|
+
showLines: 400
|
|
3166
|
+
};
|
|
3167
|
+
var SIGNAL = /\b(error|errors|fail|failed|failure|failing|exception|traceback|panic|fatal|assert(?:ion)?|warn(?:ing)?|denied|not found|undefined|segfault|timeout|timed out)\b|✗|×|✖|FAIL|ERR!/i;
|
|
3168
|
+
function outputDir(root) {
|
|
3169
|
+
return join6(root, ".codebuddy", "cache", "outputs");
|
|
3170
|
+
}
|
|
3171
|
+
var shape = (line) => line.replace(/\d+/g, "#").trim();
|
|
3172
|
+
function reduceOutput(text3, id) {
|
|
3173
|
+
const lines = text3.split("\n");
|
|
3174
|
+
if (lines.length <= OUTPUT_LIMITS.minLines || Buffer.byteLength(text3) <= OUTPUT_LIMITS.minBytes) {
|
|
3175
|
+
return null;
|
|
3176
|
+
}
|
|
3177
|
+
if (text3.includes("\0")) return null;
|
|
3178
|
+
const keep = /* @__PURE__ */ new Set();
|
|
3179
|
+
for (let i = 0; i < Math.min(OUTPUT_LIMITS.head, lines.length); i++) keep.add(i);
|
|
3180
|
+
for (let i = Math.max(0, lines.length - OUTPUT_LIMITS.tail); i < lines.length; i++) keep.add(i);
|
|
3181
|
+
lines.forEach((line, index2) => {
|
|
3182
|
+
if (!SIGNAL.test(line)) return;
|
|
3183
|
+
const from = Math.max(0, index2 - OUTPUT_LIMITS.contextBefore);
|
|
3184
|
+
const to = Math.min(lines.length - 1, index2 + OUTPUT_LIMITS.contextAfter);
|
|
3185
|
+
for (let i = from; i <= to; i++) keep.add(i);
|
|
3186
|
+
});
|
|
3187
|
+
const out = [];
|
|
3188
|
+
let index = 0;
|
|
3189
|
+
while (index < lines.length) {
|
|
3190
|
+
if (!keep.has(index)) {
|
|
3191
|
+
const start = index;
|
|
3192
|
+
while (index < lines.length && !keep.has(index)) index++;
|
|
3193
|
+
out.push(
|
|
3194
|
+
`\u2026 ${index - start} lines omitted (codebuddy output show ${id} --range ${start + 1}:${index})`
|
|
3195
|
+
);
|
|
3196
|
+
continue;
|
|
3197
|
+
}
|
|
3198
|
+
const line = lines[index];
|
|
3199
|
+
const same = SIGNAL.test(line) ? (other) => other === line : (other) => shape(other) === shape(line);
|
|
3200
|
+
let run = index + 1;
|
|
3201
|
+
while (run < lines.length && keep.has(run) && same(lines[run])) run++;
|
|
3202
|
+
out.push(line);
|
|
3203
|
+
if (run - index > 2) {
|
|
3204
|
+
out.push(
|
|
3205
|
+
`\u2026 ${run - index - 1} similar lines (codebuddy output show ${id} --range ${index + 2}:${run})`
|
|
3206
|
+
);
|
|
3207
|
+
index = run;
|
|
3208
|
+
} else index++;
|
|
3209
|
+
}
|
|
3210
|
+
const reduced = out.join("\n");
|
|
3211
|
+
return Buffer.byteLength(reduced) <= Buffer.byteLength(text3) * (1 - OUTPUT_LIMITS.minSaving) ? reduced : null;
|
|
3212
|
+
}
|
|
3213
|
+
async function storeOutput(root, command, output, exitCode, now = /* @__PURE__ */ new Date()) {
|
|
3214
|
+
const truncated = Buffer.byteLength(output) > OUTPUT_LIMITS.storeBytes;
|
|
3215
|
+
const body = truncated ? `${output.slice(0, OUTPUT_LIMITS.storeBytes)}
|
|
3216
|
+
[codebuddy: stored copy cut at ${OUTPUT_LIMITS.storeBytes} bytes]` : output;
|
|
3217
|
+
const id = createHash("sha256").update(`${command}\0${now.toISOString()}\0${body}`).digest("hex").slice(0, 12);
|
|
3218
|
+
const meta = {
|
|
3219
|
+
id,
|
|
3220
|
+
command,
|
|
3221
|
+
exitCode,
|
|
3222
|
+
createdAt: now.toISOString(),
|
|
3223
|
+
expiresAt: new Date(now.getTime() + OUTPUT_LIMITS.retentionDays * 864e5).toISOString(),
|
|
3224
|
+
lines: body.split("\n").length,
|
|
3225
|
+
bytes: Buffer.byteLength(body),
|
|
3226
|
+
truncated
|
|
3227
|
+
};
|
|
3228
|
+
const dir = outputDir(root);
|
|
3229
|
+
await mkdir2(dir, { recursive: true, mode: 448 });
|
|
3230
|
+
await writeAtomic(join6(dir, `${id}.log`), body, { mode: 384 });
|
|
3231
|
+
await writeAtomic(join6(dir, `${id}.json`), `${JSON.stringify(meta)}
|
|
3232
|
+
`, { mode: 384 });
|
|
3233
|
+
await pruneOutputs(root, now).catch(() => void 0);
|
|
3234
|
+
return meta;
|
|
3235
|
+
}
|
|
3236
|
+
async function pruneOutputs(root, now = /* @__PURE__ */ new Date()) {
|
|
3237
|
+
const dir = outputDir(root);
|
|
3238
|
+
let removed = 0;
|
|
3239
|
+
for (const name2 of (await readdir(dir).catch(() => [])).filter(
|
|
3240
|
+
(n) => n.endsWith(".json")
|
|
3241
|
+
)) {
|
|
3242
|
+
const meta = await readMeta(root, name2.slice(0, -5));
|
|
3243
|
+
if (meta && Date.parse(meta.expiresAt) <= now.getTime()) {
|
|
3244
|
+
await rm2(join6(dir, `${meta.id}.log`), { force: true });
|
|
3245
|
+
await rm2(join6(dir, name2), { force: true });
|
|
3246
|
+
removed++;
|
|
3247
|
+
}
|
|
3248
|
+
}
|
|
3249
|
+
return removed;
|
|
3250
|
+
}
|
|
3251
|
+
async function readMeta(root, id) {
|
|
3252
|
+
if (!/^[a-f0-9]{12}$/.test(id)) return null;
|
|
3253
|
+
try {
|
|
3254
|
+
return JSON.parse(await readFile3(join6(outputDir(root), `${id}.json`), "utf8"));
|
|
3255
|
+
} catch {
|
|
3256
|
+
return null;
|
|
3257
|
+
}
|
|
3258
|
+
}
|
|
3259
|
+
async function showOutput(root, id, options = {}) {
|
|
3260
|
+
const meta = await readMeta(root, id);
|
|
3261
|
+
if (!meta) return { status: "missing", id };
|
|
3262
|
+
if (Date.parse(meta.expiresAt) <= (options.now ?? /* @__PURE__ */ new Date()).getTime()) {
|
|
3263
|
+
return { status: "expired", id };
|
|
3264
|
+
}
|
|
3265
|
+
const body = await readFile3(join6(outputDir(root), `${id}.log`), "utf8").catch(() => null);
|
|
3266
|
+
if (body === null) return { status: "missing", id };
|
|
3267
|
+
const lines = body.split("\n");
|
|
3268
|
+
let picked;
|
|
3269
|
+
if (options.grep) {
|
|
3270
|
+
const pattern = new RegExp(options.grep, "i");
|
|
3271
|
+
const set = /* @__PURE__ */ new Set();
|
|
3272
|
+
lines.forEach((line, index) => {
|
|
3273
|
+
if (!pattern.test(line)) return;
|
|
3274
|
+
for (let i = Math.max(0, index - 2); i <= Math.min(lines.length - 1, index + 2); i++)
|
|
3275
|
+
set.add(i);
|
|
3276
|
+
});
|
|
3277
|
+
picked = [...set].sort((a, b) => a - b);
|
|
3278
|
+
} else {
|
|
3279
|
+
const [from, to] = options.range ?? [1, lines.length];
|
|
3280
|
+
picked = [];
|
|
3281
|
+
for (let i = Math.max(1, from); i <= Math.min(lines.length, to); i++) picked.push(i - 1);
|
|
3282
|
+
}
|
|
3283
|
+
const shown = picked.slice(0, OUTPUT_LIMITS.showLines);
|
|
3284
|
+
return {
|
|
3285
|
+
status: "ok",
|
|
3286
|
+
meta,
|
|
3287
|
+
text: shown.map((i) => `${i + 1}: ${lines[i]}`).join("\n"),
|
|
3288
|
+
more: picked.length > shown.length
|
|
3289
|
+
};
|
|
3290
|
+
}
|
|
3291
|
+
async function listOutputs(root) {
|
|
3292
|
+
const names = await readdir(outputDir(root)).catch(() => []);
|
|
3293
|
+
const metas = await Promise.all(
|
|
3294
|
+
names.filter((n) => n.endsWith(".json")).map((n) => readMeta(root, n.slice(0, -5)))
|
|
3295
|
+
);
|
|
3296
|
+
return metas.filter((meta) => meta !== null).sort((a, b) => b.createdAt.localeCompare(a.createdAt));
|
|
3297
|
+
}
|
|
3298
|
+
|
|
3299
|
+
// src/cli/commands/output.ts
|
|
3300
|
+
function registerOutputCommands(program, runSafely2) {
|
|
3301
|
+
program.command("run").argument("<command...>", "The command and its arguments (after --).").description(
|
|
3302
|
+
"Run a command; print a reduced view of long output and keep the original for `codebuddy output show`."
|
|
3303
|
+
).action(async (parts) => {
|
|
3304
|
+
await runSafely2(async () => {
|
|
3305
|
+
const command = parts.join(" ");
|
|
3306
|
+
const { output: output2, exitCode } = await capture(parts);
|
|
3307
|
+
const root = process.cwd();
|
|
3308
|
+
const provisional = reduceOutput(output2, "xxxxxxxxxxxx");
|
|
3309
|
+
if (provisional === null) {
|
|
3310
|
+
process.stdout.write(output2);
|
|
3311
|
+
} else {
|
|
3312
|
+
const stored = await storeOutput(root, command, output2, exitCode);
|
|
3313
|
+
const reduced = reduceOutput(output2, stored.id) ?? output2;
|
|
3314
|
+
process.stdout.write(`${reduced}
|
|
3315
|
+
`);
|
|
3316
|
+
process.stdout.write(
|
|
3317
|
+
`[codebuddy run: exit ${exitCode ?? "signal"}; ${stored.lines} lines shown as ${reduced.split("\n").length}; full output: codebuddy output show ${stored.id} [--grep RE | --range A:B], kept until ${stored.expiresAt.slice(0, 10)}]
|
|
3318
|
+
`
|
|
3319
|
+
);
|
|
3320
|
+
}
|
|
3321
|
+
process.exitCode = exitCode ?? 1;
|
|
3322
|
+
});
|
|
3323
|
+
});
|
|
3324
|
+
const output = program.command("output").description("Stored originals of `codebuddy run` output.");
|
|
3325
|
+
output.command("list", { isDefault: true }).description("List stored outputs, newest first.").action(async () => {
|
|
3326
|
+
await runSafely2(async () => {
|
|
3327
|
+
const stored = await listOutputs(process.cwd());
|
|
3328
|
+
if (stored.length === 0) console.log(pc15.dim("no stored outputs"));
|
|
3329
|
+
for (const meta of stored) {
|
|
3330
|
+
console.log(
|
|
3331
|
+
`${meta.id} exit ${meta.exitCode ?? "-"} ${meta.lines} lines until ${meta.expiresAt.slice(0, 10)} ${meta.command.slice(0, 80)}`
|
|
3332
|
+
);
|
|
3333
|
+
}
|
|
3334
|
+
});
|
|
3335
|
+
});
|
|
3336
|
+
output.command("show").argument("<id>").option("--range <a:b>", "1-based inclusive line range.").option("--grep <pattern>", "Lines matching a regular expression, with 2 lines of context.").description("Print exact stored lines (at most 400 per call).").action(async (id, opts) => {
|
|
3337
|
+
await runSafely2(async () => {
|
|
3338
|
+
const range = opts.range?.match(/^(\d+):(\d+)$/);
|
|
3339
|
+
if (opts.range && !range) throw new Error("--range must look like 120:180");
|
|
3340
|
+
const result = await showOutput(process.cwd(), id, {
|
|
3341
|
+
...range ? { range: [Number(range[1]), Number(range[2])] } : {},
|
|
3342
|
+
...opts.grep ? { grep: opts.grep } : {}
|
|
3343
|
+
});
|
|
3344
|
+
if (result.status !== "ok") {
|
|
3345
|
+
throw new Error(`stored output ${id} is ${result.status}`);
|
|
3346
|
+
}
|
|
3347
|
+
console.log(result.text);
|
|
3348
|
+
if (result.more) console.log(pc15.dim("\u2026 more lines; narrow --range or --grep"));
|
|
3349
|
+
});
|
|
3350
|
+
});
|
|
3351
|
+
}
|
|
3352
|
+
function capture(parts) {
|
|
3353
|
+
return new Promise((resolve6, reject) => {
|
|
3354
|
+
const [file, ...args] = parts;
|
|
3355
|
+
const child = parts.length === 1 ? spawn5(file, { shell: true, stdio: ["inherit", "pipe", "pipe"] }) : spawn5(file, args, { stdio: ["inherit", "pipe", "pipe"] });
|
|
3356
|
+
const chunks = [];
|
|
3357
|
+
child.stdout.on("data", (chunk) => chunks.push(chunk));
|
|
3358
|
+
child.stderr.on("data", (chunk) => chunks.push(chunk));
|
|
3359
|
+
child.on("error", reject);
|
|
3360
|
+
child.on(
|
|
3361
|
+
"close",
|
|
3362
|
+
(code, signal) => resolve6({
|
|
3363
|
+
output: Buffer.concat(chunks).toString("utf8"),
|
|
3364
|
+
exitCode: code ?? (signal ? 128 + (constants2.signals[signal] ?? 0) : null)
|
|
3365
|
+
})
|
|
3366
|
+
);
|
|
3367
|
+
});
|
|
3368
|
+
}
|
|
3369
|
+
|
|
3370
|
+
// src/cli/commands/plan.ts
|
|
3371
|
+
import { spawn as spawn6 } from "child_process";
|
|
2991
3372
|
import { relative as relative4 } from "path";
|
|
2992
|
-
import
|
|
3373
|
+
import pc16 from "picocolors";
|
|
2993
3374
|
function makeLifecycle(cwd = process.cwd()) {
|
|
2994
3375
|
const store = new PlanFileStore(cwd);
|
|
2995
3376
|
return { store, lifecycle: new PlanLifecycle(store) };
|
|
@@ -2997,67 +3378,67 @@ function makeLifecycle(cwd = process.cwd()) {
|
|
|
2997
3378
|
function statusColor(status) {
|
|
2998
3379
|
switch (status) {
|
|
2999
3380
|
case "draft":
|
|
3000
|
-
return
|
|
3381
|
+
return pc16.dim(status);
|
|
3001
3382
|
case "approved":
|
|
3002
|
-
return
|
|
3383
|
+
return pc16.cyan(status);
|
|
3003
3384
|
case "executing":
|
|
3004
|
-
return
|
|
3385
|
+
return pc16.yellow(status);
|
|
3005
3386
|
case "complete":
|
|
3006
|
-
return
|
|
3387
|
+
return pc16.green(status);
|
|
3007
3388
|
case "abandoned":
|
|
3008
|
-
return
|
|
3389
|
+
return pc16.red(status);
|
|
3009
3390
|
}
|
|
3010
3391
|
}
|
|
3011
3392
|
function renderPlan(plan) {
|
|
3012
3393
|
const lines = [];
|
|
3013
|
-
lines.push(`${
|
|
3014
|
-
lines.push(
|
|
3394
|
+
lines.push(`${pc16.bold(plan.title)} ${statusColor(plan.status)}`);
|
|
3395
|
+
lines.push(pc16.dim(plan.id));
|
|
3015
3396
|
lines.push("");
|
|
3016
|
-
lines.push(`${
|
|
3397
|
+
lines.push(`${pc16.bold("Brief:")} ${plan.brief}`);
|
|
3017
3398
|
if (plan.filesToTouch.length > 0) {
|
|
3018
3399
|
lines.push("");
|
|
3019
|
-
lines.push(
|
|
3400
|
+
lines.push(pc16.bold("Files to touch:"));
|
|
3020
3401
|
for (const file of plan.filesToTouch) {
|
|
3021
3402
|
lines.push(` ${file.action.padEnd(6)} ${file.path}${file.notes ? ` \u2014 ${file.notes}` : ""}`);
|
|
3022
3403
|
}
|
|
3023
3404
|
}
|
|
3024
3405
|
if (plan.testsToAdd.length > 0) {
|
|
3025
3406
|
lines.push("");
|
|
3026
|
-
lines.push(
|
|
3407
|
+
lines.push(pc16.bold("Tests to add:"));
|
|
3027
3408
|
for (const test of plan.testsToAdd) {
|
|
3028
3409
|
lines.push(` ${test.path}${test.description ? ` \u2014 ${test.description}` : ""}`);
|
|
3029
3410
|
}
|
|
3030
3411
|
}
|
|
3031
3412
|
if (plan.outOfScope.length > 0) {
|
|
3032
3413
|
lines.push("");
|
|
3033
|
-
lines.push(
|
|
3414
|
+
lines.push(pc16.bold("Out of scope:"));
|
|
3034
3415
|
for (const item of plan.outOfScope) lines.push(` - ${item}`);
|
|
3035
3416
|
}
|
|
3036
3417
|
if (plan.risks.length > 0) {
|
|
3037
3418
|
lines.push("");
|
|
3038
|
-
lines.push(
|
|
3419
|
+
lines.push(pc16.bold("Risks:"));
|
|
3039
3420
|
for (const item of plan.risks) lines.push(` - ${item}`);
|
|
3040
3421
|
}
|
|
3041
3422
|
if (plan.commitSha) {
|
|
3042
3423
|
lines.push("");
|
|
3043
|
-
lines.push(`${
|
|
3424
|
+
lines.push(`${pc16.bold("Commit:")} ${plan.commitSha}`);
|
|
3044
3425
|
}
|
|
3045
3426
|
lines.push("");
|
|
3046
|
-
lines.push(
|
|
3427
|
+
lines.push(pc16.dim("\u2500".repeat(40)));
|
|
3047
3428
|
lines.push(plan.body);
|
|
3048
3429
|
return lines.join("\n");
|
|
3049
3430
|
}
|
|
3050
3431
|
function openEditor2(path) {
|
|
3051
3432
|
const editor = process.env.EDITOR ?? process.env.VISUAL ?? "vi";
|
|
3052
3433
|
return new Promise((resolve6, reject) => {
|
|
3053
|
-
const child =
|
|
3434
|
+
const child = spawn6(editor, [path], { stdio: "inherit" });
|
|
3054
3435
|
child.on("error", reject);
|
|
3055
3436
|
child.on("close", () => resolve6());
|
|
3056
3437
|
});
|
|
3057
3438
|
}
|
|
3058
3439
|
function runGit(args) {
|
|
3059
3440
|
return new Promise((resolve6, reject) => {
|
|
3060
|
-
const child =
|
|
3441
|
+
const child = spawn6("git", args, { stdio: ["ignore", "pipe", "pipe"] });
|
|
3061
3442
|
let stdout = "";
|
|
3062
3443
|
let stderr = "";
|
|
3063
3444
|
child.stdout.on("data", (c) => {
|
|
@@ -3082,14 +3463,14 @@ function registerPlanCommands(program, runSafely2) {
|
|
|
3082
3463
|
title: opts.title ?? brief,
|
|
3083
3464
|
brief
|
|
3084
3465
|
});
|
|
3085
|
-
console.log(`${
|
|
3466
|
+
console.log(`${pc16.green("created")} ${created.id} (${statusColor(created.status)})`);
|
|
3086
3467
|
if (opts.edit !== false && process.stdin.isTTY) {
|
|
3087
3468
|
await openEditor2(created.path);
|
|
3088
3469
|
const { store } = makeLifecycle();
|
|
3089
3470
|
await store.readPlan(created.id);
|
|
3090
|
-
console.log(
|
|
3471
|
+
console.log(pc16.dim("saved and validated"));
|
|
3091
3472
|
}
|
|
3092
|
-
console.log(
|
|
3473
|
+
console.log(pc16.dim(relative4(process.cwd(), created.path)));
|
|
3093
3474
|
});
|
|
3094
3475
|
});
|
|
3095
3476
|
plan.command("list").option("--status <status>", "Filter by status.").option("--all", "Include completed and abandoned plans.").description("List plans in the current namespace.").action(async (opts) => {
|
|
@@ -3101,11 +3482,11 @@ function registerPlanCommands(program, runSafely2) {
|
|
|
3101
3482
|
else if (!opts.all)
|
|
3102
3483
|
plans = plans.filter((p) => p.status !== "complete" && p.status !== "abandoned");
|
|
3103
3484
|
if (plans.length === 0) {
|
|
3104
|
-
console.log(
|
|
3485
|
+
console.log(pc16.dim("no plans"));
|
|
3105
3486
|
return;
|
|
3106
3487
|
}
|
|
3107
3488
|
for (const p of plans) {
|
|
3108
|
-
console.log(`${statusColor(p.status).padEnd(20)} ${
|
|
3489
|
+
console.log(`${statusColor(p.status).padEnd(20)} ${pc16.bold(p.title)} ${pc16.dim(p.id)}`);
|
|
3109
3490
|
}
|
|
3110
3491
|
});
|
|
3111
3492
|
});
|
|
@@ -3121,7 +3502,7 @@ function registerPlanCommands(program, runSafely2) {
|
|
|
3121
3502
|
const existing = await store.readPlan(id);
|
|
3122
3503
|
await openEditor2(existing.path);
|
|
3123
3504
|
await store.readPlan(id);
|
|
3124
|
-
console.log(
|
|
3505
|
+
console.log(pc16.dim("saved and validated"));
|
|
3125
3506
|
});
|
|
3126
3507
|
});
|
|
3127
3508
|
plan.command("approve").argument("<id>").description("Promote a draft to approved (one active plan per namespace).").action(async (id) => {
|
|
@@ -3145,7 +3526,7 @@ function registerPlanCommands(program, runSafely2) {
|
|
|
3145
3526
|
...opts.commit ? { commitSha: opts.commit } : {},
|
|
3146
3527
|
...opts.notes ? { notes: opts.notes } : {}
|
|
3147
3528
|
});
|
|
3148
|
-
if (!opts.commit) console.log(
|
|
3529
|
+
if (!opts.commit) console.log(pc16.yellow("note: no --commit supplied"));
|
|
3149
3530
|
console.log(`${next.id} \u2192 ${statusColor(next.status)}`);
|
|
3150
3531
|
});
|
|
3151
3532
|
});
|
|
@@ -3164,7 +3545,7 @@ function registerPlanCommands(program, runSafely2) {
|
|
|
3164
3545
|
const args = ["diff", opts.from, ...opts.to ? [opts.to] : [], "--", relPath];
|
|
3165
3546
|
const result = await runGit(args);
|
|
3166
3547
|
if (result.stdout.trim().length === 0) {
|
|
3167
|
-
console.log(
|
|
3548
|
+
console.log(pc16.dim("no changes"));
|
|
3168
3549
|
} else {
|
|
3169
3550
|
process.stdout.write(result.stdout);
|
|
3170
3551
|
}
|
|
@@ -3181,13 +3562,13 @@ function registerPlanCommands(program, runSafely2) {
|
|
|
3181
3562
|
throw new Error(`Invalid policy "${mode}". Use one of: ${PLAN_POLICIES.join(", ")}.`);
|
|
3182
3563
|
}
|
|
3183
3564
|
await setPlanPolicy(mode);
|
|
3184
|
-
console.log(`${
|
|
3565
|
+
console.log(`${pc16.green("plan policy")} = ${mode}`);
|
|
3185
3566
|
});
|
|
3186
3567
|
});
|
|
3187
3568
|
}
|
|
3188
3569
|
|
|
3189
3570
|
// src/cli/commands/risk.ts
|
|
3190
|
-
import
|
|
3571
|
+
import pc17 from "picocolors";
|
|
3191
3572
|
function registerRiskCommands(program, runSafely2) {
|
|
3192
3573
|
const risk = program.command("risk").description("Assess evidence-backed change risk.");
|
|
3193
3574
|
risk.command("assess").option("--plan <id>", "Assess paths listed in a CodeBuddy plan.").option("--paths <paths>", "Comma-separated repo-relative paths to assess.").option("--git", "Assess staged, unstaged, and untracked git changes.").option("--limit <n>", "Maximum risk items to show.", Number).option("--json", "Print machine-readable JSON.").option("--explain", "Show evidence for each risk item.").description("Assess risk for a plan, explicit paths, or current git changes.").action(
|
|
@@ -3215,31 +3596,31 @@ function parsePaths3(value) {
|
|
|
3215
3596
|
}
|
|
3216
3597
|
function printAssessment(assessment, explain) {
|
|
3217
3598
|
if (assessment.items.length === 0) {
|
|
3218
|
-
console.log(
|
|
3599
|
+
console.log(pc17.dim("no risk evidence found"));
|
|
3219
3600
|
return;
|
|
3220
3601
|
}
|
|
3221
3602
|
for (const item of assessment.items) {
|
|
3222
3603
|
console.log(
|
|
3223
|
-
`${
|
|
3604
|
+
`${pc17.bold(item.path)} score ${scoreColor2(item.score)} category ${pc17.cyan(item.category)}`
|
|
3224
3605
|
);
|
|
3225
3606
|
console.log(` ${item.reason}`);
|
|
3226
3607
|
if (explain) {
|
|
3227
3608
|
for (const evidence of item.evidence) console.log(` \u21B3 ${formatEvidence(evidence)}`);
|
|
3228
3609
|
} else {
|
|
3229
|
-
console.log(
|
|
3610
|
+
console.log(pc17.dim(` ${item.evidence.length} evidence item(s)`));
|
|
3230
3611
|
}
|
|
3231
3612
|
}
|
|
3232
3613
|
console.log(
|
|
3233
|
-
|
|
3614
|
+
pc17.dim(
|
|
3234
3615
|
`
|
|
3235
3616
|
${assessment.stats.itemsProduced} item(s), ${assessment.stats.signalsRun} signal(s), ${assessment.stats.pathsConsidered} path(s) considered`
|
|
3236
3617
|
)
|
|
3237
3618
|
);
|
|
3238
3619
|
}
|
|
3239
3620
|
function scoreColor2(score) {
|
|
3240
|
-
if (score >= 75) return
|
|
3241
|
-
if (score >= 50) return
|
|
3242
|
-
return
|
|
3621
|
+
if (score >= 75) return pc17.red(String(score));
|
|
3622
|
+
if (score >= 50) return pc17.yellow(String(score));
|
|
3623
|
+
return pc17.green(String(score));
|
|
3243
3624
|
}
|
|
3244
3625
|
function formatEvidence(evidence) {
|
|
3245
3626
|
switch (evidence.kind) {
|
|
@@ -3261,7 +3642,7 @@ function truncate2(value, max) {
|
|
|
3261
3642
|
|
|
3262
3643
|
// src/cli/commands/rules.ts
|
|
3263
3644
|
import { relative as relative5 } from "path";
|
|
3264
|
-
import
|
|
3645
|
+
import pc18 from "picocolors";
|
|
3265
3646
|
async function resolveMode(client, value) {
|
|
3266
3647
|
if (value) {
|
|
3267
3648
|
const mode = parseMode(value);
|
|
@@ -3301,7 +3682,7 @@ function registerRulesCommands(program, runSafely2) {
|
|
|
3301
3682
|
`${actionLabel(result.action)} ${clientDisplayName(client)} workflow in ${where}`
|
|
3302
3683
|
);
|
|
3303
3684
|
if (result.action !== "unchanged") {
|
|
3304
|
-
console.log(
|
|
3685
|
+
console.log(pc18.dim(" managed block between codebuddy:workflow markers; safe to re-run"));
|
|
3305
3686
|
}
|
|
3306
3687
|
});
|
|
3307
3688
|
});
|
|
@@ -3309,20 +3690,20 @@ function registerRulesCommands(program, runSafely2) {
|
|
|
3309
3690
|
function actionLabel(action) {
|
|
3310
3691
|
switch (action) {
|
|
3311
3692
|
case "created":
|
|
3312
|
-
return
|
|
3693
|
+
return pc18.green("created");
|
|
3313
3694
|
case "added":
|
|
3314
|
-
return
|
|
3695
|
+
return pc18.green("added");
|
|
3315
3696
|
case "updated":
|
|
3316
|
-
return
|
|
3697
|
+
return pc18.cyan("updated");
|
|
3317
3698
|
case "removed":
|
|
3318
|
-
return
|
|
3699
|
+
return pc18.yellow("removed");
|
|
3319
3700
|
default:
|
|
3320
|
-
return
|
|
3701
|
+
return pc18.dim("unchanged");
|
|
3321
3702
|
}
|
|
3322
3703
|
}
|
|
3323
3704
|
|
|
3324
3705
|
// src/cli/commands/suggest.ts
|
|
3325
|
-
import
|
|
3706
|
+
import pc19 from "picocolors";
|
|
3326
3707
|
function parsePaths4(value) {
|
|
3327
3708
|
return value.split(",").map((path) => path.trim()).filter(Boolean);
|
|
3328
3709
|
}
|
|
@@ -3344,7 +3725,7 @@ function registerSuggestCommand(program, runSafely2) {
|
|
|
3344
3725
|
}
|
|
3345
3726
|
printSuggestions(result.suggestions);
|
|
3346
3727
|
console.log(
|
|
3347
|
-
|
|
3728
|
+
pc19.dim(
|
|
3348
3729
|
`
|
|
3349
3730
|
${result.stats.produced} suggestion(s) across ${result.stats.pathsConsidered} path(s)`
|
|
3350
3731
|
)
|
|
@@ -3355,72 +3736,72 @@ ${result.stats.produced} suggestion(s) across ${result.stats.pathsConsidered} pa
|
|
|
3355
3736
|
}
|
|
3356
3737
|
function printSuggestions(suggestions) {
|
|
3357
3738
|
if (suggestions.length === 0) {
|
|
3358
|
-
console.log(
|
|
3739
|
+
console.log(pc19.dim("no suggestions \u2014 nothing high-signal to report"));
|
|
3359
3740
|
return;
|
|
3360
3741
|
}
|
|
3361
3742
|
for (const suggestion of suggestions) {
|
|
3362
|
-
console.log(`${severityBadge2(suggestion.severity)} ${
|
|
3743
|
+
console.log(`${severityBadge2(suggestion.severity)} ${pc19.bold(suggestion.title)}`);
|
|
3363
3744
|
console.log(` ${suggestion.detail}`);
|
|
3364
3745
|
for (const evidence of suggestion.evidence) {
|
|
3365
|
-
console.log(
|
|
3746
|
+
console.log(pc19.dim(` \u21B3 ${evidence.kind}: ${evidence.detail}`));
|
|
3366
3747
|
}
|
|
3367
|
-
if (suggestion.commandHint) console.log(
|
|
3748
|
+
if (suggestion.commandHint) console.log(pc19.dim(` \u2192 ${suggestion.commandHint}`));
|
|
3368
3749
|
}
|
|
3369
3750
|
}
|
|
3370
3751
|
function severityBadge2(severity) {
|
|
3371
3752
|
switch (severity) {
|
|
3372
3753
|
case "high":
|
|
3373
|
-
return
|
|
3754
|
+
return pc19.red("[high]");
|
|
3374
3755
|
case "medium":
|
|
3375
|
-
return
|
|
3756
|
+
return pc19.yellow("[med ]");
|
|
3376
3757
|
case "low":
|
|
3377
|
-
return
|
|
3758
|
+
return pc19.cyan("[low ]");
|
|
3378
3759
|
default:
|
|
3379
|
-
return
|
|
3760
|
+
return pc19.dim("[info]");
|
|
3380
3761
|
}
|
|
3381
3762
|
}
|
|
3382
3763
|
|
|
3383
3764
|
// src/cli/commands/symbols.ts
|
|
3384
|
-
import { readFile as
|
|
3765
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
3385
3766
|
import { resolve as resolve5 } from "path";
|
|
3386
|
-
import
|
|
3767
|
+
import pc20 from "picocolors";
|
|
3387
3768
|
function registerSymbolsCommand(program, runSafely2) {
|
|
3388
3769
|
program.command("symbols").argument("<path>", "Repo-relative or absolute path to a code file.").option("--json", "Print machine-readable JSON.").description("List a file's top-level symbols (functions, classes, types, exports).").action(async (path, opts) => {
|
|
3389
3770
|
await runSafely2(async () => {
|
|
3390
3771
|
if (!supportsSymbols(path)) {
|
|
3391
|
-
console.log(
|
|
3772
|
+
console.log(pc20.dim(`no symbol extraction for ${path} (unsupported language)`));
|
|
3392
3773
|
return;
|
|
3393
3774
|
}
|
|
3394
|
-
const content = await
|
|
3775
|
+
const content = await readFile4(resolve5(path), "utf8");
|
|
3395
3776
|
const table = extractSymbolTable(content, path);
|
|
3396
3777
|
if (opts.json) {
|
|
3397
3778
|
console.log(JSON.stringify({ path, symbols: table }, null, 2));
|
|
3398
3779
|
return;
|
|
3399
3780
|
}
|
|
3400
3781
|
if (table.length === 0) {
|
|
3401
|
-
console.log(
|
|
3782
|
+
console.log(pc20.dim("no top-level symbols found"));
|
|
3402
3783
|
return;
|
|
3403
3784
|
}
|
|
3404
3785
|
for (const symbol of table) {
|
|
3405
|
-
const badge = symbol.exported ?
|
|
3786
|
+
const badge = symbol.exported ? pc20.green("export") : pc20.dim("local ");
|
|
3406
3787
|
console.log(
|
|
3407
|
-
`${badge} ${
|
|
3788
|
+
`${badge} ${pc20.cyan(symbol.kind.padEnd(9))} ${pc20.bold(symbol.name)} ${pc20.dim(`L${symbol.startLine}-${symbol.endLine}`)}`
|
|
3408
3789
|
);
|
|
3409
3790
|
}
|
|
3410
|
-
console.log(
|
|
3791
|
+
console.log(pc20.dim(`
|
|
3411
3792
|
${table.length} symbol(s)`));
|
|
3412
3793
|
});
|
|
3413
3794
|
});
|
|
3414
3795
|
}
|
|
3415
3796
|
|
|
3416
3797
|
// src/cli/commands/telemetry.ts
|
|
3417
|
-
import
|
|
3798
|
+
import pc21 from "picocolors";
|
|
3418
3799
|
|
|
3419
3800
|
// src/telemetry/collector.ts
|
|
3420
|
-
import { createHash, timingSafeEqual } from "crypto";
|
|
3421
|
-
import { appendFile, mkdir as
|
|
3801
|
+
import { createHash as createHash2, timingSafeEqual } from "crypto";
|
|
3802
|
+
import { appendFile, mkdir as mkdir3, readdir as readdir2, readFile as readFile5 } from "fs/promises";
|
|
3422
3803
|
import { createServer as createServer2 } from "http";
|
|
3423
|
-
import { join as
|
|
3804
|
+
import { join as join7 } from "path";
|
|
3424
3805
|
import { z as z2 } from "zod";
|
|
3425
3806
|
|
|
3426
3807
|
// src/telemetry/admin-page.ts
|
|
@@ -3945,7 +4326,7 @@ var batchSchema = z2.object({
|
|
|
3945
4326
|
});
|
|
3946
4327
|
async function startCollector(options) {
|
|
3947
4328
|
const { dataDir } = options;
|
|
3948
|
-
await
|
|
4329
|
+
await mkdir3(dataDir, { recursive: true });
|
|
3949
4330
|
const registry = await loadRegistry(dataDir);
|
|
3950
4331
|
let summaryCache;
|
|
3951
4332
|
let npmCache;
|
|
@@ -3993,7 +4374,7 @@ async function startCollector(options) {
|
|
|
3993
4374
|
if (!registry.has(batch.installId)) {
|
|
3994
4375
|
registry.set(batch.installId, receivedAt);
|
|
3995
4376
|
await appendFile(
|
|
3996
|
-
|
|
4377
|
+
join7(dataDir, "installs.jsonl"),
|
|
3997
4378
|
`${JSON.stringify({ installId: batch.installId, firstSeen: receivedAt })}
|
|
3998
4379
|
`
|
|
3999
4380
|
);
|
|
@@ -4001,7 +4382,7 @@ async function startCollector(options) {
|
|
|
4001
4382
|
const { events, ...meta } = batch;
|
|
4002
4383
|
const lines = events.map((event) => JSON.stringify({ ...meta, ...event, receivedAt }));
|
|
4003
4384
|
await appendFile(
|
|
4004
|
-
|
|
4385
|
+
join7(dataDir, `events-${receivedAt.slice(0, 10)}.jsonl`),
|
|
4005
4386
|
`${lines.join("\n")}
|
|
4006
4387
|
`
|
|
4007
4388
|
);
|
|
@@ -4098,7 +4479,7 @@ function passwordMatches(request, password3) {
|
|
|
4098
4479
|
if (!header.startsWith("Basic ")) return false;
|
|
4099
4480
|
const decoded = Buffer.from(header.slice(6), "base64").toString("utf8");
|
|
4100
4481
|
const given = decoded.slice(decoded.indexOf(":") + 1);
|
|
4101
|
-
const digest = (value) =>
|
|
4482
|
+
const digest = (value) => createHash2("sha256").update(value).digest();
|
|
4102
4483
|
return timingSafeEqual(digest(given), digest(password3));
|
|
4103
4484
|
}
|
|
4104
4485
|
function readBody(request) {
|
|
@@ -4122,10 +4503,10 @@ function listen2(server, port) {
|
|
|
4122
4503
|
}
|
|
4123
4504
|
async function readEvents(dataDir, days, now = Date.now()) {
|
|
4124
4505
|
const since = new Date(now - (days - 1) * 864e5).toISOString().slice(0, 10);
|
|
4125
|
-
const files = (await
|
|
4506
|
+
const files = (await readdir2(dataDir).catch(() => [])).filter((file) => /^events-\d{4}-\d{2}-\d{2}\.jsonl$/.test(file) && file.slice(7, 17) >= since).sort();
|
|
4126
4507
|
const events = [];
|
|
4127
4508
|
for (const file of files) {
|
|
4128
|
-
for (const line of (await
|
|
4509
|
+
for (const line of (await readFile5(join7(dataDir, file), "utf8")).split("\n")) {
|
|
4129
4510
|
if (!line) continue;
|
|
4130
4511
|
try {
|
|
4131
4512
|
events.push(JSON.parse(line));
|
|
@@ -4400,8 +4781,8 @@ function installTrace(events, prefix) {
|
|
|
4400
4781
|
}
|
|
4401
4782
|
async function loadRegistry(dataDir) {
|
|
4402
4783
|
const registry = /* @__PURE__ */ new Map();
|
|
4403
|
-
const path =
|
|
4404
|
-
const raw = await
|
|
4784
|
+
const path = join7(dataDir, "installs.jsonl");
|
|
4785
|
+
const raw = await readFile5(path, "utf8").catch(() => null);
|
|
4405
4786
|
if (raw !== null) {
|
|
4406
4787
|
for (const line of raw.split("\n")) {
|
|
4407
4788
|
try {
|
|
@@ -4446,10 +4827,10 @@ function registerTelemetryCommands(program, runSafely2) {
|
|
|
4446
4827
|
const state = await readTelemetryState();
|
|
4447
4828
|
const blocked = telemetryBlocked(state);
|
|
4448
4829
|
console.log(
|
|
4449
|
-
blocked ? `${
|
|
4830
|
+
blocked ? `${pc21.yellow("\u25CB")} telemetry off (${blocked})` : `${pc21.green("\u25CF")} telemetry on`
|
|
4450
4831
|
);
|
|
4451
|
-
console.log(
|
|
4452
|
-
if (telemetryUrl()) console.log(
|
|
4832
|
+
console.log(pc21.dim(` install id ${state.installId} (${telemetryStatePath()})`));
|
|
4833
|
+
if (telemetryUrl()) console.log(pc21.dim(` collector ${telemetryUrl()}`));
|
|
4453
4834
|
});
|
|
4454
4835
|
});
|
|
4455
4836
|
telemetry.command("enable").description("Allow anonymous usage data from this machine.").action(async () => {
|
|
@@ -4460,7 +4841,7 @@ function registerTelemetryCommands(program, runSafely2) {
|
|
|
4460
4841
|
noticeAt: state.noticeAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
4461
4842
|
});
|
|
4462
4843
|
console.log(TELEMETRY_NOTICE);
|
|
4463
|
-
console.log(
|
|
4844
|
+
console.log(pc21.green("Telemetry enabled."));
|
|
4464
4845
|
});
|
|
4465
4846
|
});
|
|
4466
4847
|
telemetry.command("disable").description("Stop sending anonymous usage data from this machine.").action(async () => {
|
|
@@ -4488,14 +4869,14 @@ function registerTelemetryCommands(program, runSafely2) {
|
|
|
4488
4869
|
adminPort: opts.adminPort,
|
|
4489
4870
|
...process.env.CODEBUDDY_ADMIN_PASSWORD ? { adminPassword: process.env.CODEBUDDY_ADMIN_PASSWORD } : {}
|
|
4490
4871
|
});
|
|
4491
|
-
console.log(`${
|
|
4492
|
-
console.log(`${
|
|
4872
|
+
console.log(`${pc21.green("\u25CF")} ingest ${pc21.bold(collector.ingestUrl)}`);
|
|
4873
|
+
console.log(`${pc21.green("\u25CF")} admin ${pc21.bold(collector.adminUrl)}`);
|
|
4493
4874
|
console.log(
|
|
4494
|
-
|
|
4875
|
+
pc21.dim(
|
|
4495
4876
|
process.env.CODEBUDDY_ADMIN_PASSWORD ? " admin panel is password-protected (CODEBUDDY_ADMIN_PASSWORD)." : " admin panel has no password: keep it private, or set CODEBUDDY_ADMIN_PASSWORD."
|
|
4496
4877
|
)
|
|
4497
4878
|
);
|
|
4498
|
-
console.log(
|
|
4879
|
+
console.log(pc21.dim(` events in ${opts.data}. Ctrl+C to stop.`));
|
|
4499
4880
|
await new Promise((resolve6) => {
|
|
4500
4881
|
const stop = () => void collector.close().then(resolve6);
|
|
4501
4882
|
process.once("SIGINT", stop);
|
|
@@ -4508,12 +4889,12 @@ function registerTelemetryCommands(program, runSafely2) {
|
|
|
4508
4889
|
// src/cli/commands/use-command.ts
|
|
4509
4890
|
import { basename as basename2 } from "path";
|
|
4510
4891
|
import { confirm as confirm2, isCancel as isCancel2, log as log2, note as note2, password as password2, select, spinner as spinner3, text as text2 } from "@clack/prompts";
|
|
4511
|
-
import
|
|
4892
|
+
import pc22 from "picocolors";
|
|
4512
4893
|
|
|
4513
4894
|
// src/core/global-config.ts
|
|
4514
|
-
import { chmod, mkdir as
|
|
4895
|
+
import { chmod, mkdir as mkdir4, readFile as readFile6, writeFile as writeFile3 } from "fs/promises";
|
|
4515
4896
|
import { homedir } from "os";
|
|
4516
|
-
import { dirname as dirname3, join as
|
|
4897
|
+
import { dirname as dirname3, join as join8 } from "path";
|
|
4517
4898
|
import { z as z3 } from "zod";
|
|
4518
4899
|
var GLOBAL_DIR = ".codebuddy";
|
|
4519
4900
|
var GLOBAL_FILE = "global.json";
|
|
@@ -4526,12 +4907,12 @@ var globalConfigSchema = z3.object({
|
|
|
4526
4907
|
installPath: z3.string().optional()
|
|
4527
4908
|
});
|
|
4528
4909
|
function globalConfigPath(home = homedir()) {
|
|
4529
|
-
return
|
|
4910
|
+
return join8(home, GLOBAL_DIR, GLOBAL_FILE);
|
|
4530
4911
|
}
|
|
4531
4912
|
async function readGlobalConfig(home = homedir()) {
|
|
4532
4913
|
const path = globalConfigPath(home);
|
|
4533
4914
|
try {
|
|
4534
|
-
const raw = await
|
|
4915
|
+
const raw = await readFile6(path, "utf8");
|
|
4535
4916
|
return globalConfigSchema.parse(JSON.parse(raw));
|
|
4536
4917
|
} catch (error) {
|
|
4537
4918
|
if (error.code === "ENOENT") return {};
|
|
@@ -4540,7 +4921,7 @@ async function readGlobalConfig(home = homedir()) {
|
|
|
4540
4921
|
}
|
|
4541
4922
|
async function writeGlobalConfig(next, home = homedir()) {
|
|
4542
4923
|
const path = globalConfigPath(home);
|
|
4543
|
-
await
|
|
4924
|
+
await mkdir4(dirname3(path), { recursive: true, mode: 448 });
|
|
4544
4925
|
await writeFile3(path, `${JSON.stringify(next, null, 2)}
|
|
4545
4926
|
`, { mode: 384 });
|
|
4546
4927
|
await chmod(path, 384);
|
|
@@ -4592,15 +4973,15 @@ async function runUseCommand(options = {}) {
|
|
|
4592
4973
|
})
|
|
4593
4974
|
));
|
|
4594
4975
|
note2(
|
|
4595
|
-
`Project folder: ${
|
|
4596
|
-
Namespace: ${
|
|
4976
|
+
`Project folder: ${pc22.bold(process.cwd())}
|
|
4977
|
+
Namespace: ${pc22.bold(namespace)}`,
|
|
4597
4978
|
"codebuddy use"
|
|
4598
4979
|
);
|
|
4599
4980
|
const stored = await readGlobalConfig();
|
|
4600
4981
|
const projectConfig = await readConfigFile();
|
|
4601
4982
|
let embeddings = projectConfig.provider?.type;
|
|
4602
4983
|
if (embeddings) {
|
|
4603
|
-
log2.info(`Embeddings: ${embeddings} (change with ${
|
|
4984
|
+
log2.info(`Embeddings: ${embeddings} (change with ${pc22.cyan("codebuddy models use")}).`);
|
|
4604
4985
|
} else if (!interactive) {
|
|
4605
4986
|
embeddings = "local";
|
|
4606
4987
|
} else {
|
|
@@ -4641,7 +5022,7 @@ Namespace: ${pc20.bold(namespace)}`,
|
|
|
4641
5022
|
log2.info("Using HF_TOKEN from environment.");
|
|
4642
5023
|
} else if (stored.hfToken) {
|
|
4643
5024
|
hfToken = stored.hfToken;
|
|
4644
|
-
log2.info(`Reusing saved Hugging Face token (${
|
|
5025
|
+
log2.info(`Reusing saved Hugging Face token (${pc22.dim("~/.codebuddy/global.json")}).`);
|
|
4645
5026
|
} else if (!interactive) {
|
|
4646
5027
|
throw new Error(
|
|
4647
5028
|
"Hugging Face embeddings need a token: set HF_TOKEN (no terminal to prompt for it)."
|
|
@@ -4775,7 +5156,7 @@ Namespace: ${pc20.bold(namespace)}`,
|
|
|
4775
5156
|
databaseUrl
|
|
4776
5157
|
});
|
|
4777
5158
|
log2.success(
|
|
4778
|
-
`Registered ${
|
|
5159
|
+
`Registered ${pc22.bold(install.serverKey)} in Claude Desktop. Restart with \u2318Q to activate.`
|
|
4779
5160
|
);
|
|
4780
5161
|
} catch (error) {
|
|
4781
5162
|
log2.warn(`Claude Desktop registration skipped: ${error.message}`);
|
|
@@ -4790,7 +5171,7 @@ Namespace: ${pc20.bold(namespace)}`,
|
|
|
4790
5171
|
databaseUrl
|
|
4791
5172
|
});
|
|
4792
5173
|
log2.success(
|
|
4793
|
-
`Registered ${
|
|
5174
|
+
`Registered ${pc22.bold(install.serverKey)} in Codex. Restart Codex to activate.`
|
|
4794
5175
|
);
|
|
4795
5176
|
} catch (error) {
|
|
4796
5177
|
log2.warn(`Codex registration skipped: ${error.message}`);
|
|
@@ -4798,24 +5179,24 @@ Namespace: ${pc20.bold(namespace)}`,
|
|
|
4798
5179
|
}
|
|
4799
5180
|
note2(
|
|
4800
5181
|
[
|
|
4801
|
-
`${
|
|
4802
|
-
`${
|
|
4803
|
-
`${
|
|
4804
|
-
`${
|
|
5182
|
+
`${pc22.green("\u2713")} CodeBuddy is ready for ${pc22.bold(folderName)}.`,
|
|
5183
|
+
`${pc22.green("\u2713")} Scaffolded ${pc22.cyan(".codebuddy/policies.yaml")} for project-specific guardrails.`,
|
|
5184
|
+
`${pc22.green("\u2713")} ${graphifyMessage}`,
|
|
5185
|
+
`${pc22.green("\u2713")} Added agent workflow instructions to ${pc22.cyan("CLAUDE.md")} and ${pc22.cyan("AGENTS.md")}.`,
|
|
4805
5186
|
``,
|
|
4806
5187
|
`Next:`,
|
|
4807
5188
|
` 1. Restart Claude Desktop and Codex.`,
|
|
4808
|
-
` 2. Ask Claude or Codex to use the ${
|
|
5189
|
+
` 2. Ask Claude or Codex to use the ${pc22.cyan("context_pack")} tool for each coding task.`,
|
|
4809
5190
|
` 3. Indexing, Graphify, Markdown memory import, and embeddings now update automatically while the MCP server is running.`,
|
|
4810
|
-
` 4. Run ${
|
|
5191
|
+
` 4. Run ${pc22.cyan("codebuddy doctor")} or ${pc22.cyan("codebuddy db doctor")} if you want a full health check.`,
|
|
4811
5192
|
``,
|
|
4812
5193
|
`Manage:`,
|
|
4813
|
-
` codebuddy claude list ${
|
|
4814
|
-
` codebuddy codex list ${
|
|
4815
|
-
` codebuddy db test ${
|
|
5194
|
+
` codebuddy claude list ${pc22.dim("# see every project wired up")}`,
|
|
5195
|
+
` codebuddy codex list ${pc22.dim("# see Codex entries")}`,
|
|
5196
|
+
` codebuddy db test ${pc22.dim("# quick Postgres connectivity check")}`,
|
|
4816
5197
|
` codebuddy claude remove codebuddy-${namespace}`,
|
|
4817
5198
|
` codebuddy codex remove codebuddy-${namespace}`,
|
|
4818
|
-
` codebuddy postgres down ${
|
|
5199
|
+
` codebuddy postgres down ${pc22.dim("# stop the DB (data preserved)")}`
|
|
4819
5200
|
].join("\n"),
|
|
4820
5201
|
"Done"
|
|
4821
5202
|
);
|
|
@@ -4826,7 +5207,7 @@ Namespace: ${pc20.bold(namespace)}`,
|
|
|
4826
5207
|
|
|
4827
5208
|
// src/cli/commands/worklog.ts
|
|
4828
5209
|
import { relative as relative6 } from "path";
|
|
4829
|
-
import
|
|
5210
|
+
import pc23 from "picocolors";
|
|
4830
5211
|
function registerWorklogCommands(program, runSafely2) {
|
|
4831
5212
|
const worklog = program.command("worklog").description("Inspect the cross-chat worklog of completed turns.");
|
|
4832
5213
|
worklog.command("list", { isDefault: true }).option("--limit <n>", "Maximum entries to show.", "20").option("--json", "Print machine-readable JSON.").description("List worklog entries, newest first.").action(async (opts) => {
|
|
@@ -4837,7 +5218,7 @@ function registerWorklogCommands(program, runSafely2) {
|
|
|
4837
5218
|
return;
|
|
4838
5219
|
}
|
|
4839
5220
|
if (entries.length === 0) {
|
|
4840
|
-
console.log(
|
|
5221
|
+
console.log(pc23.dim("no worklog entries yet"));
|
|
4841
5222
|
return;
|
|
4842
5223
|
}
|
|
4843
5224
|
for (const entry of entries) console.log(renderRow2(entry));
|
|
@@ -4851,36 +5232,36 @@ function registerWorklogCommands(program, runSafely2) {
|
|
|
4851
5232
|
worklog.command("latest").description("Show the most recent worklog entry.").action(async () => {
|
|
4852
5233
|
await runSafely2(async () => {
|
|
4853
5234
|
const [entry] = await new WorklogStore().list();
|
|
4854
|
-
console.log(entry ? renderEntry(entry) :
|
|
5235
|
+
console.log(entry ? renderEntry(entry) : pc23.dim("no worklog entries yet"));
|
|
4855
5236
|
});
|
|
4856
5237
|
});
|
|
4857
5238
|
}
|
|
4858
5239
|
function renderRow2(entry) {
|
|
4859
5240
|
const summary = entry.summary.replace(/\s+/g, " ");
|
|
4860
5241
|
const short2 = summary.length <= 70 ? summary : `${summary.slice(0, 69)}\u2026`;
|
|
4861
|
-
return `${
|
|
5242
|
+
return `${pc23.dim(entry.createdAt.slice(0, 16))} ${pc23.dim(entry.id)} ${short2} ${pc23.dim(`(${entry.files.length} file(s))`)}`;
|
|
4862
5243
|
}
|
|
4863
5244
|
function renderEntry(entry) {
|
|
4864
|
-
const lines = [`${
|
|
4865
|
-
if (entry.sourceSessionId) lines.push(`${
|
|
4866
|
-
if (entry.sourcePlanId) lines.push(`${
|
|
4867
|
-
if (entry.commitSha) lines.push(`${
|
|
4868
|
-
if (entry.files.length > 0) lines.push(`${
|
|
5245
|
+
const lines = [`${pc23.bold(entry.id)} ${pc23.dim(entry.createdAt)} ${pc23.dim(entry.namespace)}`];
|
|
5246
|
+
if (entry.sourceSessionId) lines.push(`${pc23.bold("session:")} ${entry.sourceSessionId}`);
|
|
5247
|
+
if (entry.sourcePlanId) lines.push(`${pc23.bold("plan:")} ${entry.sourcePlanId}`);
|
|
5248
|
+
if (entry.commitSha) lines.push(`${pc23.bold("commit:")} ${entry.commitSha}`);
|
|
5249
|
+
if (entry.files.length > 0) lines.push(`${pc23.bold("files:")} ${entry.files.join(", ")}`);
|
|
4869
5250
|
if (entry.verification.length > 0) {
|
|
4870
|
-
lines.push(`${
|
|
5251
|
+
lines.push(`${pc23.bold("verification:")}`, ...entry.verification.map((line) => ` - ${line}`));
|
|
4871
5252
|
}
|
|
4872
5253
|
if (entry.savedMemory.length > 0) {
|
|
4873
|
-
lines.push(`${
|
|
5254
|
+
lines.push(`${pc23.bold("saved memory:")} ${entry.savedMemory.join(", ")}`);
|
|
4874
5255
|
}
|
|
4875
5256
|
if (entry.queuedForReview.length > 0) {
|
|
4876
|
-
lines.push(`${
|
|
5257
|
+
lines.push(`${pc23.bold("queued for review:")} ${entry.queuedForReview.join(", ")}`);
|
|
4877
5258
|
}
|
|
4878
|
-
lines.push("", entry.summary, "",
|
|
5259
|
+
lines.push("", entry.summary, "", pc23.dim(relative6(process.cwd(), entry.path)));
|
|
4879
5260
|
return lines.join("\n");
|
|
4880
5261
|
}
|
|
4881
5262
|
|
|
4882
5263
|
// src/cli/commands/zvec.ts
|
|
4883
|
-
import
|
|
5264
|
+
import pc24 from "picocolors";
|
|
4884
5265
|
function registerZvecCommands(program, runSafely2) {
|
|
4885
5266
|
const zvec = program.command("zvec").description("Optional zvec-grep semantic file discovery for the context tools.");
|
|
4886
5267
|
zvec.command("status", { isDefault: true }).option("--json", "Print machine-readable JSON.").description("Show whether zvec-grep is enabled, installed, supported and indexed.").action(async (opts) => {
|
|
@@ -4890,22 +5271,22 @@ function registerZvecCommands(program, runSafely2) {
|
|
|
4890
5271
|
console.log(JSON.stringify(report, null, 2));
|
|
4891
5272
|
return;
|
|
4892
5273
|
}
|
|
4893
|
-
const mark = (ok2) => ok2 ?
|
|
5274
|
+
const mark = (ok2) => ok2 ? pc24.green("yes") : pc24.yellow("no");
|
|
4894
5275
|
console.log(`enabled: ${mark(report.enabled)}`);
|
|
4895
5276
|
console.log(`binary: ${report.binary}`);
|
|
4896
5277
|
console.log(
|
|
4897
|
-
`version: ${report.version ??
|
|
5278
|
+
`version: ${report.version ?? pc24.yellow("not found")}${report.version && !report.supported ? pc24.yellow(" (unsupported; need 0.2.x)") : ""}`
|
|
4898
5279
|
);
|
|
4899
5280
|
console.log(`index ready: ${mark(report.indexReady)}`);
|
|
4900
5281
|
console.log(
|
|
4901
|
-
`zg server: ${report.server} ${
|
|
5282
|
+
`zg server: ${report.server} ${pc24.dim("(running = faster queries; optional)")}`
|
|
4902
5283
|
);
|
|
4903
5284
|
console.log(`status: ${report.reason}`);
|
|
4904
|
-
if (!report.version) console.log(
|
|
5285
|
+
if (!report.version) console.log(pc24.dim("install: npm install -g @zvec/zvec-grep"));
|
|
4905
5286
|
else if (report.supported && !report.indexReady)
|
|
4906
|
-
console.log(
|
|
5287
|
+
console.log(pc24.dim("next: codebuddy zvec index"));
|
|
4907
5288
|
else if (report.indexReady && !report.enabled)
|
|
4908
|
-
console.log(
|
|
5289
|
+
console.log(pc24.dim("next: codebuddy zvec enable"));
|
|
4909
5290
|
});
|
|
4910
5291
|
});
|
|
4911
5292
|
zvec.command("index").option("--model <model>", "Embedding model for a new index.", DEFAULT_ZVEC_MODEL).option("--rebuild", "Rebuild the index from scratch (e.g. after changing model).").description("Build or refresh the zg index for this repository (explicit; never automatic).").action(async (opts) => {
|
|
@@ -4915,21 +5296,21 @@ function registerZvecCommands(program, runSafely2) {
|
|
|
4915
5296
|
...opts.rebuild ? { rebuild: true } : {}
|
|
4916
5297
|
});
|
|
4917
5298
|
if (code !== 0) throw new Error(`zg index exited with code ${code}`);
|
|
4918
|
-
console.log(
|
|
5299
|
+
console.log(pc24.dim("next: codebuddy zvec enable (.zvec-grep/ ignores itself in git)"));
|
|
4919
5300
|
});
|
|
4920
5301
|
});
|
|
4921
5302
|
zvec.command("enable").description("Use zvec-grep candidates in context_pack / context_before_edit.").action(async () => {
|
|
4922
5303
|
await runSafely2(async () => {
|
|
4923
5304
|
await setZvecEnabled(true);
|
|
4924
5305
|
console.log(
|
|
4925
|
-
`${
|
|
5306
|
+
`${pc24.green("enabled")} zvec-grep retrieval (falls back to keywords if unavailable)`
|
|
4926
5307
|
);
|
|
4927
5308
|
});
|
|
4928
5309
|
});
|
|
4929
5310
|
zvec.command("disable").description("Stop using zvec-grep; keyword ranking only.").action(async () => {
|
|
4930
5311
|
await runSafely2(async () => {
|
|
4931
5312
|
await setZvecEnabled(false);
|
|
4932
|
-
console.log(`${
|
|
5313
|
+
console.log(`${pc24.yellow("disabled")} zvec-grep retrieval`);
|
|
4933
5314
|
});
|
|
4934
5315
|
});
|
|
4935
5316
|
}
|
|
@@ -5202,6 +5583,36 @@ function createCli() {
|
|
|
5202
5583
|
console.log(JSON.stringify(await runtime.repository.getStats(), null, 2));
|
|
5203
5584
|
});
|
|
5204
5585
|
});
|
|
5586
|
+
program.command("storage").option("--json", "Print machine-readable JSON.").description(
|
|
5587
|
+
"Memory storage health: Markdown/database drift, backup coverage, embedding backlog and spaces, capture lag."
|
|
5588
|
+
).action(async (opts) => {
|
|
5589
|
+
await runSafely(async () => {
|
|
5590
|
+
const root = process.cwd();
|
|
5591
|
+
const capture2 = {
|
|
5592
|
+
stagedNotCaptured: await new HookStagingStore(root).pending(),
|
|
5593
|
+
journalBehind: (await journalLag(root)).filter((entry) => entry.behindBytes !== 0)
|
|
5594
|
+
};
|
|
5595
|
+
let database;
|
|
5596
|
+
try {
|
|
5597
|
+
const runtime = await createRuntime(await loadRuntimeConfig());
|
|
5598
|
+
try {
|
|
5599
|
+
database = await runtime.memory.storageReport();
|
|
5600
|
+
} finally {
|
|
5601
|
+
await runtime.close();
|
|
5602
|
+
}
|
|
5603
|
+
} catch (error) {
|
|
5604
|
+
database = { unavailable: error.message };
|
|
5605
|
+
}
|
|
5606
|
+
if (opts.json) {
|
|
5607
|
+
console.log(JSON.stringify({ database, capture: capture2 }, null, 2));
|
|
5608
|
+
return;
|
|
5609
|
+
}
|
|
5610
|
+
printStorage(database, capture2);
|
|
5611
|
+
if ("unavailable" in database || database.markdownOnly.length + database.dbOnly.length > 0) {
|
|
5612
|
+
process.exitCode = 1;
|
|
5613
|
+
}
|
|
5614
|
+
});
|
|
5615
|
+
});
|
|
5205
5616
|
program.command("doctor").description("Check CodeBuddy environment health.").option("--skip-model-check", "Do not call Hugging Face models.").action(async (opts) => {
|
|
5206
5617
|
await runSafely(async () => {
|
|
5207
5618
|
const report = await runDoctor({ skipModelCheck: opts.skipModelCheck ?? true });
|
|
@@ -5228,6 +5639,8 @@ function createCli() {
|
|
|
5228
5639
|
registerLearnCommand(program, runSafely);
|
|
5229
5640
|
registerMemoryCommands(program, runSafely);
|
|
5230
5641
|
registerWorklogCommands(program, runSafely);
|
|
5642
|
+
registerJournalCommands(program, runSafely);
|
|
5643
|
+
registerOutputCommands(program, runSafely);
|
|
5231
5644
|
registerZvecCommands(program, runSafely);
|
|
5232
5645
|
registerLlmCommands(program, runSafely);
|
|
5233
5646
|
registerSuggestCommand(program, runSafely);
|
|
@@ -5255,7 +5668,20 @@ var HELP_GROUPS = [
|
|
|
5255
5668
|
["Get started:", ["use", "init", "doctor", "hooks", "clients", "models", "dashboard"]],
|
|
5256
5669
|
[
|
|
5257
5670
|
"Daily work:",
|
|
5258
|
-
[
|
|
5671
|
+
[
|
|
5672
|
+
"context",
|
|
5673
|
+
"plan",
|
|
5674
|
+
"change",
|
|
5675
|
+
"risk",
|
|
5676
|
+
"suggest",
|
|
5677
|
+
"memory",
|
|
5678
|
+
"worklog",
|
|
5679
|
+
"journal",
|
|
5680
|
+
"run",
|
|
5681
|
+
"output",
|
|
5682
|
+
"map",
|
|
5683
|
+
"symbols"
|
|
5684
|
+
]
|
|
5259
5685
|
],
|
|
5260
5686
|
["Indexing and search:", ["index", "watch", "reindex", "zvec", "graphify", "llm"]],
|
|
5261
5687
|
[
|
|
@@ -5265,6 +5691,7 @@ var HELP_GROUPS = [
|
|
|
5265
5691
|
"db",
|
|
5266
5692
|
"migrate",
|
|
5267
5693
|
"stats",
|
|
5694
|
+
"storage",
|
|
5268
5695
|
"inspect",
|
|
5269
5696
|
"namespaces",
|
|
5270
5697
|
"list-facts",
|
|
@@ -5315,7 +5742,7 @@ async function runSafely(fn) {
|
|
|
5315
5742
|
try {
|
|
5316
5743
|
await fn();
|
|
5317
5744
|
} catch (error) {
|
|
5318
|
-
console.error(
|
|
5745
|
+
console.error(pc25.red(String(redactSecrets(error.message))));
|
|
5319
5746
|
process.exitCode = 1;
|
|
5320
5747
|
}
|
|
5321
5748
|
}
|
|
@@ -5329,9 +5756,9 @@ function parseDuration(value) {
|
|
|
5329
5756
|
return amount * 60 * 1e3;
|
|
5330
5757
|
}
|
|
5331
5758
|
function printDoctor(report) {
|
|
5332
|
-
const ok2 =
|
|
5333
|
-
const bad =
|
|
5334
|
-
const warn2 =
|
|
5759
|
+
const ok2 = pc25.green("ok");
|
|
5760
|
+
const bad = pc25.red("fail");
|
|
5761
|
+
const warn2 = pc25.yellow("warn");
|
|
5335
5762
|
console.log(`scaffold root: ${report.scaffold.codebuddyDir.ok ? ok2 : bad}`);
|
|
5336
5763
|
if (report.scaffold.codebuddyDir.warning)
|
|
5337
5764
|
console.log(` ${report.scaffold.codebuddyDir.warning}`);
|
|
@@ -5357,7 +5784,7 @@ function printDoctor(report) {
|
|
|
5357
5784
|
);
|
|
5358
5785
|
console.log(`estimated daily cap remaining: ${report.usage.estimatedDailyCapRemaining}`);
|
|
5359
5786
|
if (report.usage.warning80Percent)
|
|
5360
|
-
console.log(
|
|
5787
|
+
console.log(pc25.yellow("usage warning: daily cap is over 80% used"));
|
|
5361
5788
|
console.log(
|
|
5362
5789
|
`config permissions: ${report.config.exists ? report.config.mode : "missing"} ${report.config.ok ? ok2 : warn2}`
|
|
5363
5790
|
);
|
|
@@ -5367,9 +5794,9 @@ function printDoctor(report) {
|
|
|
5367
5794
|
}
|
|
5368
5795
|
}
|
|
5369
5796
|
function printDbDoctor(report) {
|
|
5370
|
-
const ok2 =
|
|
5371
|
-
const bad =
|
|
5372
|
-
const warn2 =
|
|
5797
|
+
const ok2 = pc25.green("ok");
|
|
5798
|
+
const bad = pc25.red("fail");
|
|
5799
|
+
const warn2 = pc25.yellow("warn");
|
|
5373
5800
|
console.log(`DB connectivity: ${report.db.ok ? ok2 : bad}`);
|
|
5374
5801
|
if (report.db.postgresUrlSource) console.log(` url source: ${report.db.postgresUrlSource}`);
|
|
5375
5802
|
if (report.db.error) console.log(` ${report.db.error}`);
|
|
@@ -5382,7 +5809,42 @@ function printDbDoctor(report) {
|
|
|
5382
5809
|
}
|
|
5383
5810
|
if (report.namespace.warning) console.log(` ${report.namespace.warning}`);
|
|
5384
5811
|
}
|
|
5812
|
+
function printStorage(database, capture2) {
|
|
5813
|
+
if ("unavailable" in database) {
|
|
5814
|
+
console.log(pc25.yellow(`database: unavailable (${database.unavailable})`));
|
|
5815
|
+
} else {
|
|
5816
|
+
const drift = database.markdownOnly.length + database.dbOnly.length;
|
|
5817
|
+
console.log(
|
|
5818
|
+
`facts: ${database.markdownFacts} Markdown, ${database.databaseFacts} database${database.invalidFiles > 0 ? `, ${database.invalidFiles} unreadable file(s)` : ""}`
|
|
5819
|
+
);
|
|
5820
|
+
console.log(
|
|
5821
|
+
drift === 0 ? pc25.green("sync: Markdown and database agree") : pc25.yellow(
|
|
5822
|
+
`sync: ${database.markdownOnly.length} file(s) not in the database, ${database.dbOnly.length} row(s) without a file (run \`codebuddy reindex\`)`
|
|
5823
|
+
)
|
|
5824
|
+
);
|
|
5825
|
+
if (database.unbacked.length > 0) {
|
|
5826
|
+
console.log(
|
|
5827
|
+
pc25.yellow(
|
|
5828
|
+
`backup: ${database.unbacked.length} database-only fact(s) have no Markdown copy`
|
|
5829
|
+
)
|
|
5830
|
+
);
|
|
5831
|
+
}
|
|
5832
|
+
const e = database.embeddings;
|
|
5833
|
+
console.log(
|
|
5834
|
+
`embeddings: ${e.ready} ready, ${e.pending} pending, ${e.processing} processing, ${e.failed} failed${database.oldestPendingAt ? ` (oldest pending ${database.oldestPendingAt})` : ""}`
|
|
5835
|
+
);
|
|
5836
|
+
for (const space of database.spaces) {
|
|
5837
|
+
console.log(` space ${space.model} ${space.space ?? "(legacy)"}: ${space.count}`);
|
|
5838
|
+
}
|
|
5839
|
+
if (database.spaces.length > 1) {
|
|
5840
|
+
console.log(pc25.yellow(" more than one embedding space: run `codebuddy reindex --respace`"));
|
|
5841
|
+
}
|
|
5842
|
+
}
|
|
5843
|
+
console.log(
|
|
5844
|
+
capture2.stagedNotCaptured.length === 0 && capture2.journalBehind.length === 0 ? pc25.green("capture: nothing pending") : `capture: ${capture2.stagedNotCaptured.length} session(s) with uncaptured edits, ${capture2.journalBehind.length} journal(s) behind their transcript`
|
|
5845
|
+
);
|
|
5846
|
+
}
|
|
5385
5847
|
export {
|
|
5386
5848
|
createCli
|
|
5387
5849
|
};
|
|
5388
|
-
//# sourceMappingURL=main-
|
|
5850
|
+
//# sourceMappingURL=main-SFC5LV4E.js.map
|