@open-agent-toolkit/cli 0.2.10 → 0.2.12

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 (43) hide show
  1. package/assets/docs/cli-utilities/configuration.md +28 -14
  2. package/assets/docs/reference/cli-reference.md +1 -1
  3. package/assets/docs/workflows/projects/artifacts.md +16 -4
  4. package/assets/docs/workflows/skills/explainer-kit.md +70 -27
  5. package/assets/public-package-versions.json +4 -4
  6. package/assets/skills/explainer-kit/SKILL.md +9 -3
  7. package/assets/skills/explainer-kit/references/contracts.md +22 -7
  8. package/assets/skills/explainer-kit/schemas/author-request.schema.json +85 -0
  9. package/assets/skills/explainer-kit/schemas/author-result.schema.json +65 -0
  10. package/assets/skills/explainer-kit/schemas/manifest.schema.json +7 -1
  11. package/assets/skills/explainer-kit/schemas/run-request.schema.json +8 -0
  12. package/assets/skills/explainer-kit/schemas/theme.schema.json +8 -0
  13. package/assets/skills/explainer-kit/scripts/lib/content-approval.mjs +26 -1
  14. package/assets/skills/explainer-kit/scripts/lib/contracts.mjs +61 -0
  15. package/assets/skills/explainer-kit/scripts/lib/durability.mjs +2 -14
  16. package/assets/skills/explainer-kit/scripts/lib/qa.mjs +56 -0
  17. package/assets/skills/explainer-kit/scripts/lib/theme.mjs +102 -4
  18. package/assets/skills/explainer-kit/scripts/run.mjs +144 -11
  19. package/assets/skills/explainer-kit/styles/business-corporate.json +77 -0
  20. package/assets/skills/explainer-kit/styles/clean-neutral.json +77 -0
  21. package/assets/skills/explainer-kit/styles/dark-edgy.json +77 -0
  22. package/assets/skills/explainer-kit/styles/navy-ocean.json +82 -0
  23. package/assets/skills/explainer-kit/templates/deck-shell.html +57 -2
  24. package/assets/skills/oat-explainer-kit/SKILL.md +15 -9
  25. package/assets/skills/oat-explainer-kit/references/config-contract.md +11 -6
  26. package/assets/skills/oat-explainer-kit/references/lifecycle-contract.md +13 -0
  27. package/assets/skills/oat-explainer-kit/scripts/finalize-tracked-run.mjs +10 -14
  28. package/assets/skills/oat-explainer-kit/scripts/resolve-config.mjs +53 -9
  29. package/assets/skills/oat-explainer-kit/scripts/run.mjs +68 -0
  30. package/assets/skills/oat-wave-execute/SKILL.md +126 -23
  31. package/assets/skills/oat-wave-program/SKILL.md +41 -7
  32. package/dist/commands/config/index.d.ts.map +1 -1
  33. package/dist/commands/config/index.js +34 -8
  34. package/dist/commands/project/archive/archive-utils.d.ts.map +1 -1
  35. package/dist/commands/project/archive/archive-utils.js +14 -5
  36. package/dist/config/oat-config.d.ts +2 -0
  37. package/dist/config/oat-config.d.ts.map +1 -1
  38. package/dist/config/oat-config.js +11 -0
  39. package/dist/config/resolve.d.ts.map +1 -1
  40. package/dist/config/resolve.js +3 -2
  41. package/dist/providers/codex/codec/config-merge.d.ts.map +1 -1
  42. package/dist/providers/codex/codec/config-merge.js +39 -1
  43. package/package.json +2 -2
@@ -106,18 +106,19 @@ The `oat-explainer-kit` adapter owns two typed config groups. Build and publish
106
106
  plumbing uses `explainers.*`; project lifecycle preferences use
107
107
  `workflow.explainers.*`.
108
108
 
