@open-agent-toolkit/cli 0.2.41 → 0.2.45

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 (204) 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/quickstart.md +9 -0
  5. package/assets/docs/reference/cli-reference.md +56 -1
  6. package/assets/docs/reference/file-locations.md +18 -1
  7. package/assets/docs/reference/oat-directory-structure.md +20 -4
  8. package/assets/docs/workflows/projects/artifacts.md +27 -1
  9. package/assets/docs/workflows/projects/implementation-execution.md +22 -0
  10. package/assets/docs/workflows/projects/index.md +6 -0
  11. package/assets/docs/workflows/projects/lifecycle.md +19 -5
  12. package/assets/docs/workflows/projects/picking-up-projects.md +75 -0
  13. package/assets/docs/workflows/projects/pr-flow.md +22 -1
  14. package/assets/docs/workflows/projects/reviewing-oat-prs.md +60 -0
  15. package/assets/public-package-versions.json +4 -4
  16. package/assets/skills/oat-brainstorm/SKILL.md +135 -32
  17. package/assets/skills/oat-brainstorm/references/destinations.md +9 -6
  18. package/assets/skills/oat-cursor-cloud-projects/SKILL.md +11 -1
  19. package/assets/skills/oat-doctor/SKILL.md +8 -1
  20. package/assets/skills/oat-project-autonomous/SKILL.md +45 -1
  21. package/assets/skills/oat-project-autonomous/references/gate-inventory.md +8 -8
  22. package/assets/skills/oat-project-capture/SKILL.md +29 -9
  23. package/assets/skills/oat-project-complete/SKILL.md +610 -38
  24. package/assets/skills/oat-project-complete/scripts/parse-completion-retry-fields.mjs +265 -0
  25. package/assets/skills/oat-project-complete/scripts/recover-completion-receipts.mjs +764 -0
  26. package/assets/skills/oat-project-complete/scripts/resolve-completion-retry.mjs +134 -0
  27. package/assets/skills/oat-project-complete/scripts/validate-nonarchive-lifecycle-receipt.mjs +160 -0
  28. package/assets/skills/oat-project-design/SKILL.md +33 -9
  29. package/assets/skills/oat-project-discover/SKILL.md +16 -3
  30. package/assets/skills/oat-project-document/SKILL.md +10 -4
  31. package/assets/skills/oat-project-document/references/docs/autonomy-contract.md +8 -8
  32. package/assets/skills/oat-project-implement/SKILL.md +14 -3
  33. package/assets/skills/oat-project-implement/references/completion-and-closeout.md +18 -6
  34. package/assets/skills/oat-project-implement/references/docs/autonomy-contract.md +8 -8
  35. package/assets/skills/oat-project-implement/references/phase-execution.md +9 -3
  36. package/assets/skills/oat-project-implement/references/plan-and-resume.md +3 -0
  37. package/assets/skills/oat-project-import-plan/SKILL.md +15 -9
  38. package/assets/skills/oat-project-new/SKILL.md +7 -5
  39. package/assets/skills/oat-project-next/SKILL.md +32 -10
  40. package/assets/skills/oat-project-plan/SKILL.md +18 -3
  41. package/assets/skills/oat-project-pr-final/SKILL.md +23 -2
  42. package/assets/skills/oat-project-pr-final/references/docs/autonomy-contract.md +8 -8
  43. package/assets/skills/oat-project-pr-progress/SKILL.md +23 -2
  44. package/assets/skills/oat-project-progress/SKILL.md +23 -9
  45. package/assets/skills/oat-project-promote-spec-driven/SKILL.md +20 -2
  46. package/assets/skills/oat-project-quick-start/SKILL.md +48 -18
  47. package/assets/skills/oat-project-quick-start/references/docs/autonomy-contract.md +8 -8
  48. package/assets/skills/oat-project-reconcile/SKILL.md +14 -10
  49. package/assets/skills/oat-project-retro/SKILL.md +3 -3
  50. package/assets/skills/oat-project-retro/references/apply-procedure.md +102 -6
  51. package/assets/skills/oat-project-retro-file/SKILL.md +57 -6
  52. package/assets/skills/oat-project-review-provide/SKILL.md +45 -4
  53. package/assets/skills/oat-project-review-receive/SKILL.md +16 -7
  54. package/assets/skills/oat-project-review-receive-remote/SKILL.md +9 -3
  55. package/assets/skills/oat-project-revise/SKILL.md +12 -3
  56. package/assets/skills/oat-project-spec/SKILL.md +16 -3
  57. package/assets/skills/oat-project-summary/SKILL.md +113 -13
  58. package/assets/skills/oat-wave-execute/SKILL.md +34 -2
  59. package/assets/skills/oat-worktree-bootstrap/SKILL.md +13 -1
  60. package/assets/skills/oat-worktree-bootstrap-auto/SKILL.md +13 -1
  61. package/dist/commands/config/index.d.ts +1 -0
  62. package/dist/commands/config/index.d.ts.map +1 -1
  63. package/dist/commands/config/index.js +30 -2
  64. package/dist/commands/doctor/index.d.ts +2 -0
  65. package/dist/commands/doctor/index.d.ts.map +1 -1
  66. package/dist/commands/doctor/index.js +27 -3
  67. package/dist/commands/doctor/synced-projects.d.ts +12 -0
  68. package/dist/commands/doctor/synced-projects.d.ts.map +1 -0
  69. package/dist/commands/doctor/synced-projects.js +208 -0
  70. package/dist/commands/init/gitattributes.d.ts +4 -0
  71. package/dist/commands/init/gitattributes.d.ts.map +1 -0
  72. package/dist/commands/init/gitattributes.js +12 -0
  73. package/dist/commands/init/gitignore.d.ts +8 -1
  74. package/dist/commands/init/gitignore.d.ts.map +1 -1
  75. package/dist/commands/init/gitignore.js +146 -41
  76. package/dist/commands/init/index.d.ts +2 -0
  77. package/dist/commands/init/index.d.ts.map +1 -1
  78. package/dist/commands/init/index.js +3 -0
  79. package/dist/commands/init/managed-block.d.ts +10 -0
  80. package/dist/commands/init/managed-block.d.ts.map +1 -0
  81. package/dist/commands/init/managed-block.js +40 -0
  82. package/dist/commands/init/tools/workflows/install-workflows.js +1 -1
  83. package/dist/commands/local/index.d.ts.map +1 -1
  84. package/dist/commands/local/index.js +5 -1
  85. package/dist/commands/local/sync.d.ts +4 -0
  86. package/dist/commands/local/sync.d.ts.map +1 -1
  87. package/dist/commands/local/sync.js +123 -2
  88. package/dist/commands/pjm/adoption.d.ts +2 -0
  89. package/dist/commands/pjm/adoption.d.ts.map +1 -1
  90. package/dist/commands/pjm/adoption.js +1 -1
  91. package/dist/commands/project/archive/archive-utils.d.ts +24 -0
  92. package/dist/commands/project/archive/archive-utils.d.ts.map +1 -1
  93. package/dist/commands/project/archive/archive-utils.js +349 -22
  94. package/dist/commands/project/archive/index.d.ts.map +1 -1
  95. package/dist/commands/project/archive/index.js +1 -0
  96. package/dist/commands/project/archive/push-runner.d.ts +5 -1
  97. package/dist/commands/project/archive/push-runner.d.ts.map +1 -1
  98. package/dist/commands/project/archive/push-runner.js +33 -4
  99. package/dist/commands/project/complete-state/index.d.ts.map +1 -1
  100. package/dist/commands/project/complete-state/index.js +3 -1
  101. package/dist/commands/project/index.d.ts.map +1 -1
  102. package/dist/commands/project/index.js +12 -0
  103. package/dist/commands/project/links/compute.d.ts +9 -0
  104. package/dist/commands/project/links/compute.d.ts.map +1 -0
  105. package/dist/commands/project/links/compute.js +27 -0
  106. package/dist/commands/project/links/index.d.ts +17 -0
  107. package/dist/commands/project/links/index.d.ts.map +1 -0
  108. package/dist/commands/project/links/index.js +72 -0
  109. package/dist/commands/project/links/refresh.d.ts +26 -0
  110. package/dist/commands/project/links/refresh.d.ts.map +1 -0
  111. package/dist/commands/project/links/refresh.js +92 -0
  112. package/dist/commands/project/links/render.d.ts +24 -0
  113. package/dist/commands/project/links/render.d.ts.map +1 -0
  114. package/dist/commands/project/links/render.js +68 -0
  115. package/dist/commands/project/list.d.ts +5 -0
  116. package/dist/commands/project/list.d.ts.map +1 -1
  117. package/dist/commands/project/list.js +182 -9
  118. package/dist/commands/project/migrate/index.d.ts +22 -0
  119. package/dist/commands/project/migrate/index.d.ts.map +1 -0
  120. package/dist/commands/project/migrate/index.js +79 -0
  121. package/dist/commands/project/new/index.d.ts +2 -0
  122. package/dist/commands/project/new/index.d.ts.map +1 -1
  123. package/dist/commands/project/new/index.js +14 -2
  124. package/dist/commands/project/new/scaffold.d.ts +22 -1
  125. package/dist/commands/project/new/scaffold.d.ts.map +1 -1
  126. package/dist/commands/project/new/scaffold.js +287 -69
  127. package/dist/commands/project/open/index.d.ts +16 -0
  128. package/dist/commands/project/open/index.d.ts.map +1 -1
  129. package/dist/commands/project/open/index.js +151 -19
  130. package/dist/commands/project/pause/index.d.ts +8 -0
  131. package/dist/commands/project/pause/index.d.ts.map +1 -1
  132. package/dist/commands/project/pause/index.js +129 -19
  133. package/dist/commands/project/prune/index.d.ts +21 -0
  134. package/dist/commands/project/prune/index.d.ts.map +1 -0
  135. package/dist/commands/project/prune/index.js +95 -0
  136. package/dist/commands/project/pull/index.d.ts +28 -0
  137. package/dist/commands/project/pull/index.d.ts.map +1 -0
  138. package/dist/commands/project/pull/index.js +157 -0
  139. package/dist/commands/project/push/index.d.ts +22 -0
  140. package/dist/commands/project/push/index.d.ts.map +1 -0
  141. package/dist/commands/project/push/index.js +100 -0
  142. package/dist/commands/project/scope/index.d.ts +17 -0
  143. package/dist/commands/project/scope/index.d.ts.map +1 -0
  144. package/dist/commands/project/scope/index.js +107 -0
  145. package/dist/commands/project/split/run.d.ts +4 -0
  146. package/dist/commands/project/split/run.d.ts.map +1 -1
  147. package/dist/commands/project/split/run.js +48 -10
  148. package/dist/commands/project/sync/git.d.ts +18 -0
  149. package/dist/commands/project/sync/git.d.ts.map +1 -0
  150. package/dist/commands/project/sync/git.js +60 -0
  151. package/dist/commands/project/sync/record.d.ts +22 -0
  152. package/dist/commands/project/sync/record.d.ts.map +1 -0
  153. package/dist/commands/project/sync/record.js +133 -0
  154. package/dist/commands/project/sync/ref-sync.d.ts +120 -0
  155. package/dist/commands/project/sync/ref-sync.d.ts.map +1 -0
  156. package/dist/commands/project/sync/ref-sync.js +962 -0
  157. package/dist/commands/project/sync/resolve-target.d.ts +27 -0
  158. package/dist/commands/project/sync/resolve-target.d.ts.map +1 -0
  159. package/dist/commands/project/sync/resolve-target.js +159 -0
  160. package/dist/commands/shared/oat-paths.d.ts +4 -1
  161. package/dist/commands/shared/oat-paths.d.ts.map +1 -1
  162. package/dist/commands/shared/oat-paths.js +2 -2
  163. package/dist/commands/shared/project-scope.d.ts +23 -0
  164. package/dist/commands/shared/project-scope.d.ts.map +1 -0
  165. package/dist/commands/shared/project-scope.js +106 -0
  166. package/dist/commands/tools/migrate/index.js +1 -1
  167. package/dist/commands/tools/shared/pack-inventory.d.ts.map +1 -1
  168. package/dist/commands/tools/shared/pack-inventory.js +11 -0
  169. package/dist/commands/tools/shared/pack-lifecycle.js +1 -1
  170. package/dist/commands/tools/shared/pack-reconcile.d.ts.map +1 -1
  171. package/dist/commands/tools/shared/pack-reconcile.js +4 -1
  172. package/dist/commands/tools/update/index.d.ts.map +1 -1
  173. package/dist/commands/tools/update/index.js +20 -10
  174. package/dist/commands/tools/update/update-tools.d.ts +2 -0
  175. package/dist/commands/tools/update/update-tools.d.ts.map +1 -1
  176. package/dist/config/oat-config.d.ts +6 -3
  177. package/dist/config/oat-config.d.ts.map +1 -1
  178. package/dist/config/oat-config.js +41 -7
  179. package/dist/config/resolve.d.ts.map +1 -1
  180. package/dist/config/resolve.js +2 -1
  181. package/dist/fs/io.d.ts +2 -1
  182. package/dist/fs/io.d.ts.map +1 -1
  183. package/dist/fs/io.js +5 -2
  184. package/dist/projects/split/finalize.d.ts.map +1 -1
  185. package/dist/projects/split/finalize.js +55 -2
  186. package/dist/projects/split/resume.d.ts +3 -0
  187. package/dist/projects/split/resume.d.ts.map +1 -1
  188. package/dist/projects/split/resume.js +34 -7
  189. package/dist/projects/split/seed-children.d.ts.map +1 -1
  190. package/dist/projects/split/seed-children.js +6 -0
  191. package/dist/projects/split/write-parent.d.ts +7 -0
  192. package/dist/projects/split/write-parent.d.ts.map +1 -1
  193. package/dist/projects/split/write-parent.js +7 -4
  194. package/dist/release/public-package-contract.d.ts.map +1 -1
  195. package/dist/release/public-package-contract.js +1 -0
  196. package/dist/validation/skills.d.ts.map +1 -1
  197. package/dist/validation/skills.js +434 -0
  198. package/package.json +4 -4
  199. package/dist/__tests__/skills/split-flow-fixtures.d.ts +0 -50
  200. package/dist/__tests__/skills/split-flow-fixtures.d.ts.map +0 -1
  201. package/dist/__tests__/skills/split-flow-fixtures.js +0 -161
  202. package/dist/commands/__tests__/helpers.d.ts +0 -12
  203. package/dist/commands/__tests__/helpers.d.ts.map +0 -1
  204. package/dist/commands/__tests__/helpers.js +0 -36
