@lumenflow/cli 2.2.2 → 2.3.2
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/README.md +147 -57
- package/dist/__tests__/agent-log-issue.test.js +56 -0
- package/dist/__tests__/cli-entry-point.test.js +66 -17
- package/dist/__tests__/cli-subprocess.test.js +25 -0
- package/dist/__tests__/init.test.js +298 -0
- package/dist/__tests__/initiative-plan.test.js +340 -0
- package/dist/__tests__/mem-cleanup-execution.test.js +19 -0
- package/dist/__tests__/merge-block.test.js +220 -0
- package/dist/__tests__/release.test.js +61 -0
- package/dist/__tests__/safe-git.test.js +191 -0
- package/dist/__tests__/state-doctor.test.js +274 -0
- package/dist/__tests__/wu-done.test.js +36 -0
- package/dist/__tests__/wu-edit.test.js +119 -0
- package/dist/__tests__/wu-prep.test.js +108 -0
- package/dist/agent-issues-query.js +4 -3
- package/dist/agent-log-issue.js +25 -4
- package/dist/backlog-prune.js +5 -4
- package/dist/cli-entry-point.js +11 -1
- package/dist/doctor.js +368 -0
- package/dist/flow-bottlenecks.js +6 -5
- package/dist/flow-report.js +4 -3
- package/dist/gates.js +356 -101
- package/dist/guard-locked.js +4 -3
- package/dist/guard-worktree-commit.js +4 -3
- package/dist/init.js +517 -86
- package/dist/initiative-add-wu.js +4 -3
- package/dist/initiative-bulk-assign-wus.js +8 -5
- package/dist/initiative-create.js +73 -37
- package/dist/initiative-edit.js +37 -21
- package/dist/initiative-list.js +4 -3
- package/dist/initiative-plan.js +337 -0
- package/dist/initiative-status.js +4 -3
- package/dist/lane-health.js +377 -0
- package/dist/lane-suggest.js +382 -0
- package/dist/mem-checkpoint.js +2 -2
- package/dist/mem-cleanup.js +2 -2
- package/dist/mem-context.js +306 -0
- package/dist/mem-create.js +2 -2
- package/dist/mem-delete.js +293 -0
- package/dist/mem-inbox.js +2 -2
- package/dist/mem-index.js +211 -0
- package/dist/mem-init.js +1 -1
- package/dist/mem-profile.js +207 -0
- package/dist/mem-promote.js +254 -0
- package/dist/mem-ready.js +2 -2
- package/dist/mem-signal.js +2 -2
- package/dist/mem-start.js +2 -2
- package/dist/mem-summarize.js +2 -2
- package/dist/mem-triage.js +2 -2
- package/dist/merge-block.js +222 -0
- package/dist/metrics-cli.js +7 -4
- package/dist/metrics-snapshot.js +4 -3
- package/dist/orchestrate-initiative.js +10 -4
- package/dist/orchestrate-monitor.js +379 -31
- package/dist/release.js +69 -29
- package/dist/signal-cleanup.js +296 -0
- package/dist/spawn-list.js +6 -5
- package/dist/state-bootstrap.js +5 -4
- package/dist/state-cleanup.js +360 -0
- package/dist/state-doctor-fix.js +196 -0
- package/dist/state-doctor.js +501 -0
- package/dist/validate-agent-skills.js +4 -3
- package/dist/validate-agent-sync.js +4 -3
- package/dist/validate-backlog-sync.js +4 -3
- package/dist/validate-skills-spec.js +4 -3
- package/dist/validate.js +4 -3
- package/dist/wu-block.js +3 -3
- package/dist/wu-claim.js +208 -98
- package/dist/wu-cleanup.js +5 -4
- package/dist/wu-create.js +71 -46
- package/dist/wu-delete.js +88 -60
- package/dist/wu-deps.js +6 -5
- package/dist/wu-done-check.js +34 -0
- package/dist/wu-done.js +39 -12
- package/dist/wu-edit.js +63 -28
- package/dist/wu-infer-lane.js +7 -6
- package/dist/wu-preflight.js +23 -81
- package/dist/wu-prep.js +125 -0
- package/dist/wu-prune.js +4 -3
- package/dist/wu-recover.js +88 -22
- package/dist/wu-repair.js +7 -6
- package/dist/wu-spawn.js +226 -270
- package/dist/wu-status.js +4 -3
- package/dist/wu-unblock.js +5 -5
- package/dist/wu-unlock-lane.js +4 -3
- package/dist/wu-validate.js +5 -4
- package/package.json +16 -7
- package/templates/core/.lumenflow/constraints.md.template +192 -0
- package/templates/core/.lumenflow/rules/git-safety.md.template +27 -0
- package/templates/core/.lumenflow/rules/wu-workflow.md.template +48 -0
- package/templates/core/AGENTS.md.template +60 -0
- package/templates/core/LUMENFLOW.md.template +255 -0
- package/templates/core/UPGRADING.md.template +121 -0
- package/templates/core/ai/onboarding/agent-safety-card.md.template +106 -0
- package/templates/core/ai/onboarding/first-wu-mistakes.md.template +198 -0
- package/templates/core/ai/onboarding/quick-ref-commands.md.template +186 -0
- package/templates/core/ai/onboarding/release-process.md.template +362 -0
- package/templates/core/ai/onboarding/troubleshooting-wu-done.md.template +159 -0
- package/templates/core/ai/onboarding/wu-create-checklist.md.template +117 -0
- package/templates/vendors/aider/.aider.conf.yml.template +27 -0
- package/templates/vendors/claude/.claude/CLAUDE.md.template +52 -0
- package/templates/vendors/claude/.claude/settings.json.template +49 -0
- package/templates/vendors/claude/.claude/skills/bug-classification/SKILL.md.template +192 -0
- package/templates/vendors/claude/.claude/skills/code-quality/SKILL.md.template +152 -0
- package/templates/vendors/claude/.claude/skills/context-management/SKILL.md.template +155 -0
- package/templates/vendors/claude/.claude/skills/execution-memory/SKILL.md.template +304 -0
- package/templates/vendors/claude/.claude/skills/frontend-design/SKILL.md.template +131 -0
- package/templates/vendors/claude/.claude/skills/initiative-management/SKILL.md.template +164 -0
- package/templates/vendors/claude/.claude/skills/library-first/SKILL.md.template +98 -0
- package/templates/vendors/claude/.claude/skills/lumenflow-gates/SKILL.md.template +87 -0
- package/templates/vendors/claude/.claude/skills/multi-agent-coordination/SKILL.md.template +84 -0
- package/templates/vendors/claude/.claude/skills/ops-maintenance/SKILL.md.template +254 -0
- package/templates/vendors/claude/.claude/skills/orchestration/SKILL.md.template +189 -0
- package/templates/vendors/claude/.claude/skills/tdd-workflow/SKILL.md.template +139 -0
- package/templates/vendors/claude/.claude/skills/worktree-discipline/SKILL.md.template +138 -0
- package/templates/vendors/claude/.claude/skills/wu-lifecycle/SKILL.md.template +106 -0
- package/templates/vendors/cline/.clinerules.template +53 -0
- package/templates/vendors/cursor/.cursor/rules/lumenflow.md.template +34 -0
- package/templates/vendors/cursor/.cursor/rules.md.template +28 -0
- package/templates/vendors/windsurf/.windsurf/rules/lumenflow.md.template +34 -0
package/dist/mem-start.js
CHANGED
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
* Usage:
|
|
11
11
|
* pnpm mem:start --wu WU-1234 [--agent-type <type>] [--context-tier <tier>] [--quiet]
|
|
12
12
|
*
|
|
13
|
-
* @see {@link
|
|
14
|
-
* @see {@link
|
|
13
|
+
* @see {@link packages/@lumenflow/cli/src/lib/mem-start-core.ts} - Core logic
|
|
14
|
+
* @see {@link packages/@lumenflow/cli/src/__tests__/mem-start.test.ts} - Tests
|
|
15
15
|
*/
|
|
16
16
|
import fs from 'node:fs/promises';
|
|
17
17
|
import path from 'node:path';
|
package/dist/mem-summarize.js
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
* pnpm mem:summarize --wu WU-1234 --dry-run # Preview without changes
|
|
17
17
|
* pnpm mem:summarize --wu WU-1234 --json # Output as JSON
|
|
18
18
|
*
|
|
19
|
-
* @see {@link
|
|
20
|
-
* @see {@link
|
|
19
|
+
* @see {@link packages/@lumenflow/cli/src/lib/mem-summarize-core.ts} - Core logic
|
|
20
|
+
* @see {@link packages/@lumenflow/cli/src/__tests__/mem-summarize.test.ts} - Tests
|
|
21
21
|
*/
|
|
22
22
|
import fs from 'node:fs/promises';
|
|
23
23
|
import path from 'node:path';
|
package/dist/mem-triage.js
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
* pnpm mem:triage --promote mem-aaa1 --lane "Operations: Tooling"
|
|
17
17
|
* pnpm mem:triage --archive mem-aaa1 --reason "Duplicate"
|
|
18
18
|
*
|
|
19
|
-
* @see {@link
|
|
20
|
-
* @see {@link
|
|
19
|
+
* @see {@link packages/@lumenflow/cli/src/lib/mem-triage-core.ts} - Core logic
|
|
20
|
+
* @see {@link packages/@lumenflow/cli/src/__tests__/mem-triage.test.ts} - Tests
|
|
21
21
|
*/
|
|
22
22
|
import fs from 'node:fs/promises';
|
|
23
23
|
import path from 'node:path';
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file merge-block.ts
|
|
3
|
+
* Merge block utilities for safe, idempotent config insertion (WU-1171)
|
|
4
|
+
*
|
|
5
|
+
* This module provides utilities to safely merge LumenFlow configuration
|
|
6
|
+
* into existing files using bounded markers (LUMENFLOW:START/END).
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Marker comments for LumenFlow blocks
|
|
10
|
+
*/
|
|
11
|
+
export const MARKERS = {
|
|
12
|
+
START: '<!-- LUMENFLOW:START -->',
|
|
13
|
+
END: '<!-- LUMENFLOW:END -->',
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Detect the predominant line ending in content.
|
|
17
|
+
*
|
|
18
|
+
* @param content - The file content to analyze
|
|
19
|
+
* @returns '\r\n' for CRLF, '\n' for LF (default)
|
|
20
|
+
*/
|
|
21
|
+
export function detectLineEnding(content) {
|
|
22
|
+
if (!content) {
|
|
23
|
+
return '\n';
|
|
24
|
+
}
|
|
25
|
+
const crlfCount = (content.match(/\r\n/g) || []).length;
|
|
26
|
+
const lfCount = (content.match(/(?<!\r)\n/g) || []).length;
|
|
27
|
+
// If no line endings found, default to LF
|
|
28
|
+
if (crlfCount === 0 && lfCount === 0) {
|
|
29
|
+
return '\n';
|
|
30
|
+
}
|
|
31
|
+
// Use majority line ending
|
|
32
|
+
return crlfCount >= lfCount ? '\r\n' : '\n';
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Normalize line endings in content to the specified style.
|
|
36
|
+
*
|
|
37
|
+
* @param content - The content to normalize
|
|
38
|
+
* @param lineEnding - The target line ending
|
|
39
|
+
* @returns Content with normalized line endings
|
|
40
|
+
*/
|
|
41
|
+
export function normalizeLineEndings(content, lineEnding) {
|
|
42
|
+
// First normalize to LF, then convert to target
|
|
43
|
+
const normalized = content.replace(/\r\n/g, '\n');
|
|
44
|
+
if (lineEnding === '\r\n') {
|
|
45
|
+
return normalized.replace(/\n/g, '\r\n');
|
|
46
|
+
}
|
|
47
|
+
return normalized;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Extract the LumenFlow block from content if it exists.
|
|
51
|
+
*
|
|
52
|
+
* @param content - The file content to search
|
|
53
|
+
* @returns Extraction result with block details
|
|
54
|
+
*/
|
|
55
|
+
export function extractMergeBlock(content) {
|
|
56
|
+
// Use indexOf for simple string matching instead of regex to avoid DOS vulnerability
|
|
57
|
+
const startIndexes = [];
|
|
58
|
+
const endIndexes = [];
|
|
59
|
+
let pos = 0;
|
|
60
|
+
while ((pos = content.indexOf(MARKERS.START, pos)) !== -1) {
|
|
61
|
+
startIndexes.push(pos);
|
|
62
|
+
pos += MARKERS.START.length;
|
|
63
|
+
}
|
|
64
|
+
pos = 0;
|
|
65
|
+
while ((pos = content.indexOf(MARKERS.END, pos)) !== -1) {
|
|
66
|
+
endIndexes.push(pos);
|
|
67
|
+
pos += MARKERS.END.length;
|
|
68
|
+
}
|
|
69
|
+
// Check for malformed cases
|
|
70
|
+
if (startIndexes.length > 1) {
|
|
71
|
+
return { found: false, malformed: true, malformedReason: 'multiple-start' };
|
|
72
|
+
}
|
|
73
|
+
if (endIndexes.length > 1) {
|
|
74
|
+
return { found: false, malformed: true, malformedReason: 'multiple-end' };
|
|
75
|
+
}
|
|
76
|
+
const hasStart = startIndexes.length === 1;
|
|
77
|
+
const hasEnd = endIndexes.length === 1;
|
|
78
|
+
if (hasStart && !hasEnd) {
|
|
79
|
+
return { found: false, malformed: true, malformedReason: 'missing-end' };
|
|
80
|
+
}
|
|
81
|
+
if (!hasStart && hasEnd) {
|
|
82
|
+
return { found: false, malformed: true, malformedReason: 'missing-start' };
|
|
83
|
+
}
|
|
84
|
+
if (!hasStart && !hasEnd) {
|
|
85
|
+
return { found: false };
|
|
86
|
+
}
|
|
87
|
+
// Both markers present - extract content
|
|
88
|
+
const startIndex = startIndexes[0];
|
|
89
|
+
const endMarkerIndex = endIndexes[0];
|
|
90
|
+
const endIndex = endMarkerIndex + MARKERS.END.length;
|
|
91
|
+
// Verify END comes after START
|
|
92
|
+
if (endMarkerIndex <= startIndex) {
|
|
93
|
+
return { found: false, malformed: true, malformedReason: 'missing-end' };
|
|
94
|
+
}
|
|
95
|
+
// Extract content between markers (excluding the markers and surrounding newlines)
|
|
96
|
+
const afterStart = startIndex + MARKERS.START.length;
|
|
97
|
+
const beforeEnd = endMarkerIndex;
|
|
98
|
+
let blockContent = content.slice(afterStart, beforeEnd);
|
|
99
|
+
// Trim leading/trailing newlines from the block content
|
|
100
|
+
// Use simple loop to avoid regex ReDoS vulnerability
|
|
101
|
+
blockContent = trimNewlines(blockContent);
|
|
102
|
+
return {
|
|
103
|
+
found: true,
|
|
104
|
+
content: blockContent,
|
|
105
|
+
startIndex,
|
|
106
|
+
endIndex,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Insert a new merge block into content.
|
|
111
|
+
*
|
|
112
|
+
* @param originalContent - The existing file content
|
|
113
|
+
* @param blockContent - The content to place inside the block
|
|
114
|
+
* @returns The content with the new block appended
|
|
115
|
+
*/
|
|
116
|
+
export function insertMergeBlock(originalContent, blockContent) {
|
|
117
|
+
const lineEnding = detectLineEnding(originalContent);
|
|
118
|
+
const normalizedBlock = normalizeLineEndings(blockContent, lineEnding);
|
|
119
|
+
// Ensure content ends with newlines for separation
|
|
120
|
+
let content = originalContent;
|
|
121
|
+
if (!content.endsWith(lineEnding)) {
|
|
122
|
+
content += lineEnding;
|
|
123
|
+
}
|
|
124
|
+
if (!content.endsWith(lineEnding + lineEnding) && content.trim().length > 0) {
|
|
125
|
+
content += lineEnding;
|
|
126
|
+
}
|
|
127
|
+
// Build the block
|
|
128
|
+
const block = [MARKERS.START, normalizedBlock, MARKERS.END, ''].join(lineEnding);
|
|
129
|
+
return content + block;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Update or insert a merge block in content.
|
|
133
|
+
*
|
|
134
|
+
* @param originalContent - The existing file content
|
|
135
|
+
* @param newBlockContent - The new content for the block
|
|
136
|
+
* @returns Result with the updated content and metadata
|
|
137
|
+
*/
|
|
138
|
+
export function updateMergeBlock(originalContent, newBlockContent) {
|
|
139
|
+
const lineEnding = detectLineEnding(originalContent);
|
|
140
|
+
const extraction = extractMergeBlock(originalContent);
|
|
141
|
+
// If malformed, warn and append fresh block
|
|
142
|
+
if (extraction.malformed) {
|
|
143
|
+
const warning = `LumenFlow markers are malformed (${extraction.malformedReason}). Appending fresh block.`;
|
|
144
|
+
const result = insertMergeBlock(originalContent, newBlockContent);
|
|
145
|
+
return {
|
|
146
|
+
content: result,
|
|
147
|
+
updated: true,
|
|
148
|
+
wasInserted: true,
|
|
149
|
+
warning,
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
// If no existing block, insert new one
|
|
153
|
+
if (!extraction.found) {
|
|
154
|
+
return {
|
|
155
|
+
content: insertMergeBlock(originalContent, newBlockContent),
|
|
156
|
+
updated: true,
|
|
157
|
+
wasInserted: true,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
// Check if content is unchanged
|
|
161
|
+
const normalizedNew = normalizeLineEndings(newBlockContent, lineEnding).trim();
|
|
162
|
+
const normalizedExisting = (extraction.content || '').trim();
|
|
163
|
+
if (normalizedNew === normalizedExisting) {
|
|
164
|
+
return {
|
|
165
|
+
content: originalContent,
|
|
166
|
+
updated: false,
|
|
167
|
+
unchanged: true,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
// Replace existing block - at this point we know extraction.found is true
|
|
171
|
+
// so startIndex and endIndex are defined
|
|
172
|
+
const startIdx = extraction.startIndex ?? 0;
|
|
173
|
+
const endIdx = extraction.endIndex ?? originalContent.length;
|
|
174
|
+
const before = originalContent.slice(0, startIdx);
|
|
175
|
+
const after = originalContent.slice(endIdx);
|
|
176
|
+
// Build the new block with preserved line endings
|
|
177
|
+
const newBlock = [
|
|
178
|
+
MARKERS.START,
|
|
179
|
+
normalizeLineEndings(newBlockContent, lineEnding),
|
|
180
|
+
MARKERS.END,
|
|
181
|
+
].join(lineEnding);
|
|
182
|
+
// Combine parts, ensuring proper line ending between before and block
|
|
183
|
+
let result = before;
|
|
184
|
+
if (!result.endsWith(lineEnding) && result.length > 0) {
|
|
185
|
+
result += lineEnding;
|
|
186
|
+
}
|
|
187
|
+
result += newBlock;
|
|
188
|
+
// Handle after part
|
|
189
|
+
if (after.trim().length > 0) {
|
|
190
|
+
if (!result.endsWith(lineEnding)) {
|
|
191
|
+
result += lineEnding;
|
|
192
|
+
}
|
|
193
|
+
result += after;
|
|
194
|
+
}
|
|
195
|
+
else if (after.includes(lineEnding)) {
|
|
196
|
+
// Preserve trailing newline if original had it
|
|
197
|
+
if (!result.endsWith(lineEnding)) {
|
|
198
|
+
result += lineEnding;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
content: result,
|
|
203
|
+
updated: true,
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
/**
|
|
207
|
+
* Trim leading and trailing newlines from a string.
|
|
208
|
+
* Uses simple loop to avoid regex ReDoS vulnerability.
|
|
209
|
+
*/
|
|
210
|
+
function trimNewlines(str) {
|
|
211
|
+
let start = 0;
|
|
212
|
+
let end = str.length;
|
|
213
|
+
// Trim leading newlines
|
|
214
|
+
while (start < end && (str[start] === '\r' || str[start] === '\n')) {
|
|
215
|
+
start++;
|
|
216
|
+
}
|
|
217
|
+
// Trim trailing newlines
|
|
218
|
+
while (end > start && (str[end - 1] === '\r' || str[end - 1] === '\n')) {
|
|
219
|
+
end--;
|
|
220
|
+
}
|
|
221
|
+
return str.slice(start, end);
|
|
222
|
+
}
|
package/dist/metrics-cli.js
CHANGED
|
@@ -25,12 +25,14 @@ import { Command } from 'commander';
|
|
|
25
25
|
import { captureMetricsSnapshot, calculateDORAMetrics, calculateFlowState, } from '@lumenflow/metrics';
|
|
26
26
|
import { getGitForCwd } from '@lumenflow/core/dist/git-adapter.js';
|
|
27
27
|
import { die } from '@lumenflow/core/dist/error-handler.js';
|
|
28
|
+
import { createWuPaths } from '@lumenflow/core/dist/wu-paths.js';
|
|
28
29
|
/** Log prefix for console output */
|
|
29
30
|
const LOG_PREFIX = '[metrics]';
|
|
30
31
|
/** Default snapshot output path */
|
|
31
32
|
const DEFAULT_OUTPUT = '.lumenflow/snapshots/metrics-latest.json';
|
|
33
|
+
const wuPaths = createWuPaths();
|
|
32
34
|
/** WU directory relative to repo root */
|
|
33
|
-
const WU_DIR =
|
|
35
|
+
const WU_DIR = wuPaths.WU_DIR();
|
|
34
36
|
/** Skip-gates audit file path */
|
|
35
37
|
const SKIP_GATES_PATH = '.lumenflow/skip-gates-audit.ndjson';
|
|
36
38
|
/**
|
|
@@ -424,9 +426,10 @@ async function main() {
|
|
|
424
426
|
break;
|
|
425
427
|
}
|
|
426
428
|
}
|
|
427
|
-
//
|
|
428
|
-
|
|
429
|
-
|
|
429
|
+
// WU-1181: Use import.meta.main instead of process.argv[1] comparison
|
|
430
|
+
// The old pattern fails with pnpm symlinks because process.argv[1] is the symlink
|
|
431
|
+
// path but import.meta.url resolves to the real path - they never match
|
|
432
|
+
if (import.meta.main) {
|
|
430
433
|
main().catch((err) => {
|
|
431
434
|
die(`Metrics command failed: ${err.message}`);
|
|
432
435
|
});
|
package/dist/metrics-snapshot.js
CHANGED
|
@@ -305,9 +305,10 @@ async function main() {
|
|
|
305
305
|
console.log(`${LOG_PREFIX} ✅ Snapshot written to: ${outputPath}`);
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
|
-
//
|
|
309
|
-
|
|
310
|
-
|
|
308
|
+
// WU-1181: Use import.meta.main instead of process.argv[1] comparison
|
|
309
|
+
// The old pattern fails with pnpm symlinks because process.argv[1] is the symlink
|
|
310
|
+
// path but import.meta.url resolves to the real path - they never match
|
|
311
|
+
if (import.meta.main) {
|
|
311
312
|
main().catch((err) => {
|
|
312
313
|
die(`Metrics snapshot failed: ${err.message}`);
|
|
313
314
|
});
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { Command } from 'commander';
|
|
13
13
|
import chalk from 'chalk';
|
|
14
|
-
import { loadInitiativeWUs, loadMultipleInitiatives,
|
|
14
|
+
import { loadInitiativeWUs, loadMultipleInitiatives, buildExecutionPlanAsync, formatExecutionPlan, formatExecutionPlanWithEmbeddedSpawns, calculateProgress, formatProgress, buildCheckpointWave, formatCheckpointOutput, validateCheckpointFlags, resolveCheckpointModeAsync, LOG_PREFIX, } from '@lumenflow/initiatives';
|
|
15
15
|
import { EXIT_CODES } from '@lumenflow/core/dist/wu-constants.js';
|
|
16
16
|
const program = new Command()
|
|
17
17
|
.name('orchestrate-initiative')
|
|
@@ -61,7 +61,7 @@ const program = new Command()
|
|
|
61
61
|
if (progressOnly) {
|
|
62
62
|
return;
|
|
63
63
|
}
|
|
64
|
-
const checkpointDecision =
|
|
64
|
+
const checkpointDecision = await resolveCheckpointModeAsync({ checkpointPerWave, noCheckpoint, dryRun }, wus);
|
|
65
65
|
if (checkpointDecision.enabled) {
|
|
66
66
|
if (initIds.length > 1) {
|
|
67
67
|
console.error(chalk.red(`${LOG_PREFIX} Error: Checkpoint mode only supports single initiative`));
|
|
@@ -76,7 +76,7 @@ const program = new Command()
|
|
|
76
76
|
return;
|
|
77
77
|
}
|
|
78
78
|
console.log(chalk.cyan(`${LOG_PREFIX} Building execution plan...`));
|
|
79
|
-
const plan =
|
|
79
|
+
const plan = await buildExecutionPlanAsync(wus);
|
|
80
80
|
if (plan.waves.length === 0) {
|
|
81
81
|
console.log(chalk.green(`${LOG_PREFIX} All WUs are complete! Nothing to execute.`));
|
|
82
82
|
return;
|
|
@@ -89,8 +89,14 @@ const program = new Command()
|
|
|
89
89
|
console.log(chalk.cyan('To execute this plan, remove the --dry-run flag.'));
|
|
90
90
|
return;
|
|
91
91
|
}
|
|
92
|
+
// WU-1202: Output spawn XML for actual execution (not dry-run)
|
|
93
|
+
// formatExecutionPlan only shows the plan structure, not spawn commands
|
|
94
|
+
// formatExecutionPlanWithEmbeddedSpawns includes Task XML for spawning agents
|
|
95
|
+
console.log('');
|
|
96
|
+
console.log(chalk.bold('Spawn Commands:'));
|
|
97
|
+
console.log(formatExecutionPlanWithEmbeddedSpawns(plan));
|
|
92
98
|
console.log(chalk.green(`${LOG_PREFIX} Execution plan output complete.`));
|
|
93
|
-
console.log(chalk.cyan('Copy the spawn
|
|
99
|
+
console.log(chalk.cyan('Copy the spawn XML above to execute agents.'));
|
|
94
100
|
}
|
|
95
101
|
catch (error) {
|
|
96
102
|
console.error(chalk.red(`${LOG_PREFIX} Error: ${error.message}`));
|