@tea-agent/loop-agent 0.1.0 → 0.2.1

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 (143) hide show
  1. package/AGENTS.md +62 -45
  2. package/CHANGELOG.md +60 -28
  3. package/README.md +160 -124
  4. package/bin/loop-agent.js +21 -21
  5. package/dist/adapters/index.js +3 -2
  6. package/dist/adapters/loop-agent.js +44 -2
  7. package/dist/application/dag/args.js +420 -0
  8. package/dist/application/dag/generate-task-dag.js +280 -0
  9. package/dist/application/dag/report-dag.js +14 -0
  10. package/dist/application/dag/run-dag.js +106 -0
  11. package/dist/application/dag/validate-dag.js +102 -0
  12. package/dist/application/loop/run-action.js +23 -0
  13. package/dist/cli/catalog.js +2 -237
  14. package/dist/cli/command-definitions.js +571 -0
  15. package/dist/cli/index.js +2 -0
  16. package/dist/cli/program.js +65 -1
  17. package/dist/cli/router.js +13 -0
  18. package/dist/cli-governance/active-residue-check.js +38 -0
  19. package/dist/commands/dag-report.js +6 -107
  20. package/dist/commands/dag-run-task.js +8 -466
  21. package/dist/commands/dag-validate.js +7 -179
  22. package/dist/commands/examples.js +90 -0
  23. package/dist/commands/init.js +1518 -0
  24. package/dist/commands/loop.js +57 -31
  25. package/dist/commands/pi-prompt.js +2 -9
  26. package/dist/commands/run-dag.js +7 -180
  27. package/dist/executors/cursor-executor-artifacts.js +3 -4
  28. package/dist/executors/cursor-worker-client.js +13 -3
  29. package/dist/executors/dag-cursor-executor.js +2 -3
  30. package/dist/executors/dag-pi-executor.js +3 -4
  31. package/dist/executors/dag-static-executor.js +2 -5
  32. package/dist/executors/pi-defaults.js +9 -0
  33. package/dist/executors/shell-executor.js +12 -20
  34. package/dist/governance/manifest-types.js +1 -0
  35. package/dist/infrastructure/harness/active-residue-policy.js +73 -0
  36. package/dist/infrastructure/harness/artifact-store.js +72 -0
  37. package/dist/infrastructure/harness/atomic-write.js +49 -0
  38. package/dist/infrastructure/harness/completed-facts-guard.js +40 -0
  39. package/dist/infrastructure/harness/loop-action-store.js +23 -0
  40. package/dist/infrastructure/harness/loop-store.js +41 -0
  41. package/dist/infrastructure/harness/one-shot-run-store.js +94 -0
  42. package/dist/infrastructure/harness/task-store.js +77 -0
  43. package/dist/records/one-shot-runs.js +26 -61
  44. package/dist/records/promotion.js +3 -4
  45. package/dist/shared/artifacts-core.js +5 -5
  46. package/dist/shared/logger.js +9 -15
  47. package/dist/task/delegate.js +4 -4
  48. package/dist/task/runtime.js +5 -7
  49. package/dist/task/state.js +6 -20
  50. package/dist/workflows/dag/convergence/controller.js +277 -0
  51. package/dist/workflows/dag/dynamic-runtime/condition.js +48 -0
  52. package/dist/workflows/dag/dynamic-runtime/loop-until.js +156 -0
  53. package/dist/workflows/dag/dynamic-runtime/map.js +185 -0
  54. package/dist/workflows/dag/dynamic-runtime/reduction.js +72 -0
  55. package/dist/workflows/dag/dynamic-runtime/shared.js +133 -0
  56. package/dist/workflows/dag/failure-routing.js +82 -0
  57. package/dist/workflows/dag/lifecycle.js +101 -8
  58. package/dist/workflows/dag/node-execution.js +262 -0
  59. package/dist/workflows/dag/report.js +73 -1
  60. package/dist/workflows/dag/run-store.js +36 -0
  61. package/dist/workflows/dag/runner.js +82 -1341
  62. package/dist/workflows/dag/scheduler.js +84 -0
  63. package/dist/workflows/dag/upstream-artifacts.js +20 -18
  64. package/dist/workflows/loop/actions/cursor-fix.js +191 -0
  65. package/dist/workflows/loop/actions/dag-action.js +130 -0
  66. package/dist/workflows/loop/actions/pi-review.js +267 -0
  67. package/dist/workflows/loop/actions/shared.js +157 -0
  68. package/dist/workflows/loop/actions/shell-verify.js +82 -0
  69. package/dist/workflows/loop/actions/types.js +1 -0
  70. package/dist/workflows/loop/actions/workflow-action.js +255 -0
  71. package/dist/workflows/loop/actions.js +55 -1212
  72. package/dist/workflows/loop/closeout.js +5 -4
  73. package/dist/workflows/loop/context.js +2 -3
  74. package/dist/workflows/loop/events.js +3 -2
  75. package/dist/workflows/loop/policy/auto-policy.js +104 -0
  76. package/dist/workflows/loop/policy/cursor-fix-policy.js +31 -0
  77. package/dist/workflows/loop/rounds.js +3 -3
  78. package/dist/workflows/loop/signals.js +4 -7
  79. package/dist/workflows/loop/state.js +11 -11
  80. package/docs/README.md +47 -44
  81. package/docs/agent-dag-recovery-playbook.md +32 -6
  82. package/docs/agent-dag-runner.md +17 -17
  83. package/docs/architecture/runtime-boundaries.md +147 -0
  84. package/docs/cursor-executor-usage.md +5 -5
  85. package/docs/decisions/README.md +2 -2
  86. package/docs/design/README.md +24 -24
  87. package/docs/development-principles.md +50 -50
  88. package/docs/dynamic-workflow-dag-engine-roadmap.md +6 -6
  89. package/docs/exec-plans/README.md +4 -4
  90. package/docs/exec-plans/active/README.md +10 -5
  91. package/docs/exec-plans/completed/README.md +9 -5
  92. package/docs/feature-workflow.md +111 -109
  93. package/docs/harness-methodology-verification.md +18 -18
  94. package/docs/loop-agent-harness.md +36 -36
  95. package/docs/production-readiness.md +96 -0
  96. package/docs/progress/README.md +2 -2
  97. package/docs/reports/README.md +4 -2
  98. package/docs/templates/agent-dag-decision-gate-dogfood-report.md +1 -1
  99. package/docs/templates/agent-dag-process-supervisor.prompt.md +2 -2
  100. package/docs/templates/agent-dag-report.schema.json +33 -2
  101. package/docs/templates/agent-dag-review-verdict.prompt.md +1 -1
  102. package/docs/templates/agent-dag.base.json +195 -195
  103. package/docs/templates/agent-dag.final-verification.json +190 -190
  104. package/docs/templates/agent-dag.schema.json +17 -17
  105. package/docs/templates/agent-dag.supervised-implementation.json +500 -500
  106. package/docs/templates/hybrid-dag.json +193 -193
  107. package/docs/templates/production-readiness-checklist.md +57 -0
  108. package/docs/templates/progress-log.md +7 -7
  109. package/docs/templates/project-start-checklist.md +8 -8
  110. package/docs/templates/qa-report.md +17 -11
  111. package/docs/templates/sprint-contract.md +19 -19
  112. package/docs/verification-matrix.md +37 -26
  113. package/examples/example-dag.json +51 -51
  114. package/examples/hybrid-loop-agent-dag.json +194 -194
  115. package/harness.json +5 -5
  116. package/package.json +62 -61
  117. package/skills/ai-engineering-context/SKILL.md +21 -21
  118. package/skills/loop-agent/SKILL.md +56 -171
  119. package/skills/loop-agent/references/README.md +6 -2
  120. package/skills/loop-agent/references/command-reference.md +107 -65
  121. package/skills/loop-agent/references/harness-policy.md +115 -115
  122. package/skills/loop-agent/references/hybrid-dag.md +30 -30
  123. package/skills/loop-agent/references/learned/README.md +13 -13
  124. package/skills/loop-agent/references/long-running-loop.md +59 -0
  125. package/skills/loop-agent/references/model-routing.md +1 -1
  126. package/skills/loop-agent/references/orchestrator-and-interventions.md +1 -1
  127. package/skills/loop-agent/references/pi-prompt.md +9 -9
  128. package/skills/loop-agent/references/pi-subagent-assisted-mode.md +0 -2
  129. package/skills/loop-agent/references/post-implementation-and-patterns.md +7 -7
  130. package/skills/loop-agent/references/task-workflow.md +19 -19
  131. package/skills/loop-agent/references/verification-and-failure-handling.md +54 -0
  132. package/skills/requesting-code-review/SKILL.md +40 -40
  133. package/skills/requesting-code-review/code-reviewer.md +4 -4
  134. package/skills/systematic-debugging/CREATION-LOG.md +43 -43
  135. package/skills/systematic-debugging/SKILL.md +113 -113
  136. package/skills/systematic-debugging/condition-based-waiting.md +20 -20
  137. package/skills/systematic-debugging/defense-in-depth.md +27 -27
  138. package/skills/systematic-debugging/root-cause-tracing.md +38 -38
  139. package/skills/systematic-debugging/test-academic.md +6 -6
  140. package/skills/systematic-debugging/test-pressure-1.md +6 -6
  141. package/skills/systematic-debugging/test-pressure-2.md +2 -2
  142. package/skills/systematic-debugging/test-pressure-3.md +6 -6
  143. package/skills/verification-before-completion/SKILL.md +37 -37
