agentplane 0.3.10 → 0.3.12

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 (271) hide show
  1. package/assets/AGENTS.md +2 -2
  2. package/assets/agents/CODER.json +4 -0
  3. package/assets/agents/CREATOR.json +1 -0
  4. package/assets/agents/DOCS.json +2 -1
  5. package/assets/agents/INTEGRATOR.json +2 -1
  6. package/assets/agents/ORCHESTRATOR.json +2 -0
  7. package/assets/agents/PLANNER.json +3 -1
  8. package/assets/agents/REVIEWER.json +1 -0
  9. package/assets/agents/TESTER.json +2 -2
  10. package/assets/agents/UPDATER.json +1 -0
  11. package/assets/agents/UPGRADER.json +1 -1
  12. package/assets/policy/governance.md +3 -4
  13. package/assets/policy/incidents.md +20 -88
  14. package/assets/policy/workflow.branch_pr.md +1 -1
  15. package/assets/policy/workflow.direct.md +2 -2
  16. package/bin/agentplane.js +114 -4
  17. package/bin/runtime-watch.js +1 -0
  18. package/bin/stale-dist-policy.d.ts +1 -1
  19. package/bin/stale-dist-policy.js +19 -1
  20. package/dist/.build-manifest.json +251 -166
  21. package/dist/cli/bootstrap-guide.d.ts.map +1 -1
  22. package/dist/cli/bootstrap-guide.js +3 -2
  23. package/dist/cli/command-guide.d.ts.map +1 -1
  24. package/dist/cli/command-guide.js +2 -1
  25. package/dist/cli/command-invocations.d.ts.map +1 -1
  26. package/dist/cli/command-invocations.js +4 -1
  27. package/dist/cli/run-cli/command-catalog/core.d.ts +1 -1
  28. package/dist/cli/run-cli/command-catalog/core.d.ts.map +1 -1
  29. package/dist/cli/run-cli/command-catalog/core.js +6 -1
  30. package/dist/cli/run-cli/command-catalog/project.d.ts +1 -1
  31. package/dist/cli/run-cli/command-catalog/project.d.ts.map +1 -1
  32. package/dist/cli/run-cli/command-catalog/project.js +3 -1
  33. package/dist/cli/run-cli/command-catalog/task.d.ts +1 -1
  34. package/dist/cli/run-cli/command-catalog/task.d.ts.map +1 -1
  35. package/dist/cli/run-cli/command-catalog/task.js +10 -0
  36. package/dist/cli/run-cli/command-catalog.d.ts +1 -1
  37. package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
  38. package/dist/cli/run-cli/commands/core/preflight.d.ts.map +1 -1
  39. package/dist/cli/run-cli/commands/core/preflight.js +44 -1
  40. package/dist/cli/run-cli.test-helpers.d.ts +1 -0
  41. package/dist/cli/run-cli.test-helpers.d.ts.map +1 -1
  42. package/dist/cli/run-cli.test-helpers.js +26 -0
  43. package/dist/commands/branch/cleanup-merged.d.ts +3 -0
  44. package/dist/commands/branch/cleanup-merged.d.ts.map +1 -1
  45. package/dist/commands/branch/cleanup-merged.js +149 -36
  46. package/dist/commands/branch/work-start.d.ts.map +1 -1
  47. package/dist/commands/branch/work-start.js +137 -1
  48. package/dist/commands/cleanup/merged.command.d.ts +2 -0
  49. package/dist/commands/cleanup/merged.command.d.ts.map +1 -1
  50. package/dist/commands/cleanup/merged.command.js +24 -0
  51. package/dist/commands/doctor/branch-pr.d.ts +4 -0
  52. package/dist/commands/doctor/branch-pr.d.ts.map +1 -0
  53. package/dist/commands/doctor/branch-pr.js +96 -0
  54. package/dist/commands/doctor/fixes.d.ts +5 -0
  55. package/dist/commands/doctor/fixes.d.ts.map +1 -1
  56. package/dist/commands/doctor/fixes.js +70 -0
  57. package/dist/commands/doctor.run.d.ts.map +1 -1
  58. package/dist/commands/doctor.run.js +6 -1
  59. package/dist/commands/finish.run.d.ts.map +1 -1
  60. package/dist/commands/finish.run.js +11 -0
  61. package/dist/commands/finish.spec.d.ts +11 -0
  62. package/dist/commands/finish.spec.d.ts.map +1 -1
  63. package/dist/commands/finish.spec.js +51 -0
  64. package/dist/commands/guard/impl/close-message.d.ts.map +1 -1
  65. package/dist/commands/guard/impl/close-message.js +23 -6
  66. package/dist/commands/guard/impl/commands.d.ts +1 -0
  67. package/dist/commands/guard/impl/commands.d.ts.map +1 -1
  68. package/dist/commands/guard/impl/commands.js +94 -2
  69. package/dist/commands/guard/impl/env.d.ts +1 -0
  70. package/dist/commands/guard/impl/env.d.ts.map +1 -1
  71. package/dist/commands/guard/impl/env.js +1 -0
  72. package/dist/commands/hooks/index.d.ts +1 -1
  73. package/dist/commands/hooks/index.d.ts.map +1 -1
  74. package/dist/commands/hooks/index.js +139 -6
  75. package/dist/commands/incidents/collect.command.d.ts.map +1 -1
  76. package/dist/commands/incidents/collect.command.js +12 -7
  77. package/dist/commands/incidents/incidents.command.js +1 -1
  78. package/dist/commands/incidents/shared.d.ts +34 -0
  79. package/dist/commands/incidents/shared.d.ts.map +1 -1
  80. package/dist/commands/incidents/shared.js +166 -12
  81. package/dist/commands/pr/check.d.ts.map +1 -1
  82. package/dist/commands/pr/check.js +241 -135
  83. package/dist/commands/pr/close-superseded.d.ts +9 -0
  84. package/dist/commands/pr/close-superseded.d.ts.map +1 -0
  85. package/dist/commands/pr/close-superseded.js +129 -0
  86. package/dist/commands/pr/close.d.ts +11 -0
  87. package/dist/commands/pr/close.d.ts.map +1 -0
  88. package/dist/commands/pr/close.js +116 -0
  89. package/dist/commands/pr/index.d.ts +2 -0
  90. package/dist/commands/pr/index.d.ts.map +1 -1
  91. package/dist/commands/pr/index.js +2 -0
  92. package/dist/commands/pr/integrate/artifacts.d.ts +7 -0
  93. package/dist/commands/pr/integrate/artifacts.d.ts.map +1 -1
  94. package/dist/commands/pr/integrate/artifacts.js +66 -1
  95. package/dist/commands/pr/integrate/cmd.d.ts.map +1 -1
  96. package/dist/commands/pr/integrate/cmd.js +43 -2
  97. package/dist/commands/pr/integrate/internal/bootstrap-guidance.d.ts +8 -0
  98. package/dist/commands/pr/integrate/internal/bootstrap-guidance.d.ts.map +1 -0
  99. package/dist/commands/pr/integrate/internal/bootstrap-guidance.js +59 -0
  100. package/dist/commands/pr/integrate/internal/cleanup.d.ts +1 -11
  101. package/dist/commands/pr/integrate/internal/cleanup.d.ts.map +1 -1
  102. package/dist/commands/pr/integrate/internal/cleanup.js +1 -46
  103. package/dist/commands/pr/integrate/internal/finalize.d.ts.map +1 -1
  104. package/dist/commands/pr/integrate/internal/finalize.js +43 -12
  105. package/dist/commands/pr/integrate/internal/github-protection.d.ts +5 -0
  106. package/dist/commands/pr/integrate/internal/github-protection.d.ts.map +1 -0
  107. package/dist/commands/pr/integrate/internal/github-protection.js +13 -0
  108. package/dist/commands/pr/integrate/internal/merge.d.ts.map +1 -1
  109. package/dist/commands/pr/integrate/internal/merge.js +36 -13
  110. package/dist/commands/pr/integrate/internal/post-integrate-bootstrap.d.ts +13 -0
  111. package/dist/commands/pr/integrate/internal/post-integrate-bootstrap.d.ts.map +1 -0
  112. package/dist/commands/pr/integrate/internal/post-integrate-bootstrap.js +25 -0
  113. package/dist/commands/pr/integrate/internal/pre-integrate-bootstrap.d.ts +15 -0
  114. package/dist/commands/pr/integrate/internal/pre-integrate-bootstrap.d.ts.map +1 -0
  115. package/dist/commands/pr/integrate/internal/pre-integrate-bootstrap.js +35 -0
  116. package/dist/commands/pr/integrate/internal/prepare.d.ts +4 -2
  117. package/dist/commands/pr/integrate/internal/prepare.d.ts.map +1 -1
  118. package/dist/commands/pr/integrate/internal/prepare.js +109 -38
  119. package/dist/commands/pr/internal/auto-commit.d.ts +7 -0
  120. package/dist/commands/pr/internal/auto-commit.d.ts.map +1 -0
  121. package/dist/commands/pr/internal/auto-commit.js +64 -0
  122. package/dist/commands/pr/internal/freshness.d.ts +21 -0
  123. package/dist/commands/pr/internal/freshness.d.ts.map +1 -0
  124. package/dist/commands/pr/internal/freshness.js +52 -0
  125. package/dist/commands/pr/internal/gh-api.d.ts +6 -0
  126. package/dist/commands/pr/internal/gh-api.d.ts.map +1 -0
  127. package/dist/commands/pr/internal/gh-api.js +80 -0
  128. package/dist/commands/pr/internal/pr-paths.d.ts +10 -0
  129. package/dist/commands/pr/internal/pr-paths.d.ts.map +1 -1
  130. package/dist/commands/pr/internal/pr-paths.js +10 -0
  131. package/dist/commands/pr/internal/review-template.d.ts.map +1 -1
  132. package/dist/commands/pr/internal/review-template.js +37 -4
  133. package/dist/commands/pr/internal/sync.d.ts +9 -0
  134. package/dist/commands/pr/internal/sync.d.ts.map +1 -1
  135. package/dist/commands/pr/internal/sync.js +531 -124
  136. package/dist/commands/pr/open.d.ts +1 -0
  137. package/dist/commands/pr/open.d.ts.map +1 -1
  138. package/dist/commands/pr/open.js +24 -2
  139. package/dist/commands/pr/pr.command.d.ts +15 -0
  140. package/dist/commands/pr/pr.command.d.ts.map +1 -1
  141. package/dist/commands/pr/pr.command.js +118 -2
  142. package/dist/commands/pr/update.d.ts.map +1 -1
  143. package/dist/commands/pr/update.js +71 -2
  144. package/dist/commands/release/apply.command.d.ts +3 -1
  145. package/dist/commands/release/apply.command.d.ts.map +1 -1
  146. package/dist/commands/release/apply.command.js +356 -34
  147. package/dist/commands/release/apply.mutation.d.ts.map +1 -1
  148. package/dist/commands/release/apply.mutation.js +1 -0
  149. package/dist/commands/release/apply.preflight.d.ts.map +1 -1
  150. package/dist/commands/release/apply.preflight.js +1 -1
  151. package/dist/commands/release/apply.reporting.d.ts +1 -0
  152. package/dist/commands/release/apply.reporting.d.ts.map +1 -1
  153. package/dist/commands/release/apply.reporting.js +12 -8
  154. package/dist/commands/release/apply.types.d.ts +13 -0
  155. package/dist/commands/release/apply.types.d.ts.map +1 -1
  156. package/dist/commands/release/plan.command.d.ts.map +1 -1
  157. package/dist/commands/release/plan.command.js +48 -0
  158. package/dist/commands/shared/gh-transport.d.ts +16 -0
  159. package/dist/commands/shared/gh-transport.d.ts.map +1 -0
  160. package/dist/commands/shared/gh-transport.js +71 -0
  161. package/dist/commands/shared/git-diff.d.ts +3 -1
  162. package/dist/commands/shared/git-diff.d.ts.map +1 -1
  163. package/dist/commands/shared/git-diff.js +10 -2
  164. package/dist/commands/shared/git-ops.d.ts +1 -0
  165. package/dist/commands/shared/git-ops.d.ts.map +1 -1
  166. package/dist/commands/shared/git-ops.js +15 -0
  167. package/dist/commands/shared/git-worktree.d.ts +2 -0
  168. package/dist/commands/shared/git-worktree.d.ts.map +1 -1
  169. package/dist/commands/shared/git-worktree.js +22 -2
  170. package/dist/commands/shared/merged-branch-cleanup.d.ts +12 -0
  171. package/dist/commands/shared/merged-branch-cleanup.d.ts.map +1 -0
  172. package/dist/commands/shared/merged-branch-cleanup.js +46 -0
  173. package/dist/commands/shared/post-commit-pr-artifacts.d.ts +9 -0
  174. package/dist/commands/shared/post-commit-pr-artifacts.d.ts.map +1 -0
  175. package/dist/commands/shared/post-commit-pr-artifacts.js +57 -0
  176. package/dist/commands/shared/pr-meta.d.ts +20 -0
  177. package/dist/commands/shared/pr-meta.d.ts.map +1 -1
  178. package/dist/commands/shared/pr-meta.js +125 -0
  179. package/dist/commands/shared/task-backend.d.ts +7 -0
  180. package/dist/commands/shared/task-backend.d.ts.map +1 -1
  181. package/dist/commands/shared/task-backend.js +71 -27
  182. package/dist/commands/shared/task-local-freshness.d.ts +2 -0
  183. package/dist/commands/shared/task-local-freshness.d.ts.map +1 -1
  184. package/dist/commands/shared/task-local-freshness.js +7 -1
  185. package/dist/commands/task/close-duplicate.d.ts.map +1 -1
  186. package/dist/commands/task/close-duplicate.js +34 -1
  187. package/dist/commands/task/derive.js +1 -1
  188. package/dist/commands/task/doc-template.d.ts.map +1 -1
  189. package/dist/commands/task/doc-template.js +7 -11
  190. package/dist/commands/task/findings-add.command.d.ts +20 -0
  191. package/dist/commands/task/findings-add.command.d.ts.map +1 -0
  192. package/dist/commands/task/findings-add.command.js +165 -0
  193. package/dist/commands/task/findings.command.d.ts +7 -0
  194. package/dist/commands/task/findings.command.d.ts.map +1 -0
  195. package/dist/commands/task/findings.command.js +20 -0
  196. package/dist/commands/task/findings.d.ts +63 -0
  197. package/dist/commands/task/findings.d.ts.map +1 -0
  198. package/dist/commands/task/findings.js +188 -0
  199. package/dist/commands/task/finish-shared.d.ts +2 -0
  200. package/dist/commands/task/finish-shared.d.ts.map +1 -1
  201. package/dist/commands/task/finish-shared.js +56 -1
  202. package/dist/commands/task/finish.d.ts +10 -0
  203. package/dist/commands/task/finish.d.ts.map +1 -1
  204. package/dist/commands/task/finish.js +125 -6
  205. package/dist/commands/task/hosted-close-pr.command.d.ts +11 -0
  206. package/dist/commands/task/hosted-close-pr.command.d.ts.map +1 -0
  207. package/dist/commands/task/hosted-close-pr.command.js +449 -0
  208. package/dist/commands/task/hosted-close.command.d.ts.map +1 -1
  209. package/dist/commands/task/hosted-close.command.js +234 -19
  210. package/dist/commands/task/hosted-merge-sync.d.ts +41 -0
  211. package/dist/commands/task/hosted-merge-sync.d.ts.map +1 -1
  212. package/dist/commands/task/hosted-merge-sync.js +291 -17
  213. package/dist/commands/task/index.d.ts +1 -0
  214. package/dist/commands/task/index.d.ts.map +1 -1
  215. package/dist/commands/task/index.js +1 -0
  216. package/dist/commands/task/new.d.ts +1 -0
  217. package/dist/commands/task/new.d.ts.map +1 -1
  218. package/dist/commands/task/new.js +71 -1
  219. package/dist/commands/task/new.spec.d.ts.map +1 -1
  220. package/dist/commands/task/new.spec.js +7 -0
  221. package/dist/commands/task/normalize.command.d.ts +2 -0
  222. package/dist/commands/task/normalize.command.d.ts.map +1 -1
  223. package/dist/commands/task/normalize.command.js +45 -0
  224. package/dist/commands/task/normalize.d.ts +2 -0
  225. package/dist/commands/task/normalize.d.ts.map +1 -1
  226. package/dist/commands/task/normalize.js +85 -8
  227. package/dist/commands/task/plan.d.ts.map +1 -1
  228. package/dist/commands/task/plan.js +7 -10
  229. package/dist/commands/task/shared/docs.d.ts +6 -0
  230. package/dist/commands/task/shared/docs.d.ts.map +1 -1
  231. package/dist/commands/task/shared/docs.js +14 -0
  232. package/dist/commands/task/shared/transitions.d.ts.map +1 -1
  233. package/dist/commands/task/shared/transitions.js +11 -1
  234. package/dist/commands/task/shared.d.ts +1 -1
  235. package/dist/commands/task/shared.d.ts.map +1 -1
  236. package/dist/commands/task/shared.js +1 -1
  237. package/dist/commands/task/start.d.ts.map +1 -1
  238. package/dist/commands/task/start.js +7 -10
  239. package/dist/commands/task/task.command.d.ts.map +1 -1
  240. package/dist/commands/task/task.command.js +4 -0
  241. package/dist/commands/task/verify-command-shared.d.ts +19 -0
  242. package/dist/commands/task/verify-command-shared.d.ts.map +1 -1
  243. package/dist/commands/task/verify-command-shared.js +152 -1
  244. package/dist/commands/task/verify-ok.command.d.ts.map +1 -1
  245. package/dist/commands/task/verify-ok.command.js +15 -2
  246. package/dist/commands/task/verify-record.d.ts +36 -0
  247. package/dist/commands/task/verify-record.d.ts.map +1 -1
  248. package/dist/commands/task/verify-record.js +166 -11
  249. package/dist/commands/task/verify-rework.command.d.ts.map +1 -1
  250. package/dist/commands/task/verify-rework.command.js +15 -2
  251. package/dist/commands/task/verify-show.command.d.ts +1 -1
  252. package/dist/commands/task/verify-show.command.d.ts.map +1 -1
  253. package/dist/commands/task/verify-show.command.js +28 -1
  254. package/dist/commands/verify.run.d.ts.map +1 -1
  255. package/dist/commands/verify.run.js +12 -0
  256. package/dist/commands/verify.spec.d.ts +2 -6
  257. package/dist/commands/verify.spec.d.ts.map +1 -1
  258. package/dist/commands/verify.spec.js +30 -3
  259. package/dist/runtime/incidents/index.d.ts +1 -1
  260. package/dist/runtime/incidents/index.d.ts.map +1 -1
  261. package/dist/runtime/incidents/resolve.d.ts.map +1 -1
  262. package/dist/runtime/incidents/resolve.js +319 -73
  263. package/dist/runtime/incidents/types.d.ts +14 -2
  264. package/dist/runtime/incidents/types.d.ts.map +1 -1
  265. package/dist/shared/env.d.ts +1 -0
  266. package/dist/shared/env.d.ts.map +1 -1
  267. package/dist/shared/env.js +22 -1
  268. package/dist/shared/protected-paths.d.ts +1 -1
  269. package/dist/shared/protected-paths.d.ts.map +1 -1
  270. package/dist/shared/protected-paths.js +4 -0
  271. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"work-start.d.ts","sourceRoot":"","sources":["../../../src/commands/branch/work-start.ts"],"names":[],"mappings":"AAeA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAiInC,wBAAsB,YAAY,CAAC,IAAI,EAAE;IACvC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqJlB"}
