agentplane 0.3.11 → 0.3.13

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 (259) hide show
  1. package/assets/AGENTS.md +2 -2
  2. package/assets/RUNNER.md +1 -1
  3. package/assets/agents/CODER.json +4 -0
  4. package/assets/agents/CREATOR.json +1 -0
  5. package/assets/agents/DOCS.json +2 -1
  6. package/assets/agents/INTEGRATOR.json +2 -1
  7. package/assets/agents/ORCHESTRATOR.json +3 -1
  8. package/assets/agents/PLANNER.json +3 -1
  9. package/assets/agents/REVIEWER.json +1 -0
  10. package/assets/agents/TESTER.json +2 -2
  11. package/assets/agents/UPDATER.json +1 -0
  12. package/assets/agents/UPGRADER.json +1 -1
  13. package/assets/codex-plugin/assets/header.png +0 -0
  14. package/assets/codex-plugin/assets/icon.svg +1 -0
  15. package/assets/codex-plugin/assets/logo.svg +1 -0
  16. package/assets/codex-plugin/skills/agentplane/SKILL.md +35 -0
  17. package/assets/policy/governance.md +4 -2
  18. package/assets/policy/incidents.md +3 -19
  19. package/assets/policy/workflow.release.md +5 -2
  20. package/bin/agentplane.js +58 -3
  21. package/bin/stale-dist-policy.js +6 -1
  22. package/dist/.build-manifest.json +271 -161
  23. package/dist/cli/exit-codes.d.ts.map +1 -1
  24. package/dist/cli/exit-codes.js +1 -0
  25. package/dist/cli/reason-codes.d.ts +1 -1
  26. package/dist/cli/reason-codes.d.ts.map +1 -1
  27. package/dist/cli/reason-codes.js +12 -0
  28. package/dist/cli/run-cli/command-catalog/core.d.ts +1 -1
  29. package/dist/cli/run-cli/command-catalog/core.d.ts.map +1 -1
  30. package/dist/cli/run-cli/command-catalog/core.js +22 -1
  31. package/dist/cli/run-cli/command-catalog/project.d.ts +1 -1
  32. package/dist/cli/run-cli/command-catalog/project.d.ts.map +1 -1
  33. package/dist/cli/run-cli/command-catalog/project.js +21 -3
  34. package/dist/cli/run-cli/command-catalog.d.ts +1 -1
  35. package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
  36. package/dist/cli/run-cli/commands/codex.d.ts +14 -0
  37. package/dist/cli/run-cli/commands/codex.d.ts.map +1 -0
  38. package/dist/cli/run-cli/commands/codex.js +100 -0
  39. package/dist/cli/run-cli/commands/core.d.ts +1 -0
  40. package/dist/cli/run-cli/commands/core.d.ts.map +1 -1
  41. package/dist/cli/run-cli/commands/core.js +1 -0
  42. package/dist/cli/run-cli/commands/init/recipes.d.ts +9 -1
  43. package/dist/cli/run-cli/commands/init/recipes.d.ts.map +1 -1
  44. package/dist/cli/run-cli/commands/init/recipes.js +32 -22
  45. package/dist/cli/run-cli/commands/init.d.ts.map +1 -1
  46. package/dist/cli/run-cli/commands/init.js +26 -21
  47. package/dist/cli/run-cli/error-guidance.js +20 -0
  48. package/dist/cli/run-cli.test-helpers.d.ts +1 -0
  49. package/dist/cli/run-cli.test-helpers.d.ts.map +1 -1
  50. package/dist/cli/run-cli.test-helpers.js +36 -19
  51. package/dist/commands/branch/cleanup-merged.d.ts +1 -0
  52. package/dist/commands/branch/cleanup-merged.d.ts.map +1 -1
  53. package/dist/commands/branch/cleanup-merged.js +18 -9
  54. package/dist/commands/branch/work-start.d.ts.map +1 -1
  55. package/dist/commands/branch/work-start.js +82 -5
  56. package/dist/commands/codex/plugin-install.d.ts +26 -0
  57. package/dist/commands/codex/plugin-install.d.ts.map +1 -0
  58. package/dist/commands/codex/plugin-install.js +209 -0
  59. package/dist/commands/doctor/branch-pr.js +2 -2
  60. package/dist/commands/guard/impl/commands.d.ts +1 -0
  61. package/dist/commands/guard/impl/commands.d.ts.map +1 -1
  62. package/dist/commands/guard/impl/commands.js +78 -8
  63. package/dist/commands/hooks/index.d.ts +1 -1
  64. package/dist/commands/hooks/index.d.ts.map +1 -1
  65. package/dist/commands/hooks/index.js +48 -12
  66. package/dist/commands/pr/check.d.ts.map +1 -1
  67. package/dist/commands/pr/check.js +3 -0
  68. package/dist/commands/pr/integrate/cmd.d.ts.map +1 -1
  69. package/dist/commands/pr/integrate/cmd.js +103 -2
  70. package/dist/commands/pr/integrate/internal/cleanup.d.ts +1 -11
  71. package/dist/commands/pr/integrate/internal/cleanup.d.ts.map +1 -1
  72. package/dist/commands/pr/integrate/internal/cleanup.js +1 -46
  73. package/dist/commands/pr/integrate/internal/finalize.d.ts.map +1 -1
  74. package/dist/commands/pr/integrate/internal/finalize.js +3 -0
  75. package/dist/commands/pr/integrate/internal/github-protection.d.ts +5 -0
  76. package/dist/commands/pr/integrate/internal/github-protection.d.ts.map +1 -0
  77. package/dist/commands/pr/integrate/internal/github-protection.js +13 -0
  78. package/dist/commands/pr/integrate/internal/pre-integrate-bootstrap.d.ts +15 -0
  79. package/dist/commands/pr/integrate/internal/pre-integrate-bootstrap.d.ts.map +1 -0
  80. package/dist/commands/pr/integrate/internal/pre-integrate-bootstrap.js +35 -0
  81. package/dist/commands/pr/integrate/internal/prepare.d.ts +1 -0
  82. package/dist/commands/pr/integrate/internal/prepare.d.ts.map +1 -1
  83. package/dist/commands/pr/integrate/internal/prepare.js +46 -7
  84. package/dist/commands/pr/internal/auto-commit.d.ts +7 -0
  85. package/dist/commands/pr/internal/auto-commit.d.ts.map +1 -0
  86. package/dist/commands/pr/internal/auto-commit.js +69 -0
  87. package/dist/commands/pr/internal/freshness.d.ts +1 -0
  88. package/dist/commands/pr/internal/freshness.d.ts.map +1 -1
  89. package/dist/commands/pr/internal/freshness.js +2 -0
  90. package/dist/commands/pr/internal/sync.d.ts.map +1 -1
  91. package/dist/commands/pr/internal/sync.js +98 -27
  92. package/dist/commands/pr/open.d.ts.map +1 -1
  93. package/dist/commands/pr/open.js +52 -3
  94. package/dist/commands/pr/update.d.ts.map +1 -1
  95. package/dist/commands/pr/update.js +13 -2
  96. package/dist/commands/recipes/active.command.d.ts +7 -0
  97. package/dist/commands/recipes/active.command.d.ts.map +1 -0
  98. package/dist/commands/recipes/active.command.js +12 -0
  99. package/dist/commands/recipes/add.command.d.ts +8 -0
  100. package/dist/commands/recipes/add.command.d.ts.map +1 -0
  101. package/dist/commands/recipes/add.command.js +33 -0
  102. package/dist/commands/recipes/detach.command.d.ts +7 -0
  103. package/dist/commands/recipes/detach.command.d.ts.map +1 -0
  104. package/dist/commands/recipes/detach.command.js +19 -0
  105. package/dist/commands/recipes/disable.command.d.ts +7 -0
  106. package/dist/commands/recipes/disable.command.d.ts.map +1 -0
  107. package/dist/commands/recipes/disable.command.js +10 -0
  108. package/dist/commands/recipes/enable.command.d.ts +7 -0
  109. package/dist/commands/recipes/enable.command.d.ts.map +1 -0
  110. package/dist/commands/recipes/enable.command.js +10 -0
  111. package/dist/commands/recipes/explain-active.command.d.ts +5 -0
  112. package/dist/commands/recipes/explain-active.command.d.ts.map +1 -0
  113. package/dist/commands/recipes/explain-active.command.js +11 -0
  114. package/dist/commands/recipes/explain.command.d.ts.map +1 -1
  115. package/dist/commands/recipes/explain.command.js +4 -2
  116. package/dist/commands/recipes/impl/apply.d.ts.map +1 -1
  117. package/dist/commands/recipes/impl/apply.js +33 -14
  118. package/dist/commands/recipes/impl/commands/active.d.ts +6 -0
  119. package/dist/commands/recipes/impl/commands/active.d.ts.map +1 -0
  120. package/dist/commands/recipes/impl/commands/active.js +46 -0
  121. package/dist/commands/recipes/impl/commands/add.d.ts +7 -0
  122. package/dist/commands/recipes/impl/commands/add.d.ts.map +1 -0
  123. package/dist/commands/recipes/impl/commands/add.js +100 -0
  124. package/dist/commands/recipes/impl/commands/detach.d.ts +6 -0
  125. package/dist/commands/recipes/impl/commands/detach.d.ts.map +1 -0
  126. package/dist/commands/recipes/impl/commands/detach.js +85 -0
  127. package/dist/commands/recipes/impl/commands/disable.d.ts +6 -0
  128. package/dist/commands/recipes/impl/commands/disable.d.ts.map +1 -0
  129. package/dist/commands/recipes/impl/commands/disable.js +21 -0
  130. package/dist/commands/recipes/impl/commands/enable.d.ts +6 -0
  131. package/dist/commands/recipes/impl/commands/enable.d.ts.map +1 -0
  132. package/dist/commands/recipes/impl/commands/enable.js +39 -0
  133. package/dist/commands/recipes/impl/commands/explain-active.d.ts +5 -0
  134. package/dist/commands/recipes/impl/commands/explain-active.d.ts.map +1 -0
  135. package/dist/commands/recipes/impl/commands/explain-active.js +20 -0
  136. package/dist/commands/recipes/impl/commands/explain.d.ts.map +1 -1
  137. package/dist/commands/recipes/impl/commands/explain.js +40 -3
  138. package/dist/commands/recipes/impl/commands/info.d.ts.map +1 -1
  139. package/dist/commands/recipes/impl/commands/info.js +21 -8
  140. package/dist/commands/recipes/impl/commands/install.d.ts.map +1 -1
  141. package/dist/commands/recipes/impl/commands/install.js +32 -29
  142. package/dist/commands/recipes/impl/commands/list.d.ts.map +1 -1
  143. package/dist/commands/recipes/impl/commands/list.js +11 -11
  144. package/dist/commands/recipes/impl/commands/remove.d.ts.map +1 -1
  145. package/dist/commands/recipes/impl/commands/remove.js +5 -0
  146. package/dist/commands/recipes/impl/commands/update.d.ts +7 -0
  147. package/dist/commands/recipes/impl/commands/update.d.ts.map +1 -0
  148. package/dist/commands/recipes/impl/commands/update.js +93 -0
  149. package/dist/commands/recipes/impl/commands.d.ts +7 -0
  150. package/dist/commands/recipes/impl/commands.d.ts.map +1 -1
  151. package/dist/commands/recipes/impl/commands.js +7 -0
  152. package/dist/commands/recipes/impl/constants.d.ts +1 -14
  153. package/dist/commands/recipes/impl/constants.d.ts.map +1 -1
  154. package/dist/commands/recipes/impl/constants.js +1 -18
  155. package/dist/commands/recipes/impl/manifest.d.ts +2 -2
  156. package/dist/commands/recipes/impl/manifest.d.ts.map +1 -1
  157. package/dist/commands/recipes/impl/manifest.js +4 -226
  158. package/dist/commands/recipes/impl/overlay-project.d.ts +32 -0
  159. package/dist/commands/recipes/impl/overlay-project.d.ts.map +1 -0
  160. package/dist/commands/recipes/impl/overlay-project.js +282 -0
  161. package/dist/commands/recipes/impl/paths.d.ts +20 -2
  162. package/dist/commands/recipes/impl/paths.d.ts.map +1 -1
  163. package/dist/commands/recipes/impl/paths.js +23 -5
  164. package/dist/commands/recipes/impl/project-installed-recipes.d.ts +2 -4
  165. package/dist/commands/recipes/impl/project-installed-recipes.d.ts.map +1 -1
  166. package/dist/commands/recipes/impl/project-installed-recipes.js +30 -74
  167. package/dist/commands/recipes/impl/project-recipe-state.d.ts +18 -0
  168. package/dist/commands/recipes/impl/project-recipe-state.d.ts.map +1 -0
  169. package/dist/commands/recipes/impl/project-recipe-state.js +94 -0
  170. package/dist/commands/recipes/impl/project-registry.d.ts +20 -0
  171. package/dist/commands/recipes/impl/project-registry.d.ts.map +1 -0
  172. package/dist/commands/recipes/impl/project-registry.js +104 -0
  173. package/dist/commands/recipes/impl/resolver.d.ts.map +1 -1
  174. package/dist/commands/recipes/impl/resolver.js +5 -3
  175. package/dist/commands/recipes/impl/types.d.ts +1 -240
  176. package/dist/commands/recipes/impl/types.d.ts.map +1 -1
  177. package/dist/commands/recipes/info.command.js +2 -2
  178. package/dist/commands/recipes/install.spec.js +4 -4
  179. package/dist/commands/recipes/list.command.js +4 -4
  180. package/dist/commands/recipes/remove.command.js +2 -2
  181. package/dist/commands/recipes/update.command.d.ts +8 -0
  182. package/dist/commands/recipes/update.command.d.ts.map +1 -0
  183. package/dist/commands/recipes/update.command.js +35 -0
  184. package/dist/commands/recipes.d.ts +7 -4
  185. package/dist/commands/recipes.d.ts.map +1 -1
  186. package/dist/commands/recipes.js +6 -3
  187. package/dist/commands/recipes.test-helpers.d.ts +3 -3
  188. package/dist/commands/recipes.test-helpers.d.ts.map +1 -1
  189. package/dist/commands/recipes.test-helpers.js +105 -15
  190. package/dist/commands/release/apply.command.d.ts +3 -1
  191. package/dist/commands/release/apply.command.d.ts.map +1 -1
  192. package/dist/commands/release/apply.command.js +354 -18
  193. package/dist/commands/release/apply.mutation.d.ts.map +1 -1
  194. package/dist/commands/release/apply.mutation.js +1 -0
  195. package/dist/commands/release/apply.reporting.d.ts +1 -0
  196. package/dist/commands/release/apply.reporting.d.ts.map +1 -1
  197. package/dist/commands/release/apply.reporting.js +12 -8
  198. package/dist/commands/release/apply.types.d.ts +13 -0
  199. package/dist/commands/release/apply.types.d.ts.map +1 -1
  200. package/dist/commands/release/plan.command.d.ts.map +1 -1
  201. package/dist/commands/release/plan.command.js +48 -0
  202. package/dist/commands/scenario/execute.command.js +4 -4
  203. package/dist/commands/scenario/impl/commands.js +4 -4
  204. package/dist/commands/scenario/info.command.js +4 -4
  205. package/dist/commands/scenario/list.command.js +3 -3
  206. package/dist/commands/scenario/run.command.js +5 -5
  207. package/dist/commands/scenario/scenario.command.js +7 -7
  208. package/dist/commands/shared/merged-branch-cleanup.d.ts +12 -0
  209. package/dist/commands/shared/merged-branch-cleanup.d.ts.map +1 -0
  210. package/dist/commands/shared/merged-branch-cleanup.js +46 -0
  211. package/dist/commands/shared/post-commit-pr-artifacts.d.ts.map +1 -1
  212. package/dist/commands/shared/post-commit-pr-artifacts.js +35 -0
  213. package/dist/commands/shared/task-backend.d.ts.map +1 -1
  214. package/dist/commands/shared/task-backend.js +37 -5
  215. package/dist/commands/shared/task-handoff.d.ts +2 -1
  216. package/dist/commands/shared/task-handoff.d.ts.map +1 -1
  217. package/dist/commands/shared/task-handoff.js +15 -0
  218. package/dist/commands/shared/task-local-freshness.d.ts +2 -0
  219. package/dist/commands/shared/task-local-freshness.d.ts.map +1 -1
  220. package/dist/commands/shared/task-local-freshness.js +7 -1
  221. package/dist/commands/task/finish-shared.d.ts +1 -0
  222. package/dist/commands/task/finish-shared.d.ts.map +1 -1
  223. package/dist/commands/task/finish-shared.js +1 -0
  224. package/dist/commands/task/handoff-show.command.d.ts.map +1 -1
  225. package/dist/commands/task/handoff-show.command.js +24 -0
  226. package/dist/commands/task/hosted-close-pr.command.d.ts.map +1 -1
  227. package/dist/commands/task/hosted-close-pr.command.js +35 -0
  228. package/dist/commands/task/hosted-close.command.d.ts.map +1 -1
  229. package/dist/commands/task/hosted-close.command.js +185 -18
  230. package/dist/commands/task/hosted-merge-sync.d.ts +4 -1
  231. package/dist/commands/task/hosted-merge-sync.d.ts.map +1 -1
  232. package/dist/commands/task/hosted-merge-sync.js +52 -10
  233. package/dist/commands/task/start-ready.d.ts.map +1 -1
  234. package/dist/commands/task/start-ready.js +0 -86
  235. package/dist/runner/context/base-prompts.d.ts +2 -1
  236. package/dist/runner/context/base-prompts.d.ts.map +1 -1
  237. package/dist/runner/context/base-prompts.js +109 -13
  238. package/dist/runner/context/recipe-context.d.ts.map +1 -1
  239. package/dist/runner/context/recipe-context.js +40 -8
  240. package/dist/runner/types.d.ts +4 -0
  241. package/dist/runner/types.d.ts.map +1 -1
  242. package/dist/runner/usecases/task-run.d.ts.map +1 -1
  243. package/dist/runner/usecases/task-run.js +2 -1
  244. package/dist/runtime/behavior/resolve.d.ts +2 -1
  245. package/dist/runtime/behavior/resolve.d.ts.map +1 -1
  246. package/dist/runtime/behavior/resolve.js +25 -5
  247. package/dist/runtime/behavior/types.d.ts +1 -0
  248. package/dist/runtime/behavior/types.d.ts.map +1 -1
  249. package/dist/runtime/capabilities/recipe.d.ts +2 -1
  250. package/dist/runtime/capabilities/recipe.d.ts.map +1 -1
  251. package/dist/runtime/capabilities/recipe.js +88 -28
  252. package/dist/shared/errors.d.ts +1 -1
  253. package/dist/shared/errors.d.ts.map +1 -1
  254. package/dist/shared/runtime-source.d.ts.map +1 -1
  255. package/dist/shared/runtime-source.js +8 -3
  256. package/package.json +3 -2
  257. package/dist/cli/recipes-bundled.d.ts +0 -10
  258. package/dist/cli/recipes-bundled.d.ts.map +0 -1
  259. package/dist/cli/recipes-bundled.js +0 -36
