@open-agent-toolkit/cli 0.2.41 → 0.2.46

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 (212) hide show
  1. package/assets/agents/oat-phase-implementer.md +11 -1
  2. package/assets/bundle-metadata.json +1 -1
  3. package/assets/docs/cli-utilities/configuration.md +11 -1
  4. package/assets/docs/cli-utilities/tool-packs.md +55 -9
  5. package/assets/docs/quickstart.md +9 -0
  6. package/assets/docs/reference/cli-reference.md +56 -1
  7. package/assets/docs/reference/file-locations.md +18 -1
  8. package/assets/docs/reference/oat-directory-structure.md +20 -4
  9. package/assets/docs/reference/troubleshooting.md +18 -11
  10. package/assets/docs/workflows/projects/artifacts.md +27 -1
  11. package/assets/docs/workflows/projects/implementation-execution.md +22 -0
  12. package/assets/docs/workflows/projects/index.md +6 -0
  13. package/assets/docs/workflows/projects/lifecycle.md +19 -5
  14. package/assets/docs/workflows/projects/picking-up-projects.md +75 -0
  15. package/assets/docs/workflows/projects/pr-flow.md +22 -1
  16. package/assets/docs/workflows/projects/reviewing-oat-prs.md +60 -0
  17. package/assets/public-package-versions.json +4 -4
  18. package/assets/skills/oat-brainstorm/SKILL.md +135 -32
  19. package/assets/skills/oat-brainstorm/references/destinations.md +9 -6
  20. package/assets/skills/oat-cursor-cloud-projects/SKILL.md +11 -1
  21. package/assets/skills/oat-doctor/SKILL.md +8 -1
  22. package/assets/skills/oat-project-autonomous/SKILL.md +45 -1
  23. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +8 -8
  24. package/assets/skills/oat-project-capture/SKILL.md +29 -9
  25. package/assets/skills/oat-project-complete/SKILL.md +610 -38
  26. package/assets/skills/oat-project-complete/scripts/parse-completion-retry-fields.mjs +265 -0
  27. package/assets/skills/oat-project-complete/scripts/recover-completion-receipts.mjs +764 -0
  28. package/assets/skills/oat-project-complete/scripts/resolve-completion-retry.mjs +134 -0
  29. package/assets/skills/oat-project-complete/scripts/validate-nonarchive-lifecycle-receipt.mjs +160 -0
  30. package/assets/skills/oat-project-design/SKILL.md +33 -9
  31. package/assets/skills/oat-project-discover/SKILL.md +16 -3
  32. package/assets/skills/oat-project-document/SKILL.md +10 -4
  33. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +8 -8
  34. package/assets/skills/oat-project-implement/SKILL.md +14 -3
  35. package/assets/skills/oat-project-implement/references/completion-and-closeout.md +18 -6
  36. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +8 -8
  37. package/assets/skills/oat-project-implement/references/phase-execution.md +9 -3
  38. package/assets/skills/oat-project-implement/references/plan-and-resume.md +3 -0
  39. package/assets/skills/oat-project-import-plan/SKILL.md +15 -9
  40. package/assets/skills/oat-project-new/SKILL.md +7 -5
  41. package/assets/skills/oat-project-next/SKILL.md +32 -10
  42. package/assets/skills/oat-project-plan/SKILL.md +18 -3
  43. package/assets/skills/oat-project-pr-final/SKILL.md +23 -2
  44. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +8 -8
  45. package/assets/skills/oat-project-pr-progress/SKILL.md +23 -2
  46. package/assets/skills/oat-project-progress/SKILL.md +23 -9
  47. package/assets/skills/oat-project-promote-spec-driven/SKILL.md +20 -2
  48. package/assets/skills/oat-project-quick-start/SKILL.md +48 -18
  49. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +8 -8
  50. package/assets/skills/oat-project-reconcile/SKILL.md +14 -10
  51. package/assets/skills/oat-project-retro/SKILL.md +3 -3
  52. package/assets/skills/oat-project-retro/references/apply-procedure.md +102 -6
  53. package/assets/skills/oat-project-retro-file/SKILL.md +57 -6
  54. package/assets/skills/oat-project-review-provide/SKILL.md +45 -4
  55. package/assets/skills/oat-project-review-receive/SKILL.md +16 -7
  56. package/assets/skills/oat-project-review-receive-remote/SKILL.md +9 -3
  57. package/assets/skills/oat-project-revise/SKILL.md +12 -3
  58. package/assets/skills/oat-project-spec/SKILL.md +16 -3
  59. package/assets/skills/oat-project-summary/SKILL.md +113 -13
  60. package/assets/skills/oat-wave-execute/SKILL.md +34 -2
  61. package/assets/skills/oat-worktree-bootstrap/SKILL.md +13 -1
  62. package/assets/skills/oat-worktree-bootstrap-auto/SKILL.md +13 -1
  63. package/dist/commands/config/index.d.ts +1 -0
  64. package/dist/commands/config/index.d.ts.map +1 -1
  65. package/dist/commands/config/index.js +34 -3
  66. package/dist/commands/doctor/index.d.ts +2 -0
  67. package/dist/commands/doctor/index.d.ts.map +1 -1
  68. package/dist/commands/doctor/index.js +27 -3
  69. package/dist/commands/doctor/synced-projects.d.ts +12 -0
  70. package/dist/commands/doctor/synced-projects.d.ts.map +1 -0
  71. package/dist/commands/doctor/synced-projects.js +208 -0
  72. package/dist/commands/init/gitattributes.d.ts +4 -0
  73. package/dist/commands/init/gitattributes.d.ts.map +1 -0
  74. package/dist/commands/init/gitattributes.js +12 -0
  75. package/dist/commands/init/gitignore.d.ts +8 -1
  76. package/dist/commands/init/gitignore.d.ts.map +1 -1
  77. package/dist/commands/init/gitignore.js +146 -41
  78. package/dist/commands/init/index.d.ts +2 -0
  79. package/dist/commands/init/index.d.ts.map +1 -1
  80. package/dist/commands/init/index.js +3 -0
  81. package/dist/commands/init/managed-block.d.ts +10 -0
  82. package/dist/commands/init/managed-block.d.ts.map +1 -0
  83. package/dist/commands/init/managed-block.js +40 -0
  84. package/dist/commands/init/tools/index.d.ts +1 -0
  85. package/dist/commands/init/tools/index.d.ts.map +1 -1
  86. package/dist/commands/init/tools/index.js +37 -9
  87. package/dist/commands/init/tools/workflows/install-workflows.js +1 -1
  88. package/dist/commands/local/index.d.ts.map +1 -1
  89. package/dist/commands/local/index.js +5 -1
  90. package/dist/commands/local/sync.d.ts +4 -0
  91. package/dist/commands/local/sync.d.ts.map +1 -1
  92. package/dist/commands/local/sync.js +123 -2
  93. package/dist/commands/pjm/adoption.d.ts +2 -0
  94. package/dist/commands/pjm/adoption.d.ts.map +1 -1
  95. package/dist/commands/pjm/adoption.js +1 -1
  96. package/dist/commands/project/archive/archive-utils.d.ts +24 -0
  97. package/dist/commands/project/archive/archive-utils.d.ts.map +1 -1
  98. package/dist/commands/project/archive/archive-utils.js +349 -22
  99. package/dist/commands/project/archive/index.d.ts.map +1 -1
  100. package/dist/commands/project/archive/index.js +1 -0
  101. package/dist/commands/project/archive/push-runner.d.ts +5 -1
  102. package/dist/commands/project/archive/push-runner.d.ts.map +1 -1
  103. package/dist/commands/project/archive/push-runner.js +33 -4
  104. package/dist/commands/project/complete-state/index.d.ts.map +1 -1
  105. package/dist/commands/project/complete-state/index.js +3 -1
  106. package/dist/commands/project/index.d.ts.map +1 -1
  107. package/dist/commands/project/index.js +12 -0
  108. package/dist/commands/project/links/compute.d.ts +9 -0
  109. package/dist/commands/project/links/compute.d.ts.map +1 -0
  110. package/dist/commands/project/links/compute.js +27 -0
  111. package/dist/commands/project/links/index.d.ts +17 -0
  112. package/dist/commands/project/links/index.d.ts.map +1 -0
  113. package/dist/commands/project/links/index.js +72 -0
  114. package/dist/commands/project/links/refresh.d.ts +26 -0
  115. package/dist/commands/project/links/refresh.d.ts.map +1 -0
  116. package/dist/commands/project/links/refresh.js +92 -0
  117. package/dist/commands/project/links/render.d.ts +24 -0
  118. package/dist/commands/project/links/render.d.ts.map +1 -0
  119. package/dist/commands/project/links/render.js +68 -0
  120. package/dist/commands/project/list.d.ts +5 -0
  121. package/dist/commands/project/list.d.ts.map +1 -1
  122. package/dist/commands/project/list.js +182 -9
  123. package/dist/commands/project/migrate/index.d.ts +22 -0
  124. package/dist/commands/project/migrate/index.d.ts.map +1 -0
  125. package/dist/commands/project/migrate/index.js +79 -0
  126. package/dist/commands/project/new/index.d.ts +2 -0
  127. package/dist/commands/project/new/index.d.ts.map +1 -1
  128. package/dist/commands/project/new/index.js +14 -2
  129. package/dist/commands/project/new/scaffold.d.ts +22 -1
  130. package/dist/commands/project/new/scaffold.d.ts.map +1 -1
  131. package/dist/commands/project/new/scaffold.js +287 -69
  132. package/dist/commands/project/open/index.d.ts +16 -0
  133. package/dist/commands/project/open/index.d.ts.map +1 -1
  134. package/dist/commands/project/open/index.js +151 -19
  135. package/dist/commands/project/pause/index.d.ts +8 -0
  136. package/dist/commands/project/pause/index.d.ts.map +1 -1
  137. package/dist/commands/project/pause/index.js +129 -19
  138. package/dist/commands/project/prune/index.d.ts +21 -0
  139. package/dist/commands/project/prune/index.d.ts.map +1 -0
  140. package/dist/commands/project/prune/index.js +95 -0
  141. package/dist/commands/project/pull/index.d.ts +28 -0
  142. package/dist/commands/project/pull/index.d.ts.map +1 -0
  143. package/dist/commands/project/pull/index.js +157 -0
  144. package/dist/commands/project/push/index.d.ts +22 -0
  145. package/dist/commands/project/push/index.d.ts.map +1 -0
  146. package/dist/commands/project/push/index.js +100 -0
  147. package/dist/commands/project/scope/index.d.ts +17 -0
  148. package/dist/commands/project/scope/index.d.ts.map +1 -0
  149. package/dist/commands/project/scope/index.js +107 -0
  150. package/dist/commands/project/split/run.d.ts +4 -0
  151. package/dist/commands/project/split/run.d.ts.map +1 -1
  152. package/dist/commands/project/split/run.js +48 -10
  153. package/dist/commands/project/sync/git.d.ts +18 -0
  154. package/dist/commands/project/sync/git.d.ts.map +1 -0
  155. package/dist/commands/project/sync/git.js +60 -0
  156. package/dist/commands/project/sync/record.d.ts +22 -0
  157. package/dist/commands/project/sync/record.d.ts.map +1 -0
  158. package/dist/commands/project/sync/record.js +133 -0
  159. package/dist/commands/project/sync/ref-sync.d.ts +120 -0
  160. package/dist/commands/project/sync/ref-sync.d.ts.map +1 -0
  161. package/dist/commands/project/sync/ref-sync.js +962 -0
  162. package/dist/commands/project/sync/resolve-target.d.ts +27 -0
  163. package/dist/commands/project/sync/resolve-target.d.ts.map +1 -0
  164. package/dist/commands/project/sync/resolve-target.js +159 -0
  165. package/dist/commands/shared/oat-paths.d.ts +4 -1
  166. package/dist/commands/shared/oat-paths.d.ts.map +1 -1
  167. package/dist/commands/shared/oat-paths.js +2 -2
  168. package/dist/commands/shared/project-scope.d.ts +23 -0
  169. package/dist/commands/shared/project-scope.d.ts.map +1 -0
  170. package/dist/commands/shared/project-scope.js +106 -0
  171. package/dist/commands/tools/migrate/index.js +1 -1
  172. package/dist/commands/tools/shared/pack-inventory.d.ts.map +1 -1
  173. package/dist/commands/tools/shared/pack-inventory.js +79 -8
  174. package/dist/commands/tools/shared/pack-lifecycle.js +1 -1
  175. package/dist/commands/tools/shared/pack-reconcile.d.ts.map +1 -1
  176. package/dist/commands/tools/shared/pack-reconcile.js +4 -1
  177. package/dist/commands/tools/shared/project-tools-config.d.ts +6 -2
  178. package/dist/commands/tools/shared/project-tools-config.d.ts.map +1 -1
  179. package/dist/commands/tools/shared/project-tools-config.js +7 -5
  180. package/dist/commands/tools/update/index.d.ts.map +1 -1
  181. package/dist/commands/tools/update/index.js +38 -14
  182. package/dist/commands/tools/update/update-tools.d.ts +2 -0
  183. package/dist/commands/tools/update/update-tools.d.ts.map +1 -1
  184. package/dist/config/oat-config.d.ts +6 -3
  185. package/dist/config/oat-config.d.ts.map +1 -1
  186. package/dist/config/oat-config.js +41 -7
  187. package/dist/config/resolve.d.ts.map +1 -1
  188. package/dist/config/resolve.js +2 -1
  189. package/dist/fs/io.d.ts +2 -1
  190. package/dist/fs/io.d.ts.map +1 -1
  191. package/dist/fs/io.js +5 -2
  192. package/dist/projects/split/finalize.d.ts.map +1 -1
  193. package/dist/projects/split/finalize.js +55 -2
  194. package/dist/projects/split/resume.d.ts +3 -0
  195. package/dist/projects/split/resume.d.ts.map +1 -1
  196. package/dist/projects/split/resume.js +34 -7
  197. package/dist/projects/split/seed-children.d.ts.map +1 -1
  198. package/dist/projects/split/seed-children.js +6 -0
  199. package/dist/projects/split/write-parent.d.ts +7 -0
  200. package/dist/projects/split/write-parent.d.ts.map +1 -1
  201. package/dist/projects/split/write-parent.js +7 -4
  202. package/dist/release/public-package-contract.d.ts.map +1 -1
  203. package/dist/release/public-package-contract.js +1 -0
  204. package/dist/validation/skills.d.ts.map +1 -1
  205. package/dist/validation/skills.js +434 -0
  206. package/package.json +4 -4
  207. package/dist/__tests__/skills/split-flow-fixtures.d.ts +0 -50
  208. package/dist/__tests__/skills/split-flow-fixtures.d.ts.map +0 -1
  209. package/dist/__tests__/skills/split-flow-fixtures.js +0 -161
  210. package/dist/commands/__tests__/helpers.d.ts +0 -12
  211. package/dist/commands/__tests__/helpers.d.ts.map +0 -1
  212. package/dist/commands/__tests__/helpers.js +0 -36
