agentplane 0.3.5 → 0.3.6

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 (187) hide show
  1. package/README.md +103 -75
  2. package/assets/AGENTS.md +4 -2
  3. package/bin/dist-guard.js +13 -3
  4. package/bin/runtime-watch.d.ts +1 -0
  5. package/bin/runtime-watch.js +22 -5
  6. package/bin/stale-dist-policy.js +9 -2
  7. package/dist/.build-manifest.json +196 -776
  8. package/dist/backends/task-backend.test-helpers.d.ts +4 -0
  9. package/dist/backends/task-backend.test-helpers.d.ts.map +1 -0
  10. package/dist/backends/task-backend.test-helpers.js +33 -0
  11. package/dist/cli/bootstrap-guide.d.ts.map +1 -1
  12. package/dist/cli/bootstrap-guide.js +1 -0
  13. package/dist/cli/command-guide.d.ts.map +1 -1
  14. package/dist/cli/command-guide.js +3 -2
  15. package/dist/cli/reason-codes.d.ts.map +1 -1
  16. package/dist/cli/reason-codes.js +30 -0
  17. package/dist/cli/run-cli/command-catalog/core.d.ts +3 -0
  18. package/dist/cli/run-cli/command-catalog/core.d.ts.map +1 -0
  19. package/dist/cli/run-cli/command-catalog/core.js +137 -0
  20. package/dist/cli/run-cli/command-catalog/lifecycle.d.ts +3 -0
  21. package/dist/cli/run-cli/command-catalog/lifecycle.d.ts.map +1 -0
  22. package/dist/cli/run-cli/command-catalog/lifecycle.js +52 -0
  23. package/dist/cli/run-cli/command-catalog/project.d.ts +3 -0
  24. package/dist/cli/run-cli/command-catalog/project.d.ts.map +1 -0
  25. package/dist/cli/run-cli/command-catalog/project.js +78 -0
  26. package/dist/cli/run-cli/command-catalog/shared.d.ts +19 -0
  27. package/dist/cli/run-cli/command-catalog/shared.d.ts.map +1 -0
  28. package/dist/cli/run-cli/command-catalog/shared.js +9 -0
  29. package/dist/cli/run-cli/command-catalog/task.d.ts +3 -0
  30. package/dist/cli/run-cli/command-catalog/task.d.ts.map +1 -0
  31. package/dist/cli/run-cli/command-catalog/task.js +85 -0
  32. package/dist/cli/run-cli/command-catalog.d.ts +3 -18
  33. package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
  34. package/dist/cli/run-cli/command-catalog.js +8 -337
  35. package/dist/cli/run-cli/commands/ide.d.ts.map +1 -1
  36. package/dist/cli/run-cli/commands/ide.js +64 -2
  37. package/dist/cli/run-cli/commands/init/ui.d.ts.map +1 -1
  38. package/dist/cli/run-cli/commands/init/ui.js +33 -13
  39. package/dist/cli/run-cli.core.pr-flow.test-helpers.d.ts +3 -0
  40. package/dist/cli/run-cli.core.pr-flow.test-helpers.d.ts.map +1 -0
  41. package/dist/cli/run-cli.core.pr-flow.test-helpers.js +41 -0
  42. package/dist/cli/run-cli.core.tasks.test-helpers.d.ts +2 -0
  43. package/dist/cli/run-cli.core.tasks.test-helpers.d.ts.map +1 -0
  44. package/dist/cli/run-cli.core.tasks.test-helpers.js +6 -0
  45. package/dist/cli/run-cli.test-helpers.d.ts +3 -0
  46. package/dist/cli/run-cli.test-helpers.d.ts.map +1 -1
  47. package/dist/cli/run-cli.test-helpers.js +138 -6
  48. package/dist/commands/commit.spec.d.ts.map +1 -1
  49. package/dist/commands/commit.spec.js +2 -2
  50. package/dist/commands/doctor/runtime.d.ts.map +1 -1
  51. package/dist/commands/doctor/runtime.js +3 -6
  52. package/dist/commands/guard/commit.command.js +1 -1
  53. package/dist/commands/guard/impl/allow.d.ts +5 -0
  54. package/dist/commands/guard/impl/allow.d.ts.map +1 -1
  55. package/dist/commands/guard/impl/allow.js +15 -10
  56. package/dist/commands/guard/impl/commands.d.ts.map +1 -1
  57. package/dist/commands/guard/impl/commands.js +137 -18
  58. package/dist/commands/guard/impl/comment-commit.d.ts.map +1 -1
  59. package/dist/commands/guard/impl/comment-commit.js +2 -0
  60. package/dist/commands/hooks/index.d.ts.map +1 -1
  61. package/dist/commands/hooks/index.js +8 -35
  62. package/dist/commands/recipes/impl/apply.d.ts +4 -0
  63. package/dist/commands/recipes/impl/apply.d.ts.map +1 -1
  64. package/dist/commands/recipes/impl/apply.js +34 -0
  65. package/dist/commands/recipes/impl/commands/explain.d.ts.map +1 -1
  66. package/dist/commands/recipes/impl/commands/explain.js +70 -11
  67. package/dist/commands/recipes/impl/commands/info.d.ts.map +1 -1
  68. package/dist/commands/recipes/impl/commands/info.js +24 -12
  69. package/dist/commands/recipes/impl/commands/install.d.ts.map +1 -1
  70. package/dist/commands/recipes/impl/commands/install.js +32 -36
  71. package/dist/commands/recipes/impl/commands/list.d.ts.map +1 -1
  72. package/dist/commands/recipes/impl/commands/list.js +7 -4
  73. package/dist/commands/recipes/impl/commands/remove.d.ts.map +1 -1
  74. package/dist/commands/recipes/impl/commands/remove.js +9 -11
  75. package/dist/commands/recipes/impl/constants.d.ts +2 -0
  76. package/dist/commands/recipes/impl/constants.d.ts.map +1 -1
  77. package/dist/commands/recipes/impl/constants.js +2 -0
  78. package/dist/commands/recipes/impl/manifest.d.ts.map +1 -1
  79. package/dist/commands/recipes/impl/manifest.js +219 -23
  80. package/dist/commands/recipes/impl/normalize.d.ts +3 -0
  81. package/dist/commands/recipes/impl/normalize.d.ts.map +1 -1
  82. package/dist/commands/recipes/impl/normalize.js +28 -24
  83. package/dist/commands/recipes/impl/paths.d.ts +9 -0
  84. package/dist/commands/recipes/impl/paths.d.ts.map +1 -1
  85. package/dist/commands/recipes/impl/paths.js +10 -1
  86. package/dist/commands/recipes/impl/project-installed-recipes.d.ts +7 -0
  87. package/dist/commands/recipes/impl/project-installed-recipes.d.ts.map +1 -0
  88. package/dist/commands/recipes/impl/project-installed-recipes.js +102 -0
  89. package/dist/commands/recipes/impl/resolver.d.ts +20 -0
  90. package/dist/commands/recipes/impl/resolver.d.ts.map +1 -0
  91. package/dist/commands/recipes/impl/resolver.js +220 -0
  92. package/dist/commands/recipes/impl/scenario.d.ts.map +1 -1
  93. package/dist/commands/recipes/impl/scenario.js +40 -11
  94. package/dist/commands/recipes/impl/types.d.ts +145 -16
  95. package/dist/commands/recipes/impl/types.d.ts.map +1 -1
  96. package/dist/commands/recipes/install.spec.d.ts.map +1 -1
  97. package/dist/commands/recipes/install.spec.js +3 -2
  98. package/dist/commands/recipes.d.ts +6 -4
  99. package/dist/commands/recipes.d.ts.map +1 -1
  100. package/dist/commands/recipes.js +5 -3
  101. package/dist/commands/recipes.test-helpers.d.ts +185 -0
  102. package/dist/commands/recipes.test-helpers.d.ts.map +1 -0
  103. package/dist/commands/recipes.test-helpers.js +339 -0
  104. package/dist/commands/scenario/impl/commands.d.ts.map +1 -1
  105. package/dist/commands/scenario/impl/commands.js +192 -336
  106. package/dist/commands/scenario/info.command.d.ts.map +1 -1
  107. package/dist/commands/scenario/info.command.js +7 -2
  108. package/dist/commands/scenario/list.command.js +2 -2
  109. package/dist/commands/scenario/run.command.d.ts.map +1 -1
  110. package/dist/commands/scenario/run.command.js +7 -2
  111. package/dist/commands/shared/reconcile-check.d.ts.map +1 -1
  112. package/dist/commands/shared/reconcile-check.js +77 -2
  113. package/dist/commands/shared/task-store.d.ts +32 -1
  114. package/dist/commands/shared/task-store.d.ts.map +1 -1
  115. package/dist/commands/shared/task-store.js +166 -42
  116. package/dist/commands/task/block.d.ts.map +1 -1
  117. package/dist/commands/task/block.js +46 -29
  118. package/dist/commands/task/close-duplicate.d.ts.map +1 -1
  119. package/dist/commands/task/close-duplicate.js +12 -37
  120. package/dist/commands/task/close-noop.d.ts.map +1 -1
  121. package/dist/commands/task/close-noop.js +12 -30
  122. package/dist/commands/task/close-shared.d.ts +14 -0
  123. package/dist/commands/task/close-shared.d.ts.map +1 -0
  124. package/dist/commands/task/close-shared.js +76 -0
  125. package/dist/commands/task/comment.d.ts.map +1 -1
  126. package/dist/commands/task/comment.js +35 -17
  127. package/dist/commands/task/doc-set.command.d.ts +2 -1
  128. package/dist/commands/task/doc-set.command.d.ts.map +1 -1
  129. package/dist/commands/task/doc-set.command.js +36 -4
  130. package/dist/commands/task/doc-template.d.ts.map +1 -1
  131. package/dist/commands/task/doc-template.js +2 -7
  132. package/dist/commands/task/doc.command.js +1 -1
  133. package/dist/commands/task/doc.d.ts +2 -1
  134. package/dist/commands/task/doc.d.ts.map +1 -1
  135. package/dist/commands/task/doc.js +123 -71
  136. package/dist/commands/task/finish.d.ts.map +1 -1
  137. package/dist/commands/task/finish.js +138 -76
  138. package/dist/commands/task/migrate-doc.d.ts.map +1 -1
  139. package/dist/commands/task/migrate-doc.js +2 -8
  140. package/dist/commands/task/plan-set.command.js +1 -1
  141. package/dist/commands/task/plan.command.d.ts +8 -0
  142. package/dist/commands/task/plan.command.d.ts.map +1 -0
  143. package/dist/commands/task/plan.command.js +37 -0
  144. package/dist/commands/task/plan.d.ts.map +1 -1
  145. package/dist/commands/task/plan.js +190 -93
  146. package/dist/commands/task/set-status.command.d.ts.map +1 -1
  147. package/dist/commands/task/set-status.command.js +1 -1
  148. package/dist/commands/task/set-status.d.ts.map +1 -1
  149. package/dist/commands/task/set-status.js +40 -3
  150. package/dist/commands/task/shared/docs.d.ts +1 -0
  151. package/dist/commands/task/shared/docs.d.ts.map +1 -1
  152. package/dist/commands/task/shared/docs.js +7 -0
  153. package/dist/commands/task/shared/transitions.d.ts +0 -2
  154. package/dist/commands/task/shared/transitions.d.ts.map +1 -1
  155. package/dist/commands/task/shared/transitions.js +0 -6
  156. package/dist/commands/task/shared.d.ts +2 -2
  157. package/dist/commands/task/shared.d.ts.map +1 -1
  158. package/dist/commands/task/shared.js +2 -2
  159. package/dist/commands/task/start.d.ts.map +1 -1
  160. package/dist/commands/task/start.js +88 -63
  161. package/dist/commands/task/task.command.d.ts +8 -0
  162. package/dist/commands/task/task.command.d.ts.map +1 -0
  163. package/dist/commands/task/task.command.js +71 -0
  164. package/dist/commands/task/verify-command-shared.d.ts +16 -0
  165. package/dist/commands/task/verify-command-shared.d.ts.map +1 -0
  166. package/dist/commands/task/verify-command-shared.js +53 -0
  167. package/dist/commands/task/verify-ok.command.d.ts +2 -6
  168. package/dist/commands/task/verify-ok.command.d.ts.map +1 -1
  169. package/dist/commands/task/verify-ok.command.js +8 -50
  170. package/dist/commands/task/verify-record.d.ts.map +1 -1
  171. package/dist/commands/task/verify-record.js +119 -140
  172. package/dist/commands/task/verify-rework.command.d.ts +2 -6
  173. package/dist/commands/task/verify-rework.command.d.ts.map +1 -1
  174. package/dist/commands/task/verify-rework.command.js +8 -50
  175. package/dist/commands/verify.spec.d.ts.map +1 -1
  176. package/dist/commands/verify.spec.js +3 -12
  177. package/dist/policy/rules/allowlist.d.ts.map +1 -1
  178. package/dist/policy/rules/allowlist.js +13 -4
  179. package/dist/policy/rules/protected-paths.d.ts.map +1 -1
  180. package/dist/policy/rules/protected-paths.js +6 -1
  181. package/dist/shared/agent-emoji.d.ts.map +1 -1
  182. package/dist/shared/protected-paths.d.ts +7 -0
  183. package/dist/shared/protected-paths.d.ts.map +1 -1
  184. package/dist/shared/protected-paths.js +26 -10
  185. package/dist/shared/repo-cli-version.d.ts.map +1 -1
  186. package/dist/shared/repo-cli-version.js +9 -3
  187. package/package.json +2 -2
