klypix-mcp 1.64.0 → 1.65.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "klypix-mcp",
3
- "version": "1.64.0",
3
+ "version": "1.65.0",
4
4
  "description": "Shared project brain and MCP coordination server for multi-agent coding.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -79,7 +79,7 @@
79
79
  "test:project-graph": "node test/project-graph.mjs",
80
80
  "bench": "node bin/klypix-mcp.mjs bench",
81
81
  "test:bench": "node test/bench.mjs",
82
- "test": "node test/publish-verdict.mjs && node test/project-graph.mjs && node test/project-map-cli.mjs && node test/mcp-auto-update.mjs && node test/mcp-supervisor.mjs && node test/runtime-inspector.mjs && node test/codex-hooks.mjs && node test/agent-presence.mjs && node test/intent-guard.mjs && node test/git-capture-install.mjs && node test/brain-history.mjs && node test/brain-graveyard.mjs && node test/finding-routing.mjs && node test/finding-routing-hook.mjs && node test/presence-relay.mjs && node test/context-gateway.mjs && node test/conformance.mjs && node test/brain-doctor.mjs && node test/version-currency.mjs && node test/ship-capture.mjs && node test/lane-message.mjs && node test/brain-quality.mjs && node test/brain-connect-orphans.mjs && node test/brief-and-recall.mjs && node test/layout-cluster.mjs && node test/brain-ask.mjs && node test/field-report-2026-07-04.mjs && node test/autoprop.mjs && node test/overlay-recency-2026-07-12.mjs && node test/brain-challenge.mjs && node test/brain-lens.mjs && node test/brain-kind.mjs && node test/rule-drafts.mjs && node test/claim-engine.mjs && node test/skill-staleness.mjs && node test/canvas-view.mjs && node test/status-completeness.mjs && node test/semantic-gate.mjs && node test/memory-runtime.mjs && node test/semantic-cache.mjs && node test/decay-status.mjs && node test/decay-hook.mjs && node test/evidence-anchors.mjs && node test/presence-visibility.mjs && node test/merge-brains.mjs && node test/concurrent-writes.mjs && node test/lock-interop.mjs && node test/a2a-smoke.mjs && node test/cli-args.mjs && node test/format-guard.mjs && node test/git-tools.mjs && node test/uninstall.mjs",
82
+ "test": "node test/publish-verdict.mjs && node test/project-graph.mjs && node test/project-map-cli.mjs && node test/mcp-auto-update.mjs && node test/mcp-supervisor.mjs && node test/runtime-inspector.mjs && node test/codex-hooks.mjs && node test/agent-presence.mjs && node test/intent-guard.mjs && node test/git-capture-install.mjs && node test/brain-history.mjs && node test/brain-graveyard.mjs && node test/archived-visibility.mjs && node test/finding-routing.mjs && node test/finding-routing-hook.mjs && node test/presence-relay.mjs && node test/context-gateway.mjs && node test/conformance.mjs && node test/brain-doctor.mjs && node test/version-currency.mjs && node test/ship-capture.mjs && node test/lane-message.mjs && node test/brain-quality.mjs && node test/brain-connect-orphans.mjs && node test/brief-and-recall.mjs && node test/layout-cluster.mjs && node test/brain-ask.mjs && node test/field-report-2026-07-04.mjs && node test/autoprop.mjs && node test/overlay-recency-2026-07-12.mjs && node test/brain-challenge.mjs && node test/brain-lens.mjs && node test/brain-kind.mjs && node test/rule-drafts.mjs && node test/claim-engine.mjs && node test/skill-staleness.mjs && node test/canvas-view.mjs && node test/status-completeness.mjs && node test/semantic-gate.mjs && node test/memory-runtime.mjs && node test/semantic-cache.mjs && node test/decay-status.mjs && node test/decay-hook.mjs && node test/evidence-anchors.mjs && node test/presence-visibility.mjs && node test/merge-brains.mjs && node test/concurrent-writes.mjs && node test/lock-interop.mjs && node test/a2a-smoke.mjs && node test/cli-args.mjs && node test/format-guard.mjs && node test/git-tools.mjs && node test/uninstall.mjs",
83
83
  "test:memory": "node test/memory-runtime.mjs",
84
84
  "test:memory:soak": "node --expose-gc test/memory-soak.mjs",
85
85
  "runtime": "node bin/klypix-runtime.mjs"
@@ -264,11 +264,17 @@ export async function opSearchCanvases({ vault, query }) {
264
264
  hit(c.text) ||
265
265
  (c.tags || []).some(t => hit('#' + t)));