@@ -0,0 +1,134 @@
1
+ import { lstat, readdir } from 'node:fs/promises';
2
+ import { join } from 'node:path';
3
+ import { pathToFileURL } from 'node:url';
4
+
5
+ import {
6
+ detectCompletionReceiptCandidate,
7
+ recoverCompletionPinSource,
8
+ recoverCompletionReceipts,
9
+ } from './recover-completion-receipts.mjs';
10
+
11
+ const SKIPPED_MUTATIONS = [
12
+ 'project-log',
13
+ 'review-move',
14
+ 'complete-state',
15
+ 'active-pointer',
16
+ 'pr-artifact',
17
+ ];
18
+
19
+ function completionRetryError(message) {
20
+ const error = new Error(message);
21
+ error.code = 'E_COMPLETION_RETRY';
22
+ return error;
23
+ }
24
+
25
+ function parseArguments(argv) {
26
+ const result = { evidencePaths: [] };
27
+ for (let index = 0; index < argv.length; index += 2) {
28
+ const flag = argv[index];
29
+ const value = argv[index + 1];
30
+ if (value === undefined) {
31
+ throw completionRetryError(`Missing value for ${flag ?? 'argument'}.`);
32
+ }
33
+ if (flag === '--project-path') result.projectPath = value;
34
+ else if (flag === '--retained-ref') result.retainedRef = value;
35
+ else if (flag === '--pr-artifact') result.prArtifactPath = value;
36
+ else if (flag === '--evidence-path') result.evidencePaths.push(value);
37
+ else if (flag === '--remote') result.remote = value;
38
+ else throw completionRetryError(`Unsupported argument: ${flag}.`);
39
+ }
40
+ return result;
41
+ }
42
+
43
+ async function resolvePrArtifact(projectPath) {
44
+ let names;
45
+ try {
46
+ names = await readdir(join(projectPath, 'pr'));
47
+ } catch (error) {
48
+ throw completionRetryError(
49
+ `Recognized completion receipt requires exactly one PR artifact: ${error.message}`,
50
+ );
51
+ }
52
+
53
+ const candidates = [];
54
+ for (const name of names.sort()) {
55
+ if (!/^project-pr-.*\.md$/.test(name)) continue;
56
+ const candidate = join(projectPath, 'pr', name);
57
+ const stat = await lstat(candidate);
58
+ if (stat.isFile() && !stat.isSymbolicLink()) {
59
+ candidates.push(`pr/${name}`);
60
+ }
61
+ }
62
+ if (candidates.length !== 1) {
63
+ throw completionRetryError(
64
+ 'Recognized completion receipt requires exactly one regular, non-symlinked PR artifact.',
65
+ );
66
+ }
67
+ return candidates[0];
68
+ }
69
+
70
+ export async function resolveCompletionRetry(options) {
71
+ const candidateResult = await detectCompletionReceiptCandidate(options);
72
+ if (!candidateResult.candidate) {
73
+ return {
74
+ status: 'continue',
75
+ route: 'normal',
76
+ candidate: false,
77
+ nextStep: '3.7',
78
+ skipMutations: false,
79
+ skippedMutations: [],
80
+ };
81
+ }
82
+
83
+ const prArtifactPath =
84
+ options.prArtifactPath ?? (await resolvePrArtifact(options.projectPath));
85
+ if (candidateResult.candidateType === 'pin-source') {
86
+ const pinSource = await recoverCompletionPinSource({
87
+ ...options,
88
+ prArtifactPath,
89
+ });
90
+ return {
91
+ ...pinSource,
92
+ route: 'pin-source',
93
+ candidate: true,
94
+ nextStep: '8.6',
95
+ skipMutations: true,
96
+ skippedMutations: SKIPPED_MUTATIONS,
97
+ prArtifactPath,
98
+ };
99
+ }
100
+ const receipts = await recoverCompletionReceipts({
101
+ ...options,
102
+ prArtifactPath,
103
+ });
104
+
105
+ return {
106
+ ...receipts,
107
+ route: 'recovery',
108
+ candidate: true,
109
+ nextStep: '7.5',
110
+ skipMutations: true,
111
+ skippedMutations: SKIPPED_MUTATIONS,
112
+ prArtifactPath,
113
+ };
114
+ }
115
+
116
+ async function main(argv) {
117
+ return resolveCompletionRetry(parseArguments(argv));
118
+ }
119
+
120
+ if (
121
+ process.argv[1] &&
122
+ import.meta.url === pathToFileURL(process.argv[1]).href
123
+ ) {
124
+ main(process.argv.slice(2))
125
+ .then((result) => {
126
+ process.stdout.write(`${JSON.stringify(result)}\n`);
127
+ })
128
+ .catch((error) => {
129
+ process.stderr.write(
130
+ `${JSON.stringify({ ok: false, code: error.code, message: error.message })}\n`,
131
+ );
132
+ process.exitCode = 1;
133
+ });
134
+ }
@@ -0,0 +1,160 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { execFileSync } from 'node:child_process';
4
+ import { existsSync, readFileSync, realpathSync } from 'node:fs';
5
+ import {
6
+ basename,
7
+ dirname,
8
+ extname,
9
+ isAbsolute,
10
+ relative,
11
+ resolve,
12
+ sep,
13
+ } from 'node:path';
14
+
15
+ function fail(message) {
16
+ process.stderr.write(`Invalid non-archive lifecycle receipt: ${message}\n`);
17
+ process.exit(1);
18
+ }
19
+
20
+ function git(cwd, args) {
21
+ try {
22
+ return execFileSync('git', args, {
23
+ cwd,
24
+ encoding: 'utf8',
25
+ stdio: ['ignore', 'pipe', 'pipe'],
26
+ }).trim();
27
+ } catch (error) {
28
+ const detail =
29
+ error?.stderr?.toString().trim() || error?.message || String(error);
30
+ fail(detail);
31
+ }
32
+ }
33
+
34
+ function gitRaw(cwd, args) {
35
+ try {
36
+ return execFileSync('git', args, {
37
+ cwd,
38
+ encoding: 'utf8',
39
+ stdio: ['ignore', 'pipe', 'pipe'],
40
+ });
41
+ } catch (error) {
42
+ const detail =
43
+ error?.stderr?.toString().trim() || error?.message || String(error);
44
+ fail(detail);
45
+ }
46
+ }
47
+
48
+ function gitSucceeds(cwd, args) {
49
+ try {
50
+ execFileSync('git', args, {
51
+ cwd,
52
+ stdio: ['ignore', 'ignore', 'ignore'],
53
+ });
54
+ return true;
55
+ } catch {
56
+ return false;
57
+ }
58
+ }
59
+
60
+ const [recordArgument, commit, projectName] = process.argv.slice(2);
61
+ if (!recordArgument || !/^[0-9a-f]{40}$/.test(commit ?? '') || !projectName) {
62
+ fail('expected <record-path> <full-commit-sha> <project-name>.');
63
+ }
64
+
65
+ const unresolvedRecordPath = resolve(recordArgument);
66
+ if (!existsSync(unresolvedRecordPath)) {
67
+ fail('record path does not exist; restore the synced discovery record.');
68
+ }
69
+ const recordPath = realpathSync(unresolvedRecordPath);
70
+ const repoRoot = realpathSync(
71
+ git(dirname(recordPath), ['rev-parse', '--show-toplevel']),
72
+ );
73
+ const recordRelative = relative(repoRoot, recordPath);
74
+ if (
75
+ recordRelative === '' ||
76
+ recordRelative === '..' ||
77
+ recordRelative.startsWith(`..${sep}`) ||
78
+ isAbsolute(recordRelative)
79
+ ) {
80
+ fail('record path is outside the repository root.');
81
+ }
82
+ const gitRecordPath = recordRelative.split(sep).join('/');
83
+ if (basename(gitRecordPath, extname(gitRecordPath)) !== projectName) {
84
+ fail('record filename must match the project name.');
85
+ }
86
+ if (!gitSucceeds(repoRoot, ['merge-base', '--is-ancestor', commit, 'HEAD'])) {
87
+ fail('receipt commit must be an ancestor of the current repository HEAD.');
88
+ }
89
+ const changedPaths = git(repoRoot, [
90
+ 'diff-tree',
91
+ '--root',
92
+ '--no-commit-id',
93
+ '--name-only',
94
+ '-r',
95
+ '--format=',
96
+ commit,
97
+ ])
98
+ .split('\n')
99
+ .filter(Boolean);
100
+ if (changedPaths.length !== 1 || changedPaths[0] !== gitRecordPath) {
101
+ fail('receipt commit must change exactly the synced discovery record path.');
102
+ }
103
+ const expectedSubject = `chore(oat): complete synced project ${projectName}`;
104
+ const subject = git(repoRoot, ['show', '-s', '--format=%s', commit]);
105
+ if (subject !== expectedSubject) {
106
+ fail(`commit subject must be "${expectedSubject}".`);
107
+ }
108
+
109
+ let committedRecordContents;
110
+ let record;
111
+ try {
112
+ committedRecordContents = gitRaw(repoRoot, [
113
+ 'show',
114
+ `${commit}:${gitRecordPath}`,
115
+ ]);
116
+ record = JSON.parse(committedRecordContents);
117
+ } catch (error) {
118
+ fail(
119
+ `committed record is not valid JSON: ${error instanceof Error ? error.message : String(error)}`,
120
+ );
121
+ }
122
+ if (readFileSync(recordPath, 'utf8') !== committedRecordContents) {
123
+ fail('working-tree record content must exactly match the receipt commit.');
124
+ }
125
+ const expectedKeys = new Set([
126
+ 'archiveSnapshot',
127
+ 'completedAt',
128
+ 'createdAt',
129
+ 'ref',
130
+ 'remote',
131
+ 'schemaVersion',
132
+ 'scope',
133
+ 'slug',
134
+ 'status',
135
+ ]);
136
+ if (
137
+ !record ||
138
+ typeof record !== 'object' ||
139
+ Array.isArray(record) ||
140
+ Object.keys(record).some((key) => !expectedKeys.has(key)) ||
141
+ record.schemaVersion !== 1 ||
142
+ record.slug !== projectName ||
143
+ record.scope !== 'synced' ||
144
+ record.ref !== `refs/oat/projects/${projectName}` ||
145
+ record.remote !== 'origin' ||
146
+ record.status !== 'complete' ||
147
+ typeof record.createdAt !== 'string' ||
148
+ Number.isNaN(Date.parse(record.createdAt)) ||
149
+ typeof record.completedAt !== 'string' ||
150
+ Number.isNaN(Date.parse(record.completedAt)) ||
151
+ (record.archiveSnapshot !== undefined &&
152
+ (typeof record.archiveSnapshot !== 'string' ||
153
+ record.archiveSnapshot.length === 0))
154
+ ) {
155
+ fail(
156
+ 'committed record must be a complete synced record with the exact project identity and lifecycle content.',
157
+ );
158
+ }
159
+
160
+ process.stdout.write(`${commit}\n`);
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-design
3
- version: 2.3.0
3
+ version: 2.3.1
4
4
  description: Use when discovery is complete and implementation-ready decisions are needed. Runs a collaborative, selective collaborative, or draft-and-review design flow, confirms requirements and produces both `spec.md` and `design.md`, and commits artifacts before the user-review gate.
