agentplane 0.3.5 → 0.3.7

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 (256) 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 +251 -821
  8. package/dist/adapters/task-backend/task-backend-adapter.d.ts +2 -2
  9. package/dist/adapters/task-backend/task-backend-adapter.d.ts.map +1 -1
  10. package/dist/adapters/task-backend/task-backend-adapter.js +2 -2
  11. package/dist/backends/task-backend/local-backend.d.ts +7 -5
  12. package/dist/backends/task-backend/local-backend.d.ts.map +1 -1
  13. package/dist/backends/task-backend/local-backend.js +79 -7
  14. package/dist/backends/task-backend/redmine/env.d.ts +1 -1
  15. package/dist/backends/task-backend/redmine/env.d.ts.map +1 -1
  16. package/dist/backends/task-backend/redmine/env.js +3 -0
  17. package/dist/backends/task-backend/redmine/inspect.d.ts +11 -0
  18. package/dist/backends/task-backend/redmine/inspect.d.ts.map +1 -0
  19. package/dist/backends/task-backend/redmine/inspect.js +75 -0
  20. package/dist/backends/task-backend/redmine/mapping.d.ts.map +1 -1
  21. package/dist/backends/task-backend/redmine/mapping.js +21 -2
  22. package/dist/backends/task-backend/redmine/state.d.ts +17 -0
  23. package/dist/backends/task-backend/redmine/state.d.ts.map +1 -0
  24. package/dist/backends/task-backend/redmine/state.js +95 -0
  25. package/dist/backends/task-backend/redmine-backend.d.ts +10 -16
  26. package/dist/backends/task-backend/redmine-backend.d.ts.map +1 -1
  27. package/dist/backends/task-backend/redmine-backend.js +205 -15
  28. package/dist/backends/task-backend/shared/constants.d.ts +1 -1
  29. package/dist/backends/task-backend/shared/constants.js +1 -1
  30. package/dist/backends/task-backend/shared/record.d.ts.map +1 -1
  31. package/dist/backends/task-backend/shared/record.js +20 -1
  32. package/dist/backends/task-backend/shared/types.d.ts +42 -4
  33. package/dist/backends/task-backend/shared/types.d.ts.map +1 -1
  34. package/dist/backends/task-backend/shared.d.ts +1 -1
  35. package/dist/backends/task-backend/shared.d.ts.map +1 -1
  36. package/dist/backends/task-backend.d.ts +1 -1
  37. package/dist/backends/task-backend.d.ts.map +1 -1
  38. package/dist/backends/task-backend.test-helpers.d.ts +4 -0
  39. package/dist/backends/task-backend.test-helpers.d.ts.map +1 -0
  40. package/dist/backends/task-backend.test-helpers.js +33 -0
  41. package/dist/backends/task-index.d.ts.map +1 -1
  42. package/dist/backends/task-index.js +1 -0
  43. package/dist/cli/bootstrap-guide.d.ts.map +1 -1
  44. package/dist/cli/bootstrap-guide.js +1 -0
  45. package/dist/cli/command-guide.d.ts.map +1 -1
  46. package/dist/cli/command-guide.js +3 -2
  47. package/dist/cli/reason-codes.d.ts.map +1 -1
  48. package/dist/cli/reason-codes.js +30 -0
  49. package/dist/cli/run-cli/command-catalog/core.d.ts +3 -0
  50. package/dist/cli/run-cli/command-catalog/core.d.ts.map +1 -0
  51. package/dist/cli/run-cli/command-catalog/core.js +137 -0
  52. package/dist/cli/run-cli/command-catalog/lifecycle.d.ts +3 -0
  53. package/dist/cli/run-cli/command-catalog/lifecycle.d.ts.map +1 -0
  54. package/dist/cli/run-cli/command-catalog/lifecycle.js +52 -0
  55. package/dist/cli/run-cli/command-catalog/project.d.ts +3 -0
  56. package/dist/cli/run-cli/command-catalog/project.d.ts.map +1 -0
  57. package/dist/cli/run-cli/command-catalog/project.js +80 -0
  58. package/dist/cli/run-cli/command-catalog/shared.d.ts +19 -0
  59. package/dist/cli/run-cli/command-catalog/shared.d.ts.map +1 -0
  60. package/dist/cli/run-cli/command-catalog/shared.js +9 -0
  61. package/dist/cli/run-cli/command-catalog/task.d.ts +3 -0
  62. package/dist/cli/run-cli/command-catalog/task.d.ts.map +1 -0
  63. package/dist/cli/run-cli/command-catalog/task.js +85 -0
  64. package/dist/cli/run-cli/command-catalog.d.ts +3 -18
  65. package/dist/cli/run-cli/command-catalog.d.ts.map +1 -1
  66. package/dist/cli/run-cli/command-catalog.js +8 -337
  67. package/dist/cli/run-cli/commands/ide.d.ts.map +1 -1
  68. package/dist/cli/run-cli/commands/ide.js +64 -2
  69. package/dist/cli/run-cli/commands/init/ui.d.ts.map +1 -1
  70. package/dist/cli/run-cli/commands/init/ui.js +33 -13
  71. package/dist/cli/run-cli/commands/init/write-env.d.ts.map +1 -1
  72. package/dist/cli/run-cli/commands/init/write-env.js +12 -0
  73. package/dist/cli/run-cli.core.pr-flow.test-helpers.d.ts +3 -0
  74. package/dist/cli/run-cli.core.pr-flow.test-helpers.d.ts.map +1 -0
  75. package/dist/cli/run-cli.core.pr-flow.test-helpers.js +41 -0
  76. package/dist/cli/run-cli.core.tasks.test-helpers.d.ts +2 -0
  77. package/dist/cli/run-cli.core.tasks.test-helpers.d.ts.map +1 -0
  78. package/dist/cli/run-cli.core.tasks.test-helpers.js +6 -0
  79. package/dist/cli/run-cli.test-helpers.d.ts +3 -0
  80. package/dist/cli/run-cli.test-helpers.d.ts.map +1 -1
  81. package/dist/cli/run-cli.test-helpers.js +140 -6
  82. package/dist/commands/backend/sync.command.d.ts +5 -1
  83. package/dist/commands/backend/sync.command.d.ts.map +1 -1
  84. package/dist/commands/backend/sync.command.js +67 -3
  85. package/dist/commands/backend.d.ts +22 -0
  86. package/dist/commands/backend.d.ts.map +1 -1
  87. package/dist/commands/backend.js +110 -1
  88. package/dist/commands/commit.spec.d.ts.map +1 -1
  89. package/dist/commands/commit.spec.js +31 -7
  90. package/dist/commands/doctor/runtime.d.ts.map +1 -1
  91. package/dist/commands/doctor/runtime.js +3 -6
  92. package/dist/commands/doctor/workspace.d.ts +8 -0
  93. package/dist/commands/doctor/workspace.d.ts.map +1 -1
  94. package/dist/commands/doctor/workspace.js +127 -3
  95. package/dist/commands/guard/commit.command.d.ts.map +1 -1
  96. package/dist/commands/guard/commit.command.js +30 -6
  97. package/dist/commands/guard/impl/allow.d.ts +9 -0
  98. package/dist/commands/guard/impl/allow.d.ts.map +1 -1
  99. package/dist/commands/guard/impl/allow.js +26 -10
  100. package/dist/commands/guard/impl/commands.d.ts.map +1 -1
  101. package/dist/commands/guard/impl/commands.js +146 -18
  102. package/dist/commands/guard/impl/comment-commit.d.ts.map +1 -1
  103. package/dist/commands/guard/impl/comment-commit.js +2 -0
  104. package/dist/commands/hooks/index.d.ts.map +1 -1
  105. package/dist/commands/hooks/index.js +8 -35
  106. package/dist/commands/recipes/impl/apply.d.ts +4 -0
  107. package/dist/commands/recipes/impl/apply.d.ts.map +1 -1
  108. package/dist/commands/recipes/impl/apply.js +34 -0
  109. package/dist/commands/recipes/impl/commands/explain.d.ts.map +1 -1
  110. package/dist/commands/recipes/impl/commands/explain.js +70 -11
  111. package/dist/commands/recipes/impl/commands/info.d.ts.map +1 -1
  112. package/dist/commands/recipes/impl/commands/info.js +24 -12
  113. package/dist/commands/recipes/impl/commands/install.d.ts.map +1 -1
  114. package/dist/commands/recipes/impl/commands/install.js +32 -36
  115. package/dist/commands/recipes/impl/commands/list.d.ts.map +1 -1
  116. package/dist/commands/recipes/impl/commands/list.js +7 -4
  117. package/dist/commands/recipes/impl/commands/remove.d.ts.map +1 -1
  118. package/dist/commands/recipes/impl/commands/remove.js +9 -11
  119. package/dist/commands/recipes/impl/constants.d.ts +2 -0
  120. package/dist/commands/recipes/impl/constants.d.ts.map +1 -1
  121. package/dist/commands/recipes/impl/constants.js +2 -0
  122. package/dist/commands/recipes/impl/manifest.d.ts.map +1 -1
  123. package/dist/commands/recipes/impl/manifest.js +219 -23
  124. package/dist/commands/recipes/impl/normalize.d.ts +3 -0
  125. package/dist/commands/recipes/impl/normalize.d.ts.map +1 -1
  126. package/dist/commands/recipes/impl/normalize.js +28 -24
  127. package/dist/commands/recipes/impl/paths.d.ts +9 -0
  128. package/dist/commands/recipes/impl/paths.d.ts.map +1 -1
  129. package/dist/commands/recipes/impl/paths.js +10 -1
  130. package/dist/commands/recipes/impl/project-installed-recipes.d.ts +7 -0
  131. package/dist/commands/recipes/impl/project-installed-recipes.d.ts.map +1 -0
  132. package/dist/commands/recipes/impl/project-installed-recipes.js +102 -0
  133. package/dist/commands/recipes/impl/resolver.d.ts +20 -0
  134. package/dist/commands/recipes/impl/resolver.d.ts.map +1 -0
  135. package/dist/commands/recipes/impl/resolver.js +220 -0
  136. package/dist/commands/recipes/impl/scenario.d.ts.map +1 -1
  137. package/dist/commands/recipes/impl/scenario.js +40 -11
  138. package/dist/commands/recipes/impl/types.d.ts +145 -16
  139. package/dist/commands/recipes/impl/types.d.ts.map +1 -1
  140. package/dist/commands/recipes/install.spec.d.ts.map +1 -1
  141. package/dist/commands/recipes/install.spec.js +3 -2
  142. package/dist/commands/recipes.d.ts +6 -4
  143. package/dist/commands/recipes.d.ts.map +1 -1
  144. package/dist/commands/recipes.js +5 -3
  145. package/dist/commands/recipes.test-helpers.d.ts +185 -0
  146. package/dist/commands/recipes.test-helpers.d.ts.map +1 -0
  147. package/dist/commands/recipes.test-helpers.js +339 -0
  148. package/dist/commands/scenario/impl/commands.d.ts.map +1 -1
  149. package/dist/commands/scenario/impl/commands.js +192 -336
  150. package/dist/commands/scenario/info.command.d.ts.map +1 -1
  151. package/dist/commands/scenario/info.command.js +7 -2
  152. package/dist/commands/scenario/list.command.js +2 -2
  153. package/dist/commands/scenario/run.command.d.ts.map +1 -1
  154. package/dist/commands/scenario/run.command.js +7 -2
  155. package/dist/commands/shared/reconcile-check.d.ts.map +1 -1
  156. package/dist/commands/shared/reconcile-check.js +77 -2
  157. package/dist/commands/shared/task-backend.d.ts +1 -1
  158. package/dist/commands/shared/task-backend.d.ts.map +1 -1
  159. package/dist/commands/shared/task-backend.js +9 -0
  160. package/dist/commands/shared/task-store.d.ts +92 -2
  161. package/dist/commands/shared/task-store.d.ts.map +1 -1
  162. package/dist/commands/shared/task-store.js +405 -43
  163. package/dist/commands/task/block.d.ts.map +1 -1
  164. package/dist/commands/task/block.js +84 -46
  165. package/dist/commands/task/close-duplicate.d.ts.map +1 -1
  166. package/dist/commands/task/close-duplicate.js +12 -37
  167. package/dist/commands/task/close-noop.d.ts.map +1 -1
  168. package/dist/commands/task/close-noop.js +12 -30
  169. package/dist/commands/task/close-shared.d.ts +14 -0
  170. package/dist/commands/task/close-shared.d.ts.map +1 -0
  171. package/dist/commands/task/close-shared.js +73 -0
  172. package/dist/commands/task/comment.d.ts.map +1 -1
  173. package/dist/commands/task/comment.js +34 -21
  174. package/dist/commands/task/derive.command.d.ts +1 -0
  175. package/dist/commands/task/derive.command.d.ts.map +1 -1
  176. package/dist/commands/task/derive.command.js +15 -2
  177. package/dist/commands/task/derive.d.ts +1 -0
  178. package/dist/commands/task/derive.d.ts.map +1 -1
  179. package/dist/commands/task/derive.js +27 -4
  180. package/dist/commands/task/doc-set.command.d.ts +2 -1
  181. package/dist/commands/task/doc-set.command.d.ts.map +1 -1
  182. package/dist/commands/task/doc-set.command.js +36 -4
  183. package/dist/commands/task/doc-template.d.ts.map +1 -1
  184. package/dist/commands/task/doc-template.js +2 -7
  185. package/dist/commands/task/doc.command.js +1 -1
  186. package/dist/commands/task/doc.d.ts +2 -1
  187. package/dist/commands/task/doc.d.ts.map +1 -1
  188. package/dist/commands/task/doc.js +139 -76
  189. package/dist/commands/task/finish.d.ts.map +1 -1
  190. package/dist/commands/task/finish.js +142 -80
  191. package/dist/commands/task/migrate-doc.d.ts +15 -0
  192. package/dist/commands/task/migrate-doc.d.ts.map +1 -1
  193. package/dist/commands/task/migrate-doc.js +128 -43
  194. package/dist/commands/task/new.d.ts.map +1 -1
  195. package/dist/commands/task/new.js +3 -1
  196. package/dist/commands/task/plan-set.command.js +1 -1
  197. package/dist/commands/task/plan.command.d.ts +8 -0
  198. package/dist/commands/task/plan.command.d.ts.map +1 -0
  199. package/dist/commands/task/plan.command.js +37 -0
  200. package/dist/commands/task/plan.d.ts.map +1 -1
  201. package/dist/commands/task/plan.js +198 -101
  202. package/dist/commands/task/set-status.command.d.ts.map +1 -1
  203. package/dist/commands/task/set-status.command.js +1 -1
  204. package/dist/commands/task/set-status.d.ts.map +1 -1
  205. package/dist/commands/task/set-status.js +115 -35
  206. package/dist/commands/task/shared/dependencies.d.ts +1 -0
  207. package/dist/commands/task/shared/dependencies.d.ts.map +1 -1
  208. package/dist/commands/task/shared/dependencies.js +10 -0
  209. package/dist/commands/task/shared/docs.d.ts +1 -0
  210. package/dist/commands/task/shared/docs.d.ts.map +1 -1
  211. package/dist/commands/task/shared/docs.js +8 -1
  212. package/dist/commands/task/shared/transitions.d.ts +17 -2
  213. package/dist/commands/task/shared/transitions.d.ts.map +1 -1
  214. package/dist/commands/task/shared/transitions.js +20 -13
  215. package/dist/commands/task/shared.d.ts +3 -3
  216. package/dist/commands/task/shared.d.ts.map +1 -1
  217. package/dist/commands/task/shared.js +3 -3
  218. package/dist/commands/task/start.d.ts.map +1 -1
  219. package/dist/commands/task/start.js +101 -71
  220. package/dist/commands/task/task.command.d.ts +8 -0
  221. package/dist/commands/task/task.command.d.ts.map +1 -0
  222. package/dist/commands/task/task.command.js +71 -0
  223. package/dist/commands/task/verify-command-shared.d.ts +16 -0
  224. package/dist/commands/task/verify-command-shared.d.ts.map +1 -0
  225. package/dist/commands/task/verify-command-shared.js +53 -0
  226. package/dist/commands/task/verify-ok.command.d.ts +2 -6
  227. package/dist/commands/task/verify-ok.command.d.ts.map +1 -1
  228. package/dist/commands/task/verify-ok.command.js +8 -50
  229. package/dist/commands/task/verify-record.d.ts.map +1 -1
  230. package/dist/commands/task/verify-record.js +124 -145
  231. package/dist/commands/task/verify-rework.command.d.ts +2 -6
  232. package/dist/commands/task/verify-rework.command.d.ts.map +1 -1
  233. package/dist/commands/task/verify-rework.command.js +8 -50
  234. package/dist/commands/upgrade/apply.d.ts +2 -0
  235. package/dist/commands/upgrade/apply.d.ts.map +1 -1
  236. package/dist/commands/upgrade/apply.js +33 -1
  237. package/dist/commands/upgrade.command.d.ts.map +1 -1
  238. package/dist/commands/upgrade.command.js +25 -0
  239. package/dist/commands/upgrade.d.ts +1 -0
  240. package/dist/commands/upgrade.d.ts.map +1 -1
  241. package/dist/commands/upgrade.js +34 -0
  242. package/dist/commands/verify.spec.d.ts.map +1 -1
  243. package/dist/commands/verify.spec.js +3 -12
  244. package/dist/policy/rules/allowlist.d.ts.map +1 -1
  245. package/dist/policy/rules/allowlist.js +16 -4
  246. package/dist/policy/rules/protected-paths.d.ts.map +1 -1
  247. package/dist/policy/rules/protected-paths.js +6 -1
  248. package/dist/ports/task-backend-port.d.ts +2 -2
  249. package/dist/ports/task-backend-port.d.ts.map +1 -1
  250. package/dist/shared/agent-emoji.d.ts.map +1 -1
  251. package/dist/shared/protected-paths.d.ts +17 -0
  252. package/dist/shared/protected-paths.d.ts.map +1 -1
  253. package/dist/shared/protected-paths.js +59 -10
  254. package/dist/shared/repo-cli-version.d.ts.map +1 -1
  255. package/dist/shared/repo-cli-version.js +9 -3
  256. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"close-duplicate.d.ts","sourceRoot":"","sources":["../../../src/commands/task/close-duplicate.ts"],"names":[],"mappings":"AAIA,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AASrF,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,cAAc,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAuFlB"}
