prae-cli 0.10.2 → 0.10.4
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/lib/bin.js +1 -1
- package/lib/{checkpoint-D7d6ZGXR.js → checkpoint-DxE4MCri.js} +1 -1
- package/lib/cli-CkL2G7pV.js +7 -0
- package/lib/{cli-BTVEk0Fh.js → cli-Dpem2eHc.js} +49 -29
- package/lib/docs/pilot-claude-code.md +39 -5
- package/lib/{facts-DkTRO2p0.js → facts-BKzQ9GLI.js} +1 -1
- package/lib/{hook-C7LGEIs2.js → hook-C7ehSrzs.js} +17 -4
- package/lib/index.js +5 -5
- package/lib/{init-DvzCuemh.js → init-B_cGYN45.js} +138 -29
- package/lib/{instructions-Bcs2n2O6.js → instructions-BqT2wN_4.js} +2 -2
- package/lib/{mcp-C2gadkb2.js → mcp-HD1KrudT.js} +1 -1
- package/lib/playground.js +20 -4
- package/lib/prae-baseline.prae.json +6 -2
- package/lib/quickstart-BsKH37Hb.js +126 -0
- package/lib/quickstart-CV2i1KDh.js +3 -0
- package/lib/{receipt-check-BtAJqyrX.js → receipt-check-D4opBPn-.js} +1 -1
- package/lib/{src-CZYvvEn5.js → src-DO3IFxZ-.js} +20 -4
- package/lib/{src-2iJy5MZc.js → src-IuqWO2qD.js} +1 -1
- package/lib/{src-CuiWC80o.js → src-Tshjqoz6.js} +1 -1
- package/lib/{test-run-DCprBW44.js → test-run-CveqObP9.js} +1 -1
- package/lib/{views-endiZu1Z.js → views-Hh3G5zpv.js} +1 -1
- package/package.json +4 -4
- package/lib/cli-DYKKNlDI.js +0 -7
- /package/lib/{ocsf-DwExfPqP.js → ocsf-CRDSY64q.js} +0 -0
- /package/lib/{src-DV83J9G2.js → src-BsDLT9wq.js} +0 -0
- /package/lib/{src-DxJIOaP5.js → src-C7rfOs_W.js} +0 -0
package/lib/bin.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
//#region src/bin.ts
|
|
3
3
|
const argv = process.argv.slice(2);
|
|
4
|
-
(argv[0] === "hook" && argv[1] === "claude-code" ? import("./hook-
|
|
4
|
+
(argv[0] === "hook" && argv[1] === "claude-code" ? argv[2] === "session-start" ? import("./quickstart-CV2i1KDh.js").then(({ runSessionStart }) => runSessionStart(argv.slice(3))) : import("./hook-C7ehSrzs.js").then(({ runHook }) => runHook(argv.slice(2))) : import("./cli-CkL2G7pV.js").then(({ main }) => main(argv))).catch((error) => {
|
|
5
5
|
console.error(`prae: ${error instanceof Error ? error.message : error}`);
|
|
6
6
|
process.exit(1);
|
|
7
7
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { c as withinAny, i as evaluate, n as FRAMEWORKS, o as hostOf, r as cite, t as parsePack } from "./src-
|
|
2
|
-
import { a as verifyEntries, b as seal, g as GENESIS, h as verifySignature, l as verifyBytes, n as Ledger, r as readEntries, t as verifyGrowing, u as fingerprint, v as chain } from "./src-
|
|
3
|
-
import { t as capabilityOf } from "./facts-
|
|
4
|
-
import { a as renderPacks, c as renderNav, i as renderOverview, l as renderShell, n as renderApprovals, o as CONTROLS, r as renderCompliance, s as esc, t as navFor, u as VERDICT_LABEL$1 } from "./views-
|
|
1
|
+
import { c as withinAny, i as evaluate, n as FRAMEWORKS, o as hostOf, r as cite, t as parsePack } from "./src-DO3IFxZ-.js";
|
|
2
|
+
import { a as verifyEntries, b as seal, g as GENESIS, h as verifySignature, l as verifyBytes, n as Ledger, r as readEntries, t as verifyGrowing, u as fingerprint, v as chain } from "./src-Tshjqoz6.js";
|
|
3
|
+
import { t as capabilityOf } from "./facts-BKzQ9GLI.js";
|
|
4
|
+
import { a as renderPacks, c as renderNav, i as renderOverview, l as renderShell, n as renderApprovals, o as CONTROLS, r as renderCompliance, s as esc, t as navFor, u as VERDICT_LABEL$1 } from "./views-Hh3G5zpv.js";
|
|
5
5
|
import { createRequire } from "node:module";
|
|
6
6
|
import { closeSync, existsSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, statSync, watch, writeFileSync } from "node:fs";
|
|
7
7
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
@@ -2112,20 +2112,29 @@ const USAGE = `⌜▪⌟ prae — operator policy for agent harnesses
|
|
|
2112
2112
|
that pack, loaded and watched as a set; a set that would not load is
|
|
2113
2113
|
not mounted (see \`prae check <dir>\`).
|
|
2114
2114
|
|
|
2115
|
-
prae init claude-code
|
|
2115
|
+
prae init claude-code [--settings <file> | --scope user|project]
|
|
2116
2116
|
[--shadow | --enforce] [--pack <file>] [--ledger <file>]
|
|
2117
2117
|
[--dir <dir>] [--apply] [--remove]
|
|
2118
2118
|
Register PRAE as a Claude Code PreToolUse hook: every tool call,
|
|
2119
2119
|
built-in or MCP, judged by the pack and sealed in a signed ledger
|
|
2120
2120
|
(default ~/.prae/claude-code/). Shadow (the default) records and
|
|
2121
2121
|
never blocks; --enforce returns deny/ask to Claude Code. Prints the
|
|
2122
|
-
settings diff; writes only with --apply
|
|
2123
|
-
|
|
2122
|
+
settings diff; writes only with --apply, or when you answer yes at
|
|
2123
|
+
a terminal. With no target, a terminal asks; otherwise it is
|
|
2124
|
+
--scope project, and nothing is done when Claude Code's managed
|
|
2125
|
+
settings already run PRAE. Also installs the
|
|
2126
|
+
/prae-quickstart skill beside the settings, offered once in the first
|
|
2127
|
+
session. --remove takes out PRAE's own entries and skill, nothing
|
|
2128
|
+
else. See docs/pilot-claude-code.md.
|
|
2124
2129
|
|
|
2125
2130
|
prae hook claude-code [--shadow | --enforce] --pack <file> --ledger <file>
|
|
2126
2131
|
[--key <private.pem>] [--settings <file>]
|
|
2127
2132
|
The command that settings entry runs: reads one PreToolUse payload on
|
|
2128
2133
|
stdin and answers through the hook's output contract.
|
|
2134
|
+
|
|
2135
|
+
prae hook claude-code session-start --dir <dir>
|
|
2136
|
+
The SessionStart entry init adds beside it: in the first session after
|
|
2137
|
+
the install, it offers the /prae-quickstart tour once, then is silent.
|
|
2129
2138
|
`;
|
|
2130
2139
|
function fail(message) {
|
|
2131
2140
|
console.error(`prae: ${message}`);
|
|
@@ -2225,13 +2234,13 @@ async function scanFile(path, packPath, json) {
|
|
|
2225
2234
|
* not come up inspecting nothing.
|
|
2226
2235
|
*/
|
|
2227
2236
|
async function mcp(root, packPath, ledgerPath) {
|
|
2228
|
-
const { serveMcp } = await import("./mcp-
|
|
2237
|
+
const { serveMcp } = await import("./mcp-HD1KrudT.js");
|
|
2229
2238
|
const { resolve: resolve$1 } = await import("node:path");
|
|
2230
2239
|
const bundled = [join(import.meta.dirname, "secret-catcher.prae.json"), join(import.meta.dirname, "..", "..", "..", "examples", "secret-catcher.prae.json")].find((candidate) => existsSync(candidate));
|
|
2231
2240
|
const chosen = packPath ?? bundled;
|
|
2232
2241
|
if (chosen === void 0) return fail("mcp needs --pack <file>; no bundled secret-catcher found");
|
|
2233
2242
|
const pack = await loadPack(chosen);
|
|
2234
|
-
const { Ledger: Ledger$1 } = await import("./src-
|
|
2243
|
+
const { Ledger: Ledger$1 } = await import("./src-IuqWO2qD.js");
|
|
2235
2244
|
const ledger = ledgerPath === void 0 ? void 0 : Ledger$1.open(ledgerPath);
|
|
2236
2245
|
console.error(`prae mcp: serving ${resolve$1(root)} under ${pack.pack} ${pack.version}` + (ledgerPath === void 0 ? " (no ledger)" : ` · ledger ${ledgerPath}`));
|
|
2237
2246
|
await serveMcp({
|
|
@@ -2282,7 +2291,7 @@ async function explain(path, tool, pairs) {
|
|
|
2282
2291
|
* a key that arrived beside it is checked against nothing.
|
|
2283
2292
|
*/
|
|
2284
2293
|
async function keygen(dir) {
|
|
2285
|
-
const { generateKeypair, fingerprint: fingerprint$1 } = await import("./src-
|
|
2294
|
+
const { generateKeypair, fingerprint: fingerprint$1 } = await import("./src-IuqWO2qD.js");
|
|
2286
2295
|
const { writeFileSync: writeFileSync$1 } = await import("node:fs");
|
|
2287
2296
|
const keys = generateKeypair();
|
|
2288
2297
|
const priv = join(dir, "prae-signing.pem");
|
|
@@ -2305,7 +2314,7 @@ async function keygen(dir) {
|
|
|
2305
2314
|
async function keygenSealed(role, dir) {
|
|
2306
2315
|
if (role !== "operator" && role !== "policy" && role !== "ledger") fail("--role is operator, policy or ledger");
|
|
2307
2316
|
const stem = role === "ledger" ? "prae-signing" : role;
|
|
2308
|
-
const { sealedKeypair, fingerprint: fingerprint$1 } = await import("./src-
|
|
2317
|
+
const { sealedKeypair, fingerprint: fingerprint$1 } = await import("./src-IuqWO2qD.js");
|
|
2309
2318
|
const { writeFileSync: writeFileSync$1 } = await import("node:fs");
|
|
2310
2319
|
const keys = sealedKeypair(process.env.PRAE_KEY_PASSPHRASE ?? await askHidden("passphrase: "));
|
|
2311
2320
|
const pub = join(dir, `${stem}.pub.pem`);
|
|
@@ -2318,7 +2327,7 @@ async function keygenSealed(role, dir) {
|
|
|
2318
2327
|
}
|
|
2319
2328
|
/** A detached signature over a pack's bytes (PRA-107). */
|
|
2320
2329
|
async function signPack(packPath, keyPath) {
|
|
2321
|
-
const { signBytes, unsealPrivateKey, fingerprint: fingerprint$1 } = await import("./src-
|
|
2330
|
+
const { signBytes, unsealPrivateKey, fingerprint: fingerprint$1 } = await import("./src-IuqWO2qD.js");
|
|
2322
2331
|
const { createPublicKey: createPublicKey$1 } = await import("node:crypto");
|
|
2323
2332
|
const bytes = readFileSync(packPath);
|
|
2324
2333
|
const parsed$1 = parsePack(bytes.toString("utf8"));
|
|
@@ -2363,7 +2372,7 @@ function askHidden(prompt) {
|
|
|
2363
2372
|
});
|
|
2364
2373
|
}
|
|
2365
2374
|
async function receipt(path, seq, keyPath, out) {
|
|
2366
|
-
const { Ledger: Ledger$1, makeReceipt, fingerprint: fingerprint$1 } = await import("./src-
|
|
2375
|
+
const { Ledger: Ledger$1, makeReceipt, fingerprint: fingerprint$1 } = await import("./src-IuqWO2qD.js");
|
|
2367
2376
|
const { readFileSync: readFileSync$1 } = await import("node:fs");
|
|
2368
2377
|
const { createPublicKey: createPublicKey$1 } = await import("node:crypto");
|
|
2369
2378
|
const privateKey = readFileSync$1(keyPath, "utf8");
|
|
@@ -2393,7 +2402,7 @@ async function receipt(path, seq, keyPath, out) {
|
|
|
2393
2402
|
* file and sets the exit code, so scripts can branch on it.
|
|
2394
2403
|
*/
|
|
2395
2404
|
async function verifyReceiptCmd(path) {
|
|
2396
|
-
const { checkReceipt } = await import("./receipt-check-
|
|
2405
|
+
const { checkReceipt } = await import("./receipt-check-D4opBPn-.js");
|
|
2397
2406
|
let parsed$1;
|
|
2398
2407
|
try {
|
|
2399
2408
|
parsed$1 = JSON.parse(await readFile(path, "utf8"));
|
|
@@ -2424,7 +2433,7 @@ async function test(suitePath, packOverride, asJson) {
|
|
|
2424
2433
|
} catch (error) {
|
|
2425
2434
|
return fail(`${suitePath} is not valid JSON: ${error instanceof Error ? error.message : error}`);
|
|
2426
2435
|
}
|
|
2427
|
-
const { parseSuite, renderSuite, runSuite } = await import("./test-run-
|
|
2436
|
+
const { parseSuite, renderSuite, runSuite } = await import("./test-run-CveqObP9.js");
|
|
2428
2437
|
const suite = parseSuite(parsed$1);
|
|
2429
2438
|
if (!suite.ok) {
|
|
2430
2439
|
console.error(`prae: ${suitePath} is not a valid test suite`);
|
|
@@ -2463,14 +2472,14 @@ async function verify$1(path, keyPath, checkpointPath) {
|
|
|
2463
2472
|
const last = entries.at(-1);
|
|
2464
2473
|
console.log(`${result.entries} entries · chain intact${last === void 0 ? "" : ` · seal ${seal(last)}`}`);
|
|
2465
2474
|
if (checkpointPath !== void 0) {
|
|
2466
|
-
const { checkCheckpoint } = await import("./checkpoint-
|
|
2475
|
+
const { checkCheckpoint } = await import("./checkpoint-DxE4MCri.js");
|
|
2467
2476
|
const publicKey = keyPath === void 0 ? void 0 : readFileSync(keyPath, "utf8");
|
|
2468
2477
|
const verdict = checkCheckpoint(entries, JSON.parse(readFileSync(checkpointPath, "utf8")), publicKey);
|
|
2469
2478
|
for (const line of verdict.lines) (verdict.ok ? console.log : console.error)(`checkpoint: ${line}`);
|
|
2470
2479
|
if (!verdict.ok) process.exitCode = 1;
|
|
2471
2480
|
}
|
|
2472
2481
|
if (keyPath !== void 0) {
|
|
2473
|
-
const { verifySignature: verifySignature$1, fingerprint: fingerprint$1 } = await import("./src-
|
|
2482
|
+
const { verifySignature: verifySignature$1, fingerprint: fingerprint$1 } = await import("./src-IuqWO2qD.js");
|
|
2474
2483
|
const { readFileSync: readFileSync$1 } = await import("node:fs");
|
|
2475
2484
|
const publicKey = readFileSync$1(keyPath, "utf8");
|
|
2476
2485
|
let signed = 0;
|
|
@@ -2548,7 +2557,7 @@ async function report(path, out, packPath) {
|
|
|
2548
2557
|
* that step is a proposal a human approves, and it starts from this list.
|
|
2549
2558
|
*/
|
|
2550
2559
|
async function instructions(from, asJson) {
|
|
2551
|
-
const { ingest } = await import("./src-
|
|
2560
|
+
const { ingest } = await import("./src-C7rfOs_W.js");
|
|
2552
2561
|
const result = ingest(from);
|
|
2553
2562
|
if (asJson) {
|
|
2554
2563
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -2584,7 +2593,7 @@ async function instructions(from, asJson) {
|
|
|
2584
2593
|
* on purpose rather than something that happened to their policy.
|
|
2585
2594
|
*/
|
|
2586
2595
|
async function propose(from, options) {
|
|
2587
|
-
const [{ ingest }, { extract }] = await Promise.all([import("./src-
|
|
2596
|
+
const [{ ingest }, { extract }] = await Promise.all([import("./src-C7rfOs_W.js"), import("./src-BsDLT9wq.js")]);
|
|
2588
2597
|
const read = ingest(from);
|
|
2589
2598
|
if (read.files.length === 0) {
|
|
2590
2599
|
console.log(`No instruction files found at or above ${from}.`);
|
|
@@ -2644,9 +2653,9 @@ async function consoleOut(path, argv) {
|
|
|
2644
2653
|
const instructionsDir = flag(argv, "instructions");
|
|
2645
2654
|
if (instructionsDir !== void 0) {
|
|
2646
2655
|
const [{ ingest }, { extract }, { renderInstructions }] = await Promise.all([
|
|
2647
|
-
import("./src-
|
|
2648
|
-
import("./src-
|
|
2649
|
-
import("./instructions-
|
|
2656
|
+
import("./src-C7rfOs_W.js"),
|
|
2657
|
+
import("./src-BsDLT9wq.js"),
|
|
2658
|
+
import("./instructions-BqT2wN_4.js")
|
|
2650
2659
|
]);
|
|
2651
2660
|
const read = ingest(instructionsDir);
|
|
2652
2661
|
instructionsView = renderInstructions(data, read, extract(read.statements));
|
|
@@ -2779,7 +2788,7 @@ async function chainMatrix(path, argv) {
|
|
|
2779
2788
|
const catalogue = guardiansPath === void 0 ? [] : JSON.parse(readFileSync(guardiansPath, "utf8")).guardians;
|
|
2780
2789
|
const guardianOf = (rule) => rule === void 0 ? void 0 : catalogue.find((g) => g.rules.includes(rule) || (g.armed ?? []).includes(rule))?.name;
|
|
2781
2790
|
const keyPath = flag(argv, "key");
|
|
2782
|
-
const { verifySignature: verifySignature$1 } = await import("./src-
|
|
2791
|
+
const { verifySignature: verifySignature$1 } = await import("./src-IuqWO2qD.js");
|
|
2783
2792
|
const publicKey = keyPath === void 0 ? void 0 : readFileSync(keyPath, "utf8");
|
|
2784
2793
|
const matrix = integrityMatrix(entries, pack, guardianOf).map((m) => {
|
|
2785
2794
|
const entry = entries.find((e) => e.seq === m.seq);
|
|
@@ -2810,7 +2819,7 @@ async function chainMatrix(path, argv) {
|
|
|
2810
2819
|
if (!chainOk || sigFailed) process.exitCode = 1;
|
|
2811
2820
|
}
|
|
2812
2821
|
async function checkpoint(path, keyPath, out) {
|
|
2813
|
-
const { makeCheckpoint } = await import("./checkpoint-
|
|
2822
|
+
const { makeCheckpoint } = await import("./checkpoint-DxE4MCri.js");
|
|
2814
2823
|
let ledger;
|
|
2815
2824
|
try {
|
|
2816
2825
|
ledger = Ledger.open(path);
|
|
@@ -2831,7 +2840,7 @@ async function checkpoint(path, keyPath, out) {
|
|
|
2831
2840
|
}
|
|
2832
2841
|
}
|
|
2833
2842
|
async function exportLedger(path, options) {
|
|
2834
|
-
const { toOcsf, ndjson, sendToHec } = await import("./ocsf-
|
|
2843
|
+
const { toOcsf, ndjson, sendToHec } = await import("./ocsf-CRDSY64q.js");
|
|
2835
2844
|
const { createRequire: createRequire$1 } = await import("node:module");
|
|
2836
2845
|
const { version } = createRequire$1(import.meta.url)("../package.json");
|
|
2837
2846
|
let ledger;
|
|
@@ -2962,22 +2971,33 @@ async function main(argv) {
|
|
|
2962
2971
|
}
|
|
2963
2972
|
case "init":
|
|
2964
2973
|
if (rest[0] === "claude-code") {
|
|
2965
|
-
const { initClaudeCode, stableNode } = await import("./init-
|
|
2974
|
+
const { initClaudeCode, stableNode } = await import("./init-B_cGYN45.js");
|
|
2975
|
+
const prompt = process.stdin.isTTY && process.stdout.isTTY ? (await import("node:readline/promises")).createInterface({
|
|
2976
|
+
input: process.stdin,
|
|
2977
|
+
output: process.stdout
|
|
2978
|
+
}) : void 0;
|
|
2966
2979
|
try {
|
|
2967
|
-
return initClaudeCode(rest.slice(1), {
|
|
2980
|
+
return await initClaudeCode(rest.slice(1), {
|
|
2968
2981
|
cwd: process.cwd(),
|
|
2969
2982
|
node: stableNode(process.execPath, process.env.PATH),
|
|
2970
2983
|
bin: resolve(process.argv[1] ?? ""),
|
|
2971
|
-
baseline: bundledBaseline()
|
|
2984
|
+
baseline: bundledBaseline(),
|
|
2985
|
+
...prompt === void 0 ? {} : { ask: (q) => prompt.question(q) }
|
|
2972
2986
|
});
|
|
2973
2987
|
} catch (error) {
|
|
2974
2988
|
return fail(error instanceof Error ? error.message : String(error));
|
|
2989
|
+
} finally {
|
|
2990
|
+
prompt?.close();
|
|
2975
2991
|
}
|
|
2976
2992
|
}
|
|
2977
2993
|
return init(rest);
|
|
2978
2994
|
case "hook": {
|
|
2979
2995
|
if (rest[0] !== "claude-code") fail("hook takes claude-code");
|
|
2980
|
-
|
|
2996
|
+
if (rest[1] === "session-start") {
|
|
2997
|
+
const { runSessionStart } = await import("./quickstart-CV2i1KDh.js");
|
|
2998
|
+
return runSessionStart(rest.slice(2));
|
|
2999
|
+
}
|
|
3000
|
+
const { runHook } = await import("./hook-C7ehSrzs.js");
|
|
2981
3001
|
return runHook(rest.slice(1));
|
|
2982
3002
|
}
|
|
2983
3003
|
case "--help":
|
|
@@ -42,10 +42,17 @@ runs the `prae` it was installed from, and an `npx` copy lives in npm's
|
|
|
42
42
|
temporary cache, which npm may clear — the hook would then stop running, and
|
|
43
43
|
Claude Code 2.1.233 lets every call through when a hook cannot start.
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
The target is the settings file to edit. `--scope user` is `~/.claude/settings.json`, which
|
|
46
46
|
covers every project. `--scope project` is `./.claude/settings.json`.
|
|
47
47
|
`--settings <file>` is any file you name, for example
|
|
48
|
-
`.claude/settings.local.json`.
|
|
48
|
+
`.claude/settings.local.json`.
|
|
49
|
+
|
|
50
|
+
With no target (prae-cli 0.10.4 or later):
|
|
51
|
+
- At a terminal, `prae init claude-code` asks whether to install for this project or for every project. It shows the diff, then asks before writing.
|
|
52
|
+
- Run without a terminal, it uses `--scope project`, says so, and writes only with `--apply`.
|
|
53
|
+
- If Claude Code's managed settings already run PRAE, as on the hosted sandbox, it says so and changes nothing.
|
|
54
|
+
|
|
55
|
+
Otherwise nothing is written without `--apply`. The file
|
|
49
56
|
is written back as 2-space JSON, the format Claude Code itself writes, so a
|
|
50
57
|
hand-formatted file shows layout changes in the diff. Its values do not change.
|
|
51
58
|
|
|
@@ -61,6 +68,25 @@ PRAE's own script by absolute path, so it does not depend on `PATH`. If you
|
|
|
61
68
|
upgrade or reinstall prae-cli, or switch Node versions, run `init` again. Claude Code reloads settings on its own,
|
|
62
69
|
so new tool calls go through PRAE without a restart.
|
|
63
70
|
|
|
71
|
+
### The quickstart inside Claude Code
|
|
72
|
+
|
|
73
|
+
From prae-cli 0.10.4, `init` also installs a five-minute guided tour.
|
|
74
|
+
|
|
75
|
+
- **The `/prae-quickstart` skill.** It is written beside the settings file:
|
|
76
|
+
- `~/.claude/skills/` for `--scope user`;
|
|
77
|
+
- `./.claude/skills/` for `--scope project`;
|
|
78
|
+
- `.claude/skills/` inside the managed settings directory.
|
|
79
|
+
|
|
80
|
+
Claude walks you through it with real calls, in a scratch folder (`./.prae-quickstart/`) it creates in your project:
|
|
81
|
+
- a read that is allowed;
|
|
82
|
+
- a synthetic credentials file that is refused (BASE-005);
|
|
83
|
+
- a recursive delete that waits for you (BASE-002);
|
|
84
|
+
- `prae verify` on the ledger;
|
|
85
|
+
- `prae explain`, which you run yourself, because PRAE's pack is not the agent's to touch.
|
|
86
|
+
|
|
87
|
+
It ends with links to prae-ai.com. The skill is written for your install, with your paths and mode. Rerun it any time.
|
|
88
|
+
- **A `SessionStart` entry, `matcher: "startup"`.** In the first session after the install, it shows `PRAE is active … Type /prae-quickstart for a five-minute tour.`, and Claude offers the tour once. It then leaves `quickstart-offered` in the state directory and stays silent in every later session. It never fails a session.
|
|
89
|
+
|
|
64
90
|
Options:
|
|
65
91
|
|
|
66
92
|
- `--pack <file>`: use your own pack. The default copies the built-in baseline
|
|
@@ -83,6 +109,7 @@ Everything lives in `~/.prae/claude-code/`, which is created with mode 0700:
|
|
|
83
109
|
| `prae-signing.pem` | The Ed25519 key that signs each row. It is generated once with mode 0600. |
|
|
84
110
|
| `prae-signing.pub.pem` | The public half. Give it to whoever verifies the record. |
|
|
85
111
|
| `prae-baseline.prae.json` | The pack in force, unless you passed `--pack`. |
|
|
112
|
+
| `quickstart-offered` | Written when the first session has offered the quickstart. Delete it to see the offer again. |
|
|
86
113
|
|
|
87
114
|
Each row holds the time, the Claude Code `session_id`, the `tool_use_id` (as
|
|
88
115
|
`correlation`), the tool, its capability (`fs:read`, `fs:write`,
|
|
@@ -115,8 +142,8 @@ This replaces PRAE's entry. It does not add a second one. In enforce mode:
|
|
|
115
142
|
| Verdict | What Claude Code does |
|
|
116
143
|
| --- | --- |
|
|
117
144
|
| allow | The hook prints nothing. Claude Code's own permission flow decides, as before. PRAE never answers `allow`, because that would skip your permission prompt. |
|
|
118
|
-
| deny | `permissionDecision: "deny"`. The call does not run, and Claude reads the reason, for example `PRAE BASE-005: … (ledger row 12)`. |
|
|
119
|
-
| ask | `permissionDecision: "ask"`. You get a permission prompt
|
|
145
|
+
| deny | `permissionDecision: "deny"`. The call does not run, and Claude reads the reason, for example `PRAE BASE-005: … (denied · ledger row 12)`. Claude Code labels it `hook error`; the `denied` at the end is PRAE's verdict, not a failure. |
|
|
146
|
+
| ask | `permissionDecision: "ask"`. You get a permission prompt with the reason, for example `PRAE BASE-002: … (approval required · ledger row 3)`. In a headless `claude -p` run nobody can answer it, so Claude Code refuses the call (verified on 2.1.233 and 2.1.308). |
|
|
120
147
|
| gate error | The pack does not parse, the ledger cannot be written, the key is unreadable, the payload is broken, or the ledger lock is held for more than 3 seconds. The hook refuses the call (exit 2) and records the error in the ledger when it can. |
|
|
121
148
|
|
|
122
149
|
In shadow mode a gate error lets the call run. It shows a `systemMessage`
|
|
@@ -128,7 +155,7 @@ warning and records a `PRAE-ERROR` row marked `shadow`.
|
|
|
128
155
|
prae init claude-code --scope user --remove --apply
|
|
129
156
|
```
|
|
130
157
|
|
|
131
|
-
This removes PRAE's hook
|
|
158
|
+
This removes PRAE's hook entries and its `/prae-quickstart` skill, and nothing else. The ledger and the key stay
|
|
132
159
|
in place, because they are the evidence of what ran. Delete
|
|
133
160
|
`~/.prae/claude-code/` yourself when you no longer need them.
|
|
134
161
|
|
|
@@ -165,6 +192,13 @@ confidence) reaches the ledger.
|
|
|
165
192
|
edit them. An edited ledger breaks its chain and its signatures. A wholesale
|
|
166
193
|
rewrite by someone who holds the key needs an external checkpoint
|
|
167
194
|
(`prae checkpoint`) to catch.
|
|
195
|
+
- **`!` shell mode is your shell, not the agent's.** A command you type after
|
|
196
|
+
`!` in the prompt runs directly, without Claude and without any hook or
|
|
197
|
+
permission rule (Claude Code's design: it "doesn't require Claude to
|
|
198
|
+
interpret or approve the command"). It is you running it, as in any
|
|
199
|
+
terminal. After PRAE holds or refuses a call, Claude may suggest that you
|
|
200
|
+
run it yourself that way; that is the model's wording, and nothing ran
|
|
201
|
+
(PRA-213, `docs/pra-213-destructive-commands.md`).
|
|
168
202
|
- **What the hook never sees.** Files you attach with `@` in a prompt are read
|
|
169
203
|
without a tool call, so no hook fires. Managed settings can switch user hooks
|
|
170
204
|
off (`allowManagedHooksOnly`, `disableAllHooks`).
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { a as PATH_ARGS, i as evaluate, l as segments, s as relativeTo, t as parsePack } from "./src-
|
|
2
|
-
import { n as Ledger } from "./src-
|
|
3
|
-
import { n as factsFor, t as capabilityOf } from "./facts-
|
|
1
|
+
import { a as PATH_ARGS, i as evaluate, l as segments, s as relativeTo, t as parsePack } from "./src-DO3IFxZ-.js";
|
|
2
|
+
import { n as Ledger } from "./src-Tshjqoz6.js";
|
|
3
|
+
import { n as factsFor, t as capabilityOf } from "./facts-BKzQ9GLI.js";
|
|
4
4
|
import { a as scan, n as MAX_SCAN_BYTES } from "./src-9phPLfAL.js";
|
|
5
5
|
import { lstatSync, readFileSync, readlinkSync, realpathSync, statSync } from "node:fs";
|
|
6
6
|
import { basename, dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|
@@ -481,6 +481,7 @@ function decide(payload, options) {
|
|
|
481
481
|
if (named !== void 0) judged = override(judged, "PRAE-SELF", `the command names \`${named}\`; PRAE’s own pack, ledger, key and hook settings are not the agent’s to change`);
|
|
482
482
|
const record = {
|
|
483
483
|
...judged.record,
|
|
484
|
+
via: VIA,
|
|
484
485
|
pack: {
|
|
485
486
|
...judged.record.pack,
|
|
486
487
|
sha256: loaded.sha256
|
|
@@ -498,7 +499,7 @@ function decide(payload, options) {
|
|
|
498
499
|
stdout: JSON.stringify({ hookSpecificOutput: {
|
|
499
500
|
hookEventName: "PreToolUse",
|
|
500
501
|
permissionDecision: judged.decision.kind,
|
|
501
|
-
permissionDecisionReason: `PRAE ${record.rule ?? ""}: ${judged.decision.reason} (ledger row ${entry.seq})`
|
|
502
|
+
permissionDecisionReason: `PRAE ${record.rule ?? ""}: ${judged.decision.reason} (${OUTCOME[judged.decision.kind]} · ledger row ${entry.seq})`
|
|
502
503
|
} }),
|
|
503
504
|
stderr: "",
|
|
504
505
|
exitCode: 0,
|
|
@@ -508,6 +509,17 @@ function decide(payload, options) {
|
|
|
508
509
|
return failed(payload, options, ledger, error, wait);
|
|
509
510
|
}
|
|
510
511
|
}
|
|
512
|
+
/** Where these rows come from, on every one (PRA-213). */
|
|
513
|
+
const VIA = "claude-code:PreToolUse";
|
|
514
|
+
/**
|
|
515
|
+
* The outcome in words, at the end of the reason: Claude Code labels a
|
|
516
|
+
* refusal "hook error", so without it a denial reads like a gate failure
|
|
517
|
+
* (PRA-213). A real failure says "PRAE gate error" instead.
|
|
518
|
+
*/
|
|
519
|
+
const OUTCOME = {
|
|
520
|
+
ask: "approval required",
|
|
521
|
+
deny: "denied"
|
|
522
|
+
};
|
|
511
523
|
/** The gate could not judge: enforce refuses, shadow proceeds; both say so. */
|
|
512
524
|
function failed(payload, options, opened, error, wait) {
|
|
513
525
|
const message = error instanceof Error ? error.message : String(error);
|
|
@@ -518,6 +530,7 @@ function failed(payload, options, opened, error, wait) {
|
|
|
518
530
|
entry = appendWithin(opened ?? openLedger(options), {
|
|
519
531
|
at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
520
532
|
...payload.session_id === void 0 ? {} : { session: payload.session_id },
|
|
533
|
+
via: VIA,
|
|
521
534
|
tool: typeof payload.tool_name === "string" ? payload.tool_name : "prae:hook",
|
|
522
535
|
verdict: "deny",
|
|
523
536
|
rule: "PRAE-ERROR",
|
package/lib/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import "./src-
|
|
2
|
-
import "./src-
|
|
3
|
-
import { a as planWrite, i as dshHome, n as applyWrite, o as praeRow, r as defaultProfile, s as profileAt, t as main } from "./cli-
|
|
4
|
-
import "./facts-
|
|
5
|
-
import "./views-
|
|
1
|
+
import "./src-DO3IFxZ-.js";
|
|
2
|
+
import "./src-Tshjqoz6.js";
|
|
3
|
+
import { a as planWrite, i as dshHome, n as applyWrite, o as praeRow, r as defaultProfile, s as profileAt, t as main } from "./cli-Dpem2eHc.js";
|
|
4
|
+
import "./facts-BKzQ9GLI.js";
|
|
5
|
+
import "./views-Hh3G5zpv.js";
|
|
6
6
|
|
|
7
7
|
export { applyWrite, defaultProfile, dshHome, main, planWrite, praeRow, profileAt };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { t as parsePack } from "./src-
|
|
2
|
-
import { d as generateKeypair, u as fingerprint } from "./src-
|
|
3
|
-
import {
|
|
1
|
+
import { t as parsePack } from "./src-DO3IFxZ-.js";
|
|
2
|
+
import { d as generateKeypair, u as fingerprint } from "./src-Tshjqoz6.js";
|
|
3
|
+
import { a as skill, o as skillFile } from "./quickstart-BsKH37Hb.js";
|
|
4
|
+
import { copyFileSync, existsSync, mkdirSync, readFileSync, realpathSync, rmSync, rmdirSync, writeFileSync } from "node:fs";
|
|
4
5
|
import { delimiter, dirname, join, resolve } from "node:path";
|
|
5
6
|
import { homedir } from "node:os";
|
|
6
7
|
|
|
@@ -40,30 +41,38 @@ function put(obj, key, value) {
|
|
|
40
41
|
if (value !== void 0 && !(key in obj)) out[key] = value;
|
|
41
42
|
return out;
|
|
42
43
|
}
|
|
43
|
-
/**
|
|
44
|
+
/** The hook events PRAE registers under. */
|
|
45
|
+
const EVENTS = ["PreToolUse", "SessionStart"];
|
|
46
|
+
/** Settings without PRAE's handlers; containers it emptied are dropped. */
|
|
44
47
|
function withoutPrae(settings) {
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
48
|
+
let hooks = settings.hooks;
|
|
49
|
+
if (hooks === void 0) return settings;
|
|
50
|
+
for (const event of EVENTS) {
|
|
51
|
+
const groups = hooks[event];
|
|
52
|
+
if (!Array.isArray(groups)) continue;
|
|
53
|
+
const kept = groups.map((g) => Array.isArray(g.hooks) && g.hooks.some(isPrae) ? {
|
|
54
|
+
...g,
|
|
55
|
+
hooks: g.hooks.filter((h) => !isPrae(h))
|
|
56
|
+
} : g).filter((g) => !Array.isArray(g.hooks) || g.hooks.length > 0);
|
|
57
|
+
if (kept.length === groups.length && kept.every((g, i) => g === groups[i])) continue;
|
|
58
|
+
hooks = put(hooks, event, kept.length === 0 ? void 0 : kept);
|
|
59
|
+
}
|
|
60
|
+
if (hooks === settings.hooks) return settings;
|
|
61
|
+
return put(settings, "hooks", Object.keys(hooks).length === 0 ? void 0 : hooks);
|
|
55
62
|
}
|
|
56
63
|
/**
|
|
57
|
-
* Settings with PRAE's
|
|
64
|
+
* Settings with PRAE's handlers as the only PRAE entries, replacing any old
|
|
65
|
+
* ones: the gate on every tool call and, given `start`, the quickstart offer
|
|
66
|
+
* at session start (PRA-215).
|
|
58
67
|
*
|
|
59
68
|
* Enforce adds `onFailure: "block"`: from Claude Code 2.1.295 a hook that
|
|
60
69
|
* cannot start or times out then blocks the call instead of letting it
|
|
61
70
|
* through. Earlier versions ignore the field (2.1.233 checked: the hook
|
|
62
71
|
* still runs, and a hook that cannot start still lets the call through).
|
|
63
72
|
*/
|
|
64
|
-
function withPrae(settings, command, enforce = false) {
|
|
73
|
+
function withPrae(settings, command, enforce = false, start) {
|
|
65
74
|
const base = withoutPrae(settings);
|
|
66
|
-
|
|
75
|
+
let hooks = base.hooks ?? {};
|
|
67
76
|
const groups = Array.isArray(hooks.PreToolUse) ? hooks.PreToolUse : [];
|
|
68
77
|
const entry = {
|
|
69
78
|
matcher: "*",
|
|
@@ -74,7 +83,19 @@ function withPrae(settings, command, enforce = false) {
|
|
|
74
83
|
...enforce ? { onFailure: "block" } : {}
|
|
75
84
|
}]
|
|
76
85
|
};
|
|
77
|
-
|
|
86
|
+
hooks = put(hooks, "PreToolUse", [...groups, entry]);
|
|
87
|
+
if (start !== void 0) {
|
|
88
|
+
const starts = Array.isArray(hooks.SessionStart) ? hooks.SessionStart : [];
|
|
89
|
+
hooks = put(hooks, "SessionStart", [...starts, {
|
|
90
|
+
matcher: "startup",
|
|
91
|
+
hooks: [{
|
|
92
|
+
type: "command",
|
|
93
|
+
command: start,
|
|
94
|
+
timeout: HOOK_TIMEOUT
|
|
95
|
+
}]
|
|
96
|
+
}]);
|
|
97
|
+
}
|
|
98
|
+
return put(base, "hooks", hooks);
|
|
78
99
|
}
|
|
79
100
|
/** A line diff (LCS), `+`/`-` on changed lines, two lines of context. */
|
|
80
101
|
function lineDiff(before, after) {
|
|
@@ -151,7 +172,8 @@ function planInit(argv, context) {
|
|
|
151
172
|
return {
|
|
152
173
|
settings,
|
|
153
174
|
before: read.text,
|
|
154
|
-
after: next === read.json ? read.text : render(next)
|
|
175
|
+
after: next === read.json ? read.text : render(next),
|
|
176
|
+
skill: { path: skillFile(settings) }
|
|
155
177
|
};
|
|
156
178
|
}
|
|
157
179
|
if (argv.includes("--shadow") && argv.includes("--enforce")) throw new Error("--shadow or --enforce, not both");
|
|
@@ -192,16 +214,36 @@ function planInit(argv, context) {
|
|
|
192
214
|
"--settings",
|
|
193
215
|
quote(settings)
|
|
194
216
|
].join(" ");
|
|
217
|
+
const start = [
|
|
218
|
+
quote(context.node),
|
|
219
|
+
quote(context.bin),
|
|
220
|
+
"hook",
|
|
221
|
+
"claude-code",
|
|
222
|
+
"session-start",
|
|
223
|
+
"--dir",
|
|
224
|
+
quote(dir)
|
|
225
|
+
].join(" ");
|
|
195
226
|
return {
|
|
196
227
|
settings,
|
|
197
228
|
before: read.text,
|
|
198
|
-
after: render(withPrae(read.json, command, mode === "--enforce")),
|
|
229
|
+
after: render(withPrae(read.json, command, mode === "--enforce", start)),
|
|
199
230
|
command,
|
|
200
231
|
dir,
|
|
201
232
|
pack,
|
|
202
233
|
ledger,
|
|
203
234
|
key,
|
|
204
|
-
...copyPack === void 0 ? {} : { copyPack }
|
|
235
|
+
...copyPack === void 0 ? {} : { copyPack },
|
|
236
|
+
skill: {
|
|
237
|
+
path: skillFile(settings),
|
|
238
|
+
text: skill({
|
|
239
|
+
mode: mode === "--enforce" ? "enforce" : "shadow",
|
|
240
|
+
prae: `${quote(context.node)} ${quote(context.bin)}`,
|
|
241
|
+
pack: quote(pack),
|
|
242
|
+
ledger: quote(ledger),
|
|
243
|
+
publicKey: quote(key.replace(/\.pem$/, ".pub.pem")),
|
|
244
|
+
settings: quote(settings)
|
|
245
|
+
})
|
|
246
|
+
}
|
|
205
247
|
};
|
|
206
248
|
}
|
|
207
249
|
/** Write what the plan says: the state directory, key and pack, then settings. */
|
|
@@ -225,14 +267,77 @@ function applyInit(plan) {
|
|
|
225
267
|
mkdirSync(dirname(plan.settings), { recursive: true });
|
|
226
268
|
writeFileSync(plan.settings, plan.after);
|
|
227
269
|
}
|
|
270
|
+
if (plan.skill.text !== void 0) {
|
|
271
|
+
mkdirSync(dirname(plan.skill.path), { recursive: true });
|
|
272
|
+
writeFileSync(plan.skill.path, plan.skill.text);
|
|
273
|
+
} else {
|
|
274
|
+
rmSync(plan.skill.path, { force: true });
|
|
275
|
+
try {
|
|
276
|
+
rmdirSync(dirname(plan.skill.path));
|
|
277
|
+
} catch {}
|
|
278
|
+
}
|
|
228
279
|
return print === void 0 ? {} : { fingerprint: print };
|
|
229
280
|
}
|
|
230
281
|
/** Whether a script path is inside npm's temporary npx cache (`…/_npx/<hash>/…`). */
|
|
231
282
|
function fromNpxCache(bin) {
|
|
232
283
|
return /[\\/]_npx[\\/]/.test(bin);
|
|
233
284
|
}
|
|
234
|
-
/**
|
|
235
|
-
function
|
|
285
|
+
/** Where Claude Code reads the managed settings file on this OS. */
|
|
286
|
+
function managedSettings(platform = process.platform) {
|
|
287
|
+
if (platform === "darwin") return "/Library/Application Support/ClaudeCode/managed-settings.json";
|
|
288
|
+
if (platform === "win32") return "C:\\Program Files\\ClaudeCode\\managed-settings.json";
|
|
289
|
+
return "/etc/claude-code/managed-settings.json";
|
|
290
|
+
}
|
|
291
|
+
/** Whether a settings file already runs PRAE's gate. */
|
|
292
|
+
function holdsPrae(path) {
|
|
293
|
+
try {
|
|
294
|
+
const groups = JSON.parse(readFileSync(path, "utf8"))?.hooks?.PreToolUse;
|
|
295
|
+
return Array.isArray(groups) && groups.some((g) => Array.isArray(g.hooks) && g.hooks.some(isPrae));
|
|
296
|
+
} catch {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* The target when none was named (PRA-215): nothing to do when managed
|
|
302
|
+
* settings already run PRAE, the person's choice at a terminal, and this
|
|
303
|
+
* project otherwise, said out loud.
|
|
304
|
+
*/
|
|
305
|
+
async function withTarget(argv, context) {
|
|
306
|
+
if (argv.includes("--settings") || argv.includes("--scope")) return argv;
|
|
307
|
+
const managed = context.managed ?? managedSettings();
|
|
308
|
+
if (!argv.includes("--remove") && holdsPrae(managed)) {
|
|
309
|
+
console.log(`PRAE is already installed for every user on this machine, in ${managed}.`);
|
|
310
|
+
console.log(existsSync(skillFile(managed)) ? "Nothing to do: start claude, and type /prae-quickstart for a five-minute tour." : "Nothing to do: start claude, and every tool call goes through PRAE.");
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
if (context.ask === void 0) {
|
|
314
|
+
console.log("No target given, so this uses --scope project: ./.claude/settings.json, this project only.");
|
|
315
|
+
console.log("For every project on this machine, pass --scope user.\n");
|
|
316
|
+
return [
|
|
317
|
+
...argv,
|
|
318
|
+
"--scope",
|
|
319
|
+
"project"
|
|
320
|
+
];
|
|
321
|
+
}
|
|
322
|
+
console.log("Where should PRAE check Claude Code's tool calls?");
|
|
323
|
+
console.log(" 1) this project ./.claude/settings.json");
|
|
324
|
+
console.log(" 2) every project ~/.claude/settings.json");
|
|
325
|
+
const answer = (await context.ask("Choose [1]: ")).trim();
|
|
326
|
+
if (answer !== "" && answer !== "1" && answer !== "2") throw new Error(`no choice ${JSON.stringify(answer)}; answer 1 or 2`);
|
|
327
|
+
console.log("");
|
|
328
|
+
return [
|
|
329
|
+
...argv,
|
|
330
|
+
"--scope",
|
|
331
|
+
answer === "2" ? "user" : "project"
|
|
332
|
+
];
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* `prae init claude-code …`: print the diff; with --apply, write it. At a
|
|
336
|
+
* terminal, a missing target is asked for, and so is the write.
|
|
337
|
+
*/
|
|
338
|
+
async function initClaudeCode(given, context) {
|
|
339
|
+
const argv = await withTarget(given, context);
|
|
340
|
+
if (argv === void 0) return;
|
|
236
341
|
const plan = planInit(argv, context);
|
|
237
342
|
const removing = argv.includes("--remove");
|
|
238
343
|
if (!removing && fromNpxCache(context.bin)) console.error(`prae: warning: this prae runs from npm's temporary npx cache (${context.bin}).\n The hook entry would point there, and npm may clear that cache: the hook would
|
|
@@ -244,29 +349,33 @@ function initClaudeCode(argv, context) {
|
|
|
244
349
|
console.log(`pack ${plan.pack}${plan.copyPack === void 0 ? "" : " (the built-in baseline, copied here)"}`);
|
|
245
350
|
console.log(`ledger ${plan.ledger}`);
|
|
246
351
|
console.log(`signing key ${plan.key} (generated if absent; 0600)`);
|
|
352
|
+
console.log(`quickstart ${plan.skill.path} (/prae-quickstart, offered once in the first session)`);
|
|
247
353
|
}
|
|
248
354
|
if (plan.after === plan.before) {
|
|
249
355
|
console.log(removing ? "\nNo PRAE hook entry in this file; nothing to remove." : "\nThe settings already hold exactly this entry.");
|
|
250
|
-
if (
|
|
356
|
+
if (argv.includes("--apply")) applyInit(plan);
|
|
251
357
|
return;
|
|
252
358
|
}
|
|
253
359
|
console.log(`\n--- ${plan.settings}\n+++ ${plan.settings} (after)`);
|
|
254
360
|
console.log(lineDiff(plan.before, plan.after));
|
|
255
361
|
if (!argv.includes("--apply")) {
|
|
256
|
-
|
|
257
|
-
|
|
362
|
+
if (!(context.ask !== void 0 && /^(y|yes|)$/i.test((await context.ask("\nWrite it? [Y/n] ")).trim()))) {
|
|
363
|
+
console.log(`\nNothing was written. Re-run with --apply to write it: prae init claude-code ${argv.map((a) => /^[\w@%+=:,./-]+$/.test(a) ? a : quote(a)).join(" ")} --apply`);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
258
366
|
}
|
|
259
367
|
const { fingerprint: print } = applyInit(plan);
|
|
260
368
|
console.log("\nwritten.");
|
|
261
369
|
if (removing) {
|
|
262
|
-
console.log("Only PRAE’s hook
|
|
263
|
-
console.log("are: they are the evidence of what ran.");
|
|
370
|
+
console.log("Only PRAE’s hook entries and its quickstart skill were removed. The ledger");
|
|
371
|
+
console.log("and key stay where they are: they are the evidence of what ran.");
|
|
264
372
|
return;
|
|
265
373
|
}
|
|
266
374
|
if (print !== void 0) console.log(`ledger key fingerprint ${print}`);
|
|
267
375
|
console.log("New Claude Code sessions run every tool call through PRAE.");
|
|
376
|
+
console.log("Start claude, and type /prae-quickstart for a five-minute tour.");
|
|
268
377
|
console.log(`Read the record: prae report ${quote(plan.ledger ?? "")} --out report.html`);
|
|
269
378
|
}
|
|
270
379
|
|
|
271
380
|
//#endregion
|
|
272
|
-
export { HOOK_TIMEOUT, MARKER, applyInit, fromNpxCache, initClaudeCode, lineDiff, planInit, quote, settingsTarget, stableNode, withPrae, withoutPrae };
|
|
381
|
+
export { HOOK_TIMEOUT, MARKER, applyInit, fromNpxCache, holdsPrae, initClaudeCode, lineDiff, managedSettings, planInit, quote, settingsTarget, stableNode, withPrae, withoutPrae };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import "./src-
|
|
2
|
-
import { c as renderNav, l as renderShell, s as esc, t as navFor } from "./views-
|
|
1
|
+
import "./src-DO3IFxZ-.js";
|
|
2
|
+
import { c as renderNav, l as renderShell, s as esc, t as navFor } from "./views-Hh3G5zpv.js";
|
|
3
3
|
|
|
4
4
|
//#region src/console/instructions.ts
|
|
5
5
|
const STYLE = `
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as evaluate } from "./src-
|
|
1
|
+
import { i as evaluate } from "./src-DO3IFxZ-.js";
|
|
2
2
|
import { a as scan, n as MAX_SCAN_BYTES } from "./src-9phPLfAL.js";
|
|
3
3
|
import { readFile, readdir, stat } from "node:fs/promises";
|
|
4
4
|
import { resolve, sep } from "node:path";
|
package/lib/playground.js
CHANGED
|
@@ -673,9 +673,13 @@
|
|
|
673
673
|
}
|
|
674
674
|
return out;
|
|
675
675
|
}
|
|
676
|
-
/**
|
|
676
|
+
/**
|
|
677
|
+
* `git*` matches `git`, `github`; `*\/.env` matches `apps/web/.env`; bare
|
|
678
|
+
* strings match exactly. A `*` stands for any run of characters, `/`
|
|
679
|
+
* included.
|
|
680
|
+
*/
|
|
677
681
|
function matches$1(pattern, value) {
|
|
678
|
-
if (pattern.
|
|
682
|
+
if (pattern.includes("*")) return globMatches(pattern, value);
|
|
679
683
|
return value === pattern;
|
|
680
684
|
}
|
|
681
685
|
/**
|
|
@@ -686,13 +690,25 @@
|
|
|
686
690
|
const source = pattern.split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*");
|
|
687
691
|
return (/* @__PURE__ */ new RegExp(`^${source}$`)).test(value);
|
|
688
692
|
}
|
|
693
|
+
const SHORT_FLAG = /^-[A-Za-z0-9]$/;
|
|
694
|
+
const FLAG_CLUSTER = /^-[A-Za-z0-9]{2,}$/;
|
|
695
|
+
/**
|
|
696
|
+
* A token pattern against one argument. A single short flag (`-r`) also
|
|
697
|
+
* matches a cluster that carries it (`-rv`, `-vr`, `-Rfv`): flags bundle, and
|
|
698
|
+
* a rule about `-r` is about recursion however it is spelled (PRA-213).
|
|
699
|
+
* Longer patterns stay exact, so `-rf` is not `-rv`.
|
|
700
|
+
*/
|
|
701
|
+
function tokenMatches(pattern, token) {
|
|
702
|
+
if (SHORT_FLAG.test(pattern) && FLAG_CLUSTER.test(token)) return token.includes(pattern.slice(1));
|
|
703
|
+
return matches$1(pattern, token);
|
|
704
|
+
}
|
|
689
705
|
/**
|
|
690
706
|
* Every wanted token holds in a segment: a plain pattern must match some
|
|
691
707
|
* token, a `!pattern` must match none. `["-rf", "!--dry-run"]` is a real
|
|
692
708
|
* force-delete, not a rehearsal of one.
|
|
693
709
|
*/
|
|
694
710
|
function tokensHold(wanted, tokens) {
|
|
695
|
-
return wanted.every((pattern) => pattern.startsWith("!") ? !tokens.some((token) =>
|
|
711
|
+
return wanted.every((pattern) => pattern.startsWith("!") ? !tokens.some((token) => tokenMatches(pattern.slice(1), token)) : tokens.some((token) => tokenMatches(pattern, token)));
|
|
696
712
|
}
|
|
697
713
|
const list = (v) => v === void 0 ? [] : typeof v === "string" ? [v] : v;
|
|
698
714
|
/**
|
|
@@ -708,7 +724,7 @@
|
|
|
708
724
|
const anyArgs = list(match.anyToken);
|
|
709
725
|
const pipes = list(match.pipedTo);
|
|
710
726
|
const shapes = list(match.pipeline);
|
|
711
|
-
const argsHold = (segment) => open && segment.openEnded === true || tokensHold(args, segment.tokens) && (anyArgs.length === 0 || anyArgs.some((wanted) => segment.tokens.some((token) =>
|
|
727
|
+
const argsHold = (segment) => open && segment.openEnded === true || tokensHold(args, segment.tokens) && (anyArgs.length === 0 || anyArgs.some((wanted) => segment.tokens.some((token) => tokenMatches(wanted, token))));
|
|
712
728
|
if (names.length > 0) {
|
|
713
729
|
const hit = parts.filter((segment) => names.some((pattern) => matches$1(pattern, segment.name) || segment.wrappers.some((wrapper) => matches$1(pattern, wrapper))));
|
|
714
730
|
if (hit.length === 0) return false;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"prae": "0.1",
|
|
3
3
|
"pack": "prae-baseline",
|
|
4
|
-
"version": "1.3.
|
|
4
|
+
"version": "1.3.2",
|
|
5
5
|
"rules": [
|
|
6
6
|
{
|
|
7
7
|
"id": "BASE-001",
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"when": {
|
|
28
28
|
"command": {
|
|
29
29
|
"name": ["rm", "shred"],
|
|
30
|
-
"anyToken": ["-rf", "-fr", "-Rf", "-fR", "-r", "-R"],
|
|
30
|
+
"anyToken": ["-rf", "-fr", "-Rf", "-fR", "-r", "-R", "--recursive"],
|
|
31
31
|
"token": ["!--dry-run"]
|
|
32
32
|
}
|
|
33
33
|
},
|
|
@@ -89,6 +89,8 @@
|
|
|
89
89
|
"inside": [
|
|
90
90
|
".env",
|
|
91
91
|
".env.*",
|
|
92
|
+
"**/.env",
|
|
93
|
+
"**/.env.*",
|
|
92
94
|
"**/.ssh/**",
|
|
93
95
|
"**/.aws/**",
|
|
94
96
|
"**/credentials*",
|
|
@@ -261,6 +263,8 @@
|
|
|
261
263
|
"anyToken": [
|
|
262
264
|
".env",
|
|
263
265
|
".env.*",
|
|
266
|
+
"*/.env",
|
|
267
|
+
"*/.env.*",
|
|
264
268
|
"~/.ssh*",
|
|
265
269
|
"$HOME/.ssh*",
|
|
266
270
|
"${HOME}/.ssh*",
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { existsSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { basename, dirname, join } from "node:path";
|
|
3
|
+
|
|
4
|
+
//#region src/claude-code/quickstart.ts
|
|
5
|
+
const SKILL = "prae-quickstart";
|
|
6
|
+
const OFFERED = "quickstart-offered";
|
|
7
|
+
/**
|
|
8
|
+
* Where Claude Code loads skills for a settings file: `skills/` beside
|
|
9
|
+
* `~/.claude/settings.json` or `./.claude/settings.json`, and
|
|
10
|
+
* `.claude/skills/` inside the managed settings directory
|
|
11
|
+
* (https://code.claude.com/docs/en/skills).
|
|
12
|
+
*/
|
|
13
|
+
function skillFile(settings) {
|
|
14
|
+
const dir = dirname(settings);
|
|
15
|
+
return join(basename(settings) === "managed-settings.json" ? join(dir, ".claude", "skills") : join(dir, "skills"), SKILL, "SKILL.md");
|
|
16
|
+
}
|
|
17
|
+
const SITE = "https://prae-ai.com";
|
|
18
|
+
/** The `/prae-quickstart` skill, written for this install's paths and mode. */
|
|
19
|
+
function skill(i) {
|
|
20
|
+
const enforce = i.mode === "enforce";
|
|
21
|
+
const tour = ".prae-quickstart";
|
|
22
|
+
return `---
|
|
23
|
+
name: ${SKILL}
|
|
24
|
+
description: A five-minute guided tour of PRAE in this Claude Code session. It shows what PRAE allows, refuses and holds, where each decision is recorded, and how to change the policy. Use it when the user asks for the PRAE quickstart or tour, or accepts the offer of one.
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
# PRAE quickstart
|
|
28
|
+
|
|
29
|
+
PRAE checks each of your tool calls against a policy pack before the call runs (a Claude Code \`PreToolUse\` hook), and records every decision in a signed, hash-chained ledger. Walk the user through it, one step at a time. For each step:
|
|
30
|
+
- say in one sentence what you are about to do;
|
|
31
|
+
- do it;
|
|
32
|
+
- say what happened and why.
|
|
33
|
+
|
|
34
|
+
Keep it short. Stop and wait only where a step says to.
|
|
35
|
+
|
|
36
|
+
## This install
|
|
37
|
+
|
|
38
|
+
- **Mode:** ${enforce ? "**enforce**. PRAE returns its refusals and holds to Claude Code." : "**shadow**. PRAE records every decision and blocks nothing: a call it would refuse still runs, and its ledger row is marked shadow."}
|
|
39
|
+
- **Policy pack:** \`${i.pack}\`
|
|
40
|
+
- **Ledger:** \`${i.ledger}\`
|
|
41
|
+
- **PRAE CLI:** \`${i.prae}\`
|
|
42
|
+
|
|
43
|
+
## Rules for the tour
|
|
44
|
+
|
|
45
|
+
- **Make every call yourself, with your own tools.** Never suggest \`!\` shell mode: it runs outside every hook, so PRAE never sees it.
|
|
46
|
+
- **Work only in \`./${tour}/\`,** which you create in step 1. The credentials file there is a synthetic canary, not a real secret.
|
|
47
|
+
- **Report what actually happened.** If the pack in force decides differently from what a step expects, say so: the pack decides, not this guide.
|
|
48
|
+
- **Never work around a refusal.** Seeing it is the point.
|
|
49
|
+
|
|
50
|
+
## 1. Set up the scratch directory
|
|
51
|
+
|
|
52
|
+
Use the Write tool to create:
|
|
53
|
+
- \`./${tour}/notes.md\`: one line, "PRAE quickstart scratch file."
|
|
54
|
+
- \`./${tour}/credentials.json\`: \`{"api_key": "prae-quickstart-canary-not-a-secret"}\`
|
|
55
|
+
- \`./${tour}/build/app.js\`: \`console.log('build output')\`
|
|
56
|
+
|
|
57
|
+
These writes are inside the working tree, so the baseline allows them.
|
|
58
|
+
|
|
59
|
+
## 2. An ordinary call: allowed
|
|
60
|
+
|
|
61
|
+
Read \`./${tour}/notes.md\`. PRAE says nothing, and Claude Code's own permission flow is unchanged. PRAE never answers "allow" on its own: it can only narrow what Claude Code would let through.
|
|
62
|
+
|
|
63
|
+
## 3. A secret: refused
|
|
64
|
+
|
|
65
|
+
Read \`./${tour}/credentials.json\` with the Read tool. ${enforce ? "PRAE refuses the read before it runs (baseline rule BASE-005). Tell the user to press **Ctrl+O** to see PRAE's own message: the rule, the reason and the ledger row. Claude Code labels any hook refusal \"hook error\", but PRAE's text says \"denied\"." : "In shadow mode the read goes through. The ledger records the refusal PRAE would have returned (BASE-005), marked shadow. Point that out."}
|
|
66
|
+
|
|
67
|
+
## 4. A destructive command: held
|
|
68
|
+
|
|
69
|
+
Run \`rm -r ./${tour}/build\`. ${enforce ? "PRAE holds it for a person (BASE-002), and Claude Code asks the user with PRAE's reason. Tell them either answer is safe here, because it is a scratch folder. Then **wait for their answer**. If they decline, nothing is deleted. If the command runs, they approved it. Claude Code does not tell you a prompt was shown, so do not report that it ran without a hold." : "In shadow mode PRAE does not hold it. Claude Code's own permission prompt may still ask. The ledger records the hold PRAE would have placed (BASE-002)."}
|
|
70
|
+
|
|
71
|
+
## 5. The record
|
|
72
|
+
|
|
73
|
+
Run \`${i.prae} verify ${i.ledger} --key ${i.publicKey}\` and show the result. Each row is hash-chained to the one before it and signed, so an edited or reordered row shows up as a break. The rows from this tour are in it.
|
|
74
|
+
|
|
75
|
+
Offer to write a printable report: \`${i.prae} report ${i.ledger} --out ./${tour}/report.html\`.
|
|
76
|
+
|
|
77
|
+
## 6. Why a rule fired
|
|
78
|
+
|
|
79
|
+
Ask the user to run this **in their own terminal**, not through you:
|
|
80
|
+
|
|
81
|
+
\`${i.prae} explain ${i.pack} Read file_path=./${tour}/credentials.json\`
|
|
82
|
+
|
|
83
|
+
It prints the trace: every rule considered, and the one that decided. Explain why you don't run it yourself. PRAE's pack, its hook settings and its signing key are protected from the agent (rule PRAE-SELF), so a session cannot change the policy that judges it. The ledger is readable, so step 5 works.
|
|
84
|
+
|
|
85
|
+
## 7. Changing the policy
|
|
86
|
+
|
|
87
|
+
The pack is the JSON file \`${i.pack}\`. The user edits it, never you. They check it with \`${i.prae} check ${i.pack}\`. The next tool call is judged by the new pack, with no restart.
|
|
88
|
+
|
|
89
|
+
${enforce ? "" : `## 8. Turning enforcement on
|
|
90
|
+
|
|
91
|
+
Shadow mode is for seeing what PRAE would do. To have it refuse and hold for real, the user runs \`${i.prae} init claude-code --settings ${i.settings} --enforce --apply\` in their own terminal, then starts a new session.
|
|
92
|
+
|
|
93
|
+
`}## Finish
|
|
94
|
+
|
|
95
|
+
- **More:** ${SITE}/products/developer-agents/ covers PRAE for Claude Code and other coding agents. ${SITE}/developers/ covers the CLI, the policy packs and the ledger.
|
|
96
|
+
- **Cleanup:** \`./${tour}/\` stays. The user can delete it. A recursive delete is held again, which is expected.
|
|
97
|
+
- **Again:** the tour can be rerun any time with \`/${SKILL}\`.
|
|
98
|
+
`;
|
|
99
|
+
}
|
|
100
|
+
/** The SessionStart hook's stdout: the one-time offer, then nothing. */
|
|
101
|
+
function sessionStart(dir) {
|
|
102
|
+
try {
|
|
103
|
+
const marker = join(dir, OFFERED);
|
|
104
|
+
if (existsSync(marker)) return "";
|
|
105
|
+
writeFileSync(marker, `${(/* @__PURE__ */ new Date()).toISOString()}\n`);
|
|
106
|
+
return JSON.stringify({
|
|
107
|
+
systemMessage: `PRAE is active: each tool call is checked against your policy before it runs. New to PRAE? Type /${SKILL} for a five-minute tour.`,
|
|
108
|
+
hookSpecificOutput: {
|
|
109
|
+
hookEventName: "SessionStart",
|
|
110
|
+
additionalContext: `PRAE was just installed, and this is the user's first session with it. PRAE checks each of your tool calls against a policy before the call runs. In your first reply, offer once, in one sentence, a five-minute guided tour (the /${SKILL} skill), then carry on with what the user asked. Run the tour only if they accept. Don't offer it again.`
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
} catch {
|
|
114
|
+
return "";
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/** `prae hook claude-code session-start --dir <dir>`. */
|
|
118
|
+
function runSessionStart(argv) {
|
|
119
|
+
const at = argv.indexOf("--dir");
|
|
120
|
+
const dir = at === -1 ? void 0 : argv[at + 1];
|
|
121
|
+
const out = dir === void 0 ? "" : sessionStart(dir);
|
|
122
|
+
if (out !== "") process.stdout.write(`${out}\n`);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
//#endregion
|
|
126
|
+
export { skill as a, sessionStart as i, SKILL as n, skillFile as o, runSessionStart as r, OFFERED as t };
|
|
@@ -674,9 +674,13 @@ function decompose(command) {
|
|
|
674
674
|
function segments(command) {
|
|
675
675
|
return [...decompose(command).segments];
|
|
676
676
|
}
|
|
677
|
-
/**
|
|
677
|
+
/**
|
|
678
|
+
* `git*` matches `git`, `github`; `*\/.env` matches `apps/web/.env`; bare
|
|
679
|
+
* strings match exactly. A `*` stands for any run of characters, `/`
|
|
680
|
+
* included.
|
|
681
|
+
*/
|
|
678
682
|
function matches$1(pattern, value) {
|
|
679
|
-
if (pattern.
|
|
683
|
+
if (pattern.includes("*")) return globMatches(pattern, value);
|
|
680
684
|
return value === pattern;
|
|
681
685
|
}
|
|
682
686
|
/**
|
|
@@ -687,13 +691,25 @@ function globMatches(pattern, value) {
|
|
|
687
691
|
const source = pattern.split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/g, "\\$&")).join(".*");
|
|
688
692
|
return (/* @__PURE__ */ new RegExp(`^${source}$`)).test(value);
|
|
689
693
|
}
|
|
694
|
+
const SHORT_FLAG = /^-[A-Za-z0-9]$/;
|
|
695
|
+
const FLAG_CLUSTER = /^-[A-Za-z0-9]{2,}$/;
|
|
696
|
+
/**
|
|
697
|
+
* A token pattern against one argument. A single short flag (`-r`) also
|
|
698
|
+
* matches a cluster that carries it (`-rv`, `-vr`, `-Rfv`): flags bundle, and
|
|
699
|
+
* a rule about `-r` is about recursion however it is spelled (PRA-213).
|
|
700
|
+
* Longer patterns stay exact, so `-rf` is not `-rv`.
|
|
701
|
+
*/
|
|
702
|
+
function tokenMatches(pattern, token) {
|
|
703
|
+
if (SHORT_FLAG.test(pattern) && FLAG_CLUSTER.test(token)) return token.includes(pattern.slice(1));
|
|
704
|
+
return matches$1(pattern, token);
|
|
705
|
+
}
|
|
690
706
|
/**
|
|
691
707
|
* Every wanted token holds in a segment: a plain pattern must match some
|
|
692
708
|
* token, a `!pattern` must match none. `["-rf", "!--dry-run"]` is a real
|
|
693
709
|
* force-delete, not a rehearsal of one.
|
|
694
710
|
*/
|
|
695
711
|
function tokensHold(wanted, tokens) {
|
|
696
|
-
return wanted.every((pattern) => pattern.startsWith("!") ? !tokens.some((token) =>
|
|
712
|
+
return wanted.every((pattern) => pattern.startsWith("!") ? !tokens.some((token) => tokenMatches(pattern.slice(1), token)) : tokens.some((token) => tokenMatches(pattern, token)));
|
|
697
713
|
}
|
|
698
714
|
const list = (v) => v === void 0 ? [] : typeof v === "string" ? [v] : v;
|
|
699
715
|
/**
|
|
@@ -709,7 +725,7 @@ function holds(match, read$1, open) {
|
|
|
709
725
|
const anyArgs = list(match.anyToken);
|
|
710
726
|
const pipes = list(match.pipedTo);
|
|
711
727
|
const shapes = list(match.pipeline);
|
|
712
|
-
const argsHold = (segment) => open && segment.openEnded === true || tokensHold(args, segment.tokens) && (anyArgs.length === 0 || anyArgs.some((wanted) => segment.tokens.some((token) =>
|
|
728
|
+
const argsHold = (segment) => open && segment.openEnded === true || tokensHold(args, segment.tokens) && (anyArgs.length === 0 || anyArgs.some((wanted) => segment.tokens.some((token) => tokenMatches(wanted, token))));
|
|
713
729
|
if (names.length > 0) {
|
|
714
730
|
const hit = parts.filter((segment) => names.some((pattern) => matches$1(pattern, segment.name) || segment.wrappers.some((wrapper) => matches$1(pattern, wrapper))));
|
|
715
731
|
if (hit.length === 0) return false;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { _ as canonical, a as verifyEntries, b as seal, c as unsealPrivateKey, d as generateKeypair, f as makeReceipt, g as GENESIS, h as verifySignature, i as tailOf, l as verifyBytes, m as verifyReceipt, n as Ledger, o as sealedKeypair, p as signEntry, r as readEntries, s as signBytes, t as verifyGrowing, u as fingerprint, v as chain, y as hashEntry } from "./src-
|
|
1
|
+
import { _ as canonical, a as verifyEntries, b as seal, c as unsealPrivateKey, d as generateKeypair, f as makeReceipt, g as GENESIS, h as verifySignature, i as tailOf, l as verifyBytes, m as verifyReceipt, n as Ledger, o as sealedKeypair, p as signEntry, r as readEntries, s as signBytes, t as verifyGrowing, u as fingerprint, v as chain, y as hashEntry } from "./src-Tshjqoz6.js";
|
|
2
2
|
|
|
3
3
|
export { GENESIS, Ledger, canonical, chain, fingerprint, generateKeypair, hashEntry, makeReceipt, readEntries, seal, sealedKeypair, signBytes, signEntry, tailOf, unsealPrivateKey, verifyBytes, verifyEntries, verifyGrowing, verifyReceipt, verifySignature };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { appendFileSync, closeSync, existsSync, fstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
1
|
+
import { appendFileSync, closeSync, existsSync, fstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, rmSync, statSync, unlinkSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join, resolve } from "node:path";
|
|
3
3
|
import { createCipheriv, createDecipheriv, createHash, createPrivateKey, createPublicKey, generateKeyPairSync, randomBytes, scryptSync, sign, verify } from "node:crypto";
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { n as FRAMEWORKS, r as cite } from "./src-
|
|
1
|
+
import { n as FRAMEWORKS, r as cite } from "./src-DO3IFxZ-.js";
|
|
2
2
|
|
|
3
3
|
//#region ../tokens/src/fonts.ts
|
|
4
4
|
const FONT_FACES = "@font-face{font-family:'Space Grotesk';font-style:normal;font-weight:300 700;font-display:swap;src:url(data:font/woff2;base64,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) format('woff2')}@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:400;font-display:swap;src:url(data:font/woff2;base64,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) format('woff2')}@font-face{font-family:'IBM Plex Mono';font-style:normal;font-weight:500;font-display:swap;src:url(data:font/woff2;base64,d09GMgABAAAAACdMAA4AAAAAXcAAACbzAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGkwbhnYchlYGYACEWBEQCoGKWO0iC4QyAAE2AiQDiGAEIAWDGgeJaRveSwXs2CNuBwSSVL8SUQQbx/YQ2CTZ/5cETsbOq4HXFBqKzknWpPZ4BDGyaqWy6mA9f+osQ7Ptj0anmwc8uo37SN49ZX6lzKiN0EDDF/ZFKXSLT5pLS5/3Rkgyy8Pzdv/v2vvMFT4YGZU8YZtUquHus4qKxmVcsn9QFevOEGyzQ8KcMbFgICEoIEhKprQSYmGhjTqjF+Xmvtf5P13kT5fhosKPZZs0p8lTkl5hRKzsnJzQ43n+b3jfDziSOAo4TgqCTuTDwZSG8CjIs9sJviqpgHdet7ek3ZLXzfxMFci5jDfestYFsS+O/IojXwI0AGCWQD9fV1X13T0rvWero10OcrwLOQaq/8vQOx6PT7J01uVAdmrHR5DuckjxIdvasHCaSH08CEQXKLpleTA7CKUwaraFqF9+s9d/dghLXEL5S5Ik3NtdThKExbhNF/ben4uOlOK/y6CyUBhFoaJCKAqVjMIppnSZrda2POcPIFQ4/TOVmT7fBte7Omu1Oh1YhzoTngOyDHQPB5M5PSBWIdYTK4TYEVTJdykJmiJtTej7a1l/2FoqbgHUB9F9ejnM4U/1e2LZSTzxWApW4CzEWIItSP8ad773HQJDQOoL+8Kh00C8bCOIHRHE3gjilQjizQji4/8VEiB6oERkRIMK9F3MC3rp5WYnSD07GmsB7ilurgNIMGh+CHl1Yycl4s8B5L6MEy7NOAehIj+7K6I/sCBRLcypCYMgIMA/3npu2AO3PHDFOScdtteDTX1YfWjYTlv0W2OZrYdpwwVm+dXwjtNMNHyiW6uG3+pqdwISY3IwRd0JE7PQPJ01yIbQG0tCLBJJF6bEiFLSjMJdgLgEIyJJ09RCtDzvUxyeQUQoeBLb01AcpEJt2tZWdPWikY2nNuMJl64wJE2YwhJ2zXn6rpxrx0/fBSGeXkw+XgJEC4gOJBi0K0prsBQjUSBgtJ4kPfdKvTcM75Wb37vxy/al7EqJ+W66kJM1uGbbqJrvgU19UkXJgOfvRS3IBi30YoYQKEHYIpbLQpHRQpYwSRWpmCVNuIIRhogET2Ihn/bQoe6HG4emgm1AC53H4Uk+xQQBhcMh4nqm7wY7G5wIkshUvflbugaOYw6Vjv6boWjrGd53n78B5O/7cNXV+4F7wL+5ogNg78Pb4m8ERhxDsUBygoo7r6+ddTHMS0cgXFSEndN6S9phQSIjKkZGNGql+gYBhwRCgiDB3+YPG62kXnvbHgHC6eRAxbI0uvJfWaNSlhQjBRhr+wXU/WRHNfUJmIOhLvaE+JnpnxEvobWmrnjlWy8m1N9COB0DGVascD/x278I/5R4EUtrranvC9m+RstjL6S1pv4ZkRaYYbqJOjWqViJXFiMVETYqgjdce+RehC/P90j9nxYbFm5P4mOPQvEPj17Aq7XWWmuttdZaUxdSqM+gWnh8q5gUAkXGUZjC/uOVrwcEWkIl1bWlyr54gDdtgep6oBQODwLmJ5GZC3E0ZIcBCxzMrp8gZUeDMQl9kB183LvYKLxBBIEMGCTQbgOFBFMI1hIBBumJt+Dk80sR4Brt5sRdLOF1gwNCEcHwACjIMh54CHC09Z161WbB2Q8cPMMg378HqoBE3wMguwCyChgEHAiKBISNVgyAF0Dz8rmcAlwbIycQUshVrNNYPyCbcOTuPJo3UvAWFAKFQYOhRBwSh8JhcQQcGcfBiXAaXD+egP8DP5MwkhBD/j9+gJEDMYko5SnRZVlYkZW7ROwDSoEG7ReNi8eN6ikbJ1xsihECaNPc5MBywDG+xc4unsWsO6sC//+Ph35tmQWwfCwTluXL6GXc0rW7pqXSpZLF8kU7CLgYcBfgYcCj2oE4FQDiePvsIY4NpvWVjo1yWDTrUU7BLF+BJm0N4L+5XokMJmN0GyuPklepQi10PoO4R4VirYnhMckUE01VqcpHNeq4TaBW64MGHU4745Mh1cb5AT5TL9sTDz2Va4M+/TZZb6PNtthpux3+ttuAQbtss8cBe+1zyH6dDjrhqGOOO+mIlX4yTa9fTPezX/1mlj/MMNN8c8w1z+8WWmqRxZZbossyf1ptjbX+sso6h60IDAKFBEDg4Ho2WewyOUAUXX1T8KYxgdgKkCcCcRSwYQFg6w+ongfyMwD5Slvsh8u5IpLJYYmaMtiPwzFc3CzCCXJe07h/D3TNsJEVhcQnVsjjxHYKQBUhmH/jQ42MK7dAZIA1lzqe0seZd+cx8axHW7rw/Lo0486tmM4ha9YRKY84RnMVyyYSYXVa16ppErUklynSMkZ1KVwilMECLhiU82CZLC3yZU6yhD1lzL3AylPVY5dNo1p8FfBz4+csU8b5DNo+C03aCM0XRPlBNqAeIInynLMwoKEplbx/Xp1uxUJN13yWL9Y0waE/bek7L68UZ4uvog3ihruf98hsGzU/WIyty281XMZgKbMg9Du5LKEPo8qccuTrUp8pIM2ZUKeIUAWKeBeM46pQtcszUUMXCVupynCo46ERF9svG41+VrN/jySKCOEifHVGOPuSFmEDMMrxGsFgASb3K255QWzDw4TcIK0ZSYO0DlVMIygwBR8Z+CDNY+gIAPxx5xw6gyQvA5MipD4bGlo0soqP27j3IBQL849GnQbS6tpIftgHgXzJRPCPa3+zbBg6UOgcEmZQJisgEGaCnL8RrwZbKpx9Fs5nxqd5n4AvnD/AHumD+AuOW92e2Swohe8aMHMetQJuWfRmrULfqIIoAVM50QWfa4WMVTRkc1I1w7hYUJhWE5iMX1GhRfiByO1yhpuJor7zMfJlWe60CskE7qUxJeeWwq+BdGR7NQiimkTjhD3EikKUnEKJgr3EySSj0FoiPa9BE6v4W17j7EZRUBL29gox0j3p3soVN4sHNuHD8/ON3PyWFxdi5vJLYogA5Xazc6tuDETrblIo4JRVgmGRaXt8ImeTiFnIMOEwUbUI8ZAxZleVfcuKja3ao0aJWUr3UU6WJZiN/kj3KKrS68VRh1wLea2Q4iwcLa+9jpJtFii35NvDxkoUvb76MLOHKs3c3mVCf+5ihw2rYr4C912QtDZ2tOhQXxyo+od1w20hudj8VQzpAhuxhSmLm5h36VAGDAjYMjDVolYMl8DJY4ilipDzL8tEq1mnDCY4lHimhLBwox0cZY3owzYVm0CLTaHXXIYQZQQqqUhOfsi4GgjaRXmk+Y5rYozQkGpomAo13OBy0H6jTNSq3EnfhUumbCpXcWU2RsPg7wZb6E7aYLWxHLaQiKoBui+iWAuHQMU0+IwXkhu2XfFno6lLRG7J7JITdnk5iD8DPBtFaQTIIm7yJaxgRV4Ku1hy1tjl6r9H7UKoPU0s+74kl2uUzlndsH5wKHoojdjbwF2ObmzskrlNMwbSUtuzWokS4Epz7bTQXAcGCuSYGcbceFeovYQuGVJyKQt14olv05J3kQ7tNd0nR7TC+kOxC7fBnwu0kH2TVFEe6k8HrhIH78mPIUV7QP+2HaT/BOadgx/1NXeeGpSzK8gfa27qGT6J/cBF7iSayCf1Zk5pYYa9K2DcsCFB2c+y/DrqIsAX9FBECd9Qbt0+mLI0pJF9hqxqDYpPjGYkmy3DmbxB32BfH9+02jCztRWKttIi0UIaLs90J3HSdy3xQFgJx0s1JCzRZAyjQjZwgz6pR4vuKROhM9SGlRyKPuOvtVJKc2ZkeqAanT3BcSZuc2aqXXGw6NBHFaL/Z6PolTJ2hCuckZwSgba3hQ+yXCbknUc+7G0/5QQKSB6QAheYO/GwJzoU+SDvXgLdUjlrPCFJTdIIHOqUYa40fKBfHB4/EqtDpXMa6v0NgjIZlW7Jt2WQvK93ECqAMq41NHuPDvL1PM2jsJhK+/sEYQwYEQ3ON0xtFVW46l39rgKnHRzRYKDxHb7Zvc23chPYcM1SDXkZAsNj/nRtva6APcED6Qh7DvST/q+OBiOLsMn4Rd6ZFFZ06WEZRJ2PRdxinM3d09f+njwIuNm6kz7qb+R1kHk7ftjXICW+Suui4e8AW2zQdx/Mi4wM9iGKwEH60mwbzscSClWhjZXpz33qWTgiNnckUnhl3bb7Wou1JW8YQ7Jibu4sjOUoIH4Xi57FxXbV1eieRiDM2M9dqwB1WEKUYcm3okEHURnv7ZZtvjLCIEnsDEzCjNswQ1aCZWmp1qQfUsuitkVNSzCcVG0DoNa8bVh6KveKUuoAMR2E0j4y9xhpFFwhDDXK1LDqF+/IHQtBu1Om5bmHb5vBH+2MHSXJ4EYBuKFG0OBI7i0UPENuUaq9/g2FiHjET/rJIt0F9nqsnRz1CCjEsLKT7SBullE1/aq5FuEodIHh/EaqycHJGR91ofOEtetzso8y0/0VZ+CWSVRTIIp+K92Qtacm48v1ghipp+B0lqQqhNJiap8gMWpqlX8DbPVond8Z51FU0YogPytlCGu/3jteiVgLBviwDzQq8/WgTrr/RlnZp3XPQIqCpv+W5QbeGdm9GizG6MoygsPJvK3/fJ+9O/J9lVChrBUCWxm4L48TAtR8gu1cokCC1PxSImKcQ5atMigbakvWCUyWD2iBwygXsQhQ56W/Cn6IudAwsJDPmfEKXdlW41N9gq65ACee2UOaTc5fu25EtvBv/vDpeHjFbvjD8AL7crvJu95kkGR87X3cOUse+/MmLvjEGnzFWAMRX/lwhuONTF+KlHL71wutVGJ+7CuxqnKUPPDgZ5pRVIj9qyQlaP99DjtCyzDGrmloC4EUwnyHJbNxHMiPLYfkVAZGKpILfwtlpowqQlHA5ntiye9kT1a020bozTTW8rY+usHzpqj1lVmX+gHi5j3eyhV/9rD67xFVDkeM27G6VvGJzCdR99OYlUapdoWoNKEhV3/UrRHRFvHN3EQGhY/K2V0MHlfpbuGhJ5Kvn2zsAikz/5QDLw4pgumYWB61swIao+I8DZClX+wygO3z9b4NtBSN39TLHoxIUsallqsIhsVrFc5KDkakxyvSdtFPqLdI80MVxsUJDtbfIS2e/HlBuEjjWZFYtvdilcxmMxwvsKgNpn99KqSU8AitH85bRKsvKMikOT3nWc9S4lsFTDK6eRRRp150UdBD43N2NUda39tS15KvbdS16efUn22/a1P85fbfS+nJerYGmZ+6xLxwfzU+0cTVMtjJq+S5jUt6z3waMVt/Y8THpnbPpbALTdcHnY+F5K0Keaf8TR5bj/ZOfC7ZCz4ueUuF0+wCNmcqINnInmhQbxzA9J+GFs6u0Q+PrU0Q+8zuPJ3xppQUY3YICMdSaBxcTzxIpx5tg9Pt6I4AYa7B68qBIelKfVvpikjYT7krKY8dXFh82Enz2Max4P+0Fzr4cytHaivIyjDVWZtKU6rq2VdsCm5OhSSrpL4gB6p0k9U8dRrZVNyqRxJHgoXZiDoTV5hXM7Wnh515wrLJ1iE8fpi/2Ry/8AMhvj+e8GFhvExlkjvlKhOwPvQLsN775o8TZI8sFshCRbkkmRZXKpMx0ZZNWWgvUrc46Rd76TK1UeaWqk0K5lCMjTmlTBOJ3hH4Hz120kPFBSS5Fl8ikxFKZbocEj89O0mqxhUIKY1RUpNZzdZRHWrxompp9nEMNImFDYSGSDUGYMle7dzo2Vggkhs0GzxHph0h4pwehP1AyLdPMfWqcyN/+wVDfb4uZP5DDDm9F/6YYxNQMKo6cwIzfVkUNo7odbfHxxJ1aXfuongm4TKSHxN/k9BcmWct06GW8LdmpmCChZkyRVKfgxdFRVOjeC93DXA89AvgTZNFP9rWwjKv2S/pqonpfIeP9fqBqZgKSYhJgFAOn2hE8CbnJg+mf7XnICiufzTqX092hkhh0JyK2kr1dL+D7If+fXB71u8/TTh38qlg0tbPetVOPzBm93H7PPE/93kOgVRYgRq+6TSVcsoNuxCZJmE4MmsKCtLnYVAEYmvYZhoGvWjghPk9ESsAtFCh/AA+BR+NridwSXQGg9UQ7ZLTIoAV6vdIclY4/31kGYmn/DGnWol8zJiye529nve9iOo/muckyyrLJSad5MAuz2aQGups55lVYqSTLOIpiOTI7QXHXmWGXTwPHqbY2jNLDZVU0tn0DLLUr8UPv9lNe3TWrLXdA0wauUFEWeoZjWnFTijfcctzy8mTAHOyc2OVuDivH+YH/+yEjtZdV51BeJiJvzIC0dAC1uZg8+Zqk38MsDfn6KE9mt+Ctb/1APo++N/fxqmLeRYE16Iubt356UDweHMd14TgmEx14CC07lMFS8GSZns6Ga1nvzZmXpVvQqgGwFIkNKV5/oJa4wFnuAN3sHPj0MD8x2KsIcjF2gayBl4VVha7pGI9A346w2qgofVcw6jUsH9cgj2cJM4eQfeTGj6vkpnErOTVXgHy0Cnjd61fP37XFI4R5bVu9eHbhLcnYI3qhqLWImfSiJ1wW9jmw2+1eo0okDlwrmf85r4+Nug5dzzPYiwvai7C49eSGwDcg9u92iGhV3hZ6wXuwQPezCG2l80B6wsDJ/dYWAS/f2DdljG7JnLMaK9shQ/fKjg7AZOhaCiqZ46wBdnIUoVBKJ/qfFZWDpayhzkNgw2UYYo5ErC7VkWucu28/uD/gR8LbMYkG5qVX5sXYa+KmZ7AY1VLZ7zxgiiFo/La7VVY4c6mddcnPCY9nzke1EqjfJkX7LYEnA/6qXwgQdNVs5YO9lYjA2uQEwZLwZb44ISSwd9P6asAtFBVEVOWh5nidmF6AItNRft7XO4tgnrKfJO0obilKAqmOa2otT5wDsJ9lfUlJf5T6Zsd2zS5sohWWDkZfNowXiPWicgGC5+dG9dl8e24LCgdqIp0LDrd5z5UbzyH7ZYKQ+gyYvfMhIIpOZWFtMLKnn8AKTSvS96s14zLSRWqdGIBnfmvKTROnTSDQSwdV97gaObKtdqDVqpIpuByaDhFSEZYQaSr3MjE2RR8LxaU5uU35N/0kr1g28B6Gkzb8IlK/dQA09LWN8w3RTawjLmkjAyCEyyGpvngzuGBjrxCyf+I0Z9f2Pw1BibWQEn87JAtQdal9SBBc/2E2V7WwBzdzCCYBbpx1t6MSQjTpMzetstlxx3jdN368fCXuYzuthMO8Dbw6ZYxnvX6WQjDLM/6TrWYQJDysbTuY7H3VjekYzJenWdWNBS1F/nDmsn5seFmZjtzWbH5pPPEPmQsso9o/RkEnoLDoUHL+zXSzfvXF/xVAPAPah4eLRS5mKH8QaHo2d3ipN/zN9rRvHQndjbGSKfG61IVNy1//lIFwuerFQJaIPMBj6Ojt5kU7+d7tSNTWY64O3gVFa81JGyHX85d0ElmEI0qXsEoEcuInNH/IUs+X8eVqbSS9KB0g0Br8oLqaeYi4vmZN0o8JdOy7z5rQoDvHmnUh6B2NVNMN2Om4uwcLt79vYAgSTMgJy76kCk/dFD4DKtU66RBUo1akZbJzQ9LmDwD0EPFeSS5Dl8qN9OnZNTnuHfPGSy06Rxp+ceLV13qkuPpJkw71sbmEtwKaR5BkKPQauQhcngU8sVtAv4KyI+cUHznfsmXbEALlRVg3+EyUnUWx72gLGWmJLO9uL7eQ8Dizwq6d+DUpV6Qd9crknpUOiEvhqcTqk7hSoPkEXME85HEzAKE7dHpguxdsig/8t4PC17s8vj9fINLoQw9Fp6gowj5FZqkK4QMKvkMRhOfTJx59lqznbI3lkh+TgqM6Eo8ajQVyLLgPmhh8GJXRk64Lrh7doejFLEiS5LkIVSHLdibi1aQgjn/gIP1zbYatqp81MLKJtxCWWF+ikTmIQmVqFxus1uM2HCFItaW19dry8WUq+sRCetmUG4lK6MrTRNEUUU0rZEsaNbuxDkIswgOHNEuV8jtYNYnP8MPxMB7zwsgXo8XiLdcwmnBzAoMClPBPCwWVMKSnsUmxT5LIn7Lm39bNkgidUvAm7kLu1Jc4NMA1UcFrIdOHmUhCHy4sJvivF/WyhjqKx/zcIafZmsF7Gs7wAo7rwp4sX0oBUJOgQyJSQwXJh7jYpAAiP//K7SfjGTk+7ufGYwDbDt6BtaQSk/UslSJJE/VQntAgUgezt7I4n7e7SX9llFjRuFYHCO7fwdxpn411phQbH9Gwhom5valZ+B6BE2m/KX+szaXuILYrMhXRDjDquysf4mpYB+eecBcD50qWLLdUlP+Cs/0TqRZzz85bwXTPpyfBOpeHiyFj5obzp8OPRWpHOOwOsYoI09Bpwu+rUXxU2C8TdbdCmT+2ocdsLs46go3wr2CirsL63i4Nh+p2G0F0R94e7L2m2Cvn/jhcyZM6XxjKm86U8xKWb0x0ROL2QdWnht9GHCtorlWFC/qgTV52qx8j4ck7SJco8bLqEyqDK+/C2oTchfRcjYU5yyk5a4OxanA196J3om+0u8V3ooClL7NwMsA8u0uc2wasxBdItT0DJM560j42K/aaEes3s5iCPSukPYkDeVGb3Wa47bl68tem/xy0ovfNFET3jXO3I+9GAHouzQ7/iYhi8VictObTAuy5X+yf8oHtCh5Ld3uYnRYzIxOC4NNTvs7zZYtAqMnHDdJpiLmcCScCGdYDZTz7rYV5lg9Ppcr12dOV7IClYS1oShiN0meVEvC0HcoiHANB9ByyCp0IlqVnMwkcRHIIi1iFCQSgdfkwQSwbFgk1sYKwMyee5GMAQ/uJRpJRVB1HBnqPio2KBaVyAUFS57auPe4tqcNaLOkEybt1KNFjVA3zDrHOgcGdTeC/gIcBgXr89HT1zDTbVyTOi7DQNh1+OOXuxSRxqxSrE5WDMxJKosLi7uEJmIxFEBz2XKK3W6SbMtwq4yynCqiLqfoRoBWTFagflQVZDKRH52LTBKgloQ+NclME9K2BwM3/SKTb/Vge5qZ27Z8UIZ2DciOFx0fmGEFVybN3JbloOdMp7M3uqndOTXpTF7nQF660hEXKnAjZL0lEHtnJQ/1tH4kwS+DpDkTGtKjMXjdBltERIW5UqE1BZ+lx/bk7DlWslIBKSznVs42beWgPFgCmdiVL2raywULFYqFfpsFCgV/5dDhz26kgPi4eJByGDF5yi28BnWZNy+KWJfza+X6l9XGHUHG7TXA2XKCm/TPRADtdstphtZvlCjZ2ITr31kkEuv79QQsW5oGG9QHRuecQgHaaM7vynpLqq5tCSqLw2H/El1bAzej8zuHVcZ2sBZJevci1sEAjBhdXRBe9nNdHcPptqx2Vj61y22ZtP6/31eRE16YGYVOhTKwcp2Bw9AP+YYYeg7Qh06eOrhhA36+J7P0cTrVdTdLvIOvyrCFaO9bnzifWO+HaDNsKv4OsZt1XaXTxwFD6+/JCnoUrtxt3hetSGbgzU+zMXxrjYhgUcxUUThCtVhJRPXvda9ChAZinpWevBpY5QOhITa4X5qm18SbUt8+Lo3XErfKklxVvsLgCmeFElHISTUoxz6edWllvJZ4UJ7krvaXhlY5C5uoz/OO+0Lj59DDp1/hZwOVe9uCbdljtoxuWz06cPXo5i2jx2Q7frS5AKaHCkxmoz3P5knn86xEPH+zFhdgkkvoV2AwwYNkq6OjQfI5RkWzUwmKjUZUxxIfD8+xCgWwPmV6QgY1h66lMUnUKOKxxF7KImHy6mThIiCNmKTfXS1FKgtkMWeFOhQznhgnh/0VTzet/3X6vbjoXyLC1mybOEJdMKLil7qp/jMGXNqTyftxttAK4v1yA75aps3B88V5STIVvkgiwuTzlSZimsTC68hKl+fPLZStcAvQxrTZf/4DH5Ej6l4j0Wm1cq1eKzlNDvBlfyquDVRqB0vtn54u3DlVatrtyDz5z9v5GaNwprPfPp+qv1nmNxlskRFrNZM1tcSD+eL/koXdZHK3MDkrnaIgl8GSzXZL5tSeHn6yWD1EJzRfkZxisrePlryKUVEzKbio34yoql81McBZLJIbtDPc/dOduYsvFwRXFeZV/eJvV7llVhNfGi+xsbOj3XNP/7/h+yin0+fjG0UZnEwfrBsYGJ294src7Ll3V2SHomqcOQ25QFb5Ca4GM9IcU0CylruFLtWhX/3CWaEOwcpoD4Z4z5I3cMeqiWGquoiqHUsng/2AbK3epU88OfVr7+TBa+Y8Ot4+/n9AC832MDONVFnFnoRxmQq81clUesZmKvGNT9Ljqepb7UjRdEeeppv0cA41GDVp7Oa+PvZNSkyJQYg7LNxirvI1+L6GFuAcbJg601dZX1xEV9E3c8aLSVVemrdqEnAcO+UXjKuM6bw8CX/OeuBN6i9L0YnbP8EjKyeBbQZZ+bMCxtM2iZOTJwODhjhde2Hw0wRY/NME7O1WTcJldbpMoZWy4j5s9lrtggMARSYMj4Qhr6K4N2mm+xy5kUsnnnwLJX0hs+0itVhJofUdrcXjQuJhCVp8sgLQfHplriMLFr3ekuUI1/EJ/SnKlH7C4ah4T9SekOCQPVG/7mDXqtyrDuryqnRrjF30Bmzs87uu9sTBRs6OTRjquWqXPd2LEV+jxjz4XSpTsdaLvgKyL/3EZ+cqMQZ9DBkYQ8Im8vHY7ZFBUavi0nZeFY1lCNVpFFzPYRhsDZGu5wHFuiXKaafzbjB4DIWuZR6sbC6g+Hjz/+Vuo6Exd+Nhcf8lxGyuuBq294Z4dVA9fA2GyHjE4WjVINUn1xgkxDruibpyVardvMw+oZFEn8vk6pTbR52KD4k/hTncZqB4XLNS3vVV1hJpATSfXJ1OJfQ8ha3lYckXJJILZCxvLexpD4F6FC47jtoRHRS9AwVHTZiBvoYMQl5DTwycqA7DIQt9JPB1wY1NGjyHWyJsM0VbhLdC3ubwtgNvHtmO4EPnpP6xDRq+bTSNZcJzhvKH4DnMsUbT7Vu3gPUc48205CXIAqtpkVGL/p/0BE+6WSdYcISQRQDHvKTbcdFxt0kH/UrKEKSrVIm5WwvoYN1wA2dYGYJYDqJt9vyWptamKm8MaFz060gZepQ06jXaLTlKOgoti3zdx+ehefzlhwKiV0ZmxB2bAN6gzfBjY4HgHN3Ukc0fXSqMzOyRPgIAwQnuYnBRCSdqly5kl7SDgahccMip0zlbPbRh0r2B9HnwB0U3WRgm+3T+OP1iDo62ExyElI3mZMaVIrJu8sMmBeca+39uyNaZhoVim3pw51UEZ2s2vDN4uy3hW47E9Ozz8QAEUIG0kgz0oc5oNIu4cZF5SfYkNJeOWXuvoXWc2MQ2ljUb3Z6VvPwEjDm/WnSDKRcdwdVuqLEb77Dkfj9anDwSQsz7+7er+6/7l/uP+5/8EX6KsM394n5sIkT4wDYODHbcT9yPzdnQOLAZEY5kQzC9n7gfJVL/KflEowk23w/ux2YsNBpBzfs7QP5qjNouwoAb7oa6I9yIsRAgDXm7iRMELIpw2HwHsiTUHdGaFLKb5CY5SWGEjDvqKmFytBM+D5XvxTFC8yFEmK1hRE5MZlZEuD6sEkbnWpNt8b2vY84cS+fTz8fP6UL6hfg5XUw/n34h/WL8nC6lX4qfS1/WlfQL6ZfSr8TPsVocV/8xC/RP/Uv/5p/+9S+Y7hcBzIHAf08u6ZvfenEZgAP60keAHT7Hoahwue9jUoaD91sfv2Hj3RmMA/mIbHHCyYMw4Lj6RKLMo5E2MPGMBMQUFeTG63JQZ+riDtaV9G2mlbgA8aK8xVK23GZUBQGixFZksCwn+rUAkV31azhP9AJu4z8FX2kBInvyEC0HNmCVFiAy9GtnkysYi+S4EgnkZeUA6KbJekBvRVNFtR+Vg9z14Koiumm4h2Af7oJuGu4BDDdOy1SpfZupsiK6abIekj1BS3RFdNNwDzkeRl6Lflm9HNr8A8P7tQqm2O/2ICQOPpbIx8L8gMae+baM201DNpsxjja5WejPcas5kWoTp7hmPLUJ/yII0qf/38aCdiL53QdDhwEW1vIDlj7tudnwbMUmVbWAngTBj1aO5i0XbcOvglhfEFvTA8dIkJuDzYxXJGgQ46SMfDyYLJUF32x4M2MtxQkTJHSSzULjQESWuW3SMJidHyu1JmD1htV/JJkE1ZJANGHGxEAnHTJYJPBMTGCDhGuzbSQGNC4r2fYCn5nHdi4gszw2DvrYbxp+u0YKojryOIvXfKAON1S/YYQIoIUIpjCJTrt1hMwISNBbZdBqv5oLuGyrnSYPAwksaDaCfqRmgdip+Oypygj5OJP4RjraCLepbESTNwdJCCKNSnIn2TEkpRqRgMI5mRYsjMUSFjGDlazlT1tF089ftlGbrTWYuQ611UYXC5nCW/psDLF/43FiiIoBjZ1oIJcTjGcxexa4SlGPElPhHsQA9gCO/y6IrfERVRVE1+MLvbPrwfNoFezW3uZGdzjSlu409kZ3cbq61sq9u2UzT3fbobj1mE4AD2se2huIpF3YpFSjKlk3l4ihqa6d6vqDP1EhjY2OWQYVC7taZdpZ1KtTj86ijE+VFn5uZRp5C5crcdgYOHsTc787jlgMWXXFcrZWsUa+fvwwzorjavUmINigIy1iRRpRDGozsfDhBGCE0OjKGXCUCrpEHFpsooSyCZSJrYILGQKsj10zhQUQvvVjK+DSBIDL6OgZZDAyMbOwsrHLlMXBycUtm0eOXHnyFUhCQpYsBQUVTSo6hjRMLGwcXDzpz0YQJO7/fTSkGLHixEuAgjZKsENEBgrespVKlD4YEfYXouU9f9tmu8OO2Gufv6yzEsxrCEINnU/Bq8hIcrsDA113G9Zjmp9M97PFlpgUOAQBRtouUizcj2Z6aSecRHiHTLXKHpMTCJ4SaKcqNWpVq+O3TL1/NWjUZLSrmrVq05Ig8JgOXbp1Wm6MzXo9N9Z4E4zzv0EnHFNivVIb/M6XYPC1MsedNOSU0844q9w551W46A8bbfLMJZdVuuI/c73y2l28waZlO+4zQn5mIMWIFSdeAhS0UTC91ZTYu95rwyMgSkJCliwFBRVNKnrXu9GvfqH2dxtDWncwsbBxcPGk4xMQEhGTkJKRU0CUEBVEDYYH+AKLGcW1zUzWbKmrYjK35rgbm62xAxOWCfplgujm4Ew2cmhKleLm4N9lDT0rpSiovq7s5G5uc4ghXxKFLRr89Cjr2VPVitm+qaodPyuLe8VffcW9bl9XVceJR89sQYBPCDBwgBcY8AsGDAjwCwd4wQEGDPgFpy+bFTiyzga72GSLbXazwh72so/9KZraNmSp56ggWU04gxVYZ4tVVlL6DA3sqyr7xxVOKy5taS6jIv+dmS3LwiX//96TJqS5qtZX9ne38BgMYggft8RLDPqIP7o145+bxjQN/koz/CKFhY9X+pFL/j0fAw4GEh0N/GotezbmMVMeAA==) format('woff2')}";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prae-cli",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.4",
|
|
4
4
|
"description": "Operator policy for agent harnesses: validate packs, explain a decision, test a pack against security invariants, verify a decision log, and provision a governed DSH profile.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh-plugin",
|
|
@@ -42,12 +42,12 @@
|
|
|
42
42
|
"typescript": "^5.9.2",
|
|
43
43
|
"vitest": "^3.2.4",
|
|
44
44
|
"@prae/controls": "0.1.0",
|
|
45
|
+
"@prae/extract": "0.1.0",
|
|
45
46
|
"@prae/instructions": "0.1.0",
|
|
46
|
-
"@prae/
|
|
47
|
+
"@prae/ledger": "0.1.0",
|
|
47
48
|
"@prae/kernel": "0.1.0",
|
|
48
49
|
"@prae/tokens": "0.1.0",
|
|
49
|
-
"@prae/
|
|
50
|
-
"@prae/ledger": "0.1.0"
|
|
50
|
+
"@prae/inspect": "0.1.0"
|
|
51
51
|
},
|
|
52
52
|
"scripts": {
|
|
53
53
|
"test": "vitest run",
|
package/lib/cli-DYKKNlDI.js
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|