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 +74 -5
- package/dist/cli.js +36 -3
- package/dist/postinstall.js +17 -7
- package/dist/promptRouteHostHook.js +223 -114
- package/dist/server.js +5 -3
- package/dist/tools/ledgerHandlers.js +147 -24
- package/dist/utils/skillBudget.js +7 -2
- package/dist/utils/skillDigest.js +363 -0
- package/package.json +1 -1
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
|
|
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
|
|
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—
|
|
572
|
-
lifecycle
|
|
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.
|
|
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.
|
|
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
|
|
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
|
|
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)')
|
package/dist/postinstall.js
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* npm postinstall — the
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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.
|
|
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 ->
|
|
35
|
+
"[prism] codex -> /hooks -> BOTH entries ending prism-route/on_prompt.py (UserPromptSubmit + SessionStart) -> press t\n");
|
|
26
36
|
}
|
|
27
37
|
}
|
|
28
38
|
catch {
|