109
- | Key | Type | Stored scopes | Default |
110
- | -------------------------------------- | -------------------- | ------------------- | --------- |
111
- | `explainers.defaults.palette` | non-empty string | local, shared, user | `neutral` |
112
- | `explainers.defaults.visualProfile` | non-empty string | local, shared, user | `clean` |
113
- | `explainers.defaults.themeBundlePath` | path | local, shared | unset |
114
- | `explainers.publish.provider` | `s3-static` | shared | unset |
115
- | `explainers.publish.s3Uri` | `s3://` URI | shared | unset |
116
- | `explainers.publish.publicBaseUrl` | HTTPS URL | shared | unset |
117
- | `explainers.publish.awsRegion` | non-empty string | shared | unset |
118
- | `explainers.publish.awsProfile` | non-empty string | local, user | unset |
119
- | `workflow.explainers.projectExplainer` | `always\|ask\|never` | local, shared, user | `ask` |
120
- | `workflow.explainers.projectRecap` | `always\|ask\|never` | local, shared, user | `ask` |
109
+ | Key | Type | Stored scopes | Default |
110
+ | -------------------------------------- | ---------------------------- | ------------------- | --------------- |
111
+ | `explainers.defaults.style` | curated style name | local, shared, user | `clean-neutral` |
112
+ | `explainers.defaults.palette` | nullable string (deprecated) | local, shared, user | `null` |
113
+ | `explainers.defaults.visualProfile` | nullable string (deprecated) | local, shared, user | `null` |
114
+ | `explainers.defaults.themeBundlePath` | path | local, shared | unset |
115
+ | `explainers.publish.provider` | `s3-static` | shared | unset |
116
+ | `explainers.publish.s3Uri` | `s3://` URI | shared | unset |
117
+ | `explainers.publish.publicBaseUrl` | HTTPS URL | shared | unset |
118
+ | `explainers.publish.awsRegion` | non-empty string | shared | unset |
119
+ | `explainers.publish.awsProfile` | non-empty string | local, user | unset |
120
+ | `workflow.explainers.projectExplainer` | `always\|ask\|never` | local, shared, user | `ask` |
121
+ | `workflow.explainers.projectRecap` | `always\|ask\|never` | local, shared, user | `ask` |
121
122
 
122
123
  Stored values resolve `local > shared > user > default` where the key permits
123
124
  each scope. Explicit runtime inputs take precedence for one invocation without
@@ -125,10 +126,23 @@ mutating stored config. Use `oat config get <key> --json` to inspect both the
125
126
  resolved value and its source, and `oat config describe <key>` for its exact
126
127
  scope and type contract.
127
128
 
129
+ For example:
130
+
131
+ ```bash
132
+ oat config set explainers.defaults.style navy-ocean --shared
133
+ oat config get explainers.defaults.style --json
134
+ oat config describe explainers.defaults.style
135
+ ```
136
+
128
137
  Shared theme-bundle paths must be repository-relative. Local paths may be
129
138
  repository-relative or absolute; user config cannot set a theme-bundle path.
130
- A supplied bundle takes precedence over named palette and profile defaults and
131
- produces a warning.
139
+ A supplied bundle takes precedence over all named selections. Otherwise choose
140
+ one of `clean-neutral`, `business-corporate`, `navy-ocean`, or `dark-edgy` with
141
+ `explainers.defaults.style`. An explicit style takes precedence over legacy
142
+ `palette` and `visualProfile` values. Those matrix fields remain available for
143
+ advanced compatibility but emit deprecation warnings. When no source explicitly
144
+ selects a theme, the core uses `clean-neutral` and records a visible fallback
145
+ warning.
132
146
 
133
147
  Publishing remains build-only when `explainers.publish.provider` is unset.
134
148
  When it is `s3-static`, `s3Uri`, `publicBaseUrl`, and `awsRegion` are all
@@ -64,7 +64,7 @@ Notable commands introduced in the current CLI surface:
64
64
  - `oat review latest --json` - find the newest review artifact by `oat_generated_at`, scanning the active or specified project's `reviews/` and `reviews/archived/` directories plus ad-hoc review locations. Same-time candidates use target priority, then lifecycle recency (`final` > higher phase/task > lower phase/task). The JSON contract returns `path`, `scope`, `generatedAt`, `kind` (`project` or `adhoc`), `archived`, and `actionable`, with `null` values when no review exists. Archived project reviews remain discoverable as history but return `actionable: false`.