@@ -3,11 +3,17 @@ import { createProjectArchiveCommand } from './archive/index.js';
3
3
  import { createProjectCompleteDiscoveryCommand } from './complete-discovery/index.js';
4
4
  import { createProjectCompleteStateCommand } from './complete-state/index.js';
5
5
  import { createProjectDispatchCeilingCommand } from './dispatch-ceiling/index.js';
6
+ import { createProjectLinksCommand } from './links/index.js';
6
7
  import { createProjectListCommand } from './list.js';
7
8
  import { createProjectLogCommand } from './log/index.js';
9
+ import { createProjectMigrateCommand } from './migrate/index.js';
8
10
  import { createProjectNewCommand } from './new/index.js';
9
11
  import { createProjectOpenCommand } from './open/index.js';
10
12
  import { createProjectPauseCommand } from './pause/index.js';
13
+ import { createProjectPruneCommand } from './prune/index.js';
14
+ import { createProjectPullCommand } from './pull/index.js';
15
+ import { createProjectPushCommand } from './push/index.js';
16
+ import { createProjectScopeCommand } from './scope/index.js';
11
17
  import { createProjectSetModeCommand } from './set-mode/index.js';
12
18
  import { createProjectSplitCommand } from './split/index.js';
13
19
  import { createProjectStatusCommand } from './status.js';