1
+ {"version":3,"file":"close-duplicate.d.ts","sourceRoot":"","sources":["../../../src/commands/task/close-duplicate.ts"],"names":[],"mappings":"AAGA,OAAO,EAAuB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIrF,wBAAsB,qBAAqB,CAAC,IAAI,EAAE;IAChD,GAAG,EAAE,cAAc,CAAC;IACpB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2DlB"}
@@ -3,7 +3,7 @@ import { CliError } from "../../shared/errors.js";
3
3
  import { ensureActionApproved } from "../shared/approval-requirements.js";
4
4
  import { loadTaskFromContext } from "../shared/task-backend.js";
5
5
  import { backendIsLocalFileBackend, getTaskStore } from "../shared/task-store.js";
6
- import { appendTaskEvent, normalizeTaskDocVersion, nowIso, requireStructuredComment, } from "./shared.js";
6
+ import { recordVerifiedNoopClosure } from "./close-shared.js";
7
7
  export async function cmdTaskCloseDuplicate(opts) {
8
8
  try {
9
9
  const sourceId = opts.taskId.trim();
@@ -36,47 +36,22 @@ export async function cmdTaskCloseDuplicate(opts) {
36
36
  const task = useStore
37
37
  ? await store.get(sourceId)
38
38
  : await loadTaskFromContext({ ctx: opts.ctx, taskId: sourceId });
39
- if (!opts.force && String(task.status || "TODO").toUpperCase() === "DONE") {
40
- throw new CliError({
41
- exitCode: 2,
42
- code: "E_USAGE",
43
- message: `Task is already DONE: ${sourceId} (use --force to override)`,
44
- });
45
- }
46
39
  const reason = opts.note?.trim();
47
40
  const canonicalTitle = canonical.title?.trim() ? ` (${canonical.title.trim()})` : "";
48
41
  const baseBody = `Verified: ${sourceId} is a bookkeeping duplicate of ${duplicateOf}${canonicalTitle}; ` +
49
42
  "no code/config changes are expected in this task and closure is recorded as no-op.";
50
43
  const body = reason ? `${baseBody}\n\nReason: ${reason}` : baseBody;
51
- const verifiedCfg = opts.ctx.config.tasks.comments.verified;
52
- requireStructuredComment(body, verifiedCfg.prefix, verifiedCfg.min_chars);
53
- const at = nowIso();
54
- const next = {
55
- ...task,
56
- status: "DONE",
57
- comments: [
58
- ...(Array.isArray(task.comments) ? task.comments : []),
59
- { author: opts.author, body },
60
- ],
61
- events: appendTaskEvent(task, {
62
- type: "status",
63
- at,
64
- author: opts.author,
65
- from: String(task.status || "TODO").toUpperCase(),
66
- to: "DONE",
67
- note: body,
68
- }),
69
- result_summary: `Closed as duplicate of ${duplicateOf}.`,
70
- risk_level: "low",
71
- breaking: false,
72
- doc_version: normalizeTaskDocVersion(task.doc_version),
73
- doc_updated_at: at,
74
- doc_updated_by: opts.author,
75
- };
76
- await (useStore ? store.update(sourceId, () => next) : opts.ctx.taskBackend.writeTask(next));
77
- if (!opts.quiet) {
78
- process.stdout.write(`task.done: ${sourceId} (duplicate of ${duplicateOf})\n`);
79
- }
44
+ await recordVerifiedNoopClosure({
45
+ ctx: opts.ctx,
46
+ task,
47
+ taskId: sourceId,
48
+ author: opts.author,
49
+ body,
50
+ resultSummary: `Closed as duplicate of ${duplicateOf}.`,
51
+ quiet: opts.quiet,
52
+ successMessage: `task.done: ${sourceId} (duplicate of ${duplicateOf})`,
53
+ force: opts.force,
54
+ });
80
55
  return 0;
81
56
  }
82
57
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"close-noop.d.ts","sourceRoot":"","sources":["../../../src/commands/task/close-noop.ts"],"names":[],"mappings":"AAIA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAQpF,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsElB"}
1
+ {"version":3,"file":"close-noop.d.ts","sourceRoot":"","sources":["../../../src/commands/task/close-noop.ts"],"names":[],"mappings":"AAIA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAGpF,wBAAsB,gBAAgB,CAAC,IAAI,EAAE;IAC3C,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,OAAO,CAAC;IACb,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAoDlB"}
@@ -3,7 +3,7 @@ import { CliError } from "../../shared/errors.js";
3
3
  import { ensureActionApproved } from "../shared/approval-requirements.js";
4
4
  import { backendIsLocalFileBackend, getTaskStore } from "../shared/task-store.js";
5
5
  import { loadCommandContext } from "../shared/task-backend.js";
6
- import { appendTaskEvent, normalizeTaskDocVersion, nowIso, requireStructuredComment, } from "./shared.js";
6
+ import { recordVerifiedNoopClosure } from "./close-shared.js";
7
7
  export async function cmdTaskCloseNoop(opts) {
8
8
  try {
9
9
  const ctx = opts.ctx ??
@@ -38,35 +38,17 @@ export async function cmdTaskCloseNoop(opts) {
38
38
  const normalizedNote = opts.note?.trim();
39
39
  const baseBody = "Verified: no implementation changes were required; closure is recorded as no-op bookkeeping.";
40
40
  const body = normalizedNote ? `${baseBody}\n\nNote: ${normalizedNote}` : baseBody;
41
- const verifiedCfg = ctx.config.tasks.comments.verified;
42
- requireStructuredComment(body, verifiedCfg.prefix, verifiedCfg.min_chars);
43
- const at = nowIso();
44
- const next = {
45
- ...task,
46
- status: "DONE",
47
- comments: [
48
- ...(Array.isArray(task.comments) ? task.comments : []),
49
- { author: opts.author, body },
50
- ],
51
- events: appendTaskEvent(task, {
52
- type: "status",
53
- at,
54
- author: opts.author,
55
- from: String(task.status || "TODO").toUpperCase(),
56
- to: "DONE",
57
- note: body,
58
- }),
59
- result_summary: "No-op closure recorded.",
60
- risk_level: "low",
61
- breaking: false,
62
- doc_version: normalizeTaskDocVersion(task.doc_version),
63
- doc_updated_at: at,
64
- doc_updated_by: opts.author,
65
- };
66
- await (useStore ? store.update(opts.taskId, () => next) : ctx.taskBackend.writeTask(next));
67
- if (!opts.quiet) {
68
- process.stdout.write(`task.done: ${opts.taskId} (no-op)\n`);
69
- }
41
+ await recordVerifiedNoopClosure({
42
+ ctx,
43
+ task,
44
+ taskId: opts.taskId,
45
+ author: opts.author,
46
+ body,
47
+ resultSummary: "No-op closure recorded.",
48
+ quiet: opts.quiet,
49
+ successMessage: `task.done: ${opts.taskId} (no-op)`,
50
+ force: opts.force,
51
+ });
70
52
  return 0;
71
53
  }
72
54
  catch (err) {
@@ -0,0 +1,14 @@
1
+ import { type TaskData } from "../../backends/task-backend.js";
2
+ import { type CommandContext } from "../shared/task-backend.js";
3
+ export declare function recordVerifiedNoopClosure(opts: {
4
+ ctx: CommandContext;
5
+ task: TaskData;
6
+ taskId: string;
7
+ author: string;
8
+ body: string;
9
+ resultSummary: string;
10
+ quiet: boolean;
11
+ successMessage: string;
12
+ force: boolean;
13
+ }): Promise<void>;
14
+ //# sourceMappingURL=close-shared.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"close-shared.d.ts","sourceRoot":"","sources":["../../../src/commands/task/close-shared.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAE/D,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAgBhE,wBAAsB,yBAAyB,CAAC,IAAI,EAAE;IACpD,GAAG,EAAE,cAAc,CAAC;IACpB,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,OAAO,CAAC;IACf,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,IAAI,CAAC,CAwEhB"}
@@ -0,0 +1,73 @@
1
+ import { CliError } from "../../shared/errors.js";
2
+ import { appendTaskCommentIntent, appendTaskEventIntent, backendIsLocalFileBackend, getTaskStore, setTaskFieldsIntent, touchTaskDocMetaIntent, } from "../shared/task-store.js";
3
+ import { appendTaskEvent, normalizeTaskDocVersion, nowIso, requireStructuredComment, } from "./shared.js";
4
+ export async function recordVerifiedNoopClosure(opts) {
5
+ if (!opts.force && String(opts.task.status || "TODO").toUpperCase() === "DONE") {
6
+ throw new CliError({
7
+ exitCode: 2,
8
+ code: "E_USAGE",
9
+ message: `Task is already DONE: ${opts.taskId} (use --force to override)`,
10
+ });
11
+ }
12
+ const verifiedCfg = opts.ctx.config.tasks.comments.verified;
13
+ requireStructuredComment(opts.body, verifiedCfg.prefix, verifiedCfg.min_chars);
14
+ const at = nowIso();
15
+ const useStore = backendIsLocalFileBackend(opts.ctx);
16
+ const store = useStore ? getTaskStore(opts.ctx) : null;
17
+ await (useStore
18
+ ? store.mutate(opts.taskId, (current) => {
19
+ if (!opts.force && String(current.status || "TODO").toUpperCase() === "DONE") {
20
+ throw new CliError({
21
+ exitCode: 2,
22
+ code: "E_USAGE",
23
+ message: `Task is already DONE: ${opts.taskId} (use --force to override)`,
24
+ });
25
+ }
26
+ return [
27
+ setTaskFieldsIntent({
28
+ status: "DONE",
29
+ result_summary: opts.resultSummary,
30
+ risk_level: "low",
31
+ breaking: false,
32
+ }),
33
+ appendTaskCommentIntent({ author: opts.author, body: opts.body }),
34
+ appendTaskEventIntent({
35
+ type: "status",
36
+ at,
37
+ author: opts.author,
38
+ from: String(current.status || "TODO").toUpperCase(),
39
+ to: "DONE",
40
+ note: opts.body,
41
+ }),
42
+ touchTaskDocMetaIntent({
43
+ updatedBy: opts.author,
44
+ version: normalizeTaskDocVersion(current.doc_version),
45
+ }),
46
+ ];
47
+ })
48
+ : opts.ctx.taskBackend.writeTask({
49
+ ...opts.task,
50
+ status: "DONE",
51
+ comments: [
52
+ ...(Array.isArray(opts.task.comments) ? opts.task.comments : []),
53
+ { author: opts.author, body: opts.body },
54
+ ],
55
+ events: appendTaskEvent(opts.task, {
56
+ type: "status",
57
+ at,
58
+ author: opts.author,
59
+ from: String(opts.task.status || "TODO").toUpperCase(),
60
+ to: "DONE",
61
+ note: opts.body,
62
+ }),
63
+ result_summary: opts.resultSummary,
64
+ risk_level: "low",
65
+ breaking: false,
66
+ doc_version: normalizeTaskDocVersion(opts.task.doc_version),
67
+ doc_updated_at: at,
68
+ doc_updated_by: opts.author,
69
+ }));
70
+ if (!opts.quiet) {
71
+ process.stdout.write(`${opts.successMessage}\n`);
72
+ }
73
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"comment.d.ts","sourceRoot":"","sources":["../../../src/commands/task/comment.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAInC,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,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,MAAM,CAAC,CAoClB"}
1
+ {"version":3,"file":"comment.d.ts","sourceRoot":"","sources":["../../../src/commands/task/comment.ts"],"names":[],"mappings":"AAGA,OAAO,EAGL,KAAK,cAAc,EACpB,MAAM,2BAA2B,CAAC;AAUnC,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,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd,GAAG,OAAO,CAAC,MAAM,CAAC,CAiDlB"}
@@ -1,7 +1,7 @@
1
1
  import { mapBackendError } from "../../cli/error-map.js";
2
2
  import { successMessage } from "../../cli/output.js";
3
3
  import { loadCommandContext, loadTaskFromContext, } from "../shared/task-backend.js";
4
- import { backendIsLocalFileBackend, getTaskStore } from "../shared/task-store.js";
4
+ import { appendTaskCommentIntent, appendTaskEventIntent, backendIsLocalFileBackend, getTaskStore, touchTaskDocMetaIntent, } from "../shared/task-store.js";
5
5
  import { appendTaskEvent, normalizeTaskDocVersion, nowIso } from "./shared.js";
6
6
  export async function cmdTaskComment(opts) {
7
7
  try {
@@ -9,27 +9,40 @@ export async function cmdTaskComment(opts) {
9
9
  (await loadCommandContext({ cwd: opts.cwd, rootOverride: opts.rootOverride ?? null }));
10
10
  const useStore = backendIsLocalFileBackend(ctx);
11
11
  const store = useStore ? getTaskStore(ctx) : null;
12
- const task = useStore
13
- ? await store.get(opts.taskId)
14
- : await loadTaskFromContext({ ctx, taskId: opts.taskId });
15
- const existing = Array.isArray(task.comments)
16
- ? task.comments.filter((item) => !!item && typeof item.author === "string" && typeof item.body === "string")
17
- : [];
12
+ const task = useStore ? null : await loadTaskFromContext({ ctx, taskId: opts.taskId });
18
13
  const at = nowIso();
19
- const next = {
20
- ...task,
21
- comments: [...existing, { author: opts.author, body: opts.body }],
22
- events: appendTaskEvent(task, {
23
- type: "comment",
24
- at,
25
- author: opts.author,
26
- body: opts.body,
27
- }),
28
- doc_version: normalizeTaskDocVersion(task.doc_version),
29
- doc_updated_at: at,
30
- doc_updated_by: opts.author,
31
- };
32
- await (useStore ? store.update(opts.taskId, () => next) : ctx.taskBackend.writeTask(next));
14
+ await (useStore
15
+ ? store.mutate(opts.taskId, (current) => [
16
+ appendTaskCommentIntent({ author: opts.author, body: opts.body }),
17
+ appendTaskEventIntent({
18
+ type: "comment",
19
+ at,
20
+ author: opts.author,
21
+ body: opts.body,
22
+ }),
23
+ touchTaskDocMetaIntent({
24
+ updatedBy: opts.author,
25
+ version: normalizeTaskDocVersion(current.doc_version),
26
+ }),
27
+ ])
28
+ : ctx.taskBackend.writeTask({
29
+ ...task,
30
+ comments: [
31
+ ...(Array.isArray(task.comments)
32
+ ? task.comments.filter((item) => !!item && typeof item.author === "string" && typeof item.body === "string")
33
+ : []),
34
+ { author: opts.author, body: opts.body },
35
+ ],
36
+ events: appendTaskEvent(task, {
37
+ type: "comment",
38
+ at,
39
+ author: opts.author,
40
+ body: opts.body,
41
+ }),
42
+ doc_version: normalizeTaskDocVersion(task.doc_version),
43
+ doc_updated_at: at,
44
+ doc_updated_by: opts.author,
45
+ }));
33
46
  process.stdout.write(`${successMessage("commented", opts.taskId)}\n`);
34
47
  return 0;
35
48
  }
@@ -7,6 +7,7 @@ export type TaskDeriveParsed = {
7
7
  owner: string;
8
8
  priority: "low" | "normal" | "med" | "high";
9
9
  tags: string[];
10
+ verify: string[];
10
11
  };
11
12
  export declare const taskDeriveSpec: CommandSpec<TaskDeriveParsed>;
12
13
  export declare function makeRunTaskDeriveHandler(getCtx: (cmd: string) => Promise<CommandContext>): (ctx: CommandCtx, p: TaskDeriveParsed) => Promise<number>;
@@ -1 +1 @@
1
- {"version":3,"file":"derive.command.d.ts","sourceRoot":"","sources":["../../../src/commands/task/derive.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAC5C,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,gBAAgB,CAqExD,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACzE,KAAK,UAAU,EAAE,GAAG,gBAAgB,KAAG,OAAO,CAAC,MAAM,CAAC,CAarE"}
1
+ {"version":3,"file":"derive.command.d.ts","sourceRoot":"","sources":["../../../src/commands/task/derive.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAGtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAC5C,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,gBAAgB,CAiFxD,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACzE,KAAK,UAAU,EAAE,GAAG,gBAAgB,KAAG,OAAO,CAAC,MAAM,CAAC,CAcrE"}
@@ -45,13 +45,24 @@ export const taskDeriveSpec = {
45
45
  minCount: 1,
46
46
  description: "Repeatable. Adds a tag (must provide at least one).",
47
47
  },
48
+ {
49
+ kind: "string",
50
+ name: "verify",
51
+ valueHint: "<command>",
52
+ repeatable: true,
53
+ description: "Repeatable. Verification commands/checks to run for this task.",
54
+ },
48
55
  ],
49
56
  examples: [
50
57
  {
51
- cmd: 'agentplane task derive 202602070101-ABCD --title "Implement X" --description "Do the thing" --owner CODER --tag code',
52
- why: "Create an implementation task derived from a spike.",
58
+ cmd: 'agentplane task derive 202602070101-ABCD --title "Implement X" --description "Do the thing" --owner CODER --tag code --verify "bun test"',
59
+ why: "Create an implementation task derived from a spike with seeded verify steps.",
53
60
  },
54
61
  ],
62
+ notes: [
63
+ "Derived tasks default to doc_version=3 and seed the README v3 section contract automatically.",
64
+ "For verify-required primary tags, this command seeds a default ## Verify Steps acceptance contract in README.",
65
+ ],
55
66
  validateRaw: (raw) => {
56
67
  const tags = toStringList(raw.opts.tag);
57
68
  if (tags.some((t) => t.trim() === "")) {
@@ -69,6 +80,7 @@ export const taskDeriveSpec = {
69
80
  owner: raw.opts.owner,
70
81
  priority: raw.opts.priority ?? "med",
71
82
  tags: toStringList(raw.opts.tag),
83
+ verify: (raw.opts.verify ?? []),
72
84
  }),
73
85
  };
74
86
  export function makeRunTaskDeriveHandler(getCtx) {
@@ -83,6 +95,7 @@ export function makeRunTaskDeriveHandler(getCtx) {
83
95
  owner: p.owner,
84
96
  priority: p.priority,
85
97
  tags: p.tags,
98
+ verify: p.verify,
86
99
  });
87
100
  };
88
101
  }
@@ -9,5 +9,6 @@ export declare function cmdTaskDerive(opts: {
9
9
  owner: string;
10
10
  priority: "low" | "normal" | "med" | "high";
11
11
  tags: string[];
12
+ verify: string[];
12
13
  }): Promise<number>;
13
14
  //# sourceMappingURL=derive.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../../../src/commands/task/derive.ts"],"names":[],"mappings":"AAGA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAepF,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAC5C,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiElB"}
1
+ {"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../../../src/commands/task/derive.ts"],"names":[],"mappings":"AAKA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAuBpF,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,KAAK,GAAG,QAAQ,GAAG,KAAK,GAAG,MAAM,CAAC;IAC5C,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CAsGlB"}
@@ -1,8 +1,10 @@
1
+ import { setMarkdownSection, taskDocToSectionMap } from "@agentplaneorg/core";
1
2
  import { mapBackendError } from "../../cli/error-map.js";
2
- import { unknownEntityMessage } from "../../cli/output.js";
3
+ import { unknownEntityMessage, warnMessage } from "../../cli/output.js";
3
4
  import { CliError } from "../../shared/errors.js";
4
5
  import { loadCommandContext } from "../shared/task-backend.js";
5
- import { extractTaskObservationSection, normalizeTaskDocVersion, nowIso, toStringArray, } from "./shared.js";
6
+ import { buildDefaultVerifyStepsSection, defaultTaskDocV3, TASK_DOC_VERSION_V3, } from "./doc-template.js";
7
+ import { extractTaskObservationSection, normalizeTaskDocVersion, nowIso, requiresVerifyStepsByPrimary, resolvePrimaryTag, toStringArray, warnIfUnknownOwner, } from "./shared.js";
6
8
  function normalizeOneLine(text, maxChars) {
7
9
  const normalized = text.trim().replaceAll(/\s+/g, " ");
8
10
  if (normalized.length <= maxChars)
@@ -45,6 +47,25 @@ export async function cmdTaskDerive(opts) {
45
47
  description = `${description} (derived from spike ${opts.spikeId})`;
46
48
  if (excerpt)
47
49
  description = `${description} [spike_notes: ${excerpt}]`;
50
+ let doc = defaultTaskDocV3({ title: opts.title, description });
51
+ const spikeTag = (ctx.config.tasks.verify.spike_tag ?? "spike").trim().toLowerCase();
52
+ const primary = resolvePrimaryTag(opts.tags, ctx);
53
+ if (primary.usedFallback) {
54
+ process.stderr.write(`${warnMessage(`primary tag not found in task tags; using fallback primary=${primary.primary}`)}\n`);
55
+ }
56
+ const requiresVerifySteps = requiresVerifyStepsByPrimary(opts.tags, ctx.config);
57
+ await warnIfUnknownOwner(ctx, opts.owner);
58
+ if (requiresVerifySteps) {
59
+ doc = setMarkdownSection(doc, "Verify Steps", buildDefaultVerifyStepsSection({
60
+ primary: primary.primary,
61
+ verifyCommands: opts.verify,
62
+ }));
63
+ process.stderr.write(`${warnMessage("task requires Verify Steps by primary tag; seeded a default ## Verify Steps section in README (review and refine before approval/start)")}\n`);
64
+ }
65
+ const hasSpike = opts.tags.some((tag) => tag.trim().toLowerCase() === spikeTag);
66
+ if (hasSpike && requiresVerifySteps) {
67
+ process.stderr.write(`${warnMessage("spike is combined with a primary tag that requires verify steps; consider splitting spike vs implementation tasks")}\n`);
68
+ }
48
69
  const at = nowIso();
49
70
  await ctx.taskBackend.writeTask({
50
71
  id: taskId,
@@ -55,9 +76,11 @@ export async function cmdTaskDerive(opts) {
55
76
  owner: opts.owner,
56
77
  tags: opts.tags,
57
78
  depends_on: [opts.spikeId],
58
- verify: [],
79
+ verify: opts.verify,
59
80
  comments: [],
60
- doc_version: 2,
81
+ doc,
82
+ sections: taskDocToSectionMap(doc),
83
+ doc_version: TASK_DOC_VERSION_V3,
61
84
  doc_updated_at: at,
62
85
  doc_updated_by: opts.owner,
63
86
  id_source: "generated",
@@ -2,10 +2,11 @@ import type { CommandCtx, CommandSpec } from "../../cli/spec/spec.js";
2
2
  import type { CommandContext } from "../shared/task-backend.js";
3
3
  export type TaskDocSetParsed = {
4
4
  taskId: string;
5
- section: string;
5
+ section?: string;
6
6
  text?: string;
7
7
  file?: string;
8
8
  updatedBy?: string;
9
+ fullDoc: boolean;
9
10
  };
10
11
  export declare const taskDocSetSpec: CommandSpec<TaskDocSetParsed>;
11
12
  export declare function makeRunTaskDocSetHandler(getCtx: (cmd: string) => Promise<CommandContext>): (ctx: CommandCtx, p: TaskDocSetParsed) => Promise<number>;
@@ -1 +1 @@
1
- {"version":3,"file":"doc-set.command.d.ts","sourceRoot":"","sources":["../../../src/commands/task/doc-set.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAEtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,gBAAgB,CAiExD,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACzE,KAAK,UAAU,EAAE,GAAG,gBAAgB,KAAG,OAAO,CAAC,MAAM,CAAC,CAYrE"}
1
+ {"version":3,"file":"doc-set.command.d.ts","sourceRoot":"","sources":["../../../src/commands/task/doc-set.command.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAEtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,MAAM,MAAM,gBAAgB,GAAG;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,WAAW,CAAC,gBAAgB,CAiGxD,CAAC;AAEF,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,cAAc,CAAC,IACzE,KAAK,UAAU,EAAE,GAAG,gBAAgB,KAAG,OAAO,CAAC,MAAM,CAAC,CAarE"}
@@ -4,20 +4,29 @@ export const taskDocSetSpec = {
4
4
  id: ["task", "doc", "set"],
5
5
  group: "Task",
6
6
  summary: "Update a task README section.",
7
+ synopsis: [
8
+ "agentplane task doc set <task-id> --section <name> (--text <text> | --file <path>) [--updated-by <id>]",
9
+ "agentplane task doc set <task-id> --full-doc (--text <text> | --file <path>) [--updated-by <id>]",
10
+ ],
7
11
  args: [{ name: "task-id", required: true, valueHint: "<task-id>" }],
8
12
  options: [
9
13
  {
10
14
  kind: "string",
11
15
  name: "section",
12
16
  valueHint: "<name>",
13
- required: true,
14
- description: "Target section heading (must be one of config.tasks.doc.sections).",
17
+ description: "Target section heading (must be one of config.tasks.doc.sections). Required unless --full-doc is set.",
18
+ },
19
+ {
20
+ kind: "boolean",
21
+ name: "full-doc",
22
+ default: false,
23
+ description: "Treat the provided text/file as the full task README payload.",
15
24
  },
16
25
  {
17
26
  kind: "string",
18
27
  name: "text",
19
28
  valueHint: "<text>",
20
- description: "Section content (mutually exclusive with --file).",
29
+ description: String.raw `Section content (mutually exclusive with --file). Literal escaped newlines (\n) are normalized for inline text.`,
21
30
  },
22
31
  {
23
32
  kind: "string",
@@ -41,8 +50,29 @@ export const taskDocSetSpec = {
41
50
  cmd: "agentplane task doc set 202602030608-F1Q8AB --section Plan --file ./plan.md",
42
51
  why: "Update one section using a file.",
43
52
  },
53
+ {
54
+ cmd: "agentplane task doc set 202602030608-F1Q8AB --full-doc --file ./task-readme.md",
55
+ why: "Replace the full task README payload explicitly.",
56
+ },
44
57
  ],
45
58
  validateRaw: (raw) => {
59
+ const fullDoc = raw.opts["full-doc"] === true;
60
+ const section = typeof raw.opts.section === "string" ? raw.opts.section.trim() : "";
61
+ if (fullDoc && section) {
62
+ throw usageError({
63
+ spec: taskDocSetSpec,
64
+ message: "Use either --section or --full-doc (not both).",
65
+ });
66
+ }
67
+ if (!fullDoc && !section) {
68
+ throw usageError({
69
+ spec: taskDocSetSpec,
70
+ message: "Missing required option: --section (or pass --full-doc).",
71
+ });
72
+ }
73
+ if (typeof raw.opts.section === "string" && section === "") {
74
+ throw usageError({ spec: taskDocSetSpec, message: "Invalid value for --section: empty." });
75
+ }
46
76
  const hasText = typeof raw.opts.text === "string";
47
77
  const hasFile = typeof raw.opts.file === "string";
48
78
  if (hasText === hasFile) {
@@ -59,10 +89,11 @@ export const taskDocSetSpec = {
59
89
  parse: (raw) => {
60
90
  return {
61
91
  taskId: String(raw.args["task-id"]),
62
- section: String(raw.opts.section),
92
+ section: typeof raw.opts.section === "string" ? raw.opts.section : undefined,
63
93
  text: typeof raw.opts.text === "string" ? raw.opts.text : undefined,
64
94
  file: typeof raw.opts.file === "string" ? raw.opts.file : undefined,
65
95
  updatedBy: typeof raw.opts["updated-by"] === "string" ? raw.opts["updated-by"] : undefined,
96
+ fullDoc: raw.opts["full-doc"] === true,
66
97
  };
67
98
  },
68
99
  };
@@ -77,6 +108,7 @@ export function makeRunTaskDocSetHandler(getCtx) {
77
108
  text: p.text,
78
109
  file: p.file,
79
110
  updatedBy: p.updatedBy,
111
+ fullDoc: p.fullDoc,
80
112
  });
81
113
  };
82
114
  }
@@ -1 +1 @@
1
- {"version":3,"file":"doc-template.d.ts","sourceRoot":"","sources":["../../../src/commands/task/doc-template.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,mBAAmB,IAAI,CAAC;AAkErC,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAkCrF;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,GAAG,MAAM,CA2BT"}
1
+ {"version":3,"file":"doc-template.d.ts","sourceRoot":"","sources":["../../../src/commands/task/doc-template.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,mBAAmB,IAAI,CAAC;AA2DrC,wBAAgB,gBAAgB,CAAC,IAAI,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,GAAG,MAAM,CAkCrF;AAED,wBAAgB,8BAA8B,CAAC,IAAI,EAAE;IACnD,OAAO,EAAE,MAAM,CAAC;IAChB,cAAc,EAAE,MAAM,EAAE,CAAC;CAC1B,GAAG,MAAM,CA2BT"}
@@ -1,13 +1,8 @@
1
1
  import { setMarkdownSection } from "@agentplaneorg/core";
2
+ import { decodeEscapedTaskTextNewlines } from "./shared/docs.js";
2
3
  export const TASK_DOC_VERSION_V3 = 3;
3
4
  function normalizeTaskHumanText(text) {
4
- let next = text.replaceAll("\r\n", "\n");
5
- const escapedDoubleNewline = next.includes(String.raw `\n\n`) || next.includes(String.raw `\r\n\r\n`);
6
- const escapedNewlineMatches = next.match(/\\n/g) ?? [];
7
- if (escapedDoubleNewline || escapedNewlineMatches.length >= 2) {
8
- next = next.replaceAll(String.raw `\r\n`, "\n").replaceAll(String.raw `\n`, "\n");
9
- }
10
- return next.trim();
5
+ return decodeEscapedTaskTextNewlines(text).trim();
11
6
  }
12
7
  function normalizeTaskHumanInlineText(text) {
13
8
  return normalizeTaskHumanText(text)
@@ -6,7 +6,7 @@ export const taskDocSpec = {
6
6
  synopsis: [
7
7
  "agentplane task doc show <task-id> [--section <name>] [--quiet]",
8
8
  "agentplane task doc set <task-id> --section <name> (--text <text> | --file <path>) [--updated-by <id>]",
9
- "agentplane task doc set <task-id> --section Summary --file ./task-readme.md # if payload contains multiple known ## headings, apply as full-doc update",
9
+ "agentplane task doc set <task-id> --full-doc (--text <text> | --file <path>) [--updated-by <id>]",
10
10
  ],
11
11
  args: [{ name: "subcommand", required: false, valueHint: "<show|set>" }],
12
12
  parse: (raw) => {
@@ -4,10 +4,11 @@ export declare function cmdTaskDocSet(opts: {
4
4
  cwd: string;
5
5
  rootOverride?: string;
6
6
  taskId: string;
7
- section: string;
7
+ section?: string;
8
8
  text?: string;
9
9
  file?: string;
10
10
  updatedBy?: string;
11
+ fullDoc: boolean;
11
12
  }): Promise<number>;
12
13
  export declare function cmdTaskDocShow(opts: {
13
14
  ctx?: CommandContext;
@@ -1 +1 @@
1
- {"version":3,"file":"doc.d.ts","sourceRoot":"","sources":["../../../src/commands/task/doc.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAmBpF,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2IlB;AAED,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,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CA4ClB"}
1
+ {"version":3,"file":"doc.d.ts","sourceRoot":"","sources":["../../../src/commands/task/doc.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAsB,KAAK,cAAc,EAAE,MAAM,2BAA2B,CAAC;AA6CpF,wBAAsB,aAAa,CAAC,IAAI,EAAE;IACxC,GAAG,CAAC,EAAE,cAAc,CAAC;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,OAAO,CAAC;CAClB,GAAG,OAAO,CAAC,MAAM,CAAC,CAgLlB;AAED,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,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;CAChB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyDlB"}