openwolf-enhanced 1.16.5 → 1.17.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/CHANGELOG.md +78 -0
- package/dist/dashboard/assets/{AISuggestions-DF-LNNBU.js → AISuggestions-1R0pnlm9.js} +1 -1
- package/dist/dashboard/assets/{ActivityLog-DuQB_TaU.js → ActivityLog-Cet80S6D.js} +1 -1
- package/dist/dashboard/assets/{ActivityTimeline-jWDsjU7p.js → ActivityTimeline-CoCPhZRg.js} +1 -1
- package/dist/dashboard/assets/{AnatomyBrowser-BOfaZMLt.js → AnatomyBrowser-BK7WiuNN.js} +1 -1
- package/dist/dashboard/assets/{BugLog-Bb8Jdare.js → BugLog-DlOfPz4q.js} +1 -1
- package/dist/dashboard/assets/{CerebrumViewer-Clix3JOG.js → CerebrumViewer-C0gSBIxg.js} +1 -1
- package/dist/dashboard/assets/{CronStatus-ne4IxXs8.js → CronStatus-DMGKkek9.js} +1 -1
- package/dist/dashboard/assets/{DesignQC-COcZ38nI.js → DesignQC-BUjKJ4wE.js} +1 -1
- package/dist/dashboard/assets/{MemoryViewer-BYUkDs9k.js → MemoryViewer-CbFNeqWm.js} +1 -1
- package/dist/dashboard/assets/{NativeMemory-20gjdcAD.js → NativeMemory-DEAyhwK9.js} +1 -1
- package/dist/dashboard/assets/{ProjectOverview-BoadyvwS.js → ProjectOverview-CnxeetBi.js} +1 -1
- package/dist/dashboard/assets/{ProjectsAggregate-z6XtnlbZ.js → ProjectsAggregate-DG5Vxc2k.js} +1 -1
- package/dist/dashboard/assets/{StatusBadge-CBsSwOOc.js → StatusBadge-DelYV9XQ.js} +1 -1
- package/dist/dashboard/assets/{TokenUsage-n2PFPxqk.js → TokenUsage-Bvk7bQ1V.js} +1 -1
- package/dist/dashboard/assets/{index-DLkIxGHf.js → index-QzB3QJTS.js} +3 -3
- package/dist/dashboard/index.html +1 -1
- package/dist/src/cli/consolidate-cmd.js +14 -7
- package/dist/src/cli/consolidate-cmd.js.map +1 -1
- package/dist/src/cli/index.js +10 -0
- package/dist/src/cli/index.js.map +1 -1
- package/dist/src/cli/llm-cmd.js +82 -0
- package/dist/src/cli/llm-cmd.js.map +1 -0
- package/dist/src/daemon/cron-engine.js +191 -57
- package/dist/src/daemon/cron-engine.js.map +1 -1
- package/dist/src/daemon/llm-provider.js +64 -8
- package/dist/src/daemon/llm-provider.js.map +1 -1
- package/dist/src/daemon/wolf-daemon.js +4 -2
- package/dist/src/daemon/wolf-daemon.js.map +1 -1
- package/dist/src/utils/recall.js +4 -0
- package/dist/src/utils/recall.js.map +1 -1
- package/package.json +1 -1
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
8
8
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
9
9
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
|
10
|
-
<script type="module" crossorigin src="./assets/index-
|
|
10
|
+
<script type="module" crossorigin src="./assets/index-QzB3QJTS.js"></script>
|
|
11
11
|
<link rel="stylesheet" crossorigin href="./assets/index-Cr3yWM5G.css">
|
|
12
12
|
</head>
|
|
13
13
|
<body>
|
|
@@ -3,7 +3,7 @@ import * as path from "node:path";
|
|
|
3
3
|
import { findProjectRoot } from "../scanner/project-root.js";
|
|
4
4
|
import { findDuplicateEntries } from "../utils/maintenance.js";
|
|
5
5
|
import { blocksFor } from "../utils/recall.js";
|
|
6
|
-
import { resolveLlmConfig, callLlm } from "../daemon/llm-provider.js";
|
|
6
|
+
import { resolveLlmConfig, callLlm, requiresApiKey } from "../daemon/llm-provider.js";
|
|
7
7
|
// Rewrite `content`: for each merge, replace block A's lines with the merged entry and delete block
|
|
8
8
|
// B's lines. Pure + bottom-up so line indices don't shift. (1-based start/end from blocksFor.)
|
|
9
9
|
export function applyConsolidations(content, merges) {
|
|
@@ -43,9 +43,9 @@ export async function consolidateCommand(opts) {
|
|
|
43
43
|
console.log(`OpenWolf Consolidate — ${pairs.length} near-duplicate pair(s) in cerebrum.md (threshold ${threshold})\n`);
|
|
44
44
|
// Resolve the LLM once (consolidation needs it). Clear guidance if unconfigured.
|
|
45
45
|
const llm = resolveLlmConfig(wolfDir);
|
|
46
|
-
const apiKey = process.env[llm.apiKeyEnv];
|
|
47
|
-
if (!apiKey) {
|
|
48
|
-
console.error(`${llm.apiKeyEnv} is not set — consolidation needs an LLM. Set it, or point openwolf.cron.llm_* at a provider (
|
|
46
|
+
const apiKey = process.env[llm.apiKeyEnv] ?? "";
|
|
47
|
+
if (!apiKey && requiresApiKey(llm)) {
|
|
48
|
+
console.error(`${llm.apiKeyEnv} is not set — consolidation needs an LLM. Set it, or point openwolf.cron.llm_* at a provider (a free OpenAI-compatible one, or a local model server — LM Studio on http://localhost:1234/v1, Ollama on http://localhost:11434/v1 — which needs no key). Provider: ${llm.provider}/${llm.model}.`);
|
|
49
49
|
process.exitCode = 1;
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
@@ -60,7 +60,9 @@ export async function consolidateCommand(opts) {
|
|
|
60
60
|
process.stdout.write(` ${Math.round(p.similarity * 100)}% lines ${p.aLine} ↔ ${p.bLine} … `);
|
|
61
61
|
let merged = "";
|
|
62
62
|
try {
|
|
63
|
-
|
|
63
|
+
// 3000, not 900: the merge itself is short, but a reasoning model bills its thinking to the same
|
|
64
|
+
// budget and would otherwise return nothing — every merge then looked "implausible" and was skipped.
|
|
65
|
+
merged = (await callLlm(llm, apiKey, MERGE_PROMPT(a.text, b.text), { maxTokens: 3000, timeoutMs: 120000 })).trim();
|
|
64
66
|
merged = merged.replace(/^```[\w]*\n?|\n?```$/g, "").trim(); // strip stray fences
|
|
65
67
|
}
|
|
66
68
|
catch (e) {
|
|
@@ -87,11 +89,16 @@ export async function consolidateCommand(opts) {
|
|
|
87
89
|
console.log(`\n(dry run) ${merges.length} pair(s) would be merged. Run without --dry-run to apply.`);
|
|
88
90
|
return;
|
|
89
91
|
}
|
|
90
|
-
// Back up, then rewrite.
|
|
92
|
+
// Back up, then rewrite. A failed backup is a HARD STOP, not best-effort: same failure class as
|
|
93
|
+
// bug-157 — if the safety net silently fails, the dangerous step must not proceed. No backup, no rewrite.
|
|
91
94
|
try {
|
|
92
95
|
fs.copyFileSync(cerebrumPath, cerebrumPath + ".bak-pre-consolidate");
|
|
93
96
|
}
|
|
94
|
-
catch {
|
|
97
|
+
catch (e) {
|
|
98
|
+
console.error(`\nAborting: could not write backup cerebrum.md.bak-pre-consolidate (${e.message}). cerebrum.md left untouched.`);
|
|
99
|
+
process.exitCode = 1;
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
95
102
|
fs.writeFileSync(cerebrumPath, applyConsolidations(content, merges), "utf-8");
|
|
96
103
|
console.log(`\nDone. Merged ${merges.length} pair(s) → cerebrum.md (backup: cerebrum.md.bak-pre-consolidate). Review the diff.`);
|
|
97
104
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"consolidate-cmd.js","sourceRoot":"","sources":["../../../src/cli/consolidate-cmd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,MAAM,2BAA2B,CAAC;
|
|
1
|
+
{"version":3,"file":"consolidate-cmd.js","sourceRoot":"","sources":["../../../src/cli/consolidate-cmd.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAItF,oGAAoG;AACpG,+FAA+F;AAC/F,MAAM,UAAU,mBAAmB,CAAC,OAAe,EAAE,MAAe;IAClE,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACrC,MAAM,GAAG,GAA0D,EAAE,CAAC;IACtE,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,UAAU,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC3E,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC,CAAC,uBAAuB;IAC/E,CAAC;IACD,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY;IACnD,KAAK,MAAM,EAAE,IAAI,GAAG;QAAE,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,EAAE,CAAC,KAAK,GAAG,CAAC,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IACpF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,YAAY,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE,CAC5C,4HAA4H;IAC5H,uIAAuI;IACvI,6HAA6H;IAC7H,aAAa,CAAC,iBAAiB,CAAC,EAAE,CAAC;AAIrC,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAqB;IAC5D,MAAM,WAAW,GAAG,eAAe,EAAE,CAAC;IACtC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,OAAO,CAAC,CAAC;IAChD,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IACvD,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,YAAY,CAAC,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IAEtG,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,UAAU,CAAC,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC;IAC5F,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,IAAI,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IACjE,MAAM,KAAK,GAAG,oBAAoB,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,CAAC,aAAa,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IACtG,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,qDAAqD,SAAS,4BAA4B,CAAC,CAAC;QACxG,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,OAAO,CAAC,CAAC;IACvD,MAAM,MAAM,GAAG,SAAS,CAAC,aAAa,EAAE,OAAO,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAEzD,OAAO,CAAC,GAAG,CAAC,0BAA0B,KAAK,CAAC,MAAM,qDAAqD,SAAS,KAAK,CAAC,CAAC;IAEvH,iFAAiF;IACjF,MAAM,GAAG,GAAG,gBAAgB,CAAC,OAAO,CAAC,CAAC;IACtC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,EAAE,CAAC;IAChD,IAAI,CAAC,MAAM,IAAI,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC;QACnC,OAAO,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,SAAS,qQAAqQ,GAAG,CAAC,QAAQ,IAAI,GAAG,CAAC,KAAK,GAAG,CAAC,CAAC;QACjU,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAY,EAAE,CAAC;IAC3B,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;YAAE,SAAS,CAAC,uBAAuB;QACrF,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACzD,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;YAAE,SAAS;QACvB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,GAAG,GAAG,CAAC,YAAY,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,KAAK,KAAK,CAAC,CAAC;QAC/F,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC;YACH,iGAAiG;YACjG,qGAAqG;YACrG,MAAM,GAAG,CAAC,MAAM,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACnH,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,uBAAuB,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,qBAAqB;QACpF,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,OAAO,CAAC,GAAG,CAAC,uBAAwB,CAAW,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC;YACzE,SAAS;QACX,CAAC;QACD,IAAI,MAAM,CAAC,MAAM,GAAG,EAAE,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC;YAC9E,OAAO,CAAC,GAAG,CAAC,oCAAoC,CAAC,CAAC;YAClD,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAC7C,MAAM,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,MAAM,EAAE,CAAC,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,EAAE,UAAU,EAAE,MAAM,EAAE,CAAC,CAAC;QAChG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACtB,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,OAAO,CAAC,GAAG,CAAC,WAAW,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACvG,CAAC;IACH,CAAC;IAED,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAAC,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IACvE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;QAChB,OAAO,CAAC,GAAG,CAAC,eAAe,MAAM,CAAC,MAAM,2DAA2D,CAAC,CAAC;QACrG,OAAO;IACT,CAAC;IAED,gGAAgG;IAChG,0GAA0G;IAC1G,IAAI,CAAC;QACH,EAAE,CAAC,YAAY,CAAC,YAAY,EAAE,YAAY,GAAG,sBAAsB,CAAC,CAAC;IACvE,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,OAAO,CAAC,KAAK,CAAC,uEAAwE,CAAW,CAAC,OAAO,gCAAgC,CAAC,CAAC;QAC3I,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IACD,EAAE,CAAC,aAAa,CAAC,YAAY,EAAE,mBAAmB,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,CAAC;IAC9E,OAAO,CAAC,GAAG,CAAC,kBAAkB,MAAM,CAAC,MAAM,oFAAoF,CAAC,CAAC;AACnI,CAAC"}
|
package/dist/src/cli/index.js
CHANGED
|
@@ -153,6 +153,16 @@ export function createProgram() {
|
|
|
153
153
|
const { consolidateCommand } = await import("./consolidate-cmd.js");
|
|
154
154
|
await consolidateCommand(opts);
|
|
155
155
|
});
|
|
156
|
+
// --- LLM command ---
|
|
157
|
+
program
|
|
158
|
+
.command("llm")
|
|
159
|
+
.description("Show (and test) the LLM the project's AI features call — incl. local models via Ollama/llama.cpp")
|
|
160
|
+
.option("--test", "Send a real prompt and time the round-trip")
|
|
161
|
+
.option("--prompt <text>", "Prompt to send with --test")
|
|
162
|
+
.action(async (opts) => {
|
|
163
|
+
const { llmCommand } = await import("./llm-cmd.js");
|
|
164
|
+
await llmCommand(opts);
|
|
165
|
+
});
|
|
156
166
|
// --- Export command ---
|
|
157
167
|
program
|
|
158
168
|
.command("export <what>")
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import * as path from "node:path";
|
|
2
|
+
import { findProjectRoot } from "../scanner/project-root.js";
|
|
3
|
+
import { resolveLlmConfig, callLlm, requiresApiKey, isLocalEndpoint } from "../daemon/llm-provider.js";
|
|
4
|
+
// The port is read back out of the configured base_url — hard-coding Ollama's 11434 sent LM Studio
|
|
5
|
+
// users (port 1234) to forward a port nothing was listening on.
|
|
6
|
+
function endpointPort(baseUrl) {
|
|
7
|
+
try {
|
|
8
|
+
const u = new URL(baseUrl);
|
|
9
|
+
return u.port || (u.protocol === "https:" ? "443" : "80");
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return "1234";
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
// Turn a fetch/HTTP failure into the one line that actually tells the user what to do next.
|
|
16
|
+
export function explainLlmError(cfg, err) {
|
|
17
|
+
const msg = err.message || String(err);
|
|
18
|
+
const cause = err.cause?.code;
|
|
19
|
+
const port = endpointPort(cfg.baseUrl);
|
|
20
|
+
if (cause === "ECONNREFUSED" || /ECONNREFUSED|fetch failed|Empty reply|socket hang up/i.test(msg)) {
|
|
21
|
+
return isLocalEndpoint(cfg.baseUrl)
|
|
22
|
+
? `Nothing is listening on ${cfg.baseUrl}. If the model runs on another machine, forward the port to this one:\n` +
|
|
23
|
+
` ssh -N -R ${port}:localhost:${port} <user>@<this-host> (run on the machine with the model)\n` +
|
|
24
|
+
` If the tunnel is already up, the model server itself is not running — LM Studio serves only while\n` +
|
|
25
|
+
` the Developer tab's server toggle is "Running" (\`lms server start\`); Ollama serves via \`ollama serve\`.`
|
|
26
|
+
: `Cannot reach ${cfg.baseUrl} — ${msg}`;
|
|
27
|
+
}
|
|
28
|
+
if (/\b404\b/.test(msg) && isLocalEndpoint(cfg.baseUrl)) {
|
|
29
|
+
return `Endpoint answered 404 — the server is up but does not know the model "${cfg.model}".\n` +
|
|
30
|
+
` Check the exact id it serves: curl ${cfg.baseUrl}/models\n` +
|
|
31
|
+
` Then load it (LM Studio: load the model or enable JIT loading; Ollama: ollama pull ${cfg.model}).`;
|
|
32
|
+
}
|
|
33
|
+
if (/max_tokens/.test(msg)) {
|
|
34
|
+
return msg; // already the actionable reasoning-model explanation from parseLlmResponse
|
|
35
|
+
}
|
|
36
|
+
if (/\b401\b|\b403\b/.test(msg)) {
|
|
37
|
+
return `Rejected (auth). ${requiresApiKey(cfg) ? `Check that $${cfg.apiKeyEnv} holds a valid key.` : "The local server demands a key — set one in $" + cfg.apiKeyEnv + "."}`;
|
|
38
|
+
}
|
|
39
|
+
return msg;
|
|
40
|
+
}
|
|
41
|
+
export async function llmCommand(opts) {
|
|
42
|
+
const wolfDir = path.join(findProjectRoot(), ".wolf");
|
|
43
|
+
const cfg = resolveLlmConfig(wolfDir);
|
|
44
|
+
const keyed = !!process.env[cfg.apiKeyEnv];
|
|
45
|
+
const local = isLocalEndpoint(cfg.baseUrl);
|
|
46
|
+
console.log("OpenWolf LLM — used by cron AI tasks and `openwolf consolidate`\n");
|
|
47
|
+
console.log(` provider ${cfg.provider}${local ? " (local model server — no API key needed)" : ""}`);
|
|
48
|
+
console.log(` endpoint ${cfg.baseUrl}`);
|
|
49
|
+
console.log(` model ${cfg.model}`);
|
|
50
|
+
console.log(` api key ${keyed ? `$${cfg.apiKeyEnv} is set` : requiresApiKey(cfg) ? `$${cfg.apiKeyEnv} is NOT set — remote providers need one` : "not required"}`);
|
|
51
|
+
if (!opts.test) {
|
|
52
|
+
console.log("\nRun `openwolf llm --test` to send a real prompt and time the round-trip.");
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
const prompt = opts.prompt || "Reply with exactly one word: OK";
|
|
56
|
+
console.log(`\n → ${JSON.stringify(prompt)}`);
|
|
57
|
+
const started = Date.now();
|
|
58
|
+
try {
|
|
59
|
+
// 2048, not 256: a reasoning model spends the budget on thinking before it answers, and 256 was
|
|
60
|
+
// gone before Qwen3 emitted a single character — the test then "passed" with an empty reply.
|
|
61
|
+
const reply = await callLlm(cfg, process.env[cfg.apiKeyEnv] ?? "", prompt, { maxTokens: 2048, timeoutMs: 120_000 });
|
|
62
|
+
const secs = (Date.now() - started) / 1000;
|
|
63
|
+
if (!reply) {
|
|
64
|
+
// An empty answer is a failure. Reporting ✓ on 0 chars is how this stayed hidden.
|
|
65
|
+
console.error(`\n ✗ the endpoint answered in ${secs.toFixed(1)}s but returned no text.\n` +
|
|
66
|
+
` The server is reachable, so this is a model/response problem, not a connection one.`);
|
|
67
|
+
process.exitCode = 1;
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
console.log(` ← ${reply.replace(/\n/g, "\n ")}`);
|
|
71
|
+
console.log(`\n ✓ ${secs.toFixed(1)}s round-trip (${reply.length} chars)`);
|
|
72
|
+
// A local 20B+ model on CPU answers at single-digit tokens/s — usable for a cron job that runs
|
|
73
|
+
// nightly, not for anything a human waits on. Say so instead of letting them find out in prod.
|
|
74
|
+
if (local && secs > 30)
|
|
75
|
+
console.log(` ⚠ that is slow — fine for nightly cron tasks, painful for interactive use.`);
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
console.error(`\n ✗ ${explainLlmError(cfg, err)}`);
|
|
79
|
+
process.exitCode = 1;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=llm-cmd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-cmd.js","sourceRoot":"","sources":["../../../src/cli/llm-cmd.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,13 +4,50 @@ import cron from "node-cron";
|
|
|
4
4
|
import { readJSON, writeJSON, readText, writeText, withLock } from "../utils/fs-safe.js";
|
|
5
5
|
import { scanProject } from "../scanner/anatomy-scanner.js";
|
|
6
6
|
import { detectWaste } from "../tracker/waste-detector.js";
|
|
7
|
-
import { resolveLlmConfig,
|
|
7
|
+
import { resolveLlmConfig, callLlmDetailed, requiresApiKey } from "./llm-provider.js";
|
|
8
|
+
/**
|
|
9
|
+
* Split text into chunks that fit a context window — at paragraph boundaries, never mid-sentence.
|
|
10
|
+
*
|
|
11
|
+
* The old code did `content.slice(-MAX)`: it kept the tail and threw the rest away. For a knowledge
|
|
12
|
+
* base that is not a size limit, it is data loss with extra steps — the model then "cleans" a quarter
|
|
13
|
+
* of the file and the other three quarters cease to exist. Splitting keeps every byte; the model just
|
|
14
|
+
* reads it in several passes.
|
|
15
|
+
*/
|
|
16
|
+
export function splitForContext(text, maxBytes) {
|
|
17
|
+
if (Buffer.byteLength(text, "utf-8") <= maxBytes)
|
|
18
|
+
return [text];
|
|
19
|
+
const chunks = [];
|
|
20
|
+
let current = "";
|
|
21
|
+
for (const para of text.split(/\n\n+/)) {
|
|
22
|
+
const candidate = current ? `${current}\n\n${para}` : para;
|
|
23
|
+
if (current && Buffer.byteLength(candidate, "utf-8") > maxBytes) {
|
|
24
|
+
chunks.push(current);
|
|
25
|
+
current = para;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
current = candidate;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (current)
|
|
32
|
+
chunks.push(current);
|
|
33
|
+
// A single paragraph bigger than the window still has to be cut somewhere — but it is the only
|
|
34
|
+
// case where anything is cut, and it is cut into pieces rather than thrown away.
|
|
35
|
+
return chunks.flatMap((c) => {
|
|
36
|
+
if (Buffer.byteLength(c, "utf-8") <= maxBytes)
|
|
37
|
+
return [c];
|
|
38
|
+
const out = [];
|
|
39
|
+
for (let i = 0; i < c.length; i += maxBytes)
|
|
40
|
+
out.push(c.slice(i, i + maxBytes));
|
|
41
|
+
return out;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
8
44
|
export class CronEngine {
|
|
9
45
|
wolfDir;
|
|
10
46
|
projectRoot;
|
|
11
47
|
logger;
|
|
12
48
|
broadcast;
|
|
13
49
|
scheduledTasks = [];
|
|
50
|
+
retryTimers = new Set();
|
|
14
51
|
failureCounts = new Map();
|
|
15
52
|
constructor(wolfDir, projectRoot, logger, broadcast) {
|
|
16
53
|
this.wolfDir = wolfDir;
|
|
@@ -41,6 +78,11 @@ export class CronEngine {
|
|
|
41
78
|
task.stop();
|
|
42
79
|
}
|
|
43
80
|
this.scheduledTasks = [];
|
|
81
|
+
// Retries are scheduled with setTimeout, not node-cron, so task.stop() above doesn't touch them.
|
|
82
|
+
// Left alone, a pending retry fires after shutdown and runs against a daemon that thinks it stopped.
|
|
83
|
+
for (const timer of this.retryTimers)
|
|
84
|
+
clearTimeout(timer);
|
|
85
|
+
this.retryTimers.clear();
|
|
44
86
|
}
|
|
45
87
|
async runTask(taskId) {
|
|
46
88
|
const manifest = this.readManifest();
|
|
@@ -68,21 +110,24 @@ export class CronEngine {
|
|
|
68
110
|
const startTime = Date.now();
|
|
69
111
|
this.logger.info(`Executing task: ${task.name}`);
|
|
70
112
|
try {
|
|
71
|
-
await this.runAction(task.action);
|
|
113
|
+
await this.runAction(task.action, task.id);
|
|
72
114
|
const duration = Date.now() - startTime;
|
|
73
|
-
// Log success
|
|
74
|
-
|
|
75
|
-
state.
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
115
|
+
// Log success. Re-read under a lock and write immediately: a concurrent task (or its long LLM
|
|
116
|
+
// await) could otherwise read the same snapshot and clobber this entry on write — lost logs.
|
|
117
|
+
withLock(path.join(this.wolfDir, "cron-state.json"), () => {
|
|
118
|
+
const state = this.readState();
|
|
119
|
+
state.execution_log.push({
|
|
120
|
+
task_id: task.id,
|
|
121
|
+
status: "success",
|
|
122
|
+
timestamp: new Date().toISOString(),
|
|
123
|
+
duration_ms: duration,
|
|
124
|
+
});
|
|
125
|
+
// Keep last 100 entries
|
|
126
|
+
if (state.execution_log.length > 100) {
|
|
127
|
+
state.execution_log = state.execution_log.slice(-100);
|
|
128
|
+
}
|
|
129
|
+
this.writeState(state);
|
|
80
130
|
});
|
|
81
|
-
// Keep last 100 entries
|
|
82
|
-
if (state.execution_log.length > 100) {
|
|
83
|
-
state.execution_log = state.execution_log.slice(-100);
|
|
84
|
-
}
|
|
85
|
-
this.writeState(state);
|
|
86
131
|
this.failureCounts.set(task.id, 0);
|
|
87
132
|
this.broadcast({
|
|
88
133
|
type: "cron_executed",
|
|
@@ -102,33 +147,38 @@ export class CronEngine {
|
|
|
102
147
|
// Retry with backoff
|
|
103
148
|
const delay = this.calculateDelay(task.retry.backoff, task.retry.base_delay_seconds, failures);
|
|
104
149
|
this.logger.info(`Retrying ${task.name} in ${delay}ms`);
|
|
105
|
-
setTimeout(() => {
|
|
150
|
+
const timer = setTimeout(() => {
|
|
151
|
+
this.retryTimers.delete(timer);
|
|
106
152
|
this.executeTask(task).catch(() => { });
|
|
107
153
|
}, delay);
|
|
154
|
+
this.retryTimers.add(timer);
|
|
108
155
|
}
|
|
109
156
|
else {
|
|
110
|
-
// Dead letter or skip
|
|
111
|
-
|
|
112
|
-
state.
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
timestamp: new Date().toISOString(),
|
|
116
|
-
duration_ms: duration,
|
|
117
|
-
error: errorMsg,
|
|
118
|
-
});
|
|
119
|
-
if (task.failsafe.dead_letter) {
|
|
120
|
-
state.dead_letter_queue.push({
|
|
157
|
+
// Dead letter or skip. Same lock as the success path — read-modify-write under it so a
|
|
158
|
+
// concurrent task cannot overwrite this failure record with its own stale snapshot.
|
|
159
|
+
withLock(path.join(this.wolfDir, "cron-state.json"), () => {
|
|
160
|
+
const state = this.readState();
|
|
161
|
+
state.execution_log.push({
|
|
121
162
|
task_id: task.id,
|
|
122
|
-
|
|
163
|
+
status: "failed",
|
|
123
164
|
timestamp: new Date().toISOString(),
|
|
124
|
-
|
|
165
|
+
duration_ms: duration,
|
|
166
|
+
error: errorMsg,
|
|
125
167
|
});
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
168
|
+
if (task.failsafe.dead_letter) {
|
|
169
|
+
state.dead_letter_queue.push({
|
|
170
|
+
task_id: task.id,
|
|
171
|
+
error: errorMsg,
|
|
172
|
+
timestamp: new Date().toISOString(),
|
|
173
|
+
attempts: failures,
|
|
174
|
+
});
|
|
175
|
+
// Keep the dead-letter queue bounded (execution_log is already capped elsewhere).
|
|
176
|
+
if (state.dead_letter_queue.length > 100) {
|
|
177
|
+
state.dead_letter_queue = state.dead_letter_queue.slice(-100);
|
|
178
|
+
}
|
|
129
179
|
}
|
|
130
|
-
|
|
131
|
-
|
|
180
|
+
this.writeState(state);
|
|
181
|
+
});
|
|
132
182
|
this.failureCounts.set(task.id, 0);
|
|
133
183
|
// Notify the dashboard that this task permanently failed (upstream #4, bug 1).
|
|
134
184
|
this.broadcast({ type: "task_error", task_id: task.id, error: errorMsg });
|
|
@@ -152,7 +202,7 @@ export class CronEngine {
|
|
|
152
202
|
return 0;
|
|
153
203
|
}
|
|
154
204
|
}
|
|
155
|
-
async runAction(action) {
|
|
205
|
+
async runAction(action, taskId = "ai_task") {
|
|
156
206
|
switch (action.type) {
|
|
157
207
|
case "scan_project":
|
|
158
208
|
scanProject(this.wolfDir, this.projectRoot);
|
|
@@ -164,7 +214,7 @@ export class CronEngine {
|
|
|
164
214
|
this.generateTokenReport();
|
|
165
215
|
break;
|
|
166
216
|
case "ai_task":
|
|
167
|
-
await this.runAiTask(action.params);
|
|
217
|
+
await this.runAiTask(action.params, taskId);
|
|
168
218
|
break;
|
|
169
219
|
default:
|
|
170
220
|
throw new Error(`Unknown action type: ${action.type}`);
|
|
@@ -234,55 +284,139 @@ export class CronEngine {
|
|
|
234
284
|
writeJSON(ledgerPath, ledger);
|
|
235
285
|
});
|
|
236
286
|
}
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
287
|
+
/**
|
|
288
|
+
* Run a model over the project's own knowledge files.
|
|
289
|
+
*
|
|
290
|
+
* Default output is `mode: "proposal"`: the model NEVER writes a canonical file. It reads, and it
|
|
291
|
+
* writes its answer to `.wolf/proposals/<task>-<stamp>.md`, which a human — or a stronger model in a
|
|
292
|
+
* session — reviews before anything is adopted. The local model does the legwork; authority over what
|
|
293
|
+
* is true stays with the reader.
|
|
294
|
+
*
|
|
295
|
+
* This is not caution for its own sake. With `mode: "overwrite"` (opt-in, still supported), this exact
|
|
296
|
+
* path was one Sunday away from replacing a 78 KB cerebrum.md with a 3.9 KB "cleaned" version — see
|
|
297
|
+
* writeCerebrumFromAi.
|
|
298
|
+
*
|
|
299
|
+
* Files larger than the model's context are SPLIT, not truncated. Cutting a knowledge base to its tail
|
|
300
|
+
* and asking for "the cleaned file" is how the 95%-loss bug happened; reading it in pieces means the
|
|
301
|
+
* model actually sees all of it, just not at once.
|
|
302
|
+
*/
|
|
303
|
+
async runAiTask(params, taskId) {
|
|
304
|
+
const mode = params.mode ?? "proposal";
|
|
305
|
+
const chunkBytes = params.chunk_bytes ?? 20 * 1024;
|
|
241
306
|
const rootPrefix = path.resolve(this.projectRoot) + path.sep;
|
|
307
|
+
const files = [];
|
|
242
308
|
for (const file of params.context_files) {
|
|
243
309
|
const filePath = path.resolve(this.projectRoot, file);
|
|
244
310
|
// Reject paths that escape the project root (e.g. "../../etc/passwd") — the file
|
|
245
311
|
// contents are fed to the model, so traversal would exfiltrate arbitrary files (#34).
|
|
246
312
|
if (filePath !== path.resolve(this.projectRoot) && !filePath.startsWith(rootPrefix)) {
|
|
247
|
-
|
|
313
|
+
files.push({ name: file, chunks: ["(rejected: outside project root)"] });
|
|
248
314
|
continue;
|
|
249
315
|
}
|
|
250
316
|
try {
|
|
251
|
-
|
|
252
|
-
if (Buffer.byteLength(content, "utf-8") > MAX_CONTEXT_BYTES) {
|
|
253
|
-
content = "...[truncated — showing most recent]\n" + content.slice(-MAX_CONTEXT_BYTES);
|
|
254
|
-
}
|
|
255
|
-
contextParts.push(`--- ${file} ---\n${content}`);
|
|
317
|
+
files.push({ name: file, chunks: splitForContext(fs.readFileSync(filePath, "utf-8"), chunkBytes) });
|
|
256
318
|
}
|
|
257
319
|
catch {
|
|
258
|
-
|
|
320
|
+
files.push({ name: file, chunks: ["(not found)"] });
|
|
259
321
|
}
|
|
260
322
|
}
|
|
261
|
-
const fullPrompt = `${params.prompt}\n\n---\nContext:\n${contextParts.join("\n\n")}`;
|
|
262
323
|
// A background daemon can't drive the interactive `claude` CLI (it delegates auth to the
|
|
263
324
|
// desktop app and fails headless). Use a direct API key instead, with a clear error if it's
|
|
264
325
|
// missing — the dashboard then shows a copy-able prompt to run inside a session (upstream #4, bug 2).
|
|
265
326
|
// The provider/model/endpoint are config-driven (openwolf.cron.llm_*), defaulting to Anthropic.
|
|
266
327
|
const llm = resolveLlmConfig(this.wolfDir);
|
|
267
|
-
const apiKey = process.env[llm.apiKeyEnv];
|
|
268
|
-
if (!apiKey) {
|
|
328
|
+
const apiKey = process.env[llm.apiKeyEnv] ?? "";
|
|
329
|
+
if (!apiKey && requiresApiKey(llm)) {
|
|
269
330
|
throw new Error(`${llm.apiKeyEnv} is not set. AI tasks require a direct API key when running as a background daemon. ` +
|
|
270
|
-
`Set it in your shell profile: export ${llm.apiKeyEnv}
|
|
331
|
+
`Set it in your shell profile: export ${llm.apiKeyEnv}=… — or point openwolf.cron.llm_base_url at a ` +
|
|
332
|
+
`local model server (LM Studio on http://localhost:1234/v1, Ollama on http://localhost:11434/v1), which needs no key.`);
|
|
271
333
|
}
|
|
272
|
-
|
|
273
|
-
const
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
334
|
+
const totalChunks = files.reduce((n, f) => n + f.chunks.length, 0);
|
|
335
|
+
const sections = [];
|
|
336
|
+
for (const f of files) {
|
|
337
|
+
for (const [i, chunk] of f.chunks.entries()) {
|
|
338
|
+
const part = f.chunks.length > 1 ? ` (part ${i + 1}/${f.chunks.length})` : "";
|
|
339
|
+
const fullPrompt = `${params.prompt}\n\n---\nContext — ${f.name}${part}:\n${chunk}`;
|
|
340
|
+
// 16k, not the 4k default: a reasoning model spends thousands of tokens thinking before the
|
|
341
|
+
// first character of its answer. Too small a budget does not fail loudly — it returns HALF a
|
|
342
|
+
// file, which still looks like a valid result to any writer downstream.
|
|
343
|
+
const { text, truncated } = await callLlmDetailed(llm, apiKey, fullPrompt, { maxTokens: 16000, timeoutMs: 600_000 });
|
|
344
|
+
if (truncated)
|
|
345
|
+
throw new Error(`The model hit max_tokens mid-answer on ${f.name}${part} — the result is an incomplete fragment, so it is discarded rather than used.`);
|
|
346
|
+
const fence = text.match(/```[\w]*\n([\s\S]*?)\n```/);
|
|
347
|
+
sections.push(`## ${f.name}${part}\n\n${(fence ? fence[1] : text).trim()}`);
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
const result = sections.map((s) => s.replace(/^## .*\n\n/, "")).join("\n\n").trim();
|
|
351
|
+
// JSON answers keep going to suggestions.json — that file is a proposal by definition, nothing
|
|
352
|
+
// canonical is at risk.
|
|
277
353
|
try {
|
|
278
354
|
const parsed = JSON.parse(result);
|
|
279
355
|
writeJSON(path.join(this.wolfDir, "suggestions.json"), { generated_at: new Date().toISOString(), ...parsed });
|
|
356
|
+
return;
|
|
280
357
|
}
|
|
281
|
-
catch {
|
|
358
|
+
catch { /* not JSON — prose, handled below */ }
|
|
359
|
+
if (mode === "overwrite") {
|
|
282
360
|
if (result.includes("## User Preferences") || result.includes("## Key Learnings") || result.includes("# Cerebrum")) {
|
|
283
|
-
|
|
361
|
+
this.writeCerebrumFromAi(result, totalChunks > files.length ? new Set(["cerebrum.md"]) : new Set());
|
|
284
362
|
}
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
this.writeProposal(taskId, llm.model, files, totalChunks, sections);
|
|
366
|
+
}
|
|
367
|
+
/** Park the model's output where it can be reviewed — never where it can overwrite something. */
|
|
368
|
+
writeProposal(taskId, model, files, totalChunks, sections) {
|
|
369
|
+
const dir = path.join(this.wolfDir, "proposals");
|
|
370
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
371
|
+
const stamp = new Date().toISOString().slice(0, 19).replace(/[:T]/g, "-");
|
|
372
|
+
const file = path.join(dir, `${taskId}-${stamp}.md`);
|
|
373
|
+
const header = [
|
|
374
|
+
`# Proposal — ${taskId}`,
|
|
375
|
+
``,
|
|
376
|
+
`> Written by \`${model}\` on ${new Date().toISOString()}. **Nothing was changed.**`,
|
|
377
|
+
`> Read this, keep what is right, and apply it by hand — or ask a session to.`,
|
|
378
|
+
`> Sources: ${files.map((f) => `\`${f.name}\`${f.chunks.length > 1 ? ` (${f.chunks.length} parts, read in full)` : ""}`).join(", ")}`,
|
|
379
|
+
totalChunks > files.length
|
|
380
|
+
? `> The file did not fit the model's context, so it was **split and read in pieces** — not truncated. Each section below covers one piece.`
|
|
381
|
+
: ``,
|
|
382
|
+
``,
|
|
383
|
+
`---`,
|
|
384
|
+
``,
|
|
385
|
+
].filter((l) => l !== undefined).join("\n");
|
|
386
|
+
fs.writeFileSync(file, header + sections.join("\n\n---\n\n") + "\n", "utf-8");
|
|
387
|
+
this.logger.info(`Proposal written: .wolf/proposals/${path.basename(file)} — review it; nothing was overwritten.`);
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* Overwrite cerebrum.md with a model's rewrite — but only when that is actually safe.
|
|
391
|
+
*
|
|
392
|
+
* This path destroyed a real project's knowledge base in a dry run: cerebrum.md was 78 KB, the
|
|
393
|
+
* context cap fed the model only the LAST 20 KB (74% missing), the prompt said "return the cleaned
|
|
394
|
+
* file content only", and the model dutifully returned a tidy 3.9 KB file. Writing it would have
|
|
395
|
+
* erased 95% of everything the project had learned — silently, at 03:00 on a Sunday, with no backup.
|
|
396
|
+
* It never fired only because ANTHROPIC_API_KEY was unset; pointing the task at a keyless local
|
|
397
|
+
* model removed that accidental safety net.
|
|
398
|
+
*
|
|
399
|
+
* Two hard rules now:
|
|
400
|
+
* 1. A file the model saw only a SLICE of is never rewritten from that slice.
|
|
401
|
+
* 2. Nothing overwrites cerebrum.md without a timestamped backup sitting next to it.
|
|
402
|
+
*/
|
|
403
|
+
writeCerebrumFromAi(result, truncatedFiles) {
|
|
404
|
+
const cerebrumPath = path.join(this.wolfDir, "cerebrum.md");
|
|
405
|
+
if (truncatedFiles.has("cerebrum.md")) {
|
|
406
|
+
throw new Error(`Refusing to overwrite cerebrum.md: it is larger than the ${20}KB context cap, so the model only saw ` +
|
|
407
|
+
`its tail. Rewriting the whole file from a fragment would delete everything above the cut. ` +
|
|
408
|
+
`Either shrink cerebrum.md (\`openwolf consolidate\`) or change this task to emit JSON suggestions ` +
|
|
409
|
+
`instead of a full-file rewrite.`);
|
|
410
|
+
}
|
|
411
|
+
try {
|
|
412
|
+
const before = fs.readFileSync(cerebrumPath, "utf-8");
|
|
413
|
+
const stamp = new Date().toISOString().slice(0, 19).replace(/[:T]/g, "-");
|
|
414
|
+
const backupDir = path.join(this.wolfDir, "backups");
|
|
415
|
+
fs.mkdirSync(backupDir, { recursive: true });
|
|
416
|
+
fs.writeFileSync(path.join(backupDir, `cerebrum-${stamp}.md`), before, "utf-8");
|
|
285
417
|
}
|
|
418
|
+
catch { /* no existing file to back up — first write is harmless */ }
|
|
419
|
+
writeText(cerebrumPath, result);
|
|
286
420
|
}
|
|
287
421
|
}
|
|
288
422
|
//# sourceMappingURL=cron-engine.js.map
|