@@ -20,10 +26,16 @@ export function createProjectCommand() {
20
26
  .addCommand(createProjectCompleteStateCommand())
21
27
  .addCommand(createProjectDispatchCeilingCommand())
22
28
  .addCommand(createProjectListCommand())
29
+ .addCommand(createProjectLinksCommand())
23
30
  .addCommand(createProjectLogCommand())
31
+ .addCommand(createProjectMigrateCommand())
24
32
  .addCommand(createProjectNewCommand())
25
33
  .addCommand(createProjectOpenCommand())
26
34
  .addCommand(createProjectPauseCommand())
35
+ .addCommand(createProjectPruneCommand())
36
+ .addCommand(createProjectPushCommand())
37
+ .addCommand(createProjectPullCommand())
38
+ .addCommand(createProjectScopeCommand())
27
39
  .addCommand(createProjectSetModeCommand())
28
40
  .addCommand(createProjectSplitCommand())
29
41
  .addCommand(createProjectStatusCommand())
@@ -0,0 +1,9 @@
1
+ import type { GitRunner } from '../../project/sync/git.js';
2
+ import type { SyncTarget } from '../../project/sync/ref-sync.js';
3
+ import { type LinksInput } from './render.js';
4
+ export interface ComputeLinksOptions {
5
+ durableSummaryPath?: string;
6
+ now: Date;
7
+ }
8
+ export declare function computeLinksInput(target: SyncTarget, git: GitRunner, options: ComputeLinksOptions): Promise<LinksInput>;
9
+ //# sourceMappingURL=compute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/links/compute.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAC5D,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAElE,OAAO,EAGL,KAAK,UAAU,EAChB,MAAM,UAAU,CAAC;AAElB,MAAM,WAAW,mBAAmB;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,GAAG,EAAE,IAAI,CAAC;CACX;AAED,wBAAsB,iBAAiB,CACrC,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,SAAS,EACd,OAAO,EAAE,mBAAmB,GAC3B,OAAO,CAAC,UAAU,CAAC,CA6BrB"}
@@ -0,0 +1,27 @@
1
+ import { LINKABLE_ARTIFACTS, } from './render.js';
2
+ export async function computeLinksInput(target, git, options) {
3
+ await git.run(['fetch', target.remote, `+${target.ref}:${target.ref}`], {
4
+ cwd: target.repoRoot,
5
+ });
6
+ const [sha, tree, origin] = await Promise.all([
7
+ git.run(['rev-parse', target.ref], { cwd: target.repoRoot }),
8
+ git.run(['ls-tree', '--name-only', target.ref], { cwd: target.repoRoot }),
9
+ git.run(['remote', 'get-url', target.remote], { cwd: target.repoRoot }),
10
+ ]);
11
+ const treeNames = new Set(tree.stdout
12
+ .split('\n')
13
+ .map((line) => line.trim())
14
+ .filter(Boolean));
15
+ const present = LINKABLE_ARTIFACTS.filter((artifact) => treeNames.has(artifact));
16
+ return {
17
+ slug: target.slug,
18
+ sha: sha.stdout,
19
+ ref: target.ref,
20
+ originUrl: origin.stdout,
21
+ present,
22
+ ...(options.durableSummaryPath
23
+ ? { durableSummaryPath: options.durableSummaryPath }
24
+ : {}),
25
+ pinnedAt: options.now.toISOString().slice(0, 10),
26
+ };
27
+ }
@@ -0,0 +1,17 @@
1
+ import { type CommandContext, type GlobalOptions } from '../../../app/command-context.js';
2
+ import { type GitRunner } from '../../project/sync/git.js';
3
+ import { resolveSyncedTarget } from '../../project/sync/resolve-target.js';
4
+ import { Command } from 'commander';
5
+ import { computeLinksInput } from './compute.js';
6
+ interface ProjectLinksDependencies {
7
+ buildCommandContext: (options: GlobalOptions) => CommandContext;
8
+ resolveProjectRoot: (cwd: string) => Promise<string>;
9
+ resolveSyncedTarget: typeof resolveSyncedTarget;
10
+ computeLinksInput: typeof computeLinksInput;
11
+ gitRunner: GitRunner;
12
+ processEnv: NodeJS.ProcessEnv;
13
+ now: () => Date;
14
+ }
15
+ export declare function createProjectLinksCommand(overrides?: Partial<ProjectLinksDependencies>): Command;
16
+ export {};
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/links/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,uCAAuC,CAAC;AAI5E,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAQ9C,UAAU,wBAAwB;IAChC,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,mBAAmB,EAAE,OAAO,mBAAmB,CAAC;IAChD,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,SAAS,EAAE,SAAS,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;IAC9B,GAAG,EAAE,MAAM,IAAI,CAAC;CACjB;AA4ED,wBAAgB,yBAAyB,CACvC,SAAS,GAAE,OAAO,CAAC,wBAAwB,CAAM,GAChD,OAAO,CAsBT"}
@@ -0,0 +1,72 @@
1
+ import { isAbsolute, relative, resolve, sep } from 'node:path';
2
+ import { buildCommandContext, } from '../../../app/command-context.js';
3
+ import { defaultGitRunner } from '../../project/sync/git.js';
4
+ import { resolveSyncedTarget } from '../../project/sync/resolve-target.js';
5
+ import { readGlobalOptions } from '../../shared/shared.utils.js';
6
+ import { CliError } from '../../../errors/cli-error.js';
7
+ import { resolveProjectRoot } from '../../../fs/paths.js';
8
+ import { Command } from 'commander';
9
+ import { computeLinksInput } from './compute.js';
10
+ import { renderLinksBlock } from './render.js';
11
+ const DEFAULT_DEPENDENCIES = {
12
+ buildCommandContext,
13
+ resolveProjectRoot,
14
+ resolveSyncedTarget,
15
+ computeLinksInput,
16
+ gitRunner: defaultGitRunner,
17
+ processEnv: process.env,
18
+ now: () => new Date(),
19
+ };
20
+ function normalizeDurableSummaryPath(repoRoot, durableSummaryPath) {
21
+ if (!durableSummaryPath)
22
+ return undefined;
23
+ const absolutePath = resolve(repoRoot, durableSummaryPath);
24
+ const repositoryRelative = relative(repoRoot, absolutePath);
25
+ if (repositoryRelative === '' ||
26
+ repositoryRelative === '..' ||
27
+ repositoryRelative.startsWith(`..${sep}`) ||
28
+ isAbsolute(repositoryRelative)) {
29
+ throw new CliError(`Durable summary path must be a file contained in the repository: ${durableSummaryPath}`, 1);
30
+ }
31
+ return repositoryRelative.split(sep).join('/');
32
+ }
33
+ async function runLinks(context, pathOrSlug, options, dependencies) {
34
+ try {
35
+ const repoRoot = await dependencies.resolveProjectRoot(context.cwd);
36
+ const target = await dependencies.resolveSyncedTarget({ repoRoot, env: dependencies.processEnv }, pathOrSlug, {}, { allowMissingCheckout: true });
37
+ const input = await dependencies.computeLinksInput(target, dependencies.gitRunner, {
38
+ durableSummaryPath: normalizeDurableSummaryPath(repoRoot, options.durableSummary),
39
+ now: dependencies.now(),
40
+ });
41
+ const markdown = renderLinksBlock(input);
42
+ if (context.json || options.format === 'json') {
43
+ context.logger.json({ ...input, markdown });
44
+ }
45
+ else {
46
+ context.logger.info(markdown);
47
+ }
48
+ process.exitCode = 0;
49
+ }
50
+ catch (error) {
51
+ const message = error instanceof Error ? error.message : String(error);
52
+ if (context.json || options.format === 'json') {
53
+ context.logger.json({ status: 'error', message });
54
+ }
55
+ else {
56
+ context.logger.error(message);
57
+ }
58
+ process.exitCode = error instanceof CliError ? error.exitCode : 2;
59
+ }
60
+ }
61
+ export function createProjectLinksCommand(overrides = {}) {
62
+ const dependencies = { ...DEFAULT_DEPENDENCIES, ...overrides };
63
+ return new Command('links')
64
+ .description('Render pinned reviewer links for a synced OAT project')
65
+ .argument('[project-path|slug]', 'Synced project path or slug')
66
+ .option('--format <format>', 'Output format (markdown or json)', 'markdown')
67
+ .option('--durable-summary <path>', 'Repository-relative durable summary path')
68
+ .action(async (pathOrSlug, options, command) => {
69
+ const context = dependencies.buildCommandContext(readGlobalOptions(command));
70
+ await runLinks(context, pathOrSlug, options, dependencies);
71
+ });
72
+ }
@@ -0,0 +1,26 @@
1
+ import { type ExecFileException, type ExecFileOptionsWithStringEncoding } from 'node:child_process';
2
+ import { type GitRunner } from '../../project/sync/git.js';
3
+ import type { SyncTarget } from '../../project/sync/ref-sync.js';
4
+ import { computeLinksInput } from './compute.js';
5
+ export interface GhResult {
6
+ stdout: string;
7
+ stderr: string;
8
+ code: number;
9
+ missing?: boolean;
10
+ }
11
+ export interface GhRunner {
12
+ run(args: string[]): Promise<GhResult>;
13
+ }
14
+ type ExecFileImplementation = (file: string, args: readonly string[], options: ExecFileOptionsWithStringEncoding, callback: (error: ExecFileException | null, stdout: string, stderr: string) => void) => unknown;
15
+ export declare function createGhRunner(execFileImpl?: ExecFileImplementation): GhRunner;
16
+ export declare const defaultGhRunner: GhRunner;
17
+ interface RefreshDependencies {
18
+ gh: GhRunner;
19
+ git: GitRunner;
20
+ computeLinksInput: typeof computeLinksInput;
21
+ now: () => Date;
22
+ warn: (message: string) => void;
23
+ }
24
+ export declare function refreshPrLinks(target: SyncTarget, prUrl: string, overrides?: Partial<RefreshDependencies>): Promise<'refreshed' | 'skipped' | 'failed'>;
25
+ export {};
26
+ //# sourceMappingURL=refresh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"refresh.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/links/refresh.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,iBAAiB,EACtB,KAAK,iCAAiC,EACvC,MAAM,oBAAoB,CAAC;AAK5B,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iCAAiC,CAAC;AAElE,OAAO,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAC;AAG9C,MAAM,WAAW,QAAQ;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,QAAQ;IACvB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC;CACxC;AAED,KAAK,sBAAsB,GAAG,CAC5B,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,iCAAiC,EAC1C,QAAQ,EAAE,CACR,KAAK,EAAE,iBAAiB,GAAG,IAAI,EAC/B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,KACX,IAAI,KACN,OAAO,CAAC;AAEb,wBAAgB,cAAc,CAC5B,YAAY,GAAE,sBAAiC,GAC9C,QAAQ,CA2BV;AAED,eAAO,MAAM,eAAe,UAAmB,CAAC;AAEhD,UAAU,mBAAmB;IAC3B,EAAE,EAAE,QAAQ,CAAC;IACb,GAAG,EAAE,SAAS,CAAC;IACf,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,GAAG,EAAE,MAAM,IAAI,CAAC;IAChB,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAUD,wBAAsB,cAAc,CAClC,MAAM,EAAE,UAAU,EAClB,KAAK,EAAE,MAAM,EACb,SAAS,GAAE,OAAO,CAAC,mBAAmB,CAAM,GAC3C,OAAO,CAAC,WAAW,GAAG,SAAS,GAAG,QAAQ,CAAC,CA4D7C"}
@@ -0,0 +1,92 @@
1
+ import { execFile, } from 'node:child_process';
2
+ import { mkdtemp, rm, writeFile } from 'node:fs/promises';
3
+ import { tmpdir } from 'node:os';
4
+ import { join } from 'node:path';
5
+ import { defaultGitRunner } from '../../project/sync/git.js';
6
+ import { computeLinksInput } from './compute.js';
7
+ import { renderLinksBlock, replaceLinksBlock } from './render.js';
8
+ export function createGhRunner(execFileImpl = execFile) {
9
+ return {
10
+ async run(args) {
11
+ return new Promise((resolve) => {
12
+ execFileImpl('gh', args, { encoding: 'utf8' }, (error, stdout, stderr) => {
13
+ resolve({
14
+ stdout: stdout.trim(),
15
+ stderr: stderr.trim(),
16
+ code: typeof error?.code === 'number'
17
+ ? error.code
18
+ : error
19
+ ? error.code === 'ENOENT'
20
+ ? 127
21
+ : 1
22
+ : 0,
23
+ ...(error?.code === 'ENOENT' ? { missing: true } : {}),
24
+ });
25
+ });
26
+ });
27
+ },
28
+ };
29
+ }
30
+ export const defaultGhRunner = createGhRunner();
31
+ const DEFAULT_DEPENDENCIES = {
32
+ gh: defaultGhRunner,
33
+ git: defaultGitRunner,
34
+ computeLinksInput,
35
+ now: () => new Date(),
36
+ warn: (message) => process.stderr.write(`${message}\n`),
37
+ };
38
+ export async function refreshPrLinks(target, prUrl, overrides = {}) {
39
+ const dependencies = { ...DEFAULT_DEPENDENCIES, ...overrides };
40
+ const viewed = await dependencies.gh.run([
41
+ 'pr',
42
+ 'view',
43
+ prUrl,
44
+ '--json',
45
+ 'body',
46
+ ]);
47
+ if (viewed.code !== 0) {
48
+ dependencies.warn(viewed.missing
49
+ ? 'Skipping PR link refresh because the GitHub CLI is unavailable.'
50
+ : `Could not read PR body for link refresh: ${viewed.stderr || viewed.stdout || `gh exited ${viewed.code}`}`);
51
+ return viewed.missing ? 'skipped' : 'failed';
52
+ }
53
+ let body;
54
+ try {
55
+ const parsed = JSON.parse(viewed.stdout);
56
+ if (typeof parsed.body !== 'string')
57
+ throw new Error('missing body');
58
+ body = parsed.body;
59
+ }
60
+ catch {
61
+ dependencies.warn('Could not parse the PR body returned by gh.');
62
+ return 'failed';
63
+ }
64
+ const input = await dependencies.computeLinksInput(target, dependencies.git, {
65
+ now: dependencies.now(),
66
+ });
67
+ const replacement = replaceLinksBlock(body, renderLinksBlock(input));
68
+ if (replacement.malformed) {
69
+ dependencies.warn('Skipping PR link refresh because the existing OAT links markers are malformed.');
70
+ return 'skipped';
71
+ }
72
+ const tempDirectory = await mkdtemp(join(tmpdir(), 'oat-pr-body-'));
73
+ const bodyFile = join(tempDirectory, 'body.md');
74
+ try {
75
+ await writeFile(bodyFile, replacement.body, 'utf8');
76
+ const edited = await dependencies.gh.run([
77
+ 'pr',
78
+ 'edit',
79
+ prUrl,
80
+ '--body-file',
81
+ bodyFile,
82
+ ]);
83
+ if (edited.code !== 0) {
84
+ dependencies.warn(`Could not refresh PR links: ${edited.stderr || edited.stdout || `gh exited ${edited.code}`}`);
85
+ return edited.missing ? 'skipped' : 'failed';
86
+ }
87
+ return 'refreshed';
88
+ }
89
+ finally {
90
+ await rm(tempDirectory, { recursive: true, force: true });
91
+ }
92
+ }
@@ -0,0 +1,24 @@
1
+ export declare const LINKABLE_ARTIFACTS: readonly ['discovery.md', 'design.md', 'summary.md'];
2
+ export type LinkableArtifact = (typeof LINKABLE_ARTIFACTS)[number];
3
+ export declare const LINKS_START = "<!-- oat:project-links:start -->";
4
+ export declare const LINKS_END = "<!-- oat:project-links:end -->";
5
+ export interface LinksInput {
6
+ slug: string;
7
+ sha: string;
8
+ ref: string;
9
+ originUrl: string;
10
+ present: LinkableArtifact[];
11
+ durableSummaryPath?: string;
12
+ pinnedAt: string;
13
+ }
14
+ export declare function parseGitHubOrigin(url: string): {
15
+ owner: string;
16
+ repo: string;
17
+ } | null;
18
+ export declare function renderLinksBlock(input: LinksInput): string;
19
+ export declare function replaceLinksBlock(body: string, block: string): {
20
+ body: string;
21
+ replaced: boolean;
22
+ malformed: boolean;
23
+ };
24
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../../../src/commands/project/links/render.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,YAC7B,cAAc,EACd,WAAW,EACX,YAAY,CACJ,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnE,eAAO,MAAM,WAAW,qCAAqC,CAAC;AAC9D,eAAO,MAAM,SAAS,mCAAmC,CAAC;AAE1D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,EAAE,MAAM,CAAC;CAClB;AAQD,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,GACV;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAaxC;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAsB1D;AAED,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,GACZ;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,OAAO,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAmBzD"}
@@ -0,0 +1,68 @@
1
+ export const LINKABLE_ARTIFACTS = [
2
+ 'discovery.md',
3
+ 'design.md',
4
+ 'summary.md',
5
+ ];
6
+ export const LINKS_START = '<!-- oat:project-links:start -->';
7
+ export const LINKS_END = '<!-- oat:project-links:end -->';
8
+ const ARTIFACT_LABELS = {
9
+ 'discovery.md': 'Discovery',
10
+ 'design.md': 'Design',
11
+ 'summary.md': 'Summary',
12
+ };
13
+ export function parseGitHubOrigin(url) {
14
+ const scpMatch = /^git@github\.com:([^/]+)\/([^/]+?)(?:\.git)?$/.exec(url);
15
+ if (scpMatch)
16
+ return { owner: scpMatch[1], repo: scpMatch[2] };
17
+ try {
18
+ const parsed = new URL(url);
19
+ if (parsed.hostname !== 'github.com')
20
+ return null;
21
+ const parts = parsed.pathname.replace(/^\/+|\/+$/g, '').split('/');
22
+ if (parts.length !== 2 || !parts[0] || !parts[1])
23
+ return null;
24
+ return { owner: parts[0], repo: parts[1].replace(/\.git$/, '') };
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ }
30
+ export function renderLinksBlock(input) {
31
+ const shortSha = input.sha.slice(0, 7);
32
+ const lines = [
33
+ LINKS_START,
34
+ '',
35
+ `**OAT project** \`${input.slug}\` (synced) — pinned to \`${input.ref}\` @ \`${shortSha}\` (${input.pinnedAt})`,
36
+ ];
37
+ const github = parseGitHubOrigin(input.originUrl);
38
+ if (github) {
39
+ const links = LINKABLE_ARTIFACTS.filter((artifact) => input.present.includes(artifact)).map((artifact) => `[${ARTIFACT_LABELS[artifact]}](https://github.com/${github.owner}/${github.repo}/blob/${input.sha}/${artifact})`);
40
+ if (links.length > 0)
41
+ lines.push(links.join(' · '));
42
+ }
43
+ if (input.durableSummaryPath) {
44
+ lines.push(`Durable summary: \`${input.durableSummaryPath}\``);
45
+ }
46
+ lines.push('', LINKS_END);
47
+ return lines.join('\n');
48
+ }
49
+ export function replaceLinksBlock(body, block) {
50
+ const start = body.indexOf(LINKS_START);
51
+ const end = body.indexOf(LINKS_END);
52
+ if ((start === -1) !== (end === -1) || (start !== -1 && end < start)) {
53
+ return { body, replaced: false, malformed: true };
54
+ }
55
+ if (start === -1) {
56
+ const prefix = body.trimEnd();
57
+ return {
58
+ body: prefix ? `${prefix}\n\n${block}` : block,
59
+ replaced: false,
60
+ malformed: false,
61
+ };
62
+ }
63
+ return {
64
+ body: `${body.slice(0, start)}${block}${body.slice(end + LINKS_END.length)}`,
65
+ replaced: true,
66
+ malformed: false,
67
+ };
68
+ }
@@ -1,4 +1,6 @@
1
1
  import { type CommandContext, type GlobalOptions } from '../../app/command-context.js';
2
+ import { type GitRunner } from '../project/sync/git.js';
3
+ import { listSyncedRecords } from '../project/sync/record.js';
2
4
  import { type ProjectSummary } from '@open-agent-toolkit/control-plane';
3
5
  import { Command } from 'commander';
4
6
  interface ProjectListDependencies {
@@ -6,8 +8,11 @@ interface ProjectListDependencies {
6
8
  resolveProjectRoot: (cwd: string) => Promise<string>;
7
9
  resolveProjectsRoot: (repoRoot: string, env: NodeJS.ProcessEnv) => Promise<string>;
8
10
  listProjects: (projectsRoot: string) => Promise<ProjectSummary[]>;
11
+ listSyncedRecords: typeof listSyncedRecords;
12
+ directoryExists: (path: string) => Promise<boolean>;
9
13
  readProjectMetadata: (projectPath: string) => Promise<ProjectListMetadata>;
10
14
  processEnv: NodeJS.ProcessEnv;
15
+ gitRunner: GitRunner;
11
16
  }
12
17
  interface ProjectListMetadata {
13
18
  kind: string;
@@ -1 +1 @@
1
- {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/project/list.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,EAEL,KAAK,cAAc,EACpB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,UAAU,uBAAuB;IAC/B,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAClE,mBAAmB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC3E,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;CAC/B;AAED,UAAU,mBAAmB;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAwJD,wBAAgB,wBAAwB,CACtC,SAAS,GAAE,OAAO,CAAC,uBAAuB,CAAM,GAC/C,OAAO,CAkBT"}
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/project/list.ts"],"names":[],"mappings":"AAWA,OAAO,EAEL,KAAK,cAAc,EACnB,KAAK,aAAa,EACnB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,4BAA4B,CAAC;AAC9E,OAAO,EAAE,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAWlE,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,mCAAmC,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAE5C,UAAU,uBAAuB;IAC/B,mBAAmB,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,cAAc,CAAC;IAChE,kBAAkB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IACrD,mBAAmB,EAAE,CACnB,QAAQ,EAAE,MAAM,EAChB,GAAG,EAAE,MAAM,CAAC,UAAU,KACnB,OAAO,CAAC,MAAM,CAAC,CAAC;IACrB,YAAY,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAClE,iBAAiB,EAAE,OAAO,iBAAiB,CAAC;IAC5C,eAAe,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACpD,mBAAmB,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,mBAAmB,CAAC,CAAC;IAC3E,UAAU,EAAE,MAAM,CAAC,UAAU,CAAC;IAC9B,SAAS,EAAE,SAAS,CAAC;CACtB;AAED,UAAU,mBAAmB;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;CACrB;AAoXD,wBAAgB,wBAAwB,CACtC,SAAS,GAAE,OAAO,CAAC,uBAAuB,CAAM,GAC/C,OAAO,CAwBT"}