@prism-d1/cli 1.9.0 → 1.10.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.
Files changed (64) hide show
  1. package/README.md +48 -0
  2. package/dist/assets/github-workflows/prism-eval-gate-kiro.yml +133 -42
  3. package/dist/assets/gitlab-workflows/prism-eval-gate.yml +100 -35
  4. package/dist/assets/kirocrew-app/README.md +12 -9
  5. package/dist/assets/kirocrew-app/app.json +3 -1
  6. package/dist/assets/kirocrew-app/assets/screenshots/page-dark.png +0 -0
  7. package/dist/assets/kirocrew-app/assets/screenshots/page-light.png +0 -0
  8. package/dist/assets/kirocrew-app/assets/screenshots/report-dark.png +0 -0
  9. package/dist/assets/kirocrew-app/assets/screenshots/report-light.png +0 -0
  10. package/dist/bin/cli.d.ts +2 -0
  11. package/dist/bin/cli.d.ts.map +1 -0
  12. package/dist/bin/cli.js +19 -0
  13. package/dist/bin/cli.js.map +1 -0
  14. package/dist/bin/prism-cli.js +12 -17
  15. package/dist/bin/prism-cli.js.map +1 -1
  16. package/dist/src/commands/_top/dashboard.d.ts +2 -0
  17. package/dist/src/commands/_top/dashboard.d.ts.map +1 -1
  18. package/dist/src/commands/_top/dashboard.js +43 -15
  19. package/dist/src/commands/_top/dashboard.js.map +1 -1
  20. package/dist/src/commands/_top/mcp.d.ts.map +1 -1
  21. package/dist/src/commands/_top/mcp.js +3 -15
  22. package/dist/src/commands/_top/mcp.js.map +1 -1
  23. package/dist/src/commands/_top/statusline.d.ts +13 -0
  24. package/dist/src/commands/_top/statusline.d.ts.map +1 -0
  25. package/dist/src/commands/_top/statusline.js +12 -0
  26. package/dist/src/commands/_top/statusline.js.map +1 -0
  27. package/dist/src/commands/_top/version.d.ts +2 -0
  28. package/dist/src/commands/_top/version.d.ts.map +1 -1
  29. package/dist/src/commands/_top/version.js +4 -0
  30. package/dist/src/commands/_top/version.js.map +1 -1
  31. package/dist/src/commands/assessment/deploy-cdk.js +1 -1
  32. package/dist/src/commands/assessment/deploy-cdk.js.map +1 -1
  33. package/dist/src/commands/enable/claude-code.d.ts +81 -0
  34. package/dist/src/commands/enable/claude-code.d.ts.map +1 -0
  35. package/dist/src/commands/enable/claude-code.js +381 -0
  36. package/dist/src/commands/enable/claude-code.js.map +1 -0
  37. package/dist/src/dashboard/page.d.ts +25 -0
  38. package/dist/src/dashboard/page.d.ts.map +1 -1
  39. package/dist/src/dashboard/page.js +66 -7
  40. package/dist/src/dashboard/page.js.map +1 -1
  41. package/dist/src/dashboard/setup-page.d.ts +1 -1
  42. package/dist/src/dashboard/setup-page.d.ts.map +1 -1
  43. package/dist/src/dashboard/setup-page.js +15 -2
  44. package/dist/src/dashboard/setup-page.js.map +1 -1
  45. package/dist/src/dashboard/snapshot.d.ts +31 -0
  46. package/dist/src/dashboard/snapshot.d.ts.map +1 -0
  47. package/dist/src/dashboard/snapshot.js +65 -0
  48. package/dist/src/dashboard/snapshot.js.map +1 -0
  49. package/dist/src/mcp/dashboard-process.d.ts +83 -0
  50. package/dist/src/mcp/dashboard-process.d.ts.map +1 -0
  51. package/dist/src/mcp/dashboard-process.js +184 -0
  52. package/dist/src/mcp/dashboard-process.js.map +1 -0
  53. package/dist/src/mcp/server.d.ts.map +1 -1
  54. package/dist/src/mcp/server.js +8 -3
  55. package/dist/src/mcp/server.js.map +1 -1
  56. package/dist/src/mcp/tools.d.ts +7 -1
  57. package/dist/src/mcp/tools.d.ts.map +1 -1
  58. package/dist/src/mcp/tools.js +100 -2
  59. package/dist/src/mcp/tools.js.map +1 -1
  60. package/dist/src/statusline/statusline.d.ts +135 -0
  61. package/dist/src/statusline/statusline.d.ts.map +1 -0
  62. package/dist/src/statusline/statusline.js +398 -0
  63. package/dist/src/statusline/statusline.js.map +1 -0
  64. package/package.json +3 -1
