@open-agent-toolkit/cli 0.2.50 → 0.2.52

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 (263) hide show
  1. package/assets/bundle-metadata.json +1 -1
  2. package/assets/docs/cli-utilities/bootstrap.md +6 -2
  3. package/assets/docs/cli-utilities/tool-packs.md +87 -33
  4. package/assets/docs/provider-sync/commands.md +30 -2
  5. package/assets/docs/provider-sync/config.md +19 -0
  6. package/assets/docs/provider-sync/manifest-and-drift.md +37 -0
  7. package/assets/docs/provider-sync/providers.md +69 -2
  8. package/assets/docs/provider-sync/scope-and-surface.md +44 -0
  9. package/assets/docs/reference/cli-reference.md +21 -5
  10. package/assets/docs/reference/file-locations.md +8 -2
  11. package/assets/docs/reference/oat-directory-structure.md +25 -9
  12. package/assets/docs/workflows/projects/artifacts.md +9 -4
  13. package/assets/docs/workflows/projects/evidence-layers.md +110 -1
  14. package/assets/docs/workflows/projects/implementation-execution.md +13 -0
  15. package/assets/docs/workflows/projects/lifecycle.md +17 -5
  16. package/assets/docs/workflows/projects/orchestration-model.md +18 -0
  17. package/assets/docs/workflows/projects/picking-up-projects.md +26 -9
  18. package/assets/docs/workflows/projects/pr-flow.md +5 -3
  19. package/assets/docs/workflows/projects/reviewing-oat-prs.md +12 -8
  20. package/assets/public-package-versions.json +4 -4
  21. package/assets/skills/oat-dispatch-subagents/SKILL.md +57 -1
  22. package/assets/skills/oat-dispatch-subagents/references/record-schema.md +77 -1
  23. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +3 -3
  24. package/assets/skills/oat-project-complete/SKILL.md +193 -26
  25. package/assets/skills/oat-project-complete/scripts/execute-synced-archive-entry.mjs +306 -0
  26. package/assets/skills/oat-project-complete/scripts/finalize-synced-archive.mjs +125 -0
  27. package/assets/skills/oat-project-complete/scripts/parse-synced-archive-resume-fields.mjs +106 -0
  28. package/assets/skills/oat-project-complete/scripts/recover-completion-receipts.mjs +110 -0
  29. package/assets/skills/oat-project-complete/scripts/resolve-synced-archive-entry.mjs +164 -0
  30. package/assets/skills/oat-project-dispatch-subagents/SKILL.md +24 -1
  31. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +3 -3
  32. package/assets/skills/oat-project-implement/references/dispatch-and-dry-run.md +11 -0
  33. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +3 -3
  34. package/assets/skills/oat-project-plan-writing/SKILL.md +12 -1
  35. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +3 -3
  36. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +3 -3
  37. package/assets/skills/oat-project-review-provide/SKILL.md +12 -1
  38. package/assets/skills/oat-project-review-provide-remote/SKILL.md +12 -1
  39. package/dist/agents/canonical/index.d.ts +2 -0
  40. package/dist/agents/canonical/index.d.ts.map +1 -1
  41. package/dist/agents/canonical/index.js +1 -0
  42. package/dist/agents/canonical/resolve.d.ts +45 -0
  43. package/dist/agents/canonical/resolve.d.ts.map +1 -0
  44. package/dist/agents/canonical/resolve.js +175 -0
  45. package/dist/commands/decision/agents-guidance.d.ts +2 -2
  46. package/dist/commands/decision/agents-guidance.d.ts.map +1 -1
  47. package/dist/commands/decision/agents-guidance.js +1 -4
  48. package/dist/commands/decision/index.d.ts.map +1 -1
  49. package/dist/commands/decision/index.js +25 -6
  50. package/dist/commands/docs/init/index.d.ts +7 -1
  51. package/dist/commands/docs/init/index.d.ts.map +1 -1
  52. package/dist/commands/docs/init/index.js +53 -20
  53. package/dist/commands/doctor/index.d.ts +8 -2
  54. package/dist/commands/doctor/index.d.ts.map +1 -1
  55. package/dist/commands/doctor/index.js +157 -46
  56. package/dist/commands/init/index.d.ts +8 -3
  57. package/dist/commands/init/index.d.ts.map +1 -1
  58. package/dist/commands/init/index.js +64 -26
  59. package/dist/commands/init/tools/index.d.ts +12 -12
  60. package/dist/commands/init/tools/index.d.ts.map +1 -1
  61. package/dist/commands/init/tools/index.js +430 -99
  62. package/dist/commands/init/tools/install-state.d.ts +2 -0
  63. package/dist/commands/init/tools/install-state.d.ts.map +1 -1
  64. package/dist/commands/init/tools/install-state.js +11 -0
  65. package/dist/commands/init/tools/project-guidance.d.ts +49 -0
  66. package/dist/commands/init/tools/project-guidance.d.ts.map +1 -0
  67. package/dist/commands/init/tools/project-guidance.js +144 -0
  68. package/dist/commands/init/tools/workflows/index.d.ts +7 -0
  69. package/dist/commands/init/tools/workflows/index.d.ts.map +1 -1
  70. package/dist/commands/init/tools/workflows/index.js +160 -7
  71. package/dist/commands/pjm/index.d.ts.map +1 -1
  72. package/dist/commands/pjm/index.js +28 -3
  73. package/dist/commands/pjm/init.d.ts +5 -0
  74. package/dist/commands/pjm/init.d.ts.map +1 -1
  75. package/dist/commands/pjm/init.js +19 -3
  76. package/dist/commands/project/archive/archive-utils.d.ts +8 -1
  77. package/dist/commands/project/archive/archive-utils.d.ts.map +1 -1
  78. package/dist/commands/project/archive/archive-utils.js +147 -50
  79. package/dist/commands/project/archive/push-runner.d.ts.map +1 -1
  80. package/dist/commands/project/archive/push-runner.js +15 -2
  81. package/dist/commands/project/dispatch/index.d.ts +10 -0
  82. package/dist/commands/project/dispatch/index.d.ts.map +1 -0
  83. package/dist/commands/project/dispatch/index.js +137 -0
  84. package/dist/commands/project/dispatch/record.d.ts +91 -0
  85. package/dist/commands/project/dispatch/record.d.ts.map +1 -0
  86. package/dist/commands/project/dispatch/record.js +402 -0
  87. package/dist/commands/project/index.d.ts.map +1 -1
  88. package/dist/commands/project/index.js +2 -0
  89. package/dist/commands/project/links/compute.d.ts +1 -0
  90. package/dist/commands/project/links/compute.d.ts.map +1 -1
  91. package/dist/commands/project/links/compute.js +5 -4
  92. package/dist/commands/project/links/index.d.ts +9 -0
  93. package/dist/commands/project/links/index.d.ts.map +1 -1
  94. package/dist/commands/project/links/index.js +71 -2
  95. package/dist/commands/project/list.d.ts +10 -2
  96. package/dist/commands/project/list.d.ts.map +1 -1
  97. package/dist/commands/project/list.js +205 -29
  98. package/dist/commands/project/open/index.d.ts +2 -0
  99. package/dist/commands/project/open/index.d.ts.map +1 -1
  100. package/dist/commands/project/open/index.js +16 -1
  101. package/dist/commands/project/prune/index.d.ts +10 -4
  102. package/dist/commands/project/prune/index.d.ts.map +1 -1
  103. package/dist/commands/project/prune/index.js +85 -15
  104. package/dist/commands/project/pull/index.d.ts +4 -0
  105. package/dist/commands/project/pull/index.d.ts.map +1 -1
  106. package/dist/commands/project/pull/index.js +82 -3
  107. package/dist/commands/project/sync/git.d.ts +9 -0
  108. package/dist/commands/project/sync/git.d.ts.map +1 -1
  109. package/dist/commands/project/sync/git.js +18 -0
  110. package/dist/commands/project/sync/ref-sync.d.ts +16 -1
  111. package/dist/commands/project/sync/ref-sync.d.ts.map +1 -1
  112. package/dist/commands/project/sync/ref-sync.js +288 -17
  113. package/dist/commands/project/sync/resolve-target.d.ts +10 -0
  114. package/dist/commands/project/sync/resolve-target.d.ts.map +1 -1
  115. package/dist/commands/project/sync/resolve-target.js +56 -1
  116. package/dist/commands/providers/inspect/inspect.d.ts +8 -1
  117. package/dist/commands/providers/inspect/inspect.d.ts.map +1 -1
  118. package/dist/commands/providers/inspect/inspect.js +146 -26
  119. package/dist/commands/providers/list/list.d.ts +8 -1
  120. package/dist/commands/providers/list/list.d.ts.map +1 -1
  121. package/dist/commands/providers/list/list.js +139 -23
  122. package/dist/commands/providers/providers.types.d.ts +25 -1
  123. package/dist/commands/providers/providers.types.d.ts.map +1 -1
  124. package/dist/commands/providers/set/index.d.ts +9 -1
  125. package/dist/commands/providers/set/index.d.ts.map +1 -1
  126. package/dist/commands/providers/set/index.js +43 -33
  127. package/dist/commands/remove/skill/remove-skill.d.ts.map +1 -1
  128. package/dist/commands/remove/skill/remove-skill.js +11 -0
  129. package/dist/commands/shared/agents-md.d.ts +42 -14
  130. package/dist/commands/shared/agents-md.d.ts.map +1 -1
  131. package/dist/commands/shared/agents-md.js +364 -70
  132. package/dist/commands/shared/project-scope.d.ts +2 -0
  133. package/dist/commands/shared/project-scope.d.ts.map +1 -1
  134. package/dist/commands/shared/project-scope.js +5 -0
  135. package/dist/commands/state/generate.d.ts +2 -0
  136. package/dist/commands/state/generate.d.ts.map +1 -1
  137. package/dist/commands/state/generate.js +93 -28
  138. package/dist/commands/status/index.d.ts +8 -3
  139. package/dist/commands/status/index.d.ts.map +1 -1
  140. package/dist/commands/status/index.js +147 -32
  141. package/dist/commands/sync/apply.d.ts.map +1 -1
  142. package/dist/commands/sync/apply.js +220 -29
  143. package/dist/commands/sync/dry-run.d.ts.map +1 -1
  144. package/dist/commands/sync/dry-run.js +30 -6
  145. package/dist/commands/sync/index.d.ts +17 -2
  146. package/dist/commands/sync/index.d.ts.map +1 -1
  147. package/dist/commands/sync/index.js +106 -41
  148. package/dist/commands/sync/sync.types.d.ts +39 -2
  149. package/dist/commands/sync/sync.types.d.ts.map +1 -1
  150. package/dist/commands/sync/sync.utils.d.ts +5 -1
  151. package/dist/commands/sync/sync.utils.d.ts.map +1 -1
  152. package/dist/commands/sync/sync.utils.js +73 -0
  153. package/dist/commands/tools/info/info-tool.d.ts +2 -0
  154. package/dist/commands/tools/info/info-tool.d.ts.map +1 -1
  155. package/dist/commands/tools/info/info-tool.js +34 -12
  156. package/dist/commands/tools/install/index.d.ts.map +1 -1
  157. package/dist/commands/tools/install/index.js +19 -3
  158. package/dist/commands/tools/list/list-tools.d.ts +2 -0
  159. package/dist/commands/tools/list/list-tools.d.ts.map +1 -1
  160. package/dist/commands/tools/list/list-tools.js +36 -7
  161. package/dist/commands/tools/remove/index.d.ts.map +1 -1
  162. package/dist/commands/tools/remove/index.js +150 -21
  163. package/dist/commands/tools/remove/remove-tools.d.ts +20 -0
  164. package/dist/commands/tools/remove/remove-tools.d.ts.map +1 -1
  165. package/dist/commands/tools/remove/remove-tools.js +122 -1
  166. package/dist/commands/tools/shared/format-pack-inventory.d.ts +19 -0
  167. package/dist/commands/tools/shared/format-pack-inventory.d.ts.map +1 -1
  168. package/dist/commands/tools/shared/format-pack-inventory.js +109 -0
  169. package/dist/commands/tools/shared/pack-evidence.d.ts +66 -0
  170. package/dist/commands/tools/shared/pack-evidence.d.ts.map +1 -0
  171. package/dist/commands/tools/shared/pack-evidence.js +132 -0
  172. package/dist/commands/tools/shared/pack-inventory.d.ts +1 -0
  173. package/dist/commands/tools/shared/pack-inventory.d.ts.map +1 -1
  174. package/dist/commands/tools/shared/pack-lifecycle-outcome.d.ts +44 -0
  175. package/dist/commands/tools/shared/pack-lifecycle-outcome.d.ts.map +1 -0
  176. package/dist/commands/tools/shared/pack-lifecycle-outcome.js +91 -0
  177. package/dist/commands/tools/update/index.d.ts.map +1 -1
  178. package/dist/commands/tools/update/index.js +74 -4
  179. package/dist/commands/tools/update/update-tools.d.ts +5 -0
  180. package/dist/commands/tools/update/update-tools.d.ts.map +1 -1
  181. package/dist/commands/tools/update/update-tools.js +64 -2
  182. package/dist/config/oat-config.d.ts +5 -0
  183. package/dist/config/oat-config.d.ts.map +1 -1
  184. package/dist/config/oat-config.js +17 -5
  185. package/dist/config/user-sync-config.d.ts +1 -0
  186. package/dist/config/user-sync-config.d.ts.map +1 -1
  187. package/dist/config/user-sync-config.js +8 -0
  188. package/dist/drift/detector.d.ts +2 -2
  189. package/dist/drift/detector.d.ts.map +1 -1
  190. package/dist/drift/detector.js +18 -0
  191. package/dist/drift/strays.d.ts.map +1 -1
  192. package/dist/drift/strays.js +5 -0
  193. package/dist/engine/collection-sync.d.ts +14 -0
  194. package/dist/engine/collection-sync.d.ts.map +1 -0
  195. package/dist/engine/collection-sync.js +282 -0
  196. package/dist/engine/compute-plan.d.ts +8 -1
  197. package/dist/engine/compute-plan.d.ts.map +1 -1
  198. package/dist/engine/compute-plan.js +303 -12
  199. package/dist/engine/engine.types.d.ts +61 -0
  200. package/dist/engine/engine.types.d.ts.map +1 -1
  201. package/dist/engine/execute-plan.d.ts +22 -2
  202. package/dist/engine/execute-plan.d.ts.map +1 -1
  203. package/dist/engine/execute-plan.js +459 -27
  204. package/dist/engine/provider-path-safety.d.ts +1 -0
  205. package/dist/engine/provider-path-safety.d.ts.map +1 -1
  206. package/dist/engine/provider-path-safety.js +15 -0
  207. package/dist/engine/scanner.d.ts +2 -2
  208. package/dist/engine/scanner.d.ts.map +1 -1
  209. package/dist/engine/scanner.js +21 -4
  210. package/dist/fs/io.d.ts +67 -0
  211. package/dist/fs/io.d.ts.map +1 -1
  212. package/dist/fs/io.js +536 -3
  213. package/dist/manifest/index.d.ts +2 -2
  214. package/dist/manifest/index.d.ts.map +1 -1
  215. package/dist/manifest/index.js +1 -1
  216. package/dist/manifest/manager.d.ts +2 -2
  217. package/dist/manifest/manager.d.ts.map +1 -1
  218. package/dist/manifest/manager.js +20 -3
  219. package/dist/manifest/manifest.types.d.ts +704 -13
  220. package/dist/manifest/manifest.types.d.ts.map +1 -1
  221. package/dist/manifest/manifest.types.js +131 -15
  222. package/dist/providers/codex/codec/sync-extension.d.ts.map +1 -1
  223. package/dist/providers/codex/codec/sync-extension.js +41 -10
  224. package/dist/providers/cursor/codec/sync-extension.d.ts.map +1 -1
  225. package/dist/providers/cursor/codec/sync-extension.js +41 -10
  226. package/dist/providers/identity/absolute-paths.d.ts +68 -0
  227. package/dist/providers/identity/absolute-paths.d.ts.map +1 -0
  228. package/dist/providers/identity/absolute-paths.js +144 -0
  229. package/dist/providers/identity/claude-runtime-observation.d.ts +105 -0
  230. package/dist/providers/identity/claude-runtime-observation.d.ts.map +1 -0
  231. package/dist/providers/identity/claude-runtime-observation.fixtures.d.ts +40 -0
  232. package/dist/providers/identity/claude-runtime-observation.fixtures.d.ts.map +1 -0
  233. package/dist/providers/identity/claude-runtime-observation.fixtures.js +146 -0
  234. package/dist/providers/identity/claude-runtime-observation.js +229 -0
  235. package/dist/providers/identity/codex-runtime-observation.d.ts +75 -0
  236. package/dist/providers/identity/codex-runtime-observation.d.ts.map +1 -0
  237. package/dist/providers/identity/codex-runtime-observation.fixtures.d.ts +37 -0
  238. package/dist/providers/identity/codex-runtime-observation.fixtures.d.ts.map +1 -0
  239. package/dist/providers/identity/codex-runtime-observation.fixtures.js +539 -0
  240. package/dist/providers/identity/codex-runtime-observation.js +255 -0
  241. package/dist/providers/identity/generic-dispatch-record.d.ts +313 -0
  242. package/dist/providers/identity/generic-dispatch-record.d.ts.map +1 -0
  243. package/dist/providers/identity/generic-dispatch-record.js +539 -0
  244. package/dist/providers/identity/oat-dispatch-record.d.ts +1964 -0
  245. package/dist/providers/identity/oat-dispatch-record.d.ts.map +1 -0
  246. package/dist/providers/identity/oat-dispatch-record.js +691 -0
  247. package/dist/providers/identity/runtime-observation.d.ts +100 -0
  248. package/dist/providers/identity/runtime-observation.d.ts.map +1 -0
  249. package/dist/providers/identity/runtime-observation.js +169 -0
  250. package/dist/providers/shared/index.d.ts +2 -0
  251. package/dist/providers/shared/index.d.ts.map +1 -1
  252. package/dist/providers/shared/index.js +1 -0
  253. package/dist/providers/shared/materialization-extension.d.ts +12 -0
  254. package/dist/providers/shared/materialization-extension.d.ts.map +1 -1
  255. package/dist/providers/shared/registry.d.ts +69 -0
  256. package/dist/providers/shared/registry.d.ts.map +1 -0
  257. package/dist/providers/shared/registry.js +252 -0
  258. package/dist/providers/shared/restart-adviser.d.ts +26 -0
  259. package/dist/providers/shared/restart-adviser.d.ts.map +1 -0
  260. package/dist/providers/shared/restart-adviser.js +96 -0
  261. package/dist/shared/types.d.ts +4 -0
  262. package/dist/shared/types.d.ts.map +1 -1
  263. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"archive-utils.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/archive/archive-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"archive-utils.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/archive/archive-utils.ts"],"names":[],"mappings":"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"}