266
266
  if (nameMatch || matched.length) {
267
- const head = `## ${rel} — "${struct.title}" · ${struct.counts.cards} cards, ${struct.counts.connections} connections${nameMatch && !matched.length ? ' (name/title match)' : ''}`;
267
+ // Matching stays recall-first (an archived card CAN be the right answer to
268
+ // "what did we try?"), but an archived hit is now labelled. Unlabelled, a
269
+ // superseded or retired decision read exactly like a current one.
270
+ const isArchived = (c) => /^archive$/i.test(c.area || '');
271
+ const n = struct.counts;
272
+ const head = `## ${rel} — "${struct.title}" · ${n.live ?? n.cards} live cards${n.archived ? `, ${n.archived} archived` : ''}, ${n.connections} connections${nameMatch && !matched.length ? ' (name/title match)' : ''}`;
268
273
  const body = matched.slice(0, 8).map(c => {
269
274
  const pos = (c.pos && c.pos.x != null) ? ` @(${Math.round(c.pos.x)},${Math.round(c.pos.y)})` : '';
270
275
  const tags = (c.tags && c.tags.length) ? ' ' + c.tags.map(t => '#' + t).join(' ') : '';
271
- return `- [${c.type}] "${c.title || '(card)'}" (${c.id})${pos}${tags}\n ${String(c.text || '').replace(/\s+/g, ' ').slice(0, 240)}`;
276
+ const arch = isArchived(c) ? ' ⛔ archived' : '';
277
+ return `- [${c.type}] "${c.title || '(card)'}" (${c.id})${pos}${tags}${arch}\n ${String(c.text || '').replace(/\s+/g, ' ').slice(0, 240)}`;
272
278
  }).join('\n');
273
279
  hits.push(matched.length ? `${head}\n${body}` : head);
274
280
  }
@@ -326,7 +326,20 @@ export async function parseKlypix(buffer) {
326
326
  const struct = {
327
327
  title: manifest?.title || canvas.title || 'Untitled',
328
328
  format: isV4 ? 'klypix-v4' : `legacy-v${canvas.version ?? '?'}`,
329
- counts: { cards: cards.length, connections: connections.length, assets: assetPaths.length },
329
+ // `cards` counts EVERY item in `order` — containers and archived cards
330
+ // included — and several headers print it raw, so a brain whose brief
331
+ // describes 1,574 live cards announced "1981 cards". Keeping it (readers
332
+ // depend on it) and adding the honest breakdown beside it, so a surface
333
+ // that means "how much is live here" can say so.
334
+ counts: {
335
+ cards: cards.length,
336
+ connections: connections.length,
337
+ assets: assetPaths.length,
338
+ containers: cards.filter(c => c?.type === 'container').length,
339
+ archived: cards.filter(c => c?.type !== 'container' && /^archive$/i.test(
340
+ (c?.parentId ? cardTitle(items[c.parentId]) : '') || '')).length,
341
+ get live() { return this.cards - this.containers - this.archived; },
342
+ },
330
343
  cards: cards.map(it => ({
331
344
  id: it.id, type: it.type,
332
345
  title: cardTitle(it),
@@ -5130,12 +5143,22 @@ export function lensToMarkdown(d, view = 'all') {
5130
5143
 
5131
5144
  /** Render a parsed struct to the markdown brief (shared by read-klypix + MCP). */
5132
5145
  export function structToMarkdown(struct, { assetsDir } = {}) {
5146
+ // Archived cards were rendered here IDENTICALLY to live ones — no marker, and
5147
+ // `area` was never printed at all — so read_canvas served superseded,
5148
+ // consolidated and deleted-then-archived decisions as current fact. This is
5149
+ // the surface an agent reads to learn a project, which makes it the worst
5150
+ // place for that. They stay in the output (this is a whole-canvas dump, and
5151
+ // history is legitimately part of it) but they are now labelled.
5152
+ const isArchived = (c) => /^archive$/i.test(c.area || '');
5133
5153
  const L = [];
5154
+ const n = struct.counts;
5134
5155
  L.push(`# ${struct.title}`);
5135
- L.push(`*${struct.format} · ${struct.counts.cards} cards · ${struct.counts.connections} connections · ${struct.counts.assets} assets*\n`);
5156
+ L.push(`*${struct.format} · ${n.live ?? n.cards} live cards${n.archived ? ` · ${n.archived} archived` : ''}${n.containers ? ` · ${n.containers} containers` : ''} · ${n.connections} connections · ${n.assets} assets*\n`);
5157
+ if (n.archived) L.push(`> ⛔ ${n.archived} card(s) below are marked archived — superseded, consolidated or retired. Read them as history, not as the current state.\n`);
5136
5158
  L.push(`## Cards`);
5137
5159
  for (const c of struct.cards) {
5138
- L.push(`### ${c.title || `(${c.type})`} \`${c.type}\``);
5160
+ const archived = isArchived(c);
5161
+ L.push(`### ${c.title || `(${c.type})`} \`${c.type}\`${archived ? ' ⛔ archived' : ''}${c.area && !archived ? ` _[${c.area}]_` : ''}`);
5139
5162
  if (c.text) L.push(c.type === 'text' ? String(c.text).trim() : `→ ${c.text}`);
5140
5163
  const meta = [];
5141
5164
  if (c.links?.length) meta.push(`links: ${c.links.map(t => `[[${t}]]`).join(', ')}`);