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
@@ -5,6 +5,8 @@ import { writeTextIfChanged } from "../../shared/write-if-changed.js";
5
5
  import { appendIncidentRegistryEntries, buildIncidentAdviceQueryFromTask, createIncidentRegistrySkeleton, parseIncidentRegistry, planIncidentCollection, resolveIncidentAdviceMatches, } from "../../runtime/incidents/index.js";
6
6
  import { extractDocSection, extractTaskObservationSection, normalizeTaskDocVersion, } from "../task/shared.js";
7
7
  export const INCIDENTS_POLICY_PATH = ".agentplane/policy/incidents.md";
8
+ export const INCIDENTS_POLICY_ASSET_PATH = "packages/agentplane/assets/policy/incidents.md";
9
+ const INCIDENTS_POLICY_LINE_BUDGET = 100;
8
10
  async function readTextIfExists(filePath) {
9
11
  try {
10
12
  return await readFile(filePath, "utf8");
@@ -19,6 +21,41 @@ async function readTextIfExists(filePath) {
19
21
  export function incidentRegistryPath(ctx) {
20
22
  return path.join(ctx.resolvedProject.gitRoot, INCIDENTS_POLICY_PATH);
21
23
  }
24
+ export function incidentRegistryAssetPath(ctx) {
25
+ return path.join(ctx.resolvedProject.gitRoot, INCIDENTS_POLICY_ASSET_PATH);
26
+ }
27
+ function normalizeIncidentRegistryDocument(text) {
28
+ const normalized = text.replaceAll("\r\n", "\n").trimEnd();
29
+ return normalized.length > 0 ? `${normalized}\n` : createIncidentRegistrySkeleton();
30
+ }
31
+ async function writeIncidentRegistryMirrors(ctx, content) {
32
+ const registryPath = incidentRegistryPath(ctx);
33
+ const assetPath = incidentRegistryAssetPath(ctx);
34
+ const assetExists = (await readTextIfExists(assetPath)) !== null;
35
+ const normalizedContent = normalizeIncidentRegistryDocument(content);
36
+ let wroteRegistry = await writeTextIfChanged(registryPath, normalizedContent);
37
+ let wroteAsset = false;
38
+ if (assetExists) {
39
+ const canonicalText = (await readTextIfExists(registryPath)) ?? normalizedContent;
40
+ wroteAsset = await writeTextIfChanged(assetPath, canonicalText);
41
+ const registryText = await readTextIfExists(registryPath);
42
+ if (registryText !== canonicalText) {
43
+ wroteRegistry = (await writeTextIfChanged(registryPath, canonicalText)) || wroteRegistry;
44
+ }
45
+ }
46
+ return wroteRegistry || wroteAsset;
47
+ }
48
+ async function resolveIncidentRegistryMirrorPaths(ctx) {
49
+ const paths = [INCIDENTS_POLICY_PATH];
50
+ const assetPath = incidentRegistryAssetPath(ctx);
51
+ if ((await readTextIfExists(assetPath)) !== null) {
52
+ paths.push(INCIDENTS_POLICY_ASSET_PATH);
53
+ }
54
+ return paths;
55
+ }
56
+ function countTextLines(text) {
57
+ return text.replaceAll("\r\n", "\n").split("\n").length;
58
+ }
22
59
  export async function loadIncidentRegistry(ctx) {
23
60
  const registryPath = incidentRegistryPath(ctx);
24
61
  const registryText = (await readTextIfExists(registryPath)) ?? createIncidentRegistrySkeleton();
@@ -60,19 +97,48 @@ export function formatIncidentCollectionIssues(taskId, plan) {
60
97
  return `line ${issue.candidate.line}: ${scope} -> missing ${issue.missingFields.join(", ")}`;
61
98
  });
62
99
  return [
63
- `${taskId}: incident-candidate entries require explicit external incident metadata before promotion.`,
100
+ `${taskId}: reusable external findings need explicit external marking and enough recovery detail before promotion.`,
64
101
  "Required fields:",
65
102
  ...issueLines.map((line) => `- ${line}`),
66
103
  ].join("\n");
67
104
  }
68
105
  export async function collectTaskIncidents(opts) {
106
+ const inspected = await inspectTaskIncidents(opts);
107
+ const { loaded, registryPath, registryPaths, registryText, registry, plan } = inspected;
108
+ if (plan.issues.length > 0) {
109
+ throw new CliError({
110
+ exitCode: 3,
111
+ code: "E_VALIDATION",
112
+ message: formatIncidentCollectionIssues(opts.taskId, plan),
113
+ });
114
+ }
115
+ const nextText = appendIncidentRegistryEntries(registryText, plan.promotable.map((item) => item.entry));
116
+ if (plan.promotable.length > 0) {
117
+ const nextLineCount = countTextLines(nextText);
118
+ if (nextLineCount > INCIDENTS_POLICY_LINE_BUDGET) {
119
+ throw new CliError({
120
+ exitCode: 3,
121
+ code: "E_VALIDATION",
122
+ message: `Incident registry write would exceed policy budget: ${nextLineCount} lines ` +
123
+ `(limit ${INCIDENTS_POLICY_LINE_BUDGET}). Compact or promote fewer entries before writing.`,
124
+ });
125
+ }
126
+ }
127
+ const wrote = opts.write && plan.promotable.length > 0
128
+ ? await writeIncidentRegistryMirrors(opts.ctx, nextText)
129
+ : false;
130
+ return { loaded, registryPath, registryPaths, registryText, registry, plan, wrote };
131
+ }
132
+ export async function inspectTaskIncidents(opts) {
69
133
  const loaded = await loadTaskIncidents(opts.ctx, opts.taskId, opts.task ?? null);
70
134
  const { registryPath, registryText, registry } = await loadIncidentRegistry(opts.ctx);
135
+ const registryPaths = await resolveIncidentRegistryMirrorPaths(opts.ctx);
71
136
  const plan = planIncidentCollection({
72
137
  task: {
73
138
  id: loaded.task.id,
74
139
  title: loaded.task.title,
75
140
  description: loaded.task.description,
141
+ scope: loaded.scope,
76
142
  tags: loaded.task.tags ?? [],
77
143
  commitHash: loaded.task.commit?.hash ?? null,
78
144
  },
@@ -80,18 +146,106 @@ export async function collectTaskIncidents(opts) {
80
146
  registry,
81
147
  now: opts.now,
82
148
  });
83
- if (plan.issues.length > 0) {
84
- throw new CliError({
85
- exitCode: 3,
86
- code: "E_VALIDATION",
87
- message: formatIncidentCollectionIssues(opts.taskId, plan),
88
- });
149
+ return { loaded, registryPath, registryPaths, registryText, registry, plan };
150
+ }
151
+ export function renderIncidentCollectionOutcome(promotedCount) {
152
+ return promotedCount > 0
153
+ ? `incident registry updated (${promotedCount} promoted)`
154
+ : "incident registry unchanged (no promotable external findings)";
155
+ }
156
+ function summarizeDetailList(values, maxItems = 3) {
157
+ const filtered = values.map((value) => value.trim()).filter((value) => value.length > 0);
158
+ if (filtered.length === 0)
159
+ return null;
160
+ if (filtered.length <= maxItems)
161
+ return filtered.join(", ");
162
+ return `${filtered.slice(0, maxItems).join(", ")}, +${filtered.length - maxItems} more`;
163
+ }
164
+ export function renderIncidentCollectionPlanOutcome(plan, opts) {
165
+ const candidates = Array.isArray(plan.candidates) ? plan.candidates.length : 0;
166
+ const skipped = Array.isArray(plan.skipped) ? plan.skipped.length : 0;
167
+ const promoted = Array.isArray(plan.promotable) ? plan.promotable.length : 0;
168
+ const duplicates = Array.isArray(plan.duplicates) ? plan.duplicates.length : 0;
169
+ const issues = Array.isArray(plan.issues) ? plan.issues.length : 0;
170
+ const findingsTextPresent = plan.findingsTextPresent === true;
171
+ const structuredFindingCount = typeof plan.structuredFindingCount === "number" ? plan.structuredFindingCount : 0;
172
+ const wrote = opts?.wrote === true;
173
+ const context = opts?.context ?? "generic";
174
+ const taskId = typeof opts?.taskId === "string" && opts.taskId.trim().length > 0 ? opts.taskId.trim() : null;
175
+ const findingsNextStep = taskId
176
+ ? ` next: agentplane task findings add ${taskId} --observation "<observation>" --impact "<impact>" --resolution "<resolution>"`
177
+ : "";
178
+ if (promoted > 0 && wrote) {
179
+ const suffix = [];
180
+ if (duplicates > 0)
181
+ suffix.push(`${duplicates} duplicate${duplicates === 1 ? "" : "s"}`);
182
+ if (skipped > 0)
183
+ suffix.push(`${skipped} skipped structured finding${skipped === 1 ? "" : "s"}`);
184
+ const base = suffix.length > 0
185
+ ? `incident registry updated (${promoted} promoted; ${suffix.join("; ")})`
186
+ : renderIncidentCollectionOutcome(promoted);
187
+ const details = [];
188
+ const promotedIds = Array.isArray(opts?.promotedIds)
189
+ ? opts.promotedIds.filter((id) => typeof id === "string" && id.trim().length > 0)
190
+ : [];
191
+ const registryPaths = Array.isArray(opts?.registryPaths)
192
+ ? opts.registryPaths.filter((filePath) => typeof filePath === "string" && filePath.trim().length > 0)
193
+ : [];
194
+ const idsSummary = summarizeDetailList(promotedIds);
195
+ const pathsSummary = summarizeDetailList(registryPaths);
196
+ if (idsSummary)
197
+ details.push(`ids=${idsSummary}`);
198
+ if (pathsSummary)
199
+ details.push(`files=${pathsSummary}`);
200
+ return details.length > 0 ? `${base} ${details.join(" ")}` : base;
89
201
  }
90
- const nextText = appendIncidentRegistryEntries(registryText, plan.promotable.map((item) => item.entry));
91
- const wrote = opts.write && plan.promotable.length > 0
92
- ? await writeTextIfChanged(registryPath, nextText)
93
- : false;
94
- return { loaded, registryPath, registryText, registry, plan, wrote };
202
+ if (promoted > 0 && !wrote) {
203
+ if (context === "collect") {
204
+ return `incident registry unchanged (${promoted} promotable external finding${promoted === 1 ? "" : "s"} validated; rerun without --check to update incidents.md)`;
205
+ }
206
+ if (context === "verify") {
207
+ return `incident registry unchanged (${promoted} promotable external finding${promoted === 1 ? "" : "s"} stayed task-local in the current task worktree; run verify --collect-incidents, agentplane incidents collect <task-id>, or finish on the base branch to update incidents.md)`;
208
+ }
209
+ return `incident registry unchanged (${promoted} promotable external finding${promoted === 1 ? "" : "s"} pending promotion)`;
210
+ }
211
+ if (issues > 0) {
212
+ const issueEntries = Array.isArray(plan.issues)
213
+ ? plan.issues
214
+ : [];
215
+ const firstIssue = issueEntries[0];
216
+ const rawMissingFields = firstIssue?.missingFields;
217
+ const missingFields = Array.isArray(rawMissingFields)
218
+ ? rawMissingFields.filter((field) => typeof field === "string" && field.trim().length > 0)
219
+ : [];
220
+ const detail = missingFields.length > 0
221
+ ? ` missing required fields: ${missingFields.join(", ")}`
222
+ : " missing required promotion fields";
223
+ const suffix = issues > 1 ? `; +${issues - 1} more candidate${issues - 1 === 1 ? "" : "s"}` : "";
224
+ return `incident registry unchanged (${issues} structured finding candidate${issues === 1 ? "" : "s"} still invalid;${detail}${suffix})`;
225
+ }
226
+ if (skipped > 0) {
227
+ return `incident registry unchanged (${skipped} structured finding${skipped === 1 ? "" : "s"} stayed task-local in the current checkout: mark reusable external findings with Promotion: incident-candidate plus Fixability: external, or use task findings add without --local-only)`;
228
+ }
229
+ if (candidates === 0 && structuredFindingCount === 0 && findingsTextPresent) {
230
+ return "incident registry unchanged (plain Findings text stays task-local in the current checkout and does not update incidents.md: add a structured Observation/Impact/Resolution block for reusable external incidents, or use task findings add without --local-only)";
231
+ }
232
+ if (candidates === 0) {
233
+ if (context === "verify") {
234
+ return ("incident registry unchanged (plain verify note stayed task-local and did not update " +
235
+ "incidents.md: add --observation, --impact, and --resolution for a reusable incident, " +
236
+ `then rerun with --collect-incidents or collect later on the base branch.${findingsNextStep})`);
237
+ }
238
+ if (context === "finish") {
239
+ return ("incident registry unchanged (plain finish body/result stayed task-local and did not " +
240
+ "update incidents.md: add --observation, --impact, and --resolution for a reusable " +
241
+ `incident before closeout.${findingsNextStep})`);
242
+ }
243
+ return "incident registry unchanged (no structured incident findings)";
244
+ }
245
+ if (duplicates > 0 && duplicates === candidates) {
246
+ return `incident registry unchanged (${duplicates} duplicate incident${duplicates === 1 ? "" : "s"} already recorded)`;
247
+ }
248
+ return "incident registry unchanged (no promotable external findings)";
95
249
  }
96
250
  export async function adviseTaskIncidents(opts) {
97
251
  const loaded = await loadTaskIncidents(opts.ctx, opts.taskId, opts.task ?? null);
@@ -1 +1 @@
1
- {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/commands/pr/check.ts"],"names":[],"mappings":"AAYA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AA8DnC,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,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,CAiMlB"}
1
+ {"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../../src/commands/pr/check.ts"],"names":[],"mappings":"AAeA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAkLnC,wBAAsB,UAAU,CAAC,IAAI,EAAE;IACrC,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,CA6NlB"}
@@ -6,12 +6,12 @@ import { fileExists } from "../../cli/fs-utils.js";
6
6
  import { createCliEmitter, workflowModeMessage } from "../../cli/output.js";
7
7
  import { CliError } from "../../shared/errors.js";
8
8
  import { parsePrMeta } from "../shared/pr-meta.js";
9
- import { gitListTaskBranches, parseTaskIdFromBranch } from "../shared/git-worktree.js";
9
+ import { findWorktreeForBranch, gitListTaskBranches, parseTaskIdFromBranch, } from "../shared/git-worktree.js";
10
10
  import { gitRevParse } from "../shared/git-ops.js";
11
- import { isTaskLocalOnlyAdvance } from "../shared/task-local-freshness.js";
12
11
  import { loadBackendTask, loadCommandContext, } from "../shared/task-backend.js";
13
- import { readPrArtifact, resolvePrPaths } from "./internal/pr-paths.js";
12
+ import { readPrArtifactFromBranch, resolvePrPaths } from "./internal/pr-paths.js";
14
13
  import { validateGithubPrBodyContents, validateReviewContents, } from "./internal/review-template.js";
14
+ import { assessPrArtifactFreshness } from "./internal/freshness.js";
15
15
  function isUnknownRevisionError(err) {
16
16
  const message = err instanceof Error ? err.message : String(err);
17
17
  return /unknown revision or path not in the working tree/i.test(message);
@@ -31,26 +31,102 @@ async function resolveArtifactBranch(opts) {
31
31
  }
32
32
  return null;
33
33
  }
34
- async function readPrArtifactWithOptionalBranch(opts) {
35
- const localPath = path.join(opts.prDir, opts.fileName);
36
- if (await fileExists(localPath)) {
37
- return await readFile(localPath, "utf8");
34
+ async function readLocalPrArtifactText(prDir, fileName) {
35
+ const localPath = path.join(prDir, fileName);
36
+ if (!(await fileExists(localPath)))
37
+ return null;
38
+ return await readFile(localPath, "utf8");
39
+ }
40
+ function validateSnapshotContents(opts) {
41
+ const errors = [];
42
+ let meta = null;
43
+ if (opts.texts.metaText) {
44
+ try {
45
+ meta = parsePrMeta(opts.texts.metaText, opts.taskId);
46
+ }
47
+ catch (err) {
48
+ const message = err instanceof Error ? err.message : String(err);
49
+ errors.push(message);
50
+ }
38
51
  }
39
- if (opts.branchCache.value === undefined) {
40
- opts.branchCache.value = await resolveArtifactBranch({
41
- ctx: opts.ctx,
42
- resolved: opts.resolved,
43
- taskId: opts.taskId,
44
- });
52
+ else {
53
+ errors.push(`Missing PR directory: ${opts.relPrDir}`, `Missing ${opts.relMetaPath}`);
45
54
  }
46
- if (!opts.branchCache.value)
47
- return null;
48
- return await readPrArtifact({
49
- resolved: opts.resolved,
50
- prDir: opts.prDir,
51
- fileName: opts.fileName,
52
- branch: opts.branchCache.value,
55
+ if (opts.texts.diffstatText === null)
56
+ errors.push(`Missing ${opts.relDiffstatPath}`);
57
+ if (opts.texts.verifyLogText === null)
58
+ errors.push(`Missing ${opts.relVerifyLogPath}`);
59
+ if (opts.texts.reviewText) {
60
+ validateReviewContents(opts.texts.reviewText, errors);
61
+ }
62
+ else {
63
+ errors.push(`Missing ${opts.relReviewPath}`);
64
+ }
65
+ if (!opts.texts.githubTitleText?.trim()) {
66
+ errors.push(`Missing ${opts.relGithubTitlePath}`);
67
+ }
68
+ if (opts.texts.githubBodyText) {
69
+ validateGithubPrBodyContents(opts.texts.githubBodyText, errors);
70
+ }
71
+ else {
72
+ errors.push(`Missing ${opts.relGithubBodyPath}`);
73
+ }
74
+ return { meta, errors };
75
+ }
76
+ async function evaluateSnapshotFreshness(opts) {
77
+ if (!opts.snapshot.meta || !opts.branchHeadSha)
78
+ return;
79
+ const freshness = await assessPrArtifactFreshness({
80
+ gitRoot: opts.gitRoot,
81
+ workflowDir: opts.workflowDir,
82
+ tasksPath: opts.tasksPath,
83
+ taskId: opts.taskId,
84
+ branchHeadSha: opts.branchHeadSha,
85
+ metaHeadSha: opts.snapshot.meta.head_sha ?? null,
86
+ metaLastVerifiedSha: opts.snapshot.meta.last_verified_sha ?? null,
87
+ metaVerifyStatus: opts.snapshot.meta.verify?.status ?? null,
88
+ taskVerificationState: opts.taskVerificationState,
89
+ verifyLogText: opts.snapshot.texts.verifyLogText,
90
+ requiresVerify: opts.requiresVerify,
53
91
  });
92
+ opts.snapshot.freshnessEvaluated = true;
93
+ opts.snapshot.freshnessReviewFresh = freshness.reviewFresh;
94
+ opts.snapshot.freshnessVerifySatisfied = freshness.verifySatisfied;
95
+ opts.snapshot.freshnessVerifyFresh = freshness.verifyFresh;
96
+ opts.snapshot.freshnessVerifyLogSha = freshness.verifyLogSha;
97
+ }
98
+ function finalizeSnapshotErrors(opts) {
99
+ const errors = [...opts.snapshot.errors];
100
+ const meta = opts.snapshot.meta;
101
+ if (!meta)
102
+ return errors;
103
+ if (opts.branchHeadSha && opts.snapshot.freshnessEvaluated) {
104
+ if (!opts.snapshot.freshnessReviewFresh) {
105
+ errors.push(`PR artifacts stale: head_sha=${meta.head_sha ?? "<missing>"} current_head=${opts.branchHeadSha}`);
106
+ }
107
+ if (opts.requiresVerify && !opts.snapshot.freshnessVerifySatisfied) {
108
+ if (meta.verify?.status !== "pass") {
109
+ errors.push("Verify requirements not satisfied (meta.verify.status != pass)");
110
+ }
111
+ if ((!meta.last_verified_sha || !meta.last_verified_at) &&
112
+ !opts.snapshot.freshnessVerifyLogSha) {
113
+ errors.push("Verify metadata missing (last_verified_sha/last_verified_at)");
114
+ }
115
+ }
116
+ if (opts.requiresVerify && meta.last_verified_sha && !opts.snapshot.freshnessVerifyFresh) {
117
+ errors.push(`Verify state stale: last_verified_sha=${meta.last_verified_sha} current_head=${opts.branchHeadSha}`);
118
+ }
119
+ return errors;
120
+ }
121
+ if (opts.requiresVerify) {
122
+ if (meta.verify?.status !== "pass") {
123
+ errors.push("Verify requirements not satisfied (meta.verify.status != pass)");
124
+ }
125
+ if (!meta.last_verified_sha || !meta.last_verified_at) {
126
+ errors.push("Verify metadata missing (last_verified_sha/last_verified_at)");
127
+ }
128
+ }
129
+ return errors;
54
130
  }
55
131
  export async function cmdPrCheck(opts) {
56
132
  try {
@@ -80,99 +156,51 @@ export async function cmdPrCheck(opts) {
80
156
  const relGithubTitlePath = path.relative(resolved.gitRoot, githubTitlePath);
81
157
  const relGithubBodyPath = path.relative(resolved.gitRoot, githubBodyPath);
82
158
  const branchCache = {};
83
- let meta = null;
84
- const metaText = await readPrArtifactWithOptionalBranch({
85
- ctx,
86
- resolved,
87
- prDir,
88
- fileName: "meta.json",
159
+ const requiresVerify = Boolean(task.verify && task.verify.length > 0);
160
+ const localTexts = {
161
+ metaText: await readLocalPrArtifactText(prDir, "meta.json"),
162
+ diffstatText: await readLocalPrArtifactText(prDir, "diffstat.txt"),
163
+ verifyLogText: await readLocalPrArtifactText(prDir, "verify.log"),
164
+ reviewText: await readLocalPrArtifactText(prDir, "review.md"),
165
+ githubTitleText: await readLocalPrArtifactText(prDir, "github-title.txt"),
166
+ githubBodyText: await readLocalPrArtifactText(prDir, "github-body.md"),
167
+ };
168
+ const localParsed = validateSnapshotContents({
169
+ texts: localTexts,
170
+ relPrDir,
171
+ relMetaPath,
172
+ relDiffstatPath,
173
+ relVerifyLogPath,
174
+ relReviewPath,
175
+ relGithubTitlePath,
176
+ relGithubBodyPath,
89
177
  taskId: task.id,
90
- branchCache,
91
178
  });
92
- if (metaText) {
93
- try {
94
- meta = parsePrMeta(metaText, task.id);
95
- }
96
- catch (err) {
97
- const message = err instanceof Error ? err.message : String(err);
98
- errors.push(message);
99
- }
179
+ const localSnapshot = {
180
+ source: "local",
181
+ texts: localTexts,
182
+ meta: localParsed.meta,
183
+ errors: localParsed.errors,
184
+ freshnessEvaluated: false,
185
+ freshnessReviewFresh: false,
186
+ freshnessVerifySatisfied: false,
187
+ freshnessVerifyFresh: false,
188
+ freshnessVerifyLogSha: null,
189
+ };
190
+ const localBranch = localSnapshot.meta?.branch?.trim() ?? "";
191
+ if (localBranch) {
192
+ branchCache.value = localBranch;
100
193
  }
101
- else {
102
- errors.push(`Missing PR directory: ${relPrDir}`, `Missing ${relMetaPath}`);
103
- }
104
- const diffstatText = await readPrArtifactWithOptionalBranch({
105
- ctx,
106
- resolved,
107
- prDir,
108
- fileName: "diffstat.txt",
109
- taskId: task.id,
110
- branchCache,
111
- });
112
- if (diffstatText === null) {
113
- errors.push(`Missing ${relDiffstatPath}`);
114
- }
115
- const verifyLogText = await readPrArtifactWithOptionalBranch({
116
- ctx,
117
- resolved,
118
- prDir,
119
- fileName: "verify.log",
120
- taskId: task.id,
121
- branchCache,
122
- });
123
- if (verifyLogText === null) {
124
- errors.push(`Missing ${relVerifyLogPath}`);
125
- }
126
- const reviewText = await readPrArtifactWithOptionalBranch({
127
- ctx,
128
- resolved,
129
- prDir,
130
- fileName: "review.md",
131
- taskId: task.id,
132
- branchCache,
133
- });
134
- if (reviewText) {
135
- validateReviewContents(reviewText, errors);
136
- }
137
- else {
138
- errors.push(`Missing ${relReviewPath}`);
139
- }
140
- const githubTitleText = await readPrArtifactWithOptionalBranch({
141
- ctx,
142
- resolved,
143
- prDir,
144
- fileName: "github-title.txt",
145
- taskId: task.id,
146
- branchCache,
147
- });
148
- if (!githubTitleText?.trim()) {
149
- errors.push(`Missing ${relGithubTitlePath}`);
150
- }
151
- const githubBodyText = await readPrArtifactWithOptionalBranch({
152
- ctx,
153
- resolved,
154
- prDir,
155
- fileName: "github-body.md",
156
- taskId: task.id,
157
- branchCache,
158
- });
159
- if (githubBodyText) {
160
- validateGithubPrBodyContents(githubBodyText, errors);
161
- }
162
- else {
163
- errors.push(`Missing ${relGithubBodyPath}`);
164
- }
165
- if (task.verify && task.verify.length > 0) {
166
- if (meta?.verify?.status !== "pass") {
167
- errors.push("Verify requirements not satisfied (meta.verify.status != pass)");
168
- }
169
- if (!meta?.last_verified_sha || !meta.last_verified_at) {
170
- errors.push("Verify metadata missing (last_verified_sha/last_verified_at)");
171
- }
194
+ else if (branchCache.value === undefined) {
195
+ branchCache.value = await resolveArtifactBranch({
196
+ ctx,
197
+ resolved,
198
+ taskId: task.id,
199
+ });
172
200
  }
173
- const branchForFreshness = branchCache.value ?? (typeof meta?.branch === "string" ? meta.branch.trim() : null);
174
- if (meta && branchForFreshness) {
175
- let branchHeadSha = null;
201
+ const branchForFreshness = branchCache.value ?? null;
202
+ let branchHeadSha = null;
203
+ if (branchForFreshness) {
176
204
  try {
177
205
  branchHeadSha = await gitRevParse(resolved.gitRoot, [branchForFreshness]);
178
206
  }
@@ -180,34 +208,112 @@ export async function cmdPrCheck(opts) {
180
208
  if (!isUnknownRevisionError(err))
181
209
  throw err;
182
210
  }
183
- if (branchHeadSha) {
184
- const reviewFresh = (meta.head_sha ?? null) === branchHeadSha ||
185
- (await isTaskLocalOnlyAdvance({
186
- gitRoot: resolved.gitRoot,
187
- workflowDir: config.paths.workflow_dir,
188
- taskId: task.id,
189
- fromRef: meta.head_sha ?? null,
190
- toRef: branchHeadSha,
191
- }));
192
- if (!reviewFresh) {
193
- errors.push(`PR artifacts stale: head_sha=${meta.head_sha ?? "<missing>"} current_head=${branchHeadSha}`);
194
- }
195
- const verifyFresh = !task.verify ||
196
- task.verify.length === 0 ||
197
- !meta.last_verified_sha ||
198
- meta.last_verified_sha === branchHeadSha ||
199
- (await isTaskLocalOnlyAdvance({
200
- gitRoot: resolved.gitRoot,
201
- workflowDir: config.paths.workflow_dir,
202
- taskId: task.id,
203
- fromRef: meta.last_verified_sha,
204
- toRef: branchHeadSha,
205
- }));
206
- if (task.verify && task.verify.length > 0 && meta.last_verified_sha && !verifyFresh) {
207
- errors.push(`Verify state stale: last_verified_sha=${meta.last_verified_sha} current_head=${branchHeadSha}`);
208
- }
211
+ }
212
+ await evaluateSnapshotFreshness({
213
+ snapshot: localSnapshot,
214
+ gitRoot: resolved.gitRoot,
215
+ workflowDir: config.paths.workflow_dir,
216
+ tasksPath: config.paths.tasks_path,
217
+ taskId: task.id,
218
+ branchHeadSha,
219
+ taskVerificationState: task.verification?.state ?? null,
220
+ requiresVerify,
221
+ });
222
+ let selectedSnapshot = localSnapshot;
223
+ if (branchForFreshness &&
224
+ branchHeadSha &&
225
+ (!localSnapshot.meta ||
226
+ !localSnapshot.freshnessReviewFresh ||
227
+ (requiresVerify && !localSnapshot.freshnessVerifySatisfied))) {
228
+ const worktreePath = await findWorktreeForBranch(resolved.gitRoot, branchForFreshness);
229
+ const branchTexts = {
230
+ metaText: await readPrArtifactFromBranch({
231
+ resolved,
232
+ prDir,
233
+ fileName: "meta.json",
234
+ branch: branchForFreshness,
235
+ worktreePath,
236
+ }),
237
+ diffstatText: await readPrArtifactFromBranch({
238
+ resolved,
239
+ prDir,
240
+ fileName: "diffstat.txt",
241
+ branch: branchForFreshness,
242
+ worktreePath,
243
+ }),
244
+ verifyLogText: await readPrArtifactFromBranch({
245
+ resolved,
246
+ prDir,
247
+ fileName: "verify.log",
248
+ branch: branchForFreshness,
249
+ worktreePath,
250
+ }),
251
+ reviewText: await readPrArtifactFromBranch({
252
+ resolved,
253
+ prDir,
254
+ fileName: "review.md",
255
+ branch: branchForFreshness,
256
+ worktreePath,
257
+ }),
258
+ githubTitleText: await readPrArtifactFromBranch({
259
+ resolved,
260
+ prDir,
261
+ fileName: "github-title.txt",
262
+ branch: branchForFreshness,
263
+ worktreePath,
264
+ }),
265
+ githubBodyText: await readPrArtifactFromBranch({
266
+ resolved,
267
+ prDir,
268
+ fileName: "github-body.md",
269
+ branch: branchForFreshness,
270
+ worktreePath,
271
+ }),
272
+ };
273
+ const branchParsed = validateSnapshotContents({
274
+ texts: branchTexts,
275
+ relPrDir,
276
+ relMetaPath,
277
+ relDiffstatPath,
278
+ relVerifyLogPath,
279
+ relReviewPath,
280
+ relGithubTitlePath,
281
+ relGithubBodyPath,
282
+ taskId: task.id,
283
+ });
284
+ const branchSnapshot = {
285
+ source: "branch",
286
+ texts: branchTexts,
287
+ meta: branchParsed.meta,
288
+ errors: branchParsed.errors,
289
+ freshnessEvaluated: false,
290
+ freshnessReviewFresh: false,
291
+ freshnessVerifySatisfied: false,
292
+ freshnessVerifyFresh: false,
293
+ freshnessVerifyLogSha: null,
294
+ };
295
+ await evaluateSnapshotFreshness({
296
+ snapshot: branchSnapshot,
297
+ gitRoot: resolved.gitRoot,
298
+ workflowDir: config.paths.workflow_dir,
299
+ tasksPath: config.paths.tasks_path,
300
+ taskId: task.id,
301
+ branchHeadSha,
302
+ taskVerificationState: task.verification?.state ?? null,
303
+ requiresVerify,
304
+ });
305
+ if (branchSnapshot.errors.length === 0 &&
306
+ branchSnapshot.meta &&
307
+ branchSnapshot.freshnessReviewFresh &&
308
+ (!requiresVerify || branchSnapshot.freshnessVerifySatisfied)) {
309
+ selectedSnapshot = branchSnapshot;
209
310
  }
210
311
  }
312
+ errors.push(...finalizeSnapshotErrors({
313
+ snapshot: selectedSnapshot,
314
+ branchHeadSha,
315
+ requiresVerify,
316
+ }));
211
317
  if (errors.length > 0) {
212
318
  throw new CliError({
213
319
  exitCode: exitCodeForError("E_VALIDATION"),
@@ -0,0 +1,9 @@
1
+ import { type CommandContext } from "../shared/task-backend.js";
2
+ export declare function cmdPrCloseSuperseded(opts: {
3
+ ctx?: CommandContext;
4
+ cwd: string;
5
+ rootOverride?: string;
6
+ taskId: string;
7
+ deleteRemoteBranch: boolean;
8
+ }): Promise<number>;
9
+ //# sourceMappingURL=close-superseded.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"close-superseded.d.ts","sourceRoot":"","sources":["../../../src/commands/pr/close-superseded.ts"],"names":[],"mappings":"AAOA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAiCnC,wBAAsB,oBAAoB,CAAC,IAAI,EAAE;IAC/C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,EAAE,OAAO,CAAC;CAC7B,GAAG,OAAO,CAAC,MAAM,CAAC,CAsHlB"}