@open-agent-toolkit/cli 0.2.73 → 0.2.74

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 (149) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/cli-utilities/configuration.md +3 -56
  3. package/assets/docs/cli-utilities/tool-packs.md +4 -4
  4. package/assets/docs/contributing/code.md +2 -2
  5. package/assets/docs/contributing/index.md +0 -1
  6. package/assets/docs/reference/cli-reference.md +1 -1
  7. package/assets/docs/reference/troubleshooting.md +17 -40
  8. package/assets/docs/workflows/projects/artifacts.md +16 -34
  9. package/assets/docs/workflows/projects/lifecycle.md +20 -19
  10. package/assets/docs/workflows/skills/explainer-kit.md +180 -440
  11. package/assets/docs/workflows/skills/index.md +1 -2
  12. package/assets/public-package-versions.json +4 -4
  13. package/assets/skills/explainer-kit/SKILL.md +96 -171
  14. package/assets/skills/explainer-kit/recipes/engineer-tour.json +1 -22
  15. package/assets/skills/explainer-kit/recipes/program-recap.json +1 -29
  16. package/assets/skills/explainer-kit/recipes/project-explainer.json +1 -22
  17. package/assets/skills/explainer-kit/recipes/project-recap.v2.json +1 -43
  18. package/assets/skills/explainer-kit/references/fact-base-contract.md +76 -101
  19. package/assets/skills/explainer-kit/references/recap-authoring.md +99 -0
  20. package/assets/skills/explainer-kit/schemas/manifest.schema.json +13 -135
  21. package/assets/skills/explainer-kit/scripts/bundle.mjs +712 -0
  22. package/assets/skills/explainer-kit/scripts/lib/claim-subject.mjs +40 -0
  23. package/assets/skills/explainer-kit/scripts/lib/contracts.mjs +113 -1504
  24. package/assets/skills/explainer-kit/scripts/lib/failure.mjs +13 -0
  25. package/assets/skills/explainer-kit/scripts/lib/package-coverage.mjs +57 -403
  26. package/assets/skills/explainer-kit/scripts/lib/qa-result.mjs +168 -0
  27. package/assets/skills/explainer-kit/scripts/lib/qa.mjs +90 -488
  28. package/assets/skills/explainer-kit/scripts/lib/recipes.mjs +28 -545
  29. package/assets/skills/explainer-kit/scripts/lib/run-package.mjs +120 -0
  30. package/assets/skills/explainer-kit/scripts/lib/sanitize.mjs +42 -0
  31. package/assets/skills/explainer-kit/scripts/record.mjs +335 -0
  32. package/assets/skills/explainer-kit/scripts/verify.mjs +648 -0
  33. package/assets/skills/oat-explainer-kit/SKILL.md +57 -117
  34. package/assets/skills/oat-explainer-kit/references/config-contract.md +20 -64
  35. package/assets/skills/oat-explainer-kit/references/lifecycle-contract.md +85 -237
  36. package/assets/skills/oat-explainer-kit/scripts/bind-project-sources.mjs +18 -10
  37. package/assets/skills/oat-explainer-kit/scripts/check-core.mjs +1 -0
  38. package/assets/skills/oat-explainer-kit/scripts/check-terminal-outcome.mjs +256 -21
  39. package/assets/skills/oat-explainer-kit/scripts/persist-intent.mjs +82 -3
  40. package/assets/skills/oat-explainer-kit/scripts/resolve-config.mjs +0 -162
  41. package/assets/skills/oat-explainer-kit/scripts/resolve-intent.mjs +57 -123
  42. package/assets/skills/oat-project-autonomous/SKILL.md +14 -13
  43. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +165 -165
  44. package/assets/skills/oat-project-complete/SKILL.md +168 -349
  45. package/assets/skills/oat-project-complete/scripts/consume-persisted-recap-intent.mjs +125 -0
  46. package/assets/skills/oat-project-complete/scripts/execute-synced-archive-entry.mjs +0 -30
  47. package/assets/skills/oat-project-complete/scripts/parse-completion-retry-fields.mjs +4 -37
  48. package/assets/skills/oat-project-complete/scripts/parse-synced-archive-resume-fields.mjs +17 -16
  49. package/assets/skills/oat-project-complete/scripts/recover-completion-receipts.mjs +9 -174
  50. package/assets/skills/oat-project-complete/scripts/resolve-completion-retry.mjs +1 -2
  51. package/assets/skills/oat-project-document/SKILL.md +1 -1
  52. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +165 -165
  53. package/assets/skills/oat-project-implement/SKILL.md +1 -1
  54. package/assets/skills/oat-project-implement/references/completion-and-closeout.md +44 -56
  55. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +165 -165
  56. package/assets/skills/oat-project-lite/SKILL.md +1 -1
  57. package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +165 -165
  58. package/assets/skills/oat-project-plan/SKILL.md +5 -6
  59. package/assets/skills/oat-project-pr-final/SKILL.md +1 -1
  60. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +165 -165
  61. package/assets/skills/oat-project-quick-start/SKILL.md +1 -1
  62. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +165 -165
  63. package/assets/skills/oat-project-summary/SKILL.md +35 -25
  64. package/assets/skills/oat-wave-execute/SKILL.md +11 -36
  65. package/assets/skills/oat-wave-program/SKILL.md +13 -37
  66. package/dist/commands/config/index.d.ts.map +1 -1
  67. package/dist/commands/config/index.js +9 -113
  68. package/dist/commands/project/archive/archive-utils.d.ts.map +1 -1
  69. package/dist/commands/project/archive/archive-utils.js +32 -184
  70. package/dist/commands/project/archive/explainer-package-coverage.d.ts +3 -8
  71. package/dist/commands/project/archive/explainer-package-coverage.d.ts.map +1 -1
  72. package/dist/commands/project/archive/explainer-package-coverage.js +1 -1
  73. package/dist/config/oat-config.d.ts +0 -11
  74. package/dist/config/oat-config.d.ts.map +1 -1
  75. package/dist/config/oat-config.js +0 -34
  76. package/dist/config/resolve.d.ts.map +1 -1
  77. package/dist/config/resolve.js +0 -8
  78. package/dist/release/public-package-contract.d.ts.map +1 -1
  79. package/dist/release/public-package-contract.js +2 -10
  80. package/dist/validation/project-state.d.ts.map +1 -1
  81. package/dist/validation/project-state.js +42 -3
  82. package/package.json +2 -2
  83. package/assets/docs/contributing/explainer-kit-verification.md +0 -133
  84. package/assets/docs/workflows/skills/explainer-kit-providers.md +0 -155
  85. package/assets/skills/explainer-kit/briefs/deep-dive.md +0 -35
  86. package/assets/skills/explainer-kit/briefs/project-page.md +0 -38
  87. package/assets/skills/explainer-kit/briefs/supporting-diagram.md +0 -28
  88. package/assets/skills/explainer-kit/briefs/walkthrough-deck.md +0 -35
  89. package/assets/skills/explainer-kit/examples/project-explainer/content.md +0 -31
  90. package/assets/skills/explainer-kit/examples/project-explainer/fact-base.md +0 -22
  91. package/assets/skills/explainer-kit/examples/project-recap/content.md +0 -77
  92. package/assets/skills/explainer-kit/examples/project-recap/fact-base.json +0 -104
  93. package/assets/skills/explainer-kit/examples/project-recap/fact-base.md +0 -44
  94. package/assets/skills/explainer-kit/examples/theme-bundle.json +0 -87
  95. package/assets/skills/explainer-kit/recipes/project-recap.v1.json +0 -93
  96. package/assets/skills/explainer-kit/references/contracts.md +0 -324
  97. package/assets/skills/explainer-kit/references/destination-contract.md +0 -210
  98. package/assets/skills/explainer-kit/references/extension-contract.md +0 -80
  99. package/assets/skills/explainer-kit/references/golden-conformance.md +0 -80
  100. package/assets/skills/explainer-kit/references/visual-review.md +0 -71
  101. package/assets/skills/explainer-kit/schemas/author-request.v2.schema.json +0 -212
  102. package/assets/skills/explainer-kit/schemas/author-request.v3.schema.json +0 -241
  103. package/assets/skills/explainer-kit/schemas/author-result.v2.schema.json +0 -52
  104. package/assets/skills/explainer-kit/schemas/build-record.schema.json +0 -98
  105. package/assets/skills/explainer-kit/schemas/durability-evidence.schema.json +0 -53
  106. package/assets/skills/explainer-kit/schemas/publish-receipt.v1.schema.json +0 -97
  107. package/assets/skills/explainer-kit/schemas/publish-receipt.v2.schema.json +0 -215
  108. package/assets/skills/explainer-kit/schemas/publish-request.v1.schema.json +0 -32
  109. package/assets/skills/explainer-kit/schemas/publish-request.v2.schema.json +0 -34
  110. package/assets/skills/explainer-kit/schemas/run-request.schema.json +0 -147
  111. package/assets/skills/explainer-kit/schemas/set-plan.v1.schema.json +0 -149
  112. package/assets/skills/explainer-kit/schemas/terminal-evidence.v1.schema.json +0 -81
  113. package/assets/skills/explainer-kit/schemas/visual-review-evidence.v1.schema.json +0 -66
  114. package/assets/skills/explainer-kit/schemas/visual-review-request.v1.schema.json +0 -117
  115. package/assets/skills/explainer-kit/schemas/visual-review-result.v1.schema.json +0 -80
  116. package/assets/skills/explainer-kit/scripts/lib/catalog.mjs +0 -349
  117. package/assets/skills/explainer-kit/scripts/lib/content-approval.mjs +0 -418
  118. package/assets/skills/explainer-kit/scripts/lib/diagram.mjs +0 -514
  119. package/assets/skills/explainer-kit/scripts/lib/durability.mjs +0 -643
  120. package/assets/skills/explainer-kit/scripts/lib/fact-base.mjs +0 -664
  121. package/assets/skills/explainer-kit/scripts/lib/internal-references.mjs +0 -538
  122. package/assets/skills/explainer-kit/scripts/lib/markdown.mjs +0 -414
  123. package/assets/skills/explainer-kit/scripts/lib/publication-policy.mjs +0 -54
  124. package/assets/skills/explainer-kit/scripts/lib/records.mjs +0 -954
  125. package/assets/skills/explainer-kit/scripts/lib/render.mjs +0 -703
  126. package/assets/skills/explainer-kit/scripts/lib/s3-roots.mjs +0 -353
  127. package/assets/skills/explainer-kit/scripts/lib/s3-static.mjs +0 -759
  128. package/assets/skills/explainer-kit/scripts/lib/set-plan.mjs +0 -209
  129. package/assets/skills/explainer-kit/scripts/lib/source-backlinks.mjs +0 -218
  130. package/assets/skills/explainer-kit/scripts/lib/terminal-evidence.mjs +0 -157
  131. package/assets/skills/explainer-kit/scripts/lib/visual-review.mjs +0 -400
  132. package/assets/skills/explainer-kit/scripts/publish.mjs +0 -76
  133. package/assets/skills/explainer-kit/scripts/record-durability.mjs +0 -64
  134. package/assets/skills/explainer-kit/scripts/render-qa.mjs +0 -461
  135. package/assets/skills/explainer-kit/scripts/run.mjs +0 -3038
  136. package/assets/skills/explainer-kit/scripts/validate.mjs +0 -59
  137. package/assets/skills/oat-explainer-kit/references/author-callback.md +0 -53
  138. package/assets/skills/oat-explainer-kit/references/migration.md +0 -144
  139. package/assets/skills/oat-explainer-kit/references/visual-review-callback.md +0 -83
  140. package/assets/skills/oat-explainer-kit/scripts/derive-destination.mjs +0 -91
  141. package/assets/skills/oat-explainer-kit/scripts/finalize-tracked-run.mjs +0 -531
  142. package/assets/skills/oat-explainer-kit/scripts/probe-recap-seams.mjs +0 -371
  143. package/assets/skills/oat-explainer-kit/scripts/run.mjs +0 -905
  144. package/dist/commands/project/archive/explainer-source-backlinks.d.ts +0 -18
  145. package/dist/commands/project/archive/explainer-source-backlinks.d.ts.map +0 -1
  146. package/dist/commands/project/archive/explainer-source-backlinks.js +0 -27
  147. package/dist/commands/project/archive/explainer-terminal-evidence.d.ts +0 -29
  148. package/dist/commands/project/archive/explainer-terminal-evidence.d.ts.map +0 -1
  149. package/dist/commands/project/archive/explainer-terminal-evidence.js +0 -37