5
5
  disable-model-invocation: true
6
6
  user-invocable: true
@@ -321,8 +321,14 @@ oat_last_updated: { today }
321
321
  Commit separately (keeps history clean; lets reviewers fetch spec independently):
322
322
 
323
323
  ```bash
324
- git add "$PROJECT_PATH/spec.md"
325
- git commit -m "docs: confirm requirements for {project-name}"
324
+ PROJECT_SCOPE=$(oat project scope "$PROJECT_PATH" --format value) || { echo "oat: cannot resolve project scope for $PROJECT_PATH; refusing to commit artifacts" >&2; exit 1; }
325
+ # fail closed: never fall back to branch bookkeeping when scope resolution fails
326
+ if [ "$PROJECT_SCOPE" = "synced" ]; then
327
+ oat project push "$PROJECT_PATH" --message "docs: confirm requirements for {project-name}" || { echo "oat: project push failed; run oat project pull, resolve the reported state, and retry" >&2; exit 1; }
328
+ else
329
+ git add "$PROJECT_PATH/spec.md"
330
+ git commit -m "docs: confirm requirements for {project-name}"
331
+ fi
326
332
  ```
327
333
 
328
334
  ### Step 2.5: Approach Reaffirmation (one divergent moment)
@@ -573,8 +579,14 @@ Even when no HiLL checkpoint is configured, the artifact is committed — consis
573
579
  # oat_ready_for: null
