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.
Files changed (213) hide show
  1. package/README.md +7 -0
  2. package/assets/manifest.json +193 -0
  3. package/assets/migrations/config/README.md +12 -0
  4. package/assets/migrations/state/0001_init.sql +154 -0
  5. package/assets/prompts/README.md +11 -0
  6. package/assets/prompts/agents/fixer.md +7 -0
  7. package/assets/prompts/agents/implementer.md +12 -0
  8. package/assets/prompts/agents/reviewer.md +8 -0
  9. package/assets/prompts/agents/security-reviewer.md +7 -0
  10. package/assets/prompts/phases/build.md +5 -0
  11. package/assets/prompts/phases/review.md +5 -0
  12. package/assets/prompts/phases/test.md +5 -0
  13. package/assets/prompts/system.md +11 -0
  14. package/assets/schemas/agent-output.schema.json +225 -0
  15. package/assets/schemas/auth-status.schema.json +87 -0
  16. package/assets/schemas/command-result.schema.json +192 -0
  17. package/assets/schemas/commands.schema.json +952 -0
  18. package/assets/schemas/config.schema.json +2259 -0
  19. package/assets/schemas/doctor-report.schema.json +104 -0
  20. package/assets/schemas/events.schema.json +8514 -0
  21. package/assets/schemas/fake-script.schema.json +549 -0
  22. package/assets/schemas/inspect.schema.json +3133 -0
  23. package/assets/schemas/manifest.schema.json +79 -0
  24. package/assets/schemas/ownership.schema.json +52 -0
  25. package/assets/schemas/policy-verdict.schema.json +282 -0
  26. package/assets/schemas/project-model.schema.json +783 -0
  27. package/assets/schemas/project-status.schema.json +217 -0
  28. package/assets/schemas/reconcile-plan.schema.json +154 -0
  29. package/assets/schemas/run-diff.schema.json +177 -0
  30. package/assets/schemas/run-snapshot-manifest.schema.json +2104 -0
  31. package/assets/schemas/run-state.schema.json +1755 -0
  32. package/assets/schemas/runtime-capabilities.schema.json +1545 -0
  33. package/assets/schemas/sandbox-capabilities.schema.json +116 -0
  34. package/assets/schemas/skill.schema.json +87 -0
  35. package/assets/schemas/spec.schema.json +202 -0
  36. package/assets/schemas/tool-catalogue.schema.json +655 -0
  37. package/assets/schemas/trust-record.schema.json +38 -0
  38. package/assets/skills/README.md +9 -0
  39. package/assets/skills/inspect-surface.md +4 -0
  40. package/dist/agent-host.mjs +2187 -0
  41. package/dist/agent-host.mjs.map +1 -0
  42. package/dist/bundle-manifest.json +104 -0
  43. package/dist/chunks/__host-DgGPyco9.mjs +18 -0
  44. package/dist/chunks/__host-DgGPyco9.mjs.map +1 -0
  45. package/dist/chunks/approve-Cv135UqI.mjs +19 -0
  46. package/dist/chunks/approve-Cv135UqI.mjs.map +1 -0
  47. package/dist/chunks/auth-BT5oVp76.mjs +132 -0
  48. package/dist/chunks/auth-BT5oVp76.mjs.map +1 -0
  49. package/dist/chunks/auth-CYOh60KG.mjs +93 -0
  50. package/dist/chunks/auth-CYOh60KG.mjs.map +1 -0
  51. package/dist/chunks/brainstorm-BwKA6yZP.mjs +7 -0
  52. package/dist/chunks/brainstorm-BwKA6yZP.mjs.map +1 -0
  53. package/dist/chunks/cancel-KV_cpsqS.mjs +15 -0
  54. package/dist/chunks/cancel-KV_cpsqS.mjs.map +1 -0
  55. package/dist/chunks/canonical-C8UxeEmB.mjs +57 -0
  56. package/dist/chunks/canonical-C8UxeEmB.mjs.map +1 -0
  57. package/dist/chunks/catalogue-BvwSrM_j.mjs +1549 -0
  58. package/dist/chunks/catalogue-BvwSrM_j.mjs.map +1 -0
  59. package/dist/chunks/compose-Dvxunpto.mjs +7307 -0
  60. package/dist/chunks/compose-Dvxunpto.mjs.map +1 -0
  61. package/dist/chunks/config-DefHA2Lw.mjs +96 -0
  62. package/dist/chunks/config-DefHA2Lw.mjs.map +1 -0
  63. package/dist/chunks/contract-BkMjU1kR.mjs +295 -0
  64. package/dist/chunks/contract-BkMjU1kR.mjs.map +1 -0
  65. package/dist/chunks/contract-bQ9FJl4N.mjs +123 -0
  66. package/dist/chunks/contract-bQ9FJl4N.mjs.map +1 -0
  67. package/dist/chunks/deny-ClTxSvHJ.mjs +15 -0
  68. package/dist/chunks/deny-ClTxSvHJ.mjs.map +1 -0
  69. package/dist/chunks/diff-Qw0II0sj.mjs +101 -0
  70. package/dist/chunks/diff-Qw0II0sj.mjs.map +1 -0
  71. package/dist/chunks/discover-eS01-me1.mjs +21 -0
  72. package/dist/chunks/discover-eS01-me1.mjs.map +1 -0
  73. package/dist/chunks/doctor-B-H2UK5e.mjs +222 -0
  74. package/dist/chunks/doctor-B-H2UK5e.mjs.map +1 -0
  75. package/dist/chunks/fix-D4Tj8RVA.mjs +18 -0
  76. package/dist/chunks/fix-D4Tj8RVA.mjs.map +1 -0
  77. package/dist/chunks/gc-BBXlBF5w.mjs +161 -0
  78. package/dist/chunks/gc-BBXlBF5w.mjs.map +1 -0
  79. package/dist/chunks/init-BUnzIkeE.mjs +63 -0
  80. package/dist/chunks/init-BUnzIkeE.mjs.map +1 -0
  81. package/dist/chunks/inspect-Buby4cQD.mjs +22 -0
  82. package/dist/chunks/inspect-Buby4cQD.mjs.map +1 -0
  83. package/dist/chunks/logs-Giq5sUau.mjs +25 -0
  84. package/dist/chunks/logs-Giq5sUau.mjs.map +1 -0
  85. package/dist/chunks/migrate-DybihKzZ.mjs +33 -0
  86. package/dist/chunks/migrate-DybihKzZ.mjs.map +1 -0
  87. package/dist/chunks/models-Btp6X2YZ.mjs +24 -0
  88. package/dist/chunks/models-Btp6X2YZ.mjs.map +1 -0
  89. package/dist/chunks/pause-BASBfKLO.mjs +16 -0
  90. package/dist/chunks/pause-BASBfKLO.mjs.map +1 -0
  91. package/dist/chunks/policy-DUIgzF3W.mjs +139 -0
  92. package/dist/chunks/policy-DUIgzF3W.mjs.map +1 -0
  93. package/dist/chunks/providers-Dx78imKj.mjs +19 -0
  94. package/dist/chunks/providers-Dx78imKj.mjs.map +1 -0
  95. package/dist/chunks/reconcile-Bhy3IIYo.mjs +50 -0
  96. package/dist/chunks/reconcile-Bhy3IIYo.mjs.map +1 -0
  97. package/dist/chunks/render-DyZr5Lgi.mjs +53 -0
  98. package/dist/chunks/render-DyZr5Lgi.mjs.map +1 -0
  99. package/dist/chunks/resume-GJQRb2Eb.mjs +15 -0
  100. package/dist/chunks/resume-GJQRb2Eb.mjs.map +1 -0
  101. package/dist/chunks/retry-CLrUem1H.mjs +15 -0
  102. package/dist/chunks/retry-CLrUem1H.mjs.map +1 -0
  103. package/dist/chunks/review-BDdjb6kB.mjs +17 -0
  104. package/dist/chunks/review-BDdjb6kB.mjs.map +1 -0
  105. package/dist/chunks/run-CgTWYlcd.mjs +82 -0
  106. package/dist/chunks/run-CgTWYlcd.mjs.map +1 -0
  107. package/dist/chunks/run-tool-C3rAv4XF.mjs +26 -0
  108. package/dist/chunks/run-tool-C3rAv4XF.mjs.map +1 -0
  109. package/dist/chunks/scan-8Gy_B6kI.mjs +122 -0
  110. package/dist/chunks/scan-8Gy_B6kI.mjs.map +1 -0
  111. package/dist/chunks/schema-C9QbUW4H.mjs +578 -0
  112. package/dist/chunks/schema-C9QbUW4H.mjs.map +1 -0
  113. package/dist/chunks/send-BdnJ85Nz.mjs +19 -0
  114. package/dist/chunks/send-BdnJ85Nz.mjs.map +1 -0
  115. package/dist/chunks/ship-DTuLGoaJ.mjs +19 -0
  116. package/dist/chunks/ship-DTuLGoaJ.mjs.map +1 -0
  117. package/dist/chunks/shutdown-BM92Iyv2.mjs +15 -0
  118. package/dist/chunks/shutdown-BM92Iyv2.mjs.map +1 -0
  119. package/dist/chunks/skip-DZG5kpcH.mjs +18 -0
  120. package/dist/chunks/skip-DZG5kpcH.mjs.map +1 -0
  121. package/dist/chunks/spec-Bq0P3jVh.mjs +20 -0
  122. package/dist/chunks/spec-Bq0P3jVh.mjs.map +1 -0
  123. package/dist/chunks/src-CId6kMsY.mjs +1689 -0
  124. package/dist/chunks/src-CId6kMsY.mjs.map +1 -0
  125. package/dist/chunks/src-CfAOde7C.mjs +5403 -0
  126. package/dist/chunks/src-CfAOde7C.mjs.map +1 -0
  127. package/dist/chunks/src-CmFjh4M0.mjs +928 -0
  128. package/dist/chunks/src-CmFjh4M0.mjs.map +1 -0
  129. package/dist/chunks/src-Cu3TxNob.mjs +783 -0
  130. package/dist/chunks/src-Cu3TxNob.mjs.map +1 -0
  131. package/dist/chunks/src-DcU4IXMe.mjs +117 -0
  132. package/dist/chunks/src-DcU4IXMe.mjs.map +1 -0
  133. package/dist/chunks/src-s7YRvk0t.mjs +2116 -0
  134. package/dist/chunks/src-s7YRvk0t.mjs.map +1 -0
  135. package/dist/chunks/status-SMjiOMYy.mjs +29 -0
  136. package/dist/chunks/status-SMjiOMYy.mjs.map +1 -0
  137. package/dist/chunks/tail-BuhT-2PH.mjs +25 -0
  138. package/dist/chunks/tail-BuhT-2PH.mjs.map +1 -0
  139. package/dist/chunks/update-BXIppsbi.mjs +16 -0
  140. package/dist/chunks/update-BXIppsbi.mjs.map +1 -0
  141. package/dist/cli.mjs +175 -0
  142. package/dist/cli.mjs.map +1 -0
  143. package/package.json +17 -32
  144. package/CHANGELOG.md +0 -1461
  145. package/bin/cli.js +0 -817
  146. package/bin/report.js +0 -141
  147. package/core/adapter/render.js +0 -415
  148. package/core/agents/implementer.template.md +0 -142
  149. package/core/agents/profile-reader.md +0 -50
  150. package/core/agents/release.md +0 -58
  151. package/core/agents/review.md +0 -179
  152. package/core/commands/cohorte-align-ds.md +0 -33
  153. package/core/commands/cohorte-audit.md +0 -58
  154. package/core/commands/cohorte-brainstorm.md +0 -70
  155. package/core/commands/cohorte-build.md +0 -219
  156. package/core/commands/cohorte-doctor.md +0 -194
  157. package/core/commands/cohorte-fix.md +0 -80
  158. package/core/commands/cohorte-fleet.md +0 -103
  159. package/core/commands/cohorte-init-pipeline.md +0 -31
  160. package/core/commands/cohorte-intake.md +0 -92
  161. package/core/commands/cohorte-patch.md +0 -118
  162. package/core/commands/cohorte-refactor.md +0 -59
  163. package/core/commands/cohorte-retro.md +0 -85
  164. package/core/commands/cohorte-review.md +0 -270
  165. package/core/commands/cohorte-ship.md +0 -122
  166. package/core/commands/cohorte-spec.md +0 -101
  167. package/core/commands/cohorte-update-pipeline.md +0 -165
  168. package/core/hooks/gate.py +0 -588
  169. package/core/runtimes/claude.json +0 -74
  170. package/core/runtimes/codex.json +0 -85
  171. package/core/runtimes/cursor.json +0 -76
  172. package/core/runtimes/gemini.json +0 -76
  173. package/core/runtimes/opencode.json +0 -73
  174. package/core/templates/agent-handoff.md +0 -34
  175. package/core/templates/brainstorm-return.md +0 -36
  176. package/core/templates/decisions.template.md +0 -42
  177. package/core/templates/design-brief.md +0 -44
  178. package/core/templates/patch.template.md +0 -86
  179. package/core/templates/pr-body.md +0 -25
  180. package/core/templates/review-feedback.md +0 -38
  181. package/core/templates/spec.template.md +0 -87
  182. package/core/templates/steps/init-pipeline/01-detect-stack.md +0 -44
  183. package/core/templates/steps/init-pipeline/02-interview-gaps.md +0 -55
  184. package/core/templates/steps/init-pipeline/03-draft-profile.md +0 -10
  185. package/core/templates/steps/init-pipeline/04-write-render.md +0 -145
  186. package/core/templates/steps/init-pipeline/05-report.md +0 -12
  187. package/core/workflows/audit.js +0 -240
  188. package/core/workflows/loop.js +0 -641
  189. package/core/workflows/refactor.js +0 -276
  190. package/core/workflows/review.js +0 -456
  191. package/install.ps1 +0 -103
  192. package/install.sh +0 -114
  193. package/lib/doctor.js +0 -534
  194. package/lib/runtime.js +0 -139
  195. package/lib/versions.js +0 -149
  196. package/lib/yaml.js +0 -129
  197. package/profile/PIPELINE.template.md +0 -259
  198. package/profile/SCHEMA.md +0 -735
  199. package/profile/cohorte.config.template.yaml +0 -43
  200. package/scripts/assert-gate-hook.mjs +0 -75
  201. package/scripts/kanban-move.sh +0 -313
  202. package/scripts/metrics/collect.mjs +0 -531
  203. package/scripts/metrics/prices.json +0 -42
  204. package/scripts/new-feature.sh.template +0 -98
  205. package/scripts/preflight.sh +0 -124
  206. package/scripts/remove-feature.sh.template +0 -56
  207. package/scripts/test-adapter.mjs +0 -437
  208. package/scripts/test-gate.mjs +0 -443
  209. package/scripts/test-kanban.mjs +0 -304
  210. package/scripts/test-lib.mjs +0 -356
  211. package/scripts/test-metrics.mjs +0 -156
  212. package/scripts/test-workflows.mjs +0 -758
  213. 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"}