65
65
  - `oat project list --json` - summary state for tracked projects under the configured projects root
66
66
  - `oat project complete-state <project-path>` - apply the canonical completed-state mutation to a project's `state.md`; used by `oat-project-complete` during lifecycle closeout
67
- - `oat project archive [project-path]` - archive a tracked project through the same local move, summary export, and optional S3 upload path used by completion. When omitted, the project path falls back to the active project.
67
+ - `oat project archive [project-path] [--project-recap-run <project-relative-path>]` - archive a tracked project through the same local move, summary export, and optional S3 upload path used by completion. When omitted, the project path falls back to the active project. The optional recap path must identify a `project-recap` run inside the project's `explainers/` directory. Archive stages the selected complete package into `.oat/repo/reference/project-recaps/<YYYYMMDD-project-slug>/`, verifies every manifest-declared immutable file byte, then atomically installs the export before deleting the active project. Existing destinations, incomplete legacy hash coverage, stale bytes, path escapes, and recipe mismatches fail without removing the active project.
68
68
  - `oat repo archive sync [project-name]` - hydrate archived project snapshots from the configured repo-scoped S3 archive into `.oat/projects/archived/`. The old `oat project archive sync` path remains as a deprecated shim.
69
69
  - `oat project validate-plan --project-path <path>` - validates `oat_plan_parallel_groups` metadata in `plan.md`; exits non-zero on invalid. See [Implementation Execution](../workflows/projects/implementation-execution.md#plan-declared-parallelism).
70
70
  - `oat project log append|check|synthesize|rollup` - manage the optional append-only project observation log: append validated judgment or structural entries, inspect grammar and synthesis status, complete end-of-run synthesis, and roll observations into `summary.md` plus the configured repository ledger. See [Project Log](../cli-utilities/project-log.md).
@@ -44,13 +44,25 @@ different retention contracts:
44
44
  - A selected final `project-recap` is a durable completion record. Before a
45
45
  shared project is removed, archive copies the complete selected run to
46
46
  `.oat/repo/reference/project-recaps/<YYYYMMDD-project-slug>/`, verifies its
47
- manifest artifact hashes, and reports that tracked export path. Summary and
48
- PR links use this export, never the gitignored local archive.
47
+ immutable package hashes, and reports that tracked export path. Summary and
48
+ PR links use this export, never the gitignored local archive. Lifecycle
49
+ callers identify the selected project-relative run with:
50
+
51
+ ```bash
52
+ oat project archive <project-path> \
53
+ --project-recap-run explainers/<recap-slug>
54
+ ```
49
55
 
50
56
  The archive exports at most one selected recap package. It preserves structured
51
57
  failure outcomes and successful intermediates, rejects an existing dated
52
- destination, and fails before deleting the active project if copy or hash
53
- verification fails.
58
+ destination, and requires the selected path to stay under the project's
59
+ `explainers/` directory with a `project-recap` manifest. Verification covers
60
+ the exact retained bytes for the privacy-safe request, content approval, fact
61
+ base JSON and Markdown, declared author results, authored Markdown, resolved
62
+ theme, and every built artifact. Canonical fact-base and theme hashes remain
63
+ normalized-object identities; `manifest.immutableHashes` independently covers
64
+ serialized file bytes. Missing, stale, or tampered coverage fails before the
65
+ active project is deleted.
54
66
 
55
67
  Local-scope projects are not archived through this export path. Their explainer
56
68
  packages inherit the local project's untracked posture and remain
@@ -20,38 +20,81 @@ OAT lifecycle callers use the adapter.
20
20
 
21
21
  ## Recipes
22
22
 
23
- The v1 project recipes serve different lifecycle jobs:
24
-
25
- | Recipe | Lifecycle use | Required narrative |
26
- | ------------------- | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------- |
27
- | `project-explainer` | Working explanation after project planning | planned architecture, decisions, risks, phases, and validation approach |
28
- | `project-recap` | Final record after implementation and final review | original request, key agent decisions, as-built architecture, implementation record, validation evidence, and outcome |
29
-
30
- Both recipes bind one project source set. The adapter binds `plan.md`,
31
- `design.md`, and `spec.md` for a project explainer; a project recap can also
32
- include `implementation.md` and `summary.md`.
33
-
34
- ## Themes
35
-
36
- Every artifact set uses one resolved theme. The bundled defaults are the
37
- `neutral` palette and `clean` visual profile. The core also ships the `ocean`,
38
- `ember`, `forest`, and `violet` palettes plus `editorial` and `technical`
39
- profiles.
40
-
41
- A caller may select named palette/profile values, supply a validated theme
42
- bundle, or provide per-run art direction. A supplied bundle takes precedence
43
- over named selections. The resolved concrete bundle is retained with the run;
44
- raw art-direction text is not retained by default. Themes contain validated
45
- light and dark modes, while the render strategy chooses either the default mode
46
- or a user-switchable result.
23
+ The core ships four versioned recipes:
24
+
25
+ | Recipe | Use | Required narrative |
26
+ | ------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------- |
27
+ | `project-explainer` | Working explanation after project planning | planned architecture, decisions, risks, phases, and validation approach |
28
+ | `project-recap` | Final record after implementation and final review | original request, key agent decisions, as-built architecture, implementation record, validation evidence, and outcome |
29
+ | `program-recap` | Bird's-eye record of a multi-wave delivery program | program overview, wave map and outcomes, convention evolution, aggregate numbers, and follow-up ledger |
30
+ | `engineer-tour` | Engineer-facing orientation to a codebase and its flow | orientation, architecture, execution flow, key code, and validation |
31
+
32
+ The OAT project lifecycle owns `project-explainer` and `project-recap`. Both
33
+ bind one project source set. The adapter binds `plan.md`, `design.md`, and
34
+ `spec.md` for a project explainer; a project recap can also include
35
+ `implementation.md` and `summary.md`. Wave callers supply the program source
36
+ set for `program-recap`; direct core callers can use `engineer-tour` without
37
+ adding an OAT dependency.
38
+
39
+ ## Content authoring and review
40
+
41
+ Every unattended run requires one provider-neutral author. The core invokes
42
+ the author once per recipe artifact with the exact narrative outline,
43
+ reconciled fact base, and bounded-discovery context. It accepts only a
44
+ schema-valid result with the required section IDs, substantive prose, and
45
+ non-secret provenance. Each section is checked independently for excessive
46
+ verbatim overlap with the fact base so one copied section cannot be hidden by
47
+ otherwise original prose.
48
+
49
+ In-process core callers supply `options.author`; core CLI callers use
50
+ `--author-module`. The OAT adapter accepts either an in-process `author` or an
51
+ `authorModulePath` and rejects zero or two seams for unattended runs before it
52
+ invokes the core. Callback and module paths are transient. Validated results
53
+ are retained under `source/author/` and covered by the run's immutable hashes.
54
+
55
+ Interactive runs may omit an author. They pause after writing
56
+ `source/content/*.md`, require an explicit content-review decision, and resume
57
+ the same run only after approval. Content approval never authorizes publishing.
58
+
59
+ ## Curated styles and themes
60
+
61
+ Every artifact set uses one resolved theme. The primary selection surface is
62
+ one of four complete curated styles:
63
+
64
+ - `clean-neutral` — restrained neutral default
65
+ - `business-corporate` — structured corporate presentation
66
+ - `navy-ocean` — navy-led technical and operational presentation
67
+ - `dark-edgy` — solid dark canvas with high-contrast editorial accents
68
+
69
+ A caller may select a style, supply a validated theme bundle, or provide
70
+ per-run art direction. A supplied bundle takes precedence over a style. Legacy
71
+ `palette` and `visualProfile` inputs remain nullable compatibility fields, but
72
+ an explicit style wins and legacy use emits a deprecation warning. When no
73
+ selection is explicit, the core uses `clean-neutral` and records the fallback.
74
+
75
+ The resolved concrete bundle is retained with the run; raw art-direction text
76
+ is not retained by default. Every bundle contains validated light and dark
77
+ modes. The render strategy chooses either the default mode or a user-switchable
78
+ result without changing the bundle identity.
47
79
 
48
80
  ## Build, durability, and publish
49
81
 
50
82
  Missing publish configuration means build-only. A completed build writes the
51
- source package, resolved theme, `manifest.json`, `build-record.json`, and the
52
- rendered `site/` tree. Rendering or publishing failures preserve successful
83
+ privacy-safe request, content approval, fact base, author results, authored
84
+ content, resolved theme, `manifest.json`, `build-record.json`, and the rendered
85
+ `site/` tree. Rendering or publishing failures preserve successful
53
86
  intermediates and recovery information.
54
87
 
88
+ `manifest.immutableHashes` covers the exact retained bytes for
89
+ `run-request.json`, content approval, fact-base JSON and Markdown, declared
90
+ author results, authored Markdown, the resolved theme, and every built
91
+ artifact. Canonical fact-base and theme hashes identify normalized objects;
92
+ they are intentionally distinct from serialized file-byte hashes. The mutable
93
+ manifest and build record are excluded from their own durability evidence and
94
+ are committed separately after verification. Older v1 manifests without
95
+ complete coverage fail with a legacy-manifest diagnostic and must be
96
+ regenerated.
97
+
55
98
  Build success and durability are separate:
56
99
 
57
100
  - `built-not-durable` means artifacts exist but verified commit or publish
@@ -69,7 +112,7 @@ content type and SHA-256 response bytes at public URLs, and writes
69
112
  fragments. Publishing is additive and does not run a root-wide destructive
70
113
  sync.
71
114
 
72
- Release validation drives the bounded palette/profile/template matrix in a real
115
+ Release validation drives the bounded curated-style/template matrix in a real
73
116
  installed Chromium browser and retains machine-readable viewport, clipping,
74
117
  motion, keyboard, no-JavaScript, and print measurements. The gate fails closed
75
118
  when no supported browser executable is available.
@@ -1,6 +1,6 @@
1
1
  {
2
- "cli": "0.2.10",
3
- "docs-config": "0.2.10",
4
- "docs-theme": "0.2.10",
5
- "docs-transforms": "0.2.10"
2
+ "cli": "0.2.12",
3
+ "docs-config": "0.2.12",
4
+ "docs-theme": "0.2.12",
5
+ "docs-transforms": "0.2.12"
6
6
  }
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: explainer-kit
3
- version: 1.0.1
3
+ version: 1.0.2
4
4
  description: Use when building destination-neutral visual explainer artifacts from explicit, versioned inputs.
5
5
  user-invocable: true
6
6
  allowed-tools: Read, Write, Edit, Bash, Grep, Glob, Agent, mcp__*
@@ -58,8 +58,14 @@ require a provider-neutral critic callback and invoke it exactly once.
58
58
  Optional claim `sections` tags route facts to matching recipe narrative
59
59
  sections; untagged claims remain shared context for every required section.
60
60
 
61
- Unattended calls use explicit, already-approved source artifacts, persist their
62
- review provenance in `source/content-approval.json`, and never prompt.
61
+ Unattended calls use explicit, already-approved source artifacts and require a
62
+ provider-neutral author callback once per recipe artifact. In-process callers
63
+ supply `options.author`; JSON-only CLI callers supply `--author-module`. The
64
+ core validates exact narrative sections and non-secret author provenance,
65
+ rejects excessive verbatim source overlap, retains each validated result under
66
+ `source/author/`, persists review provenance in
67
+ `source/content-approval.json`, and never prompts. Keep executable callback
68
+ references out of the persisted run request.
63
69
 
64
70
  Interactive runs stop with an `incomplete` outcome after writing
65
71
  `source/content/*.md`. Review and correct that Markdown, then provide an
@@ -30,6 +30,14 @@ claims, sources, overrides, and the freshness policy. It returns:
30
30
  No provider name, command, credential, or dispatch protocol is part of this
31
31
  contract.
32
32
 
33
+ Every unattended run also requires a provider-neutral author callback. An
34
+ in-process caller supplies `options.author(request)`; a JSON-only CLI caller
35
+ uses `--author-module author.mjs`. The core invokes it once per recipe artifact
36
+ with an `AuthorRequestV1` containing the exact narrative outline, reconciled
37
+ fact base, and bounded-discovery context. It must return an `AuthorResultV1`
38
+ with every required section in order, non-empty prose, and non-secret
39
+ provenance. The executable callback is never persisted in `run-request.json`.
40
+
33
41
  ## Explicit source forms
34
42
 
35
43
  - `factBase.mode: supplied` points to a valid `FactBaseV1` JSON file. The core
@@ -47,8 +55,9 @@ contract.
47
55
  reconciles the loaded claims and invokes the critic exactly once.
48
56
 
49
57
  An unattended request asserts that its explicit source artifacts are already
50
- approved. It does not prompt. Interactive review and same-run approval/resume
51
- are introduced separately and are not part of this contract.
58
+ approved. It does not prompt, and it fails before narrative serialization when
59
+ the author is absent, returns an invalid result, or copies excessive verbatim
60
+ source text. Interactive review and same-run approval/resume remain unchanged.
52
61
 
53
62
  ## Pipeline and retained package
54
63
 
@@ -56,14 +65,16 @@ The core executes:
56
65
 
57
66
  1. validate request and recipe
58
67
  2. reconcile or check the fact base
59
- 3. apply bounded discovery and create recipe content
68
+ 3. apply bounded discovery and obtain or create recipe content
60
69
  4. resolve one theme
61
70
  5. render typed artifacts
62
71
  6. run structural and optional browser QA
63
72
  7. write the manifest and build record
64
73
 
65
- The run package retains `source/fact-base.json`, `source/fact-base.md`,
66
- `source/content/*.md`, `theme.resolved.json`, rendered `site/` files,
74
+ The run package retains the privacy-safe `run-request.json`,
75
+ `source/content-approval.json`, `source/fact-base.json`,
76
+ `source/fact-base.md`, `source/content/*.md`, optional structured
77
+ `source/author/*.json` results, `theme.resolved.json`, rendered `site/` files,
67
78
  `manifest.json`, and `build-record.json` as far as each stage succeeds. A stage
68
79
  failure records a structured error and recovery action without deleting earlier
69
80
  outputs. Raw art direction is omitted unless the request explicitly opts in.
@@ -81,9 +92,13 @@ Durability and publishing are never implicit.
81
92
  Caller-created commit evidence is subsequently verified with
82
93
  `record-durability.mjs`; the core never creates commits. The first evidence
83
94
  commit must contain every path and byte hash in `manifest.immutableHashes`:
84
- fact-base JSON and Markdown, all content Markdown, the resolved theme, and
85
- every built artifact retained in the package. Mutable `manifest.json` and
95
+ the privacy-safe request, content approval, fact-base JSON and Markdown,
96
+ declared author results, all content Markdown, the resolved theme, and every
97
+ built artifact retained in the package. Mutable `manifest.json` and
86
98
  `build-record.json` remain excluded for the separate evidence update.
99
+ Schema-v1 manifests created before complete-package coverage are rejected
100
+ with a legacy-manifest diagnostic and must be regenerated; validators never
101
+ invent missing hashes.
87
102
  - `durability.strategy: publish` invokes the explicit `publish` callback with
88
103
  the complete publish request. A verified receipt is subsequently recorded as
89
104
  durability evidence.
@@ -0,0 +1,85 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "explainer-kit.author-request/v1",
4
+ "title": "AuthorRequestV1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "schemaVersion",
9
+ "run",
10
+ "recipe",
11
+ "artifact",
12
+ "narrativeOutline",
13
+ "factBase",
14
+ "discovery"
15
+ ],
16
+ "properties": {
17
+ "schemaVersion": { "const": "explainer-kit.author-request/v1" },
18
+ "run": {
19
+ "type": "object",
20
+ "additionalProperties": false,
21
+ "required": ["runId", "slug"],
22
+ "properties": {
23
+ "runId": { "type": "string", "minLength": 1 },
24
+ "slug": {
25
+ "type": "string",
26
+ "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$"
27
+ }
28
+ }
29
+ },
30
+ "recipe": {
31
+ "type": "object",
32
+ "additionalProperties": false,
33
+ "required": ["id", "version", "requiredNarrative"],
34
+ "properties": {
35
+ "id": { "type": "string", "minLength": 1 },
36
+ "version": { "type": "string", "minLength": 1 },
37
+ "requiredNarrative": {
38
+ "type": "array",
39
+ "items": { "type": "string", "minLength": 1 },
40
+ "minItems": 1,
41
+ "uniqueItems": true
42
+ }
43
+ }
44
+ },
45
+ "artifact": {
46
+ "type": "object",
47
+ "additionalProperties": false,
48
+ "required": ["id", "type"],
49
+ "properties": {
50
+ "id": { "type": "string", "minLength": 1 },
51
+ "type": { "enum": ["hub", "diagram", "explainer", "deck", "catalog"] }
52
+ }
53
+ },
54
+ "narrativeOutline": {
55
+ "type": "array",
56
+ "items": {
57
+ "type": "object",
58
+ "additionalProperties": false,
59
+ "required": ["id", "title"],
60
+ "properties": {
61
+ "id": { "type": "string", "minLength": 1 },
62
+ "title": { "type": "string", "minLength": 1 }
63
+ }
64
+ },
65
+ "minItems": 1,
66
+ "uniqueItems": true
67
+ },
68
+ "factBase": { "$ref": "explainer-kit.fact-base/v1" },
69
+ "discovery": {
70
+ "type": "object",
71
+ "additionalProperties": false,
72
+ "required": ["rounds", "findings", "reason"],
73
+ "properties": {
74
+ "rounds": { "type": "integer", "minimum": 0 },
75
+ "findings": {
76
+ "type": "array",
77
+ "items": { "type": "string", "minLength": 1 }
78
+ },
79
+ "reason": {
80
+ "enum": ["not-requested", "two-empty-rounds", "hard-maximum"]
81
+ }
82
+ }
83
+ }
84
+ }
85
+ }
@@ -0,0 +1,65 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "explainer-kit.author-result/v1",
4
+ "title": "AuthorResultV1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": ["schemaVersion", "artifactId", "content", "provenance"],
8
+ "properties": {
9
+ "schemaVersion": { "const": "explainer-kit.author-result/v1" },
10
+ "artifactId": { "type": "string", "minLength": 1 },
11
+ "content": {
12
+ "type": "object",
13
+ "additionalProperties": false,
14
+ "required": ["title", "description", "sections"],
15
+ "properties": {
16
+ "title": { "type": "string", "minLength": 1 },
17
+ "description": { "type": "string", "minLength": 1 },
18
+ "eyebrow": { "type": "string", "minLength": 1 },
19
+ "footer": { "type": "string", "minLength": 1 },
20
+ "sections": {
21
+ "type": "array",
22
+ "items": {
23
+ "type": "object",
24
+ "additionalProperties": false,
25
+ "required": ["id", "title", "prose"],
26
+ "properties": {
27
+ "id": { "type": "string", "minLength": 1 },
28
+ "title": { "type": "string", "minLength": 1 },
29
+ "prose": { "type": "string", "minLength": 1 }
30
+ }
31
+ },
32
+ "minItems": 1,
33
+ "uniqueItems": true
34
+ },
35
+ "artifactLinks": {
36
+ "type": "array",
37
+ "items": {
38
+ "type": "object",
39
+ "additionalProperties": false,
40
+ "required": ["id", "type", "label"],
41
+ "properties": {
42
+ "id": { "type": "string", "minLength": 1 },
43
+ "type": {
44
+ "enum": ["hub", "diagram", "explainer", "deck", "catalog"]
45
+ },
46
+ "label": { "type": "string", "minLength": 1 }
47
+ }
48
+ },
49
+ "uniqueItems": true
50
+ }
51
+ }
52
+ },
53
+ "provenance": {
54
+ "type": "object",
55
+ "additionalProperties": false,
56
+ "required": ["authorId", "generatedAt"],
57
+ "properties": {
58
+ "authorId": { "type": "string", "minLength": 1 },
59
+ "generatedAt": { "type": "string", "format": "date-time" },
60
+ "method": { "type": "string", "minLength": 1 },
61
+ "model": { "type": "string", "minLength": 1 }
62
+ }
63
+ }
64
+ }
65
+ }
@@ -43,7 +43,13 @@
43
43
  "factBasePath": { "$ref": "#/$defs/safeRelativePath" },