574
580
  # oat_last_updated: {today}
575
581
 
576
- git add "$PROJECT_PATH/spec.md" "$PROJECT_PATH/design.md" "$PROJECT_PATH/state.md"
577
- git diff --cached --quiet || git commit -m "docs: draft design for {project-name} (awaiting review)"
582
+ PROJECT_SCOPE=$(oat project scope "$PROJECT_PATH" --format value) || { echo "oat: cannot resolve project scope for $PROJECT_PATH; refusing to commit artifacts" >&2; exit 1; }
583
+ # fail closed: never fall back to branch bookkeeping when scope resolution fails
584
+ if [ "$PROJECT_SCOPE" = "synced" ]; then
585
+ oat project push "$PROJECT_PATH" --message "docs: draft design for {project-name} (awaiting review)" || { echo "oat: project push failed; run oat project pull, resolve the reported state, and retry" >&2; exit 1; }
586
+ else
587
+ git add "$PROJECT_PATH/spec.md" "$PROJECT_PATH/design.md" "$PROJECT_PATH/state.md"
588
+ git diff --cached --quiet || git commit -m "docs: draft design for {project-name} (awaiting review)"
589
+ fi
578
590
  ```
579
591
 
580
592
  **Step 6b: Read state.md frontmatter**
@@ -610,8 +622,14 @@ Wait for user response:
610
622
  - Approval → continue to Step 7.
611
623
  - Change requests → revise the relevant section(s), re-run Step 5
612
624
  (Self-Review), then MAKE A NEW COMMIT:
613
- git add "$PROJECT_PATH/spec.md" "$PROJECT_PATH/design.md"
614
- git commit -m "docs: revise design after user review feedback"
625
+ PROJECT_SCOPE=$(oat project scope "$PROJECT_PATH" --format value) || { echo "oat: cannot resolve project scope for $PROJECT_PATH; refusing to commit artifacts" >&2; exit 1; }
626
+ # fail closed: never fall back to branch bookkeeping when scope resolution fails
627
+ if [ "$PROJECT_SCOPE" = "synced" ]; then
628
+ oat project push "$PROJECT_PATH" --message "docs: revise design after user review feedback" || { echo "oat: project push failed; run oat project pull, resolve the reported state, and retry" >&2; exit 1; }
629
+ else
630
+ git add "$PROJECT_PATH/spec.md" "$PROJECT_PATH/design.md"
631
+ git commit -m "docs: revise design after user review feedback"
632
+ fi
615
633
  Re-present this prompt.
616
634
  - If user does not approve yet (wants to pause without explicit change
617
635
  requests): keep design frontmatter as oat_status: in_progress /
@@ -759,8 +777,14 @@ Reach this commit step only after the configured gate passes or resolves
759
777
  according to its `onFailure` policy.
760
778
 
761
779
  ```bash