@@ -4,6 +4,7 @@ import { resolveBaseBranch } from "@agentplaneorg/core";
4
4
  import { fileExists } from "../../../../cli/fs-utils.js";
5
5
  import { exitCodeForError } from "../../../../cli/exit-codes.js";
6
6
  import { unknownEntityMessage, workflowModeMessage } from "../../../../cli/output.js";
7
+ import { withDiagnosticContext } from "../../../../shared/diagnostics.js";
7
8
  import { CliError } from "../../../../shared/errors.js";
8
9
  import { ensureGitClean } from "../../../guard/index.js";
9
10
  import { gitDiffNames } from "../../../shared/git-diff.js";
@@ -17,6 +18,7 @@ import { readAndValidatePrArtifacts, ensureCommittedPrArtifactsOnBranch } from "
17
18
  import { computeVerifyState } from "../verify.js";
18
19
  import { parsePrMetaForwardCompatible } from "../../../shared/pr-meta.js";
19
20
  import { assessPrArtifactFreshness } from "../../internal/freshness.js";
21
+ import { requiresPullRequestMergePath } from "./github-protection.js";
20
22
  export async function prepareIntegrate(opts) {
21
23
  const ctx = opts.ctx ??
22
24
  (await loadCommandContext({ cwd: opts.cwd, rootOverride: opts.rootOverride ?? null }));
@@ -51,13 +53,6 @@ export async function prepareIntegrate(opts) {
51
53
  });
