cohorte 2.10.1 → 3.0.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/assets/manifest.json +193 -0
- package/assets/migrations/config/README.md +12 -0
- package/assets/migrations/state/0001_init.sql +154 -0
- package/assets/prompts/README.md +11 -0
- package/assets/prompts/agents/fixer.md +7 -0
- package/assets/prompts/agents/implementer.md +12 -0
- package/assets/prompts/agents/reviewer.md +8 -0
- package/assets/prompts/agents/security-reviewer.md +7 -0
- package/assets/prompts/phases/build.md +5 -0
- package/assets/prompts/phases/review.md +5 -0
- package/assets/prompts/phases/test.md +5 -0
- package/assets/prompts/system.md +11 -0
- package/assets/schemas/agent-output.schema.json +225 -0
- package/assets/schemas/auth-status.schema.json +87 -0
- package/assets/schemas/command-result.schema.json +192 -0
- package/assets/schemas/commands.schema.json +952 -0
- package/assets/schemas/config.schema.json +2259 -0
- package/assets/schemas/doctor-report.schema.json +104 -0
- package/assets/schemas/events.schema.json +8514 -0
- package/assets/schemas/fake-script.schema.json +549 -0
- package/assets/schemas/inspect.schema.json +3133 -0
- package/assets/schemas/manifest.schema.json +79 -0
- package/assets/schemas/ownership.schema.json +52 -0
- package/assets/schemas/policy-verdict.schema.json +282 -0
- package/assets/schemas/project-model.schema.json +783 -0
- package/assets/schemas/project-status.schema.json +217 -0
- package/assets/schemas/reconcile-plan.schema.json +154 -0
- package/assets/schemas/run-diff.schema.json +177 -0
- package/assets/schemas/run-snapshot-manifest.schema.json +2104 -0
- package/assets/schemas/run-state.schema.json +1755 -0
- package/assets/schemas/runtime-capabilities.schema.json +1545 -0
- package/assets/schemas/sandbox-capabilities.schema.json +116 -0
- package/assets/schemas/skill.schema.json +87 -0
- package/assets/schemas/spec.schema.json +202 -0
- package/assets/schemas/tool-catalogue.schema.json +655 -0
- package/assets/schemas/trust-record.schema.json +38 -0
- package/assets/skills/README.md +9 -0
- package/assets/skills/inspect-surface.md +4 -0
- package/dist/agent-host.mjs +2187 -0
- package/dist/agent-host.mjs.map +1 -0
- package/dist/bundle-manifest.json +104 -0
- package/dist/chunks/__host-DgGPyco9.mjs +18 -0
- package/dist/chunks/__host-DgGPyco9.mjs.map +1 -0
- package/dist/chunks/approve-Cv135UqI.mjs +19 -0
- package/dist/chunks/approve-Cv135UqI.mjs.map +1 -0
- package/dist/chunks/auth-BT5oVp76.mjs +132 -0
- package/dist/chunks/auth-BT5oVp76.mjs.map +1 -0
- package/dist/chunks/auth-CYOh60KG.mjs +93 -0
- package/dist/chunks/auth-CYOh60KG.mjs.map +1 -0
- package/dist/chunks/brainstorm-BwKA6yZP.mjs +7 -0
- package/dist/chunks/brainstorm-BwKA6yZP.mjs.map +1 -0
- package/dist/chunks/cancel-KV_cpsqS.mjs +15 -0
- package/dist/chunks/cancel-KV_cpsqS.mjs.map +1 -0
- package/dist/chunks/canonical-C8UxeEmB.mjs +57 -0
- package/dist/chunks/canonical-C8UxeEmB.mjs.map +1 -0
- package/dist/chunks/catalogue-BvwSrM_j.mjs +1549 -0
- package/dist/chunks/catalogue-BvwSrM_j.mjs.map +1 -0
- package/dist/chunks/compose-Dvxunpto.mjs +7307 -0
- package/dist/chunks/compose-Dvxunpto.mjs.map +1 -0
- package/dist/chunks/config-DefHA2Lw.mjs +96 -0
- package/dist/chunks/config-DefHA2Lw.mjs.map +1 -0
- package/dist/chunks/contract-BkMjU1kR.mjs +295 -0
- package/dist/chunks/contract-BkMjU1kR.mjs.map +1 -0
- package/dist/chunks/contract-bQ9FJl4N.mjs +123 -0
- package/dist/chunks/contract-bQ9FJl4N.mjs.map +1 -0
- package/dist/chunks/deny-ClTxSvHJ.mjs +15 -0
- package/dist/chunks/deny-ClTxSvHJ.mjs.map +1 -0
- package/dist/chunks/diff-Qw0II0sj.mjs +101 -0
- package/dist/chunks/diff-Qw0II0sj.mjs.map +1 -0
- package/dist/chunks/discover-eS01-me1.mjs +21 -0
- package/dist/chunks/discover-eS01-me1.mjs.map +1 -0
- package/dist/chunks/doctor-B-H2UK5e.mjs +222 -0
- package/dist/chunks/doctor-B-H2UK5e.mjs.map +1 -0
- package/dist/chunks/fix-D4Tj8RVA.mjs +18 -0
- package/dist/chunks/fix-D4Tj8RVA.mjs.map +1 -0
- package/dist/chunks/gc-BBXlBF5w.mjs +161 -0
- package/dist/chunks/gc-BBXlBF5w.mjs.map +1 -0
- package/dist/chunks/init-BUnzIkeE.mjs +63 -0
- package/dist/chunks/init-BUnzIkeE.mjs.map +1 -0
- package/dist/chunks/inspect-Buby4cQD.mjs +22 -0
- package/dist/chunks/inspect-Buby4cQD.mjs.map +1 -0
- package/dist/chunks/logs-Giq5sUau.mjs +25 -0
- package/dist/chunks/logs-Giq5sUau.mjs.map +1 -0
- package/dist/chunks/migrate-DybihKzZ.mjs +33 -0
- package/dist/chunks/migrate-DybihKzZ.mjs.map +1 -0
- package/dist/chunks/models-Btp6X2YZ.mjs +24 -0
- package/dist/chunks/models-Btp6X2YZ.mjs.map +1 -0
- package/dist/chunks/pause-BASBfKLO.mjs +16 -0
- package/dist/chunks/pause-BASBfKLO.mjs.map +1 -0
- package/dist/chunks/policy-DUIgzF3W.mjs +139 -0
- package/dist/chunks/policy-DUIgzF3W.mjs.map +1 -0
- package/dist/chunks/providers-Dx78imKj.mjs +19 -0
- package/dist/chunks/providers-Dx78imKj.mjs.map +1 -0
- package/dist/chunks/reconcile-Bhy3IIYo.mjs +50 -0
- package/dist/chunks/reconcile-Bhy3IIYo.mjs.map +1 -0
- package/dist/chunks/render-DyZr5Lgi.mjs +53 -0
- package/dist/chunks/render-DyZr5Lgi.mjs.map +1 -0
- package/dist/chunks/resume-GJQRb2Eb.mjs +15 -0
- package/dist/chunks/resume-GJQRb2Eb.mjs.map +1 -0
- package/dist/chunks/retry-CLrUem1H.mjs +15 -0
- package/dist/chunks/retry-CLrUem1H.mjs.map +1 -0
- package/dist/chunks/review-BDdjb6kB.mjs +17 -0
- package/dist/chunks/review-BDdjb6kB.mjs.map +1 -0
- package/dist/chunks/run-CgTWYlcd.mjs +82 -0
- package/dist/chunks/run-CgTWYlcd.mjs.map +1 -0
- package/dist/chunks/run-tool-C3rAv4XF.mjs +26 -0
- package/dist/chunks/run-tool-C3rAv4XF.mjs.map +1 -0
- package/dist/chunks/scan-8Gy_B6kI.mjs +122 -0
- package/dist/chunks/scan-8Gy_B6kI.mjs.map +1 -0
- package/dist/chunks/schema-C9QbUW4H.mjs +578 -0
- package/dist/chunks/schema-C9QbUW4H.mjs.map +1 -0
- package/dist/chunks/send-BdnJ85Nz.mjs +19 -0
- package/dist/chunks/send-BdnJ85Nz.mjs.map +1 -0
- package/dist/chunks/ship-DTuLGoaJ.mjs +19 -0
- package/dist/chunks/ship-DTuLGoaJ.mjs.map +1 -0
- package/dist/chunks/shutdown-BM92Iyv2.mjs +15 -0
- package/dist/chunks/shutdown-BM92Iyv2.mjs.map +1 -0
- package/dist/chunks/skip-DZG5kpcH.mjs +18 -0
- package/dist/chunks/skip-DZG5kpcH.mjs.map +1 -0
- package/dist/chunks/spec-Bq0P3jVh.mjs +20 -0
- package/dist/chunks/spec-Bq0P3jVh.mjs.map +1 -0
- package/dist/chunks/src-CId6kMsY.mjs +1689 -0
- package/dist/chunks/src-CId6kMsY.mjs.map +1 -0
- package/dist/chunks/src-CfAOde7C.mjs +5403 -0
- package/dist/chunks/src-CfAOde7C.mjs.map +1 -0
- package/dist/chunks/src-CmFjh4M0.mjs +928 -0
- package/dist/chunks/src-CmFjh4M0.mjs.map +1 -0
- package/dist/chunks/src-Cu3TxNob.mjs +783 -0
- package/dist/chunks/src-Cu3TxNob.mjs.map +1 -0
- package/dist/chunks/src-DcU4IXMe.mjs +117 -0
- package/dist/chunks/src-DcU4IXMe.mjs.map +1 -0
- package/dist/chunks/src-s7YRvk0t.mjs +2116 -0
- package/dist/chunks/src-s7YRvk0t.mjs.map +1 -0
- package/dist/chunks/status-SMjiOMYy.mjs +29 -0
- package/dist/chunks/status-SMjiOMYy.mjs.map +1 -0
- package/dist/chunks/tail-BuhT-2PH.mjs +25 -0
- package/dist/chunks/tail-BuhT-2PH.mjs.map +1 -0
- package/dist/chunks/update-BXIppsbi.mjs +16 -0
- package/dist/chunks/update-BXIppsbi.mjs.map +1 -0
- package/dist/cli.mjs +175 -0
- package/dist/cli.mjs.map +1 -0
- package/package.json +17 -32
- package/CHANGELOG.md +0 -1461
- package/bin/cli.js +0 -817
- package/bin/report.js +0 -141
- package/core/adapter/render.js +0 -415
- package/core/agents/implementer.template.md +0 -142
- package/core/agents/profile-reader.md +0 -50
- package/core/agents/release.md +0 -58
- package/core/agents/review.md +0 -179
- package/core/commands/cohorte-align-ds.md +0 -33
- package/core/commands/cohorte-audit.md +0 -58
- package/core/commands/cohorte-brainstorm.md +0 -70
- package/core/commands/cohorte-build.md +0 -219
- package/core/commands/cohorte-doctor.md +0 -194
- package/core/commands/cohorte-fix.md +0 -80
- package/core/commands/cohorte-fleet.md +0 -103
- package/core/commands/cohorte-init-pipeline.md +0 -31
- package/core/commands/cohorte-intake.md +0 -92
- package/core/commands/cohorte-patch.md +0 -118
- package/core/commands/cohorte-refactor.md +0 -59
- package/core/commands/cohorte-retro.md +0 -85
- package/core/commands/cohorte-review.md +0 -270
- package/core/commands/cohorte-ship.md +0 -122
- package/core/commands/cohorte-spec.md +0 -101
- package/core/commands/cohorte-update-pipeline.md +0 -165
- package/core/hooks/gate.py +0 -588
- package/core/runtimes/claude.json +0 -74
- package/core/runtimes/codex.json +0 -85
- package/core/runtimes/cursor.json +0 -76
- package/core/runtimes/gemini.json +0 -76
- package/core/runtimes/opencode.json +0 -73
- package/core/templates/agent-handoff.md +0 -34
- package/core/templates/brainstorm-return.md +0 -36
- package/core/templates/decisions.template.md +0 -42
- package/core/templates/design-brief.md +0 -44
- package/core/templates/patch.template.md +0 -86
- package/core/templates/pr-body.md +0 -25
- package/core/templates/review-feedback.md +0 -38
- package/core/templates/spec.template.md +0 -87
- package/core/templates/steps/init-pipeline/01-detect-stack.md +0 -44
- package/core/templates/steps/init-pipeline/02-interview-gaps.md +0 -55
- package/core/templates/steps/init-pipeline/03-draft-profile.md +0 -10
- package/core/templates/steps/init-pipeline/04-write-render.md +0 -145
- package/core/templates/steps/init-pipeline/05-report.md +0 -12
- package/core/workflows/audit.js +0 -240
- package/core/workflows/loop.js +0 -641
- package/core/workflows/refactor.js +0 -276
- package/core/workflows/review.js +0 -456
- package/install.ps1 +0 -103
- package/install.sh +0 -114
- package/lib/doctor.js +0 -534
- package/lib/runtime.js +0 -139
- package/lib/versions.js +0 -149
- package/lib/yaml.js +0 -129
- package/profile/PIPELINE.template.md +0 -259
- package/profile/SCHEMA.md +0 -735
- package/profile/cohorte.config.template.yaml +0 -43
- package/scripts/assert-gate-hook.mjs +0 -75
- package/scripts/kanban-move.sh +0 -313
- package/scripts/metrics/collect.mjs +0 -531
- package/scripts/metrics/prices.json +0 -42
- package/scripts/new-feature.sh.template +0 -98
- package/scripts/preflight.sh +0 -124
- package/scripts/remove-feature.sh.template +0 -56
- package/scripts/test-adapter.mjs +0 -437
- package/scripts/test-gate.mjs +0 -443
- package/scripts/test-kanban.mjs +0 -304
- package/scripts/test-lib.mjs +0 -356
- package/scripts/test-metrics.mjs +0 -156
- package/scripts/test-workflows.mjs +0 -758
- package/scripts/validate-core.mjs +0 -325
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { N as errorOf, j as CohorteError } from "./src-Cu3TxNob.mjs";
|
|
2
|
+
//#region src/commands/__host/index.ts
|
|
3
|
+
const host = {
|
|
4
|
+
verb: "__host",
|
|
5
|
+
async run(ctx, args) {
|
|
6
|
+
const runIndex = args.positionals.indexOf("--run");
|
|
7
|
+
const runId = runIndex >= 0 ? args.positionals[runIndex + 1] : void 0;
|
|
8
|
+
if (!runId || runId.startsWith("--")) return 2;
|
|
9
|
+
if (!ctx.hostRunner) throw new CohorteError(errorOf("configuration/unexpected", "the detached host composition is missing its run engine binding"));
|
|
10
|
+
const stop = await ctx.hostRunner.run(runId);
|
|
11
|
+
ctx.stdio.stdout.write(`${JSON.stringify(stop)}\n`);
|
|
12
|
+
return stop.reason === "review-clean" ? 0 : 1;
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
//#endregion
|
|
16
|
+
export { host as default };
|
|
17
|
+
|
|
18
|
+
//# sourceMappingURL=__host-DgGPyco9.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"__host-DgGPyco9.mjs","names":[],"sources":["../../../../apps/cli/src/commands/__host/index.ts"],"sourcesContent":["// apps/cli/src/commands/__host/index.ts — the hidden detached-host entry point (DESIGN 4.7).\nimport { CohorteError, errorOf } from '@cohorte/base';\nimport type { CommandModule } from '../../contract/index.ts';\n\nconst host: CommandModule = {\n verb: '__host',\n async run(ctx, args) {\n const runIndex = args.positionals.indexOf('--run');\n const runId = runIndex >= 0 ? args.positionals[runIndex + 1] : undefined;\n if (!runId || runId.startsWith('--')) return 2;\n if (!ctx.hostRunner) {\n throw new CohorteError(\n errorOf('configuration/unexpected', 'the detached host composition is missing its run engine binding'),\n );\n }\n const stop = await ctx.hostRunner.run(runId);\n ctx.stdio.stdout.write(`${JSON.stringify(stop)}\\n`);\n return stop.reason === 'review-clean' ? 0 : 1;\n },\n};\n\nexport default host;\n"],"mappings":";;AAIA,MAAM,OAAsB;CAC1B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,MAAM,WAAW,KAAK,YAAY,QAAQ,OAAO;EACjD,MAAM,QAAQ,YAAY,IAAI,KAAK,YAAY,WAAW,KAAK,KAAA;EAC/D,IAAI,CAAC,SAAS,MAAM,WAAW,IAAI,GAAG,OAAO;EAC7C,IAAI,CAAC,IAAI,YACP,MAAM,IAAI,aACR,QAAQ,4BAA4B,iEAAiE,CACvG;EAEF,MAAM,OAAO,MAAM,IAAI,WAAW,IAAI,KAAK;EAC3C,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,IAAI,EAAE,GAAG;EAClD,OAAO,KAAK,WAAW,iBAAiB,IAAI;CAC9C;AACF"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
//#region src/commands/approve/index.ts
|
|
2
|
+
const approve = {
|
|
3
|
+
verb: "approve",
|
|
4
|
+
async run(ctx, args) {
|
|
5
|
+
const [runId, approvalId, answer] = args.positionals;
|
|
6
|
+
if (!runId || !approvalId) return 2;
|
|
7
|
+
const result = await ctx.controller.send("approve", {
|
|
8
|
+
approvalId,
|
|
9
|
+
scope: "once",
|
|
10
|
+
...answer ? { answer } : {}
|
|
11
|
+
}, { runId });
|
|
12
|
+
ctx.stdio.stdout.write(`${JSON.stringify(result)}\n`);
|
|
13
|
+
return result.status === "rejected" ? 3 : result.status === "pending" ? 4 : 0;
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
//#endregion
|
|
17
|
+
export { approve as default };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=approve-Cv135UqI.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approve-Cv135UqI.mjs","names":[],"sources":["../../../../apps/cli/src/commands/approve/index.ts"],"sourcesContent":["// apps/cli/src/commands/approve/index.ts — DESIGN §9 verb `approve` (PLAN §3 rule 3 \"later units fill\n// stub files that lie inside their owned paths; they never edit ... the registry\"). Wave-0 stub: exits with the\n// documented not-available error (spec 24 `configuration/phase-not-available`); filled by the Wave-4/5\n// unit that owns `apps/cli/src/commands/approve/**`.\nimport type { CommandModule } from '../../contract/index.ts';\n\nconst approve: CommandModule = {\n verb: 'approve',\n async run(ctx, args) {\n const [runId, approvalId, answer] = args.positionals;\n if (!runId || !approvalId) return 2;\n const result = await ctx.controller.send(\n 'approve',\n { approvalId: approvalId as never, scope: 'once', ...(answer ? { answer } : {}) },\n { runId },\n );\n ctx.stdio.stdout.write(`${JSON.stringify(result)}\\n`);\n return result.status === 'rejected' ? 3 : result.status === 'pending' ? 4 : 0;\n },\n};\n\nexport default approve;\n"],"mappings":";AAMA,MAAM,UAAyB;CAC7B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,MAAM,CAAC,OAAO,YAAY,UAAU,KAAK;EACzC,IAAI,CAAC,SAAS,CAAC,YAAY,OAAO;EAClC,MAAM,SAAS,MAAM,IAAI,WAAW,KAClC,WACA;GAAc;GAAqB,OAAO;GAAQ,GAAI,SAAS,EAAE,OAAO,IAAI,CAAC;EAAG,GAChF,EAAE,MAAM,CACV;EACA,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,MAAM,EAAE,GAAG;EACpD,OAAO,OAAO,WAAW,aAAa,IAAI,OAAO,WAAW,YAAY,IAAI;CAC9E;AACF"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { t as canonicalJson } from "./canonical-C8UxeEmB.mjs";
|
|
2
|
+
import { c as systemClock } from "./src-Cu3TxNob.mjs";
|
|
3
|
+
import { createHmac, randomBytes, timingSafeEqual } from "node:crypto";
|
|
4
|
+
import { chmod, mkdir, readFile, rename, stat, unlink, writeFile } from "node:fs/promises";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
//#region ../../packages/base/src/hmac.ts
|
|
7
|
+
/** HMAC-SHA256 as lowercase hex. A string is authenticated as UTF-8. Comparing two MACs is the caller's job, and must be timing-safe. */
|
|
8
|
+
function hmacSha256Hex(key, data) {
|
|
9
|
+
if (key.byteLength === 0) throw new RangeError("hmacSha256Hex: empty key");
|
|
10
|
+
return createHmac("sha256", key).update(data).digest("hex");
|
|
11
|
+
}
|
|
12
|
+
/** Domain separation: an anchor body can never be mistaken for a command body signed with the same project key. */
|
|
13
|
+
const ANCHOR_MAC_PURPOSE = "cohorte/chain-anchor/v1";
|
|
14
|
+
/**
|
|
15
|
+
* The MAC anchor of `checkpoint.created` over `(runId, atSequence, chainHash)` (DESIGN 2.6.7, ADR-0022).
|
|
16
|
+
* THE definition: `security` signs with it (`CommandAuthenticator.anchor`) and `persistence` verifies with it
|
|
17
|
+
* (`verifyChain`), and those two packages may not import each other. The signed bytes are the canonical JSON of
|
|
18
|
+
* `{ purpose, runId, atSequence, chainHash }`, so no field can bleed into its neighbour.
|
|
19
|
+
*/
|
|
20
|
+
function computeAnchorMac(key, runId, atSequence, chainHash) {
|
|
21
|
+
if (!Number.isSafeInteger(atSequence) || atSequence < 0) throw new RangeError(`computeAnchorMac: atSequence must be a non-negative safe integer, got ${atSequence}`);
|
|
22
|
+
return hmacSha256Hex(key, canonicalJson({
|
|
23
|
+
purpose: ANCHOR_MAC_PURPOSE,
|
|
24
|
+
runId,
|
|
25
|
+
atSequence,
|
|
26
|
+
chainHash
|
|
27
|
+
}));
|
|
28
|
+
}
|
|
29
|
+
//#endregion
|
|
30
|
+
//#region ../../packages/security/src/auth/index.ts
|
|
31
|
+
function createKeyStore(options) {
|
|
32
|
+
const pathFor = (id) => join(options.directory, `${id}.key`);
|
|
33
|
+
return { async projectKey(projectKeyId, opts) {
|
|
34
|
+
if (!/^[A-Za-z0-9._-]+$/.test(projectKeyId)) throw new TypeError("invalid project key id");
|
|
35
|
+
await mkdir(options.directory, {
|
|
36
|
+
recursive: true,
|
|
37
|
+
mode: 448
|
|
38
|
+
});
|
|
39
|
+
await chmod(options.directory, 448);
|
|
40
|
+
const path = pathFor(projectKeyId);
|
|
41
|
+
try {
|
|
42
|
+
if (((await stat(path)).mode & 511) !== 384) throw new Error("key file permissions are not 0600");
|
|
43
|
+
const key = await readFile(path);
|
|
44
|
+
if (key.byteLength !== 32) throw new Error("project key must be 32 bytes");
|
|
45
|
+
return Uint8Array.from(key);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
if (error.code !== "ENOENT" || !opts.create) throw error;
|
|
48
|
+
const key = randomBytes(32);
|
|
49
|
+
const temporary = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
50
|
+
await writeFile(temporary, key, { mode: 384 });
|
|
51
|
+
await chmod(temporary, 384);
|
|
52
|
+
await rename(temporary, path);
|
|
53
|
+
return Uint8Array.from(key);
|
|
54
|
+
}
|
|
55
|
+
} };
|
|
56
|
+
}
|
|
57
|
+
function createCommandAuthenticator() {
|
|
58
|
+
return {
|
|
59
|
+
scheme: "hmac-sha256",
|
|
60
|
+
sign(canonicalBody, key) {
|
|
61
|
+
return hmacSha256Hex(key, canonicalBody);
|
|
62
|
+
},
|
|
63
|
+
verify(canonicalBody, value, key) {
|
|
64
|
+
try {
|
|
65
|
+
const expected = Buffer.from(hmacSha256Hex(key, canonicalBody), "hex");
|
|
66
|
+
const actual = Buffer.from(value, "hex");
|
|
67
|
+
return expected.byteLength === actual.byteLength && timingSafeEqual(expected, actual);
|
|
68
|
+
} catch {
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
anchor(runId, atSequence, chainHash, key) {
|
|
73
|
+
return computeAnchorMac(key, runId, atSequence, chainHash);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
function createTrustStore(options) {
|
|
78
|
+
const pathFor = (id) => join(options.directory, `${id}.json`);
|
|
79
|
+
const unsigned = (record) => canonicalJson(record);
|
|
80
|
+
return {
|
|
81
|
+
async lookup(projectKeyId, policySha256) {
|
|
82
|
+
try {
|
|
83
|
+
const path = pathFor(projectKeyId);
|
|
84
|
+
if (((await stat(path)).mode & 511) !== 384) return void 0;
|
|
85
|
+
const record = JSON.parse(await readFile(path, "utf8"));
|
|
86
|
+
if (record.policySha256 !== policySha256) return void 0;
|
|
87
|
+
const key = await options.keys.projectKey(projectKeyId, { create: false });
|
|
88
|
+
const { mac: _mac, ...recordWithoutMac } = record;
|
|
89
|
+
return hmacSha256Hex(key, unsigned(recordWithoutMac)) === record.mac ? record : void 0;
|
|
90
|
+
} catch {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
async grant(projectKeyId, grant) {
|
|
95
|
+
const key = await options.keys.projectKey(projectKeyId, { create: true });
|
|
96
|
+
const recordWithoutMac = {
|
|
97
|
+
policySha256: grant.policySha256,
|
|
98
|
+
loosenedKeys: [...grant.loosenedKeys],
|
|
99
|
+
grantedAt: systemClock.now(),
|
|
100
|
+
grantedBy: grant.grantedBy
|
|
101
|
+
};
|
|
102
|
+
const record = {
|
|
103
|
+
...recordWithoutMac,
|
|
104
|
+
mac: hmacSha256Hex(key, unsigned(recordWithoutMac))
|
|
105
|
+
};
|
|
106
|
+
await mkdir(options.directory, {
|
|
107
|
+
recursive: true,
|
|
108
|
+
mode: 448
|
|
109
|
+
});
|
|
110
|
+
await chmod(options.directory, 448);
|
|
111
|
+
const path = pathFor(projectKeyId);
|
|
112
|
+
const temporary = `${path}.tmp-${process.pid}-${Date.now()}`;
|
|
113
|
+
await writeFile(temporary, `${JSON.stringify(record)}\n`, { mode: 384 });
|
|
114
|
+
await chmod(temporary, 384);
|
|
115
|
+
await rename(temporary, path);
|
|
116
|
+
return record;
|
|
117
|
+
},
|
|
118
|
+
async revoke(projectKeyId) {
|
|
119
|
+
try {
|
|
120
|
+
await unlink(pathFor(projectKeyId));
|
|
121
|
+
return true;
|
|
122
|
+
} catch (error) {
|
|
123
|
+
if (error.code === "ENOENT") return false;
|
|
124
|
+
throw error;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
//#endregion
|
|
130
|
+
export { computeAnchorMac as i, createKeyStore as n, createTrustStore as r, createCommandAuthenticator as t };
|
|
131
|
+
|
|
132
|
+
//# sourceMappingURL=auth-BT5oVp76.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-BT5oVp76.mjs","names":[],"sources":["../../../../packages/base/src/hmac.ts","../../../../packages/security/src/auth/index.ts"],"sourcesContent":["import { createHmac } from 'node:crypto';\nimport { canonicalJson } from './canonical.ts';\nimport type { RunId } from './ids.ts';\n\n/** HMAC-SHA256 as lowercase hex. A string is authenticated as UTF-8. Comparing two MACs is the caller's job, and must be timing-safe. */\nexport function hmacSha256Hex(key: Uint8Array, data: string | Uint8Array): string {\n if (key.byteLength === 0) throw new RangeError('hmacSha256Hex: empty key');\n return createHmac('sha256', key).update(data).digest('hex');\n}\n\n/** Domain separation: an anchor body can never be mistaken for a command body signed with the same project key. */\nexport const ANCHOR_MAC_PURPOSE = 'cohorte/chain-anchor/v1';\n\n/**\n * The MAC anchor of `checkpoint.created` over `(runId, atSequence, chainHash)` (DESIGN 2.6.7, ADR-0022).\n * THE definition: `security` signs with it (`CommandAuthenticator.anchor`) and `persistence` verifies with it\n * (`verifyChain`), and those two packages may not import each other. The signed bytes are the canonical JSON of\n * `{ purpose, runId, atSequence, chainHash }`, so no field can bleed into its neighbour.\n */\nexport function computeAnchorMac(key: Uint8Array, runId: RunId, atSequence: number, chainHash: string): string {\n if (!Number.isSafeInteger(atSequence) || atSequence < 0) {\n throw new RangeError(`computeAnchorMac: atSequence must be a non-negative safe integer, got ${atSequence}`);\n }\n return hmacSha256Hex(key, canonicalJson({ purpose: ANCHOR_MAC_PURPOSE, runId, atSequence, chainHash }));\n}\n","// File-backed project keys, HMAC command authentication and trust records.\n\nimport { randomBytes, timingSafeEqual } from 'node:crypto';\nimport { chmod, mkdir, readFile, rename, stat, unlink, writeFile } from 'node:fs/promises';\nimport { join } from 'node:path';\nimport { canonicalJson, computeAnchorMac, hmacSha256Hex, type RunId, systemClock } from '@cohorte/base';\nimport type { TrustRecord, TrustStore } from '@cohorte/config/schema';\nimport type { CommandAuthenticator, KeyStore } from '../contract/index.ts';\n\nexport interface KeyStoreOptions {\n /** `~/.cohorte/keys`: directory 0700, files 0600; wrong modes are refused */\n directory: string;\n}\n\nexport function createKeyStore(options: KeyStoreOptions): KeyStore {\n const pathFor = (id: string): string => join(options.directory, `${id}.key`);\n return {\n async projectKey(projectKeyId, opts): Promise<Uint8Array> {\n if (!/^[A-Za-z0-9._-]+$/.test(projectKeyId)) throw new TypeError('invalid project key id');\n await mkdir(options.directory, { recursive: true, mode: 0o700 });\n await chmod(options.directory, 0o700);\n const path = pathFor(projectKeyId);\n try {\n const metadata = await stat(path);\n if ((metadata.mode & 0o777) !== 0o600) throw new Error('key file permissions are not 0600');\n const key = await readFile(path);\n if (key.byteLength !== 32) throw new Error('project key must be 32 bytes');\n return Uint8Array.from(key);\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'ENOENT' || !opts.create) throw error;\n const key = randomBytes(32);\n const temporary = `${path}.tmp-${process.pid}-${Date.now()}`;\n await writeFile(temporary, key, { mode: 0o600 });\n await chmod(temporary, 0o600);\n await rename(temporary, path);\n return Uint8Array.from(key);\n }\n },\n };\n}\n\nexport function createCommandAuthenticator(): CommandAuthenticator {\n return {\n scheme: 'hmac-sha256',\n sign(canonicalBody, key): string {\n return hmacSha256Hex(key, canonicalBody);\n },\n verify(canonicalBody, value, key): boolean {\n try {\n const expected = Buffer.from(hmacSha256Hex(key, canonicalBody), 'hex');\n const actual = Buffer.from(value, 'hex');\n return expected.byteLength === actual.byteLength && timingSafeEqual(expected, actual);\n } catch {\n return false;\n }\n },\n anchor(runId: RunId, atSequence: number, chainHash: string, key): string {\n return computeAnchorMac(key, runId, atSequence, chainHash);\n },\n };\n}\n\nexport interface TrustStoreOptions {\n /** `~/.cohorte/trust`: directory 0700, files 0600 */\n directory: string;\n /** records are MAC'd with the project key; a bad MAC or wrong modes = ABSENT (fail closed) */\n keys: KeyStore;\n}\n\nexport function createTrustStore(options: TrustStoreOptions): TrustStore {\n const pathFor = (id: string): string => join(options.directory, `${id}.json`);\n const unsigned = (record: Omit<TrustRecord, 'mac'>): string => canonicalJson(record);\n return {\n async lookup(projectKeyId, policySha256): Promise<TrustRecord | undefined> {\n try {\n const path = pathFor(projectKeyId);\n const metadata = await stat(path);\n if ((metadata.mode & 0o777) !== 0o600) return undefined;\n const record = JSON.parse(await readFile(path, 'utf8')) as TrustRecord;\n if (record.policySha256 !== policySha256) return undefined;\n const key = await options.keys.projectKey(projectKeyId, { create: false });\n const { mac: _mac, ...recordWithoutMac } = record;\n const expected = hmacSha256Hex(key, unsigned(recordWithoutMac));\n return expected === record.mac ? record : undefined;\n } catch {\n return undefined;\n }\n },\n async grant(projectKeyId, grant): Promise<TrustRecord> {\n const key = await options.keys.projectKey(projectKeyId, { create: true });\n const recordWithoutMac = {\n policySha256: grant.policySha256,\n loosenedKeys: [...grant.loosenedKeys],\n grantedAt: systemClock.now(),\n grantedBy: grant.grantedBy,\n };\n const record: TrustRecord = {\n ...recordWithoutMac,\n mac: hmacSha256Hex(key, unsigned(recordWithoutMac)),\n };\n await mkdir(options.directory, { recursive: true, mode: 0o700 });\n await chmod(options.directory, 0o700);\n const path = pathFor(projectKeyId);\n const temporary = `${path}.tmp-${process.pid}-${Date.now()}`;\n await writeFile(temporary, `${JSON.stringify(record)}\\n`, { mode: 0o600 });\n await chmod(temporary, 0o600);\n await rename(temporary, path);\n return record;\n },\n async revoke(projectKeyId): Promise<boolean> {\n try {\n await unlink(pathFor(projectKeyId));\n return true;\n } catch (error) {\n if ((error as NodeJS.ErrnoException).code === 'ENOENT') return false;\n throw error;\n }\n },\n };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
//#region src/commands/auth/index.ts
|
|
3
|
+
function document(ctx, statuses) {
|
|
4
|
+
return {
|
|
5
|
+
documentVersion: 1,
|
|
6
|
+
generatedAt: ctx.clock.now(),
|
|
7
|
+
runtime: (() => {
|
|
8
|
+
return {
|
|
9
|
+
id: ctx.runtime.resolve().id,
|
|
10
|
+
version: "unknown"
|
|
11
|
+
};
|
|
12
|
+
})(),
|
|
13
|
+
providers: statuses.map((status) => ({
|
|
14
|
+
...status,
|
|
15
|
+
...status.accountLabel === void 0 ? { accountLabelNote: "account: not exposed by the engine" } : {}
|
|
16
|
+
}))
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function print(ctx, value) {
|
|
20
|
+
if (ctx.stdio.stdout && value) ctx.stdio.stdout.write(`${JSON.stringify(value)}\n`);
|
|
21
|
+
}
|
|
22
|
+
async function loginUi(ctx, signal) {
|
|
23
|
+
const readline = createInterface({
|
|
24
|
+
input: ctx.stdio.stdin,
|
|
25
|
+
output: ctx.stdio.stdout,
|
|
26
|
+
terminal: false
|
|
27
|
+
});
|
|
28
|
+
const abort = () => readline.close();
|
|
29
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
30
|
+
return {
|
|
31
|
+
show(event) {
|
|
32
|
+
const text = event.message ?? event.instructions ?? event.url ?? event.verificationUri ?? event.userCode ?? "";
|
|
33
|
+
if (text) ctx.stdio.stdout.write(`${text}\n`);
|
|
34
|
+
},
|
|
35
|
+
async ask(prompt) {
|
|
36
|
+
if (prompt.kind === "select" && prompt.options?.length) {
|
|
37
|
+
ctx.stdio.stdout.write(`${prompt.message}\n`);
|
|
38
|
+
prompt.options.forEach((option, index) => {
|
|
39
|
+
ctx.stdio.stdout.write(` ${index + 1}. ${option.label}\n`);
|
|
40
|
+
});
|
|
41
|
+
const answer = await readline.question("Choice: ");
|
|
42
|
+
const index = Number.parseInt(answer, 10) - 1;
|
|
43
|
+
return prompt.options[index]?.id ?? answer;
|
|
44
|
+
}
|
|
45
|
+
return readline.question(`${prompt.message} `);
|
|
46
|
+
},
|
|
47
|
+
close() {
|
|
48
|
+
signal.removeEventListener("abort", abort);
|
|
49
|
+
readline.close();
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
const auth = {
|
|
54
|
+
verb: "auth",
|
|
55
|
+
async run(ctx, args) {
|
|
56
|
+
const runtime = ctx.runtime.resolve();
|
|
57
|
+
const provider = args.positionals[0];
|
|
58
|
+
if (args.subVerb === "status" || args.subVerb === void 0) {
|
|
59
|
+
const value = document(ctx, await runtime.authStatus(provider ? [provider] : ["openai-codex", "anthropic"]));
|
|
60
|
+
if (args.json) print(ctx, value);
|
|
61
|
+
else for (const status of value.providers) ctx.stdio.stdout.write(`${status.provider}: ${status.state} (${status.billing})\n`);
|
|
62
|
+
return 0;
|
|
63
|
+
}
|
|
64
|
+
if (!provider) return 2;
|
|
65
|
+
if (args.subVerb === "logout") {
|
|
66
|
+
await runtime.logout(provider);
|
|
67
|
+
const value = document(ctx, await runtime.authStatus([provider]));
|
|
68
|
+
if (args.json) print(ctx, value);
|
|
69
|
+
else ctx.stdio.stdout.write(`${provider}: logged out\n`);
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
if (args.subVerb === "login") {
|
|
73
|
+
const controller = new AbortController();
|
|
74
|
+
const timeout = setTimeout(() => controller.abort(), 6e5);
|
|
75
|
+
const ui = await loginUi(ctx, controller.signal);
|
|
76
|
+
try {
|
|
77
|
+
const status = await runtime.login(provider, ui, controller.signal);
|
|
78
|
+
const value = document(ctx, [status]);
|
|
79
|
+
if (args.json) print(ctx, value);
|
|
80
|
+
else ctx.stdio.stdout.write(`${status.provider}: ${status.state}\n`);
|
|
81
|
+
return 0;
|
|
82
|
+
} finally {
|
|
83
|
+
clearTimeout(timeout);
|
|
84
|
+
ui.close();
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return 10;
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
//#endregion
|
|
91
|
+
export { auth as default };
|
|
92
|
+
|
|
93
|
+
//# sourceMappingURL=auth-CYOh60KG.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth-CYOh60KG.mjs","names":[],"sources":["../../../../apps/cli/src/commands/auth/index.ts"],"sourcesContent":["// apps/cli/src/commands/auth/index.ts — DESIGN §9 verb `auth`; provider authentication is delegated to the\n// selected runtime child so credentials never cross the CLI/runtime boundary.\nimport { createInterface } from 'node:readline/promises';\nimport type { ProviderAuthStatus } from '@cohorte/runtime-contract';\nimport type { CommandModule } from '../../contract/index.ts';\n\nfunction document(ctx: Parameters<CommandModule['run']>[0], statuses: ProviderAuthStatus[]) {\n return {\n documentVersion: 1,\n generatedAt: ctx.clock.now(),\n runtime: (() => {\n const runtime = ctx.runtime.resolve();\n return { id: runtime.id, version: 'unknown' };\n })(),\n providers: statuses.map((status) => ({\n ...status,\n ...(status.accountLabel === undefined ? { accountLabelNote: 'account: not exposed by the engine' } : {}),\n })),\n };\n}\n\nfunction print(ctx: Parameters<CommandModule['run']>[0], value: ReturnType<typeof document>): void {\n if (ctx.stdio.stdout && value) ctx.stdio.stdout.write(`${JSON.stringify(value)}\\n`);\n}\n\nasync function loginUi(ctx: Parameters<CommandModule['run']>[0], signal: AbortSignal) {\n const readline = createInterface({ input: ctx.stdio.stdin, output: ctx.stdio.stdout, terminal: false });\n const abort = () => readline.close();\n signal.addEventListener('abort', abort, { once: true });\n return {\n show(event: {\n kind: string;\n url?: string;\n instructions?: string;\n message?: string;\n userCode?: string;\n verificationUri?: string;\n }) {\n const text = event.message ?? event.instructions ?? event.url ?? event.verificationUri ?? event.userCode ?? '';\n if (text) ctx.stdio.stdout.write(`${text}\\n`);\n },\n async ask(prompt: { kind: string; message: string; options?: { id: string; label: string }[] }) {\n if (prompt.kind === 'select' && prompt.options?.length) {\n ctx.stdio.stdout.write(`${prompt.message}\\n`);\n prompt.options.forEach((option, index) => {\n ctx.stdio.stdout.write(` ${index + 1}. ${option.label}\\n`);\n });\n const answer = await readline.question('Choice: ');\n const index = Number.parseInt(answer, 10) - 1;\n return prompt.options[index]?.id ?? answer;\n }\n return readline.question(`${prompt.message} `);\n },\n close() {\n signal.removeEventListener('abort', abort);\n readline.close();\n },\n };\n}\n\nconst auth: CommandModule = {\n verb: 'auth',\n async run(ctx, args) {\n const runtime = ctx.runtime.resolve();\n const provider = args.positionals[0];\n if (args.subVerb === 'status' || args.subVerb === undefined) {\n const statuses = await runtime.authStatus(provider ? [provider] : ['openai-codex', 'anthropic']);\n const value = document(ctx, statuses);\n if (args.json) print(ctx, value);\n else\n for (const status of value.providers)\n ctx.stdio.stdout.write(`${status.provider}: ${status.state} (${status.billing})\\n`);\n return 0;\n }\n if (!provider) return 2;\n if (args.subVerb === 'logout') {\n await runtime.logout(provider);\n const value = document(ctx, await runtime.authStatus([provider]));\n if (args.json) print(ctx, value);\n else ctx.stdio.stdout.write(`${provider}: logged out\\n`);\n return 0;\n }\n if (args.subVerb === 'login') {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 10 * 60_000);\n const ui = await loginUi(ctx, controller.signal);\n try {\n const status = await runtime.login(provider, ui, controller.signal);\n const value = document(ctx, [status]);\n if (args.json) print(ctx, value);\n else ctx.stdio.stdout.write(`${status.provider}: ${status.state}\\n`);\n return 0;\n } finally {\n clearTimeout(timeout);\n ui.close();\n }\n }\n return 10;\n },\n};\n\nexport default auth;\n"],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { r as notImplementedCommand } from "./contract-BkMjU1kR.mjs";
|
|
2
|
+
//#region src/commands/brainstorm/index.ts
|
|
3
|
+
var brainstorm_default = notImplementedCommand("brainstorm");
|
|
4
|
+
//#endregion
|
|
5
|
+
export { brainstorm_default as default };
|
|
6
|
+
|
|
7
|
+
//# sourceMappingURL=brainstorm-BwKA6yZP.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"brainstorm-BwKA6yZP.mjs","names":[],"sources":["../../../../apps/cli/src/commands/brainstorm/index.ts"],"sourcesContent":["// apps/cli/src/commands/brainstorm/index.ts — DESIGN §9 verb `brainstorm` (PLAN §3 rule 3 \"later units fill\n// stub files that lie inside their owned paths; they never edit ... the registry\"). Wave-0 stub: exits with the\n// documented not-available error (spec 24 `configuration/phase-not-available`); filled by the Wave-4/5\n// unit that owns `apps/cli/src/commands/brainstorm/**`.\nimport { notImplementedCommand } from '../../contract/index.ts';\n\nexport default notImplementedCommand('brainstorm');\n"],"mappings":";;AAMA,IAAA,qBAAe,sBAAsB,YAAY"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
//#region src/commands/cancel/index.ts
|
|
2
|
+
const cancel = {
|
|
3
|
+
verb: "cancel",
|
|
4
|
+
async run(ctx, args) {
|
|
5
|
+
const runId = args.positionals[0];
|
|
6
|
+
if (!runId) return 2;
|
|
7
|
+
const result = await ctx.controller.send("cancel", { keepWorktrees: false }, { runId });
|
|
8
|
+
ctx.stdio.stdout.write(`${JSON.stringify(result)}\n`);
|
|
9
|
+
return result.status === "rejected" ? 3 : result.status === "pending" ? 4 : 0;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
//#endregion
|
|
13
|
+
export { cancel as default };
|
|
14
|
+
|
|
15
|
+
//# sourceMappingURL=cancel-KV_cpsqS.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cancel-KV_cpsqS.mjs","names":[],"sources":["../../../../apps/cli/src/commands/cancel/index.ts"],"sourcesContent":["// apps/cli/src/commands/cancel/index.ts — DESIGN §9 verb `cancel` (PLAN §3 rule 3 \"later units fill\n// stub files that lie inside their owned paths; they never edit ... the registry\"). Wave-0 stub: exits with the\n// documented not-available error (spec 24 `configuration/phase-not-available`); filled by the Wave-4/5\n// unit that owns `apps/cli/src/commands/cancel/**`.\nimport type { CommandModule } from '../../contract/index.ts';\n\nconst cancel: CommandModule = {\n verb: 'cancel',\n async run(ctx, args) {\n const runId = args.positionals[0];\n if (!runId) return 2;\n const result = await ctx.controller.send('cancel', { keepWorktrees: false }, { runId });\n ctx.stdio.stdout.write(`${JSON.stringify(result)}\\n`);\n return result.status === 'rejected' ? 3 : result.status === 'pending' ? 4 : 0;\n },\n};\n\nexport default cancel;\n"],"mappings":";AAMA,MAAM,SAAwB;CAC5B,MAAM;CACN,MAAM,IAAI,KAAK,MAAM;EACnB,MAAM,QAAQ,KAAK,YAAY;EAC/B,IAAI,CAAC,OAAO,OAAO;EACnB,MAAM,SAAS,MAAM,IAAI,WAAW,KAAK,UAAU,EAAE,eAAe,MAAM,GAAG,EAAE,MAAM,CAAC;EACtF,IAAI,MAAM,OAAO,MAAM,GAAG,KAAK,UAAU,MAAM,EAAE,GAAG;EACpD,OAAO,OAAO,WAAW,aAAa,IAAI,OAAO,WAAW,YAAY,IAAI;CAC9E;AACF"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
//#region ../../packages/base/src/canonical.ts
|
|
3
|
+
const describe = (value) => {
|
|
4
|
+
if (value === null) return "null";
|
|
5
|
+
if (typeof value !== "object") return typeof value;
|
|
6
|
+
const name = Object.getPrototypeOf(value)?.constructor?.name;
|
|
7
|
+
return typeof name === "string" && name ? name : "object";
|
|
8
|
+
};
|
|
9
|
+
const write = (value, path, ancestors) => {
|
|
10
|
+
if (value === null) return "null";
|
|
11
|
+
switch (typeof value) {
|
|
12
|
+
case "boolean": return value ? "true" : "false";
|
|
13
|
+
case "number":
|
|
14
|
+
if (!Number.isFinite(value)) throw new TypeError(`canonicalJson: ${value} at ${path || "/"} is not a JSON number`);
|
|
15
|
+
return JSON.stringify(value);
|
|
16
|
+
case "string": return JSON.stringify(value.normalize("NFC"));
|
|
17
|
+
case "object": break;
|
|
18
|
+
default: throw new TypeError(`canonicalJson: a ${typeof value} at ${path || "/"} is not JSON`);
|
|
19
|
+
}
|
|
20
|
+
if (ancestors.has(value)) throw new TypeError(`canonicalJson: cycle at ${path || "/"}`);
|
|
21
|
+
ancestors.add(value);
|
|
22
|
+
try {
|
|
23
|
+
if (Array.isArray(value)) {
|
|
24
|
+
const items = [];
|
|
25
|
+
for (let index = 0; index < value.length; index += 1) items.push(write(value[index], `${path}/${index}`, ancestors));
|
|
26
|
+
return `[${items.join(",")}]`;
|
|
27
|
+
}
|
|
28
|
+
const proto = Object.getPrototypeOf(value);
|
|
29
|
+
if (proto !== Object.prototype && proto !== null) throw new TypeError(`canonicalJson: a ${describe(value)} at ${path || "/"} is not a plain JSON object`);
|
|
30
|
+
const members = /* @__PURE__ */ new Map();
|
|
31
|
+
for (const [rawKey, member] of Object.entries(value)) {
|
|
32
|
+
if (member === void 0) continue;
|
|
33
|
+
const key = rawKey.normalize("NFC");
|
|
34
|
+
if (members.has(key)) throw new TypeError(`canonicalJson: two keys collide as ${JSON.stringify(key)} at ${path || "/"} once normalised`);
|
|
35
|
+
members.set(key, write(member, `${path}/${key}`, ancestors));
|
|
36
|
+
}
|
|
37
|
+
return `{${[...members.keys()].sort().map((key) => `${JSON.stringify(key)}:${members.get(key)}`).join(",")}}`;
|
|
38
|
+
} finally {
|
|
39
|
+
ancestors.delete(value);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
/**
|
|
43
|
+
* The one serialisation that is hashed, signed or compared: sorted keys, no whitespace, NFC strings (keys included).
|
|
44
|
+
* Throws a TypeError on anything that is not JSON — a non-finite number, `undefined` outside an object member,
|
|
45
|
+
* a function, a bigint, a class instance, a cycle — rather than hash something `JSON.parse` could not give back.
|
|
46
|
+
*/
|
|
47
|
+
function canonicalJson(v) {
|
|
48
|
+
return write(v, "", /* @__PURE__ */ new Set());
|
|
49
|
+
}
|
|
50
|
+
/** A string is hashed as UTF-8, as given: no normalisation here. */
|
|
51
|
+
function sha256Hex(data) {
|
|
52
|
+
return createHash("sha256").update(data).digest("hex");
|
|
53
|
+
}
|
|
54
|
+
//#endregion
|
|
55
|
+
export { sha256Hex as n, canonicalJson as t };
|
|
56
|
+
|
|
57
|
+
//# sourceMappingURL=canonical-C8UxeEmB.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonical-C8UxeEmB.mjs","names":[],"sources":["../../../../packages/base/src/canonical.ts"],"sourcesContent":["import { createHash } from 'node:crypto';\nimport type { Sha256 } from './ids.ts';\nimport type { JsonValue } from './json.ts';\n\nconst describe = (value: unknown): string => {\n if (value === null) return 'null';\n if (typeof value !== 'object') return typeof value;\n const name: unknown = Object.getPrototypeOf(value)?.constructor?.name;\n return typeof name === 'string' && name ? name : 'object';\n};\n\nconst write = (value: unknown, path: string, ancestors: Set<object>): string => {\n if (value === null) return 'null';\n switch (typeof value) {\n case 'boolean':\n return value ? 'true' : 'false';\n case 'number':\n if (!Number.isFinite(value))\n throw new TypeError(`canonicalJson: ${value} at ${path || '/'} is not a JSON number`);\n // JSON.stringify is the ECMAScript shortest round-trip form RFC 8785 prescribes, and writes -0 as 0.\n return JSON.stringify(value);\n case 'string':\n return JSON.stringify(value.normalize('NFC'));\n case 'object':\n break;\n default:\n throw new TypeError(`canonicalJson: a ${typeof value} at ${path || '/'} is not JSON`);\n }\n\n if (ancestors.has(value)) throw new TypeError(`canonicalJson: cycle at ${path || '/'}`);\n ancestors.add(value);\n try {\n if (Array.isArray(value)) {\n const items: string[] = [];\n for (let index = 0; index < value.length; index += 1)\n items.push(write(value[index], `${path}/${index}`, ancestors));\n return `[${items.join(',')}]`;\n }\n const proto: unknown = Object.getPrototypeOf(value);\n if (proto !== Object.prototype && proto !== null) {\n throw new TypeError(`canonicalJson: a ${describe(value)} at ${path || '/'} is not a plain JSON object`);\n }\n const members = new Map<string, string>();\n for (const [rawKey, member] of Object.entries(value)) {\n // Dropped exactly as JSON.stringify drops it, so a value hashes like the form that gets stored.\n if (member === undefined) continue;\n const key = rawKey.normalize('NFC');\n if (members.has(key))\n throw new TypeError(\n `canonicalJson: two keys collide as ${JSON.stringify(key)} at ${path || '/'} once normalised`,\n );\n members.set(key, write(member, `${path}/${key}`, ancestors));\n }\n // Default sort = UTF-16 code units, the order of RFC 8785.\n const keys = [...members.keys()].sort();\n return `{${keys.map((key) => `${JSON.stringify(key)}:${members.get(key)}`).join(',')}}`;\n } finally {\n ancestors.delete(value);\n }\n};\n\n/**\n * The one serialisation that is hashed, signed or compared: sorted keys, no whitespace, NFC strings (keys included).\n * Throws a TypeError on anything that is not JSON — a non-finite number, `undefined` outside an object member,\n * a function, a bigint, a class instance, a cycle — rather than hash something `JSON.parse` could not give back.\n */\nexport function canonicalJson(v: JsonValue): string {\n return write(v, '', new Set());\n}\n\n/** A string is hashed as UTF-8, as given: no normalisation here. */\nexport function sha256Hex(data: string | Uint8Array): Sha256 {\n return createHash('sha256').update(data).digest('hex') as Sha256;\n}\n"],"mappings":";;AAIA,MAAM,YAAY,UAA2B;CAC3C,IAAI,UAAU,MAAM,OAAO;CAC3B,IAAI,OAAO,UAAU,UAAU,OAAO,OAAO;CAC7C,MAAM,OAAgB,OAAO,eAAe,KAAK,CAAC,EAAE,aAAa;CACjE,OAAO,OAAO,SAAS,YAAY,OAAO,OAAO;AACnD;AAEA,MAAM,SAAS,OAAgB,MAAc,cAAmC;CAC9E,IAAI,UAAU,MAAM,OAAO;CAC3B,QAAQ,OAAO,OAAf;EACE,KAAK,WACH,OAAO,QAAQ,SAAS;EAC1B,KAAK;GACH,IAAI,CAAC,OAAO,SAAS,KAAK,GACxB,MAAM,IAAI,UAAU,kBAAkB,MAAM,MAAM,QAAQ,IAAI,sBAAsB;GAEtF,OAAO,KAAK,UAAU,KAAK;EAC7B,KAAK,UACH,OAAO,KAAK,UAAU,MAAM,UAAU,KAAK,CAAC;EAC9C,KAAK,UACH;EACF,SACE,MAAM,IAAI,UAAU,oBAAoB,OAAO,MAAM,MAAM,QAAQ,IAAI,aAAa;CACxF;CAEA,IAAI,UAAU,IAAI,KAAK,GAAG,MAAM,IAAI,UAAU,2BAA2B,QAAQ,KAAK;CACtF,UAAU,IAAI,KAAK;CACnB,IAAI;EACF,IAAI,MAAM,QAAQ,KAAK,GAAG;GACxB,MAAM,QAAkB,CAAC;GACzB,KAAK,IAAI,QAAQ,GAAG,QAAQ,MAAM,QAAQ,SAAS,GACjD,MAAM,KAAK,MAAM,MAAM,QAAQ,GAAG,KAAK,GAAG,SAAS,SAAS,CAAC;GAC/D,OAAO,IAAI,MAAM,KAAK,GAAG,EAAE;EAC7B;EACA,MAAM,QAAiB,OAAO,eAAe,KAAK;EAClD,IAAI,UAAU,OAAO,aAAa,UAAU,MAC1C,MAAM,IAAI,UAAU,oBAAoB,SAAS,KAAK,EAAE,MAAM,QAAQ,IAAI,4BAA4B;EAExG,MAAM,0BAAU,IAAI,IAAoB;EACxC,KAAK,MAAM,CAAC,QAAQ,WAAW,OAAO,QAAQ,KAAK,GAAG;GAEpD,IAAI,WAAW,KAAA,GAAW;GAC1B,MAAM,MAAM,OAAO,UAAU,KAAK;GAClC,IAAI,QAAQ,IAAI,GAAG,GACjB,MAAM,IAAI,UACR,sCAAsC,KAAK,UAAU,GAAG,EAAE,MAAM,QAAQ,IAAI,iBAC9E;GACF,QAAQ,IAAI,KAAK,MAAM,QAAQ,GAAG,KAAK,GAAG,OAAO,SAAS,CAAC;EAC7D;EAGA,OAAO,IADM,CAAC,GAAG,QAAQ,KAAK,CAAC,CAAC,CAAC,KACnB,CAAC,CAAC,KAAK,QAAQ,GAAG,KAAK,UAAU,GAAG,EAAE,GAAG,QAAQ,IAAI,GAAG,GAAG,CAAC,CAAC,KAAK,GAAG,EAAE;CACvF,UAAU;EACR,UAAU,OAAO,KAAK;CACxB;AACF;;;;;;AAOA,SAAgB,cAAc,GAAsB;CAClD,OAAO,MAAM,GAAG,oBAAI,IAAI,IAAI,CAAC;AAC/B;;AAGA,SAAgB,UAAU,MAAmC;CAC3D,OAAO,WAAW,QAAQ,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,KAAK;AACvD"}
|