762
- git add "$PROJECT_PATH/design.md" "$PROJECT_PATH/state.md"
763
- git diff --cached --quiet || git commit -m "chore(oat): mark design complete for {project-name}"
780
+ PROJECT_SCOPE=$(oat project scope "$PROJECT_PATH" --format value) || { echo "oat: cannot resolve project scope for $PROJECT_PATH; refusing to commit artifacts" >&2; exit 1; }
781
+ # fail closed: never fall back to branch bookkeeping when scope resolution fails
782
+ if [ "$PROJECT_SCOPE" = "synced" ]; then
783
+ oat project push "$PROJECT_PATH" --message "chore(oat): mark design complete for {project-name}" || { echo "oat: project push failed; run oat project pull, resolve the reported state, and retry" >&2; exit 1; }
784
+ else
785
+ git add "$PROJECT_PATH/design.md" "$PROJECT_PATH/state.md"
786
+ git diff --cached --quiet || git commit -m "chore(oat): mark design complete for {project-name}"
787
+ fi
764
788
  ```
765
789
 
766
790
  ### Step 9: Output Summary
@@ -1,6 +1,6 @@
1
1
  ---
2
2
  name: oat-project-discover
3
- version: 2.2.0
3
+ version: 2.2.1
4
4
  description: Use when the user explicitly asks to continue discovery for an active spec-driven OAT project — e.g. "continue discovery", "run discovery", or confirms a previously offered discovery step. Do NOT auto-invoke for new ideas or quick-mode projects. Gathers requirements and context before spec/design.
5
5
  disable-model-invocation: false
6
6
  user-invocable: true
@@ -549,14 +549,27 @@ according to its `onFailure` policy.
549
549
  During implementation of OAT itself, use standard commit format.
550
550
 
551
551
  ```bash