@@ -0,0 +1,381 @@
1
+ /**
2
+ * `prism-cli enable claude-code`: set Claude Code's status line to
3
+ * `prism-cli statusline`.
4
+ *
5
+ * A Claude Code plugin cannot set `statusLine` (plugin settings only apply
6
+ * `agent` and `subagentStatusLine`), so this is the one place that writes the
7
+ * user's Claude Code settings: `$CLAUDE_CONFIG_DIR/settings.json`, else
8
+ * `~/.claude/settings.json`, the same file Claude Code reads.
9
+ *
10
+ * Before a write it prints the plan and a diff, asks (or takes --yes), and
11
+ * copies the file to `settings.json.bak-<timestamp>`. Only the `statusLine`
12
+ * key changes; every other key is kept in order and the file is rewritten
13
+ * as 2-space JSON. A status line that is not PRISM's is shown and left alone
14
+ * unless --replace. --uninstall removes PRISM's status line and puts back the
15
+ * one it replaced, read from the newest backup that holds one.
16
+ *
17
+ * It never installs the plugin; it prints the /plugin commands.
18
+ */
19
+ import { createInterface } from 'node:readline';
20
+ import { chmodSync, copyFileSync, existsSync, mkdirSync, readdirSync, readFileSync, realpathSync, renameSync, statSync, writeFileSync } from 'node:fs';
21
+ import { homedir } from 'node:os';
22
+ import { delimiter, dirname, join, resolve } from 'node:path';
23
+ import { fileURLToPath } from 'node:url';
24
+ import { findPackageDir, installsOnPath } from '../_top/version.js';
25
+ import { findOnPath } from '../../utils/tool-check.js';
26
+ import { runGuarded } from './security.js';
27
+ export const PLUGIN_ID = 'prism@prism-d1-velocity';
28
+ export const PLUGIN_HINT = [
29
+ '/plugin marketplace add aws-samples/sample-prism-d1-velocity',
30
+ '/plugin install prism@prism-d1-velocity',
31
+ ];
32
+ export const REFRESH_INTERVAL_S = 60;
33
+ export const BACKUP_PREFIX = 'settings.json.bak-';
34
+ /** The PATH a process started outside a login shell usually has (a desktop launcher, an IDE). */
35
+ export const NON_INTERACTIVE_PATH = ['/usr/local/bin', '/opt/homebrew/bin', '/usr/bin', '/bin'].join(delimiter);
36
+ /** Where Claude Code keeps its user settings: CLAUDE_CONFIG_DIR, else ~/.claude. */
37
+ export function configDir(env, home) {
38
+ return env.CLAUDE_CONFIG_DIR ? resolve(env.CLAUDE_CONFIG_DIR) : join(home, '.claude');
39
+ }
40
+ /** Claude Code's global state file (MCP servers in user scope): `<CLAUDE_CONFIG_DIR>/.claude.json`, else `~/.claude.json`. */
41
+ export function globalConfigFile(env, home) {
42
+ return env.CLAUDE_CONFIG_DIR ? join(resolve(env.CLAUDE_CONFIG_DIR), '.claude.json') : join(home, '.claude.json');
43
+ }
44
+ /** True for a status line this command wrote (any prism-cli path, any flags). */
45
+ export function isPrismStatusLine(s) {
46
+ const c = s && typeof s === 'object' ? s.command : undefined;
47
+ return typeof c === 'string' && /prism-cli(\.js)?['"]?\s+statusline\b/.test(c);
48
+ }
49
+ export function desiredStatusLine(command) {
50
+ return { type: 'command', command, refreshInterval: REFRESH_INTERVAL_S };
51
+ }
52
+ /** Single-quotes a path for the shell Claude Code runs the command with, when it needs it. */
53
+ export function shQuote(p) {
54
+ return /^[A-Za-z0-9_./:@%+=-]+$/.test(p) ? p : `'${p.replace(/'/g, `'\\''`)}'`;
55
+ }
56
+ /**
57
+ * `prism-cli statusline` when this prism-cli, and node, are on the PATH a
58
+ * non-interactive process has; else the absolute node and entry script, so an
59
+ * nvm or Volta install still works when Claude Code starts without the shell's PATH.
60
+ */
61
+ export function statuslineCommand(o) {
62
+ const sys = o.systemPath ?? NON_INTERACTIVE_PATH;
63
+ const first = installsOnPath(sys, o.ownPackageDir)[0];
64
+ if (first?.isThis && findOnPath('node', sys))
65
+ return 'prism-cli statusline';
66
+ return `${shQuote(o.execPath)} ${shQuote(o.entry)} statusline`;
67
+ }
68
+ function readSettings(path) {
69
+ if (!existsSync(path))
70
+ return { path, exists: false, text: '', json: {} };
71
+ const text = readFileSync(path, 'utf8');
72
+ let json;
73
+ try {
74
+ json = text.trim() ? JSON.parse(text) : {};
75
+ }
76
+ catch (e) {
77
+ throw new UserError(`${path} is not valid JSON (${String(e?.message || e).split('\n')[0]}); fix it first. Nothing was changed.`);
78
+ }
79
+ if (!json || typeof json !== 'object' || Array.isArray(json))
80
+ throw new UserError(`${path} does not hold a JSON object. Nothing was changed.`);
81
+ return { path, exists: true, text, json: json };
82
+ }
83
+ class UserError extends Error {
84
+ }
85
+ /** `obj` with statusLine set (kept in place when present, else appended) or removed. */
86
+ export function withStatusLine(obj, s) {
87
+ const out = {};
88
+ let placed = false;
89
+ for (const [k, v] of Object.entries(obj)) {
90
+ if (k === 'statusLine') {
91
+ if (s)
92
+ out[k] = s;
93
+ placed = true;
94
+ continue;
95
+ }
96
+ out[k] = v;
97
+ }
98
+ if (s && !placed)
99
+ out.statusLine = s;
100
+ return out;
101
+ }
102
+ export const render = (obj) => JSON.stringify(obj, null, 2) + '\n';
103
+ /** A unified-style line diff (LCS); settings files are small. */
104
+ export function lineDiff(a, b, label) {
105
+ const x = a ? a.replace(/\n$/, '').split('\n') : [];
106
+ const y = b.replace(/\n$/, '').split('\n');
107
+ const n = x.length, m = y.length;
108
+ const L = Array.from({ length: n + 1 }, () => new Array(m + 1).fill(0));
109
+ for (let i = n - 1; i >= 0; i--)
110
+ for (let j = m - 1; j >= 0; j--)
111
+ L[i][j] = x[i] === y[j] ? L[i + 1][j + 1] + 1 : Math.max(L[i + 1][j], L[i][j + 1]);
112
+ const out = [`--- ${label}`, `+++ ${label}`];
113
+ let i = 0, j = 0;
114
+ while (i < n || j < m) {
115
+ if (i < n && j < m && x[i] === y[j]) {
116
+ out.push(` ${x[i]}`);
117
+ i++;
118
+ j++;
119
+ }
120
+ else if (i < n && (j === m || L[i + 1][j] >= L[i][j + 1]))
121
+ out.push(`- ${x[i++]}`);
122
+ else
123
+ out.push(`+ ${y[j++]}`);
124
+ }
125
+ return out;
126
+ }
127
+ const stamp = (d) => d.toISOString().replace(/[-:]/g, '').replace(/\.\d+Z$/, 'Z');
128
+ /** Copies settings.json to settings.json.bak-<timestamp> (mode 0600); returns its path. */
129
+ function backup(path, now) {
130
+ let b = join(dirname(path), `${BACKUP_PREFIX}${stamp(now)}`);
131
+ for (let n = 1; existsSync(b); n++)
132
+ b = join(dirname(path), `${BACKUP_PREFIX}${stamp(now)}-${n}`);
133
+ copyFileSync(path, b);
134
+ chmodSync(b, 0o600);
135
+ return b;
136
+ }
137
+ /**
138
+ * Writes beside the file and renames it into place, keeping the file's mode
139
+ * (0600 for a new file). A symlinked settings.json (a dotfiles repo) is
140
+ * written at its target, so the link stays a link.
141
+ */
142
+ function writeAtomic(link, text) {
143
+ let path = link;
144
+ try {
145
+ path = realpathSync(link);
146
+ }
147
+ catch { /* new file */ }
148
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
149
+ const mode = existsSync(path) ? statSync(path).mode & 0o777 : 0o600;
150
+ const tmp = `${path}.tmp-${process.pid}`;
151
+ writeFileSync(tmp, text, { mode });
152
+ chmodSync(tmp, mode);
153
+ renameSync(tmp, path);
154
+ }
155
+ /** The statusLine PRISM replaced: walk backups newest first, skipping ones that hold PRISM's own. */
156
+ export function previousStatusLine(dir) {
157
+ let names;
158
+ try {
159
+ names = readdirSync(dir).filter((n) => n.startsWith(BACKUP_PREFIX)).sort().reverse();
160
+ }
161
+ catch {
162
+ return null;
163
+ }
164
+ for (const n of names) {
165
+ let j; // any: a backup of a JSON settings file, checked below.
166
+ try {
167
+ j = JSON.parse(readFileSync(join(dir, n), 'utf8'));
168
+ }
169
+ catch {
170
+ continue;
171
+ }
172
+ if (!j || typeof j !== 'object')
173
+ continue;
174
+ const s = j.statusLine;
175
+ if (s && isPrismStatusLine(s))
176
+ continue;
177
+ return { file: join(dir, n), statusLine: s && typeof s === 'object' ? s : null };
178
+ }
179
+ return null;
180
+ }
181
+ // ------------------------------------------------------------ plugin and MCP detection (read-only)
182
+ function readJson(path) {
183
+ try {
184
+ return JSON.parse(readFileSync(path, 'utf8'));
185
+ }
186
+ catch {
187
+ return null;
188
+ }
189
+ }
190
+ /** From `<config>/plugins/installed_plugins.json` and `enabledPlugins` in settings.json. */
191
+ export function pluginState(dir, settings) {
192
+ const j = readJson(join(dir, 'plugins', 'installed_plugins.json'));
193
+ const entries = j?.plugins?.[PLUGIN_ID];
194
+ const list = Array.isArray(entries) ? entries : [];
195
+ const enabledMap = settings.enabledPlugins;
196
+ const enabled = enabledMap && typeof enabledMap === 'object' && PLUGIN_ID in enabledMap ? enabledMap[PLUGIN_ID] === true : null;
197
+ return { installed: list.length > 0, enabled, version: typeof list[0]?.version === 'string' ? list[0].version : null };
198
+ }
199
+ const runsPrismMcp = (s) => s && typeof s === 'object' && /prism-cli/.test(String(s.command ?? '')) && [s.command, ...(Array.isArray(s.args) ? s.args : [])].join(' ').includes('mcp');
200
+ /** Where a `prism-cli mcp` server is configured: user scope in the global config, this repo's .mcp.json. */
201
+ export function mcpServers(globalFile, cwd) {
202
+ const out = [];
203
+ const g = readJson(globalFile);
204
+ for (const [name, s] of Object.entries(g?.mcpServers ?? {}))
205
+ if (runsPrismMcp(s))
206
+ out.push(`user scope: ${name}`);
207
+ const p = readJson(join(cwd, '.mcp.json'));
208
+ for (const [name, s] of Object.entries(p?.mcpServers ?? {}))
209
+ if (runsPrismMcp(s))
210
+ out.push(`project .mcp.json: ${name}`);
211
+ return out;
212
+ }
213
+ // ------------------------------------------------------------ main
214
+ const yes = (a) => ['y', 'yes'].includes(a.trim().toLowerCase());
215
+ async function confirm(question, opts, d) {
216
+ if (opts.yes)
217
+ return true;
218
+ if (!d.isTTY) {
219
+ d.error('Error: no terminal to confirm. Re-run with --yes, or --dry-run to see the plan.');
220
+ return false;
221
+ }
222
+ if (yes(await d.ask(question)))
223
+ return true;
224
+ d.error('Nothing changed.');
225
+ return false;
226
+ }
227
+ function tilde(p, home) {
228
+ return p === home || p.startsWith(home + '/') ? '~' + p.slice(home.length) : p;
229
+ }
230
+ function pluginHint(state, d) {
231
+ if (state.installed && state.enabled !== false)
232
+ return;
233
+ d.log(state.installed ? '\n The PRISM plugin is installed but disabled: /plugin enable prism@prism-d1-velocity' : '\n The PRISM plugin (slash commands, MCP tools, a findings summary at session start) is not installed. In Claude Code:');
234
+ if (!state.installed)
235
+ for (const l of PLUGIN_HINT)
236
+ d.log(` ${l}`);
237
+ }
238
+ function showStatus(s, dir, d) {
239
+ const sl = s.json.statusLine;
240
+ const plugin = pluginState(dir, s.json);
241
+ const mcp = mcpServers(globalConfigFile(d.env, d.home), d.cwd);
242
+ d.log('\n📊 Claude Code status\n');
243
+ d.log(` Settings: ${tilde(s.path, d.home)}${s.exists ? '' : ' (does not exist yet)'}${d.env.CLAUDE_CONFIG_DIR ? ' (CLAUDE_CONFIG_DIR)' : ''}`);
244
+ d.log(` Status line: ${!sl ? 'not set' : isPrismStatusLine(sl) ? `PRISM: ${String(sl.command)}` : `another one: ${JSON.stringify(sl)}`}`);
245
+ if (sl && isPrismStatusLine(sl) && sl.command !== d.command)
246
+ d.log(` (this prism-cli would write: ${d.command})`);
247
+ d.log(` Plugin: ${plugin.installed ? `${PLUGIN_ID}${plugin.version ? ` ${plugin.version}` : ''}${plugin.enabled === false ? ' (disabled)' : ''}` : 'not installed'}`);
248
+ d.log(` MCP server: ${plugin.installed ? 'from the plugin (plugin:prism:prism)' : ''}${mcp.length ? `${plugin.installed ? '; also ' : ''}${mcp.join(', ')}` : plugin.installed ? '' : 'not configured'}`);
249
+ if (plugin.installed && mcp.length)
250
+ d.log(' The plugin already runs prism-cli mcp; remove the other entry (claude mcp remove <name>) so tools are not listed twice.');
251
+ pluginHint(plugin, d);
252
+ if (!sl || !isPrismStatusLine(sl))
253
+ d.log('\n → prism-cli enable claude-code');
254
+ d.log('');
255
+ return 0;
256
+ }
257
+ async function apply(s, next, title, opts, d) {
258
+ const text = render(next);
259
+ d.log('');
260
+ for (const l of lineDiff(s.text, text, tilde(s.path, d.home)))
261
+ d.log(` ${l}`);
262
+ d.log(`\n ${s.exists ? `A copy of the current file is saved first as ${BACKUP_PREFIX}<timestamp>.` : 'The file is created (mode 0600).'} Other keys are kept; the file is rewritten as 2-space JSON.`);
263
+ if (opts.dryRun) {
264
+ d.log('\n Dry run: nothing was written. Re-run without --dry-run to apply.\n');
265
+ return false;
266
+ }
267
+ if (!await confirm(`\n ${title}? [y/N] `, opts, d))
268
+ return false;
269
+ if (s.exists)
270
+ d.log(` ✓ Backup: ${tilde(backup(s.path, d.now()), d.home)}`);
271
+ writeAtomic(s.path, text);
272
+ d.log(` ✓ Wrote ${tilde(s.path, d.home)}`);
273
+ return true;
274
+ }
275
+ async function uninstall(s, dir, opts, d) {
276
+ const sl = s.json.statusLine;
277
+ d.log(opts.dryRun ? '\n🔌 enable claude-code --uninstall: dry run, nothing is changed\n' : '\n🔌 enable claude-code --uninstall\n');
278
+ if (!sl) {
279
+ d.log(' No status line is set. Nothing to remove.\n');
280
+ return 0;
281
+ }
282
+ if (!isPrismStatusLine(sl)) {
283
+ d.log(` The status line is not PRISM's, so it is left alone: ${JSON.stringify(sl)}\n`);
284
+ return 0;
285
+ }
286
+ const prev = previousStatusLine(dir);
287
+ const restore = prev?.statusLine ?? null;
288
+ d.log(restore ? ` Plan: put back the status line PRISM replaced (from ${tilde(prev.file, d.home)}): ${JSON.stringify(restore)}` : ' Plan: remove PRISM\'s status line (there was none before it).');
289
+ if (!await apply(s, withStatusLine(s.json, restore), restore ? 'Restore it' : 'Remove it', opts, d))
290
+ return opts.dryRun ? 0 : 1;
291
+ d.log(' Claude Code picks the change up on its next status line update.\n');
292
+ return 0;
293
+ }
294
+ export async function enableClaudeCode(opts, d) {
295
+ if (opts.replace && (opts.uninstall || opts.status)) {
296
+ d.error('Error: --replace only applies when installing.');
297
+ return 1;
298
+ }
299
+ const dir = configDir(d.env, d.home);
300
+ let s;
301
+ try {
302
+ s = readSettings(join(dir, 'settings.json'));
303
+ }
304
+ catch (e) {
305
+ if (e instanceof UserError) {
306
+ d.error(`Error: ${e.message}`);
307
+ return 1;
308
+ }
309
+ throw e;
310
+ }
311
+ if (opts.status)
312
+ return showStatus(s, dir, d);
313
+ if (opts.uninstall)
314
+ return uninstall(s, dir, opts, d);
315
+ const want = desiredStatusLine(d.command);
316
+ const cur = s.json.statusLine;
317
+ d.log(opts.dryRun ? '\n🔌 enable claude-code: dry run, nothing is changed\n' : '\n🔌 enable claude-code\n');
318
+ d.log(` Settings: ${tilde(s.path, d.home)}${s.exists ? '' : ' (new file)'}`);
319
+ d.log(` Command: ${d.command}${d.command === 'prism-cli statusline' ? '' : '\n (absolute paths: prism-cli is not on the PATH Claude Code may start with, e.g. an nvm or Volta install)'}`);
320
+ const plugin = pluginState(dir, s.json);
321
+ if (cur && JSON.stringify(cur) === JSON.stringify(want)) {
322
+ d.log(' Plan: already set; nothing to do.');
323
+ pluginHint(plugin, d);
324
+ d.log('');
325
+ return 0;
326
+ }
327
+ if (cur && !isPrismStatusLine(cur)) {
328
+ d.log(` Existing status line (not PRISM's): ${JSON.stringify(cur)}`);
329
+ if (!opts.replace) {
330
+ d.error(' Refusing to replace it. Re-run with --replace (it is kept in the backup, and --uninstall puts it back).');
331
+ return 1;
332
+ }
333
+ d.log(' Plan: replace it with PRISM\'s (--replace); --uninstall puts it back.');
334
+ }
335
+ else {
336
+ d.log(` Plan: ${cur ? 'update PRISM\'s status line' : 'add a statusLine entry'}: ${JSON.stringify(want)}`);
337
+ }
338
+ if (!await apply(s, withStatusLine(s.json, want), 'Write it', opts, d))
339
+ return opts.dryRun ? 0 : 1;
340
+ d.log('\n Claude Code shows it on its next status line update (a new session, or after the next message).');
341
+ d.log(' Check: prism-cli enable claude-code --status');
342
+ d.log(' Remove: prism-cli enable claude-code --uninstall');
343
+ pluginHint(plugin, d);
344
+ d.log('');
345
+ return 0;
346
+ }
347
+ export function defaultDeps() {
348
+ const here = dirname(fileURLToPath(import.meta.url));
349
+ const ownPackageDir = findPackageDir(here) ?? process.cwd();
350
+ let entry = process.argv[1] ? resolve(process.argv[1]) : join(ownPackageDir, 'dist', 'bin', 'prism-cli.js');
351
+ try {
352
+ entry = realpathSync(entry);
353
+ }
354
+ catch { /* keep as is */ }
355
+ return {
356
+ home: homedir(),
357
+ env: process.env,
358
+ cwd: process.cwd(),
359
+ command: statuslineCommand({ ownPackageDir, execPath: process.execPath, entry }),
360
+ isTTY: !!(process.stdin.isTTY && process.stdout.isTTY),
361
+ ask: (q) => new Promise((done) => {
362
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
363
+ rl.question(q, (a) => { rl.close(); done(a.trim()); });
364
+ }),
365
+ log: (line = '') => console.log(line),
366
+ error: (line) => console.error(line),
367
+ now: () => new Date(),
368
+ };
369
+ }
370
+ export default {
371
+ description: 'Set Claude Code\'s status line to prism-cli statusline in your Claude Code user settings (CLAUDE_CONFIG_DIR respected), after a diff, a backup and your confirmation',
372
+ options: [
373
+ { flags: '--yes', description: 'Do not ask before writing settings.json' },
374
+ { flags: '--dry-run', description: 'Print the plan and the diff; write nothing' },
375
+ { flags: '--replace', description: 'Replace a status line that is not PRISM\'s (it is kept in the backup; --uninstall puts it back)' },
376
+ { flags: '--status', description: 'Show the status line, the PRISM plugin and the prism-cli MCP server configuration (read-only)' },
377
+ { flags: '--uninstall', description: 'Remove PRISM\'s status line, putting back the one it replaced' },
378
+ ],
379
+ action: (opts) => runGuarded(() => enableClaudeCode(opts, defaultDeps())),
380
+ };
381
+ //# sourceMappingURL=claude-code.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"claude-code.js","sourceRoot":"","sources":["../../../../src/commands/enable/claude-code.ts"],"names":[],"mappings":"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"}
@@ -7,4 +7,29 @@
7
7
  * innerHTML is never used for data.