44
44
  "factBaseHash": { "$ref": "#/$defs/hash" },
45
45
  "sourceRevision": { "type": "string", "minLength": 1 },
46
- "inputHashes": { "$ref": "#/$defs/hashMap" }
46
+ "inputHashes": { "$ref": "#/$defs/hashMap" },
47
+ "authorResultPaths": {
48
+ "type": "array",
49
+ "items": { "$ref": "#/$defs/safeRelativePath" },
50
+ "minItems": 1,
51
+ "uniqueItems": true
52
+ }
47
53
  }
48
54
  },
49
55
  "theme": {
@@ -115,6 +115,14 @@
115
115
  "type": "object",
116
116
  "additionalProperties": false,
117
117
  "properties": {
118
+ "style": {
119
+ "enum": [
120
+ "clean-neutral",
121
+ "business-corporate",
122
+ "navy-ocean",
123
+ "dark-edgy"
124
+ ]
125
+ },
118
126
  "palette": { "type": "string", "minLength": 1 },
119
127
  "visualProfile": { "type": "string", "minLength": 1 },
120
128
  "suppliedBundlePath": {
@@ -178,6 +178,14 @@
178
178
  "additionalProperties": false,
179
179
  "required": ["derived"],
180
180
  "properties": {
181
+ "style": {
182
+ "enum": [
183
+ "clean-neutral",
184
+ "business-corporate",
185
+ "navy-ocean",
186
+ "dark-edgy"
187
+ ]
188
+ },
181
189
  "palette": { "type": "string", "minLength": 1 },
182
190
  "visualProfile": { "type": "string", "minLength": 1 },
183
191
  "derived": { "type": "boolean" },
@@ -12,7 +12,12 @@ const DECISIONS = new Map([
12
12
  ['rejected', 'rejected'],
13
13
  ]);
14
14
 
15
- export async function resolveContentApproval(run, mode, reviewedSource) {
15
+ export async function resolveContentApproval(
16
+ run,
17
+ mode,
18
+ reviewedSource,
19
+ authorResultPaths,
20
+ ) {
16
21
  assertRun(run);
17
22
  if (!MODES.has(mode)) {
18
23
  throw new Error('Content approval mode must be interactive or unattended.');
@@ -21,6 +26,7 @@ export async function resolveContentApproval(run, mode, reviewedSource) {
21
26
  const previous = await readPrevious(run);
22
27
  let record;
23
28
  if (mode === 'unattended') {
29
+ assertAuthorResultPaths(authorResultPaths);
24
30
  const provenance =
25
31
  reviewedSource ?? approvedSourceProvenance(run.request.factBase);
26
32
  assertProvenance(provenance);
@@ -30,6 +36,7 @@ export async function resolveContentApproval(run, mode, reviewedSource) {
30
36
  mode,
31
37
  status: 'approved',
32
38
  reviewedSource: structuredClone(provenance),
39
+ authorResultPaths: [...authorResultPaths],
33
40
  attempts: previous?.attempts ?? [],
34
41
  };
35
42
  } else if (reviewedSource === undefined) {
@@ -164,6 +171,24 @@ function assertProvenance(value) {
164
171
  }
165
172
  }
166
173
 
174
+ function assertAuthorResultPaths(value) {
175
+ if (
176
+ !Array.isArray(value) ||
177
+ value.length === 0 ||
178
+ new Set(value).size !== value.length ||
179
+ value.some(
180
+ (path) =>
181
+ typeof path !== 'string' ||
182
+ !/^source\/author\/[^/]+\.json$/.test(path) ||
183
+ path.includes('..'),
184
+ )
185
+ ) {
186
+ throw new Error(
187
+ 'Unattended content approval requires unique source/author result paths.',
188
+ );
189
+ }
190
+ }
191
+
167
192
  function assertRun(run) {
168
193
  if (
169
194
  !isObject(run) ||