prism-mcp-server 20.17.2 → 20.18.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/README.md CHANGED
@@ -42,6 +42,9 @@ A paid subscription adds cloud sync, higher model tiers, and team features throu
42
42
  offline last-good recovery.
43
43
  - **Hook-free startup** — MCP metadata and native instructions request Prism's
44
44
  startup context without requiring lifecycle hooks or a Prism-owned launcher.
45
+ Where a host offers hooks (Claude Code, Codex), `prism connect` adds two
46
+ small ones on top: mid-session prompt routing, and a post-compaction
47
+ re-injection of the protected-floor digest.
45
48
  - **Safe escalation and observability** — inference outcomes are explicit,
46
49
  reserved content remains fail-closed, and local/cloud usage is recorded for
47
50
  review.
@@ -87,14 +90,14 @@ skill for you.
87
90
 
88
91
  ```bash
89
92
  /plugin marketplace add anthropics/claude-plugins-community
90
- /plugin install synalux-prism@claude-community
93
+ /plugin install prism-coder@claude-community
91
94
  ```
92
95
 
93
96
  **Codex** — this repository is itself a plugin marketplace:
94
97
 
95
98
  ```bash
96
99
  codex plugin marketplace add dcostenco/prism-coder
97
- codex plugin add synalux-prism@prism
100
+ codex plugin add prism-coder@prism
98
101
  ```
99
102
 
100
103
  The plugin registers `prism-mcp` via `npx -y prism-mcp-server`. If you already
@@ -138,6 +141,69 @@ or by re-enabling after each run.
138
141
  <details>
139
142
  <summary>Release history (optional)</summary>
140
143
 
144
+ ## What's New in v20.18.0
145
+
146
+ ### The protected floor rides the bootstrap — and survives compaction
147
+
148
+ - **`session_bootstrap` now inlines a digest of the protected floor** on
149
+ paid tiers at standard and deep depth: one inert line per rule, derived
150
+ from each skill's first paragraph (or its pinned `digest:`), plus its
151
+ section map, ~5.6K chars for the full floor. Small-context hosts such as
152
+ Codex were re-reading the sixteen SKILL.md files every session (median 8
153
+ re-reads / 36KB, worst 823 / 5.1MB in rollout logs) because the bootstrap
154
+ only *named* them. The digest is paid for on top of the context budget, so
155
+ the ledger/handoff share at every depth is byte-identical to before. Quick
156
+ depth stays names-only — the opt-out.
157
+ - **A second hook re-injects the digest after compaction.** `prism connect`
158
+ registers the prism-route script on `SessionStart` matched to `compact`
159
+ (Claude Code and Codex); it runs `prism floor-digest`, which applies the
160
+ same tier and depth decisions as the bootstrap, and adds nothing on
161
+ startup/resume/clear. Hosts without hooks (Gemini, Cursor) still get the
162
+ digest on every bootstrap. **Codex: UNVERIFIED against a live compaction.**
163
+ The hook is registered and the script accepts the documented payload
164
+ spellings, but no Codex compaction has been observed end-to-end; on a
165
+ payload it does not recognise it re-injects nothing rather than something
166
+ wrong. If the digest comes from a generation whose skill files never
167
+ finished syncing, the re-injected block carries the same STALE warning the
168
+ bootstrap shows.
169
+ - **Codex trust is reported honestly after a hook rewrite.** Approvals are
170
+ keyed by definition hash, so a rewritten `hooks.json` — this release adds
171
+ the SessionStart entry — voids prior trust: connect prints AWAITING TRUST
172
+ for both entries instead of a green ✓ for a hook Codex would silently skip,
173
+ and trust recorded for an older hook version is never mistaken for current.
174
+ - **A host config that no longer parses is left alone.** If
175
+ `~/.claude/settings.json` or `~/.codex/hooks.json` exists but is not valid
176
+ JSON, connect keeps it byte-identical, registers no hook there, and says so
177
+ — it no longer replaces the file with a minimal hooks-only one. The npm
178
+ postinstall notice says the same, instead of asking you to trust a Codex
179
+ hook it never registered.
180
+ - Fixed: a symptom-routed skill whose closing frontmatter fence is its last
181
+ line was inlined with its YAML (triggers included) as if it were the rule.
182
+ - Fixed: a digest line that crosses into a new section keeps that section's
183
+ heading in front of it — whatever opened the section (an H2, a mid-document
184
+ H1, an empty heading, a setext underline) — so "Delegate to" / "Do NOT
185
+ delegate" rules cannot read with the wrong polarity once joined. A skill
186
+ file on disk is used only when it digests: empty, cut off inside its
187
+ frontmatter, or frontmatter-only files fall back to the stored copy instead
188
+ of rendering YAML as the rule.
189
+ - Fixed: on Windows, a Codex hook approval is recognised even though Codex
190
+ stores the path with escaped backslashes.
191
+ - The publish gate now refuses release notes that run *ahead* of the package
192
+ version (CHANGELOG, README, translated READMEs) — reading the newest
193
+ version on the heading line, so a `v20.17.3 – v20.18.0` range counts as
194
+ 20.18.0, and surviving a typographic apostrophe or a BOM.
195
+
196
+ ## What's New in v20.17.3
197
+
198
+ - **A plugin install can no longer enable the prompt-routing hook.** The
199
+ package's maintenance paths (npm postinstall, server startup) now only
200
+ refresh a hook that an explicit `prism connect` previously installed —
201
+ a prism MCP registration in host config no longer counts as consent.
202
+ First install of the hook happens through `prism connect` or not at all.
203
+ - **The Claude Code plugin launcher is fully deterministic.** It runs the
204
+ exact pinned server version with npm lifecycle scripts disabled, and
205
+ the plugin now documents its security posture in `plugins/prism/README.md`.
206
+
141
207
  ## What's New in v20.17.2