8
8
  */
9
9
  export declare function renderPage(nonce: string, csrf?: string): string;
10
+ /** What a static snapshot embeds: the /api/data payload and the /api/setup answer, as the live page would fetch them. */
11
+ export interface SnapshotData {
12
+ data: unknown;
13
+ setup: unknown;
14
+ /** ISO time the snapshot was written. */
15
+ generatedAt: string;
16
+ version: string;
17
+ }
18
+ /** JSON for a <script type="application/json"> block: `<` escaped, so the text can never close the element. */
19
+ export declare function embedJson(v: unknown): string;
20
+ /** The exact element markers renderSnapshotPage writes, so a test can read the file back without parsing HTML. */
21
+ export declare const SNAPSHOT_MARKERS: {
22
+ readonly script: "<script>";
23
+ readonly data: "<script type=\"application/json\" id=\"prism-snapshot\">";
24
+ readonly scriptEnd: "</script>";
25
+ readonly style: "<style>";
26
+ readonly styleEnd: "</style>";
27
+ };
28
+ /**
29
+ * The same page as renderPage, as one static file: the data is embedded, the
30
+ * scripts and the style are allowed by hash in a CSP meta tag with
31
+ * default-src 'none' (no fetch, no remote resource), and the Setup page's Run
32
+ * buttons become Copy buttons. No token, no server.
33
+ */
34
+ export declare function renderSnapshotPage(s: SnapshotData): string;
10
35
  //# sourceMappingURL=page.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../src/dashboard/page.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAqqBH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,MAAM,CAgB3D"}
