@theronap/cortex-mcp 0.9.138 → 0.9.139
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/bin/cortex-mcp.mjs +30 -0
- package/lib/edge_extract.mjs +12 -4
- package/package.json +1 -1
package/bin/cortex-mcp.mjs
CHANGED
|
@@ -28,6 +28,36 @@ const VERSION = JSON.parse(readFileSync(join(dirname(fileURLToPath(import.meta.u
|
|
|
28
28
|
const cmd = process.argv[2]
|
|
29
29
|
const rest = process.argv.slice(3)
|
|
30
30
|
|
|
31
|
+
// ── The summarizer subprocess runs NO context hooks ──────────────────────────────────────────────
|
|
32
|
+
//
|
|
33
|
+
// Edge extraction shells out to `claude --print` with CORTEX_SUMMARIZING=1. That headless session
|
|
34
|
+
// fires the SAME hook chain as a real one, and on a wired seat that is five SessionStart commands
|
|
35
|
+
// plus hydrate on UserPromptSubmit — four of which make network calls to Agnoclast.
|
|
36
|
+
//
|
|
37
|
+
// `capture` (Stop) has guarded on this env var since the recursion fix. Nothing else did, so every
|
|
38
|
+
// summarizer call still paid for snapshot-context + status + skills + hydrate before the model saw
|
|
39
|
+
// a single token of the prompt. Two consequences, both measured live 2026-09-08:
|
|
40
|
+
//
|
|
41
|
+
// 1. LATENCY. Extraction ran 45-68s against a 45s timeout and failed as often as it succeeded.
|
|
42
|
+
// A one-off `claude --print 'say ok'` on the same credential answers in about a second.
|
|
43
|
+
// 2. POLLUTED OUTPUT. `status` prints the pending-records block to stdout, so the summarizer
|
|
44
|
+
// answered THAT before the prompt: its stdout began "You have 17 intake units in the cleanup
|
|
45
|
+
// queue ... Want me to help with either?" ahead of the JSON. The extractor asks for "ONLY
|
|
46
|
+
// minified JSON"; a hook prepending prose to the model's input is how that instruction gets
|
|
47
|
+
// overridden by the system itself.
|
|
48
|
+
//
|
|
49
|
+
// The guard is here, at the dispatcher, rather than in each subcommand: it is one rule about what a
|
|
50
|
+
// summarizer subprocess IS, and putting it in five places is how the sixth gets forgotten. Exit 0
|
|
51
|
+
// and silent — a hook that errors is noise, and there is genuinely nothing to do.
|
|
52
|
+
//
|
|
53
|
+
// ⚠ NOT guarded: `capture` (has its own, with a diagnostic), and anything a human might run by hand
|
|
54
|
+
// while this var happens to be set. Only the ambient context commands are listed.
|
|
55
|
+
const CONTEXT_HOOK_COMMANDS = new Set(['snapshot-context', 'status', 'hydrate', 'skills'])
|
|
56
|
+
if (process.env.CORTEX_SUMMARIZING && CONTEXT_HOOK_COMMANDS.has(cmd)) {
|
|
57
|
+
process.stderr.write(`cortex: ${cmd} skipped — summarizer subprocess (CORTEX_SUMMARIZING)\n`)
|
|
58
|
+
process.exit(0)
|
|
59
|
+
}
|
|
60
|
+
|
|
31
61
|
if (cmd === '--version' || cmd === '-v') {
|
|
32
62
|
process.stdout.write(`cortex-mcp ${VERSION}\n`)
|
|
33
63
|
process.exit(0)
|
package/lib/edge_extract.mjs
CHANGED
|
@@ -275,11 +275,19 @@ export function classifyEdgeFailure(r) {
|
|
|
275
275
|
// spawn itself failed — almost always ENOENT, i.e. `claude` is not on the hook's PATH. A Stop hook
|
|
276
276
|
// runs with a login shell's PATH, which is not always the interactive one.
|
|
277
277
|
if (r.error) {
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
278
|
+
if (r.error.code === 'ENOENT') {
|
|
279
|
+
return { reason: 'no-claude', detail: '`claude` is not on PATH for this hook; edge extraction cannot run here' }
|
|
280
|
+
}
|
|
281
|
+
// ⚠ A spawnSync TIMEOUT surfaces here, as error.code ETIMEDOUT — not only as a signal. Observed
|
|
282
|
+
// live 2026-09-08: `[spawn-failed] spawnSync claude ETIMEDOUT` at 47.3s against a 45s limit,
|
|
283
|
+
// which reads as "the spawn broke" when the truth is "it ran and was too slow". Checking the
|
|
284
|
+
// signal alone missed it, so both are checked; this classifier's own first outing found this.
|
|
285
|
+
if (r.error.code === 'ETIMEDOUT') {
|
|
286
|
+
return { reason: 'timeout', detail: `exceeded ${summaryTimeoutMs()}ms` }
|
|
287
|
+
}
|
|
288
|
+
return { reason: 'spawn-failed', detail: r.error.message }
|
|
281
289
|
}
|
|
282
|
-
//
|
|
290
|
+
// The other shape of the same event: spawnSync killed the child, so status is null and signal set.
|
|
283
291
|
if (r.signal) return { reason: 'timeout', detail: `killed by ${r.signal} after ${summaryTimeoutMs()}ms` }
|
|
284
292
|
|
|
285
293
|
const out = `${r.stdout ?? ''}\n${r.stderr ?? ''}`
|
package/package.json
CHANGED