coding-agent-harness 1.0.2 → 1.0.4

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 (177) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/CONTRIBUTING.md +98 -0
  3. package/README.md +211 -86
  4. package/README.zh-CN.md +54 -34
  5. package/SKILL.md +25 -18
  6. package/docs-release/README.md +9 -5
  7. package/docs-release/architecture/overview.md +17 -5
  8. package/docs-release/architecture/overview.zh-CN.md +9 -5
  9. package/docs-release/assets/dashboard-overview.png +0 -0
  10. package/docs-release/guides/agent-installation.en-US.md +31 -8
  11. package/docs-release/guides/agent-installation.md +34 -9
  12. package/docs-release/guides/contributing.md +100 -0
  13. package/docs-release/guides/contributing.zh-CN.md +99 -0
  14. package/docs-release/guides/document-audience-and-surfaces.en-US.md +3 -2
  15. package/docs-release/guides/document-audience-and-surfaces.md +3 -2
  16. package/docs-release/guides/full-legacy-migration-subagent-strategy.md +2 -2
  17. package/docs-release/guides/full-legacy-migration-subagent-strategy.zh-CN.md +2 -2
  18. package/docs-release/guides/legacy-migration-agent-prompt.md +0 -11
  19. package/docs-release/guides/legacy-migration-agent-prompt.zh-CN.md +0 -11
  20. package/docs-release/guides/migration-playbook.en-US.md +14 -15
  21. package/docs-release/guides/migration-playbook.md +14 -15
  22. package/docs-release/guides/parent-control-repository-pattern.en-US.md +7 -5
  23. package/docs-release/guides/parent-control-repository-pattern.md +7 -5
  24. package/docs-release/guides/preset-development.md +214 -0
  25. package/docs-release/guides/repository-operating-models.en-US.md +5 -4
  26. package/docs-release/guides/repository-operating-models.md +5 -4
  27. package/docs-release/guides/task-state-machine.en-US.md +207 -0
  28. package/docs-release/guides/task-state-machine.md +214 -0
  29. package/docs-release/intl/en-US.md +1 -1
  30. package/docs-release/intl/zh-CN.md +1 -1
  31. package/examples/minimal-project/docs/09-PLANNING/TASKS/demo-task/findings.md +7 -0
  32. package/package.json +8 -3
  33. package/presets/legacy-migration/checks/preset-check.mjs +3 -0
  34. package/presets/legacy-migration/preset.yaml +134 -0
  35. package/presets/legacy-migration/scripts/plan-work-queue.mjs +4 -0
  36. package/presets/legacy-migration/scripts/scaffold-task-contracts.mjs +4 -0
  37. package/presets/legacy-migration/templates/execution_strategy.append.md +18 -0
  38. package/presets/legacy-migration/templates/findings.seed.md +17 -0
  39. package/presets/legacy-migration/templates/review.seed.md +12 -0
  40. package/presets/legacy-migration/templates/task_plan.append.md +9 -0
  41. package/presets/legacy-migration/templates/visual_map.append.md +12 -0
  42. package/presets/legacy-migration/workbench/dashboard-panels.yaml +2 -0
  43. package/presets/legacy-migration/workbench/migration-queue.schema.json +23 -0
  44. package/presets/lesson-sedimentation/preset.yaml +23 -0
  45. package/presets/lesson-sedimentation/templates/prompt.md +23 -0
  46. package/presets/module/preset.yaml +25 -0
  47. package/presets/module/templates/execution_strategy.append.md +8 -0
  48. package/presets/module/templates/task_plan.append.md +17 -0
  49. package/presets/standard-task/preset.yaml +31 -0
  50. package/presets/standard-task/templates/task_plan.append.md +7 -0
  51. package/references/adversarial-review-standard.md +2 -2
  52. package/references/agents-md-pattern.md +2 -2
  53. package/references/delivery-operating-model-standard.md +3 -3
  54. package/references/docs-directory-standard.md +6 -7
  55. package/references/harness-ledger.md +53 -96
  56. package/references/lessons-governance.md +88 -93
  57. package/references/module-parallel-standard.md +14 -14
  58. package/references/planning-loop.md +12 -6
  59. package/references/pull-request-standard.md +118 -0
  60. package/references/repo-governance-standard.md +11 -2
  61. package/references/review-routing-standard.md +7 -1
  62. package/references/ssot-governance.md +67 -59
  63. package/references/taskr-gap-analysis.md +600 -0
  64. package/references/walkthrough-closeout.md +7 -7
  65. package/scripts/check-harness.mjs +40 -301
  66. package/scripts/commands/dashboard-command.mjs +67 -0
  67. package/scripts/commands/migration-command.mjs +96 -0
  68. package/scripts/commands/preset-command.mjs +73 -0
  69. package/scripts/commands/task-command.mjs +327 -0
  70. package/scripts/harness.mjs +55 -260
  71. package/scripts/lib/capability-registry.mjs +66 -8
  72. package/scripts/lib/check-module-parallel.mjs +237 -0
  73. package/scripts/lib/check-profiles.mjs +61 -153
  74. package/scripts/lib/check-task-contracts.mjs +47 -0
  75. package/scripts/lib/core-shared.mjs +10 -0
  76. package/scripts/lib/dashboard-data.mjs +29 -6
  77. package/scripts/lib/dashboard-workbench.mjs +52 -12
  78. package/scripts/lib/dashboard-writer.mjs +14 -2
  79. package/scripts/lib/git-status-summary.mjs +46 -0
  80. package/scripts/lib/governance-index-generator.mjs +174 -0
  81. package/scripts/lib/governance-sync.mjs +514 -0
  82. package/scripts/lib/governance-table-boundary.mjs +175 -0
  83. package/scripts/lib/harness-core.mjs +5 -0
  84. package/scripts/lib/lesson-maintenance.mjs +36 -29
  85. package/scripts/lib/migration-support.mjs +1 -1
  86. package/scripts/lib/preset-audit-contracts.mjs +37 -0
  87. package/scripts/lib/preset-engine.mjs +497 -0
  88. package/scripts/lib/preset-registry.mjs +627 -0
  89. package/scripts/lib/preset-resource-contracts.mjs +83 -0
  90. package/scripts/lib/review-confirm-git-gate.mjs +248 -0
  91. package/scripts/lib/status-dashboard-renderer.mjs +102 -0
  92. package/scripts/lib/subagent-authorization-audit.mjs +196 -0
  93. package/scripts/lib/task-completion-consistency.mjs +16 -0
  94. package/scripts/lib/task-index.mjs +93 -0
  95. package/scripts/lib/task-lesson-candidates.mjs +242 -0
  96. package/scripts/lib/task-lesson-sedimentation.mjs +326 -0
  97. package/scripts/lib/task-lifecycle/review-confirm.mjs +101 -0
  98. package/scripts/lib/task-lifecycle/review-gates.mjs +70 -0
  99. package/scripts/lib/task-lifecycle/text-utils.mjs +24 -0
  100. package/scripts/lib/task-lifecycle.mjs +297 -403
  101. package/scripts/lib/task-review-model.mjs +469 -0
  102. package/scripts/lib/task-scanner.mjs +130 -236
  103. package/scripts/lib/task-tombstone-commands.mjs +140 -0
  104. package/scripts/postinstall.mjs +14 -0
  105. package/skills/preset-creator/SKILL.md +179 -0
  106. package/skills/preset-creator/references/complex-task-skeleton/README.md +31 -0
  107. package/skills/preset-creator/references/complex-task-skeleton/artifacts/INDEX.md +12 -0
  108. package/skills/preset-creator/references/complex-task-skeleton/brief.md +32 -0
  109. package/skills/preset-creator/references/complex-task-skeleton/execution_strategy.md +71 -0
  110. package/skills/preset-creator/references/complex-task-skeleton/findings.md +24 -0
  111. package/skills/preset-creator/references/complex-task-skeleton/lesson_candidates.md +70 -0
  112. package/skills/preset-creator/references/complex-task-skeleton/long-running-task-contract.md +76 -0
  113. package/skills/preset-creator/references/complex-task-skeleton/progress.md +33 -0
  114. package/skills/preset-creator/references/complex-task-skeleton/references/INDEX.md +13 -0
  115. package/skills/preset-creator/references/complex-task-skeleton/review.md +107 -0
  116. package/skills/preset-creator/references/complex-task-skeleton/task_plan.md +111 -0
  117. package/skills/preset-creator/references/complex-task-skeleton/visual_map.md +50 -0
  118. package/skills/preset-creator/references/preset-package-skeleton.md +296 -0
  119. package/templates/AGENTS.md.template +19 -15
  120. package/templates/dashboard/assets/app-src/00-state.js +1 -0
  121. package/templates/dashboard/assets/app-src/10-router.js +2 -1
  122. package/templates/dashboard/assets/app-src/20-overview.js +11 -5
  123. package/templates/dashboard/assets/app-src/30-tasks.js +92 -246
  124. package/templates/dashboard/assets/app-src/35-task-detail.js +246 -0
  125. package/templates/dashboard/assets/app-src/45-review.js +241 -22
  126. package/templates/dashboard/assets/app-src/50-migration.js +24 -10
  127. package/templates/dashboard/assets/app-src/90-bindings.js +171 -29
  128. package/templates/dashboard/assets/app.css +698 -156
  129. package/templates/dashboard/assets/app.css.manifest.json +9 -0
  130. package/templates/dashboard/assets/app.js +662 -91
  131. package/templates/dashboard/assets/app.manifest.json +1 -0
  132. package/templates/dashboard/assets/css-src/00-foundation.css +342 -0
  133. package/templates/dashboard/assets/css-src/10-panels-flow.css +236 -0
  134. package/templates/dashboard/assets/css-src/20-briefs-controls.css +398 -0
  135. package/templates/dashboard/assets/css-src/30-task-index.css +739 -0
  136. package/templates/dashboard/assets/css-src/35-review-workspace.css +507 -0
  137. package/templates/dashboard/assets/css-src/40-detail-modules-migration.css +427 -0
  138. package/templates/dashboard/assets/css-src/50-responsive-overrides.css +551 -0
  139. package/templates/dashboard/assets/i18n.js +123 -21
  140. package/templates/ledger/Harness-Ledger.md +13 -25
  141. package/templates/lessons/lesson-arch-process-change.md +1 -1
  142. package/templates/lessons/lesson-new-doc.md +1 -1
  143. package/templates/lessons/lesson-ref-change.md +1 -1
  144. package/templates/planning/execution_strategy.md +31 -0
  145. package/templates/planning/lesson_candidates.md +18 -6
  146. package/templates/planning/optional/artifacts/INDEX.md +3 -3
  147. package/templates/planning/optional/references/INDEX.md +3 -3
  148. package/templates/planning/review.md +59 -0
  149. package/templates/planning/task_plan.md +36 -13
  150. package/templates/reference/execution-workflow-standard.md +4 -3
  151. package/templates/reference/pull-request-standard.md +80 -0
  152. package/templates/reference/repo-governance-standard.md +7 -6
  153. package/templates/reference/review-routing-standard.md +6 -0
  154. package/templates/reference/walkthrough-standard.md +2 -1
  155. package/templates/verifier/verifier-output.md +1 -1
  156. package/templates-zh-CN/AGENTS.md.template +20 -16
  157. package/templates-zh-CN/ledger/Harness-Ledger.md +17 -40
  158. package/templates-zh-CN/planning/execution_strategy.md +30 -0
  159. package/templates-zh-CN/planning/lesson_candidates.md +18 -6
  160. package/templates-zh-CN/planning/review.md +59 -1
  161. package/templates-zh-CN/planning/task_plan.md +30 -10
  162. package/templates-zh-CN/reference/adversarial-review-standard.md +1 -1
  163. package/templates-zh-CN/reference/docs-library-standard.md +1 -1
  164. package/templates-zh-CN/reference/execution-workflow-standard.md +4 -3
  165. package/templates-zh-CN/reference/harness-ledger-standard.md +2 -2
  166. package/templates-zh-CN/reference/pull-request-standard.md +106 -0
  167. package/templates-zh-CN/reference/repo-governance-standard.md +4 -3
  168. package/templates-zh-CN/reference/review-routing-standard.md +8 -1
  169. package/templates-zh-CN/reference/walkthrough-standard.md +3 -2
  170. package/templates-zh-CN/walkthrough/Closeout-SSoT.md +1 -1
  171. package/docs-release/assets/dashboard-overview-en.png +0 -0
  172. package/scripts/smoke-dashboard.mjs +0 -92
  173. package/scripts/test-harness.mjs +0 -1395
  174. package/templates/ssot/Feature-SSoT.md +0 -43
  175. package/templates/ssot/Lessons-SSoT.md +0 -44
  176. package/templates-zh-CN/ssot/Feature-SSoT.md +0 -49
  177. package/templates-zh-CN/ssot/Lessons-SSoT.md +0 -49