@@ -1,4 +1,5 @@
1
1
  import path from 'node:path';
2
+ import { readFileSync } from 'node:fs';
2
3
  import { buildStepContextFiles } from './context.js';
3
4
  import { loadHarnessManifest } from '../governance/harness.js';
4
5
  function getKeyRepoPaths(repoRoot, manifest) {
@@ -58,6 +59,10 @@ async function getContextFilesForStep(repoRoot, manifest, taskId, step, taskConf
58
59
  });
59
60
  }
60
61
  function getVerifyCommands(repoRoot, options) {
62
+ const manifestCommands = getManifestVerifyCommands(repoRoot, options.preset);
63
+ if (manifestCommands) {
64
+ return applyQuota(manifestCommands, options);
65
+ }
61
66
  const quickCommands = [
62
67
  {
63
68
  args: ['bash', 'scripts/check-repo.sh'],
@@ -84,11 +89,48 @@ function getVerifyCommands(repoRoot, options) {
84
89
  : options.preset === 'standard'
85
90
  ? [...quickCommands, ...standardCommands]
86
91
  : [...quickCommands, ...standardCommands, ...fullCommands];
92
+ return applyQuota(selectedCommands, options);
93
+ }
94
+ function applyQuota(commands, options) {
87
95
  if (options.phase === 'final' || !options.quota || options.quota === 'full') {
88
- return selectedCommands;
96
+ return commands;
89
97
  }
90
98
  const maxCommands = options.quota === '1' ? 1 : 3;
91
- return selectedCommands.slice(0, maxCommands);
99
+ return commands.slice(0, maxCommands);
100
+ }
101
+ function commandFromScript(repoRoot, label, command) {
102
+ return {
103
+ args: ['bash', '-lc', command],
104
+ cwd: repoRoot,
105
+ label,
106
+ };
107
+ }
108
+ function getManifestVerifyCommands(repoRoot, preset) {
109
+ try {
110
+ const manifest = JSON.parse(readFileSync(path.join(repoRoot, 'harness.json'), 'utf-8'));
111
+ const quick = typeof manifest.scripts?.quickVerify === 'string'
112
+ ? manifest.scripts.quickVerify
113
+ : undefined;
114
+ const standard = typeof manifest.scripts?.standardVerify === 'string'
115
+ ? manifest.scripts.standardVerify
116
+ : undefined;
117
+ const full = typeof manifest.scripts?.fullVerify === 'string'
118
+ ? manifest.scripts.fullVerify
119
+ : undefined;
120
+ if (!quick && !standard && !full)
121
+ return undefined;
122
+ const quickCommands = quick ? [commandFromScript(repoRoot, 'repo quick verification', quick)] : [];
123
+ const standardCommands = standard ? [commandFromScript(repoRoot, 'repo standard verification', standard)] : [];
124
+ const fullCommands = full ? [commandFromScript(repoRoot, 'repo full verification', full)] : [];
125
+ if (preset === 'quick')
126
+ return quickCommands;
127
+ if (preset === 'standard')
128
+ return [...quickCommands, ...standardCommands];
129
+ return [...quickCommands, ...standardCommands, ...fullCommands];
130
+ }
131
+ catch {
132
+ return undefined;
133
+ }
92
134
  }
93
135
  export const loopAgentAdapter = {
94
136
  name: 'loop-agent',
@@ -0,0 +1,420 @@
1
+ import path from "node:path";
2
+ import { DAG_PAUSED_LATEST_REPORT_PRESET, DAG_RECOVERY_ACTIONS, } from "../../workflows/dag/report.js";
3
+ const RECOVERY_ACTIONS = new Set(DAG_RECOVERY_ACTIONS);
4
+ const LIFECYCLE_FILTERS = new Set([
5
+ "active",
6
+ "paused",
7
+ "completed",
8
+ "all",
9
+ ]);
10
+ export function parseDagRunTaskArgs(args, defaultCwd) {
11
+ if (args.length === 0) {
12
+ throw new Error("usage: dag run-task <task-id> [--output <path>] [--profile auto|minimal|standard|reviewed|supervised] [--strict-models] [--no-cursor] [--execute] [--init-only] [--dry-run] [--cwd <dir>] [--max-concurrent N] [--run-id id] [--canvas-path <abs-path> | --canvas <name> [--canvases-dir <dir>]]");
13
+ }
14
+ let taskId;
15
+ let outputPath;
16
+ let strictModels = false;
17
+ let noCursor = false;
18
+ let execute = false;
19
+ let initOnly = false;
20
+ let dryRun = false;
21
+ let cwd;
22
+ let maxConcurrent;
23
+ let runId;
24
+ let canvasPath;
25
+ let canvasName;
26
+ let canvasesDir;
27
+ let profile = "standard";
28
+ let profileExplicit = false;
29
+ for (let i = 0; i < args.length; i += 1) {
30
+ const arg = args[i];
31
+ if (arg === "--output" || arg === "-o") {
32
+ outputPath = args[++i];
33
+ if (!outputPath) {
34
+ throw new Error("dag run-task --output requires a path");
35
+ }
36
+ continue;
37
+ }
38
+ if (arg.startsWith("--output=")) {
39
+ outputPath = arg.slice("--output=".length);
40
+ continue;
41
+ }
42
+ if (arg === "--strict-models") {
43
+ strictModels = true;
44
+ continue;
45
+ }
46
+ if (arg === "--no-cursor") {
47
+ noCursor = true;
48
+ continue;
49
+ }
50
+ if (arg === "--execute") {
51
+ execute = true;
52
+ continue;
53
+ }
54
+ if (arg === "--init-only") {
55
+ initOnly = true;
56
+ continue;
57
+ }
58
+ if (arg === "--dry-run") {
59
+ dryRun = true;
60
+ continue;
61
+ }
62
+ if (arg === "--cwd" || arg === "-C") {
63
+ cwd = args[++i];
64
+ continue;
65
+ }
66
+ if (arg.startsWith("--cwd=")) {
67
+ cwd = arg.slice(6);
68
+ continue;
69
+ }
70
+ if (arg === "--max-concurrent") {
71
+ maxConcurrent = Number(args[++i]);
72
+ continue;
73
+ }
74
+ if (arg === "--run-id") {
75
+ runId = args[++i];
76
+ continue;
77
+ }
78
+ if (arg === "--canvas-path") {
79
+ canvasPath = args[++i];
80
+ continue;
81
+ }
82
+ if (arg.startsWith("--canvas-path=")) {
83
+ canvasPath = arg.slice(14);
84
+ continue;
85
+ }
86
+ if (arg === "--canvas") {
87
+ canvasName = args[++i];
88
+ continue;
89
+ }
90
+ if (arg.startsWith("--canvas=")) {
91
+ canvasName = arg.slice(9);
92
+ continue;
93
+ }
94
+ if (arg === "--canvases-dir") {
95
+ canvasesDir = args[++i];
96
+ continue;
97
+ }
98
+ if (arg.startsWith("--canvases-dir=")) {
99
+ canvasesDir = arg.slice(15);
100
+ continue;
101
+ }
102
+ if (arg === "--profile") {
103
+ const value = args[++i];
104
+ if (!value) {
105
+ throw new Error("dag run-task --profile requires a value");
106
+ }
107
+ profile = parseDagRunTaskProfile(value);
108
+ profileExplicit = true;
109
+ continue;
110
+ }
111
+ if (arg.startsWith("--profile=")) {
112
+ profile = parseDagRunTaskProfile(arg.slice("--profile=".length));
113
+ profileExplicit = true;
114
+ continue;
115
+ }
116
+ if (arg.startsWith("-")) {
117
+ throw new Error(`unknown dag run-task flag: ${arg}`);
118
+ }
119
+ if (taskId) {
120
+ throw new Error(`unexpected positional argument: ${arg}`);
121
+ }
122
+ taskId = arg;
123
+ }
124
+ if (!taskId) {
125
+ throw new Error("dag run-task requires <task-id>");
126
+ }
127
+ return {
128
+ taskId,
129
+ outputPath: outputPath ? path.resolve(outputPath) : undefined,
130
+ strictModels,
131
+ noCursor,
132
+ execute,
133
+ initOnly,
134
+ dryRun,
135
+ cwd: path.resolve(cwd ?? defaultCwd ?? process.cwd()),
136
+ maxConcurrent,
137
+ runId,
138
+ canvasPath,
139
+ canvasName,
140
+ canvasesDir,
141
+ profile,
142
+ profileExplicit,
143
+ };
144
+ }
145
+ function parseDagRunTaskProfile(value) {
146
+ if (value === "auto" ||
147
+ value === "minimal" ||
148
+ value === "standard" ||
149
+ value === "reviewed" ||
150
+ value === "supervised") {
151
+ return value;
152
+ }
153
+ throw new Error(`dag run-task --profile must be one of: auto, minimal, standard, reviewed, supervised; got ${value}`);
154
+ }
155
+ export function parseDagValidateArgs(args) {
156
+ if (args.length === 0) {
157
+ throw new Error("usage: dag validate --dag <path> [--strict-models] [--strict-governance]");
158
+ }
159
+ let dagPath;
160
+ let strictModelMatrix = false;
161
+ let strictGovernance = false;
162
+ const forbidExecutors = [];
163
+ let spineTaskId;
164
+ for (let i = 0; i < args.length; i += 1) {
165
+ const arg = args[i];
166
+ if (arg === "--dag") {
167
+ dagPath = args[++i];
168
+ if (!dagPath) {
169
+ throw new Error("dag validate --dag requires a path");
170
+ }
171
+ continue;
172
+ }
173
+ if (arg.startsWith("--dag=")) {
174
+ dagPath = arg.slice("--dag=".length);
175
+ if (!dagPath) {
176
+ throw new Error("dag validate --dag requires a path");
177
+ }
178
+ continue;
179
+ }
180
+ if (arg === "--strict-models") {
181
+ strictModelMatrix = true;
182
+ continue;
183
+ }
184
+ if (arg === "--strict-governance") {
185
+ strictGovernance = true;
186
+ continue;
187
+ }
188
+ if (arg === "--forbid-executor") {
189
+ const executor = args[++i];
190
+ if (!executor) {
191
+ throw new Error("dag validate --forbid-executor requires an executor");
192
+ }
193
+ forbidExecutors.push(executor);
194
+ continue;
195
+ }
196
+ if (arg === "--spine-task") {
197
+ spineTaskId = args[++i];
198
+ if (!spineTaskId) {
199
+ throw new Error("dag validate --spine-task requires a task id");
200
+ }
201
+ continue;
202
+ }
203
+ if (arg.startsWith("--spine-task=")) {
204
+ spineTaskId = arg.slice("--spine-task=".length);
205
+ if (!spineTaskId) {
206
+ throw new Error("dag validate --spine-task requires a task id");
207
+ }
208
+ continue;
209
+ }
210
+ if (arg.startsWith("--forbid-executor=")) {
211
+ const executor = arg.slice("--forbid-executor=".length);
212
+ if (!executor) {
213
+ throw new Error("dag validate --forbid-executor requires an executor");
214
+ }
215
+ forbidExecutors.push(executor);
216
+ continue;
217
+ }
218
+ if (arg.startsWith("-")) {
219
+ throw new Error(`unknown dag validate flag: ${arg}`);
220
+ }
221
+ if (dagPath) {
222
+ throw new Error(`unexpected positional argument: ${arg}`);
223
+ }
224
+ dagPath = arg;
225
+ }
226
+ if (!dagPath) {
227
+ throw new Error("dag validate requires --dag <path>");
228
+ }
229
+ return {
230
+ dagPath: path.resolve(dagPath),
231
+ strictModelMatrix,
232
+ strictGovernance,
233
+ forbidExecutors,
234
+ spineTaskId,
235
+ };
236
+ }
237
+ export function parseRunDagArgs(args, defaultCwd) {
238
+ if (args.length === 0) {
239
+ throw new Error("usage: run-dag --dag <path> [--cwd <dir>] [--init-only] [--dry-run] [--max-concurrent N] [--run-id id] [--canvas-path <abs-path> | --canvas <name> [--canvases-dir <dir>]]");
240
+ }
241
+ let dagPath;
242
+ let cwd;
243
+ let initOnly = false;
244
+ let dryRun = false;
245
+ let maxConcurrent;
246
+ let runId;
247
+ let noCursor = false;
248
+ let canvasPath;
249
+ let canvasName;
250
+ let canvasesDir;
251
+ for (let i = 0; i < args.length; i += 1) {
252
+ const arg = args[i];
253
+ if (arg === "--dag") {
254
+ dagPath = args[++i];
255
+ }
256
+ else if (arg.startsWith("--dag=")) {
257
+ dagPath = arg.slice(6);
258
+ }
259
+ else if (arg === "--cwd" || arg === "-C") {
260
+ cwd = args[++i];
261
+ }
262
+ else if (arg.startsWith("--cwd=")) {
263
+ cwd = arg.slice(6);
264
+ }
265
+ else if (arg === "--init-only") {
266
+ initOnly = true;
267
+ }
268
+ else if (arg === "--dry-run") {
269
+ dryRun = true;
270
+ }
271
+ else if (arg === "--max-concurrent") {
272
+ maxConcurrent = Number(args[++i]);
273
+ }
274
+ else if (arg === "--run-id") {
275
+ runId = args[++i];
276
+ }
277
+ else if (arg === "--no-cursor") {
278
+ noCursor = true;
279
+ }
280
+ else if (arg === "--canvas-path") {
281
+ canvasPath = args[++i];
282
+ }
283
+ else if (arg.startsWith("--canvas-path=")) {
284
+ canvasPath = arg.slice(14);
285
+ }
286
+ else if (arg === "--canvas") {
287
+ canvasName = args[++i];
288
+ }
289
+ else if (arg.startsWith("--canvas=")) {
290
+ canvasName = arg.slice(9);
291
+ }
292
+ else if (arg === "--canvases-dir") {
293
+ canvasesDir = args[++i];
294
+ }
295
+ else if (arg.startsWith("--canvases-dir=")) {
296
+ canvasesDir = arg.slice(15);
297
+ }
298
+ else if (!arg.startsWith("-")) {
299
+ if (!dagPath)
300
+ dagPath = arg;
301
+ else
302
+ throw new Error(`unexpected positional argument: ${arg}`);
303
+ }
304
+ else {
305
+ throw new Error(`unknown run-dag flag: ${arg}`);
306
+ }
307
+ }
308
+ if (!dagPath) {
309
+ throw new Error("run-dag requires --dag <path>");
310
+ }
311
+ return {
312
+ dagPath: path.resolve(dagPath),
313
+ cwd: path.resolve(cwd ?? defaultCwd ?? process.cwd()),
314
+ initOnly,
315
+ dryRun,
316
+ maxConcurrent,
317
+ runId,
318
+ noCursor,
319
+ canvasPath,
320
+ canvasName,
321
+ canvasesDir,
322
+ };
323
+ }
324
+ export function parseDagReportArgs(args) {
325
+ let runId;
326
+ let lifecycle = "all";
327
+ let json = false;
328
+ let markdown = false;
329
+ let failedOnly = false;
330
+ let latest = false;
331
+ let pausedLatest = false;
332
+ let action;
333
+ for (let i = 0; i < args.length; i += 1) {
334
+ const arg = args[i];
335
+ if (arg === "--run-id") {
336
+ runId = args[++i];
337
+ continue;
338
+ }
339
+ if (arg.startsWith("--run-id=")) {
340
+ runId = arg.slice("--run-id=".length);
341
+ continue;
342
+ }
343
+ if (arg === "--lifecycle") {
344
+ const value = args[++i];
345
+ if (!LIFECYCLE_FILTERS.has(value)) {
346
+ throw new Error(`invalid --lifecycle value: ${value} (expected active|paused|completed|all)`);
347
+ }
348
+ lifecycle = value;
349
+ continue;
350
+ }
351
+ if (arg.startsWith("--lifecycle=")) {
352
+ const value = arg.slice("--lifecycle=".length);
353
+ if (!LIFECYCLE_FILTERS.has(value)) {
354
+ throw new Error(`invalid --lifecycle value: ${value} (expected active|paused|completed|all)`);
355
+ }
356
+ lifecycle = value;
357
+ continue;
358
+ }
359
+ if (arg === "--json") {
360
+ json = true;
361
+ continue;
362
+ }
363
+ if (arg === "--markdown") {
364
+ markdown = true;
365
+ continue;
366
+ }
367
+ if (arg === "--failed-only") {
368
+ failedOnly = true;
369
+ continue;
370
+ }
371
+ if (arg === "--latest") {
372
+ latest = true;
373
+ continue;
374
+ }
375
+ if (arg === "--paused-latest") {
376
+ pausedLatest = true;
377
+ continue;
378
+ }
379
+ if (arg === "--action") {
380
+ const value = args[++i];
381
+ if (!RECOVERY_ACTIONS.has(value)) {
382
+ throw new Error(`invalid --action value: ${value} (expected ${[...DAG_RECOVERY_ACTIONS].join("|")})`);
383
+ }
384
+ action = value;
385
+ continue;
386
+ }
387
+ if (arg.startsWith("--action=")) {
388
+ const value = arg.slice("--action=".length);
389
+ if (!RECOVERY_ACTIONS.has(value)) {
390
+ throw new Error(`invalid --action value: ${value} (expected ${[...DAG_RECOVERY_ACTIONS].join("|")})`);
391
+ }
392
+ action = value;
393
+ continue;
394
+ }
395
+ if (arg.startsWith("-")) {
396
+ throw new Error(`unknown dag report flag: ${arg}`);
397
+ }
398
+ throw new Error(`unexpected positional argument: ${arg}`);
399
+ }
400
+ if (json && markdown) {
401
+ throw new Error("cannot use --json and --markdown together");
402
+ }
403
+ if (pausedLatest) {
404
+ if (lifecycle !== "all") {
405
+ throw new Error("cannot combine --paused-latest with an explicit --lifecycle filter");
406
+ }
407
+ lifecycle = DAG_PAUSED_LATEST_REPORT_PRESET.lifecycle;
408
+ latest = DAG_PAUSED_LATEST_REPORT_PRESET.latest;
409
+ }
410
+ return {
411
+ runId,
412
+ lifecycle,
413
+ json,
414
+ markdown,
415
+ failedOnly,
416
+ latest,
417
+ pausedLatest,
418
+ action,
419
+ };
420
+ }