@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.
- package/AGENTS.md +62 -45
- package/CHANGELOG.md +60 -28
- package/README.md +160 -124
- package/bin/loop-agent.js +21 -21
- package/dist/adapters/index.js +3 -2
- package/dist/adapters/loop-agent.js +44 -2
- package/dist/application/dag/args.js +420 -0
- package/dist/application/dag/generate-task-dag.js +280 -0
- package/dist/application/dag/report-dag.js +14 -0
- package/dist/application/dag/run-dag.js +106 -0
- package/dist/application/dag/validate-dag.js +102 -0
- package/dist/application/loop/run-action.js +23 -0
- package/dist/cli/catalog.js +2 -237
- package/dist/cli/command-definitions.js +571 -0
- package/dist/cli/index.js +2 -0
- package/dist/cli/program.js +65 -1
- package/dist/cli/router.js +13 -0
- package/dist/cli-governance/active-residue-check.js +38 -0
- package/dist/commands/dag-report.js +6 -107
- package/dist/commands/dag-run-task.js +8 -466
- package/dist/commands/dag-validate.js +7 -179
- package/dist/commands/examples.js +90 -0
- package/dist/commands/init.js +1518 -0
- package/dist/commands/loop.js +57 -31
- package/dist/commands/pi-prompt.js +2 -9
- package/dist/commands/run-dag.js +7 -180
- package/dist/executors/cursor-executor-artifacts.js +3 -4
- package/dist/executors/cursor-worker-client.js +13 -3
- package/dist/executors/dag-cursor-executor.js +2 -3
- package/dist/executors/dag-pi-executor.js +3 -4
- package/dist/executors/dag-static-executor.js +2 -5
- package/dist/executors/pi-defaults.js +9 -0
- package/dist/executors/shell-executor.js +12 -20
- package/dist/governance/manifest-types.js +1 -0
- package/dist/infrastructure/harness/active-residue-policy.js +73 -0
- package/dist/infrastructure/harness/artifact-store.js +72 -0
- package/dist/infrastructure/harness/atomic-write.js +49 -0
- package/dist/infrastructure/harness/completed-facts-guard.js +40 -0
- package/dist/infrastructure/harness/loop-action-store.js +23 -0
- package/dist/infrastructure/harness/loop-store.js +41 -0
- package/dist/infrastructure/harness/one-shot-run-store.js +94 -0
- package/dist/infrastructure/harness/task-store.js +77 -0
- package/dist/records/one-shot-runs.js +26 -61
- package/dist/records/promotion.js +3 -4
- package/dist/shared/artifacts-core.js +5 -5
- package/dist/shared/logger.js +9 -15
- package/dist/task/delegate.js +4 -4
- package/dist/task/runtime.js +5 -7
- package/dist/task/state.js +6 -20
- package/dist/workflows/dag/convergence/controller.js +277 -0
- package/dist/workflows/dag/dynamic-runtime/condition.js +48 -0
- package/dist/workflows/dag/dynamic-runtime/loop-until.js +156 -0
- package/dist/workflows/dag/dynamic-runtime/map.js +185 -0
- package/dist/workflows/dag/dynamic-runtime/reduction.js +72 -0
- package/dist/workflows/dag/dynamic-runtime/shared.js +133 -0
- package/dist/workflows/dag/failure-routing.js +82 -0
- package/dist/workflows/dag/lifecycle.js +101 -8
- package/dist/workflows/dag/node-execution.js +262 -0
- package/dist/workflows/dag/report.js +73 -1
- package/dist/workflows/dag/run-store.js +36 -0
- package/dist/workflows/dag/runner.js +82 -1341
- package/dist/workflows/dag/scheduler.js +84 -0
- package/dist/workflows/dag/upstream-artifacts.js +20 -18
- package/dist/workflows/loop/actions/cursor-fix.js +191 -0
- package/dist/workflows/loop/actions/dag-action.js +130 -0
- package/dist/workflows/loop/actions/pi-review.js +267 -0
- package/dist/workflows/loop/actions/shared.js +157 -0
- package/dist/workflows/loop/actions/shell-verify.js +82 -0
- package/dist/workflows/loop/actions/types.js +1 -0
- package/dist/workflows/loop/actions/workflow-action.js +255 -0
- package/dist/workflows/loop/actions.js +55 -1212
- package/dist/workflows/loop/closeout.js +5 -4
- package/dist/workflows/loop/context.js +2 -3
- package/dist/workflows/loop/events.js +3 -2
- package/dist/workflows/loop/policy/auto-policy.js +104 -0
- package/dist/workflows/loop/policy/cursor-fix-policy.js +31 -0
- package/dist/workflows/loop/rounds.js +3 -3
- package/dist/workflows/loop/signals.js +4 -7
- package/dist/workflows/loop/state.js +11 -11
- package/docs/README.md +47 -44
- package/docs/agent-dag-recovery-playbook.md +32 -6
- package/docs/agent-dag-runner.md +17 -17
- package/docs/architecture/runtime-boundaries.md +147 -0
- package/docs/cursor-executor-usage.md +5 -5
- package/docs/decisions/README.md +2 -2
- package/docs/design/README.md +24 -24
- package/docs/development-principles.md +50 -50
- package/docs/dynamic-workflow-dag-engine-roadmap.md +6 -6
- package/docs/exec-plans/README.md +4 -4
- package/docs/exec-plans/active/README.md +10 -5
- package/docs/exec-plans/completed/README.md +9 -5
- package/docs/feature-workflow.md +111 -109
- package/docs/harness-methodology-verification.md +18 -18
- package/docs/loop-agent-harness.md +36 -36
- package/docs/production-readiness.md +96 -0
- package/docs/progress/README.md +2 -2
- package/docs/reports/README.md +4 -2
- package/docs/templates/agent-dag-decision-gate-dogfood-report.md +1 -1
- package/docs/templates/agent-dag-process-supervisor.prompt.md +2 -2
- package/docs/templates/agent-dag-report.schema.json +33 -2
- package/docs/templates/agent-dag-review-verdict.prompt.md +1 -1
- package/docs/templates/agent-dag.base.json +195 -195
- package/docs/templates/agent-dag.final-verification.json +190 -190
- package/docs/templates/agent-dag.schema.json +17 -17
- package/docs/templates/agent-dag.supervised-implementation.json +500 -500
- package/docs/templates/hybrid-dag.json +193 -193
- package/docs/templates/production-readiness-checklist.md +57 -0
- package/docs/templates/progress-log.md +7 -7
- package/docs/templates/project-start-checklist.md +8 -8
- package/docs/templates/qa-report.md +17 -11
- package/docs/templates/sprint-contract.md +19 -19
- package/docs/verification-matrix.md +37 -26
- package/examples/example-dag.json +51 -51
- package/examples/hybrid-loop-agent-dag.json +194 -194
- package/harness.json +5 -5
- package/package.json +62 -61
- package/skills/ai-engineering-context/SKILL.md +21 -21
- package/skills/loop-agent/SKILL.md +56 -171
- package/skills/loop-agent/references/README.md +6 -2
- package/skills/loop-agent/references/command-reference.md +107 -65
- package/skills/loop-agent/references/harness-policy.md +115 -115
- package/skills/loop-agent/references/hybrid-dag.md +30 -30
- package/skills/loop-agent/references/learned/README.md +13 -13
- package/skills/loop-agent/references/long-running-loop.md +59 -0
- package/skills/loop-agent/references/model-routing.md +1 -1
- package/skills/loop-agent/references/orchestrator-and-interventions.md +1 -1
- package/skills/loop-agent/references/pi-prompt.md +9 -9
- package/skills/loop-agent/references/pi-subagent-assisted-mode.md +0 -2
- package/skills/loop-agent/references/post-implementation-and-patterns.md +7 -7
- package/skills/loop-agent/references/task-workflow.md +19 -19
- package/skills/loop-agent/references/verification-and-failure-handling.md +54 -0
- package/skills/requesting-code-review/SKILL.md +40 -40
- package/skills/requesting-code-review/code-reviewer.md +4 -4
- package/skills/systematic-debugging/CREATION-LOG.md +43 -43
- package/skills/systematic-debugging/SKILL.md +113 -113
- package/skills/systematic-debugging/condition-based-waiting.md +20 -20
- package/skills/systematic-debugging/defense-in-depth.md +27 -27
- package/skills/systematic-debugging/root-cause-tracing.md +38 -38
- package/skills/systematic-debugging/test-academic.md +6 -6
- package/skills/systematic-debugging/test-pressure-1.md +6 -6
- package/skills/systematic-debugging/test-pressure-2.md +2 -2
- package/skills/systematic-debugging/test-pressure-3.md +6 -6
- 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
|
|
96
|
+
return commands;
|
|
89
97
|
}
|
|
90
98
|
const maxCommands = options.quota === '1' ? 1 : 3;
|
|
91
|
-
return
|
|
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
|
+
}
|