klypix-mcp 1.82.0 → 1.82.2

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.
@@ -391,7 +391,7 @@ try {
391
391
  // canvas-view-app.html is the canvas_view MCP App UI — staged raw (an HTML
392
392
  // file must never get a JS-comment banner) beside the flat server, which
393
393
  // resolves it via its ./canvas-view-app.html candidate path.
394
- for (const f of ['global-brain-hook.mjs', 'capture-gap.mjs', 'brain-semantic.mjs', 'semantic-memory.mjs', 'enrichment.mjs', 'brain-note.mjs', 'brain-git-hook.mjs', 'git-capture-install.mjs', 'brain-history.mjs', 'brain-graveyard.mjs', 'klypix-format.mjs', 'klypix-core.mjs', 'brain-write-lock.mjs', 'agent-rules.mjs', 'brain-doctor.mjs', 'agent-presence.mjs', 'mcp-presence.mjs', 'repo-state.mjs', 'result-reconcile.mjs', 'finding-routing.mjs', 'presence-relay.mjs', 'mcp-supervisor.mjs', 'mcp-auto-update.mjs', 'runtime-inspector.mjs', 'project-graph.mjs', 'bench.mjs', 'codex-brain-hook.mjs', 'codex-hooks.mjs', 'canvas-view-app.html']) {
394
+ for (const f of ['global-brain-hook.mjs', 'capture-gap.mjs', 'brain-semantic.mjs', 'semantic-memory.mjs', 'enrichment.mjs', 'brain-note.mjs', 'brain-git-hook.mjs', 'git-capture-install.mjs', 'brain-history.mjs', 'brain-graveyard.mjs', 'klypix-format.mjs', 'klypix-core.mjs', 'brain-write-lock.mjs', 'agent-rules.mjs', 'brain-doctor.mjs', 'editor-detect.mjs', 'agent-presence.mjs', 'mcp-presence.mjs', 'repo-state.mjs', 'result-reconcile.mjs', 'finding-routing.mjs', 'presence-relay.mjs', 'mcp-supervisor.mjs', 'mcp-auto-update.mjs', 'runtime-inspector.mjs', 'project-graph.mjs', 'bench.mjs', 'codex-brain-hook.mjs', 'codex-hooks.mjs', 'canvas-view-app.html']) {
395
395
  const s = path.join(SRC, f); if (exists(s)) staged.push({ dst: f, content: fs.readFileSync(s, 'utf8') });
396
396
  }
397
397
  for (const [src, dst] of [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "klypix-mcp",
3
- "version": "1.82.0",
3
+ "version": "1.82.2",
4
4
  "mcpName": "io.github.dahshanlabs/klypix-mcp",
5
5
  "description": "Active state management for multi-agent coding: a shared, versioned project brain over MCP.",
6
6
  "type": "module",
@@ -820,11 +820,14 @@ export function linkProject(projectDir, opts = {}) {
820
820
  * @returns {{ files, drift, unprojected, ok, version }}
821
821
  */
822
822
  export function auditProject(projectDir, opts = {}) {
823
- const { rules, mcp, version } = linkProject(projectDir, { ...opts, check: true });
823
+ const { rules, mcp, version, skipped } = linkProject(projectDir, { ...opts, check: true });
824
824
  const files = [...rules, ...mcp];
825
825
  const ACTIONABLE = new Set(['missing', 'stale', 'hand-edited']);
826
826
  const drift = files.filter((f) => ACTIONABLE.has(f.status));
827
- return { files, drift, ok: drift.length === 0, version };
827
+ // `skipped` (1.82.1): targets the caller's editor filter excluded — hosts this machine
828
+ // does not have. Reported so a verdict can SAY what it did not audit instead of
829
+ // silently narrowing; drift is judged only over what a present host would read.
830
+ return { files, drift, ok: drift.length === 0, version, skipped: skipped || [] };
828
831
  }
829
832
 
830
833
  export { BRAIN_INSTRUCTIONS, INSTRUCTIONS_HASH, FENCE_RE, parseFence, cmpSemver };
@@ -26,6 +26,7 @@ import path from 'path';
26
26
  import crypto from 'crypto';
27
27
  import { fileURLToPath } from 'url';
28
28
  import { auditProject, codexGlobalInstructionsInstalled, resolveVersion } from './agent-rules.mjs';
29
+ import { detectEditors } from './editor-detect.mjs';
29
30
  import { codexPresenceHookStatus } from './codex-hooks.mjs';
30
31
  import { inspectAutoUpdate } from './mcp-auto-update.mjs';
31
32
  import { renderReceiptSummary, summarizeReceipts } from './finding-routing.mjs';
@@ -528,7 +529,17 @@ export function inspect(opts = {}) {
528
529
  // Harness drift only counts toward the verdict for a real brain project; auditProject
529
530
  // against the BAKED brain version (the deployed truth) when available.
530
531
  const harnessVer = version.baked || resolveVersion();
531
- const harness = hasBrain ? auditProject(projectDir, { version: harnessVer }) : { files: [], drift: [], ok: true, version: harnessVer };
532
+ // Audit ONLY what a host on this machine would read the same detected-editor set
533
+ // `install` projects with (setup.mjs). Field finding 2026-09-01 (install-smoke on a
534
+ // clean ubuntu + macos runner): install wrote 3 files for the 2 hosts present, then
535
+ // doctor audited all 14 and reported "11 of 14 drifted — MISSING" for Cursor,
536
+ // Windsurf, Cline, Copilot, Gemini and Aider config nobody had installed, exiting 1
537
+ // on a brand-new user's very first command. Write and audit must share one filter.
538
+ // Files a teammate already committed stay audited regardless (targetJustified rule 3).
539
+ // opts.editors is a test seam: a Set/array to pin, or null to force the unfiltered audit.
540
+ const harnessEditors = opts.editors !== undefined ? opts.editors
541
+ : detectEditors({ env }).present.keys();
542
+ const harness = hasBrain ? auditProject(projectDir, { version: harnessVer, editors: harnessEditors }) : { files: [], drift: [], ok: true, version: harnessVer, skipped: [] };
532
543
 
533
544
  // npm currency (caller fetches it; we just compare to the baked truth).
534
545
  // Three honest states, not two (G4/G5/G6, 2026-08-14): `matches` collapsed
@@ -879,9 +890,11 @@ export function render(r, opts = {}) {
879
890
  if (!r.project.hasBrain) L.push(`${c.dim}· HARNESS no ./brain.klypix in ${r.project.dir} — projection n/a${c.rst}`);
880
891
  else {
881
892
  const cmark = r.layers.harness === 'ok' ? ok : warn;
882
- if (r.harness.ok) L.push(`${cmark} ${c.bold}HARNESS${c.rst} all ${r.harness.files.length} projected file(s) in sync`);
893
+ const notHere = (r.harness.skipped || []).filter((x) => /not installed/.test(x.why || '')).length;
894
+ const notHereNote = notHere ? `${c.dim} · ${notHere} host file(s) not audited — that editor is not installed here${c.rst}` : '';
895
+ if (r.harness.ok) L.push(`${cmark} ${c.bold}HARNESS${c.rst} all ${r.harness.files.length} projected file(s) in sync${notHereNote}`);
883
896
  else {
884
- L.push(`${cmark} ${c.bold}HARNESS${c.rst} ${r.harness.drift.length} of ${r.harness.files.length} drifted:`);
897
+ L.push(`${cmark} ${c.bold}HARNESS${c.rst} ${r.harness.drift.length} of ${r.harness.files.length} drifted:${notHereNote}`);
885
898
  for (const h of r.harness.drift) L.push(` · ${h.file} — ${c.yel}${h.status.toUpperCase()}${c.rst}${h.stampedVersion ? ` (stamped v${h.stampedVersion})` : ''}`);
886
899
  }
887
900
  }