142
208
 
143
209
  - **Pasted logs can no longer falsely activate skills.** Symptom-triggered
@@ -568,8 +634,8 @@ the host's final verification responsibility are unchanged.
568
634
  materializes entitled packages in the native `~/.agents/skills` directory
569
635
  before the command exits. Codex therefore sees the current skillset on its
570
636
  first launch instead of requiring a second restart. Prism rechecks the same
571
- snapshot at MCP startup, session load, and every five minutes—without host
572
- lifecycle hooks.
637
+ snapshot at MCP startup, session load, and every five minutes—skill delivery
638
+ never depends on a host lifecycle hook.
573
639
 
574
640
  On the first user turn, Prism's native skill, MCP metadata, and managed host
575
641
  instructions request one `session_bootstrap({})` call. Prism then uses the
@@ -602,7 +668,10 @@ sections from `~/CLAUDE.md`, preserves every other instruction, and installs a
602
668
  small ownership-marked native block that selects `session_bootstrap({})` on the
603
669
  first turn. User hooks, custom instruction sections, and near matches remain
604
670
  untouched; native skills and server-side reminders preserve those Prism
605
- features without host lifecycle hooks. Because hosts expose no native
671
+ features without depending on host lifecycle hooks. On Claude Code and Codex
672
+ connect additionally registers the prism-route script twice: on every prompt
673
+ (mid-session skill routing) and on `SessionStart` matched to `compact` only
674
+ (post-compaction protected-floor digest). Because hosts expose no native
606
675
  session-end callback, handoff at shutdown is instruction-driven rather than a
607
676
  guaranteed lifecycle event.
608
677
 
package/dist/cli.js CHANGED
@@ -348,10 +348,16 @@ program
348
348
  const { ensurePromptRouteHook } = await import('./promptRouteHostHook.js');
349
349
  for (const r of ensurePromptRouteHook({ hosts: hookHosts, mode: 'explicit' })) {
350
350
  const state = r.script === 'unchanged' && r.config === 'unchanged' ? 'up to date' : 'installed';
351
- if (r.host === 'codex' && r.codexApproval === 'pending-or-unknown') {
351
+ if (r.config === 'skipped-unparseable') {
352
+ // The file was left byte-identical on purpose: replacing
353
+ // it would have wiped the operator's own settings along
354
+ // with the syntax error.
355
+ console.log(`⚠ ${r.host}: ${r.configPath} is not valid JSON — prism-route hooks NOT registered; fix the file and re-run prism connect`);
356
+ }
357
+ else if (r.host === 'codex' && r.codexApproval === 'pending-or-unknown') {
352
358
  // Codex silently skips untrusted hooks — a green "installed"
353
359
  // here would be the "configured and inert" lie.
354
- console.log(`⚠ codex: prism-route hook ${state}, AWAITING TRUST — run codex, then /hooks, and trust the entry ending prism-route/on_prompt.py`);
360
+ console.log(`⚠ codex: prism-route hook ${state}, AWAITING TRUST — run codex, then /hooks, and trust BOTH entries ending prism-route/on_prompt.py (UserPromptSubmit and SessionStart)`);
355
361
  }
356
362
  else if (r.host === 'codex' && r.codexApproval === 'state-present-unverifiable') {
357
363
  // Approvals are keyed by definition hash, whose algorithm is
@@ -362,7 +368,7 @@ program
362
368
  console.log(`− codex: prism-route hook ${state}; trust state exists but is not verifiable from here — confirm once in /hooks`);
363
369
  }
364
370
  else {
365
- console.log(`✓ ${r.host}: prism-route prompt hook ${state} (${r.scriptPath})`);
371
+ console.log(`✓ ${r.host}: prism-route hooks ${state} — prompt routing + post-compaction floor (${r.scriptPath})`);
366
372
  }
367
373
  }
368
374
  }