552
- git add "$PROJECT_PATH/"
553
- git commit -m "docs: complete discovery for {project-name}
552
+ PROJECT_SCOPE=$(oat project scope "$PROJECT_PATH" --format value) || { echo "oat: cannot resolve project scope for $PROJECT_PATH; refusing to commit artifacts" >&2; exit 1; }
553
+ # fail closed: never fall back to branch bookkeeping when scope resolution fails
554
+ if [ "$PROJECT_SCOPE" = "synced" ]; then
555
+ oat project push "$PROJECT_PATH" --message "docs: complete discovery for {project-name}
556
+
557
+ Key decisions:
558
+ - {Decision 1}
559
+ - {Decision 2}
560
+
561
+ Ready for design phase" || { echo "oat: project push failed; run oat project pull, resolve the reported state, and retry" >&2; exit 1; }
562
+ else
563
+ PROJECT_OUTPUT_PATHS=("$PROJECT_PATH/discovery.md" "$PROJECT_PATH/state.md")
564
+ git add -- "${PROJECT_OUTPUT_PATHS[@]}"
565
+ git commit -m "docs: complete discovery for {project-name}
554
566
 
555
567
  Key decisions:
556
568
  - {Decision 1}
557
569
  - {Decision 2}
558
570
 
559
571
  Ready for design phase"