@@ -5,7 +5,8 @@ import { basename, dirname, isAbsolute, join, posix as path, relative, resolve,
5
5
  import { promisify } from 'node:util';
6
6
  import { defaultGitRunner } from '../../project/sync/git.js';
7
7
  import { readSyncedRecord, writeSyncedRecord, } from '../../project/sync/record.js';
8
- import { buildSyncTarget, commitRecordChange, preflightSyncedCheckout, removeSyncedCheckout, } from '../../project/sync/ref-sync.js';
8
+ import { buildSyncTarget, commitRecordChange, preflightSyncedCheckout, removeSyncedCheckout, retireSyncedRef, } from '../../project/sync/ref-sync.js';
9
+ import { probeSyncedTerminalRefs } from '../../project/sync/resolve-target.js';
9
10
  import { canonicalizePath, resolveProjectScope, resolveScopeRoot, syncedRecordPath, } from '../../shared/project-scope.js';
10
11
  import { CliError } from '../../../errors/cli-error.js';
11
12
  import { copyDirectory, copySingleFile, dirExists, ensureDir, fileExists, } from '../../../fs/io.js';
@@ -356,6 +357,66 @@ async function verifyArchiveSnapshotMetadata(archivePath, expected) {
356
357
  throw new CliError(`Existing archive \`${archivePath}\` does not match persisted snapshot \`${expected.snapshotName}\`; refusing to overwrite it.`);
357
358
  }
358
359
  }