@@ -0,0 +1,327 @@
1
+ import fs from "node:fs";
2
+ import {
3
+ confirmTaskReview,
4
+ createTask,
5
+ readPresetPackage,
6
+ buildTaskIndex,
7
+ createLessonSedimentationTask,
8
+ archiveTask,
9
+ listLifecycleTasks,
10
+ promoteLessonCandidate,
11
+ reopenTask,
12
+ softDeleteTask,
13
+ supersedeTask,
14
+ updateModuleStep,
15
+ updateTaskPhase,
16
+ updateTaskLifecycle,
17
+ } from "../lib/harness-core.mjs";
18
+
19
+ export function runTaskCommand(command, { args, takeFlag, takeOption, targetArg }) {
20
+ if (command === "new-task") {
21
+ const dryRun = takeFlag("--dry-run");
22
+ const locale = takeOption("--locale", "");
23
+ const title = takeOption("--title", "");
24
+ const moduleKey = takeOption("--module", "");
25
+ const budget = takeOption("--budget", "standard");
26
+ const preset = takeOption("--preset", "");
27
+ const fromSession = takeOption("--from-session", "");
28
+ const longRunning = takeFlag("--long-running");
29
+ try {
30
+ const parsed = parseNewTaskArgs(args, { preset, fromSession });
31
+ const taskId = parsed.taskId;
32
+ if (!taskId) {
33
+ console.error("Missing task id");
34
+ process.exit(2);
35
+ }
36
+ console.log(JSON.stringify(createTask(parsed.target, taskId, { title, locale, dryRun, moduleKey, budget, longRunning, preset, fromSession, presetArgs: parsed.presetArgs }), null, 2));
37
+ } catch (error) {
38
+ console.error(error.message);
39
+ process.exit(1);
40
+ }
41
+ return;
42
+ }
43
+
44
+ if (command === "task-phase") {
45
+ const state = takeOption("--state", "");
46
+ const completion = takeOption("--completion", "");
47
+ const evidenceStatus = takeOption("--evidence", "");
48
+ const taskId = args.shift();
49
+ const phaseId = args.shift();
50
+ if (!taskId || !phaseId) {
51
+ console.error("Missing task id or phase id");
52
+ process.exit(2);
53
+ }
54
+ try {
55
+ console.log(JSON.stringify(updateTaskPhase(targetArg(), taskId, phaseId, { state, completion, evidenceStatus }), null, 2));
56
+ } catch (error) {
57
+ console.error(error.message);
58
+ process.exit(1);
59
+ }
60
+ return;
61
+ }
62
+
63
+ if (["task-start", "task-log", "task-block", "task-review", "task-complete"].includes(command)) {
64
+ const message = takeOption("--message", "");
65
+ const evidence = takeOption("--evidence", "");
66
+ const taskId = args.shift();
67
+ if (!taskId) {
68
+ console.error("Missing task id");
69
+ process.exit(2);
70
+ }
71
+ const lifecycle = {
72
+ "task-start": { event: "task-start", state: "in_progress" },
73
+ "task-log": { event: "task-log", state: "" },
74
+ "task-block": { event: "task-block", state: "blocked" },
75
+ "task-review": { event: "task-review", state: "review" },
76
+ "task-complete": { event: "task-complete", state: "done" },
77
+ }[command];
78
+ try {
79
+ console.log(JSON.stringify(updateTaskLifecycle(targetArg(), taskId, { ...lifecycle, message, evidence }), null, 2));
80
+ } catch (error) {
81
+ console.error(error.message);
82
+ process.exit(1);
83
+ }
84
+ return;
85
+ }
86
+
87
+ if (command === "review-confirm") {
88
+ const reviewer = takeOption("--reviewer", "Human Reviewer");
89
+ const message = takeOption("--message", "");
90
+ const evidence = takeOption("--evidence", "");
91
+ const confirmText = takeOption("--confirm", "");
92
+ const taskId = args.shift();
93
+ if (!taskId) {
94
+ console.error("Missing task id");
95
+ process.exit(2);
96
+ }
97
+ try {
98
+ console.log(JSON.stringify(confirmTaskReview(targetArg(), taskId, { reviewer, message, evidence, confirmText }), null, 2));
99
+ } catch (error) {
100
+ console.error(formatTaskCommandError(error));
101
+ process.exit(1);
102
+ }
103
+ return;
104
+ }
105
+
106
+ if (command === "lesson-promote") {
107
+ const dryRun = takeFlag("--dry-run");
108
+ const apply = takeFlag("--apply");
109
+ const taskId = args.shift();
110
+ const candidateId = args.shift();
111
+ if (!taskId || !candidateId) {
112
+ console.error("Missing task id or candidate id");
113
+ process.exit(2);
114
+ }
115
+ try {
116
+ console.log(JSON.stringify(promoteLessonCandidate(targetArg(), taskId, candidateId, { dryRun, apply }), null, 2));
117
+ } catch (error) {
118
+ console.error(error.message);
119
+ process.exit(1);
120
+ }
121
+ return;
122
+ }
123
+
124
+ if (command === "lesson-sediment") {
125
+ const dryRun = takeFlag("--dry-run");
126
+ const title = takeOption("--title", "");
127
+ const taskId = args.shift();
128
+ const candidateId = args.shift();
129
+ if (!taskId || !candidateId) {
130
+ console.error("Missing task id or candidate id");
131
+ process.exit(2);
132
+ }
133
+ try {
134
+ console.log(JSON.stringify(createLessonSedimentationTask(targetArg(), taskId, candidateId, { dryRun, title }), null, 2));
135
+ } catch (error) {
136
+ console.error(error.message);
137
+ process.exit(1);
138
+ }
139
+ return;
140
+ }
141
+
142
+ if (command === "task-list") {
143
+ const json = takeFlag("--json");
144
+ const state = takeOption("--state", "");
145
+ const moduleKey = takeOption("--module", "");
146
+ const queue = takeOption("--queue", "");
147
+ const preset = takeOption("--preset", "");
148
+ const review = takeOption("--review", "");
149
+ const lesson = takeOption("--lesson", "");
150
+ const search = takeOption("--search", "");
151
+ const missingMaterials = takeFlag("--missing-materials");
152
+ const result = listLifecycleTasks(targetArg(), { state, moduleKey, queue, preset, review, lesson, search, missingMaterials });
153
+ if (json) {
154
+ console.log(JSON.stringify(result, null, 2));
155
+ } else {
156
+ for (const task of result.tasks) {
157
+ console.log(`${task.id}\t${task.state}\t${task.completion}%\t${task.title}`);
158
+ }
159
+ }
160
+ return;
161
+ }
162
+
163
+ if (command === "task-index") {
164
+ const json = takeFlag("--json");
165
+ const result = buildTaskIndex(targetArg());
166
+ if (json) console.log(JSON.stringify(result, null, 2));
167
+ else console.log(`${result.tasks.length} tasks indexed (${result.schemaVersion})`);
168
+ return;
169
+ }
170
+
171
+ if (command === "task-supersede") {
172
+ const by = takeOption("--by", "");
173
+ const reason = takeOption("--reason", "");
174
+ const taskId = args.shift();
175
+ if (!taskId) {
176
+ console.error("Missing task id");
177
+ process.exit(2);
178
+ }
179
+ try {
180
+ console.log(JSON.stringify(supersedeTask(targetArg(), taskId, { by, reason }), null, 2));
181
+ } catch (error) {
182
+ console.error(error.message);
183
+ process.exit(1);
184
+ }
185
+ return;
186
+ }
187
+
188
+ if (["task-delete", "task-archive", "task-reopen"].includes(command)) {
189
+ const soft = takeFlag("--soft");
190
+ const reason = takeOption("--reason", "");
191
+ const taskId = args.shift();
192
+ if (!taskId) {
193
+ console.error("Missing task id");
194
+ process.exit(2);
195
+ }
196
+ try {
197
+ if (command === "task-delete" && !soft) throw new Error("task-delete only supports --soft; hard delete is intentionally disabled.");
198
+ const result =
199
+ command === "task-delete"
200
+ ? softDeleteTask(targetArg(), taskId, { reason })
201
+ : command === "task-archive"
202
+ ? archiveTask(targetArg(), taskId, { reason })
203
+ : reopenTask(targetArg(), taskId, { reason });
204
+ console.log(JSON.stringify(result, null, 2));
205
+ } catch (error) {
206
+ console.error(error.message);
207
+ process.exit(1);
208
+ }
209
+ return;
210
+ }
211
+
212
+ if (command === "module-step") {
213
+ const state = takeOption("--state", "done");
214
+ const moduleKey = args.shift();
215
+ const stepId = args.shift();
216
+ if (!moduleKey || !stepId) {
217
+ console.error("Missing module key or step id");
218
+ process.exit(2);
219
+ }
220
+ try {
221
+ console.log(JSON.stringify(updateModuleStep(targetArg(), moduleKey, stepId, { state }), null, 2));
222
+ } catch (error) {
223
+ console.error(error.message);
224
+ process.exit(1);
225
+ }
226
+ return;
227
+ }
228
+
229
+ throw new Error(`Unsupported task command: ${command}`);
230
+ }
231
+
232
+ function parseNewTaskArgs(args, { preset = "", fromSession = "" } = {}) {
233
+ const values = [...args];
234
+ let taskId = "";
235
+ if (!fromSession) {
236
+ taskId = values.shift() || "";
237
+ } else if (values.length > 0 && !values[0].startsWith("-") && !(values.length === 1 && fs.existsSync(values[0]))) {
238
+ taskId = values.shift();
239
+ }
240
+ const presetPackage = preset ? readPresetPackageForNewTask(preset, values) : null;
241
+ if (!taskId && fromSession) taskId = presetPackage?.task?.defaultTaskId || "harness-v1-migration";
242
+ const parsed = splitPresetArgsAndTarget(values, presetPackage);
243
+ return {
244
+ taskId,
245
+ target: parsed.target || ".",
246
+ presetArgs: parsed.presetArgs,
247
+ };
248
+ }
249
+
250
+ function readPresetPackageForNewTask(preset, values) {
251
+ const candidates = presetDiscoveryTargetCandidates(values);
252
+ let fallbackPackage = null;
253
+ let lastError = null;
254
+ for (const targetInput of candidates) {
255
+ try {
256
+ const presetPackage = readPresetPackage(preset, { targetInput });
257
+ if (presetPackage.source === "project") return presetPackage;
258
+ if (!fallbackPackage) fallbackPackage = presetPackage;
259
+ } catch (error) {
260
+ lastError = error;
261
+ }
262
+ }
263
+ if (fallbackPackage) return fallbackPackage;
264
+ throw lastError;
265
+ }
266
+
267
+ function presetDiscoveryTargetCandidates(values) {
268
+ const candidates = [];
269
+ for (let index = values.length - 1; index >= 0; index -= 1) {
270
+ const value = values[index];
271
+ if (!value || value.startsWith("-")) continue;
272
+ if (!candidates.includes(value)) candidates.push(value);
273
+ }
274
+ if (!candidates.includes(".")) candidates.push(".");
275
+ return candidates;
276
+ }
277
+
278
+ function splitPresetArgsAndTarget(values, presetPackage) {
279
+ const presetArgs = [];
280
+ const targetCandidates = [];
281
+ const declaredFlags = new Map(Object.values(presetPackage?.inputs || {}).filter((input) => input.flag).map((input) => [input.flag, input]));
282
+ for (let index = 0; index < values.length; index += 1) {
283
+ const value = values[index];
284
+ const declared = declaredFlags.get(value);
285
+ if (declared) {
286
+ presetArgs.push(value);
287
+ if (declared.type !== "flag" && index + 1 < values.length) {
288
+ presetArgs.push(values[index + 1]);
289
+ index += 1;
290
+ }
291
+ } else if (value.startsWith("-")) {
292
+ presetArgs.push(value);
293
+ if (index + 1 < values.length && !values[index + 1].startsWith("-")) {
294
+ presetArgs.push(values[index + 1]);
295
+ index += 1;
296
+ }
297
+ } else {
298
+ targetCandidates.push(value);
299
+ }
300
+ }
301
+ if (targetCandidates.length > 1) {
302
+ throw new Error(`Too many positional arguments for new-task: ${targetCandidates.join(", ")}`);
303
+ }
304
+ return {
305
+ target: targetCandidates[0] || "",
306
+ presetArgs,
307
+ };
308
+ }
309
+
310
+ function formatTaskCommandError(error) {
311
+ const lines = [error.message];
312
+ if (Array.isArray(error.recovery) && error.recovery.length > 0) {
313
+ lines.push("", "Recovery:");
314
+ for (const item of error.recovery) lines.push(`- ${item}`);
315
+ }
316
+ if (error.details?.entries?.length) {
317
+ lines.push("", "Blocking Git status:");
318
+ for (const entry of error.details.entries) lines.push(`- ${entry.raw || entry.path}`);
319
+ }
320
+ if (error.details?.disallowed?.length) {
321
+ lines.push("", "Disallowed paths:");
322
+ for (const item of error.details.disallowed) lines.push(`- ${item}`);
323
+ }
324
+ if (error.details?.stderr) lines.push("", error.details.stderr);
325
+ if (error.details?.stdout) lines.push("", error.details.stdout);
326
+ return lines.join("\n");
327
+ }