1
+ {"version":3,"file":"work-start.d.ts","sourceRoot":"","sources":["../../../src/commands/branch/work-start.ts"],"names":[],"mappings":"AA0BA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAsRnC,wBAAsB,YAAY,CAAC,IAAI,EAAE;IACvC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,CAAC,CA+JlB"}
@@ -1,4 +1,4 @@
1
- import { copyFile, mkdir, readFile, readdir, writeFile } from "node:fs/promises";
1
+ import { chmod, copyFile, cp, mkdir, readFile, readdir, rm, symlink, writeFile, } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { resolveBaseBranch } from "@agentplaneorg/core";
4
4
  import { LocalBackend } from "../../backends/task-backend.js";
@@ -11,9 +11,40 @@ import { execFileAsync, gitEnv } from "../shared/git.js";
11
11
  import { gitAheadBehind } from "../shared/git-diff.js";
12
12
  import { gitBranchExists, gitBranchUpstream, gitCurrentBranch } from "../shared/git-ops.js";
13
13
  import { isPathWithin } from "../shared/path.js";
14
+ import { resolveRuntimeSourceInfo } from "../../shared/runtime-source.js";
14
15
  import { loadBackendTask, loadCommandContext, } from "../shared/task-backend.js";
16
+ function isPresentString(value) {
17
+ return value !== null;
18
+ }
15
19
  import { ensurePlanApprovedIfRequired } from "../task/shared.js";