360
+ async function resolveRecordlessSyncedArchiveIdentity(options, target, git, dependencies) {
361
+ const tentativeTarget = await resolveArchiveProjectTarget(options, dependencies);
362
+ assertDurableArchiveProjectTarget(tentativeTarget);
363
+ const archiveRoot = dirname(tentativeTarget.archivePath);
364
+ const candidates = [];
365
+ let entries;
366
+ try {
367
+ entries = await readdir(archiveRoot, { withFileTypes: true });
368
+ }
369
+ catch {
370
+ entries = [];
371
+ }
372
+ for (const entry of entries) {
373
+ if (!entry.isDirectory())
374
+ continue;
375
+ const archivePath = join(archiveRoot, entry.name);
376
+ let metadata;
377
+ try {
378
+ metadata = JSON.parse(await readFile(join(archivePath, ARCHIVE_SNAPSHOT_METADATA_FILENAME), 'utf8'));
379
+ }
380
+ catch {
381
+ continue;
382
+ }
383
+ if (isRecord(metadata) &&
384
+ metadata.projectName === options.projectName &&
385
+ metadata.scope === 'synced' &&
386
+ typeof metadata.snapshotName === 'string' &&
387
+ typeof metadata.sourceRefSha === 'string' &&
388
+ /^[0-9a-f]{40}$/.test(metadata.sourceRefSha)) {
389
+ candidates.push({
390
+ archivePath,
391
+ metadata: {
392
+ projectName: options.projectName,
393
+ snapshotName: metadata.snapshotName,
394
+ scope: 'synced',
395
+ sourceRefSha: metadata.sourceRefSha,
396
+ },
397
+ });
398
+ }
399
+ }
400
+ if (candidates.length === 0) {
401
+ throw new CliError(`Synced project ${options.projectName} has no active record and no persisted synced archive identity; refusing to create a replacement active record or a new snapshot.`, 2);
402
+ }
403
+ const probe = dependencies.probeSyncedTerminalRefs ?? probeSyncedTerminalRefs;
404
+ const matches = [];
405
+ for (const candidate of candidates) {
406
+ const terminal = await probe(target, candidate.metadata.sourceRefSha, git);
407
+ if (terminal.completedSha === candidate.metadata.sourceRefSha &&
408
+ (terminal.activeSha === null ||
409
+ terminal.activeSha === candidate.metadata.sourceRefSha)) {
410
+ matches.push(candidate);
411
+ }
412
+ }
413
+ if (matches.length !== 1) {
414
+ throw new CliError(matches.length === 0
415
+ ? `Synced project ${options.projectName} has no active record, but no persisted archive identity matches its authoritative completed ref; refusing terminal retry before export or S3 mutation.`
416
+ : `Synced project ${options.projectName} has no active record and multiple persisted archives match its authoritative completed ref; refusing an ambiguous terminal retry.`, 2);
417
+ }
418
+ return matches[0];
419
+ }
359
420
  async function exportProjectSummary(archivePath, snapshotName, summaryExportPath, repoRoot, dependencies) {
360
421
  const summarySource = join(archivePath, 'summary.md');
361
422
  const exists = dependencies.fileExists ?? fileExists;
@@ -850,29 +911,42 @@ export async function archiveProjectOnCompletion(options, dependencies = {}) {
850
911
  const syncTarget = isSynced
851
912
  ? buildSyncTarget(options.repoRoot, options.projectsRoot, options.projectName)
852
913
  : null;
853
- const git = dependencies.gitRunner ?? defaultGitRunner;
854
914
  let activeRecord = record;
915
+ const git = dependencies.gitRunner ?? defaultGitRunner;
916
+ const recordlessIdentity = syncTarget && !activeRecord
917
+ ? await resolveRecordlessSyncedArchiveIdentity(options, syncTarget, git, dependencies)
918
+ : null;
855
919
  let sourceRefSha;
856
920
  if (syncTarget) {
857
- if (!activeRecord) {
858
- throw new CliError(`Synced project ${options.projectName} is missing its discovery record; restore the record or run oat project pull ${options.projectName} from a clean checkout to adopt the project before archiving.`, 2);
921
+ if (recordlessIdentity) {
922
+ sourceRefSha = recordlessIdentity.metadata.sourceRefSha;
859
923
  }
860
- const preflight = await (dependencies.preflightSyncedCheckout ?? preflightSyncedCheckout)(syncTarget, git);
861
- if (preflight.status !== 'clean' &&
862
- !(preflight.status === 'absent' && activeRecord.status === 'complete')) {
863
- const recoveryCommand = preflight.status === 'absent'
864
- ? `oat project pull ${options.projectName}`
865
- : `oat project push ${options.projectName}`;
866
- throw new CliError(`Synced project ${options.projectName} is ${preflight.status}; run ${recoveryCommand} before archiving.`, 1);
924
+ else {
925
+ const preflight = await (dependencies.preflightSyncedCheckout ?? preflightSyncedCheckout)(syncTarget, git);
926
+ const isBoundTerminalRetry = Boolean(preflight.sha &&
927
+ activeRecord?.archiveSourceRefSha === preflight.sha &&
928
+ preflight.status === 'unpushed');
929
+ if (preflight.status !== 'clean' &&
930
+ !(preflight.status === 'absent' &&
931
+ (activeRecord?.status === 'complete' ||
932
+ Boolean(activeRecord?.archiveSourceRefSha))) &&
933
+ !isBoundTerminalRetry) {
934
+ const recoveryCommand = preflight.status === 'absent'
935
+ ? `oat project pull ${options.projectName}`
936
+ : `oat project push ${options.projectName}`;
937
+ throw new CliError(`Synced project ${options.projectName} is ${preflight.status}; run ${recoveryCommand} before archiving.`, 1);
938
+ }
939
+ sourceRefSha =
940
+ preflight.sha ??
941
+ activeRecord?.archiveSourceRefSha ??
942
+ (await git.run(['rev-parse', syncTarget.ref], {
943
+ cwd: options.repoRoot,
944
+ })).stdout;
867
945
  }
868
- sourceRefSha =
869
- preflight.sha ??
870
- (await git.run(['rev-parse', syncTarget.ref], { cwd: options.repoRoot }))
871
- .stdout;
872
946
  if (!/^[0-9a-f]{40}$/.test(sourceRefSha)) {
873
947
  throw new CliError(`Unable to bind archive retry identity for ${options.projectName} to ${syncTarget.ref}.`, 2);
874
948
  }
875
- if (activeRecord.archiveSourceRefSha &&
949
+ if (activeRecord?.archiveSourceRefSha &&
876
950
  activeRecord.archiveSourceRefSha !== sourceRefSha) {
877
951
  throw new CliError(`Archive retry for ${options.projectName} is bound to source ref ${activeRecord.archiveSourceRefSha}, but ${syncTarget.ref} is now ${sourceRefSha}. Restore the retained ref to the recorded commit to finish this archive transaction, or preserve the existing snapshot and start a separately reviewed recovery; refusing to accept stale archive content.`, 1);
878
952
  }
@@ -881,9 +955,11 @@ export async function archiveProjectOnCompletion(options, dependencies = {}) {
881
955
  repoRoot: options.repoRoot,
882
956
  projectsRoot: options.projectsRoot,
883
957
  projectName: options.projectName,
884
- ...(activeRecord?.archiveSnapshot
958
+ ...((activeRecord?.archiveSnapshot ??
959
+ recordlessIdentity?.metadata.snapshotName)
885
960
  ? {
886
- archiveSnapshot: activeRecord.archiveSnapshot,
961
+ archiveSnapshot: activeRecord?.archiveSnapshot ??
962
+ recordlessIdentity?.metadata.snapshotName,
887
963
  archiveScope: projectScope,
888
964
  }
889
965
  : {}),
@@ -902,7 +978,9 @@ export async function archiveProjectOnCompletion(options, dependencies = {}) {
902
978
  }
903
979
  const archivePath = archiveTarget.archivePath;
904
980
  const exportIdentity = syncTarget
905
- ? (activeRecord?.archiveSnapshot ?? snapshotName)
981
+ ? (activeRecord?.archiveSnapshot ??
982
+ recordlessIdentity?.metadata.snapshotName ??
983
+ snapshotName)
906
984
  : snapshotName;
907
985
  const snapshotId = syncTarget ? exportIdentity : basename(archivePath);
908
986
  const shouldPersistArchiveSnapshot = Boolean(syncTarget &&
@@ -1000,6 +1078,9 @@ export async function archiveProjectOnCompletion(options, dependencies = {}) {
1000
1078
  env: dependencies.env,
1001
1079
  });
1002
1080
  warnings.push(...access.warnings);
1081
+ if (syncTarget && !access.ok) {
1082
+ throw new CliError(`Synced archive durability for ${options.projectName} requires the configured S3 upload to succeed before terminal cleanup. ${access.warnings.join(' ') || 'Archive S3 access could not be verified.'}`, 1);
1083
+ }
1003
1084
  if (access.ok) {
1004
1085
  const remoteRepoRoot = await resolvePrimaryRepoRoot(options.repoRoot, dependencies);
1005
1086
  s3Path = buildProjectArchiveS3Uri(options.s3Uri, remoteRepoRoot, exportIdentity);
@@ -1018,6 +1099,9 @@ export async function archiveProjectOnCompletion(options, dependencies = {}) {
1018
1099
  }
1019
1100
  catch (error) {
1020
1101
  const message = error instanceof Error ? error.message : String(error);
1102
+ if (syncTarget) {
1103
+ throw new CliError(`Synced archive durability for ${options.projectName} requires the configured S3 upload to succeed before terminal cleanup: ${message}`, 1);
1104
+ }
1021
1105
  warnings.push(`Archive S3 sync to \`${s3Path}\` failed: ${message}`);
1022
1106
  s3Path = null;
1023
1107
  }
@@ -1025,38 +1109,53 @@ export async function archiveProjectOnCompletion(options, dependencies = {}) {
1025
1109
  }
1026
1110
  let lifecycleCommit = null;
1027
1111
  let recapExportPaths = [];
1112
+ let terminalReceipt = null;
1113
+ let recordRetired = false;
1028
1114
  if (syncTarget) {
1029
- if (!activeRecord) {
1030
- throw new CliError(`Synced project ${options.projectName} is missing its discovery record.`, 2);
1115
+ if (!sourceRefSha) {
1116
+ throw new CliError(`Synced project ${options.projectName} has no verified source SHA for terminal sealing.`, 2);
1117
+ }
1118
+ terminalReceipt = await (dependencies.retireSyncedRef ?? retireSyncedRef)(syncTarget, sourceRefSha, git);
1119
+ if (terminalReceipt.state !== 'completed-only' &&
1120
+ terminalReceipt.state !== 'matching-aliases') {
1121
+ throw new CliError(`Synced project ${options.projectName} did not reach a verified terminal ref state.`, 2);
1122
+ }
1123
+ const removed = await (dependencies.removeSyncedCheckout ?? removeSyncedCheckout)(syncTarget, git, { force: true });
1124
+ if (removed.status !== 'removed' && removed.status !== 'absent') {
1125
+ throw new CliError(`Synced checkout became ${removed.status} during archive; run oat project push ${options.projectName} and retry.`, 1);
1031
1126
  }
1032
1127
  if (projectRecapExport) {
1033
1128
  recapExportPaths = (await listArchiveExportFiles(projectRecapExport.exportRoot)).filter((filePath) => basename(filePath) !== 'manifest.json' &&
1034
1129
  basename(filePath) !== 'build-record.json');
1035
1130
  }
1036
- activeRecord = {
1037
- ...activeRecord,
1038
- status: 'complete',
1039
- completedAt: activeRecord.completedAt ?? timestamp,
1040
- };
1041
- await writeRecord(recordPath, activeRecord);
1131
+ await (dependencies.removeSyncedRecord
1132
+ ? dependencies.removeSyncedRecord(recordPath)
1133
+ : removePath(recordPath, { recursive: true, force: true }));
1134
+ recordRetired = true;
1042
1135
  if (options.commit !== false) {
1043
1136
  const pathspecs = [
1044
1137
  recordPath,
1045
1138
  ...(summaryExportFile ? [summaryExportFile] : []),
1046
1139
  ...recapExportPaths,
1047
1140
  ];
1048
- const committed = await (dependencies.commitRecordChange ?? commitRecordChange)(options.repoRoot, pathspecs, `chore(oat): complete synced project ${options.projectName}`, git, {
1049
- summaryExportPath: options.summaryExportPath,
1050
- projectRoots: syncTarget,
1051
- recapExportRoot: projectRecapExport?.exportRoot,
1052
- });
1141
+ const lifecycleStatus = await git.run([
1142
+ 'status',
1143
+ '--porcelain=v1',
1144
+ '--untracked-files=all',
1145
+ '--',
1146
+ ...pathspecs.map((pathspec) => relative(canonicalizePath(resolve(options.repoRoot)), canonicalizePath(resolve(pathspec)))),
1147
+ ], { cwd: options.repoRoot });
1148
+ const committed = lifecycleStatus.stdout === ''
1149
+ ? null
1150
+ : await (dependencies.commitRecordChange ?? commitRecordChange)(options.repoRoot, pathspecs, `chore(oat): complete synced project ${options.projectName}`, git, {
1151
+ summaryExportPath: options.summaryExportPath,
1152
+ projectRoots: syncTarget,
1153
+ recapExportRoot: projectRecapExport?.exportRoot,
1154
+ });
1053
1155
  lifecycleCommit =
1054
1156
  committed?.sha ??
1055
- (await recoverSyncedLifecycleCommit(options.repoRoot, pathspecs, activeRecord, `chore(oat): complete synced project ${options.projectName}`, git));
1056
- }
1057
- const removed = await (dependencies.removeSyncedCheckout ?? removeSyncedCheckout)(syncTarget, git);
1058
- if (removed.status !== 'removed' && removed.status !== 'absent') {
1059
- throw new CliError(`Synced checkout became ${removed.status} during archive; run oat project push ${options.projectName} and retry.`, 1);
1157
+ (await recoverSyncedLifecycleCommit(options.repoRoot, pathspecs, options.projectName, `chore(oat): complete synced project ${options.projectName}`, git));
1158
+ await dependencies.afterLifecycleCommit?.();
1060
1159
  }
1061
1160
  }
1062
1161
  return {
@@ -1068,12 +1167,14 @@ export async function archiveProjectOnCompletion(options, dependencies = {}) {
1068
1167
  lifecycleCommit,
1069
1168
  recapExportPaths,
1070
1169
  snapshotId,
1170
+ terminalReceipt,
1171
+ recordRetired,
1071
1172
  };
1072
1173
  }
1073
- async function recoverSyncedLifecycleCommit(repoRoot, pathspecs, record, expectedSubject, git) {
1174
+ async function recoverSyncedLifecycleCommit(repoRoot, pathspecs, projectName, expectedSubject, git) {
1074
1175
  const [recordPathspec] = pathspecs;
1075
1176
  if (!recordPathspec) {
1076
- throw new CliError(`Unable to recover the prior lifecycle commit for ${record.slug}: no lifecycle paths were supplied.`, 2);
1177
+ throw new CliError(`Unable to recover the prior lifecycle commit for ${projectName}: no lifecycle paths were supplied.`, 2);
1077
1178
  }
1078
1179
  const recordPath = relative(resolve(repoRoot), resolve(recordPathspec))
1079
1180
  .split(sep)
@@ -1086,7 +1187,7 @@ async function recoverSyncedLifecycleCommit(repoRoot, pathspecs, record, expecte
1086
1187
  cwd: repoRoot,
1087
1188
  })).stdout;
1088
1189
  if (!/^[0-9a-f]{40}$/.test(candidate)) {
1089
- throw new CliError(`Unable to recover the prior lifecycle commit for ${record.slug}.`, 2);
1190
+ throw new CliError(`Unable to recover the prior lifecycle commit for ${projectName}.`, 2);
1090
1191
  }
1091
1192
  const subject = (await git.run(['show', '-s', '--format=%s', candidate], { cwd: repoRoot })).stdout;
1092
1193
  const ancestor = await git.run(['merge-base', '--is-ancestor', candidate, 'HEAD'], { cwd: repoRoot, allowFailure: true });
@@ -1095,20 +1196,16 @@ async function recoverSyncedLifecycleCommit(repoRoot, pathspecs, record, expecte
1095
1196
  .filter(Boolean)
1096
1197
  .sort();
1097
1198
  const contentsMatch = await git.run(['diff', '--quiet', candidate, '--', ...normalizedPathspecs], { cwd: repoRoot, allowFailure: true });
1098
- const committedRecord = await git.run(['show', `${candidate}:${recordPath}`], { cwd: repoRoot });
1099
- let parsedRecord;
1100
- try {
1101
- parsedRecord = JSON.parse(committedRecord.stdout);
1102
- }
1103
- catch {
1104
- parsedRecord = null;
1105
- }
1199
+ const committedRecord = await git.run(['show', `${candidate}:${recordPath}`], {
1200
+ cwd: repoRoot,
1201
+ allowFailure: true,
1202
+ });
1106
1203
  if (subject !== expectedSubject ||
1107
1204
  ancestor.code !== 0 ||
1108
1205
  contentsMatch.code !== 0 ||
1109
1206
  JSON.stringify(changedPaths) !== JSON.stringify(normalizedPathspecs) ||
1110
- JSON.stringify(parsedRecord) !== JSON.stringify(record)) {
1111
- throw new CliError(`Unable to recover lifecycle commit ${candidate} for ${record.slug}: subject, path set, contents, or branch relationship did not match the completed archive transaction.`, 2);
1207
+ committedRecord.code === 0) {
1208
+ throw new CliError(`Unable to recover lifecycle commit ${candidate} for ${projectName}: subject, path set, record deletion, contents, or branch relationship did not match the completed archive transaction.`, 2);
1112
1209
  }
1113
1210
  return candidate;
1114
1211
  }
@@ -1 +1 @@
1
- {"version":3,"file":"push-runner.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/archive/push-runner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAOjE,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,cAAc,EACpB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAEL,6BAA6B,EAI7B,2BAA2B,EAC3B,sBAAsB,EACtB,oCAAoC,EAEpC,KAAK,iCAAiC,EACtC,KAAK,gCAAgC,EAEtC,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,qCAAqC;IACpD,mBAAmB,EAAE,CACnB,OAAO,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,KAC/C,cAAc,CAAC;IACpB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,2BAA2B,EAAE,OAAO,2BAA2B,CAAC;IAChE,gBAAgB,EAAE,OAAO,gBAAgB,CAAC;IAC1C,oCAAoC,EAAE,OAAO,oCAAoC,CAAC;IAClF,0BAA0B,EAAE,CAC1B,OAAO,EAAE,iCAAiC,KACvC,OAAO,CAAC,gCAAgC,CAAC,CAAC;IAC/C,6BAA6B,EAAE,OAAO,6BAA6B,CAAC;IACpE,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;IAC9B,SAAS,EAAE,MAAM,MAAM,CAAC;CACzB;AAsBD,wBAAgB,4CAA4C,IAAI,qCAAqC,CAgBpG;AAuJD,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,qCAAqC,EACnD,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CAyGf"}
1
+ {"version":3,"file":"push-runner.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/archive/push-runner.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAE,KAAK,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAChF,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAOjE,OAAO,EAGL,KAAK,SAAS,EACd,KAAK,cAAc,EACpB,MAAM,oBAAoB,CAAC;AAI5B,OAAO,EAEL,6BAA6B,EAI7B,2BAA2B,EAC3B,sBAAsB,EACtB,oCAAoC,EAEpC,KAAK,iCAAiC,EACtC,KAAK,gCAAgC,EAEtC,MAAM,iBAAiB,CAAC;AAEzB,MAAM,WAAW,kBAAkB;IACjC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,qCAAqC;IACpD,mBAAmB,EAAE,CACnB,OAAO,EAAE,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC,CAAC,CAAC,KAC/C,cAAc,CAAC;IACpB,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,aAAa,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,SAAS,CAAC,CAAC;IACxD,kBAAkB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAClE,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,sBAAsB,EAAE,OAAO,sBAAsB,CAAC;IACtD,2BAA2B,EAAE,OAAO,2BAA2B,CAAC;IAChE,gBAAgB,EAAE,OAAO,gBAAgB,CAAC;IAC1C,oCAAoC,EAAE,OAAO,oCAAoC,CAAC;IAClF,0BAA0B,EAAE,CAC1B,OAAO,EAAE,iCAAiC,KACvC,OAAO,CAAC,gCAAgC,CAAC,CAAC;IAC/C,6BAA6B,EAAE,OAAO,6BAA6B,CAAC;IACpE,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;IAC9B,SAAS,EAAE,MAAM,MAAM,CAAC;CACzB;AA0BD,wBAAgB,4CAA4C,IAAI,qCAAqC,CAgBpG;AA2JD,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,qCAAqC,EACnD,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,OAAO,EAAE,kBAAkB,EAC3B,OAAO,EAAE,cAAc,GACtB,OAAO,CAAC,IAAI,CAAC,CAmHf"}
@@ -82,6 +82,10 @@ async function buildDryRunReport(dependencies, repoRoot, config, target, archive
82
82
  snapshotId: projectScope === 'synced'
83
83
  ? snapshotName
84
84
  : basename(archiveTarget.archivePath),
85
+ completedRef: null,
86
+ verifiedSourceSha: null,
87
+ activeAliasDisposition: null,
88
+ recordRetired: false,
85
89
  };
86
90
  }
87
91
  function emitArchivePushText(report, summaryExportPath, logger) {
@@ -148,10 +152,11 @@ export async function runArchivePushCommand(dependencies, projectPathArg, option
148
152
  timestamp: dependencies.timestamp,
149
153
  });
150
154
  assertDurableArchiveProjectTarget(archiveTarget);
151
- if (options.projectRecapRun?.trim()) {
155
+ const dryRun = options.dryRun === true || context.dryRun;
156
+ const recordlessSyncedApply = projectScope === 'synced' && syncedRecord === null && !dryRun;
157
+ if (options.projectRecapRun?.trim() && !recordlessSyncedApply) {
152
158
  await dependencies.verifySelectedProjectRecapForArchive(target.projectPath, options.projectRecapRun.trim());
153
159
  }
154
- const dryRun = options.dryRun === true || context.dryRun;
155
160
  if (dryRun) {
156
161
  const report = await buildDryRunReport(dependencies, repoRoot, config, target, archiveTarget, snapshotName, projectScope);
157
162
  emitArchivePushReport(report, config.archive?.summaryExportPath, context);
@@ -174,6 +179,14 @@ export async function runArchivePushCommand(dependencies, projectPathArg, option
174
179
  lifecycleCommit: result.lifecycleCommit,
175
180
  recapExportPaths: result.recapExportPaths,
176
181
  snapshotId: result.snapshotId,
182
+ completedRef: result.terminalReceipt?.completedRef ?? null,
183
+ verifiedSourceSha: result.terminalReceipt?.verifiedSha ?? null,
184
+ activeAliasDisposition: result.terminalReceipt
185
+ ? result.terminalReceipt.activeAliasRetained
186
+ ? 'retained'
187
+ : 'removed'
188
+ : null,
189
+ recordRetired: result.recordRetired,
177
190
  };
178
191
  emitArchivePushReport(report, config.archive?.summaryExportPath, context);
179
192
  process.exitCode = 0;
@@ -0,0 +1,10 @@
1
+ import { type CommandContext, type GlobalOptions } from '../../../app/command-context.js';
2
+ import { Command } from 'commander';
3
+ export interface ProjectDispatchCommandDependencies {
4
+ buildCommandContext: (options: GlobalOptions) => CommandContext;
5
+ resolveProjectRoot: (cwd: string) => Promise<string>;
6
+ readFile: (path: string) => Promise<string>;
7
+ readStdin: () => Promise<string>;
8
+ }
9
+ export declare function createProjectDispatchCommand(overrides?: Partial<ProjectDispatchCommandDependencies>): Command;
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/dispatch/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAI9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAapC,MAAM,WAAW,kCAAkC;IACjD,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAC5C,SAAS,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CAClC;AA0ID,wBAAgB,4BAA4B,CAC1C,SAAS,GAAE,OAAO,CAAC,kCAAkC,CAAM,GAC1D,OAAO,CA2BT"}
@@ -0,0 +1,137 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ import { isAbsolute, join } from 'node:path';
3
+ import { buildCommandContext, } from '../../../app/command-context.js';
4
+ import { readGlobalOptions } from '../../shared/shared.utils.js';
5
+ import { fileExists } from '../../../fs/io.js';
6
+ import { resolveProjectRoot, validateRealPathWithinScope } from '../../../fs/paths.js';
7
+ import { Command } from 'commander';
8
+ import { recordProjectDispatch, redactDispatchMessage, } from './record.js';
9
+ const DEFAULT_DEPENDENCIES = {
10
+ buildCommandContext,
11
+ resolveProjectRoot,
12
+ readFile: (path) => readFile(path, 'utf8'),
13
+ readStdin: async () => {
14
+ const chunks = [];
15
+ for await (const chunk of process.stdin) {
16
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
17
+ }
18
+ return Buffer.concat(chunks).toString('utf8');
19
+ },
20
+ };
21
+ async function resolveProjectPath(repoRoot, project) {
22
+ if (!project)
23
+ return null;
24
+ const candidate = isAbsolute(project) ? project : join(repoRoot, project);
25
+ const validated = await validateRealPathWithinScope(candidate, repoRoot);
26
+ if (!(await fileExists(join(validated.realPath, 'state.md')))) {
27
+ throw new Error('Project path must contain a readable state.md.');
28
+ }
29
+ return validated.realPath;
30
+ }
31
+ function axes(values) {
32
+ return values
33
+ .map(([name, value]) => `${name}=${value ?? 'not-reported'}`)
34
+ .join(' ');
35
+ }
36
+ /**
37
+ * Render the two layers separately. Configured invocation is launcher-owned and
38
+ * immutable; runtime observation is optional per-run corroboration. They are
39
+ * never combined into one "effective" identity, because a mismatch must stay
40
+ * legible as a mismatch rather than silently overwrite either side.
41
+ */
42
+ function runtimeIdentityLines(identity) {
43
+ const { configured, observed } = identity;
44
+ return [
45
+ `Configured invocation (immutable): ${axes([
46
+ ['role', configured.roleName],
47
+ ['role_selector', configured.roleSelector],
48
+ ['model', configured.model],
49
+ ['effort', configured.effort],
50
+ ['service_tier', configured.serviceTier],
51
+ ])}`,
52
+ observed === null
53
+ ? `Observed runtime identity: not reported${identity.reason === null ? '' : ` (${identity.reason})`} (corroboration only; the configured invocation is unchanged).`
54
+ : `Observed runtime identity (${observed.source}, ${identity.match} on ${identity.comparedAxes.length === 0
55
+ ? 'no comparable axis'
56
+ : identity.comparedAxes.join('+')}): ${axes([
57
+ ['lineage', observed.childLineage],
58
+ ['role', observed.role],
59
+ ['model', observed.model],
60
+ ['effort', observed.effort],
61
+ ['service_tier', observed.serviceTier],
62
+ ])}`,
63
+ ];
64
+ }
65
+ async function runRecordCommand(options, context, dependencies) {
66
+ let repoRoot = null;
67
+ let projectPath = null;
68
+ try {
69
+ repoRoot = await dependencies.resolveProjectRoot(context.cwd);
70
+ projectPath = await resolveProjectPath(repoRoot, options.project);
71
+ const content = options.eventFile === '-'
72
+ ? await dependencies.readStdin()
73
+ : await dependencies.readFile(options.eventFile);
74
+ // Hand the raw event to the recorder; it owns the single authoritative
75
+ // parse, and parsing twice would relabel the provenance of its own output.
76
+ const raw = await recordProjectDispatch({
77
+ projectPath,
78
+ input: JSON.parse(content),
79
+ });
80
+ // The degradation reason is caller-influenced text on the success path, so
81
+ // it goes through the same single redaction boundary as every failure
82
+ // message. Producing a message that skips this boundary is exactly the
83
+ // per-producer regression this command was restructured to prevent.
84
+ const result = {
85
+ ...raw,
86
+ runtimeIdentity: {
87
+ ...raw.runtimeIdentity,
88
+ reason: raw.runtimeIdentity.reason === null
89
+ ? null
90
+ : redactDispatchMessage(raw.runtimeIdentity.reason, {
91
+ project: projectPath,
92
+ repo: repoRoot,
93
+ home: context.home,
94
+ }),
95
+ },
96
+ };
97
+ if (context.json) {
98
+ context.logger.json(result);
99
+ }
100
+ else {
101
+ if (result.status === 'persisted') {
102
+ context.logger.success(`Recorded project dispatch: ${result.path}`);
103
+ }
104
+ else {
105
+ context.logger.info('Dispatch evidence is valid; no project path was supplied, so nothing was persisted.');
106
+ }
107
+ for (const line of runtimeIdentityLines(result.runtimeIdentity)) {
108
+ context.logger.info(line);
109
+ }
110
+ }
111
+ process.exitCode = 0;
112
+ }
113
+ catch (error) {
114
+ // Single redaction boundary for every failure this command can surface.
115
+ const message = redactDispatchMessage(error instanceof Error ? error.message : String(error), { project: projectPath, repo: repoRoot, home: context.home });
116
+ if (context.json) {
117
+ context.logger.json({ status: 'error', message });
118
+ }
119
+ else {
120
+ context.logger.error(message);
121
+ }
122
+ process.exitCode = 1;
123
+ }
124
+ }
125
+ export function createProjectDispatchCommand(overrides = {}) {
126
+ const dependencies = { ...DEFAULT_DEPENDENCIES, ...overrides };
127
+ return new Command('dispatch')
128
+ .description('Validate and persist project dispatch provenance')
129
+ .addCommand(new Command('record')
130
+ .description('Record one generic dispatch plus namespaced OAT evidence')
131
+ .option('--project <project-path>', 'Project path; omit to validate without persistence')
132
+ .requiredOption('--event-file <json-file-or-dash>', 'Complete record and event JSON file, or - for standard input')
133
+ .action(async (options, command) => {
134
+ const context = dependencies.buildCommandContext(readGlobalOptions(command));
135
+ await runRecordCommand(options, context, dependencies);
136
+ }));
137
+ }
@@ -0,0 +1,91 @@
1
+ import { type GenericDispatchRecord } from '../../../providers/identity/generic-dispatch-record.js';
2
+ import { type OatDispatchEvidenceEvent, type PersistedOatDispatchRecordV1 } from '../../../providers/identity/oat-dispatch-record.js';
3
+ /**
4
+ * Test seam for deterministic concurrency coverage. `afterRead` fires after the
5
+ * caller has read the journal revision it will publish against and before the
6
+ * writer lock is acquired, which is exactly the window a stale concurrent
7
+ * writer occupies.
8
+ */
9
+ export interface DispatchRecordRaceBarriers {
10
+ afterRead?: () => Promise<void>;
11
+ }
12
+ /**
13
+ * Hard redaction boundary. Producers redact their own messages, but this is the
14
+ * last stop before a message reaches `--json`, so a future call site that
15
+ * forgets cannot regress NFR1. Known roots become stable labels; anything else
16
+ * that still looks like an absolute path is scrubbed.
17
+ *
18
+ * The detector is shared with the record sanitizer. Two independent notions of
19
+ * "looks like a path" is how a path could be scrubbed from an error message and
20
+ * written verbatim into the durable record by the same command.
21
+ */
22
+ export declare function redactDispatchMessage(message: string, roots?: {
23
+ project?: string | null;
24
+ repo?: string | null;
25
+ home?: string | null;
26
+ }): string;
27
+ export interface DispatchRecordInput {
28
+ record: GenericDispatchRecord;
29
+ event: OatDispatchEvidenceEvent;
30
+ /** Why an observation degraded, when one did. Not durable evidence. */
31
+ observationReason?: string | null;
32
+ }
33
+ /**
34
+ * Configured and observed identity, reported side by side and never merged.
35
+ * `configured` is the launcher-owned immutable selection; `observed` is
36
+ * optional per-run corroboration that is `null` whenever the provider reported
37
+ * nothing. A `match` of `mismatching` is evidence, not authorization.
38
+ */
39
+ export interface DispatchRecordRuntimeIdentity {
40
+ configured: {
41
+ roleName: string;
42
+ roleSelector: string | null;
43
+ model: string | null;
44
+ effort: string | null;
45
+ serviceTier: string | null;
46
+ };
47
+ observed: {
48
+ provider: string;
49
+ source: string;
50
+ observedAt: string;
51
+ childLineage: string | null;
52
+ role: string | null;
53
+ model: string | null;
54
+ effort: string | null;
55
+ serviceTier: string | null;
56
+ } | null;
57
+ match: 'matching' | 'mismatching' | 'not-comparable' | null;
58
+ /**
59
+ * The axes `match` rests on. A `matching` verdict says nothing about an axis
60
+ * absent from this list.
61
+ */
62
+ comparedAxes: readonly string[];
63
+ /**
64
+ * Why an observation is `not-reported`, so a caller attaching a 25 MB rollout
65
+ * can tell that outcome from one attaching an empty array. A per-command
66
+ * diagnostic, never durable evidence.
67
+ */
68
+ reason: string | null;
69
+ status: 'reported' | 'not-reported';
70
+ }
71
+ export type ProjectDispatchRecordResult = {
72
+ status: 'persisted' | 'validated-only';
73
+ path: string | null;
74
+ created: boolean;
75
+ record: PersistedOatDispatchRecordV1;
76
+ runtimeIdentity: DispatchRecordRuntimeIdentity;
77
+ };
78
+ export declare function parseDispatchRecordInput(value: unknown): DispatchRecordInput;
79
+ /**
80
+ * Parse once, here. An earlier revision parsed in the command layer and again
81
+ * here; because the metadata path resolves to a finished observation, the second
82
+ * parse saw its own output as caller-supplied and overwrote the parser source
83
+ * with `caller-asserted`. Parsing is not idempotent by design — provenance
84
+ * depends on which input form arrived — so it must happen exactly once.
85
+ */
86
+ export declare function recordProjectDispatch(input: {
87
+ projectPath: string | null;
88
+ input: unknown;
89
+ raceBarriers?: DispatchRecordRaceBarriers;
90
+ }): Promise<ProjectDispatchRecordResult>;
91
+ //# sourceMappingURL=record.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"record.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/dispatch/record.ts"],"names":[],"mappings":"AAcA,OAAO,EAKL,KAAK,qBAAqB,EAC3B,MAAM,6CAA6C,CAAC;AACrD,OAAO,EAOL,KAAK,wBAAwB,EAE7B,KAAK,4BAA4B,EAElC,MAAM,yCAAyC,CAAC;AAWjD;;;;;GAKG;AACH,MAAM,WAAW,0BAA0B;IACzC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CACjC;AAoCD;;;;;;;;;GASG;AAEH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,MAAM,EACf,KAAK,GAAE;IACL,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjB,GACL,MAAM,CAcR;AAaD,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,qBAAqB,CAAC;IAC9B,KAAK,EAAE,wBAAwB,CAAC;IAChC,uEAAuE;IACvE,iBAAiB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACnC;AAED;;;;;GAKG;AACH,MAAM,WAAW,6BAA6B;IAC5C,UAAU,EAAE;QACV,QAAQ,EAAE,MAAM,CAAC;QACjB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,CAAC;IACF,QAAQ,EAAE;QACR,QAAQ,EAAE,MAAM,CAAC;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;QAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;QACpB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;QACrB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;QACtB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;KAC5B,GAAG,IAAI,CAAC;IACT,KAAK,EAAE,UAAU,GAAG,aAAa,GAAG,gBAAgB,GAAG,IAAI,CAAC;IAC5D;;;OAGG;IACH,YAAY,EAAE,SAAS,MAAM,EAAE,CAAC;IAChC;;;;OAIG;IACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,UAAU,GAAG,cAAc,CAAC;CACrC;AAED,MAAM,MAAM,2BAA2B,GAAG;IACxC,MAAM,EAAE,WAAW,GAAG,gBAAgB,CAAC;IACvC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,4BAA4B,CAAC;IACrC,eAAe,EAAE,6BAA6B,CAAC;CAChD,CAAC;AAsEF,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,CAgF5E;AAgKD;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE;IACjD,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,KAAK,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,0BAA0B,CAAC;CAC3C,GAAG,OAAO,CAAC,2BAA2B,CAAC,CA6HvC"}