572
+ fi
560
573
  ```
561
574
 
562
575
  ### Step 16: Output Summary
@@ -1,11 +1,11 @@
1
1
  ---
2
2
  name: oat-project-document
3
- version: 1.8.0
3
+ version: 1.8.1
4
4
  description: Use when the user requests or confirms documenting an active OAT project — e.g. "document the project", "update the docs", "run oat-project-document", or confirms a previously offered documentation run. Do NOT auto-invoke when implementation completes. Analyzes project artifacts, presents a documentation delta plan, and applies approved changes.
5
5
  argument-hint: '[project-path] [--auto]'
6
6
  disable-model-invocation: false
7
7
  user-invocable: true
8
- allowed-tools: Read, Write, Edit, Bash(git:*), Bash(oat tools:*), Glob, Grep, AskUserQuestion, Skill
8
+ allowed-tools: Read, Write, Edit, Bash(git:*), Bash(jq:*), Bash(oat pjm:*), Bash(oat project push:*), Bash(oat project scope:*), Bash(oat tools:*), Glob, Grep, AskUserQuestion, Skill
9
9
  ---
10
10
 
11
11
  # Project Documentation Sync
@@ -524,8 +524,14 @@ Update `$PROJECT_PATH/state.md` frontmatter based on apply outcome:
524
524
  - If `$ALL_SUCCEEDED` is false: do **not** set `oat_docs_updated: complete` — leave the field as `null` so the skill can be re-run. Still set `oat_project_state_updated: "{ISO 8601 UTC timestamp}"`. Surface the failures clearly in the summary report (Step 8d) so the user knows which updates failed and why.
525
525
 
526
526
  ```bash
527
- git add "$PROJECT_PATH/state.md"
528
- git diff --cached --quiet || git commit -m "chore({project-name}): mark docs updated"
527
+ PROJECT_SCOPE=$(oat project scope "$PROJECT_PATH" --format value) || { echo "oat: cannot resolve project scope for $PROJECT_PATH; refusing to commit artifacts" >&2; exit 1; }
528
+ # fail closed: never fall back to branch bookkeeping when scope resolution fails
529
+ if [ "$PROJECT_SCOPE" = "synced" ]; then
530
+ oat project push "$PROJECT_PATH" --message "chore({project-name}): mark docs updated" || { echo "oat: project push failed; run oat project pull, resolve the reported state, and retry" >&2; exit 1; }
531
+ else
532
+ git add "$PROJECT_PATH/state.md"
533
+ git diff --cached --quiet || git commit -m "chore({project-name}): mark docs updated"
534
+ fi
529
535
  ```
530
536
 
531
537
  **8c. Handle edge cases:**