52
54
  }
53
55
  const currentBranch = await gitCurrentBranch(resolved.gitRoot);
54
- if (currentBranch !== baseBranch) {
55
- throw new CliError({
56
- exitCode: exitCodeForError("E_GIT"),
57
- code: "E_GIT",
58
- message: `integrate must run on base branch ${baseBranch} (current: ${currentBranch})`,
59
- });
60
- }
61
56
  const { prDir, metaPath, diffstatPath, verifyLogPath } = await resolvePrPaths({
62
57
  ctx,
63
58
  cwd: opts.cwd,
@@ -91,6 +86,43 @@ export async function prepareIntegrate(opts) {
91
86
  message: unknownEntityMessage("branch", branch),
92
87
  });
93
88
  }
89
+ if (currentBranch !== baseBranch) {
90
+ if (currentBranch === branch) {
91
+ const baseWorktreePath = await findWorktreeForBranch(resolved.gitRoot, baseBranch);
92
+ const rerunCommand = baseWorktreePath && baseWorktreePath.trim().length > 0
93
+ ? `agentplane integrate ${opts.taskId} --branch ${branch} --root ${baseWorktreePath}`
94
+ : `git checkout ${baseBranch} && agentplane integrate ${opts.taskId} --branch ${branch}`;
95
+ throw new CliError({
96
+ exitCode: exitCodeForError("E_GIT"),
97
+ code: "E_GIT",
98
+ message: `integrate must run from the ${baseBranch} base checkout, not from task branch ${branch}. ` +
99
+ `Rerun it against the base checkout after leaving this task worktree.`,
100
+ context: withDiagnosticContext({
101
+ command: "integrate",
102
+ task_id: opts.taskId,
103
+ branch,
104
+ base_branch: baseBranch,
105
+ current_branch: currentBranch,
106
+ ...(baseWorktreePath ? { base_worktree_path: baseWorktreePath } : {}),
107
+ reason_code: "integrate_base_checkout_required",
108
+ }, {
109
+ state: `integrate was invoked from task branch ${branch} instead of base branch ${baseBranch}`,
110
+ likelyCause: "the operator is inside the task worktree, but branch_pr integrate is only valid from the registered base checkout",
111
+ hint: "Use the base checkout/worktree for the resolved base branch, not the task branch worktree, when running integrate.",
112
+ nextAction: {
113
+ command: rerunCommand,
114
+ reason: "rerun integrate against the base checkout route",
115
+ reasonCode: "integrate_base_checkout_required",
116
+ },
117
+ }),
118
+ });
119
+ }
120
+ throw new CliError({
121
+ exitCode: exitCodeForError("E_GIT"),
122
+ code: "E_GIT",
123
+ message: `integrate must run on base branch ${baseBranch} (current: ${currentBranch})`,
124
+ });
125
+ }
94
126
  await ensureCommittedPrArtifactsOnBranch({
95
127
  resolved,
96
128
  prDir,
@@ -132,6 +164,10 @@ export async function prepareIntegrate(opts) {
132
164
  preferBranchSnapshot: true,
133
165
  branchSnapshotBranch: branch,
134
166
  });
167
+ const protectedBaseRequiresPrMerge = await requiresPullRequestMergePath({
168
+ gitRoot: resolved.gitRoot,
169
+ baseBranch: base,
170
+ });
135
171
  const changedPaths = await gitDiffNames(resolved.gitRoot, base, branch);
136
172
  const tasksPath = loadedConfig.paths.tasks_path;
137
173
  if (changedPaths.includes(tasksPath)) {
@@ -145,6 +181,7 @@ export async function prepareIntegrate(opts) {
145
181
  let freshness = await assessPrArtifactFreshness({
146
182
  gitRoot: resolved.gitRoot,
147
183
  workflowDir: loadedConfig.paths.workflow_dir,
184
+ tasksPath: loadedConfig.paths.tasks_path,
148
185
  taskId: opts.taskId,
149
186
  branchHeadSha,
150
187
  metaHeadSha: metaSource.head_sha ?? null,
@@ -181,6 +218,7 @@ export async function prepareIntegrate(opts) {
181
218
  freshness = await assessPrArtifactFreshness({
182
219
  gitRoot: resolved.gitRoot,
183
220
  workflowDir: loadedConfig.paths.workflow_dir,
221
+ tasksPath: loadedConfig.paths.tasks_path,
184
222
  taskId: opts.taskId,
185
223
  branchHeadSha,
186
224
  metaHeadSha: repairedMetaSource.head_sha ?? null,
@@ -218,6 +256,7 @@ export async function prepareIntegrate(opts) {
218
256
  task,
219
257
  baseBranch,
220
258
  currentBranch,
259
+ protectedBaseRequiresPrMerge,
221
260
  prDir,
222
261
  metaPath,
223
262
  diffstatPath,
@@ -0,0 +1,7 @@
1
+ import type { CommandContext } from "../../shared/task-backend.js";
2
+ export declare function maybeAutoCommitTaskPrArtifacts(opts: {
3
+ ctx: CommandContext;
4
+ taskId: string;
5
+ branch: string;
6
+ }): Promise<boolean>;
7
+ //# sourceMappingURL=auto-commit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auto-commit.d.ts","sourceRoot":"","sources":["../../../../src/commands/pr/internal/auto-commit.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAiCnE,wBAAsB,8BAA8B,CAAC,IAAI,EAAE;IACzD,GAAG,EAAE,cAAc,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,OAAO,CAAC,CA8CnB"}
@@ -0,0 +1,69 @@
1
+ import path from "node:path";
2
+ import { extractTaskSuffix } from "@agentplaneorg/core";
3
+ import { buildGitCommitEnv } from "../../guard/impl/env.js";
4
+ import { toGitPath } from "../../shared/git-diff.js";
5
+ import { execFileAsync, gitEnv } from "../../shared/git.js";
6
+ import { gitCurrentBranch } from "../../shared/git-ops.js";
7
+ function taskPrDirPrefix(workflowDir, taskId) {
8
+ return `${toGitPath(path.join(workflowDir, taskId, "pr"))}/`;
9
+ }
10
+ function taskReadmePath(workflowDir, taskId) {
11
+ return toGitPath(path.join(workflowDir, taskId, "README.md"));
12
+ }
13
+ function isTaskPacketPath(opts) {
14
+ const normalized = toGitPath(opts.relPath);
15
+ return (normalized === taskReadmePath(opts.workflowDir, opts.taskId) ||
16
+ normalized.startsWith(taskPrDirPrefix(opts.workflowDir, opts.taskId)));
17
+ }
18
+ async function readCachedPaths(gitRoot) {
19
+ const { stdout } = await execFileAsync("git", ["diff", "--cached", "--name-only", "--relative"], {
20
+ cwd: gitRoot,
21
+ env: gitEnv(),
22
+ });
23
+ return stdout
24
+ .split("\n")
25
+ .map((line) => line.trim())
26
+ .filter((line) => line.length > 0);
27
+ }
28
+ function taskPrArtifactRefreshMessage(taskId) {
29
+ return `📝 ${extractTaskSuffix(taskId)} task: refresh PR artifacts`;
30
+ }
31
+ export async function maybeAutoCommitTaskPrArtifacts(opts) {
32
+ if (opts.ctx.config.workflow_mode !== "branch_pr")
33
+ return false;
34
+ const branchText = await gitCurrentBranch(opts.ctx.resolvedProject.gitRoot);
35
+ const currentBranch = branchText.trim();
36
+ if (!currentBranch || currentBranch !== opts.branch.trim())
37
+ return false;
38
+ const changedPaths = await opts.ctx.git.statusChangedPaths();
39
+ const taskPacketPaths = changedPaths.filter((relPath) => isTaskPacketPath({
40
+ workflowDir: opts.ctx.config.paths.workflow_dir,
41
+ taskId: opts.taskId,
42
+ relPath,
43
+ }));
44
+ if (taskPacketPaths.length === 0)
45
+ return false;
46
+ const cachedPaths = await readCachedPaths(opts.ctx.resolvedProject.gitRoot);
47
+ if (cachedPaths.some((relPath) => !isTaskPacketPath({
48
+ workflowDir: opts.ctx.config.paths.workflow_dir,
49
+ taskId: opts.taskId,
50
+ relPath,
51
+ }))) {
52
+ return false;
53
+ }
54
+ await opts.ctx.git.stage(taskPacketPaths);
55
+ await opts.ctx.git.commit({
56
+ message: taskPrArtifactRefreshMessage(opts.taskId),
57
+ env: buildGitCommitEnv({
58
+ taskId: opts.taskId,
59
+ allowTasks: true,
60
+ allowBase: false,
61
+ allowPolicy: false,
62
+ allowConfig: false,
63
+ allowHooks: false,
64
+ allowCI: false,
65
+ }),
66
+ });
67
+ opts.ctx.git.invalidateStatus();
68
+ return true;
69
+ }
@@ -8,6 +8,7 @@ export type PrArtifactFreshness = {
8
8
  export declare function assessPrArtifactFreshness(opts: {
9
9
  gitRoot: string;
10
10
  workflowDir: string;
11
+ tasksPath?: string;
11
12
  taskId: string;
12
13
  branchHeadSha: string;
13
14
  metaHeadSha: unknown;
@@ -1 +1 @@
1
- {"version":3,"file":"freshness.d.ts","sourceRoot":"","sources":["../../../../src/commands/pr/internal/freshness.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC,CAAC;AAEF,wBAAsB,yBAAyB,CAAC,IAAI,EAAE;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,EAAE,OAAO,CAAC;CACzB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAgD/B"}
1
+ {"version":3,"file":"freshness.d.ts","sourceRoot":"","sources":["../../../../src/commands/pr/internal/freshness.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,mBAAmB,GAAG;IAChC,WAAW,EAAE,OAAO,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,eAAe,EAAE,OAAO,CAAC;IACzB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC,CAAC;AAEF,wBAAsB,yBAAyB,CAAC,IAAI,EAAE;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,WAAW,EAAE,OAAO,CAAC;IACrB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,cAAc,EAAE,OAAO,CAAC;CACzB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAkD/B"}
@@ -15,6 +15,7 @@ export async function assessPrArtifactFreshness(opts) {
15
15
  (await isTaskLocalOnlyAdvance({
16
16
  gitRoot: opts.gitRoot,
17
17
  workflowDir: opts.workflowDir,
18
+ tasksPath: opts.tasksPath,
18
19
  taskId: opts.taskId,
19
20
  fromRef: metaHeadSha,
20
21
  toRef: opts.branchHeadSha,
@@ -33,6 +34,7 @@ export async function assessPrArtifactFreshness(opts) {
33
34
  (await isTaskLocalOnlyAdvance({
34
35
  gitRoot: opts.gitRoot,
35
36
  workflowDir: opts.workflowDir,
37
+ tasksPath: opts.tasksPath,
36
38
  taskId: opts.taskId,
37
39
  fromRef: metaLastVerifiedSha,
38
40
  toRef: opts.branchHeadSha,
@@ -1 +1 @@
1
- {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../../src/commands/pr/internal/sync.ts"],"names":[],"mappings":"AAqBA,OAAO,EAML,KAAK,MAAM,EACZ,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,8BAA8B,CAAC;AAsFtC,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,CAAC;AAEhD,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,iBAAiB,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC/D,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAyOF,KAAK,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAC;AAmCpC,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/B,GAAG,IAAI,CAAC,CAmDR;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,YAAY,CAAC;CAC3B,GAAG,OAAO,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,WAAW,CAAC,EAAE,aAAa,CAAC;CAC7B,CAAC,CA6SD"}
1
+ {"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../../../src/commands/pr/internal/sync.ts"],"names":[],"mappings":"AAqBA,OAAO,EAML,KAAK,MAAM,EACZ,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,8BAA8B,CAAC;AAoFtC,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,WAAW,CAAC;AAEhD,MAAM,MAAM,aAAa,GAAG;IAC1B,MAAM,EAAE,iBAAiB,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;IAC/D,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AA6SF,KAAK,UAAU,GAAG,MAAM,GAAG,QAAQ,CAAC;AAmCpC,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,GAAG,OAAO,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC/B,GAAG,IAAI,CAAC,CAmDR;AAED,wBAAsB,eAAe,CAAC,IAAI,EAAE;IAC1C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,YAAY,CAAC;CAC3B,GAAG,OAAO,CAAC;IACV,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC9B,WAAW,CAAC,EAAE,aAAa,CAAC;CAC7B,CAAC,CA4TD"}
@@ -1,6 +1,6 @@
1
1
  import { mkdir, readFile, rm } from "node:fs/promises";
2
2
  import path from "node:path";
3
- import { resolveBaseBranch } from "@agentplaneorg/core";
3
+ import { extractTaskSuffix, resolveBaseBranch } from "@agentplaneorg/core";
4
4
  import { mapBackendError } from "../../../cli/error-map.js";
5
5
  import { exitCodeForError } from "../../../cli/exit-codes.js";
6
6
  import { fileExists } from "../../../cli/fs-utils.js";
@@ -9,13 +9,13 @@ import { CliError } from "../../../shared/errors.js";
9
9
  import { writeJsonStableIfChanged, writeTextIfChanged } from "../../../shared/write-if-changed.js";
10
10
  import { execFileAsync, gitEnv } from "../../shared/git.js";
11
11
  import { gitDiffStat } from "../../shared/git-diff.js";
12
- import { gitCurrentBranch } from "../../shared/git-ops.js";
12
+ import { gitBranchUpstream, gitCurrentBranch } from "../../shared/git-ops.js";
13
13
  import { parseTaskIdFromBranch } from "../../shared/git-worktree.js";
14
14
  import { isTransientGhTransportError, normalizeGhTransportError, withGhTransportRetry, } from "../../shared/gh-transport.js";
15
15
  import { INCIDENTS_POLICY_PATH } from "../../incidents/shared.js";
16
- import { buildObservedGithubPrMeta, buildOpenedPrMeta, resolvePrArtifactHeadSha, buildUpdatedPrMeta, parsePrMeta, } from "../../shared/pr-meta.js";
17
- import { loadBackendTask, loadCommandContext, } from "../../shared/task-backend.js";
16
+ import { buildObservedGithubPrMeta, buildOpenedPrMeta, buildUpdatedPrMeta, resolvePrArtifactHeadSha, parsePrMeta, } from "../../shared/pr-meta.js";
18
17
  import { isTaskLocalOnlyAdvance } from "../../shared/task-local-freshness.js";
18
+ import { loadBackendTask, loadCommandContext, } from "../../shared/task-backend.js";
19
19
  import { resolvePrPaths } from "./pr-paths.js";
20
20
  import { readPrHandoffNotes } from "./note-store.js";
21
21
  import { ghEnv } from "./gh-api.js";
@@ -147,6 +147,36 @@ function formatGithubPrLink(prNumber, prUrl, verb) {
147
147
  ? `${verb} GitHub PR #${prNumber}: ${prUrl.trim()}`
148
148
  : `${verb} GitHub PR #${prNumber}`;
149
149
  }
150
+ function shouldPersistObservedGithubPrMeta(observed) {
151
+ if (!observed)
152
+ return false;
153
+ return observed.status === "MERGED";
154
+ }
155
+ function taskPrArtifactRefreshMessage(taskId) {
156
+ return `📝 ${extractTaskSuffix(taskId)} task: refresh PR artifacts`;
157
+ }
158
+ async function resolveRenderableBranchHead(opts) {
159
+ const branchHeadSha = await resolveBranchHeadSha({
160
+ gitRoot: opts.gitRoot,
161
+ branch: opts.branch,
162
+ });
163
+ if (!branchHeadSha)
164
+ return { headSha: null, artifactRefresh: false };
165
+ try {
166
+ const { stdout: subjectStdout } = await execFileAsync("git", ["log", "-1", "--pretty=%s", branchHeadSha], {
167
+ cwd: opts.gitRoot,
168
+ env: gitEnv(),
169
+ });
170
+ const subject = subjectStdout.trim();
171
+ return {
172
+ headSha: branchHeadSha,
173
+ artifactRefresh: subject === taskPrArtifactRefreshMessage(opts.taskId),
174
+ };
175
+ }
176
+ catch {
177
+ return { headSha: branchHeadSha, artifactRefresh: false };
178
+ }
179
+ }
150
180
  function formatUnpublishedRemoteHeadReason(branch) {
151
181
  return (`task branch ${branch} is not yet published on origin; push it with ` +
152
182
  `\`git push -u origin ${branch}\` and rerun \`agentplane pr open\``);
@@ -248,9 +278,17 @@ async function resolveBranchHeadSha(opts) {
248
278
  }
249
279
  }
250
280
  async function computePrDiffstat(opts) {
281
+ const diffBaseRef = await resolvePrDiffBaseRef({
282
+ gitRoot: opts.gitRoot,
283
+ baseBranch: opts.baseBranch,
284
+ });
285
+ const taskDir = path.dirname(opts.prDir);
251
286
  try {
252
- return await gitDiffStat(opts.gitRoot, opts.baseBranch, opts.branch, {
253
- excludePaths: [path.relative(opts.gitRoot, opts.prDir)],
287
+ return await gitDiffStat(opts.gitRoot, diffBaseRef, opts.branch, {
288
+ excludePaths: [
289
+ path.relative(opts.gitRoot, opts.prDir),
290
+ path.relative(opts.gitRoot, path.join(taskDir, "README.md")),
291
+ ],
254
292
  });
255
293
  }
256
294
  catch (err) {
@@ -259,6 +297,24 @@ async function computePrDiffstat(opts) {
259
297
  return "";
260
298
  }
261
299
  }
300
+ async function resolvePrDiffBaseRef(opts) {
301
+ const upstreamRef = await gitBranchUpstream(opts.gitRoot, opts.baseBranch);
302
+ const candidate = upstreamRef?.trim() ?? "";
303
+ if (!candidate)
304
+ return opts.baseBranch;
305
+ try {
306
+ const { stdout } = await execFileAsync("git", ["rev-parse", "--verify", candidate], {
307
+ cwd: opts.gitRoot,
308
+ env: gitEnv(),
309
+ });
310
+ return stdout.trim() ? candidate : opts.baseBranch;
311
+ }
312
+ catch (err) {
313
+ if (!isUnknownRevisionError(err))
314
+ throw err;
315
+ return opts.baseBranch;
316
+ }
317
+ }
262
318
  async function resolvePrSyncBranch(opts) {
263
319
  const explicitBranch = opts.branch?.trim() ?? "";
264
320
  if (explicitBranch) {
@@ -386,21 +442,28 @@ export async function syncPrArtifacts(opts) {
386
442
  cliBaseOpt: null,
387
443
  mode: config.workflow_mode,
388
444
  });
389
- const headSha = await resolveBranchHeadSha({ gitRoot: resolved.gitRoot, branch });
445
+ const { headSha, artifactRefresh } = await resolveRenderableBranchHead({
446
+ gitRoot: resolved.gitRoot,
447
+ taskId: task.id,
448
+ branch,
449
+ });
390
450
  const preservePreviousHead = Boolean(existingMeta?.head_sha) &&
391
451
  Boolean(headSha) &&
392
452
  (await isTaskLocalOnlyAdvance({
393
453
  gitRoot: resolved.gitRoot,
394
454
  workflowDir: config.paths.workflow_dir,
455
+ tasksPath: config.paths.tasks_path,
395
456
  taskId: task.id,
396
457
  fromRef: existingMeta?.head_sha ?? null,
397
458
  toRef: headSha,
398
459
  }));
399
- const renderedHeadSha = resolvePrArtifactHeadSha({
400
- previousHeadSha: existingMeta?.head_sha ?? null,
401
- currentHeadSha: headSha,
402
- preservePrevious: preservePreviousHead,
403
- });
460
+ const renderedHeadSha = artifactRefresh
461
+ ? (existingMeta?.head_sha ?? undefined)
462
+ : resolvePrArtifactHeadSha({
463
+ previousHeadSha: existingMeta?.head_sha ?? null,
464
+ currentHeadSha: headSha,
465
+ preservePrevious: preservePreviousHead,
466
+ });
404
467
  const preservedRenderUpdatedAt = existingMeta &&
405
468
  (existingMeta.branch ?? null) === branch &&
406
469
  (existingMeta.base ?? null) === (baseBranch ?? null) &&
@@ -418,7 +481,9 @@ export async function syncPrArtifacts(opts) {
418
481
  prDir,
419
482
  })
420
483
  : "";
421
- const renderedSummaryHeadSha = renderedHeadSha ?? headSha;
484
+ const renderedSummaryHeadSha = artifactRefresh
485
+ ? renderedHeadSha
486
+ : (renderedHeadSha ?? headSha);
422
487
  let nextMeta = buildOpenedPrMeta({
423
488
  taskId: task.id,
424
489
  branch,
@@ -441,7 +506,7 @@ export async function syncPrArtifacts(opts) {
441
506
  autoSummary: renderPrAutoSummary({
442
507
  updatedAt: renderUpdatedAt,
443
508
  branch,
444
- headSha: renderedSummaryHeadSha,
509
+ headSha: renderedSummaryHeadSha ?? null,
445
510
  diffstat,
446
511
  }),
447
512
  });
@@ -451,11 +516,13 @@ export async function syncPrArtifacts(opts) {
451
516
  baseBranch,
452
517
  });
453
518
  if (observedGithubPr) {
454
- nextMeta = buildObservedGithubPrMeta({
455
- meta: nextMeta,
456
- observed: observedGithubPr,
457
- at: now,
458
- });
519
+ if (shouldPersistObservedGithubPrMeta(observedGithubPr)) {
520
+ nextMeta = buildObservedGithubPrMeta({
521
+ meta: nextMeta,
522
+ observed: observedGithubPr,
523
+ at: now,
524
+ });
525
+ }
459
526
  openOutcome = {
460
527
  action: "linked-existing",
461
528
  message: formatGithubPrLink(observedGithubPr.prNumber, observedGithubPr.prUrl, "linked to"),
@@ -476,11 +543,13 @@ export async function syncPrArtifacts(opts) {
476
543
  body: githubBody,
477
544
  });
478
545
  if (createdGithubPr.observed) {
479
- nextMeta = buildObservedGithubPrMeta({
480
- meta: nextMeta,
481
- observed: createdGithubPr.observed,
482
- at: now,
483
- });
546
+ if (shouldPersistObservedGithubPrMeta(createdGithubPr.observed)) {
547
+ nextMeta = buildObservedGithubPrMeta({
548
+ meta: nextMeta,
549
+ observed: createdGithubPr.observed,
550
+ at: now,
551
+ });
552
+ }
484
553
  openOutcome = {
485
554
  action: "created",
486
555
  message: formatGithubPrLink(createdGithubPr.observed.prNumber, createdGithubPr.observed.prUrl, "created"),
@@ -496,7 +565,7 @@ export async function syncPrArtifacts(opts) {
496
565
  const nextAutoSummary = renderPrAutoSummary({
497
566
  updatedAt: renderUpdatedAt,
498
567
  branch,
499
- headSha: renderedSummaryHeadSha,
568
+ headSha: renderedSummaryHeadSha ?? null,
500
569
  diffstat,
501
570
  });
502
571
  const nextReview = renderPrReviewDocument({
@@ -550,7 +619,7 @@ export async function syncPrArtifacts(opts) {
550
619
  branch,
551
620
  baseBranch,
552
621
  });
553
- if (observedGithubPr) {
622
+ if (shouldPersistObservedGithubPrMeta(observedGithubPr)) {
554
623
  nextMeta = buildObservedGithubPrMeta({
555
624
  meta: nextMeta,
556
625
  observed: observedGithubPr,
@@ -560,7 +629,9 @@ export async function syncPrArtifacts(opts) {
560
629
  const nextAutoSummary = renderPrAutoSummary({
561
630
  updatedAt: nextMeta.updated_at,
562
631
  branch,
563
- headSha: nextMeta.head_sha ?? renderedHeadSha ?? headSha,
632
+ headSha: artifactRefresh
633
+ ? (nextMeta.head_sha ?? renderedHeadSha ?? null)
634
+ : (nextMeta.head_sha ?? renderedHeadSha ?? headSha ?? null),
564
635
  diffstat,
565
636
  });
566
637
  const nextReview = renderPrReviewDocument({
@@ -1 +1 @@
1
- {"version":3,"file":"open.d.ts","sourceRoot":"","sources":["../../../src/commands/pr/open.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAiBhE,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiClB"}
1
+ {"version":3,"file":"open.d.ts","sourceRoot":"","sources":["../../../src/commands/pr/open.ts"],"names":[],"mappings":"AAQA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAuCpF,wBAAsB,SAAS,CAAC,IAAI,EAAE;IACpC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,CAAC,CAgElB"}
@@ -3,6 +3,10 @@ import { mapBackendError } from "../../cli/error-map.js";
3
3
  import { exitCodeForError } from "../../cli/exit-codes.js";
4
4
  import { createCliEmitter } from "../../cli/output.js";
5
5
  import { CliError } from "../../shared/errors.js";
6
+ import { execFileAsync, gitEnv } from "../shared/git.js";
7
+ import { gitBranchUpstream } from "../shared/git-ops.js";
8
+ import { loadCommandContext } from "../shared/task-backend.js";
9
+ import { maybeAutoCommitTaskPrArtifacts } from "./internal/auto-commit.js";
6
10
  import { syncPrArtifacts } from "./internal/sync.js";
7
11
  function prOpenOutcomeDetails(meta, openOutcome) {
8
12
  if (openOutcome)
@@ -14,6 +18,24 @@ function prOpenOutcomeDetails(meta, openOutcome) {
14
18
  }
15
19
  return "local PR artifacts synced; remote PR creation staged";
16
20
  }
21
+ async function pushTaskBranchUpstreamIfConfigured(opts) {
22
+ const upstream = await gitBranchUpstream(opts.gitRoot, opts.branch);
23
+ const trimmed = upstream?.trim() ?? "";
24
+ if (!trimmed)
25
+ return false;
26
+ const slashIndex = trimmed.indexOf("/");
27
+ if (slashIndex <= 0 || slashIndex === trimmed.length - 1)
28
+ return false;
29
+ const remote = trimmed.slice(0, slashIndex);
30
+ const upstreamBranch = trimmed.slice(slashIndex + 1);
31
+ if (!remote || !upstreamBranch)
32
+ return false;
33
+ await execFileAsync("git", ["push", "--no-verify", remote, `HEAD:${upstreamBranch}`], {
34
+ cwd: opts.gitRoot,
35
+ env: gitEnv(),
36
+ });
37
+ return true;
38
+ }
17
39
  export async function cmdPrOpen(opts) {
18
40
  try {
19
41
  const output = createCliEmitter();
@@ -25,16 +47,43 @@ export async function cmdPrOpen(opts) {
25
47
  message: "Invalid value for --author.",
26
48
  });
27
49
  }
28
- const { meta, prDir, resolved, openOutcome } = await syncPrArtifacts({
29
- ctx: opts.ctx,
50
+ const commandCtx = opts.ctx ??
51
+ (await loadCommandContext({ cwd: opts.cwd, rootOverride: opts.rootOverride ?? null }));
52
+ const initialSync = await syncPrArtifacts({
53
+ ctx: commandCtx,
30
54
  cwd: opts.cwd,
31
55
  rootOverride: opts.rootOverride,
32
56
  taskId: opts.taskId,
33
57
  mode: "open",
34
58
  author,
35
59
  branch: opts.branch,
36
- remoteMode: opts.syncOnly ? "sync-only" : "auto",
60
+ remoteMode: "sync-only",
37
61
  });
62
+ const didAutoCommit = initialSync.meta.branch
63
+ ? await maybeAutoCommitTaskPrArtifacts({
64
+ ctx: commandCtx,
65
+ taskId: opts.taskId,
66
+ branch: initialSync.meta.branch,
67
+ })
68
+ : false;
69
+ if (didAutoCommit && !opts.syncOnly && initialSync.meta.branch) {
70
+ await pushTaskBranchUpstreamIfConfigured({
71
+ gitRoot: commandCtx.resolvedProject.gitRoot,
72
+ branch: initialSync.meta.branch,
73
+ });
74
+ }
75
+ const { meta, prDir, resolved, openOutcome } = opts.syncOnly
76
+ ? initialSync
77
+ : await syncPrArtifacts({
78
+ ctx: commandCtx,
79
+ cwd: opts.cwd,
80
+ rootOverride: opts.rootOverride,
81
+ taskId: opts.taskId,
82
+ mode: "open",
83
+ author,
84
+ branch: opts.branch,
85
+ remoteMode: "auto",
86
+ });
38
87
  output.success("pr open", path.relative(resolved.gitRoot, prDir), prOpenOutcomeDetails(meta, openOutcome ?? null));
39
88
  return 0;
40
89
  }
@@ -1 +1 @@
1
- {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/commands/pr/update.ts"],"names":[],"mappings":"AAOA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAmEnC,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACtC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4BlB"}
1
+ {"version":3,"file":"update.d.ts","sourceRoot":"","sources":["../../../src/commands/pr/update.ts"],"names":[],"mappings":"AAOA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAqEnC,wBAAsB,WAAW,CAAC,IAAI,EAAE;IACtC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsClB"}
@@ -5,6 +5,7 @@ import { createCliEmitter } from "../../cli/output.js";
5
5
  import { CliError } from "../../shared/errors.js";
6
6
  import { gitRevParse } from "../shared/git-ops.js";
7
7
  import { loadBackendTask, loadCommandContext, } from "../shared/task-backend.js";
8
+ import { maybeAutoCommitTaskPrArtifacts } from "./internal/auto-commit.js";
8
9
  import { assessPrArtifactFreshness } from "./internal/freshness.js";
9
10
  import { syncPrArtifacts } from "./internal/sync.js";
10
11
  async function readTextIfExists(filePath) {
@@ -38,6 +39,7 @@ async function warnOnStaleVerifyAfterUpdate(opts) {
38
39
  const freshness = await assessPrArtifactFreshness({
39
40
  gitRoot: opts.resolved.gitRoot,
40
41
  workflowDir: path.join(opts.resolved.gitRoot, config.paths.workflow_dir),
42
+ tasksPath: config.paths.tasks_path,
41
43
  taskId: opts.taskId,
42
44
  branchHeadSha,
43
45
  metaHeadSha: opts.meta.head_sha ?? null,
@@ -54,16 +56,25 @@ async function warnOnStaleVerifyAfterUpdate(opts) {
54
56
  export async function cmdPrUpdate(opts) {
55
57
  try {
56
58
  const output = createCliEmitter();
59
+ const commandCtx = opts.ctx ??
60
+ (await loadCommandContext({ cwd: opts.cwd, rootOverride: opts.rootOverride ?? null }));
57
61
  const { meta, prDir, resolved } = await syncPrArtifacts({
58
- ctx: opts.ctx,
62
+ ctx: commandCtx,
59
63
  cwd: opts.cwd,
60
64
  rootOverride: opts.rootOverride,
61
65
  taskId: opts.taskId,
62
66
  mode: "update",
63
67
  });
68
+ if (meta.branch) {
69
+ await maybeAutoCommitTaskPrArtifacts({
70
+ ctx: commandCtx,
71
+ taskId: opts.taskId,
72
+ branch: meta.branch,
73
+ });
74
+ }
64
75
  await warnOnStaleVerifyAfterUpdate({
65
76
  output,
66
- ctx: opts.ctx,
77
+ ctx: commandCtx,
67
78
  cwd: opts.cwd,
68
79
  rootOverride: opts.rootOverride,
69
80
  taskId: opts.taskId,
@@ -0,0 +1,7 @@
1
+ import type { CommandHandler, CommandSpec } from "../../cli/spec/spec.js";
2
+ export type RecipesActiveParsed = {
3
+ full: boolean;
4
+ };
5
+ export declare const recipesActiveSpec: CommandSpec<RecipesActiveParsed>;
6
+ export declare const runRecipesActive: CommandHandler<RecipesActiveParsed>;
7
+ //# sourceMappingURL=active.command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"active.command.d.ts","sourceRoot":"","sources":["../../../src/commands/recipes/active.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAI1E,MAAM,MAAM,mBAAmB,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAEpD,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,mBAAmB,CAS9D,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,cAAc,CAAC,mBAAmB,CAC2B,CAAC"}
@@ -0,0 +1,12 @@
1
+ import { cmdRecipeActiveParsed } from "../recipes.js";
2
+ export const recipesActiveSpec = {
3
+ id: ["recipes", "active"],
4
+ group: "Recipes",
5
+ summary: "List active project overlays.",
6
+ options: [
7
+ { kind: "boolean", name: "full", default: false, description: "Print full JSON payload." },
8
+ ],
9
+ examples: [{ cmd: "agentplane recipes active", why: "Show overlays active for the project." }],
10
+ parse: (raw) => ({ full: raw.opts.full === true }),
11
+ };
12
+ export const runRecipesActive = (ctx, parsed) => cmdRecipeActiveParsed({ cwd: ctx.cwd, rootOverride: ctx.rootOverride, full: parsed.full });
@@ -0,0 +1,8 @@
1
+ import type { CommandHandler, CommandSpec } from "../../cli/spec/spec.js";
2
+ export type RecipesAddParsed = {
3
+ recipeRef: string;
4
+ mode?: "copy" | "link";
5
+ };
6
+ export declare const recipesAddSpec: CommandSpec<RecipesAddParsed>;
7
+ export declare const runRecipesAdd: CommandHandler<RecipesAddParsed>;
8
+ //# sourceMappingURL=add.command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.command.d.ts","sourceRoot":"","sources":["../../../src/commands/recipes/add.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAI1E,MAAM,MAAM,gBAAgB,GAAG;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACxB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,gBAAgB,CAyBxD,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,cAAc,CAAC,gBAAgB,CAMvD,CAAC"}