prism-mcp-server 20.17.3 → 20.18.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/README.md +121 -24
- package/dist/cli.js +76 -4
- package/dist/postinstall.js +9 -2
- package/dist/promptRouteHostHook.js +362 -120
- package/dist/tools/ledgerHandlers.js +187 -26
- package/dist/tools/promptRouteHandler.js +7 -1
- package/dist/tools/scopedSkillTriggers.js +38 -2
- package/dist/utils/skillBudget.js +7 -2
- package/dist/utils/skillDigest.js +363 -0
- package/package.json +8 -6
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.
|
|
@@ -83,14 +86,18 @@ behind it are in the
|
|
|
83
86
|
Prism also ships as a plugin, which registers the MCP server and the startup
|
|
84
87
|
skill for you.
|
|
85
88
|
|
|
86
|
-
|
|
89
|
+
Both hosts install straight from this repository. There is nothing to host and
|
|
90
|
+
no server to run: the catalogue is the `.claude-plugin/marketplace.json` file
|
|
91
|
+
committed here, and your client clones it from GitHub.
|
|
92
|
+
|
|
93
|
+
**Claude Code:**
|
|
87
94
|
|
|
88
95
|
```bash
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
claude plugin marketplace add dcostenco/prism-coder
|
|
97
|
+
claude plugin install prism-coder@prism
|
|
91
98
|
```
|
|
92
99
|
|
|
93
|
-
**Codex
|
|
100
|
+
**Codex:**
|
|
94
101
|
|
|
95
102
|
```bash
|
|
96
103
|
codex plugin marketplace add dcostenco/prism-coder
|
|
@@ -138,6 +145,88 @@ or by re-enabling after each run.
|
|
|
138
145
|
<details>
|
|
139
146
|
<summary>Release history (optional)</summary>
|
|
140
147
|
|
|
148
|
+
## What's New in v20.18.1
|
|
149
|
+
|
|
150
|
+
### Task skills survive compaction and update in place
|
|
151
|
+
|
|
152
|
+
- **Prompt-routed task skills now return after compaction.** The hook restores
|
|
153
|
+
the three most recently active task skills alongside the protected-floor
|
|
154
|
+
digest, so a short follow-up such as `continue` keeps the workflow and visual
|
|
155
|
+
verification rules that governed the work before context was compacted.
|
|
156
|
+
- **A completed managed-skill sync refreshes active task rules on the next
|
|
157
|
+
prompt.** The hook compares the materialized generation on disk with its
|
|
158
|
+
per-session state, re-authorizes every restored name against the current
|
|
159
|
+
manifest, and injects the current bodies. A downgrade clears stale paid task
|
|
160
|
+
state; Prism-managed directories cannot use the user-owned local-skill
|
|
161
|
+
exception.
|
|
162
|
+
- **User-owned local skills now route with their actual body.** A local
|
|
163
|
+
`SKILL.md` remains usable while signed out, while an entitled platform body
|
|
164
|
+
takes precedence if both sources use the same name.
|
|
165
|
+
- **Codex hook context is anchored to the user's request.** Routed rules tell
|
|
166
|
+
the model to execute the preceding user request with the rules applied,
|
|
167
|
+
avoiding the trailing developer-context placement being mistaken for a new
|
|
168
|
+
task. The anchor and all restored content share the 9,800-character limit.
|
|
169
|
+
- **Hook version 5 enforces its command version.** A still-running host with a
|
|
170
|
+
trusted v4 command cannot execute the rewritten v5 script. After upgrading,
|
|
171
|
+
run `prism connect --refresh --no-models`; Codex must trust both new v5 hook
|
|
172
|
+
entries in `/hooks`. Restart the host if it has not reloaded the new hook
|
|
173
|
+
definitions. Once v5 is active, later skill-body generations refresh on the
|
|
174
|
+
next prompt without another host restart.
|
|
175
|
+
- State names are validated and bounded before they become CLI arguments, and
|
|
176
|
+
the two-call refresh paths fit inside the host's 15-second hook timeout.
|
|
177
|
+
|
|
178
|
+
## What's New in v20.18.0
|
|
179
|
+
|
|
180
|
+
### The protected floor rides the bootstrap — and survives compaction
|
|
181
|
+
|
|
182
|
+
- **`session_bootstrap` now inlines a digest of the protected floor** on
|
|
183
|
+
paid tiers at standard and deep depth: one inert line per rule, derived
|
|
184
|
+
from each skill's first paragraph (or its pinned `digest:`), plus its
|
|
185
|
+
section map, ~5.6K chars for the full floor. Small-context hosts such as
|
|
186
|
+
Codex were re-reading the sixteen SKILL.md files every session (median 8
|
|
187
|
+
re-reads / 36KB, worst 823 / 5.1MB in rollout logs) because the bootstrap
|
|
188
|
+
only *named* them. The digest is paid for on top of the context budget, so
|
|
189
|
+
the ledger/handoff share at every depth is byte-identical to before. Quick
|
|
190
|
+
depth stays names-only — the opt-out.
|
|
191
|
+
- **A second hook re-injects the digest after compaction.** `prism connect`
|
|
192
|
+
registers the prism-route script on `SessionStart` matched to `compact`
|
|
193
|
+
(Claude Code and Codex); it runs `prism floor-digest`, which applies the
|
|
194
|
+
same tier and depth decisions as the bootstrap, and adds nothing on
|
|
195
|
+
startup/resume/clear. Hosts without hooks (Gemini, Cursor) still get the
|
|
196
|
+
digest on every bootstrap. **Codex: UNVERIFIED against a live compaction.**
|
|
197
|
+
The hook is registered and the script accepts the documented payload
|
|
198
|
+
spellings, but no Codex compaction has been observed end-to-end; on a
|
|
199
|
+
payload it does not recognise it re-injects nothing rather than something
|
|
200
|
+
wrong. If the digest comes from a generation whose skill files never
|
|
201
|
+
finished syncing, the re-injected block carries the same STALE warning the
|
|
202
|
+
bootstrap shows.
|
|
203
|
+
- **Codex trust is reported honestly after a hook rewrite.** Approvals are
|
|
204
|
+
keyed by definition hash, so a rewritten `hooks.json` — this release adds
|
|
205
|
+
the SessionStart entry — voids prior trust: connect prints AWAITING TRUST
|
|
206
|
+
for both entries instead of a green ✓ for a hook Codex would silently skip,
|
|
207
|
+
and trust recorded for an older hook version is never mistaken for current.
|
|
208
|
+
- **A host config that no longer parses is left alone.** If
|
|
209
|
+
`~/.claude/settings.json` or `~/.codex/hooks.json` exists but is not valid
|
|
210
|
+
JSON, connect keeps it byte-identical, registers no hook there, and says so
|
|
211
|
+
— it no longer replaces the file with a minimal hooks-only one. The npm
|
|
212
|
+
postinstall notice says the same, instead of asking you to trust a Codex
|
|
213
|
+
hook it never registered.
|
|
214
|
+
- Fixed: a symptom-routed skill whose closing frontmatter fence is its last
|
|
215
|
+
line was inlined with its YAML (triggers included) as if it were the rule.
|
|
216
|
+
- Fixed: a digest line that crosses into a new section keeps that section's
|
|
217
|
+
heading in front of it — whatever opened the section (an H2, a mid-document
|
|
218
|
+
H1, an empty heading, a setext underline) — so "Delegate to" / "Do NOT
|
|
219
|
+
delegate" rules cannot read with the wrong polarity once joined. A skill
|
|
220
|
+
file on disk is used only when it digests: empty, cut off inside its
|
|
221
|
+
frontmatter, or frontmatter-only files fall back to the stored copy instead
|
|
222
|
+
of rendering YAML as the rule.
|
|
223
|
+
- Fixed: on Windows, a Codex hook approval is recognised even though Codex
|
|
224
|
+
stores the path with escaped backslashes.
|
|
225
|
+
- The publish gate now refuses release notes that run *ahead* of the package
|
|
226
|
+
version (CHANGELOG, README, translated READMEs) — reading the newest
|
|
227
|
+
version on the heading line, so a `v20.17.3 – v20.18.0` range counts as
|
|
228
|
+
20.18.0, and surviving a typographic apostrophe or a BOM.
|
|
229
|
+
|
|
141
230
|
## What's New in v20.17.3
|
|
142
231
|
|
|
143
232
|
- **A plugin install can no longer enable the prompt-routing hook.** The
|
|
@@ -579,8 +668,8 @@ the host's final verification responsibility are unchanged.
|
|
|
579
668
|
materializes entitled packages in the native `~/.agents/skills` directory
|
|
580
669
|
before the command exits. Codex therefore sees the current skillset on its
|
|
581
670
|
first launch instead of requiring a second restart. Prism rechecks the same
|
|
582
|
-
snapshot at MCP startup, session load, and every five minutes—
|
|
583
|
-
lifecycle
|
|
671
|
+
snapshot at MCP startup, session load, and every five minutes—skill delivery
|
|
672
|
+
never depends on a host lifecycle hook.
|
|
584
673
|
|
|
585
674
|
On the first user turn, Prism's native skill, MCP metadata, and managed host
|
|
586
675
|
instructions request one `session_bootstrap({})` call. Prism then uses the
|
|
@@ -613,7 +702,10 @@ sections from `~/CLAUDE.md`, preserves every other instruction, and installs a
|
|
|
613
702
|
small ownership-marked native block that selects `session_bootstrap({})` on the
|
|
614
703
|
first turn. User hooks, custom instruction sections, and near matches remain
|
|
615
704
|
untouched; native skills and server-side reminders preserve those Prism
|
|
616
|
-
features without host lifecycle hooks.
|
|
705
|
+
features without depending on host lifecycle hooks. On Claude Code and Codex
|
|
706
|
+
connect additionally registers the prism-route script twice: on every prompt
|
|
707
|
+
(mid-session skill routing) and on `SessionStart` matched to `compact` only
|
|
708
|
+
(post-compaction protected-floor digest). Because hosts expose no native
|
|
617
709
|
session-end callback, handoff at shutdown is instruction-driven rather than a
|
|
618
710
|
guaranteed lifecycle event.
|
|
619
711
|
|
|
@@ -1376,27 +1468,32 @@ Prism works alongside these tools — use whichever fits your workflow.
|
|
|
1376
1468
|
|
|
1377
1469
|
### Web IDE — Prism Coder
|
|
1378
1470
|
|
|
1379
|
-
|
|
1471
|
+
Open [synalux.ai/coder](https://synalux.ai/coder), sign in, connect GitHub, and import a repository you can access. Select a branch, open a file, edit, and save back to GitHub.
|
|
1380
1472
|
|
|
1381
|
-
- **Monaco editor**
|
|
1382
|
-
- **
|
|
1383
|
-
- **
|
|
1384
|
-
- **
|
|
1385
|
-
- **
|
|
1386
|
-
- **
|
|
1387
|
-
- **Node.js debugger** via Chrome DevTools Protocol
|
|
1388
|
-
- **Tasks runner** (VS Code `tasks.json` compatible), **Problems panel** (Monaco diagnostics)
|
|
1389
|
-
- **12-language i18n** — full UI localization
|
|
1473
|
+
- **Monaco editor** — multiple tabs, split view, syntax highlighting, and familiar VS Code keybindings.
|
|
1474
|
+
- **GitHub editing** — branch selection, file saves, history, and conflict protection. If a file changes remotely, a conflicting save keeps your local draft for recovery. Binary renames preserve bytes, and Unicode paths are supported.
|
|
1475
|
+
- **AI Agent Mode** — describe a task, review proposed file changes, apply selected changes, and save on an isolated agent branch. Rollback discards that branch and returns to your previous work.
|
|
1476
|
+
- **Live Share** — start a session and share its invite with repository members for synchronized edits and labeled remote cursors. First-party signaling is enabled on the hosted IDE.
|
|
1477
|
+
- **In-browser Node.js and terminal** — WebContainer runs package scripts and previews when the browser supports its runtime. The optional server PTY and Node.js debugger require a connected development server.
|
|
1478
|
+
- **Tasks and diagnostics** — a `tasks.json` runner and a Problems panel for Monaco diagnostics; localized interface strings are available in 12 languages.
|
|
1390
1479
|
|
|
1391
|
-
|
|
1392
|
-
<img src="docs/screenshots/agent-mode.png" alt="Prism Coder IDE — Agent Mode creating a component with auto-fix and type-checking" width="500" />
|
|
1393
|
-
</p>
|
|
1480
|
+
**Production session, September 8, 2026.** The following screenshots were captured from the live IDE using a private test repository. The session exercised GitHub import/save, conflict recovery, binary rename, Unicode files, Agent review/apply/save/rollback, and Live Share text and cursors in both directions.
|
|
1394
1481
|
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1482
|
+
**Review an Agent proposal before applying it.** The diff below proposes a new `add(a, b)` function. Selected changes were then applied and the exact file was saved to the agent branch; rollback was checked afterward.
|
|
1483
|
+
|
|
1484
|
+

|
|
1485
|
+
|
|
1486
|
+
**Keep your draft when a remote edit conflicts.** The status bar reports the conflict while the unsaved local edit remains in the editor. Draft recovery was also checked after reloading.
|
|
1487
|
+
|
|
1488
|
+

|
|
1489
|
+
|
|
1490
|
+
**See collaborators' edits and cursors.** The host receives the guest's edit and cursor in the first capture. The guest receives the host's return edit and cursor in the second. These captures show two Safari tabs using the same authorized account; separate-user and cross-device connections were not covered by this run.
|
|
1491
|
+
|
|
1492
|
+

|
|
1493
|
+
|
|
1494
|
+

|
|
1398
1495
|
|
|
1399
|
-
|
|
1496
|
+
**Runtime requirements.** Chrome or Edge is recommended for WebContainer package installation, tests, and previews; see [WebContainer browser support](https://developer.stackblitz.com/platform/webcontainers/browser-support). Safari editing and the workflows shown above were exercised, but npm installation still failed in this Safari session. Successful editing does not establish successful code execution. Agent test and type-check execution also depends on the runtime. Cloud AI requires the applicable plan and configured service; local Ollama requires an explicit connection.
|
|
1400
1497
|
|
|
1401
1498
|
### VS Code Extension — Synalux
|
|
1402
1499
|
|
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
|
}
|
|
@@ -525,7 +531,11 @@ program
|
|
|
525
531
|
const shaped = result.names.length > 0
|
|
526
532
|
? reshapeForInlineBudget(result, HOOK_INLINE_SAFE_CHARS, writeRouteOffload)
|
|
527
533
|
: { text: '' };
|
|
528
|
-
const payload = JSON.stringify({
|
|
534
|
+
const payload = JSON.stringify({
|
|
535
|
+
names: result.names,
|
|
536
|
+
alreadyLoaded: result.alreadyLoaded,
|
|
537
|
+
text: result.names.length > 0 ? shaped.text : '',
|
|
538
|
+
});
|
|
529
539
|
await new Promise((resolveWrite) => process.stdout.write(payload + '\n', () => resolveWrite()));
|
|
530
540
|
}
|
|
531
541
|
catch {
|
|
@@ -540,6 +550,68 @@ program
|
|
|
540
550
|
process.exit(0);
|
|
541
551
|
}
|
|
542
552
|
});
|
|
553
|
+
// Re-inject the most recently active task skills after the host discards its
|
|
554
|
+
// transcript, or immediately after a new managed manifest reaches disk. Names
|
|
555
|
+
// are re-authorized against the cached manifest before any body is returned.
|
|
556
|
+
program
|
|
557
|
+
.command('reinject-skills')
|
|
558
|
+
.description('Render previously active, still-entitled skills for the host hook.')
|
|
559
|
+
.requiredOption('--names <names>', 'Comma-separated skill names from the hook session state')
|
|
560
|
+
.option('--budget <chars>', 'Maximum inline characters', String(9_800))
|
|
561
|
+
.action(async (options) => {
|
|
562
|
+
try {
|
|
563
|
+
const names = options.names.split(',').map((name) => name.trim()).filter(Boolean);
|
|
564
|
+
const requestedBudget = Number.parseInt(options.budget ?? '', 10);
|
|
565
|
+
const { runNamedSkillRouteFromCache } = await import('./tools/ledgerHandlers.js');
|
|
566
|
+
const { reshapeForInlineBudget, HOOK_INLINE_SAFE_CHARS } = await import('./tools/promptRouteHandler.js');
|
|
567
|
+
const budget = Number.isFinite(requestedBudget)
|
|
568
|
+
? Math.max(256, Math.min(HOOK_INLINE_SAFE_CHARS, requestedBudget))
|
|
569
|
+
: HOOK_INLINE_SAFE_CHARS;
|
|
570
|
+
const result = await runNamedSkillRouteFromCache(names);
|
|
571
|
+
const shaped = result.names.length > 0
|
|
572
|
+
? reshapeForInlineBudget(result, budget, writeRouteOffload)
|
|
573
|
+
: { text: '' };
|
|
574
|
+
const payload = JSON.stringify({ ok: true, names: result.names, text: result.names.length > 0 ? shaped.text : '' });
|
|
575
|
+
await new Promise((resolveWrite) => process.stdout.write(payload + '\n', () => resolveWrite()));
|
|
576
|
+
}
|
|
577
|
+
catch {
|
|
578
|
+
await new Promise((resolveWrite) => process.stdout.write('{"ok":false,"names":[],"text":""}\n', () => resolveWrite()));
|
|
579
|
+
}
|
|
580
|
+
finally {
|
|
581
|
+
try {
|
|
582
|
+
await closeStorage();
|
|
583
|
+
}
|
|
584
|
+
catch { /* exit anyway */ }
|
|
585
|
+
process.exit(0);
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
// ── floor-digest ──────────────────────────────────────────────
|
|
589
|
+
// Called by the same hook on SessionStart with source "compact": the host
|
|
590
|
+
// just discarded the bootstrap along with the rest of the transcript, and
|
|
591
|
+
// this is the protected floor coming back in one line per rule. Same
|
|
592
|
+
// contract as route-prompt — exit 0, one JSON line, cached DB and the local
|
|
593
|
+
// skills root only. Fires once per compaction, never per prompt.
|
|
594
|
+
program
|
|
595
|
+
.command('floor-digest')
|
|
596
|
+
.description('Print the protected-floor digest as {names, text} JSON. Used by the prism-route host hook after a context compaction.')
|
|
597
|
+
.action(async () => {
|
|
598
|
+
try {
|
|
599
|
+
const { renderProtectedFloorDigestForHook } = await import('./tools/ledgerHandlers.js');
|
|
600
|
+
const result = await renderProtectedFloorDigestForHook();
|
|
601
|
+
const payload = JSON.stringify({ names: result.names, text: result.text });
|
|
602
|
+
await new Promise((resolveWrite) => process.stdout.write(payload + '\n', () => resolveWrite()));
|
|
603
|
+
}
|
|
604
|
+
catch {
|
|
605
|
+
await new Promise((resolveWrite) => process.stdout.write('{"names":[],"text":""}\n', () => resolveWrite()));
|
|
606
|
+
}
|
|
607
|
+
finally {
|
|
608
|
+
try {
|
|
609
|
+
await closeStorage();
|
|
610
|
+
}
|
|
611
|
+
catch { /* exit anyway */ }
|
|
612
|
+
process.exit(0);
|
|
613
|
+
}
|
|
614
|
+
});
|
|
543
615
|
program
|
|
544
616
|
.command('load <project>')
|
|
545
617
|
.description('Load session context for a project (same output as session_load_context MCP tool)')
|
package/dist/postinstall.js
CHANGED
|
@@ -23,9 +23,16 @@ try {
|
|
|
23
23
|
// approval impossible to miss. Approval is per hook-version, not per
|
|
24
24
|
// release: it recurs only when the hook script itself changes.
|
|
25
25
|
const codex = results.find((r) => r.host === "codex");
|
|
26
|
-
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") {
|
|
27
34
|
console.error("\n[prism] Codex hook installed but NOT yet trusted — Codex silently skips it until you approve it once:\n" +
|
|
28
|
-
"[prism] codex -> /hooks ->
|
|
35
|
+
"[prism] codex -> /hooks -> BOTH entries ending prism-route/on_prompt.py (UserPromptSubmit + SessionStart) -> press t\n");
|
|
29
36
|
}
|
|
30
37
|
}
|
|
31
38
|
catch {
|