klypix-mcp 1.31.0 → 1.31.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/klypix-format.mjs +31 -4
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "klypix-mcp",
|
|
3
|
-
"version": "1.31.
|
|
3
|
+
"version": "1.31.1",
|
|
4
4
|
"description": "Every project gets a brain — one open .klypix file your AI agents read, write, and argue from, over MCP. Works with Claude, Cursor, Cline, any model.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
package/src/klypix-format.mjs
CHANGED
|
@@ -2645,6 +2645,26 @@ export async function captureIntoBrain(buffer, { cards = [], resolutions = [], u
|
|
|
2645
2645
|
};
|
|
2646
2646
|
canvas.connections = Array.isArray(canvas.connections) ? canvas.connections : [];
|
|
2647
2647
|
|
|
2648
|
+
// Fallback-add near-dup guard (live incident 2026-07-23): ✓/~ markers
|
|
2649
|
+
// BYPASS the hook's seen-dedup by design (self-heal re-stamps a drifted
|
|
2650
|
+
// fact), so a marker that stops matching — e.g. a ✓ whose target was
|
|
2651
|
+
// archived by its own FIRST run — re-fires on every Stop while it sits
|
|
2652
|
+
// in the transcript tail. Its no-match FALLBACK path must therefore
|
|
2653
|
+
// never re-add: 4 duplicate 🏁 fallback cards landed from one ✓ before
|
|
2654
|
+
// this guard. Checks live cards AND this batch's queued adds.
|
|
2655
|
+
const nearDupExists = (text) => {
|
|
2656
|
+
const t = tokenSet(text);
|
|
2657
|
+
if (t.size < 3) return false;
|
|
2658
|
+
for (const c of liveTextCards()) if (overlapScore(t, tokenSet(c.text)) >= 0.9) return true;
|
|
2659
|
+
for (const c of cards) if (c && c.text && overlapScore(t, tokenSet(c.text)) >= 0.9) return true;
|
|
2660
|
+
return false;
|
|
2661
|
+
};
|
|
2662
|
+
// Engine-authored text inserted into LIVE cards (fallback 🏁 cards, ✔
|
|
2663
|
+
// partial stamps) must never carry lifecycle glyphs from the marker's
|
|
2664
|
+
// prose — a ✓ whose text MENTIONED "❓/🎯" made its fallback card
|
|
2665
|
+
// classify as an open question in every brief (glyph-in-prose trap).
|
|
2666
|
+
const stripLifecycleGlyphs = (s) => String(s || '').replace(/[❓🎯🏁🛠✅✔↩⤵️]/gu, '').replace(/\s+/g, ' ').trim();
|
|
2667
|
+
|
|
2648
2668
|
// RESOLVE (✓ markers) — best live match in the area, PLUS its near-tie
|
|
2649
2669
|
// twins: a rephrased duplicate ❓ scores within a hair of its sibling, and
|
|
2650
2670
|
// resolving only the first left the twin open forever (it kept surfacing
|
|
@@ -2685,12 +2705,13 @@ export async function captureIntoBrain(buffer, { cards = [], resolutions = [], u
|
|
|
2685
2705
|
const uncoveredItems = items.filter(it => coverageOf(it.tokens, rTok) < 0.5);
|
|
2686
2706
|
const partial = (coveredItems.length && uncoveredItems.length) || (/🏁/.test(best.text) && items.length > 0);
|
|
2687
2707
|
if (partial) {
|
|
2708
|
+
const cleanR = stripLifecycleGlyphs(r.text);
|
|
2688
2709
|
const still = uncoveredItems.length ? ` — still open: ${uncoveredItems.map(x => x.text.slice(0, 50)).join(' + ').slice(0, 160)}` : '';
|
|
2689
2710
|
await rewriteCard(best.id, j => {
|
|
2690
|
-
j.content = `${j.content}\n✔ partial ${today}: ${
|
|
2711
|
+
j.content = `${j.content}\n✔ partial ${today}: ${cleanR.slice(0, 100)}${still}`;
|
|
2691
2712
|
j.borderColor = 'rgba(16,185,129,0.45)';
|
|
2692
2713
|
});
|
|
2693
|
-
best.text += `\n✔ partial ${today}: ${
|
|
2714
|
+
best.text += `\n✔ partial ${today}: ${cleanR}`;
|
|
2694
2715
|
stats.partialResolved = (stats.partialResolved || 0) + 1;
|
|
2695
2716
|
continue;
|
|
2696
2717
|
}
|
|
@@ -2706,7 +2727,11 @@ export async function captureIntoBrain(buffer, { cards = [], resolutions = [], u
|
|
|
2706
2727
|
// __fromResolve: an unmatched-✓ fallback card must not seed the
|
|
2707
2728
|
// fulfillment cross-check (it would cover its own source item at
|
|
2708
2729
|
// cov 1.0 and self-feed a suggestion loop — review-traced).
|
|
2709
|
-
|
|
2730
|
+
// Glyph-stripped + near-dup-guarded (see helpers above).
|
|
2731
|
+
const cleanR = stripLifecycleGlyphs(r.text);
|
|
2732
|
+
if (cleanR && !nearDupExists(cleanR)) {
|
|
2733
|
+
milestonesFallback.push({ text: (r.area ? `${r.area}: ` : '') + `🏁 ${cleanR}`, area: r.area, borderColor: 'rgba(59,130,246,0.8)', __fromResolve: true });
|
|
2734
|
+
}
|
|
2710
2735
|
}
|
|
2711
2736
|
}
|
|
2712
2737
|
|
|
@@ -2757,7 +2782,9 @@ export async function captureIntoBrain(buffer, { cards = [], resolutions = [], u
|
|
|
2757
2782
|
});
|
|
2758
2783
|
best.text = isTerseConfirm ? `${best.text}\n(re-affirmed ${today}: ${u.text})` : u.text;
|
|
2759
2784
|
stats.updated++;
|
|
2760
|
-
} else {
|
|
2785
|
+
} else if (!nearDupExists(u.text)) {
|
|
2786
|
+
// ~ fallback add is guarded like ✓'s: an unmatched ~ re-harvested
|
|
2787
|
+
// from the transcript tail must not stack a copy every turn.
|
|
2761
2788
|
cards.push({ text: (u.area ? `${u.area}: ` : '') + u.text + (u.area ? `\n#${u.area.toLowerCase().replace(/[^a-z0-9]+/g, '-')}` : ''), area: u.area, createdVia: u.createdVia, ...(Array.isArray(u.evidence) && u.evidence.length ? { evidence: u.evidence } : {}) });
|
|
2762
2789
|
}
|
|
2763
2790
|
}
|