@open-agent-toolkit/cli 0.2.5 → 0.2.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/assets/docs/cli-utilities/configuration.md +40 -0
- package/assets/docs/cli-utilities/tool-packs.md +31 -0
- package/assets/docs/workflows/projects/artifacts.md +27 -0
- package/assets/docs/workflows/skills/explainer-kit.md +125 -0
- package/assets/docs/workflows/skills/index.md +4 -0
- package/assets/migration/pjm-restructure.md +12 -0
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/explainer-kit/SKILL.md +95 -0
- package/assets/skills/explainer-kit/examples/project-explainer/content.md +31 -0
- package/assets/skills/explainer-kit/examples/project-explainer/fact-base.md +22 -0
- package/assets/skills/explainer-kit/examples/project-recap/content.md +34 -0
- package/assets/skills/explainer-kit/examples/project-recap/fact-base.md +22 -0
- package/assets/skills/explainer-kit/examples/theme-bundle.json +87 -0
- package/assets/skills/explainer-kit/palettes/ember.json +37 -0
- package/assets/skills/explainer-kit/palettes/forest.json +37 -0
- package/assets/skills/explainer-kit/palettes/neutral.json +37 -0
- package/assets/skills/explainer-kit/palettes/ocean.json +37 -0
- package/assets/skills/explainer-kit/palettes/violet.json +37 -0
- package/assets/skills/explainer-kit/profiles/clean.json +42 -0
- package/assets/skills/explainer-kit/profiles/editorial.json +42 -0
- package/assets/skills/explainer-kit/profiles/technical.json +39 -0
- package/assets/skills/explainer-kit/recipes/engineer-tour.json +33 -0
- package/assets/skills/explainer-kit/recipes/project-explainer.json +33 -0
- package/assets/skills/explainer-kit/recipes/project-recap.json +34 -0
- package/assets/skills/explainer-kit/references/contracts.md +101 -0
- package/assets/skills/explainer-kit/references/destination-contract.md +94 -0
- package/assets/skills/explainer-kit/references/extension-contract.md +71 -0
- package/assets/skills/explainer-kit/references/fact-base-contract.md +119 -0
- package/assets/skills/explainer-kit/schemas/build-record.schema.json +92 -0
- package/assets/skills/explainer-kit/schemas/durability-evidence.schema.json +53 -0
- package/assets/skills/explainer-kit/schemas/fact-base.schema.json +129 -0
- package/assets/skills/explainer-kit/schemas/manifest.schema.json +193 -0
- package/assets/skills/explainer-kit/schemas/publish-receipt.schema.json +97 -0
- package/assets/skills/explainer-kit/schemas/publish-request.schema.json +32 -0
- package/assets/skills/explainer-kit/schemas/run-request.schema.json +132 -0
- package/assets/skills/explainer-kit/schemas/theme.schema.json +217 -0
- package/assets/skills/explainer-kit/scripts/lib/content-approval.mjs +180 -0
- package/assets/skills/explainer-kit/scripts/lib/contracts.mjs +680 -0
- package/assets/skills/explainer-kit/scripts/lib/durability.mjs +538 -0
- package/assets/skills/explainer-kit/scripts/lib/fact-base.mjs +494 -0
- package/assets/skills/explainer-kit/scripts/lib/fs-safe.mjs +218 -0
- package/assets/skills/explainer-kit/scripts/lib/qa.mjs +512 -0
- package/assets/skills/explainer-kit/scripts/lib/recipes.mjs +289 -0
- package/assets/skills/explainer-kit/scripts/lib/records.mjs +231 -0
- package/assets/skills/explainer-kit/scripts/lib/render.mjs +485 -0
- package/assets/skills/explainer-kit/scripts/lib/s3-static.mjs +587 -0
- package/assets/skills/explainer-kit/scripts/lib/safe-paths.mjs +96 -0
- package/assets/skills/explainer-kit/scripts/lib/theme.mjs +332 -0
- package/assets/skills/explainer-kit/scripts/publish.mjs +76 -0
- package/assets/skills/explainer-kit/scripts/record-durability.mjs +64 -0
- package/assets/skills/explainer-kit/scripts/render-qa.mjs +273 -0
- package/assets/skills/explainer-kit/scripts/run.mjs +778 -0
- package/assets/skills/explainer-kit/scripts/validate.mjs +59 -0
- package/assets/skills/explainer-kit/templates/deck-shell.html +233 -0
- package/assets/skills/explainer-kit/templates/diagram-shell.html +219 -0
- package/assets/skills/explainer-kit/templates/engineer-tour.html +273 -0
- package/assets/skills/explainer-kit/templates/house-style.html +218 -0
- package/assets/skills/oat-explainer-kit/SKILL.md +92 -0
- package/assets/skills/oat-explainer-kit/references/config-contract.md +67 -0
- package/assets/skills/oat-explainer-kit/references/lifecycle-contract.md +143 -0
- package/assets/skills/oat-explainer-kit/references/migration.md +143 -0
- package/assets/skills/oat-explainer-kit/scripts/bind-project-sources.mjs +103 -0
- package/assets/skills/oat-explainer-kit/scripts/check-core.mjs +127 -0
- package/assets/skills/oat-explainer-kit/scripts/finalize-tracked-run.mjs +392 -0
- package/assets/skills/oat-explainer-kit/scripts/persist-intent.mjs +130 -0
- package/assets/skills/oat-explainer-kit/scripts/resolve-config.mjs +293 -0
- package/assets/skills/oat-explainer-kit/scripts/resolve-intent.mjs +209 -0
- package/assets/skills/oat-explainer-kit/scripts/resolve-paths.mjs +166 -0
- package/assets/skills/oat-explainer-kit/scripts/run.mjs +284 -0
- package/assets/skills/oat-project-autonomous/SKILL.md +22 -1
- package/assets/skills/oat-project-autonomous/references/gate-inventory.md +5 -1
- package/assets/skills/oat-project-complete/SKILL.md +166 -28
- package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +5 -1
- package/assets/skills/oat-project-implement/SKILL.md +1 -1
- package/assets/skills/oat-project-implement/references/completion-and-closeout.md +17 -0
- package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +5 -1
- package/assets/skills/oat-project-plan/SKILL.md +30 -1
- package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +5 -1
- package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +5 -1
- package/assets/skills/oat-project-summary/SKILL.md +20 -1
- package/assets/skills/oat-wave-execute/SKILL.md +1 -1
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +232 -1
- package/dist/commands/init/tools/shared/skill-manifest.d.ts +2 -2
- package/dist/commands/init/tools/shared/skill-manifest.d.ts.map +1 -1
- package/dist/commands/init/tools/shared/skill-manifest.js +2 -0
- package/dist/commands/project/archive/archive-utils.d.ts +12 -0
- package/dist/commands/project/archive/archive-utils.d.ts.map +1 -1
- package/dist/commands/project/archive/archive-utils.js +320 -8
- package/dist/commands/project/archive/index.d.ts.map +1 -1
- package/dist/commands/project/archive/index.js +1 -0
- package/dist/commands/project/archive/push-runner.d.ts +1 -0
- package/dist/commands/project/archive/push-runner.d.ts.map +1 -1
- package/dist/commands/project/archive/push-runner.js +9 -2
- package/dist/config/oat-config.d.ts +26 -0
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +88 -0
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +18 -0
- package/dist/validation/project-state.d.ts +3 -0
- package/dist/validation/project-state.d.ts.map +1 -1
- package/dist/validation/project-state.js +91 -0
- package/package.json +2 -2
- /package/assets/skills/{oat-wave-execute/assets/program-recap.recipe.json → explainer-kit/recipes/program-recap.json} +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Lifecycle intent contract
|
|
2
|
+
|
|
3
|
+
The OAT adapter resolves `projectExplainer` and `projectRecap` intent without
|
|
4
|
+
reading or mutating project files. Lifecycle callers pass explicit inputs to
|
|
5
|
+
`resolveIntent(...)` and persist only the returned `record`, when present.
|
|
6
|
+
|
|
7
|
+
## Resolution
|
|
8
|
+
|
|
9
|
+
Precedence is:
|
|
10
|
+
|
|
11
|
+
1. lifecycle mode policy;
|
|
12
|
+
2. valid project state;
|
|
13
|
+
3. `workflow.explainers.*` preference;
|
|
14
|
+
4. the built-in `ask` default.
|
|
15
|
+
|
|
16
|
+
`resolveIntent({ product, mode, state, preference, kickoffRequest, answer,
|
|
17
|
+
now })` is pure. Its result contains the effective `decision`, the
|
|
18
|
+
`resolutionSource`, whether a prompt is needed, an optional state `record`, and
|
|
19
|
+
warnings.
|
|
20
|
+
|
|
21
|
+
In autonomous mode, `projectRecap` always resolves to `generate` with source
|
|
22
|
+
`autonomous_policy`. A lower-precedence skip or `never` preference is overridden
|
|
23
|
+
and reported as a warning. Autonomous `projectExplainer` resolves to `generate`
|
|
24
|
+
only when the kickoff prompt explicitly requested it; otherwise it resolves to
|
|
25
|
+
`skip` without writing an invalid prompt-source skip record.
|
|
26
|
+
|
|
27
|
+
In interactive mode, an existing valid project record prevents another prompt.
|
|
28
|
+
Preferences `always` and `never` resolve directly but are not copied into
|
|
29
|
+
project state: doing so would freeze a workflow preference snapshot.
|
|
30
|
+
An unresolved `ask` prompts once. Either answer produces an `interactive`
|
|
31
|
+
record, so a decision made at any lifecycle gate can be persisted and reused.
|
|
32
|
+
|
|
33
|
+
## State records
|
|
34
|
+
|
|
35
|
+
Records use the Phase 1 state contract:
|
|
36
|
+
|
|
37
|
+
```yaml
|
|
38
|
+
oat_project_explainer:
|
|
39
|
+
decision: generate
|
|
40
|
+
source: kickoff_prompt
|
|
41
|
+
decided_at: '2026-07-18T02:30:00Z'
|
|
42
|
+
oat_project_recap:
|
|
43
|
+
decision: generate
|
|
44
|
+
source: autonomous_policy
|
|
45
|
+
decided_at: '2026-07-18T02:30:00Z'
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Allowed decision/source pairs are:
|
|
49
|
+
|
|
50
|
+
| Product | Allowed pairs |
|
|
51
|
+
| ------------------ | ------------------------------------------------------------------------ |
|
|
52
|
+
| `projectExplainer` | `generate/interactive`, `skip/interactive`, `generate/kickoff_prompt` |
|
|
53
|
+
| `projectRecap` | `generate/interactive`, `skip/interactive`, `generate/autonomous_policy` |
|
|
54
|
+
|
|
55
|
+
In particular, `skip/autonomous_policy` is invalid.
|
|
56
|
+
|
|
57
|
+
## Safe persistence
|
|
58
|
+
|
|
59
|
+
`hashStateContent(content)` creates the optimistic concurrency token used by
|
|
60
|
+
`persistIntent(...)`. A caller reads `state.md`, resolves intent, and supplies
|
|
61
|
+
that content hash with the chosen record. Persistence:
|
|
62
|
+
|
|
63
|
+
- accepts only a regular `state.md` file and rejects symlinks;
|
|
64
|
+
- validates the closed record and product-specific source matrix;
|
|
65
|
+
- rejects a changed file with `E_INTENT_STALE_WRITE`;
|
|
66
|
+
- replaces only the selected top-level intent block while preserving unrelated
|
|
67
|
+
frontmatter fields and the Markdown body; and
|
|
68
|
+
- writes a same-directory temporary file and atomically renames it.
|
|
69
|
+
|
|
70
|
+
On a stale-write conflict, the caller must re-read state, resolve precedence
|
|
71
|
+
again, and decide whether a write is still required. It must not retry the old
|
|
72
|
+
record blindly.
|
|
73
|
+
|
|
74
|
+
## Tracked-run finalization
|
|
75
|
+
|
|
76
|
+
`planTrackedRunFinalization(request, context)` is the shared command planner for
|
|
77
|
+
tracked project explainer and recap runs. The request contains `runRoot`,
|
|
78
|
+
`manifestPath`, `commitMode`, and optional `relocatedFrom`. Context supplies the
|
|
79
|
+
repository root, project name, and, for `completion-bookkeeping`, the existing
|
|
80
|
+
full artifact commit SHA.
|
|
81
|
+
|
|
82
|
+
The returned stages must run in order:
|
|
83
|
+
|
|
84
|
+
1. In `dedicated` mode, commit exactly the manifest-declared immutable package
|
|
85
|
+
with `docs(oat): persist <recipe> for <project>`. In
|
|
86
|
+
`completion-bookkeeping` mode, reuse the caller's existing lifecycle commit.
|
|
87
|
+
2. Replace `$ARTIFACT_COMMIT` with the created full SHA when present, then pass
|
|
88
|
+
the planned durability request to the compatible core's
|
|
89
|
+
`recordDurability(...)`. The core verifies commit blobs and updates records;
|
|
90
|
+
it never invokes Git or creates commits.
|
|
91
|
+
3. Commit only `manifest.json` and `build-record.json` as the evidence update.
|
|
92
|
+
4. Call `verifyTrackedRunFinalization(...)`, then push once so the artifact and
|
|
93
|
+
evidence commits travel together.
|
|
94
|
+
|
|
95
|
+
Artifact evidence contains retained fact-base, content, theme, and rendered
|
|
96
|
+
paths. It always excludes mutable `manifest.json` and `build-record.json`.
|
|
97
|
+
Generated Git commands use explicit pathspecs and `commit --only`; callers must
|
|
98
|
+
also snapshot unrelated working-tree changes before execution and supply the
|
|
99
|
+
before/after lists to the verifier. A mismatch prevents pushing.
|
|
100
|
+
|
|
101
|
+
An evidence-verification failure is a successful finalizer termination with
|
|
102
|
+
run outcome `built-not-durable`: commit the warning-bearing mutable records and
|
|
103
|
+
push them with the artifact commit. It does not block project completion. A
|
|
104
|
+
later attempt reuses the same artifact commit, supplies the current HEAD as
|
|
105
|
+
`currentHead`, invokes core verification again, and appends a new evidence
|
|
106
|
+
commit. If the manifest already contains matching durable commit evidence, the
|
|
107
|
+
planner returns `complete` with no commands, making repeat termination
|
|
108
|
+
idempotent.
|
|
109
|
+
|
|
110
|
+
For archive relocation, `relocatedFrom` identifies the prior active run for
|
|
111
|
+
caller reporting. The current run's immutable paths and the export bookkeeping
|
|
112
|
+
commit are submitted to the core; core evidence supersession remains the
|
|
113
|
+
authoritative relocation record.
|
|
114
|
+
|
|
115
|
+
## Completion-time archive relocation
|
|
116
|
+
|
|
117
|
+
Completion consumes the machine-readable `oat project archive --json` report.
|
|
118
|
+
When a recap was selected, `projectRecapExport.sourceRunRoot`,
|
|
119
|
+
`projectRecapExport.exportRoot`, and
|
|
120
|
+
`projectRecapExport.manifest.relativePath` identify the relocation. The caller
|
|
121
|
+
must not predict the dated export path or substitute the gitignored local
|
|
122
|
+
archive.
|
|
123
|
+
|
|
124
|
+
Archive completion is exactly two commits: the lifecycle bookkeeping commit, then the exported recap evidence commit. The bookkeeping commit contains the
|
|
125
|
+
tracked export and active-tree deletion and is passed to the finalizer as the
|
|
126
|
+
existing artifact commit in `completion-bookkeeping` mode. The finalizer
|
|
127
|
+
attests only immutable package paths under the reported export root. The
|
|
128
|
+
second commit contains only the updated exported `manifest.json` and
|
|
129
|
+
`build-record.json`; one push follows both commits.
|
|
130
|
+
|
|
131
|
+
The exported-path evidence supersedes the selected run's prior active-path evidence. Mutable records are never part of their own commit evidence, and no
|
|
132
|
+
path under `.oat/projects/archived/` is evidence.
|
|
133
|
+
|
|
134
|
+
Failure to verify the exported commit evidence is non-blocking. The tracked
|
|
135
|
+
export remains committed, the mutable records retain the warning and
|
|
136
|
+
`built-not-durable` outcome, and the evidence-record commit and push still
|
|
137
|
+
complete. A later attestation may recover durability without repeating the
|
|
138
|
+
archive.
|
|
139
|
+
|
|
140
|
+
Post-archive summary and PR recap links target `projectRecapExport.exportRoot`
|
|
141
|
+
under `.oat/repo/reference/project-recaps/` on the current head branch. The
|
|
142
|
+
tracked summary export and the PR body may carry that link; the gitignored
|
|
143
|
+
archive never does.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Private-wrapper migration
|
|
2
|
+
|
|
3
|
+
This runbook migrates the externally owned private wrapper from the monolithic
|
|
4
|
+
`oat-explainer-kit` 0.4.1 workflow to the frozen v1 pre/core/post seam. Keep the
|
|
5
|
+
0.4.1 installation and its private configuration available until one unchanged
|
|
6
|
+
release candidate passes every acceptance gate.
|
|
7
|
+
|
|
8
|
+
## Prepare the private wrapper
|
|
9
|
+
|
|
10
|
+
1. Back up the installed 0.4.1 skill, private presets, Stoa configuration, and
|
|
11
|
+
Google Docs settings. Confirm the backup contains `SKILL.md`, scripts,
|
|
12
|
+
references, and templates.
|
|
13
|
+
2. Install the candidate `explainer-kit` at user scope and verify that the
|
|
14
|
+
wrapper resolves that installed copy, never a source checkout.
|
|
15
|
+
3. Change wrapper pre-resolution to produce one
|
|
16
|
+
`explainer-kit.run-request/v1`. Keep preset selection, vault/Stoa paths,
|
|
17
|
+
Google account data, authentication choices, and personal destination
|
|
18
|
+
topology in private wrapper configuration.
|
|
19
|
+
4. Invoke the core once, consume only `explainer-kit.manifest/v1` and the
|
|
20
|
+
optional publish receipt, then perform Stoa notes, Google Docs sync, and
|
|
21
|
+
private link maintenance as post-run work.
|
|
22
|
+
|
|
23
|
+
Do not add a plugin, inject private work between core stages, or add private
|
|
24
|
+
lanes to public OAT config.
|
|
25
|
+
|
|
26
|
+
### Private `presets.example.json`
|
|
27
|
+
|
|
28
|
+
The private wrapper's `personal-oat` example should carry the confirmed public
|
|
29
|
+
root:
|
|
30
|
+
|
|
31
|
+
```json
|
|
32
|
+
{
|
|
33
|
+
"presets": {
|
|
34
|
+
"personal-oat": {
|
|
35
|
+
"publicBaseUrl": "https://dy4vzrzaexuy5.cloudfront.net"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Copy `presets.example.json` to an untracked `presets.json` before adding
|
|
42
|
+
accounts or authentication details.
|
|
43
|
+
|
|
44
|
+
### Private Stoa configuration
|
|
45
|
+
|
|
46
|
+
The eventual private Stoa configuration may use the same confirmed public root
|
|
47
|
+
to create manifest-derived links:
|
|
48
|
+
|
|
49
|
+
```json
|
|
50
|
+
{
|
|
51
|
+
"explainerLinks": {
|
|
52
|
+
"publicBaseUrl": "https://dy4vzrzaexuy5.cloudfront.net",
|
|
53
|
+
"source": "explainer-kit.manifest/v1"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
This is private-wrapper migration/config context, not a public core default or
|
|
59
|
+
neutral fixture.
|
|
60
|
+
|
|
61
|
+
## Release-candidate sequence
|
|
62
|
+
|
|
63
|
+
1. Build and retain the packaged RC in a dedicated builder-owned directory;
|
|
64
|
+
record its immutable RC identity:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
node tools/release/build-explainer-rc.mjs \
|
|
68
|
+
--output dist/explainer-kit-rc \
|
|
69
|
+
--record .oat/repo/reference/explainer-kit-acceptance/v1/rc.json
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
The builder rejects repository/source roots, symlinks, and unowned existing
|
|
73
|
+
directories. Reuse only an output carrying its ownership marker.
|
|
74
|
+
|
|
75
|
+
2. Run packaged direct-core and OAT-adapter build-only smoke tests.
|
|
76
|
+
3. Migrate the real private wrapper against that exact RC.
|
|
77
|
+
4. Run the operator-owned wrapper E2E as an executable pre/core/post sequence:
|
|
78
|
+
resolve the private preset and external request; invoke the packaged core;
|
|
79
|
+
then publish the manifest, retain its complete receipt, and perform
|
|
80
|
+
vault/Stoa, Google Docs, and personal-link work. Verify all post-run evidence
|
|
81
|
+
against the immutable core execution record.
|
|
82
|
+
5. Run the live S3/CDN acceptance against the same unchanged RC.
|
|
83
|
+
6. Promote only when both retained acceptance records pass and reference the
|
|
84
|
+
same RC identity.
|
|
85
|
+
|
|
86
|
+
Every packaged invocation supplies the retained artifacts explicitly; there is
|
|
87
|
+
no current-working-directory fallback. The wrapper core stage does not declare
|
|
88
|
+
post-run receipt evidence:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
node tools/release/run-explainer-rc.mjs \
|
|
92
|
+
--rc-manifest .oat/repo/reference/explainer-kit-acceptance/v1/rc.json \
|
|
93
|
+
--artifacts-dir dist/explainer-kit-rc \
|
|
94
|
+
--entry scripts/run.mjs \
|
|
95
|
+
--record .oat/repo/reference/explainer-kit-acceptance/v1/private-wrapper-execution.json \
|
|
96
|
+
-- \
|
|
97
|
+
--request /path/to/private/run-request.json
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
The packaged CLI emits exactly one complete JSON result document; pretty
|
|
101
|
+
printing across lines is valid and progress text is not. After that command
|
|
102
|
+
returns, the private wrapper publishes and links the core manifest. Retain
|
|
103
|
+
`private-wrapper-manifest.json`,
|
|
104
|
+
`private-wrapper-publish-receipt.json`, and
|
|
105
|
+
`private-wrapper-result.json` beside the RC identity. Wrapper acceptance reads
|
|
106
|
+
and validates the full receipt as a separate post-run stage and rejects a
|
|
107
|
+
foreign run ID, sentinel, artifact set, or manifest hash even when caller-owned
|
|
108
|
+
files repeat the same receipt hash.
|
|
109
|
+
|
|
110
|
+
The live connector stage is a separate packaged invocation:
|
|
111
|
+
|
|
112
|
+
```bash
|
|
113
|
+
node tools/release/run-explainer-rc.mjs \
|
|
114
|
+
--rc-manifest .oat/repo/reference/explainer-kit-acceptance/v1/rc.json \
|
|
115
|
+
--artifacts-dir dist/explainer-kit-rc \
|
|
116
|
+
--entry scripts/publish.mjs \
|
|
117
|
+
--record .oat/repo/reference/explainer-kit-acceptance/v1/live-publish-result.json \
|
|
118
|
+
-- \
|
|
119
|
+
--request .oat/repo/reference/explainer-kit-acceptance/v1/live-publish-request.json \
|
|
120
|
+
--receipt .oat/repo/reference/explainer-kit-acceptance/v1/publish-receipt.json \
|
|
121
|
+
--confirm-publish
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Retain the execution record produced by that command. Acceptance binds it to
|
|
125
|
+
the canonical request, manifest, receipt, and core run ID and rejects stale
|
|
126
|
+
cross-run evidence.
|
|
127
|
+
|
|
128
|
+
The in-repository compatibility fixture is a development guard. It does not
|
|
129
|
+
satisfy the operator-owned real-wrapper gate.
|
|
130
|
+
|
|
131
|
+
## Rollback
|
|
132
|
+
|
|
133
|
+
If migration or acceptance fails, do not promote the candidate:
|
|
134
|
+
|
|
135
|
+
1. Preserve the failed candidate's sanitized diagnostics and issue a new RC
|
|
136
|
+
only after correcting the public seam or private wrapper.
|
|
137
|
+
2. Restore the backed-up 0.4.1 skill and private configuration.
|
|
138
|
+
3. Remove the candidate user-scope core and refresh provider views with
|
|
139
|
+
`oat sync --scope all`.
|
|
140
|
+
4. Verify one known-good 0.4.1 build before resuming normal wrapper use.
|
|
141
|
+
|
|
142
|
+
Do not retire the backup until the unchanged promoted RC has passed the
|
|
143
|
+
operator-owned wrapper and live-publish gates.
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { access, readFile, realpath } from 'node:fs/promises';
|
|
2
|
+
import { basename, join } from 'node:path';
|
|
3
|
+
|
|
4
|
+
const RECIPE_ARTIFACTS = Object.freeze({
|
|
5
|
+
'project-explainer': ['plan', 'design', 'spec'],
|
|
6
|
+
'project-recap': ['plan', 'design', 'spec', 'implementation', 'summary'],
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export async function bindProjectSources({
|
|
10
|
+
projectRoot,
|
|
11
|
+
recipe,
|
|
12
|
+
suppliedFactBasePath,
|
|
13
|
+
}) {
|
|
14
|
+
if (!projectRoot) {
|
|
15
|
+
throw new TypeError('projectRoot is required to bind OAT artifacts.');
|
|
16
|
+
}
|
|
17
|
+
const artifactIds = RECIPE_ARTIFACTS[recipe];
|
|
18
|
+
if (!artifactIds) {
|
|
19
|
+
throw new Error(`Unsupported OAT project recipe: ${recipe}`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const canonicalProjectRoot = await realpath(projectRoot);
|
|
23
|
+
if (suppliedFactBasePath) {
|
|
24
|
+
const path = await realpath(suppliedFactBasePath);
|
|
25
|
+
return {
|
|
26
|
+
factBase: {
|
|
27
|
+
mode: 'supplied',
|
|
28
|
+
path,
|
|
29
|
+
freshnessPolicy: 'live-wins',
|
|
30
|
+
},
|
|
31
|
+
reviewedSource: {
|
|
32
|
+
kind: 'approved-fact-base',
|
|
33
|
+
locator: path,
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const sourceSetId = basename(canonicalProjectRoot);
|
|
39
|
+
const sources = [];
|
|
40
|
+
for (const id of artifactIds) {
|
|
41
|
+
const locator = join(canonicalProjectRoot, `${id}.md`);
|
|
42
|
+
try {
|
|
43
|
+
await access(locator);
|
|
44
|
+
} catch (error) {
|
|
45
|
+
if (error?.code === 'ENOENT') continue;
|
|
46
|
+
throw error;
|
|
47
|
+
}
|
|
48
|
+
sources.push({
|
|
49
|
+
id,
|
|
50
|
+
kind: 'file',
|
|
51
|
+
locator: await realpath(locator),
|
|
52
|
+
role: 'project',
|
|
53
|
+
sourceSetId,
|
|
54
|
+
authoritativeFor: authoritativeTopics(id),
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
if (sources.length === 0) {
|
|
58
|
+
throw new Error(
|
|
59
|
+
`No approved OAT lifecycle artifacts were found for ${recipe}.`,
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
factBase: {
|
|
65
|
+
mode: 'federated',
|
|
66
|
+
freshnessPolicy: 'live-wins',
|
|
67
|
+
sources,
|
|
68
|
+
},
|
|
69
|
+
reviewedSource: {
|
|
70
|
+
kind: 'approved-oat-artifacts',
|
|
71
|
+
locator: canonicalProjectRoot,
|
|
72
|
+
},
|
|
73
|
+
sourceLoader: loadOatArtifact,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function loadOatArtifact(source) {
|
|
78
|
+
const text = (await readFile(source.locator, 'utf8')).trim();
|
|
79
|
+
return {
|
|
80
|
+
claims: [
|
|
81
|
+
{
|
|
82
|
+
id: source.id,
|
|
83
|
+
text,
|
|
84
|
+
locator: source.locator,
|
|
85
|
+
},
|
|
86
|
+
],
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function authoritativeTopics(id) {
|
|
91
|
+
return {
|
|
92
|
+
plan: ['phases', 'validation-approach'],
|
|
93
|
+
design: ['planned-architecture', 'decisions', 'risks'],
|
|
94
|
+
spec: ['original-request', 'requirements'],
|
|
95
|
+
implementation: [
|
|
96
|
+
'key-agent-decisions',
|
|
97
|
+
'as-built-architecture',
|
|
98
|
+
'implementation-record',
|
|
99
|
+
'validation-evidence',
|
|
100
|
+
],
|
|
101
|
+
summary: ['outcome'],
|
|
102
|
+
}[id];
|
|
103
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { basename, dirname, join, resolve } from 'node:path';
|
|
4
|
+
|
|
5
|
+
export const CORE_INSTALL_COMMAND = 'oat tools install utility --scope user';
|
|
6
|
+
export const CORE_UPDATE_COMMAND =
|
|
7
|
+
'oat tools update --pack utility --scope user';
|
|
8
|
+
|
|
9
|
+
export async function checkCoreCompatibility({
|
|
10
|
+
adapterRoot,
|
|
11
|
+
userSkillsRoot = join(homedir(), '.agents', 'skills'),
|
|
12
|
+
minimumVersion,
|
|
13
|
+
}) {
|
|
14
|
+
const minimum = parseVersion(minimumVersion);
|
|
15
|
+
if (minimum === null) {
|
|
16
|
+
throw new TypeError(
|
|
17
|
+
`minimumVersion must be a semantic version, received: ${minimumVersion}`,
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const canonicalAdapterRoot = resolve(adapterRoot);
|
|
22
|
+
const adapterSkillsRoot = dirname(canonicalAdapterRoot);
|
|
23
|
+
const canonicalUserSkillsRoot = resolve(userSkillsRoot);
|
|
24
|
+
const coreRoot = join(canonicalUserSkillsRoot, 'explainer-kit');
|
|
25
|
+
if (
|
|
26
|
+
basename(canonicalAdapterRoot) !== 'oat-explainer-kit' ||
|
|
27
|
+
basename(adapterSkillsRoot) !== 'skills' ||
|
|
28
|
+
basename(dirname(adapterSkillsRoot)) !== '.agents' ||
|
|
29
|
+
basename(canonicalUserSkillsRoot) !== 'skills' ||
|
|
30
|
+
basename(dirname(canonicalUserSkillsRoot)) !== '.agents'
|
|
31
|
+
) {
|
|
32
|
+
return failure({
|
|
33
|
+
code: 'invalid-layout',
|
|
34
|
+
coreRoot,
|
|
35
|
+
minimumVersion,
|
|
36
|
+
message:
|
|
37
|
+
'oat-explainer-kit is not running from an installed canonical .agents/skills path.',
|
|
38
|
+
guidance: CORE_INSTALL_COMMAND,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
let skill;
|
|
43
|
+
try {
|
|
44
|
+
skill = await readFile(join(coreRoot, 'SKILL.md'), 'utf8');
|
|
45
|
+
} catch (error) {
|
|
46
|
+
if (error && typeof error === 'object' && error.code === 'ENOENT') {
|
|
47
|
+
return failure({
|
|
48
|
+
code: 'missing',
|
|
49
|
+
coreRoot,
|
|
50
|
+
minimumVersion,
|
|
51
|
+
message: 'A canonical installed explainer-kit core was not found.',
|
|
52
|
+
guidance: CORE_INSTALL_COMMAND,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
throw error;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const installedVersion = readFrontmatterVersion(skill);
|
|
59
|
+
const installed = parseVersion(installedVersion);
|
|
60
|
+
if (
|
|
61
|
+
installed === null ||
|
|
62
|
+
installed.major !== minimum.major ||
|
|
63
|
+
installed.minor < minimum.minor
|
|
64
|
+
) {
|
|
65
|
+
return failure({
|
|
66
|
+
code: 'incompatible',
|
|
67
|
+
coreRoot,
|
|
68
|
+
installedVersion,
|
|
69
|
+
minimumVersion,
|
|
70
|
+
message: installedVersion
|
|
71
|
+
? `Installed explainer-kit ${installedVersion} is incompatible with required ${minimumVersion}.`
|
|
72
|
+
: 'Installed explainer-kit has no valid version.',
|
|
73
|
+
guidance: CORE_UPDATE_COMMAND,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return {
|
|
78
|
+
ok: true,
|
|
79
|
+
code: 'compatible',
|
|
80
|
+
coreRoot,
|
|
81
|
+
installedVersion,
|
|
82
|
+
minimumVersion,
|
|
83
|
+
message: `Installed explainer-kit ${installedVersion} is compatible.`,
|
|
84
|
+
guidance: null,
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function failure({
|
|
89
|
+
code,
|
|
90
|
+
coreRoot,
|
|
91
|
+
installedVersion = null,
|
|
92
|
+
minimumVersion,
|
|
93
|
+
message,
|
|
94
|
+
guidance,
|
|
95
|
+
}) {
|
|
96
|
+
return {
|
|
97
|
+
ok: false,
|
|
98
|
+
code,
|
|
99
|
+
coreRoot,
|
|
100
|
+
installedVersion,
|
|
101
|
+
minimumVersion,
|
|
102
|
+
message,
|
|
103
|
+
guidance,
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function readFrontmatterVersion(content) {
|
|
108
|
+
const match = content.match(/^version:\s*([^\s#]+)\s*(?:#.*)?$/m);
|
|
109
|
+
return match?.[1] ?? null;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
function parseVersion(value) {
|
|
113
|
+
if (typeof value !== 'string') {
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
const match = value.match(
|
|
117
|
+
/^(\d+)\.(\d+)\.(\d+)(?:-[0-9A-Za-z]+(?:[.-][0-9A-Za-z]+)*)?$/,
|
|
118
|
+
);
|
|
119
|
+
if (!match) {
|
|
120
|
+
return null;
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
major: Number(match[1]),
|
|
124
|
+
minor: Number(match[2]),
|
|
125
|
+
patch: Number(match[3]),
|
|
126
|
+
};
|
|
127
|
+
}
|