16
20
  import { validateWorkAgent, validateWorkSlug } from "./internal/work-validate.js";
21
+ const HOOK_SHIM_MARKER = "agentplane-hook-shim";
22
+ function repoLocalHookShimText() {
23
+ return [
24
+ "#!/usr/bin/env sh",
25
+ `# ${HOOK_SHIM_MARKER} (do not edit)`,
26
+ "set -e",
27
+ 'SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"',
28
+ 'REPO_ROOT="$(dirname "$(dirname "$SCRIPT_DIR")")"',
29
+ 'LOCAL_BIN="$REPO_ROOT/packages/agentplane/bin/agentplane.js"',
30
+ 'if command -v node >/dev/null 2>&1 && [ -f "$LOCAL_BIN" ]; then',
31
+ ' exec node "$LOCAL_BIN" "$@"',
32
+ "fi",
33
+ 'ENV_BIN="${AGENTPLANE_HOOK_RUNNER:-}"',
34
+ 'if [ -n "$ENV_BIN" ] && command -v node >/dev/null 2>&1 && [ -f "$ENV_BIN" ]; then',
35
+ ' exec node "$ENV_BIN" "$@"',
36
+ "fi",
37
+ "if command -v agentplane >/dev/null 2>&1; then",
38
+ ' exec agentplane "$@"',
39
+ "fi",
40
+ "if command -v npx >/dev/null 2>&1; then",
41
+ ' exec npx --yes agentplane "$@"',
42
+ "fi",
43
+ 'echo "agentplane shim: runner not found (need env runner, repo-local source, agentplane in PATH, or node+npx)." >&2',
44
+ " exit 127",
45
+ "",
46
+ ].join("\n");
47
+ }
17
48
  function directWorkLockPath(agentplaneDir) {
18
49
  // Intentionally under cache/ so it stays out of git by default.
19
50
  return path.join(agentplaneDir, "cache", "direct-work.json");
@@ -54,13 +85,108 @@ async function materializeLocalBackendReadmesForWorktree(opts) {
54
85
  for (const entry of entries) {
55
86
  if (!entry.isDirectory())
56
87
  continue;
88
+ const sourceTaskRoot = path.join(sourceRoot, entry.name);
57
89
  const sourceReadme = path.join(sourceRoot, entry.name, "README.md");
58
90
  if (!(await fileExists(sourceReadme)))
59
91
  continue;
60
92
  const targetReadme = path.join(targetRoot, entry.name, "README.md");
61
93
  await mkdir(path.dirname(targetReadme), { recursive: true });
62
94
  await copyFile(sourceReadme, targetReadme);
95
+ if (entry.name !== opts.taskId)
96
+ continue;
97
+ // Hand off ownership of the active task README to the task worktree so
98
+ // later merges cannot collide with a stale untracked copy on the base checkout.
99
+ await rm(sourceReadme, { force: true });
100
+ const remainingEntries = await readdir(sourceTaskRoot).catch(() => []);
101
+ if (remainingEntries.length === 0) {
102
+ await rm(sourceTaskRoot, { recursive: true, force: true });
103
+ }
104
+ }
105
+ }
106
+ async function materializeRepoLocalDistForWorktree(opts) {
107
+ const runtimeSource = resolveRuntimeSourceInfo({ cwd: process.cwd() });
108
+ const sourceRoots = [
109
+ ...new Set([
110
+ path.resolve(opts.repoRoot),
111
+ path.resolve(process.cwd()),
112
+ runtimeSource.agentplane.packageRoot
113
+ ? path.resolve(runtimeSource.agentplane.packageRoot, "..", "..")
114
+ : null,
115
+ ].filter((value) => isPresentString(value))),
116
+ ];
117
+ const copyTargets = [
118
+ ["packages/core/dist", "packages/core/dist"],
119
+ ["packages/agentplane/dist", "packages/agentplane/dist"],
120
+ ["packages/agentplane/bin", "packages/agentplane/bin"],
121
+ ];
122
+ for (const [sourceRelativePath, targetRelativePath] of copyTargets) {
123
+ let sourcePath = "";
124
+ for (const sourceRoot of sourceRoots) {
125
+ const candidate = path.join(sourceRoot, sourceRelativePath);
126
+ if (await fileExists(candidate)) {
127
+ sourcePath = candidate;
128
+ break;
129
+ }
130
+ }
131
+ if (!sourcePath)
132
+ continue;
133
+ const targetPath = path.join(opts.worktreePath, targetRelativePath);
134
+ if (await fileExists(targetPath))
135
+ continue;
136
+ await mkdir(path.dirname(targetPath), { recursive: true });
137
+ await cp(sourcePath, targetPath, { recursive: true });
138
+ }
139
+ }
140
+ async function linkDirectoryIntoWorktree(opts) {
141
+ let sourcePath = "";
142
+ for (const sourceRoot of opts.sourceRoots) {
143
+ const candidate = path.join(sourceRoot, opts.relativePath);
144
+ if (await fileExists(candidate)) {
145
+ sourcePath = candidate;
146
+ break;
147
+ }
63
148
  }
149
+ if (!sourcePath)
150
+ return false;
151
+ const targetPath = path.join(opts.worktreePath, opts.relativePath);
152
+ if (await fileExists(targetPath))
153
+ return false;
154
+ await mkdir(path.dirname(targetPath), { recursive: true });
155
+ await symlink(sourcePath, targetPath, process.platform === "win32" ? "junction" : "dir");
156
+ return true;
157
+ }
158
+ async function materializeRepoLocalInstallLayoutForWorktree(opts) {
159
+ const runtimeSource = resolveRuntimeSourceInfo({ cwd: process.cwd() });
160
+ const sourceRoots = [
161
+ ...new Set([
162
+ path.resolve(opts.repoRoot),
163
+ path.resolve(process.cwd()),
164
+ runtimeSource.agentplane.packageRoot
165
+ ? path.resolve(runtimeSource.agentplane.packageRoot, "..", "..")
166
+ : null,
167
+ ].filter((value) => isPresentString(value))),
168
+ ];
169
+ const linkTargets = [
170
+ "node_modules",
171
+ path.join("packages", "core", "node_modules"),
172
+ path.join("packages", "agentplane", "node_modules"),
173
+ "agentplane-recipes",
174
+ ];
175
+ for (const relativePath of linkTargets) {
176
+ await linkDirectoryIntoWorktree({
177
+ sourceRoots,
178
+ worktreePath: opts.worktreePath,
179
+ relativePath,
180
+ });
181
+ }
182
+ }
183
+ async function materializeHookShimForWorktree(worktreePath) {
184
+ const shimPath = path.join(worktreePath, ".agentplane", "bin", "agentplane");
185
+ if (await fileExists(shimPath))
186
+ return;
187
+ await mkdir(path.dirname(shimPath), { recursive: true });
188
+ await writeFile(shimPath, repoLocalHookShimText(), "utf8");
189
+ await chmod(shimPath, 0o755);
64
190
  }
65
191
  async function ensureGitClean(gitRoot) {
66
192
  const { stdout } = await execFileAsync("git", ["status", "--porcelain"], {
@@ -227,7 +353,17 @@ export async function cmdWorkStart(opts) {
227
353
  backend: ctx.taskBackend,
228
354
  repoRoot: resolved.gitRoot,
229
355
  worktreePath,
356
+ taskId: opts.taskId,
357
+ });
358
+ await materializeRepoLocalDistForWorktree({
359
+ repoRoot: resolved.gitRoot,
360
+ worktreePath,
361
+ });
362
+ await materializeRepoLocalInstallLayoutForWorktree({
363
+ repoRoot: resolved.gitRoot,
364
+ worktreePath,
230
365
  });
366
+ await materializeHookShimForWorktree(worktreePath);
231
367
  }
232
368
  else {
233
369
  if (branchExists) {
@@ -7,6 +7,8 @@ export type CleanupMergedParsed = {
7
7
  base: string | null;
8
8
  yes: boolean;
9
9
  archive: boolean;
10
+ deleteRemoteBranches: boolean;
11
+ fetch: boolean;
10
12
  quiet: boolean;
11
13
  };
12
14
  export declare const cleanupMergedSpec: CommandSpec<CleanupMergedParsed>;
@@ -1 +1 @@
1
- {"version":3,"file":"merged.command.d.ts","sourceRoot":"","sources":["../../../src/commands/cleanup/merged.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,KAAK,kBAAkB,GAAG,kBAAkB,CAAC;AAE7C,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,kBAAkB,CAUvD,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,mBAAmB,CAkC9D,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,cAAc,CAAC,kBAAkB,CAQzD,CAAC;AAEF,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IAC5E,KAAK,UAAU,EAAE,GAAG,mBAAmB,KAAG,OAAO,CAAC,MAAM,CAAC,CAWxE"}
1
+ {"version":3,"file":"merged.command.d.ts","sourceRoot":"","sources":["../../../src/commands/cleanup/merged.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AACtF,OAAO,EAIL,KAAK,kBAAkB,EACxB,MAAM,4BAA4B,CAAC;AAEpC,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,KAAK,kBAAkB,GAAG,kBAAkB,CAAC;AAE7C,eAAO,MAAM,WAAW,EAAE,WAAW,CAAC,kBAAkB,CAUvD,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,GAAG,EAAE,OAAO,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,oBAAoB,EAAE,OAAO,CAAC;IAC9B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,WAAW,CAAC,mBAAmB,CAwD9D,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,cAAc,CAAC,kBAAkB,CAQzD,CAAC;AAEF,wBAAgB,2BAA2B,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IAC5E,KAAK,UAAU,EAAE,GAAG,mBAAmB,KAAG,OAAO,CAAC,MAAM,CAAC,CAaxE"}
@@ -25,6 +25,18 @@ export const cleanupMergedSpec = {
25
25
  default: false,
26
26
  description: "Archive PR artifacts before deletion.",
27
27
  },
28
+ {
29
+ kind: "boolean",
30
+ name: "delete-remote-branches",
31
+ default: false,
32
+ description: "Also delete matching remote task branches on origin.",
33
+ },
34
+ {
35
+ kind: "boolean",
36
+ name: "fetch",
37
+ default: false,
38
+ description: "Fetch and prune origin before candidate resolution.",
39
+ },
28
40
  { kind: "boolean", name: "quiet", default: false, description: "Reduce output noise." },
29
41
  ],
30
42
  examples: [
@@ -33,6 +45,14 @@ export const cleanupMergedSpec = {
33
45
  cmd: "agentplane cleanup merged --yes --archive",
34
46
  why: "Delete candidates and archive PR artifacts.",
35
47
  },
48
+ {
49
+ cmd: "agentplane cleanup merged --yes --delete-remote-branches",
50
+ why: "Delete candidates and matching remote task branches on origin.",
51
+ },
52
+ {
53
+ cmd: "agentplane cleanup merged --fetch",
54
+ why: "Refresh origin before evaluating cleanup candidates.",
55
+ },
36
56
  ],
37
57
  validateRaw: (raw) => {
38
58
  const base = typeof raw.opts.base === "string" ? raw.opts.base.trim() : "";
@@ -44,6 +64,8 @@ export const cleanupMergedSpec = {
44
64
  base: typeof raw.opts.base === "string" ? raw.opts.base : null,
45
65
  yes: raw.opts.yes === true,
46
66
  archive: raw.opts.archive === true,
67
+ deleteRemoteBranches: raw.opts["delete-remote-branches"] === true,
68
+ fetch: raw.opts.fetch === true,
47
69
  quiet: raw.opts.quiet === true,
48
70
  }),
49
71
  };
@@ -65,6 +87,8 @@ export function makeRunCleanupMergedHandler(getCtx) {
65
87
  base: p.base ?? undefined,
66
88
  yes: p.yes,
67
89
  archive: p.archive,
90
+ deleteRemoteBranches: p.deleteRemoteBranches,
91
+ fetch: p.fetch,
68
92
  quiet: p.quiet,
69
93
  });
70
94
  };
@@ -0,0 +1,4 @@
1
+ import type { CommandContext } from "../shared/task-backend.js";
2
+ export declare function checkBranchPrShippedTaskDrift(ctx?: CommandContext): Promise<string[]>;
3
+ export declare function checkBranchPrDoneTaskOpenPrDrift(ctx?: CommandContext): Promise<string[]>;
4
+ //# sourceMappingURL=branch-pr.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"branch-pr.d.ts","sourceRoot":"","sources":["../../../src/commands/doctor/branch-pr.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAMhE,wBAAsB,6BAA6B,CAAC,GAAG,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAuC3F;AAED,wBAAsB,gCAAgC,CAAC,GAAG,CAAC,EAAE,cAAc,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAkC9F"}
@@ -0,0 +1,96 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { renderDiagnosticFinding } from "../../shared/diagnostics.js";
4
+ import { findDoneBranchPrTasksWithOpenPrArtifacts, findLocallyShippedBranchPrTasks, } from "../task/hosted-merge-sync.js";
5
+ export async function checkBranchPrShippedTaskDrift(ctx) {
6
+ if (ctx?.backendId !== "local" || ctx.config.workflow_mode !== "branch_pr")
7
+ return [];
8
+ let tasks = [];
9
+ try {
10
+ tasks = await ctx.taskBackend.listTasks();
11
+ }
12
+ catch {
13
+ return [];
14
+ }
15
+ if (tasks.length === 0)
16
+ return [];
17
+ const matches = await findLocallyShippedBranchPrTasks({ ctx, tasks });
18
+ if (matches.length === 0)
19
+ return [];
20
+ const examples = matches
21
+ .slice(0, 5)
22
+ .map((entry) => `${entry.taskId}@${entry.base}:${entry.commitHash.slice(0, 12)} verified_via=${entry.verificationSource}`)
23
+ .join(", ");
24
+ return [
25
+ renderDiagnosticFinding({
26
+ severity: "WARN",
27
+ state: "branch_pr tasks appear shipped on the base branch but remain open",
28
+ likelyCause: "the verified task commit already landed on the base branch, but canonical task closure artifacts were never reconciled",
29
+ nextAction: {
30
+ command: "agentplane task normalize --sync-branch-pr-state",
31
+ reason: "mark locally shipped branch_pr tasks as DONE in the task projection before committing the reconciled task artifacts on the base branch",
32
+ },
33
+ details: [
34
+ `Affected tasks: ${matches.length}`,
35
+ examples ? `Examples: ${examples}` : "Examples unavailable.",
36
+ ],
37
+ }),
38
+ ];
39
+ }
40
+ export async function checkBranchPrDoneTaskOpenPrDrift(ctx) {
41
+ if (ctx?.backendId !== "local" || ctx.config.workflow_mode !== "branch_pr")
42
+ return [];
43
+ const tasks = await readDoneTaskSnapshot(ctx);
44
+ if (tasks.length === 0)
45
+ return [];
46
+ const matches = await findDoneBranchPrTasksWithOpenPrArtifacts({ ctx, tasks });
47
+ if (matches.length === 0)
48
+ return [];
49
+ const examples = matches
50
+ .slice(0, 5)
51
+ .map((entry) => `${entry.taskId}@${entry.base}:${entry.commitHash.slice(0, 12)} branch=${entry.branch}`)
52
+ .join(", ");
53
+ return [
54
+ renderDiagnosticFinding({
55
+ severity: "WARN",
56
+ state: "DONE branch_pr tasks still have open or unmerged PR artifacts",
57
+ likelyCause: "the task was marked DONE, but its branch_pr PR artifacts were never reconciled to MERGED and the task branch still exists",
58
+ nextAction: {
59
+ command: "agentplane task normalize --sync-branch-pr-state --task-id <task-id>",
60
+ reason: "reconcile the shipped task's local branch_pr state and PR artifacts to MERGED without scanning unrelated task history",
61
+ },
62
+ details: [
63
+ `Affected tasks: ${matches.length}`,
64
+ examples ? `Examples: ${examples}` : "Examples unavailable.",
65
+ ],
66
+ }),
67
+ ];
68
+ }
69
+ async function readDoneTaskSnapshot(ctx) {
70
+ try {
71
+ const tasks = await ctx.taskBackend.listTasks();
72
+ if (tasks.length > 0) {
73
+ return tasks;
74
+ }
75
+ }
76
+ catch {
77
+ // Fall back to the legacy export snapshot when the live backend read is unavailable.
78
+ }
79
+ const tasksJsonPath = path.join(ctx.resolvedProject.agentplaneDir, "tasks.json");
80
+ try {
81
+ const raw = await readFile(tasksJsonPath, "utf8");
82
+ const parsed = JSON.parse(raw);
83
+ if (!Array.isArray(parsed.tasks))
84
+ return [];
85
+ return parsed.tasks.filter((task) => isTaskDataLike(task));
86
+ }
87
+ catch {
88
+ return [];
89
+ }
90
+ }
91
+ function isTaskDataLike(value) {
92
+ if (!value || typeof value !== "object" || Array.isArray(value))
93
+ return false;
94
+ const record = value;
95
+ return typeof record.id === "string" && typeof record.status === "string";
96
+ }
@@ -1,3 +1,4 @@
1
+ import type { CommandContext } from "../shared/task-backend.js";
1
2
  export declare function safeFixGitignore(repoRoot: string): Promise<{
2
3
  changed: boolean;
3
4
  note: string;
@@ -6,4 +7,8 @@ export declare function safeFixTaskIndex(repoRoot: string): Promise<{
6
7
  changed: boolean;
7
8
  note: string;
8
9
  }>;
10
+ export declare function safeFixLegacyUntrackedTaskReadmes(repoRoot: string, ctx?: CommandContext): Promise<{
11
+ changed: boolean;
12
+ note: string;
13
+ }>;
9
14
  //# sourceMappingURL=fixes.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"fixes.d.ts","sourceRoot":"","sources":["../../../src/commands/doctor/fixes.ts"],"names":[],"mappings":"AAMA,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAyB7C;AAED,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAQ7C"}
1
+ {"version":3,"file":"fixes.d.ts","sourceRoot":"","sources":["../../../src/commands/doctor/fixes.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAEhE,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAyB7C;AAED,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAQ7C;AAED,wBAAsB,iCAAiC,CACrD,QAAQ,EAAE,MAAM,EAChB,GAAG,CAAC,EAAE,cAAc,GACnB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CA8E7C"}
@@ -1,6 +1,8 @@
1
1
  import fs from "node:fs/promises";
2
2
  import path from "node:path";
3
+ import { parseTaskReadme } from "@agentplaneorg/core";
3
4
  import { RUNTIME_GITIGNORE_LINES } from "../../shared/runtime-artifacts.js";
5
+ import { GitContext } from "../shared/git-context.js";
4
6
  import { loadCommandContext } from "../shared/task-backend.js";
5
7
  export async function safeFixGitignore(repoRoot) {
6
8
  const gitignorePath = path.join(repoRoot, ".gitignore");
@@ -38,3 +40,71 @@ export async function safeFixTaskIndex(repoRoot) {
38
40
  return { changed: false, note: "Skip: could not rebuild tasks index cache." };
39
41
  }
40
42
  }
43
+ export async function safeFixLegacyUntrackedTaskReadmes(repoRoot, ctx) {
44
+ const commandCtx = ctx ??
45
+ (await loadCommandContext({
46
+ cwd: repoRoot,
47
+ rootOverride: null,
48
+ }));
49
+ const workflowDir = (commandCtx.config.paths.workflow_dir ?? ".agentplane/tasks").replaceAll("\\", "/");
50
+ const git = commandCtx.git ?? new GitContext({ gitRoot: repoRoot });
51
+ let untracked = [];
52
+ try {
53
+ untracked = await git.statusUntrackedPaths();
54
+ }
55
+ catch {
56
+ return { changed: false, note: "Skip: could not inspect untracked task README collisions." };
57
+ }
58
+ const candidates = untracked.filter((relPath) => relPath.startsWith(`${workflowDir}/`) && relPath.endsWith("/README.md"));
59
+ if (candidates.length === 0) {
60
+ return { changed: false, note: "OK: no legacy untracked task README collisions." };
61
+ }
62
+ const removed = [];
63
+ for (const relPath of candidates) {
64
+ const absPath = path.join(repoRoot, relPath);
65
+ let text = "";
66
+ try {
67
+ text = await fs.readFile(absPath, "utf8");
68
+ }
69
+ catch {
70
+ continue;
71
+ }
72
+ let parsed;
73
+ try {
74
+ parsed = parseTaskReadme(text);
75
+ }
76
+ catch {
77
+ continue;
78
+ }
79
+ const taskId = path.basename(path.dirname(absPath));
80
+ const parsedId = typeof parsed.frontmatter.id === "string" && parsed.frontmatter.id.trim().length > 0
81
+ ? parsed.frontmatter.id.trim()
82
+ : taskId;
83
+ const status = typeof parsed.frontmatter.status === "string"
84
+ ? parsed.frontmatter.status.trim().toUpperCase()
85
+ : "";
86
+ if (parsedId !== taskId || status !== "DONE")
87
+ continue;
88
+ await fs.rm(absPath, { force: true });
89
+ try {
90
+ const remaining = await fs.readdir(path.dirname(absPath));
91
+ if (remaining.length === 0) {
92
+ await fs.rmdir(path.dirname(absPath));
93
+ }
94
+ }
95
+ catch {
96
+ // Ignore cleanup failures for parent directories; the file removal is the actual fix.
97
+ }
98
+ removed.push(taskId);
99
+ }
100
+ if (removed.length === 0) {
101
+ return {
102
+ changed: false,
103
+ note: "OK: no safe-to-remove legacy untracked DONE task README collisions.",
104
+ };
105
+ }
106
+ return {
107
+ changed: true,
108
+ note: `Fixed: removed legacy untracked DONE task README collisions (${removed.join(", ")}).`,
109
+ };
110
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.run.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.run.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAarD,eAAO,MAAM,SAAS,EAAE,cAAc,CAAC,YAAY,CA6DlD,CAAC"}
1
+ {"version":3,"file":"doctor.run.d.ts","sourceRoot":"","sources":["../../src/commands/doctor.run.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAqBrD,eAAO,MAAM,SAAS,EAAE,cAAc,CAAC,YAAY,CAiElD,CAAC"}
@@ -2,7 +2,8 @@ import { loadConfig, resolveProject } from "@agentplaneorg/core";
2
2
  import { warnMessage, successMessage } from "../cli/output.js";
3
3
  import { loadCommandContext } from "./shared/task-backend.js";
4
4
  import { checkDoneTaskCommitInvariants } from "./doctor/archive.js";
5
- import { safeFixGitignore, safeFixTaskIndex } from "./doctor/fixes.js";
5
+ import { checkBranchPrDoneTaskOpenPrDrift, checkBranchPrShippedTaskDrift, } from "./doctor/branch-pr.js";
6
+ import { safeFixGitignore, safeFixLegacyUntrackedTaskReadmes, safeFixTaskIndex, } from "./doctor/fixes.js";
6
7
  import { checkLayering } from "./doctor/layering.js";
7
8
  import { checkRuntimeSourceFacts, findingSeverity } from "./doctor/runtime.js";
8
9
  import { checkWorkspace } from "./doctor/workspace.js";
@@ -21,6 +22,8 @@ export const runDoctor = async (ctx, p) => {
21
22
  const runChecks = async () => {
22
23
  let checks = [
23
24
  ...(await checkWorkspace(repoRoot, { ctx: commandCtx })),
25
+ ...(await checkBranchPrShippedTaskDrift(commandCtx)),
26
+ ...(await checkBranchPrDoneTaskOpenPrDrift(commandCtx)),
24
27
  ...checkRuntimeSourceFacts(ctx.cwd, loadedConfig.config),
25
28
  ...(await checkDoneTaskCommitInvariants(repoRoot, { fullArchive: p.archiveFull })),
26
29
  ];
@@ -38,6 +41,8 @@ export const runDoctor = async (ctx, p) => {
38
41
  if (p.fix) {
39
42
  const fix = await safeFixGitignore(repoRoot);
40
43
  console.log(successMessage("doctor fix", undefined, fix.note));
44
+ const legacyTaskReadmes = await safeFixLegacyUntrackedTaskReadmes(repoRoot, commandCtx);
45
+ console.log(successMessage("doctor fix", undefined, legacyTaskReadmes.note));
41
46
  const idx = await safeFixTaskIndex(repoRoot);
42
47
  console.log(successMessage("doctor fix", undefined, idx.note));
43
48
  const workflowFix = await safeFixWorkflow(repoRoot);
@@ -1 +1 @@
1
- {"version":3,"file":"finish.run.d.ts","sourceRoot":"","sources":["../../src/commands/finish.run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG/D,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEjE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACrE,KAAK,UAAU,EAAE,GAAG,YAAY,KAAG,OAAO,CAAC,MAAM,CAAC,CAuCjE"}
1
+ {"version":3,"file":"finish.run.d.ts","sourceRoot":"","sources":["../../src/commands/finish.run.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,0BAA0B,CAAC;AAG/D,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAEjE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACrE,KAAK,UAAU,EAAE,GAAG,YAAY,KAAG,OAAO,CAAC,MAAM,CAAC,CAkDjE"}
@@ -38,6 +38,17 @@ export function makeRunFinishHandler(getCtx) {
38
38
  closeCommit: p.closeCommit,
39
39
  noCloseCommit: p.noCloseCommit,
40
40
  closeUnstageOthers: p.closeUnstageOthers,
41
+ baseBranchOverride: p.baseBranchOverride,
42
+ observation: p.observation,
43
+ impact: p.impact,
44
+ resolution: p.resolution,
45
+ localOnly: p.localOnly,
46
+ repoFixable: p.repoFixable,
47
+ incidentScope: p.incidentScope,
48
+ incidentTags: p.incidentTags,
49
+ incidentMatch: p.incidentMatch,
50
+ incidentAdvice: p.incidentAdvice,
51
+ incidentRule: p.incidentRule,
41
52
  quiet: p.quiet,
42
53
  });
43
54
  };
@@ -24,6 +24,17 @@ export type FinishParsed = {
24
24
  closeCommit: boolean;
25
25
  noCloseCommit: boolean;
26
26
  closeUnstageOthers: boolean;
27
+ baseBranchOverride?: string;
28
+ observation?: string;
29
+ impact?: string;
30
+ resolution?: string;
31
+ localOnly: boolean;
32
+ repoFixable: boolean;
33
+ incidentScope?: string;
34
+ incidentTags: string[];
35
+ incidentMatch: string[];
36
+ incidentAdvice?: string;
37
+ incidentRule?: string;
27
38
  quiet: boolean;
28
39
  };
29
40
  export declare const finishSpec: CommandSpec<FinishParsed>;
@@ -1 +1 @@
1
- {"version":3,"file":"finish.spec.d.ts","sourceRoot":"","sources":["../../src/commands/finish.spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASvD,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,wBAAwB,EAAE,OAAO,CAAC;IAClC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,CAqUhD,CAAC"}
1
+ {"version":3,"file":"finish.spec.d.ts","sourceRoot":"","sources":["../../src/commands/finish.spec.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAUvD,MAAM,MAAM,YAAY,GAAG;IACzB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,CAAC;IAC9B,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,iBAAiB,EAAE,OAAO,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,EAAE,CAAC;IACtB,eAAe,EAAE,OAAO,CAAC;IACzB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,kBAAkB,EAAE,OAAO,CAAC;IAC5B,YAAY,EAAE,OAAO,CAAC;IACtB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,qBAAqB,EAAE,OAAO,CAAC;IAC/B,wBAAwB,EAAE,OAAO,CAAC;IAClC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,EAAE,OAAO,CAAC;IACvB,kBAAkB,EAAE,OAAO,CAAC;IAC5B,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,OAAO,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,UAAU,EAAE,WAAW,CAAC,YAAY,CA4XhD,CAAC"}
@@ -1,4 +1,5 @@
1
1
  import { usageError } from "../cli/spec/errors.js";
2
+ import { verifyFindingOptions, validateVerifyFindingSource } from "./task/verify-command-shared.js";
2
3
  import { toStringList } from "../cli/spec/parse-utils.js";
3
4
  import { findRepoWideAllowPrefixes, repoWideAllowPrefixMessage, } from "../shared/allow-prefix-policy.js";
4
5
  export const finishSpec = {
@@ -157,6 +158,13 @@ export const finishSpec = {
157
158
  default: false,
158
159
  description: "With --close-commit: unstage any currently staged paths before staging the task README.",
159
160
  },
161
+ {
162
+ kind: "string",
163
+ name: "base",
164
+ valueHint: "<branch>",
165
+ description: "Optional explicit base branch override for branch_pr finish validation and close-commit reconciliation.",
166
+ },
167
+ ...verifyFindingOptions,
160
168
  { kind: "boolean", name: "quiet", default: false, description: "Suppress output." },
161
169
  ],
162
170
  examples: [
@@ -168,6 +176,10 @@ export const finishSpec = {
168
176
  cmd: 'agentplane finish 202602030608-F1Q8AB --author INTEGRATOR --body "Verified: all checks passed" --commit-from-comment --commit-allow packages/agentplane/src',
169
177
  why: "Finish and create a commit from the comment (single-task only).",
170
178
  },
179
+ {
180
+ cmd: 'agentplane finish 202602030608-F1Q8AB --author INTEGRATOR --body "Verified: all checks passed" --commit abcdef123456 --observation "Recurring manual recovery remained easy to miss." --impact "incidents.md stayed stale until a second command." --resolution "Capture the closeout finding during finish itself."',
181
+ why: "Finish a task while appending a structured finding that can promote into incidents.md.",
182
+ },
171
183
  ],
172
184
  validateRaw: (raw) => {
173
185
  const ids = raw.args["task-id"];
@@ -270,9 +282,29 @@ export const finishSpec = {
270
282
  message: "--close-unstage-others requires --close-commit",
271
283
  });
272
284
  }
285
+ if (typeof raw.opts.base === "string" && raw.opts.base.trim().length === 0) {
286
+ throw usageError({
287
+ spec: finishSpec,
288
+ command: "finish",
289
+ message: "Invalid value for --base: empty.",
290
+ });
291
+ }
273
292
  const hasMeta = typeof raw.opts.result === "string" ||
274
293
  typeof raw.opts.risk === "string" ||
275
294
  raw.opts.breaking === true;
295
+ const hasFindingInput = [
296
+ raw.opts.observation,
297
+ raw.opts.impact,
298
+ raw.opts.resolution,
299
+ raw.opts["incident-scope"],
300
+ raw.opts["incident-advice"],
301
+ raw.opts["incident-rule"],
302
+ ].some((value) => typeof value === "string" && value.trim().length > 0)
303
+ ? true
304
+ : (Array.isArray(raw.opts["incident-tag"]) && raw.opts["incident-tag"].length > 0) ||
305
+ (Array.isArray(raw.opts["incident-match"]) && raw.opts["incident-match"].length > 0) ||
306
+ raw.opts["local-only"] === true ||
307
+ raw.opts["repo-fixable"] === true;
276
308
  if (hasMeta && taskIds.length !== 1) {
277
309
  throw usageError({
278
310
  spec: finishSpec,
@@ -280,6 +312,14 @@ export const finishSpec = {
280
312
  message: "--result/--risk/--breaking requires exactly one task id",
281
313
  });
282
314
  }
315
+ if (hasFindingInput && taskIds.length !== 1) {
316
+ throw usageError({
317
+ spec: finishSpec,
318
+ command: "finish",
319
+ message: "--observation/--impact/--resolution and incident finding options require exactly one task id",
320
+ });
321
+ }
322
+ validateVerifyFindingSource(raw, finishSpec, { command: "finish" });
283
323
  },
284
324
  parse: (raw) => ({
285
325
  taskIds: Array.isArray(raw.args["task-id"])
@@ -308,6 +348,17 @@ export const finishSpec = {
308
348
  closeCommit: raw.opts["close-commit"] === true,
309
349
  noCloseCommit: raw.opts["no-close-commit"] === true,
310
350
  closeUnstageOthers: raw.opts["close-unstage-others"] === true,
351
+ baseBranchOverride: typeof raw.opts.base === "string" ? raw.opts.base : undefined,
352
+ observation: typeof raw.opts.observation === "string" ? raw.opts.observation : undefined,
353
+ impact: typeof raw.opts.impact === "string" ? raw.opts.impact : undefined,
354
+ resolution: typeof raw.opts.resolution === "string" ? raw.opts.resolution : undefined,
355
+ localOnly: raw.opts["local-only"] === true,
356
+ repoFixable: raw.opts["repo-fixable"] === true,
357
+ incidentScope: typeof raw.opts["incident-scope"] === "string" ? raw.opts["incident-scope"] : undefined,
358
+ incidentTags: toStringList(raw.opts["incident-tag"]),
359
+ incidentMatch: toStringList(raw.opts["incident-match"]),
360
+ incidentAdvice: typeof raw.opts["incident-advice"] === "string" ? raw.opts["incident-advice"] : undefined,
361
+ incidentRule: typeof raw.opts["incident-rule"] === "string" ? raw.opts["incident-rule"] : undefined,
311
362
  quiet: raw.opts.quiet === true,
312
363
  }),
313
364
  };
@@ -1 +1 @@
1
- {"version":3,"file":"close-message.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/close-message.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAsHlE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,QAAQ,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAsD9B;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,MAAM,CAET"}
1
+ {"version":3,"file":"close-message.d.ts","sourceRoot":"","sources":["../../../../src/commands/guard/impl/close-message.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mCAAmC,CAAC;AAyIlE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,wBAAsB,uBAAuB,CAAC,IAAI,EAAE;IAClD,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,QAAQ,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAsD9B;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE;IAC1C,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,MAAM,CAET"}