@@ -28,6 +28,43 @@ async function clearDirectWorkLockIfMatches(opts) {
28
28
  // best-effort
29
29
  }
30
30
  }
31
+ function assertTaskCanFinish(opts) {
32
+ if (!opts.force && String(opts.task.status || "TODO").toUpperCase() === "DONE") {
33
+ throw new CliError({
34
+ exitCode: 2,
35
+ code: "E_USAGE",
36
+ message: `Task is already DONE: ${opts.task.id} (use --force to override)`,
37
+ });
38
+ }
39
+ ensureVerificationSatisfiedIfRequired(opts.task, opts.config);
40
+ const normalizedDoc = ensureDocSections(typeof opts.task.doc === "string" ? opts.task.doc : "", opts.config.tasks.doc.required_sections);
41
+ ensureAgentFilledRequiredDocSections({
42
+ task: opts.task,
43
+ config: opts.config,
44
+ doc: normalizedDoc,
45
+ action: "finish task",
46
+ });
47
+ if (!opts.isMetaTask)
48
+ return;
49
+ const tags = Array.isArray(opts.task.tags)
50
+ ? opts.task.tags.filter((t) => typeof t === "string")
51
+ : [];
52
+ const isSpike = tags.includes("spike");
53
+ if (!isSpike && opts.taskCount === 1 && !opts.resultSummary) {
54
+ throw new CliError({
55
+ exitCode: 2,
56
+ code: "E_USAGE",
57
+ message: "Missing required --result for non-spike tasks.",
58
+ });
59
+ }
60
+ if (opts.resultProvided && !opts.resultSummary) {
61
+ throw new CliError({
62
+ exitCode: 2,
63
+ code: "E_USAGE",
64
+ message: "Invalid value for --result: empty.",
65
+ });
66
+ }
67
+ }
31
68
  export async function cmdFinish(opts) {
32
69
  try {
33
70
  const ctx = opts.ctx ??
@@ -123,6 +160,7 @@ export async function cmdFinish(opts) {
123
160
  const shouldCloseCommit = opts.closeCommit === true || (defaultDirectCloseCommit && opts.noCloseCommit !== true);
124
161
  const metaTaskId = opts.taskIds.length === 1 ? (opts.taskIds[0] ?? "") : "";
125
162
  const wantMeta = typeof opts.result === "string" || typeof opts.risk === "string" || opts.breaking === true;
163
+ const resultProvided = typeof opts.result === "string";
126
164
  if (wantMeta && opts.taskIds.length !== 1) {
127
165
  throw new CliError({
128
166
  exitCode: 2,
@@ -137,78 +175,87 @@ export async function cmdFinish(opts) {
137
175
  let primaryTag = null;
138
176
  for (const taskId of opts.taskIds) {
139
177
  const task = useStore ? await store.get(taskId) : await loadTaskFromContext({ ctx, taskId });
140
- if (!opts.force) {
141
- const currentStatus = String(task.status || "TODO").toUpperCase();
142
- if (currentStatus === "DONE") {
143
- throw new CliError({
144
- exitCode: 2,
145
- code: "E_USAGE",
146
- message: `Task is already DONE: ${task.id} (use --force to override)`,
147
- });
148
- }
149
- }
178
+ assertTaskCanFinish({
179
+ task,
180
+ config: ctx.config,
181
+ taskCount: opts.taskIds.length,
182
+ isMetaTask: taskId === metaTaskId,
183
+ resultProvided,
184
+ resultSummary,
185
+ force: opts.force,
186
+ });
150
187
  if (taskId === primaryTaskId &&
151
188
  (opts.commitFromComment || statusCommitRequested) &&
152
189
  primaryStatusFrom === null) {
153
190
  primaryStatusFrom = String(task.status || "TODO").toUpperCase();
154
191
  primaryTag = resolvePrimaryTag(toStringArray(task.tags), ctx).primary;
155
192
  }
156
- ensureVerificationSatisfiedIfRequired(task, ctx.config);
157
- const normalizedDoc = ensureDocSections(typeof task.doc === "string" ? task.doc : "", ctx.config.tasks.doc.required_sections);
158
- ensureAgentFilledRequiredDocSections({
159
- task,
160
- config: ctx.config,
161
- doc: normalizedDoc,
162
- action: "finish task",
163
- });
164
- if (taskId === metaTaskId) {
165
- const tags = Array.isArray(task.tags)
166
- ? task.tags.filter((t) => typeof t === "string")
167
- : [];
168
- const isSpike = tags.includes("spike");
169
- if (!isSpike && opts.taskIds.length === 1 && !resultSummary) {
170
- throw new CliError({
171
- exitCode: 2,
172
- code: "E_USAGE",
173
- message: "Missing required --result for non-spike tasks.",
174
- });
175
- }
176
- if (typeof opts.result === "string" && !resultSummary) {
177
- throw new CliError({
178
- exitCode: 2,
179
- code: "E_USAGE",
180
- message: "Invalid value for --result: empty.",
193
+ const at = nowIso();
194
+ if (useStore) {
195
+ await store.patch(taskId, (current) => {
196
+ assertTaskCanFinish({
197
+ task: current,
198
+ config: ctx.config,
199
+ taskCount: opts.taskIds.length,
200
+ isMetaTask: taskId === metaTaskId,
201
+ resultProvided,
202
+ resultSummary,
203
+ force: opts.force,
181
204
  });
182
- }
205
+ const currentStatus = String(current.status || "TODO").toUpperCase();
206
+ return {
207
+ task: {
208
+ status: "DONE",
209
+ commit: { hash: commitInfo.hash, message: commitInfo.message },
210
+ ...(taskId === metaTaskId && resultSummary ? { result_summary: resultSummary } : {}),
211
+ ...(taskId === metaTaskId && riskLevel ? { risk_level: riskLevel } : {}),
212
+ ...(taskId === metaTaskId && breaking ? { breaking: true } : {}),
213
+ },
214
+ appendComments: [{ author: opts.author, body: opts.body }],
215
+ appendEvents: [
216
+ {
217
+ type: "status",
218
+ at,
219
+ author: opts.author,
220
+ from: currentStatus,
221
+ to: "DONE",
222
+ note: opts.body,
223
+ },
224
+ ],
225
+ docMeta: {
226
+ touch: true,
227
+ updatedBy: opts.author,
228
+ version: normalizeTaskDocVersion(current.doc_version),
229
+ },
230
+ };
231
+ });
232
+ }
233
+ else {
234
+ const existingComments = Array.isArray(task.comments)
235
+ ? task.comments.filter((item) => !!item && typeof item.author === "string" && typeof item.body === "string")
236
+ : [];
237
+ const nextTask = {
238
+ ...task,
239
+ status: "DONE",
240
+ commit: { hash: commitInfo.hash, message: commitInfo.message },
241
+ comments: [...existingComments, { author: opts.author, body: opts.body }],
242
+ events: appendTaskEvent(task, {
243
+ type: "status",
244
+ at,
245
+ author: opts.author,
246
+ from: String(task.status || "TODO").toUpperCase(),
247
+ to: "DONE",
248
+ note: opts.body,
249
+ }),
250
+ result_summary: taskId === metaTaskId && resultSummary ? resultSummary : task.result_summary,
251
+ risk_level: taskId === metaTaskId && riskLevel ? riskLevel : task.risk_level,
252
+ breaking: taskId === metaTaskId && breaking ? true : task.breaking,
253
+ doc_version: normalizeTaskDocVersion(task.doc_version),
254
+ doc_updated_at: at,
255
+ doc_updated_by: opts.author,
256
+ };
257
+ await ctx.taskBackend.writeTask(nextTask);
183
258
  }
184
- const existingComments = Array.isArray(task.comments)
185
- ? task.comments.filter((item) => !!item && typeof item.author === "string" && typeof item.body === "string")
186
- : [];
187
- const commentsValue = [...existingComments, { author: opts.author, body: opts.body }];
188
- const at = nowIso();
189
- const nextTask = {
190
- ...task,
191
- status: "DONE",
192
- commit: { hash: commitInfo.hash, message: commitInfo.message },
193
- comments: commentsValue,
194
- events: appendTaskEvent(task, {
195
- type: "status",
196
- at,
197
- author: opts.author,
198
- from: String(task.status || "TODO").toUpperCase(),
199
- to: "DONE",
200
- note: opts.body,
201
- }),
202
- result_summary: taskId === metaTaskId && resultSummary ? resultSummary : task.result_summary,
203
- risk_level: taskId === metaTaskId && riskLevel ? riskLevel : task.risk_level,
204
- breaking: taskId === metaTaskId && breaking ? true : task.breaking,
205
- doc_version: normalizeTaskDocVersion(task.doc_version),
206
- doc_updated_at: at,
207
- doc_updated_by: opts.author,
208
- };
209
- await (useStore
210
- ? store.update(taskId, () => nextTask)
211
- : ctx.taskBackend.writeTask(nextTask));
212
259
  }
213
260
  if (opts.commitFromComment || statusCommitRequested) {
214
261
  enforceStatusCommitPolicy({
@@ -233,6 +280,9 @@ export async function cmdFinish(opts) {
233
280
  }
234
281
  }
235
282
  if (opts.commitFromComment) {
283
+ if (!opts.quiet) {
284
+ process.stdout.write(`${infoMessage("task marked DONE; creating commit from verification comment")}\n`);
285
+ }
236
286
  if (typeof opts.commitEmoji === "string" && opts.commitEmoji.trim() !== "✅") {
237
287
  throw new CliError({
238
288
  exitCode: 2,
@@ -263,19 +313,28 @@ export async function cmdFinish(opts) {
263
313
  // commitFromComment creates the git commit and returns the actual head hash/subject.
264
314
  // Refresh task commit metadata to this hash and amend the same commit in local mode so
265
315
  // "task done" metadata does not require a manual follow-up close commit.
266
- const taskAfterCommit = useStore
267
- ? await store.get(primaryTaskId)
268
- : await loadTaskFromContext({ ctx, taskId: primaryTaskId });
269
- const updatedAfterCommit = {
270
- ...taskAfterCommit,
271
- commit: { hash: committed.hash, message: committed.message },
272
- doc_version: normalizeTaskDocVersion(taskAfterCommit.doc_version),
273
- doc_updated_at: nowIso(),
274
- doc_updated_by: opts.author,
275
- };
276
316
  await (useStore
277
- ? store.update(primaryTaskId, () => updatedAfterCommit)
278
- : ctx.taskBackend.writeTask(updatedAfterCommit));
317
+ ? store.patch(primaryTaskId, (current) => ({
318
+ task: {
319
+ commit: { hash: committed.hash, message: committed.message },
320
+ },
321
+ docMeta: {
322
+ touch: true,
323
+ updatedBy: opts.author,
324
+ version: normalizeTaskDocVersion(current.doc_version),
325
+ },
326
+ }))
327
+ : (async () => {
328
+ const taskAfterCommit = await loadTaskFromContext({ ctx, taskId: primaryTaskId });
329
+ const updatedAfterCommit = {
330
+ ...taskAfterCommit,
331
+ commit: { hash: committed.hash, message: committed.message },
332
+ doc_version: normalizeTaskDocVersion(taskAfterCommit.doc_version),
333
+ doc_updated_at: nowIso(),
334
+ doc_updated_by: opts.author,
335
+ };
336
+ await ctx.taskBackend.writeTask(updatedAfterCommit);
337
+ })());
279
338
  if (backendWritesTaskReadmes) {
280
339
  const workflowReadmeRelPath = path.join(ctx.config.paths.workflow_dir, primaryTaskId, "README.md");
281
340
  await ctx.git.stage([workflowReadmeRelPath]);
@@ -294,6 +353,9 @@ export async function cmdFinish(opts) {
294
353
  }
295
354
  }
296
355
  if (statusCommitRequested) {
356
+ if (!opts.quiet) {
357
+ process.stdout.write(`${infoMessage("task marked DONE; creating status commit")}\n`);
358
+ }
297
359
  if (typeof opts.statusCommitEmoji === "string" && opts.statusCommitEmoji.trim() !== "✅") {
298
360
  throw new CliError({
299
361
  exitCode: 2,
@@ -1 +1 @@
1
- {"version":3,"file":"migrate-doc.d.ts","sourceRoot":"","sources":["../../../src/commands/task/migrate-doc.ts"],"names":[],"mappings":"AAiSA,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqDlB"}
1
+ {"version":3,"file":"migrate-doc.d.ts","sourceRoot":"","sources":["../../../src/commands/task/migrate-doc.ts"],"names":[],"mappings":"AA2RA,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;IACf,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,GAAG,OAAO,CAAC,MAAM,CAAC,CAqDlB"}
@@ -7,7 +7,7 @@ import { fileExists, getPathKind } from "../../cli/fs-utils.js";
7
7
  import { successMessage } from "../../cli/output.js";
8
8
  import { CliError } from "../../shared/errors.js";
9
9
  import { exportTaskProjectionSnapshot, loadCommandContext } from "../shared/task-backend.js";
10
- import { extractDocSection, extractTaskObservationSection, normalizeTaskDocVersion, normalizeVerificationSectionLayout, } from "./shared/docs.js";
10
+ import { extractDocSection, extractTaskObservationSection, decodeEscapedTaskTextNewlines, normalizeTaskDocVersion, normalizeVerificationSectionLayout, } from "./shared/docs.js";
11
11
  import { defaultTaskDocV3 } from "./doc-template.js";
12
12
  const V3_CANONICAL_ORDER = [
13
13
  "Summary",
@@ -61,13 +61,7 @@ function renderMarkdownSections(sections) {
61
61
  function normalizeLiteralNewlinesInHumanSection(title, text) {
62
62
  if (!HUMAN_TEXT_SECTIONS.has(normalizeSectionKey(title)))
63
63
  return text.trimEnd();
64
- let next = text.replaceAll("\r\n", "\n");
65
- const escapedDoubleNewline = next.includes(String.raw `\n\n`) || next.includes(String.raw `\r\n\r\n`);
66
- const escapedNewlineMatches = next.match(/\\n/g) ?? [];
67
- if (escapedDoubleNewline || escapedNewlineMatches.length >= 2) {
68
- next = next.replaceAll(String.raw `\r\n`, "\n").replaceAll(String.raw `\n`, "\n");
69
- }
70
- return next.trimEnd();
64
+ return decodeEscapedTaskTextNewlines(text).trimEnd();
71
65
  }
72
66
  function firstSectionText(sections, title) {
73
67
  const target = normalizeSectionKey(title);
@@ -10,7 +10,7 @@ export const taskPlanSetSpec = {
10
10
  kind: "string",
11
11
  name: "text",
12
12
  valueHint: "<text>",
13
- description: "Plan text to write into the task README Plan section.",
13
+ description: String.raw `Plan text to write into the task README Plan section. Literal escaped newlines (\n) are normalized for inline text.`,
14
14
  },
15
15
  {
16
16
  kind: "string",
@@ -0,0 +1,8 @@
1
+ import type { CommandHandler, CommandSpec } from "../../cli/spec/spec.js";
2
+ type TaskPlanGroupParsed = {
3
+ cmd: string[];
4
+ };
5
+ export declare const taskPlanSpec: CommandSpec<TaskPlanGroupParsed>;
6
+ export declare const runTaskPlan: CommandHandler<TaskPlanGroupParsed>;
7
+ export {};
8
+ //# sourceMappingURL=plan.command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.command.d.ts","sourceRoot":"","sources":["../../../src/commands/task/plan.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAc,cAAc,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAItF,KAAK,mBAAmB,GAAG;IAAE,GAAG,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAI7C,eAAO,MAAM,YAAY,EAAE,WAAW,CAAC,mBAAmB,CAqBzD,CAAC;AAEF,eAAO,MAAM,WAAW,EAAE,cAAc,CAAC,mBAAmB,CAW3D,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { usageError } from "../../cli/spec/errors.js";
2
+ import { suggestOne } from "../../cli/spec/suggest.js";
3
+ const TASK_PLAN_SUBCOMMANDS = ["set", "approve", "reject"];
4
+ export const taskPlanSpec = {
5
+ id: ["task", "plan"],
6
+ group: "Task",
7
+ summary: "Task plan commands (set/approve/reject).",
8
+ synopsis: ["agentplane task plan <set|approve|reject> [args] [options]"],
9
+ args: [{ name: "cmd", required: false, variadic: true, valueHint: "<subcommand>" }],
10
+ examples: [
11
+ {
12
+ cmd: 'agentplane task plan set <task-id> --text "..." --updated-by ORCHESTRATOR',
13
+ why: "Write or replace the task plan.",
14
+ },
15
+ {
16
+ cmd: "agentplane task plan approve <task-id> --by ORCHESTRATOR",
17
+ why: "Approve the current task plan.",
18
+ },
19
+ {
20
+ cmd: 'agentplane task plan reject <task-id> --by ORCHESTRATOR --note "..."',
21
+ why: "Reject the current task plan with a note.",
22
+ },
23
+ ],
24
+ parse: (raw) => ({ cmd: (raw.args.cmd ?? []) }),
25
+ };
26
+ export const runTaskPlan = (_ctx, p) => {
27
+ const input = p.cmd.join(" ");
28
+ const suggestion = suggestOne(input, [...TASK_PLAN_SUBCOMMANDS]);
29
+ const suffix = suggestion ? ` Did you mean: ${suggestion}?` : "";
30
+ const message = p.cmd.length === 0 ? "Missing subcommand." : `Unknown subcommand: ${p.cmd[0]}.`;
31
+ throw usageError({
32
+ spec: taskPlanSpec,
33
+ command: "task plan",
34
+ message: `${message}${suffix}`,
35
+ context: { command: "task plan" },
36
+ });
37
+ };
@@ -1 +1 @@
1
- {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/commands/task/plan.ts"],"names":[],"mappings":"AASA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAuDnC,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,CAAC,CA6ElB;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,MAAM,CAAC,CA4FlB;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,MAAM,CAAC,CAuDlB"}
1
+ {"version":3,"file":"plan.d.ts","sourceRoot":"","sources":["../../../src/commands/task/plan.ts"],"names":[],"mappings":"AASA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAkJnC,wBAAsB,cAAc,CAAC,IAAI,EAAE;IACzC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,CAAC,CA8HlB;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE;IAC7C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,GAAG,OAAO,CAAC,MAAM,CAAC,CA2DlB;AAED,wBAAsB,iBAAiB,CAAC,IAAI,EAAE;IAC5C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,MAAM,CAAC,CAkElB"}