@@ -1,66 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "explainer-kit.visual-review-evidence/v1",
4
- "type": "object",
5
- "additionalProperties": false,
6
- "required": [
7
- "schemaVersion",
8
- "requestHash",
9
- "attempt",
10
- "disposition",
11
- "reasons"
12
- ],
13
- "properties": {
14
- "schemaVersion": {
15
- "const": "explainer-kit.visual-review-evidence/v1"
16
- },
17
- "requestHash": { "$ref": "#/$defs/hash" },
18
- "attempt": { "enum": [1, 2] },
19
- "disposition": { "enum": ["pass", "correct", "failed"] },
20
- "reasons": {
21
- "type": "array",
22
- "minItems": 0,
23
- "maxItems": 50,
24
- "items": { "$ref": "#/$defs/reason" }
25
- }
26
- },
27
- "$defs": {
28
- "hash": {
29
- "type": "string",
30
- "pattern": "^sha256:[a-f0-9]{64}$"
31
- },
32
- "reason": {
33
- "type": "object",
34
- "additionalProperties": false,
35
- "required": ["stage", "kind", "count"],
36
- "properties": {
37
- "stage": {
38
- "enum": [
39
- "planning",
40
- "authoring",
41
- "rendering",
42
- "link-validation",
43
- "browser-review",
44
- "visual-review",
45
- "durability",
46
- "finalization"
47
- ]
48
- },
49
- "kind": {
50
- "enum": [
51
- "finding",
52
- "provider-failure",
53
- "pipeline-failure",
54
- "superseded"
55
- ]
56
- },
57
- "artifactId": {
58
- "type": "string",
59
- "minLength": 1,
60
- "maxLength": 2000
61
- },
62
- "count": { "type": "integer", "minimum": 1, "maximum": 50 }
63
- }
64
- }
65
- }
66
- }
@@ -1,117 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "explainer-kit.visual-review-request/v1",
4
- "title": "VisualReviewRequestV1",
5
- "type": "object",
6
- "additionalProperties": false,
7
- "required": [
8
- "schemaVersion",
9
- "requestId",
10
- "requestHash",
11
- "browserRuntime",
12
- "captureIdentity",
13
- "plan",
14
- "renderedArtifacts"
15
- ],
16
- "properties": {
17
- "schemaVersion": {
18
- "const": "explainer-kit.visual-review-request/v1"
19
- },
20
- "requestId": { "$ref": "#/$defs/safeId" },
21
- "requestHash": { "$ref": "#/$defs/hash" },
22
- "browserRuntime": { "$ref": "#/$defs/browserRuntime" },
23
- "captureIdentity": { "$ref": "#/$defs/hash" },
24
- "plan": { "$ref": "explainer-kit.set-plan/v1" },
25
- "renderedArtifacts": {
26
- "type": "array",
27
- "items": { "$ref": "#/$defs/renderedArtifact" },
28
- "minItems": 1,
29
- "uniqueItems": true
30
- }
31
- },
32
- "$defs": {
33
- "safeRelativePath": {
34
- "type": "string",
35
- "minLength": 1,
36
- "pattern": "^(?!/)(?!.*(?:^|/)\\.\\.(?:/|$))(?!.*\\\\).+$"
37
- },
38
- "safeId": {
39
- "type": "string",
40
- "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$"
41
- },
42
- "hash": {
43
- "type": "string",
44
- "pattern": "^sha256:[a-f0-9]{64}$"
45
- },
46
- "browserRuntime": {
47
- "type": "object",
48
- "additionalProperties": false,
49
- "required": ["kind", "name", "version"],
50
- "properties": {
51
- "kind": { "enum": ["launched", "fixture"] },
52
- "name": { "const": "chromium" },
53
- "version": { "type": "string", "minLength": 1 }
54
- }
55
- },
56
- "renderedArtifact": {
57
- "type": "object",
58
- "additionalProperties": false,
59
- "required": ["artifactId", "renderedPath", "renderedHash", "evidence"],
60
- "properties": {
61
- "artifactId": {
62
- "type": "string",
63
- "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$"
64
- },
65
- "renderedPath": { "$ref": "#/$defs/safeRelativePath" },
66
- "renderedHash": { "$ref": "#/$defs/hash" },
67
- "cohesionObservations": {
68
- "type": "array",
69
- "items": { "$ref": "#/$defs/cohesionObservation" },
70
- "uniqueItems": true
71
- },
72
- "evidence": {
73
- "type": "array",
74
- "items": { "$ref": "#/$defs/evidence" },
75
- "minItems": 1,
76
- "uniqueItems": true
77
- }
78
- }
79
- },
80
- "cohesionObservation": {
81
- "type": "object",
82
- "additionalProperties": false,
83
- "required": ["artifactId", "contentHash", "group", "claim", "value"],
84
- "properties": {
85
- "artifactId": { "$ref": "#/$defs/safeId" },
86
- "contentHash": { "$ref": "#/$defs/hash" },
87
- "group": {
88
- "enum": ["terminology", "statuses", "numericClaims"]
89
- },
90
- "claim": { "type": "string", "minLength": 1 },
91
- "value": {
92
- "oneOf": [{ "type": "string", "minLength": 1 }, { "type": "number" }]
93
- }
94
- }
95
- },
96
- "evidence": {
97
- "type": "object",
98
- "additionalProperties": false,
99
- "required": [
100
- "viewport",
101
- "screenshotPath",
102
- "screenshotHash",
103
- "metricsPath",
104
- "metricsHash",
105
- "captureIdentity"
106
- ],
107
- "properties": {
108
- "viewport": { "enum": ["desktop", "tablet", "mobile"] },
109
- "screenshotPath": { "$ref": "#/$defs/safeRelativePath" },
110
- "screenshotHash": { "$ref": "#/$defs/hash" },
111
- "metricsPath": { "$ref": "#/$defs/safeRelativePath" },
112
- "metricsHash": { "$ref": "#/$defs/hash" },
113
- "captureIdentity": { "$ref": "#/$defs/hash" }
114
- }
115
- }
116
- }
117
- }
@@ -1,80 +0,0 @@
1
- {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "explainer-kit.visual-review-result/v1",
4
- "title": "VisualReviewResultV1",
5
- "type": "object",
6
- "additionalProperties": false,
7
- "required": [
8
- "schemaVersion",
9
- "reviewId",
10
- "requestId",
11
- "requestHash",
12
- "reviewedAt",
13
- "disposition",
14
- "artifactIds",
15
- "findings"
16
- ],
17
- "properties": {
18
- "schemaVersion": {
19
- "const": "explainer-kit.visual-review-result/v1"
20
- },
21
- "reviewId": { "$ref": "#/$defs/safeId" },
22
- "requestId": { "$ref": "#/$defs/safeId" },
23
- "requestHash": { "$ref": "#/$defs/hash" },
24
- "reviewedAt": { "type": "string", "format": "date-time" },
25
- "disposition": { "enum": ["pass", "correct", "fail"] },
26
- "artifactIds": {
27
- "type": "array",
28
- "items": { "$ref": "#/$defs/safeId" },
29
- "minItems": 1,
30
- "uniqueItems": true
31
- },
32
- "findings": {
33
- "type": "array",
34
- "items": { "$ref": "#/$defs/finding" },
35
- "uniqueItems": true
36
- }
37
- },
38
- "$defs": {
39
- "safeId": {
40
- "type": "string",
41
- "pattern": "^[a-z0-9]+(?:[._-][a-z0-9]+)*$"
42
- },
43
- "hash": {
44
- "type": "string",
45
- "pattern": "^sha256:[a-f0-9]{64}$"
46
- },
47
- "finding": {
48
- "type": "object",
49
- "additionalProperties": false,
50
- "required": [
51
- "artifactId",
52
- "rubric",
53
- "severity",
54
- "evidence",
55
- "correction"
56
- ],
57
- "properties": {
58
- "artifactId": { "$ref": "#/$defs/safeId" },
59
- "rubric": {
60
- "enum": [
61
- "first-viewport",
62
- "hierarchy",
63
- "representation",
64
- "legibility",
65
- "medium-fit",
66
- "cohesion",
67
- "coverage",
68
- "redundancy",
69
- "interaction"
70
- ]
71
- },
72
- "severity": {
73
- "enum": ["critical", "important", "medium", "minor"]
74
- },
75
- "evidence": { "type": "string", "minLength": 1 },
76
- "correction": { "type": "string", "minLength": 1 }
77
- }
78
- }
79
- }
80
- }
@@ -1,349 +0,0 @@
1
- import { canonicalStringify, validateContract } from './contracts.mjs';
2
-
3
- /**
4
- * Bumped to v2 when the root `publicVerification` marker was added below.
5
- *
6
- * The catalog is serialized, hashed, and recorded as an auxiliary artifact in
7
- * the publish receipt, so adding a root key changes the bytes. Released
8
- * `0.2.30` emits the v1 shape, which has no such key: leaving both shapes under
9
- * one version string would put two different wire formats behind one identifier
10
- * for anyone parsing `catalog.json` by declared version.
11
- *
12
- * There is deliberately no v1 read path. Unlike `publish-request/v1` and
13
- * `publish-receipt/v1`, which are retained because a v1 record can still be
14
- * replayed, the catalog is regenerate-only and never reconstructed from a v1
15
- * receipt: every rebuild site short-circuits on a non-v2 receipt
16
- * (`durability.mjs` verifyPublishEvidence, `run.mjs` publicationValidationContext,
17
- * and the normative `private-wrapper.mjs` example), and `0.2.30` emits
18
- * `publish-receipt/v1` only. Accepting v1 here would be unreachable code. If a
19
- * future reader ever does replay a v1-era catalog, it must reconstruct that
20
- * shape explicitly rather than relaxing this constant.
21
- */
22
- const CATALOG_SCHEMA_VERSION = 'explainer-kit.initiative-catalog/v2';
23
-
24
- export const PUBLIC_VERIFICATION_REQUIRED = 'required';
25
- export const PUBLIC_VERIFICATION_SKIPPED_BY_POLICY = 'skipped-by-policy';
26
-
27
- /**
28
- * Single source of truth for public-verification state.
29
- *
30
- * The catalog is built, serialized and hashed *before* the first upload and long
31
- * before any per-artifact public verification runs, so it can never carry a
32
- * verification *outcome*: writing one would either require re-uploading the
33
- * catalog or invalidate the hash the receipt records for it. It therefore
34
- * carries verification *policy* only, and the authoritative outcome stays in the
35
- * run's publish receipt, which the catalog's `runId` identifies.
36
- *
37
- * Both the catalog marker and the receipt's skipped status are derived from this
38
- * one result so the two cannot drift apart.
39
- */
40
- export function resolvePublicVerificationPolicy(publicAccess) {
41
- return publicAccess === 'protected'
42
- ? {
43
- publicAccess: 'protected',
44
- catalogMarker: PUBLIC_VERIFICATION_SKIPPED_BY_POLICY,
45
- verifyPublicly: false,
46
- receiptSkipStatus: 'skipped-protected',
47
- }
48
- : {
49
- publicAccess: 'public',
50
- catalogMarker: PUBLIC_VERIFICATION_REQUIRED,
51
- verifyPublicly: true,
52
- receiptSkipStatus: 'skipped-protected',
53
- };
54
- }
55
-
56
- /**
57
- * The public-access policy must be stated explicitly, never defaulted.
58
- *
59
- * It selects the catalog's `publicVerification` marker, which is part of the
60
- * serialized bytes and therefore of the catalog hash the receipt records. An
61
- * options bag that silently defaulted to the permissive `public` branch is what
62
- * let four call sites omit it and still produce a plausible-looking catalog:
63
- * the connector published `skipped-by-policy` for a `protected` run while the
64
- * durability verifier rebuilt `required`, so the hashes diverged and no
65
- * `protected` publication could ever be recorded durable.
66
- *
67
- * Passing `{ publicAccess: undefined }` is allowed and means `public` — that is
68
- * the correct reading for `publish-request/v1` and `publish-receipt/v1`, which
69
- * have no such field. Omitting the key entirely is a programming error.
70
- */
71
- function requiredPublicAccess(options, caller) {
72
- if (
73
- options === null ||
74
- typeof options !== 'object' ||
75
- !('publicAccess' in options)
76
- ) {
77
- throw new TypeError(
78
- `${caller} requires an explicit { publicAccess } policy: it selects the catalog's publicVerification marker and therefore its hash. Pass { publicAccess: undefined } for v1 records, which are public by definition.`,
79
- );
80
- }
81
- return options.publicAccess;
82
- }
83
-
84
- export function initiativeCatalogPath(slug) {
85
- if (typeof slug !== 'string' || !/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(slug)) {
86
- throw new TypeError('Initiative catalog requires a safe initiative slug.');
87
- }
88
- return `site/initiatives/${slug}/catalog.json`;
89
- }
90
-
91
- export function catalogFromManifest(manifest, publicBaseUrl, options) {
92
- const publicAccess = requiredPublicAccess(options, 'catalogFromManifest');
93
- const validation = validateContract('manifest', manifest);
94
- if (!validation.valid) {
95
- throw new TypeError(
96
- `Initiative catalog requires a valid finalized manifest: ${validation.errors[0].message}`,
97
- );
98
- }
99
- const baseUrl = normalizePublicBaseUrl(publicBaseUrl);
100
- const artifacts = manifest.artifacts.map((artifact) => {
101
- if (
102
- artifact.status !== 'built' ||
103
- typeof artifact.renderedPath !== 'string' ||
104
- !artifact.renderedPath.startsWith('site/') ||
105
- typeof artifact.hash !== 'string'
106
- ) {
107
- throw new TypeError(
108
- `Initiative catalog cannot publish non-built artifact ${artifact.id}.`,
109
- );
110
- }
111
- return {
112
- id: artifact.id,
113
- type: artifact.type,
114
- status: artifact.status,
115
- renderedPath: artifact.renderedPath,
116
- ...(artifact.mediaType && { mediaType: artifact.mediaType }),
117
- hash: artifact.hash,
118
- url: absoluteArtifactUrl(baseUrl, artifact.renderedPath),
119
- };
120
- });
121
-
122
- return {
123
- schemaVersion: CATALOG_SCHEMA_VERSION,
124
- runId: manifest.runId,
125
- slug: manifest.slug,
126
- recipe: structuredClone(manifest.recipe),
127
- createdAt: manifest.createdAt,
128
- // Policy, never outcome. See resolvePublicVerificationPolicy.
129
- publicVerification:
130
- resolvePublicVerificationPolicy(publicAccess).catalogMarker,
131
- artifacts,
132
- sourceBacklinks: structuredClone(manifest.source.backlinks ?? []),
133
- };
134
- }
135
-
136
- export function validateInitiativeCatalog(
137
- catalog,
138
- manifest,
139
- publicBaseUrl,
140
- options,
141
- ) {
142
- const publicAccess = requiredPublicAccess(
143
- options,
144
- 'validateInitiativeCatalog',
145
- );
146
- const errors = [];
147
- let normalizedPublicBaseUrl;
148
- try {
149
- normalizedPublicBaseUrl = normalizePublicBaseUrl(publicBaseUrl);
150
- } catch (error) {
151
- add(
152
- errors,
153
- '$.artifacts',
154
- 'catalog-public-root',
155
- error instanceof Error
156
- ? error.message
157
- : 'Initiative catalog requires an HTTPS public base URL.',
158
- );
159
- }
160
- if (!catalog || typeof catalog !== 'object' || Array.isArray(catalog)) {
161
- return {
162
- valid: false,
163
- errors: [
164
- {
165
- path: '$',
166
- code: 'catalog-shape',
167
- message: 'Initiative catalog must be an object.',
168
- },
169
- ],
170
- };
171
- }
172
- const expectedRootKeys = new Set([
173
- 'schemaVersion',
174
- 'runId',
175
- 'slug',
176
- 'recipe',
177
- 'createdAt',
178
- 'publicVerification',
179
- 'artifacts',
180
- 'sourceBacklinks',
181
- ]);
182
- if (Object.keys(catalog).some((key) => !expectedRootKeys.has(key))) {
183
- add(
184
- errors,
185
- '$',
186
- 'catalog-shape',
187
- 'Initiative catalog contains an unknown property.',
188
- );
189
- }
190
-
191
- for (const [field, expected] of [
192
- ['schemaVersion', CATALOG_SCHEMA_VERSION],
193
- ['runId', manifest?.runId],
194
- ['slug', manifest?.slug],
195
- ['createdAt', manifest?.createdAt],
196
- ]) {
197
- if (catalog[field] !== expected) {
198
- add(
199
- errors,
200
- `$.${field}`,
201
- 'catalog-manifest-mismatch',
202
- `Catalog ${field} does not match the finalized manifest.`,
203
- );
204
- }
205
- }
206
- // Derived from the same resolver the receipt status comes from, so a catalog
207
- // that disagrees with the run's resolved verification policy is rejected.
208
- const expectedPublicVerification =
209
- resolvePublicVerificationPolicy(publicAccess).catalogMarker;
210
- if (catalog.publicVerification !== expectedPublicVerification) {
211
- add(
212
- errors,
213
- '$.publicVerification',
214
- 'catalog-verification-policy',
215
- `Catalog publicVerification must be ${expectedPublicVerification} for this run's public access policy.`,
216
- );
217
- }
218
-
219
- if (
220
- canonicalStringify(catalog.recipe) !== canonicalStringify(manifest?.recipe)
221
- ) {
222
- add(
223
- errors,
224
- '$.recipe',
225
- 'catalog-manifest-mismatch',
226
- 'Catalog recipe does not match the finalized manifest.',
227
- );
228
- }
229
-
230
- const catalogArtifacts = Array.isArray(catalog.artifacts)
231
- ? catalog.artifacts
232
- : [];
233
- const manifestArtifacts = Array.isArray(manifest?.artifacts)
234
- ? manifest.artifacts
235
- : [];
236
- if (
237
- !Array.isArray(catalog.artifacts) ||
238
- catalogArtifacts.length !== manifestArtifacts.length
239
- ) {
240
- add(
241
- errors,
242
- '$.artifacts',
243
- 'catalog-artifact-parity',
244
- 'Catalog artifacts must exactly cover the finalized manifest artifacts.',
245
- );
246
- }
247
- for (const [index, artifact] of manifestArtifacts.entries()) {
248
- const entry = catalogArtifacts[index];
249
- const expected = {
250
- id: artifact.id,
251
- type: artifact.type,
252
- status: artifact.status,
253
- renderedPath: artifact.renderedPath,
254
- ...(artifact.mediaType && { mediaType: artifact.mediaType }),
255
- hash: artifact.hash,
256
- url:
257
- normalizedPublicBaseUrl === undefined
258
- ? undefined
259
- : absoluteArtifactUrl(normalizedPublicBaseUrl, artifact.renderedPath),
260
- };
261
- const actual = entry && typeof entry === 'object' ? entry : undefined;
262
- if (canonicalStringify(actual) !== canonicalStringify(expected)) {
263
- add(
264
- errors,
265
- `$.artifacts[${index}]`,
266
- 'catalog-artifact-mismatch',
267
- `Catalog artifact ${artifact.id} is stale or does not match the finalized manifest.`,
268
- );
269
- }
270
- }
271
-
272
- if (
273
- canonicalStringify(catalog.sourceBacklinks) !==
274
- canonicalStringify(manifest?.source?.backlinks ?? [])
275
- ) {
276
- add(
277
- errors,
278
- '$.sourceBacklinks',
279
- 'catalog-source-mismatch',
280
- 'Catalog source backlinks do not match the finalized manifest.',
281
- );
282
- }
283
- for (const [index, backlink] of (Array.isArray(catalog.sourceBacklinks)
284
- ? catalog.sourceBacklinks
285
- : []
286
- ).entries()) {
287
- if (
288
- typeof backlink?.sourceId !== 'string' ||
289
- !isImmutableGithubUrl(backlink?.url)
290
- ) {
291
- add(
292
- errors,
293
- `$.sourceBacklinks[${index}]`,
294
- 'catalog-source-url',
295
- 'Catalog source backlinks must be immutable absolute GitHub URLs.',
296
- );
297
- }
298
- }
299
-
300
- return { valid: errors.length === 0, errors };
301
- }
302
-
303
- export function serializeInitiativeCatalog(catalog) {
304
- return `${JSON.stringify(catalog, null, 2)}\n`;
305
- }
306
-
307
- function normalizePublicBaseUrl(value) {
308
- let url;
309
- try {
310
- url = new URL(value);
311
- } catch {
312
- throw new TypeError(
313
- 'Initiative catalog requires an HTTPS public base URL.',
314
- );
315
- }
316
- if (
317
- url.protocol !== 'https:' ||
318
- url.username ||
319
- url.password ||
320
- url.search ||
321
- url.hash
322
- ) {
323
- throw new TypeError(
324
- 'Initiative catalog requires credential-free HTTPS without query or fragment.',
325
- );
326
- }
327
- return url.href.replace(/\/+$/, '');
328
- }
329
-
330
- function absoluteArtifactUrl(baseUrl, renderedPath) {
331
- return `${baseUrl}/${renderedPath
332
- .slice('site/'.length)
333
- .split('/')
334
- .map((part) => encodeURIComponent(part))
335
- .join('/')}`;
336
- }
337
-
338
- function isImmutableGithubUrl(value) {
339
- return (
340
- typeof value === 'string' &&
341
- /^https:\/\/github\.com\/[^/]+\/[^/]+\/blob\/[a-f0-9]{40}\/.+#L[1-9][0-9]*(?:-L[1-9][0-9]*)?$/.test(
342
- value,
343
- )
344
- );
345
- }
346
-
347
- function add(errors, path, code, message) {
348
- errors.push({ path, code, message });
349
- }