@open-agent-toolkit/cli 0.3.15 → 0.3.17
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/NOTICES.md +48 -0
- package/assets/agents/oat-phase-implementer.md +26 -6
- package/assets/agents/oat-reviewer.md +51 -1
- package/assets/bundle-metadata.json +1 -1
- package/assets/docs/contributing/documentation.md +4 -0
- package/assets/docs/contributing/skills.md +3 -1
- package/assets/docs/getting-started/bootstrap.md +1 -1
- package/assets/docs/getting-started/index.md +0 -4
- package/assets/docs/getting-started/tool-packs.md +0 -7
- package/assets/docs/provider-sync/commands.md +21 -0
- package/assets/docs/reference/cli-reference.md +44 -2
- package/assets/docs/reference/config-and-local-state.md +11 -2
- package/assets/docs/reference/configuration.md +10 -2
- package/assets/docs/reference/project-artifacts.md +43 -8
- package/assets/docs/skills/index.md +1 -0
- package/assets/docs/skills/recon.md +8 -5
- package/assets/docs/skills/repo-improve.md +9 -7
- package/assets/docs/workflows/advanced/autonomy.md +50 -0
- package/assets/docs/workflows/advanced/workflow-gates.md +109 -10
- package/assets/docs/workflows/approvals-and-automation.md +3 -1
- package/assets/docs/workflows/backlog-and-planning/backlog-lifecycle.md +25 -24
- package/assets/docs/workflows/backlog-and-planning/remote-project-management.md +0 -7
- package/assets/docs/workflows/ideas/lifecycle.md +2 -7
- package/assets/docs/workflows/projects/closeout/closeout-skills.md +62 -1
- package/assets/docs/workflows/projects/execution/implementation-execution.md +23 -3
- package/assets/docs/workflows/projects/execution/project-log.md +6 -0
- package/assets/docs/workflows/projects/lifecycle.md +7 -0
- package/assets/docs/workflows/projects/reviews/index.md +63 -1
- package/assets/docs/workflows/projects/reviews/review-flavors.md +8 -0
- package/assets/docs/workflows/waves/wave-workflows.md +11 -3
- package/assets/public-package-versions.json +4 -4
- package/assets/skills/oat-agent-instructions-apply/SKILL.md +14 -4
- package/assets/skills/oat-brainstorm/SKILL.md +17 -13
- package/assets/skills/oat-docs-apply/SKILL.md +13 -3
- package/assets/skills/oat-doctor/SKILL.md +11 -1
- package/assets/skills/oat-explainer-kit/SKILL.md +1 -1
- package/assets/skills/oat-explainer-kit/references/lifecycle-contract.md +6 -3
- package/assets/skills/oat-pjm-review-backlog/SKILL.md +2 -2
- package/assets/skills/oat-pjm-update-repo-reference/SKILL.md +28 -3
- package/assets/skills/oat-project-autonomous/SKILL.md +60 -5
- package/assets/skills/oat-project-autonomous/references/gate-inventory.md +210 -165
- package/assets/skills/oat-project-capture/SKILL.md +7 -3
- package/assets/skills/oat-project-complete/SKILL.md +39 -34
- package/assets/skills/oat-project-complete/scripts/execute-synced-archive-entry.mjs +106 -28
- package/assets/skills/oat-project-complete/scripts/parse-synced-archive-resume-fields.mjs +30 -3
- package/assets/skills/oat-project-complete-auto/SKILL.md +388 -0
- package/assets/skills/oat-project-design/SKILL.md +12 -9
- package/assets/skills/oat-project-discover/SKILL.md +8 -4
- package/assets/skills/oat-project-document/SKILL.md +14 -5
- package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +210 -165
- package/assets/skills/oat-project-implement/SKILL.md +6 -1
- package/assets/skills/oat-project-implement/references/completion-and-closeout.md +34 -7
- package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +210 -165
- package/assets/skills/oat-project-implement/references/docs/complexity-review-fallback.md +262 -0
- package/assets/skills/oat-project-implement/references/docs/gate-approval-record.md +80 -0
- package/assets/skills/oat-project-implement/references/phase-execution.md +38 -6
- package/assets/skills/oat-project-import-plan/SKILL.md +20 -6
- package/assets/skills/oat-project-lite/SKILL.md +7 -5
- package/assets/skills/oat-project-lite/references/docs/autonomy-contract.md +210 -165
- package/assets/skills/oat-project-new/SKILL.md +6 -2
- package/assets/skills/oat-project-next/SKILL.md +19 -2
- package/assets/skills/oat-project-next/references/docs/gate-approval-record.md +80 -0
- package/assets/skills/oat-project-plan/SKILL.md +14 -6
- package/assets/skills/oat-project-pr-final/SKILL.md +4 -3
- package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +210 -165
- package/assets/skills/oat-project-progress/SKILL.md +27 -1
- package/assets/skills/oat-project-progress/references/docs/gate-approval-record.md +80 -0
- package/assets/skills/oat-project-promote-spec-driven/SKILL.md +7 -3
- package/assets/skills/oat-project-quick-start/SKILL.md +47 -14
- package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +210 -165
- package/assets/skills/oat-project-quick-start/references/docs/complexity-review-fallback.md +262 -0
- package/assets/skills/oat-project-quick-start/references/docs/gate-approval-record.md +80 -0
- package/assets/skills/oat-project-reconcile/SKILL.md +8 -4
- package/assets/skills/oat-project-retro/SKILL.md +1 -1
- package/assets/skills/oat-project-retro/references/apply-procedure.md +6 -6
- package/assets/skills/oat-project-retro-file/SKILL.md +7 -3
- package/assets/skills/oat-project-review-provide/SKILL.md +23 -4
- package/assets/skills/oat-project-review-provide-remote/SKILL.md +19 -1
- package/assets/skills/oat-project-review-receive/SKILL.md +57 -14
- package/assets/skills/oat-project-review-receive/references/docs/complexity-review-fallback.md +262 -0
- package/assets/skills/oat-project-review-receive-remote/SKILL.md +7 -3
- package/assets/skills/oat-project-revise/SKILL.md +13 -5
- package/assets/skills/oat-project-spec/SKILL.md +8 -4
- package/assets/skills/oat-project-summary/SKILL.md +11 -7
- package/assets/skills/oat-repo-knowledge-index/SKILL.md +54 -20
- package/assets/skills/oat-repo-knowledge-index/scripts/refresh-owned.mjs +118 -0
- package/assets/skills/oat-review-provide/SKILL.md +7 -3
- package/assets/skills/oat-review-receive-remote/SKILL.md +14 -4
- package/assets/skills/oat-wave-execute/SKILL.md +72 -38
- package/assets/skills/oat-wave-execute/assets/wrapper-plan-template.md +16 -2
- package/assets/skills/oat-wave-program/SKILL.md +15 -6
- package/assets/skills/oat-worktree-bootstrap-auto/SKILL.md +45 -17
- package/assets/skills/oat-wrap-up/SKILL.md +9 -3
- package/assets/skills/oat-wrap-up/references/report-template.md +1 -1
- package/assets/skills/recon/SKILL.md +1 -1
- package/assets/skills/recon/references/packet-contract.md +18 -3
- package/assets/skills/recon/scripts/lib/contracts.mjs +16 -2
- package/assets/skills/recon/scripts/reconcile-ledger.mjs +20 -10
- package/assets/skills/recon/scripts/render-packet.mjs +31 -3
- package/assets/skills/recon/scripts/validate-packet.mjs +5 -5
- package/assets/templates/pjm-agents.md +38 -8
- package/assets/templates/repo-agents.md +5 -0
- package/assets/templates/repo-readme.md +5 -0
- package/assets/templates/state.md +7 -0
- package/dist/commands/backlog/archive.d.ts +3 -0
- package/dist/commands/backlog/archive.d.ts.map +1 -1
- package/dist/commands/backlog/archive.js +63 -26
- package/dist/commands/backlog/index.d.ts.map +1 -1
- package/dist/commands/backlog/index.js +3 -0
- package/dist/commands/backlog/rewrite-references.d.ts +5 -0
- package/dist/commands/backlog/rewrite-references.d.ts.map +1 -1
- package/dist/commands/backlog/rewrite-references.js +39 -1
- package/dist/commands/config/index.d.ts.map +1 -1
- package/dist/commands/config/index.js +13 -0
- package/dist/commands/gate/index.d.ts +5 -0
- package/dist/commands/gate/index.d.ts.map +1 -1
- package/dist/commands/gate/index.js +270 -9
- package/dist/commands/init/index.d.ts.map +1 -1
- package/dist/commands/init/index.js +1 -0
- package/dist/commands/internal/commit-paths.d.ts +3 -0
- package/dist/commands/internal/commit-paths.d.ts.map +1 -0
- package/dist/commands/internal/commit-paths.js +31 -0
- package/dist/commands/internal/index.d.ts.map +1 -1
- package/dist/commands/internal/index.js +2 -0
- package/dist/commands/pjm/init.d.ts.map +1 -1
- package/dist/commands/pjm/init.js +37 -8
- package/dist/commands/project/archive/archive-utils.d.ts +6 -3
- package/dist/commands/project/archive/archive-utils.d.ts.map +1 -1
- package/dist/commands/project/archive/archive-utils.js +510 -104
- package/dist/commands/project/archive/push-runner.d.ts.map +1 -1
- package/dist/commands/project/archive/push-runner.js +1 -0
- package/dist/commands/project/log/append.d.ts +2 -3
- package/dist/commands/project/log/append.d.ts.map +1 -1
- package/dist/commands/project/log/append.js +55 -101
- package/dist/commands/project/migrate/index.d.ts +1 -2
- package/dist/commands/project/migrate/index.d.ts.map +1 -1
- package/dist/commands/project/migrate/index.js +8 -2
- package/dist/commands/project/new/scaffold.d.ts.map +1 -1
- package/dist/commands/project/new/scaffold.js +4 -4
- package/dist/commands/project/promote/promote.d.ts +8 -0
- package/dist/commands/project/promote/promote.d.ts.map +1 -1
- package/dist/commands/project/promote/promote.js +37 -6
- package/dist/commands/project/status.d.ts.map +1 -1
- package/dist/commands/project/status.js +3 -0
- package/dist/commands/project/sync/ref-sync.d.ts +12 -1
- package/dist/commands/project/sync/ref-sync.d.ts.map +1 -1
- package/dist/commands/project/sync/ref-sync.js +347 -23
- package/dist/commands/shared/exact-path-commit.d.ts +32 -0
- package/dist/commands/shared/exact-path-commit.d.ts.map +1 -0
- package/dist/commands/shared/exact-path-commit.js +691 -0
- package/dist/commands/shared/frontmatter.d.ts +1 -1
- package/dist/commands/shared/frontmatter.d.ts.map +1 -1
- package/dist/commands/shared/frontmatter.js +1 -0
- package/dist/commands/state/generate.d.ts +1 -1
- package/dist/commands/state/generate.d.ts.map +1 -1
- package/dist/commands/state/generate.js +87 -8
- package/dist/commands/sync/apply.d.ts.map +1 -1
- package/dist/commands/sync/apply.js +31 -5
- package/dist/commands/sync/dry-run.d.ts.map +1 -1
- package/dist/commands/sync/dry-run.js +28 -11
- package/dist/commands/sync/sync.utils.d.ts +13 -0
- package/dist/commands/sync/sync.utils.d.ts.map +1 -1
- package/dist/commands/sync/sync.utils.js +21 -1
- package/dist/commands/tools/shared/pack-manifest.d.ts.map +1 -1
- package/dist/commands/tools/shared/pack-manifest.js +1 -0
- package/dist/config/oat-config.d.ts +1 -0
- package/dist/config/oat-config.d.ts.map +1 -1
- package/dist/config/oat-config.js +3 -0
- package/dist/config/resolve.d.ts.map +1 -1
- package/dist/config/resolve.js +1 -0
- package/dist/drift/detector.js +6 -6
- package/dist/engine/compute-plan.d.ts.map +1 -1
- package/dist/engine/compute-plan.js +87 -2
- package/dist/engine/engine.types.d.ts +10 -1
- package/dist/engine/engine.types.d.ts.map +1 -1
- package/dist/engine/engine.types.js +4 -0
- package/dist/engine/execute-plan.d.ts.map +1 -1
- package/dist/engine/execute-plan.js +42 -5
- package/dist/engine/managed-copy-hash.d.ts +4 -3
- package/dist/engine/managed-copy-hash.d.ts.map +1 -1
- package/dist/engine/managed-copy-hash.js +4 -3
- package/dist/fs/assets.d.ts.map +1 -1
- package/dist/fs/assets.js +7 -1
- package/dist/manifest/hash.d.ts +8 -10
- package/dist/manifest/hash.d.ts.map +1 -1
- package/dist/ui/output.js +1 -1
- package/dist/validation/skills.d.ts.map +1 -1
- package/dist/validation/skills.js +151 -11
- package/package.json +3 -2
|
@@ -5,13 +5,17 @@ disable-model-invocation: true
|
|
|
5
5
|
user-invocable: true
|
|
6
6
|
allowed-tools: Read, Write, Bash, Glob, Grep, AskUserQuestion
|
|
7
7
|
metadata:
|
|
8
|
-
version: 1.0.
|
|
8
|
+
version: 1.0.4
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# Capture Untracked Work
|
|
12
12
|
|
|
13
13
|
Retroactively create an OAT project from work that happened outside the structured workflow. Populates `discovery.md` from conversation context and `implementation.md` from commit history, producing a tracked project ready for review or PR.
|
|
14
14
|
|
|
15
|
+
## Hook-safe exact-path commits
|
|
16
|
+
|
|
17
|
+
Before a parent-branch commit, verify `oat internal commit-paths --help` succeeds. If unavailable, stop and update the OAT CLI; never fall back to a staged-index or pathspec-only commit. Set `COMMIT_IDENTITY` to a unique operation/artifact identity before the first attempt and retain it for every retry; use a new identity for a new operation. Pass only the exact produced file list, including tracked removals and both names of a rename. A blocked/failed result stops the workflow; retain its receipt and follow its diagnostics. Hooks remain enabled. Synced project artifacts continue through `oat project push`.
|
|
18
|
+
|
|
15
19
|
## When to Use
|
|
16
20
|
|
|
17
21
|
Use when:
|
|
@@ -268,8 +272,8 @@ PROJECT_SCOPE=$(oat project scope "$PROJECT_PATH" --format value) || {
|
|
|
268
272
|
if [ "$PROJECT_SCOPE" = "synced" ]; then
|
|
269
273
|
oat project push "$PROJECT_PATH" --message "chore(oat): capture existing work for {name}" || { echo "oat: project push failed; run oat project pull, resolve the reported state, and retry" >&2; exit 1; }
|
|
270
274
|
else
|
|
271
|
-
|
|
272
|
-
|
|
275
|
+
OWNED_COMMIT_PATHS=("$PROJECT_PATH/discovery.md" "$PROJECT_PATH/implementation.md" "$PROJECT_PATH/state.md")
|
|
276
|
+
oat internal commit-paths --identity "${COMMIT_IDENTITY:?set once and retain for retries}:oat-project-capture:1" --message "chore(oat): capture existing work for {name}" -- "${OWNED_COMMIT_PATHS[@]}" || exit 1
|
|
273
277
|
fi
|
|
274
278
|
```
|
|
275
279
|
|
|
@@ -5,13 +5,17 @@ disable-model-invocation: true
|
|
|
5
5
|
user-invocable: true
|
|
6
6
|
allowed-tools: Read, Write, Bash, AskUserQuestion
|
|
7
7
|
metadata:
|
|
8
|
-
version: 1.7.
|
|
8
|
+
version: 1.7.15
|
|
9
9
|
---
|
|
10
10
|
|
|
11
11
|
# Complete Project
|
|
12
12
|
|
|
13
13
|
Mark the active OAT project lifecycle as complete.
|
|
14
14
|
|
|
15
|
+
## Hook-safe exact-path commits
|
|
16
|
+
|
|
17
|
+
Before a parent-branch commit, verify `oat internal commit-paths --help` succeeds. If unavailable, stop and update the OAT CLI; never fall back to a staged-index or pathspec-only commit. Set `COMMIT_IDENTITY` to a unique operation/artifact identity before the first attempt and retain it for every retry; use a new identity for a new operation. Pass only the exact produced file list, including tracked removals and both names of a rename. A blocked/failed result stops the workflow; retain its receipt and follow its diagnostics. Hooks remain enabled. Synced project artifacts continue through `oat project push`.
|
|
18
|
+
|
|
15
19
|
## Progress Indicators (User-Facing)
|
|
16
20
|
|
|
17
21
|
When executing this skill, provide lightweight progress feedback so the user can tell what's happening after they confirm.
|
|
@@ -1237,21 +1241,23 @@ another lifecycle commit. `removed` is the completed-only terminal shape;
|
|
|
1237
1241
|
`retained` is the equally terminal same-SHA active alias shape. A differing-SHA
|
|
1238
1242
|
state is never a successful report.
|
|
1239
1243
|
|
|
1240
|
-
When `SELECTED_PROJECT_RECAP_RUN` is non-empty,
|
|
1241
|
-
`projectRecapExport.sourceRunRoot`, `
|
|
1242
|
-
`
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1244
|
+
When `SELECTED_PROJECT_RECAP_RUN` is non-empty, require the report's
|
|
1245
|
+
`projectRecapExport.sourceRunRoot`, `exportRoot`, `runId`,
|
|
1246
|
+
`page.sourceRelativePath`, `page.originalSha256`, `page.exportedSha256`, and
|
|
1247
|
+
positive `verifiedArtifactCount`. The export is one tracked
|
|
1248
|
+
`.oat/repo/reference/project-recaps/<snapshotId>.html` page. Confirm the source
|
|
1249
|
+
is the selected run under the pre-archive project path, or under `archivePath`
|
|
1250
|
+
on a terminal retry. Verify the run ID and manifest-declared original page/hash
|
|
1251
|
+
against the retained archived run, and the exported hash against the tracked
|
|
1252
|
+
page. Record `exportRoot` as the final page, never as a package directory.
|
|
1253
|
+
|
|
1254
|
+
The archive report is authoritative. A missing, malformed, mismatched,
|
|
1255
|
+
outside-root, or gitignored export report is an archive failure; stop before
|
|
1256
|
+
lifecycle bookkeeping. Link only to the tracked page. The full original run,
|
|
1257
|
+
including source, manifest, and QA evidence, remains in the archived project;
|
|
1258
|
+
it is retained evidence rather than a remote link target. Persisted older
|
|
1259
|
+
receipts with `manifest.relativePath === "manifest.json"` remain readable as
|
|
1260
|
+
legacy package receipts; new exports never create a tracked manifest sidecar.
|
|
1255
1261
|
|
|
1256
1262
|
SELECTED_PROJECT_RECAP_RUN must be project-relative. Never add `--project-recap-run` when `SELECTED_PROJECT_RECAP_RUN` is empty. The empty case remains the existing archive behavior. Because this step runs only for durable projects, local-scope projects never pass a recap archive argument.
|
|
1257
1263
|
|
|
@@ -1286,12 +1292,12 @@ final synced links,
|
|
|
1286
1292
|
dashboard refresh, the required bookkeeping push, tracked-PR closeout when
|
|
1287
1293
|
applicable, and final confirmation.
|
|
1288
1294
|
|
|
1289
|
-
Rewrite recap links in the tracked summary export and the PR description body from `projectRecapExport.exportRoot`; do not derive them from the local archive.
|
|
1295
|
+
Rewrite recap links in the tracked summary export and the PR description body from the reported HTML `projectRecapExport.exportRoot`; do not derive them from the local archive. Preserve the reported run ID and original/exported page hashes in the summary outcome. On resume use `EXPORTED_PAGE_PATH`; `EXPORTED_MANIFEST_PATH` is populated only for a persisted legacy package receipt.
|
|
1290
1296
|
Use a repository-relative path under
|
|
1291
1297
|
`.oat/repo/reference/project-recaps/` and a blob URL on the current head branch
|
|
1292
1298
|
while the PR is open. If `summaryExportFile` is non-null, update its concise
|
|
1293
1299
|
`Explainer Outcome` recap link. Update the archived PR-description artifact
|
|
1294
|
-
used by Step 11 or 11.5 so its recap reference points to the same tracked
|
|
1300
|
+
used by Step 11 or 11.5 so its recap reference points to the same tracked HTML page.
|
|
1295
1301
|
Omit either link when its containing artifact does not exist.
|
|
1296
1302
|
|
|
1297
1303
|
Use the current head branch for the blob URL while the PR is open. Never link to `.oat/projects/archived/`; it is gitignored and will return 404 remotely.
|
|
@@ -1423,9 +1429,16 @@ Expected changes may include:
|
|
|
1423
1429
|
- `.oat/config.local.json` (if `activeProject` cleared)
|
|
1424
1430
|
- Shared-project deletions; synced archive record deletion is already sealed by
|
|
1425
1431
|
the archive-owned lifecycle commit
|
|
1426
|
-
- The
|
|
1432
|
+
- The tracked recap page and tracked summary export reported by
|
|
1427
1433
|
archive (if present)
|
|
1428
1434
|
|
|
1435
|
+
Initialize `COMPLETION_OUTPUT_PATHS=()` before closeout writes. Each producer
|
|
1436
|
+
appends its exact successful output paths from the expected changes above,
|
|
1437
|
+
including tracked removals and both names of a rename; omit ignored local
|
|
1438
|
+
config/dashboard outputs. Retain that list for retries. Do not infer ownership
|
|
1439
|
+
from the staged index or pass project/export directories. The synced record
|
|
1440
|
+
producer already supplies the single exact `SYNCED_RECORD_PATH`.
|
|
1441
|
+
|
|
1429
1442
|
Run:
|
|
1430
1443
|
|
|
1431
1444
|
```bash
|
|
@@ -1433,23 +1446,15 @@ if [[ "$PROJECT_SCOPE" == "synced" ]]; then
|
|
|
1433
1446
|
if [[ "$SHOULD_ARCHIVE" == "true" ]]; then
|
|
1434
1447
|
test -n "$LIFECYCLE_COMMIT"
|
|
1435
1448
|
else
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
"$SYNCED_RECORD_PATH" "$LIFECYCLE_COMMIT" "$PROJECT_NAME" || exit 1
|
|
1441
|
-
else
|
|
1442
|
-
git commit --only "$SYNCED_RECORD_PATH" \
|
|
1443
|
-
-m "chore(oat): complete synced project ${PROJECT_NAME}" &&
|
|
1444
|
-
LIFECYCLE_COMMIT=$(git rev-parse HEAD) &&
|
|
1445
|
-
node "$NONARCHIVE_LIFECYCLE_RECEIPT_SCRIPT" \
|
|
1446
|
-
"$SYNCED_RECORD_PATH" "$LIFECYCLE_COMMIT" "$PROJECT_NAME" || exit 1
|
|
1447
|
-
fi
|
|
1449
|
+
oat internal commit-paths --identity "${COMMIT_IDENTITY:?set once and retain for retries}:oat-project-complete:1" --message "chore(oat): complete synced project ${PROJECT_NAME}" -- "$SYNCED_RECORD_PATH" || exit 1
|
|
1450
|
+
LIFECYCLE_COMMIT=$(git log -1 --format=%H -- "$SYNCED_RECORD_PATH") || exit 1
|
|
1451
|
+
node "$NONARCHIVE_LIFECYCLE_RECEIPT_SCRIPT" \
|
|
1452
|
+
"$SYNCED_RECORD_PATH" "$LIFECYCLE_COMMIT" "$PROJECT_NAME" || exit 1
|
|
1448
1453
|
fi
|
|
1449
1454
|
else
|
|
1450
1455
|
git status --short
|
|
1451
|
-
|
|
1452
|
-
|
|
1456
|
+
: "${COMPLETION_OUTPUT_PATHS:?retain the exact lifecycle producer file list}"
|
|
1457
|
+
oat internal commit-paths --identity "${COMMIT_IDENTITY:?set once and retain for retries}:oat-project-complete:2" --message "chore(oat): complete project lifecycle for ${PROJECT_NAME}" -- "${COMPLETION_OUTPUT_PATHS[@]}" || exit 1
|
|
1453
1458
|
LIFECYCLE_COMMIT=$(git rev-parse HEAD)
|
|
1454
1459
|
fi
|
|
1455
1460
|
```
|
|
@@ -1623,7 +1628,7 @@ Show user:
|
|
|
1623
1628
|
- If archived: "Archived location: **{PROJECT_PATH}**"
|
|
1624
1629
|
- If S3 archive sync ran: include `ARCHIVE_S3_CONTEXT` when the archive command reported profile/region details. If only `ARCHIVE_S3_PATH` is available, include the S3 destination and note that profile/region context was not reported by the command. Never echo raw credentials (`AWS_SECRET_ACCESS_KEY`, `AWS_SESSION_TOKEN`, etc.).
|
|
1625
1630
|
- Include the lifecycle bookkeeping commit hash and the single push result.
|
|
1626
|
-
- Report the final recap outcome and tracked
|
|
1631
|
+
- Report the final recap outcome and tracked recap page path.
|
|
1627
1632
|
- Report every absorbed-project retirement finding from the Step 3.7 sweep with
|
|
1628
1633
|
its disposition. This is the required destination whenever the sweep could not
|
|
1629
1634
|
append them to the project log — an absent log, or a resume whose log is
|
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import { execFile as execFileCallback } from 'node:child_process';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
2
3
|
import { realpathSync } from 'node:fs';
|
|
3
4
|
import { readFile } from 'node:fs/promises';
|
|
4
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
isAbsolute,
|
|
7
|
+
posix,
|
|
8
|
+
relative,
|
|
9
|
+
sep,
|
|
10
|
+
resolve,
|
|
11
|
+
join,
|
|
12
|
+
dirname,
|
|
13
|
+
basename,
|
|
14
|
+
} from 'node:path';
|
|
5
15
|
import { fileURLToPath } from 'node:url';
|
|
6
16
|
import { promisify } from 'node:util';
|
|
7
17
|
|
|
@@ -23,45 +33,112 @@ async function buildPostArchiveContinuation(
|
|
|
23
33
|
) {
|
|
24
34
|
let selectedProjectRecapRun = '';
|
|
25
35
|
let exportedManifestPath = '';
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
) {
|
|
36
|
-
throw executionError(
|
|
37
|
-
'Archive resume report has an invalid project recap export receipt.',
|
|
38
|
-
);
|
|
36
|
+
let exportedPagePath = '';
|
|
37
|
+
const canonicalPath = (value) => {
|
|
38
|
+
try {
|
|
39
|
+
return realpathSync(value);
|
|
40
|
+
} catch (error) {
|
|
41
|
+
if (error.code !== 'ENOENT') throw error;
|
|
42
|
+
const parent = dirname(value);
|
|
43
|
+
if (parent === value) throw error;
|
|
44
|
+
return join(canonicalPath(parent), basename(value));
|
|
39
45
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
};
|
|
47
|
+
const recap = archiveReport.projectRecapExport;
|
|
48
|
+
if (recap != null) {
|
|
49
|
+
const inside = (root, target) => {
|
|
50
|
+
if (typeof target !== 'string' || !isAbsolute(target)) return null;
|
|
51
|
+
const child = relative(canonicalPath(root), canonicalPath(target))
|
|
52
|
+
.split(sep)
|
|
53
|
+
.join('/');
|
|
54
|
+
return child && !/^\.\.(?:[/\\]|$)/.test(child) && !isAbsolute(child)
|
|
55
|
+
? child
|
|
56
|
+
: null;
|
|
57
|
+
};
|
|
58
|
+
selectedProjectRecapRun =
|
|
59
|
+
inside(projectPath, recap.sourceRunRoot) ??
|
|
60
|
+
inside(archiveReport.archivePath, recap.sourceRunRoot);
|
|
61
|
+
const exportRelative = inside(
|
|
62
|
+
join(repoRoot, '.oat/repo/reference/project-recaps'),
|
|
63
|
+
recap.exportRoot,
|
|
64
|
+
);
|
|
43
65
|
if (
|
|
44
|
-
selectedProjectRecapRun
|
|
45
|
-
|
|
46
|
-
isAbsolute(selectedProjectRecapRun)
|
|
66
|
+
!selectedProjectRecapRun?.startsWith('explainers/') ||
|
|
67
|
+
!exportRelative
|
|
47
68
|
) {
|
|
48
69
|
throw executionError(
|
|
49
|
-
'Archive resume recap source is outside
|
|
70
|
+
'Archive resume recap source or export is outside its allowed root.',
|
|
50
71
|
);
|
|
51
72
|
}
|
|
52
|
-
const
|
|
73
|
+
const repoRelativeExport = relative(
|
|
74
|
+
canonicalPath(repoRoot),
|
|
75
|
+
canonicalPath(recap.exportRoot),
|
|
76
|
+
)
|
|
53
77
|
.split(sep)
|
|
54
78
|
.join('/');
|
|
55
79
|
if (
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
isAbsolute(exportRootRelative)
|
|
80
|
+
recap.manifest?.relativePath === 'manifest.json' &&
|
|
81
|
+
recap.page == null
|
|
59
82
|
) {
|
|
60
|
-
|
|
61
|
-
|
|
83
|
+
// Persisted pre-flat-export receipts remain readable.
|
|
84
|
+
exportedManifestPath = posix.join(repoRelativeExport, 'manifest.json');
|
|
85
|
+
} else {
|
|
86
|
+
const page = recap.page;
|
|
87
|
+
const sourcePage = page?.sourceRelativePath;
|
|
88
|
+
if (
|
|
89
|
+
exportRelative !== `${archiveReport.snapshotId}.html` ||
|
|
90
|
+
typeof recap.runId !== 'string' ||
|
|
91
|
+
!recap.runId ||
|
|
92
|
+
!Number.isInteger(recap.verifiedArtifactCount) ||
|
|
93
|
+
recap.verifiedArtifactCount < 1 ||
|
|
94
|
+
typeof sourcePage !== 'string' ||
|
|
95
|
+
!sourcePage.startsWith('site/') ||
|
|
96
|
+
!sourcePage.endsWith('.html') ||
|
|
97
|
+
sourcePage.split('/').some((part) => part === '..') ||
|
|
98
|
+
!/^sha256:[0-9a-f]{64}$/.test(page?.originalSha256) ||
|
|
99
|
+
!/^sha256:[0-9a-f]{64}$/.test(page?.exportedSha256)
|
|
100
|
+
)
|
|
101
|
+
throw executionError(
|
|
102
|
+
'Archive resume report has an invalid flat recap receipt.',
|
|
103
|
+
);
|
|
104
|
+
const archivedRun = join(
|
|
105
|
+
archiveReport.archivePath,
|
|
106
|
+
selectedProjectRecapRun,
|
|
62
107
|
);
|
|
108
|
+
const hash = (bytes) =>
|
|
109
|
+
`sha256:${createHash('sha256').update(bytes).digest('hex')}`;
|
|
110
|
+
try {
|
|
111
|
+
if (
|
|
112
|
+
!inside(archiveReport.archivePath, archivedRun) ||
|
|
113
|
+
!inside(archivedRun, join(archivedRun, sourcePage)) ||
|
|
114
|
+
!inside(archivedRun, join(archivedRun, 'manifest.json'))
|
|
115
|
+
)
|
|
116
|
+
throw new Error('archived source escapes its root');
|
|
117
|
+
const manifest = JSON.parse(
|
|
118
|
+
await readFile(join(archivedRun, 'manifest.json'), 'utf8'),
|
|
119
|
+
);
|
|
120
|
+
const original = await readFile(join(archivedRun, sourcePage));
|
|
121
|
+
const exported = await readFile(recap.exportRoot);
|
|
122
|
+
if (
|
|
123
|
+
manifest.runId !== recap.runId ||
|
|
124
|
+
Object.keys(manifest.immutableHashes).length !==
|
|
125
|
+
recap.verifiedArtifactCount ||
|
|
126
|
+
!manifest.artifacts.some(
|
|
127
|
+
(artifact) =>
|
|
128
|
+
(artifact.renderedPath ?? artifact.contentPath) === sourcePage,
|
|
129
|
+
) ||
|
|
130
|
+
manifest.immutableHashes[sourcePage] !== page.originalSha256 ||
|
|
131
|
+
hash(original) !== page.originalSha256 ||
|
|
132
|
+
hash(exported) !== page.exportedSha256
|
|
133
|
+
)
|
|
134
|
+
throw new Error('run, page, or hash mismatch');
|
|
135
|
+
} catch (error) {
|
|
136
|
+
throw executionError(
|
|
137
|
+
`Archive resume flat recap identity failed: ${error.message}`,
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
exportedPagePath = repoRelativeExport;
|
|
63
141
|
}
|
|
64
|
-
exportedManifestPath = posix.join(exportRootRelative, manifestPath);
|
|
65
142
|
}
|
|
66
143
|
return {
|
|
67
144
|
required: true,
|
|
@@ -73,6 +150,7 @@ async function buildPostArchiveContinuation(
|
|
|
73
150
|
selectedProjectRecapRun,
|
|
74
151
|
projectRecapExport: archiveReport.projectRecapExport ?? null,
|
|
75
152
|
exportedManifestPath,
|
|
153
|
+
exportedPagePath,
|
|
76
154
|
};
|
|
77
155
|
}
|
|
78
156
|
|
|
@@ -15,6 +15,21 @@ function shellQuote(value) {
|
|
|
15
15
|
export function parseSyncedArchiveResumeFields(result) {
|
|
16
16
|
const continuation = result?.continuation;
|
|
17
17
|
const hasRecapExport = continuation?.projectRecapExport !== null;
|
|
18
|
+
const recap = continuation?.projectRecapExport;
|
|
19
|
+
const flatPage = `.oat/repo/reference/project-recaps/${result?.archiveReport?.snapshotId}.html`;
|
|
20
|
+
const invalidFlat =
|
|
21
|
+
recap?.page &&
|
|
22
|
+
(typeof recap.runId !== 'string' ||
|
|
23
|
+
!recap.runId ||
|
|
24
|
+
typeof recap.page.sourceRelativePath !== 'string' ||
|
|
25
|
+
!recap.page.sourceRelativePath.startsWith('site/') ||
|
|
26
|
+
!/^sha256:[0-9a-f]{64}$/.test(recap.page.originalSha256) ||
|
|
27
|
+
!/^sha256:[0-9a-f]{64}$/.test(recap.page.exportedSha256) ||
|
|
28
|
+
!Number.isInteger(recap.verifiedArtifactCount) ||
|
|
29
|
+
recap.verifiedArtifactCount < 1 ||
|
|
30
|
+
continuation.exportedPagePath !== flatPage ||
|
|
31
|
+
typeof recap.exportRoot !== 'string' ||
|
|
32
|
+
!recap.exportRoot.endsWith(`/${flatPage}`));
|
|
18
33
|
const allowedContinuationFields = new Set([
|
|
19
34
|
'required',
|
|
20
35
|
'rejoinStep',
|
|
@@ -25,6 +40,7 @@ export function parseSyncedArchiveResumeFields(result) {
|
|
|
25
40
|
'selectedProjectRecapRun',
|
|
26
41
|
'projectRecapExport',
|
|
27
42
|
'exportedManifestPath',
|
|
43
|
+
'exportedPagePath',
|
|
28
44
|
]);
|
|
29
45
|
if (
|
|
30
46
|
!continuation ||
|
|
@@ -42,10 +58,20 @@ export function parseSyncedArchiveResumeFields(result) {
|
|
|
42
58
|
continuation.archivePath.length === 0 ||
|
|
43
59
|
typeof continuation.lifecycleCommit !== 'string' ||
|
|
44
60
|
!/^[0-9a-f]{40}$/.test(continuation.lifecycleCommit) ||
|
|
61
|
+
invalidFlat ||
|
|
45
62
|
(hasRecapExport &&
|
|
46
|
-
(
|
|
47
|
-
|
|
48
|
-
|
|
63
|
+
(JSON.stringify(continuation.projectRecapExport) !==
|
|
64
|
+
JSON.stringify(result.archiveReport?.projectRecapExport) ||
|
|
65
|
+
(continuation.projectRecapExport?.page
|
|
66
|
+
? typeof continuation.exportedPagePath !== 'string' ||
|
|
67
|
+
!continuation.exportedPagePath.endsWith('.html') ||
|
|
68
|
+
continuation.exportedManifestPath !== ''
|
|
69
|
+
: typeof continuation.exportedManifestPath !== 'string' ||
|
|
70
|
+
!continuation.exportedManifestPath.endsWith('/manifest.json') ||
|
|
71
|
+
Boolean(continuation.exportedPagePath)))) ||
|
|
72
|
+
(!hasRecapExport &&
|
|
73
|
+
(continuation.exportedManifestPath !== '' ||
|
|
74
|
+
Boolean(continuation.exportedPagePath)))
|
|
49
75
|
) {
|
|
50
76
|
throw fieldsError(
|
|
51
77
|
'Synced archive resume result has no verified post-archive continuation.',
|
|
@@ -66,6 +92,7 @@ export function parseSyncedArchiveResumeFields(result) {
|
|
|
66
92
|
continuation.projectRecapExport ?? null,
|
|
67
93
|
),
|
|
68
94
|
EXPORTED_MANIFEST_PATH: continuation.exportedManifestPath,
|
|
95
|
+
EXPORTED_PAGE_PATH: continuation.exportedPagePath ?? '',
|
|
69
96
|
PROJECT_REF_COMMIT: '',
|
|
70
97
|
SHOULD_OPEN_PR: 'false',
|
|
71
98
|
};
|