klypix-mcp 1.45.0 → 1.45.1
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/package.json +1 -1
- package/src/brain-note.mjs +2 -1
- package/src/klypix-core.mjs +7 -2
- package/src/klypix-format.mjs +33 -1
package/package.json
CHANGED
package/src/brain-note.mjs
CHANGED
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
// Optional trailing path picks a different .klypix (default ./brain.klypix).
|
|
20
20
|
import fs from 'fs';
|
|
21
21
|
import path from 'path';
|
|
22
|
-
import { captureIntoBrain, tidyBrain, atomicWrite, noteToCaptureInput } from './klypix-format.mjs';
|
|
22
|
+
import { captureIntoBrain, tidyBrain, atomicWrite, noteToCaptureInput, formatCaptureReceipts } from './klypix-format.mjs';
|
|
23
23
|
|
|
24
24
|
const MARKERS = { '': '', '?': '?', '!': '!', '✓': '✓', '~': '~', question: '?', milestone: '!', resolve: '✓', update: '~', decision: '', done: '✓' };
|
|
25
25
|
const normMarker = (m) => MARKERS[String(m || '').toLowerCase()] ?? '';
|
|
@@ -66,6 +66,7 @@ try {
|
|
|
66
66
|
const bits = [`${s.added || 0} added`];
|
|
67
67
|
for (const k of ['resolved', 'updated', 'closed', 'superseded', 'linked']) if (s[k]) bits.push(`${s[k]} ${k}`);
|
|
68
68
|
console.error(`✓ brain-note → ${path.basename(file)} (${bits.join(' · ')})`);
|
|
69
|
+
for (const line of formatCaptureReceipts(s)) console.error(` ${line}`);
|
|
69
70
|
} catch (e) {
|
|
70
71
|
console.error(`brain-note failed (brain unchanged): ${e?.message || e}`);
|
|
71
72
|
process.exit(1);
|
package/src/klypix-core.mjs
CHANGED
|
@@ -32,7 +32,7 @@ import {
|
|
|
32
32
|
statusContextToMarkdown, findFulfillmentCandidates,
|
|
33
33
|
splitQueryTokens, scoreCardsAgainstQuery, correctionOverlaysFor,
|
|
34
34
|
isFastDecayCard, DECAY_STALE_MS, formatDecayAge,
|
|
35
|
-
readPendingShips, clearPendingShips, pendingShipCards,
|
|
35
|
+
readPendingShips, clearPendingShips, pendingShipCards, formatCaptureReceipts,
|
|
36
36
|
} from './klypix-format.mjs';
|
|
37
37
|
import { capMessages, findProjectBrain } from './agent-presence.mjs';
|
|
38
38
|
|
|
@@ -1031,7 +1031,12 @@ export async function opBrainNote({ vault, canvas, text: noteText, area, marker
|
|
|
1031
1031
|
: '';
|
|
1032
1032
|
// Name the resolved brain explicitly (basename + how) so a write never lands
|
|
1033
1033
|
// in a surprise file silently — the write-side twin of the read-op stamp.
|
|
1034
|
-
|
|
1034
|
+
// Host-neutral capture receipts (2026-08-01): Codex/Cursor/Cline capture
|
|
1035
|
+
// through THIS verb, not the Claude Stop hook — without these lines the
|
|
1036
|
+
// write-side ⏳/⚠️ nudges existed only on one host brand.
|
|
1037
|
+
const receipts = formatCaptureReceipts(s);
|
|
1038
|
+
const rc = receipts.length ? `\n${receipts.join('\n')}` : '';
|
|
1039
|
+
return { blocks: [text(`✓ brain_note → ${path.basename(file)} (via ${t.how}) · ${bits.join(' · ')}. Reopen the brain in the KLYPIX app to see it.${corr}${rc}`)] };
|
|
1035
1040
|
} catch (e) {
|
|
1036
1041
|
return err(`brain_note failed (brain unchanged): ${e.message}`);
|
|
1037
1042
|
}
|
package/src/klypix-format.mjs
CHANGED
|
@@ -4229,8 +4229,17 @@ const LIMITATION_CUE_RE = new RegExp([
|
|
|
4229
4229
|
/\bnot (?:implemented|wired|supported|available|built|shipped|published|deployed|enforced|persisted|possible|reachable|exposed|functional)\b/u.source,
|
|
4230
4230
|
/\breturns? (?:a )?(?:mock|stub|null|nothing)\b/u.source,
|
|
4231
4231
|
/\bis (?:dead|unused|missing|absent|unreachable|unwired|talk[- ]?only)\b/u.source,
|
|
4232
|
-
/\bonly (?:works|runs|streams|answers|covers|supports|reads)\b/u.source,
|
|
4232
|
+
/\bonly (?:works|runs|streams|answers|covers|supports|reads|checks|compares|matches|lowercases|normalizes)\b/u.source,
|
|
4233
4233
|
/\bstill (?:missing|absent|manual|unwired|blocked|mocked?)\b/u.source,
|
|
4234
|
+
// 2026-08-01, first real-world miss (the day after shipping): the presence-
|
|
4235
|
+
// bugs skill card asserted "compares hostPid ALONE", "only lowercases+slash-
|
|
4236
|
+
// normalizes" and "indistinguishable from success" — all state claims, none
|
|
4237
|
+
// matched a cue, so the card kept reading as settled law for a full session
|
|
4238
|
+
// after ab10688 had fixed every one of them. Cues grow ON-DEMAND from real
|
|
4239
|
+
// misses, never speculatively — each addition below names its incident.
|
|
4240
|
+
/\b(?:compares?|keys?|keyed|matches?) [\p{L}\p{N}_-]+ alone\b/u.source,
|
|
4241
|
+
/\bindistinguishable from\b/u.source,
|
|
4242
|
+
/\bsilently (?:miss(?:es|ed)?|fail(?:s|ed)?|drop(?:s|ped)?)\b/u.source,
|
|
4234
4243
|
].join('|'), 'iu');
|
|
4235
4244
|
// Imperative openers = advice, not state. Anchored to the CLAUSE start so
|
|
4236
4245
|
// "Chat has no tools" (subject-first) passes while "never set X" is refused.
|
|
@@ -4321,6 +4330,29 @@ export function findSkillObsolescenceCandidates(struct, milestones, { coverAt =
|
|
|
4321
4330
|
return capped;
|
|
4322
4331
|
}
|
|
4323
4332
|
|
|
4333
|
+
// ── Capture receipts, host-neutral (2026-08-01 parity fix) ──────────────────
|
|
4334
|
+
// The ⏳/⚠️ capture receipts used to print ONLY through the Claude Stop-hook's
|
|
4335
|
+
// stderr — a Codex / Cursor / Cline session capturing through brain_note (MCP
|
|
4336
|
+
// or CLI) got "1 added · 1 superseded" and never saw the nudge, so on those
|
|
4337
|
+
// hosts the write-side half of both detection classes was silently absent.
|
|
4338
|
+
// One formatter, consumed by opBrainNote (MCP) and brain-note (CLI), so every
|
|
4339
|
+
// host hears what the hook hears; the hook keeps its own prefix style.
|
|
4340
|
+
export function formatCaptureReceipts(stats, { maxEach = 3 } = {}) {
|
|
4341
|
+
const s = stats || {};
|
|
4342
|
+
const lines = [];
|
|
4343
|
+
for (const f of (Array.isArray(s.fulfillCandidates) ? s.fulfillCandidates : []).slice(0, maxEach)) {
|
|
4344
|
+
const rest = f.uncovered && f.uncovered.length ? ` · does NOT cover: ${f.uncovered.map(u => `"${String(u).slice(0, 50)}"`).join(', ')}` : '';
|
|
4345
|
+
const act = f.marker
|
|
4346
|
+
? `— if truly done, emit: ${f.marker}`
|
|
4347
|
+
: '— PARTIAL/short: the card stays open (verify by hand; dismiss via brain_connect relationship:"not_fulfilled")';
|
|
4348
|
+
lines.push(`⏳ likely fulfilled (${f.cov}): "${String(f.item).slice(0, 70)}"${rest} ${act}`);
|
|
4349
|
+
}
|
|
4350
|
+
for (const f of (Array.isArray(s.skillStale) ? s.skillStale : []).slice(0, maxEach)) {
|
|
4351
|
+
lines.push(`⚠️ rule may be obsolete (${f.cov}): skill "${String(f.skill).slice(0, 70)}" asserts "${String(f.clause || '').slice(0, 60)}" — this ship appears to remove it. If so, amend: ${f.marker} (retire by naming it in closes:, or dismiss via brain_connect relationship:"not_fulfilled")`);
|
|
4352
|
+
}
|
|
4353
|
+
return lines;
|
|
4354
|
+
}
|
|
4355
|
+
|
|
4324
4356
|
// Persisted-edge overlay reader for 'may obsolete' hints — the 🛠️ twin of
|
|
4325
4357
|
// fulfillmentOverlaysFor, same rules: dismissals win, a since-archived
|
|
4326
4358
|
// milestone no longer vouches, machine-written hints stay hedged forever.
|