1
+ {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../src/dashboard/page.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAurBH,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,SAAK,GAAG,MAAM,CAgB3D;AAED,yHAAyH;AACzH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,EAAE,MAAM,CAAC;CACjB;AAID,+GAA+G;AAC/G,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,CAE5C;AAED,kHAAkH;AAClH,eAAO,MAAM,gBAAgB;;;;;;CAMnB,CAAC;AAIX;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,YAAY,GAAG,MAAM,CAoB1D"}
@@ -6,6 +6,7 @@
6
6
  * Every value from the payload is placed with textContent or a DOM attribute;
7
7
  * innerHTML is never used for data.
8
8
  */
9
+ import { createHash } from 'node:crypto';
9
10
  import { SETUP_SCRIPT, SETUP_STYLE, THEME_BOOT, THEME_SCRIPT } from './setup-page.js';
10
11
  /** Colour tokens; the dark set applies by system preference unless the toggle picks Light, and always with Dark. */
11
12
  const LIGHT_VARS = '--bg:#f7f7f8; --card:#fff; --text:#1d1d1f; --muted:#6b6b73; --line:#e3e3e8; --ok:#1a7f37; --warn:#9a6700; --bad:#cf222e; --high:#cf222e; --medium:#bf8700; --low:#3d6fa8; --accent:#0969da; --raised:var(--bg);';
@@ -48,6 +49,7 @@ a.rlink { color:var(--accent); } a.rlink:hover { text-decoration:underline; }
48
49
  .help { font-size:12px; margin-top:4px; overflow-wrap:anywhere; } .help-links { margin-top:2px; } .help-steps { margin:4px 0; padding-left:18px; } .help code { white-space:normal; overflow-wrap:anywhere; }
49
50
  .banner { border:1px solid var(--warn); border-left-width:4px; border-radius:6px; padding:10px 12px; margin:4px 0 12px; background:color-mix(in srgb, var(--warn) 10%, var(--card)); }
50
51
  .banner strong { color:var(--text); display:block; margin-bottom:4px; } .banner .fix code { white-space:normal; overflow-wrap:anywhere; } .note { color:var(--muted); font-size:12px; margin-top:10px; }
52
+ .banner.snapshot { margin:12px 20px 0; border-color:var(--accent); background:color-mix(in srgb, var(--accent) 8%, var(--card)); } .banner.snapshot strong { font-size:15px; }
51
53
  svg.trend rect.high { fill:var(--high); } svg.trend rect.medium { fill:var(--medium); } svg.trend rect.low { fill:var(--low); } svg.trend rect.zero { fill:var(--ok); }
52
54
  svg.trend line { stroke:var(--line); }
53
55
  .repo-title { font-size:12px; color:var(--muted); margin-bottom:6px; word-break:break-all; }
@@ -69,6 +71,8 @@ ${SETUP_STYLE}
69
71
  `;
70
72
  const SCRIPT = `
71
73
  'use strict';
74
+ /** Set in a static snapshot (dashboard --snapshot): the embedded data. Nothing is fetched and nothing runs. */
75
+ const SNAPSHOT = (() => { const n = document.getElementById('prism-snapshot'); try { return n ? JSON.parse(n.textContent) : null; } catch (e) { return null; } })();
72
76
  const SVG = 'http://www.w3.org/2000/svg';
73
77
  function el(tag, attrs, ...kids) {
74
78
  const n = document.createElement(tag);
@@ -187,8 +191,10 @@ function summaryPanel(sum) {
187
191
 
188
192
  const SCAN_LABEL = { ok: ['ok', 'ok'], 'not-scanned': ['warn', 'not scanned'], 'no-verify': ['warn', 'no-verify'], flagged: ['missing', 'secrets found'], none: ['skipped', '-'] };
189
193
 
190
- /** Link to a scan report. Ids come from the server's own listing; encodeURIComponent keeps them literal. */
191
- const reportLink = (id, label) => el('a', { href: '/report/' + encodeURIComponent(id), class: 'rlink' }, label);
194
+ /** Link to a scan report. Ids come from the server's own listing; encodeURIComponent keeps them literal. A snapshot has no report pages. */
195
+ const reportLink = (id, label) => SNAPSHOT
196
+ ? el('span', { title: 'Report pages open from the live dashboard (prism-cli dashboard) or prism-cli codewatch report' }, label)
197
+ : el('a', { href: '/report/' + encodeURIComponent(id), class: 'rlink' }, label);
192
198
 
193
199
  function reviewCell(rv) {
194
200
  if (rv.state === 'not-reviewed') return el('span', { class: 'fix' }, 'not reviewed');
@@ -628,6 +634,11 @@ async function load(fresh) {
628
634
  }
629
635
 
630
636
  async function getJson(path) {
637
+ if (SNAPSHOT) {
638
+ if (path === '/api/data') return SNAPSHOT.data;
639
+ if (path.startsWith('/api/usage')) return { usage: SNAPSHOT.data.usage, cacheHit: true };
640
+ throw new Error('not in this snapshot');
641
+ }
631
642
  const res = await fetch(path, { credentials: 'same-origin', cache: 'no-store' });
632
643
  if (!res.ok) throw new Error('HTTP ' + res.status);
633
644
  return res.json();
@@ -666,16 +677,23 @@ async function render() {
666
677
  PREV = CUR;
667
678
  const c = data.overview.counts;
668
679
  meta.textContent = c.repos + ' repos under ' + txt(data.scope.root_display) + ' · ' + c.codewatch + ' with codewatch' + (data.scope.truncated ? ' (scan capped)' : '')
669
- + ' · updated ' + when(data.generated_at) + (changed.size ? ' · ' + changed.size + ' value' + (changed.size === 1 ? '' : 's') + ' changed (outlined)' : '') + ' · refreshes every minute while visible';
680
+ + (SNAPSHOT ? ' · data from ' + when(data.generated_at) + ' · static snapshot, does not refresh'
681
+ : ' · updated ' + when(data.generated_at) + (changed.size ? ' · ' + changed.size + ' value' + (changed.size === 1 ? '' : 's') + ' changed (outlined)' : '') + ' · refreshes every minute while visible');
670
682
  await renderSetup(data);
671
683
  return data;
672
684
  }
673
685
  ${SETUP_SCRIPT}
674
686
  ${THEME_SCRIPT}
675
- document.getElementById('refresh').addEventListener('click', () => load(true));
676
- setInterval(() => { if (document.visibilityState === 'visible' && Date.now() - lastLoad >= AUTO_REFRESH_MS - 1000) load(false); }, AUTO_REFRESH_MS / 4);
677
- document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible' && Date.now() - lastLoad >= AUTO_REFRESH_MS) load(false); });
678
- load(false);
687
+ if (SNAPSHOT) {
688
+ const at = document.getElementById('snapshot-at');
689
+ if (at) at.textContent = when(SNAPSHOT.generatedAt);
690
+ load(false);
691
+ } else {
692
+ document.getElementById('refresh').addEventListener('click', () => load(true));
693
+ setInterval(() => { if (document.visibilityState === 'visible' && Date.now() - lastLoad >= AUTO_REFRESH_MS - 1000) load(false); }, AUTO_REFRESH_MS / 4);
694
+ document.addEventListener('visibilitychange', () => { if (document.visibilityState === 'visible' && Date.now() - lastLoad >= AUTO_REFRESH_MS) load(false); });
695
+ load(false);
696
+ }
679
697
  `;
680
698
  export function renderPage(nonce, csrf = '') {
681
699
  // The nonce and the CSRF token are base64/base64url generated server-side; nothing user-derived is interpolated here.
@@ -695,4 +713,45 @@ export function renderPage(nonce, csrf = '') {
695
713
  <main id="setup" hidden></main>
696
714
  <script nonce="${nonce}">${SCRIPT}</script></body></html>`;
697
715
  }
716
+ const sha256 = (s) => `'sha256-${createHash('sha256').update(s, 'utf8').digest('base64')}'`;
717
+ /** JSON for a <script type="application/json"> block: `<` escaped, so the text can never close the element. */
718
+ export function embedJson(v) {
719
+ return JSON.stringify(v).replace(/</g, '\\u003c').replace(/\u2028/g, '\\u2028').replace(/\u2029/g, '\\u2029');
720
+ }
721
+ /** The exact element markers renderSnapshotPage writes, so a test can read the file back without parsing HTML. */
722
+ export const SNAPSHOT_MARKERS = {
723
+ script: '<script>',
724
+ data: '<script type="application/json" id="prism-snapshot">',
725
+ scriptEnd: '</script>',
726
+ style: '<style>',
727
+ styleEnd: '</style>',
728
+ };
729
+ const escapeHtml = (s) => s.replace(/[&<>"']/g, (c) => `&#${c.charCodeAt(0)};`);
730
+ /**
731
+ * The same page as renderPage, as one static file: the data is embedded, the
732
+ * scripts and the style are allowed by hash in a CSP meta tag with
733
+ * default-src 'none' (no fetch, no remote resource), and the Setup page's Run
734
+ * buttons become Copy buttons. No token, no server.
735
+ */
736
+ export function renderSnapshotPage(s) {
737
+ const M = SNAPSHOT_MARKERS;
738
+ const at = escapeHtml(s.generatedAt);
739
+ const csp = `default-src 'none'; script-src ${sha256(THEME_BOOT)} ${sha256(SCRIPT)}; style-src ${sha256(STYLE)}; img-src data:; base-uri 'none'; form-action 'none'`;
740
+ return `<!DOCTYPE html>
741
+ <html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
742
+ <meta http-equiv="Content-Security-Policy" content="${csp}">
743
+ <meta name="referrer" content="no-referrer">
744
+ ${M.script}${THEME_BOOT}${M.scriptEnd}
745
+ <title>PRISM dashboard snapshot ${at}</title>${M.style}${STYLE}${M.styleEnd}</head>
746
+ <body><header><h1>PRISM dashboard</h1>
747
+ <nav class="tabs" aria-label="Views"><a href="#" data-view="dashboard">Dashboard</a><a href="#setup" data-view="setup">Setup</a></nav>
748
+ <div class="theme" role="group" aria-label="Theme"><button type="button" data-theme-set="light">Light</button><button type="button" data-theme-set="dark">Dark</button><button type="button" data-theme-set="system">System</button></div>
749
+ <span class="meta" id="meta"></span></header>
750
+ <div class="banner snapshot" role="note"><strong>Snapshot generated <time id="snapshot-at" datetime="${at}">${at}</time></strong>
751
+ <div class="fix">A static copy written by prism-cli ${escapeHtml(s.version)} dashboard --snapshot. It does not refresh and nothing on it runs: commands are copy only. For the live page run <code>prism-cli dashboard</code>.</div></div>
752
+ <main id="main"></main>
753
+ <main id="setup" hidden></main>
754
+ ${M.data}${embedJson(s)}${M.scriptEnd}
755
+ ${M.script}${SCRIPT}${M.scriptEnd}</body></html>`;
756
+ }
698
757
  //# sourceMappingURL=page.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"page.js","sourceRoot":"","sources":["../../../src/dashboard/page.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEtF,oHAAoH;AACpH,MAAM,UAAU,GAAG,iNAAiN,CAAC;AACrO,MAAM,SAAS,GAAG,kNAAkN,CAAC;AAErO,MAAM,KAAK,GAAG;+BACiB,UAAU;8FACqD,SAAS;iDACtD,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAoDxD,WAAW;CACZ,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA2lBb,YAAY;EACZ,YAAY;;;;;CAKb,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,IAAI,GAAG,EAAE;IACjD,sHAAsH;IACtH,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACtE,OAAO;;mCAE0B,IAAI;iBACtB,KAAK,KAAK,UAAU;8CACS,KAAK,KAAK,KAAK;;;;;;;;iBAQ5C,KAAK,KAAK,MAAM,yBAAyB,CAAC;AAC3D,CAAC"}
1
+ {"version":3,"file":"page.js","sourceRoot":"","sources":["../../../src/dashboard/page.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAEtF,oHAAoH;AACpH,MAAM,UAAU,GAAG,iNAAiN,CAAC;AACrO,MAAM,SAAS,GAAG,kNAAkN,CAAC;AAErO,MAAM,KAAK,GAAG;+BACiB,UAAU;8FACqD,SAAS;iDACtD,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqDxD,WAAW;CACZ,CAAC;AAEF,MAAM,MAAM,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAqmBb,YAAY;EACZ,YAAY;;;;;;;;;;;CAWb,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,KAAa,EAAE,IAAI,GAAG,EAAE;IACjD,sHAAsH;IACtH,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,CAAC,CAAC;IACtE,OAAO;;mCAE0B,IAAI;iBACtB,KAAK,KAAK,UAAU;8CACS,KAAK,KAAK,KAAK;;;;;;;;iBAQ5C,KAAK,KAAK,MAAM,yBAAyB,CAAC;AAC3D,CAAC;AAWD,MAAM,MAAM,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,WAAW,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;AAEpG,+GAA+G;AAC/G,MAAM,UAAU,SAAS,CAAC,CAAU;IAClC,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC,OAAO,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;AAChH,CAAC;AAED,kHAAkH;AAClH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,MAAM,EAAE,UAAU;IAClB,IAAI,EAAE,sDAAsD;IAC5D,SAAS,EAAE,WAAW;IACtB,KAAK,EAAE,SAAS;IAChB,QAAQ,EAAE,UAAU;CACZ,CAAC;AAEX,MAAM,UAAU,GAAG,CAAC,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;AAExF;;;;;GAKG;AACH,MAAM,UAAU,kBAAkB,CAAC,CAAe;IAChD,MAAM,CAAC,GAAG,gBAAgB,CAAC;IAC3B,MAAM,EAAE,GAAG,UAAU,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,kCAAkC,MAAM,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,MAAM,CAAC,eAAe,MAAM,CAAC,KAAK,CAAC,sDAAsD,CAAC;IACrK,OAAO;;sDAE6C,GAAG;;EAEvD,CAAC,CAAC,MAAM,GAAG,UAAU,GAAG,CAAC,CAAC,SAAS;kCACH,EAAE,WAAW,CAAC,CAAC,KAAK,GAAG,KAAK,GAAG,CAAC,CAAC,QAAQ;;;;;uGAK4B,EAAE,KAAK,EAAE;sDAC1D,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC;;;EAGzE,CAAC,CAAC,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS;EACnC,CAAC,CAAC,MAAM,GAAG,MAAM,GAAG,CAAC,CAAC,SAAS,gBAAgB,CAAC;AAClD,CAAC"}