@@ -540,6 +546,33 @@ program
540
546
  process.exit(0);
541
547
  }
542
548
  });
549
+ // ── floor-digest ──────────────────────────────────────────────
550
+ // Called by the same hook on SessionStart with source "compact": the host
551
+ // just discarded the bootstrap along with the rest of the transcript, and
552
+ // this is the protected floor coming back in one line per rule. Same
553
+ // contract as route-prompt — exit 0, one JSON line, cached DB and the local
554
+ // skills root only. Fires once per compaction, never per prompt.
555
+ program
556
+ .command('floor-digest')
557
+ .description('Print the protected-floor digest as {names, text} JSON. Used by the prism-route host hook after a context compaction.')
558
+ .action(async () => {
559
+ try {
560
+ const { renderProtectedFloorDigestForHook } = await import('./tools/ledgerHandlers.js');
561
+ const result = await renderProtectedFloorDigestForHook();
562
+ const payload = JSON.stringify({ names: result.names, text: result.text });
563
+ await new Promise((resolveWrite) => process.stdout.write(payload + '\n', () => resolveWrite()));
564
+ }
565
+ catch {
566
+ await new Promise((resolveWrite) => process.stdout.write('{"names":[],"text":""}\n', () => resolveWrite()));
567
+ }
568
+ finally {
569
+ try {
570
+ await closeStorage();
571
+ }
572
+ catch { /* exit anyway */ }
573
+ process.exit(0);
574
+ }
575
+ });
543
576
  program
544
577
  .command('load <project>')
545
578
  .description('Load session context for a project (same output as session_load_context MCP tool)')
@@ -1,9 +1,12 @@
1
1
  /**
2
- * npm postinstall — the upgrade path for the prism-route hook.
3
- *
4
- * `prism connect` is only typed once per machine, so an upgrade that adds or
5
- * fixes the hook would otherwise reach no one until they reconnect. Silent
6
- * and always-exit-0: a hook installer must never break `npm install`.
2
+ * npm postinstall — the UPGRADE path for the prism-route hook, never the
3
+ * install path. `prism connect` is typed once per machine and is the only
4
+ * consent that first-installs the hook; this script merely refreshes hosts
5
+ * that carry the managed marker from that explicit install (mode "auto" is
6
+ * marker-gated in ensurePromptRouteHook). On any machine without the marker
7
+ * — including every Claude Code plugin install, where npx runs this
8
+ * package's lifecycle scripts — it is a no-op that writes nothing. Silent
9
+ * and always-exit-0: a lifecycle script must never break `npm install`.
7
10
  */
8
11
  import { ensurePromptRouteHook } from "./promptRouteHostHook.js";
9
12
  try {
@@ -20,9 +23,16 @@ try {
20
23
  // approval impossible to miss. Approval is per hook-version, not per
21
24
  // release: it recurs only when the hook script itself changes.
22
25
  const codex = results.find((r) => r.host === "codex");
23
- if (codex && codex.codexApproval === "pending-or-unknown") {
26
+ if (codex && codex.config === "skipped-unparseable") {
27
+ // Nothing was registered, so there is nothing to trust: telling the
28
+ // operator to press t in /hooks would send them looking for an entry
29
+ // that does not exist. The file was left byte-identical on purpose.
30
+ console.error(`\n[prism] Codex ${codex.configPath} is not valid JSON — prism-route hooks NOT registered.\n` +
31
+ "[prism] Fix the file, then run: prism connect --host codex\n");
32
+ }
33
+ else if (codex && codex.codexApproval === "pending-or-unknown") {
24
34
  console.error("\n[prism] Codex hook installed but NOT yet trusted — Codex silently skips it until you approve it once:\n" +
25
- "[prism] codex -> /hooks -> entry ending prism-route/on_prompt.py -> press t\n");
35
+ "[prism] codex -> /hooks -> BOTH entries ending prism-route/on_prompt.py (UserPromptSubmit + SessionStart) -> press t\n");
26
36
  }
27
37
  }
28
38
  catch {