@lumenflow/cli 1.0.0 → 1.3.0
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/dist/__tests__/flow-report.test.js +24 -0
- package/dist/__tests__/metrics-snapshot.test.js +24 -0
- package/dist/agent-issues-query.js +251 -0
- package/dist/agent-log-issue.js +67 -0
- package/dist/agent-session-end.js +36 -0
- package/dist/agent-session.js +46 -0
- package/dist/flow-bottlenecks.js +183 -0
- package/dist/flow-report.js +311 -0
- package/dist/gates.js +126 -49
- package/dist/init.js +297 -0
- package/dist/initiative-bulk-assign-wus.js +315 -0
- package/dist/initiative-create.js +3 -7
- package/dist/initiative-edit.js +3 -3
- package/dist/metrics-snapshot.js +314 -0
- package/dist/orchestrate-init-status.js +64 -0
- package/dist/orchestrate-initiative.js +100 -0
- package/dist/orchestrate-monitor.js +90 -0
- package/dist/wu-claim.js +313 -116
- package/dist/wu-cleanup.js +49 -3
- package/dist/wu-create.js +195 -121
- package/dist/wu-delete.js +241 -0
- package/dist/wu-done.js +146 -23
- package/dist/wu-edit.js +152 -61
- package/dist/wu-infer-lane.js +2 -2
- package/dist/wu-spawn.js +77 -158
- package/dist/wu-unlock-lane.js +158 -0
- package/package.json +30 -10
package/dist/wu-cleanup.js
CHANGED
|
@@ -13,15 +13,19 @@
|
|
|
13
13
|
*
|
|
14
14
|
* Usage:
|
|
15
15
|
* pnpm wu:cleanup --id WU-703
|
|
16
|
+
* pnpm wu:cleanup --artifacts
|
|
16
17
|
*/
|
|
17
18
|
import { execSync } from 'node:child_process';
|
|
18
19
|
import { getGitForCwd } from '@lumenflow/core/dist/git-adapter.js';
|
|
19
20
|
import { existsSync } from 'node:fs';
|
|
20
21
|
import path from 'node:path';
|
|
21
22
|
import { createWUParser, WU_OPTIONS } from '@lumenflow/core/dist/arg-parser.js';
|
|
23
|
+
import { die } from '@lumenflow/core/dist/error-handler.js';
|
|
24
|
+
import { cleanupWorktreeBuildArtifacts } from '@lumenflow/core/dist/rebase-artifact-cleanup.js';
|
|
25
|
+
import { detectCurrentWorktree } from '@lumenflow/core/dist/wu-done-validators.js';
|
|
22
26
|
import { WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
23
27
|
import { readWU } from '@lumenflow/core/dist/wu-yaml.js';
|
|
24
|
-
import { BRANCHES, EXIT_CODES, FILE_SYSTEM, REMOTES, GIT_REFS, } from '@lumenflow/core/dist/wu-constants.js';
|
|
28
|
+
import { BRANCHES, EXIT_CODES, FILE_SYSTEM, LOG_PREFIX, REMOTES, GIT_REFS, } from '@lumenflow/core/dist/wu-constants.js';
|
|
25
29
|
// WU-2278: Import ownership validation for cross-agent protection
|
|
26
30
|
import { validateWorktreeOwnership } from '@lumenflow/core/dist/worktree-ownership.js';
|
|
27
31
|
/* eslint-disable security/detect-non-literal-fs-filename */
|
|
@@ -31,6 +35,13 @@ const BOX = {
|
|
|
31
35
|
MID: '╠═══════════════════════════════════════════════════════════════════╣',
|
|
32
36
|
BOT: '╚═══════════════════════════════════════════════════════════════════╝',
|
|
33
37
|
};
|
|
38
|
+
const CLEANUP_OPTIONS = {
|
|
39
|
+
artifacts: {
|
|
40
|
+
name: 'artifacts',
|
|
41
|
+
flags: '--artifacts',
|
|
42
|
+
description: 'Remove build artifacts (dist, tsbuildinfo) in current worktree',
|
|
43
|
+
},
|
|
44
|
+
};
|
|
34
45
|
// Help text is now auto-generated by commander via createWUParser
|
|
35
46
|
async function verifyPRMerged(laneBranch) {
|
|
36
47
|
// Try gh API first (most reliable)
|
|
@@ -115,14 +126,49 @@ async function deleteBranch(laneBranch) {
|
|
|
115
126
|
console.log(`[wu-cleanup] ✓ Remote branch already deleted: ${laneBranch}`);
|
|
116
127
|
}
|
|
117
128
|
}
|
|
129
|
+
async function cleanupArtifactsInWorktree() {
|
|
130
|
+
const worktreePath = detectCurrentWorktree();
|
|
131
|
+
if (!worktreePath) {
|
|
132
|
+
die(`${LOG_PREFIX.CLEANUP} Not in a worktree.\n\n` +
|
|
133
|
+
'Run this command from inside a worktree:\n' +
|
|
134
|
+
' cd worktrees/<lane>-wu-xxx\n' +
|
|
135
|
+
' pnpm wu:cleanup --artifacts\n');
|
|
136
|
+
}
|
|
137
|
+
console.log(`${LOG_PREFIX.CLEANUP} Cleaning build artifacts in ${worktreePath}`);
|
|
138
|
+
const result = await cleanupWorktreeBuildArtifacts(worktreePath);
|
|
139
|
+
if (result.removedCount === 0) {
|
|
140
|
+
console.log(`${LOG_PREFIX.CLEANUP} ✓ No build artifacts found`);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
if (result.distDirectories.length > 0) {
|
|
144
|
+
console.log(`${LOG_PREFIX.CLEANUP} Removed dist directories:`);
|
|
145
|
+
for (const dir of result.distDirectories) {
|
|
146
|
+
console.log(` - ${dir}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (result.tsbuildinfoFiles.length > 0) {
|
|
150
|
+
console.log(`${LOG_PREFIX.CLEANUP} Removed tsbuildinfo files:`);
|
|
151
|
+
for (const file of result.tsbuildinfoFiles) {
|
|
152
|
+
console.log(` - ${file}`);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
console.log(`${LOG_PREFIX.CLEANUP} ✓ Build artifact cleanup complete`);
|
|
156
|
+
}
|
|
118
157
|
async function main() {
|
|
119
158
|
const args = createWUParser({
|
|
120
159
|
name: 'wu-cleanup',
|
|
121
160
|
description: 'Clean up worktree and branch after PR merge (PR-based completion workflow)',
|
|
122
|
-
options: [WU_OPTIONS.id],
|
|
123
|
-
required: [
|
|
161
|
+
options: [WU_OPTIONS.id, CLEANUP_OPTIONS.artifacts],
|
|
162
|
+
required: [],
|
|
124
163
|
allowPositionalId: true,
|
|
125
164
|
});
|
|
165
|
+
if (args.artifacts) {
|
|
166
|
+
await cleanupArtifactsInWorktree();
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (!args.id) {
|
|
170
|
+
die(`${LOG_PREFIX.CLEANUP} Missing required --id (or use --artifacts).`);
|
|
171
|
+
}
|
|
126
172
|
const id = args.id.toUpperCase();
|
|
127
173
|
const wu = readWU(WU_PATHS.WU(id), id);
|
|
128
174
|
// Use kebab-case lane naming (match wu-claim.mjs logic)
|
package/dist/wu-create.js
CHANGED
|
@@ -40,7 +40,7 @@ import { inferSubLane } from '@lumenflow/core/dist/lane-inference.js';
|
|
|
40
40
|
import { parseBacklogFrontmatter } from '@lumenflow/core/dist/backlog-parser.js';
|
|
41
41
|
import { createWUParser, WU_OPTIONS } from '@lumenflow/core/dist/arg-parser.js';
|
|
42
42
|
import { WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
43
|
-
import {
|
|
43
|
+
import { validateWU } from '@lumenflow/core/dist/wu-schema.js';
|
|
44
44
|
import { COMMIT_FORMATS, FILE_SYSTEM, STRING_LITERALS, READINESS_UI, } from '@lumenflow/core/dist/wu-constants.js';
|
|
45
45
|
// WU-1593: Use centralized validateWUIDFormat (DRY)
|
|
46
46
|
import { ensureOnMain, validateWUIDFormat } from '@lumenflow/core/dist/wu-helpers.js';
|
|
@@ -52,6 +52,8 @@ import { validateSpecCompleteness } from '@lumenflow/core/dist/wu-done-validator
|
|
|
52
52
|
import { readWU } from '@lumenflow/core/dist/wu-yaml.js';
|
|
53
53
|
// WU-2253: Import WU spec linter for acceptance/code_paths validation
|
|
54
54
|
import { lintWUSpec, formatLintErrors } from '@lumenflow/core/dist/wu-lint.js';
|
|
55
|
+
// WU-1025: Import placeholder validator for inline content validation
|
|
56
|
+
import { validateNoPlaceholders, buildPlaceholderErrorMessage, } from '@lumenflow/core/dist/wu-validator.js';
|
|
55
57
|
/** Log prefix for console output */
|
|
56
58
|
const LOG_PREFIX = '[wu:create]';
|
|
57
59
|
/** Micro-worktree operation name */
|
|
@@ -175,67 +177,29 @@ function displayReadinessSummary(id) {
|
|
|
175
177
|
console.warn(`${LOG_PREFIX} ⚠️ Could not validate readiness: ${err.message}`);
|
|
176
178
|
}
|
|
177
179
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
* @param {Object} opts - Additional options
|
|
188
|
-
* @returns {string} Relative path to created YAML file
|
|
189
|
-
*/
|
|
190
|
-
function createWUYamlInWorktree(worktreePath, id, lane, title, priority, type, opts = {}) {
|
|
191
|
-
const wuRelativePath = WU_PATHS.WU(id);
|
|
192
|
-
const wuAbsolutePath = join(worktreePath, wuRelativePath);
|
|
193
|
-
const wuDir = join(worktreePath, WU_PATHS.WU_DIR());
|
|
194
|
-
mkdirSync(wuDir, { recursive: true });
|
|
195
|
-
// WU-1428: Use todayISO() for consistent YYYY-MM-DD format (library-first)
|
|
196
|
-
const today = todayISO();
|
|
197
|
-
// Parse initiative system fields from opts (WU-1247) and assigned_to (WU-1368)
|
|
198
|
-
const { initiative, phase, blockedBy, blocks, labels, assignedTo } = opts;
|
|
199
|
-
// WU-1364: Parse full spec inline options
|
|
200
|
-
const { description: inlineDescription, acceptance: inlineAcceptance, codePaths, testPathsManual, testPathsUnit, testPathsE2e, } = opts;
|
|
201
|
-
// WU-1998: Parse exposure field options
|
|
202
|
-
const { exposure, userJourney, uiPairingWus } = opts;
|
|
203
|
-
// WU-2320: Parse spec_refs option
|
|
204
|
-
const { specRefs } = opts;
|
|
205
|
-
// Helper to parse comma-separated strings into arrays (DRY)
|
|
206
|
-
const parseCommaSeparated = (value) => value
|
|
207
|
-
? value
|
|
208
|
-
.split(',')
|
|
209
|
-
.map((s) => s.trim())
|
|
210
|
-
.filter(Boolean)
|
|
211
|
-
: [];
|
|
212
|
-
// WU-1364: Build description (inline or placeholder)
|
|
213
|
-
const description = inlineDescription
|
|
214
|
-
? inlineDescription
|
|
215
|
-
: `${PLACEHOLDER_SENTINEL} Describe the work to be done.\n\nContext: ...\nProblem: ...\nSolution: ...\n`;
|
|
216
|
-
// WU-1364: Build acceptance (inline array or placeholder)
|
|
217
|
-
const acceptance = inlineAcceptance && inlineAcceptance.length > 0
|
|
218
|
-
? inlineAcceptance
|
|
219
|
-
: [
|
|
220
|
-
`${PLACEHOLDER_SENTINEL} Define acceptance criteria`,
|
|
221
|
-
'pnpm format, lint, typecheck → PASS',
|
|
222
|
-
];
|
|
223
|
-
// WU-1364: Build code_paths from inline flag
|
|
180
|
+
// Helper to parse comma-separated strings into arrays (DRY)
|
|
181
|
+
const parseCommaSeparated = (value) => value
|
|
182
|
+
? value
|
|
183
|
+
.split(',')
|
|
184
|
+
.map((s) => s.trim())
|
|
185
|
+
.filter(Boolean)
|
|
186
|
+
: [];
|
|
187
|
+
function buildWUContent({ id, lane, title, priority, type, created, opts, }) {
|
|
188
|
+
const { description, acceptance, codePaths, testPathsManual, testPathsUnit, testPathsE2e, initiative, phase, blockedBy, blocks, labels, assignedTo, exposure, userJourney, uiPairingWus, specRefs, } = opts;
|
|
224
189
|
const code_paths = parseCommaSeparated(codePaths);
|
|
225
|
-
// WU-1364: Build tests object from inline flags
|
|
226
190
|
const tests = {
|
|
227
191
|
manual: parseCommaSeparated(testPathsManual),
|
|
228
192
|
unit: parseCommaSeparated(testPathsUnit),
|
|
229
193
|
e2e: parseCommaSeparated(testPathsE2e),
|
|
230
194
|
};
|
|
231
|
-
|
|
195
|
+
return {
|
|
232
196
|
id,
|
|
233
197
|
title,
|
|
234
198
|
lane,
|
|
235
199
|
type,
|
|
236
200
|
status: 'ready',
|
|
237
201
|
priority,
|
|
238
|
-
created
|
|
202
|
+
created,
|
|
239
203
|
description,
|
|
240
204
|
acceptance,
|
|
241
205
|
code_paths,
|
|
@@ -245,24 +209,107 @@ function createWUYamlInWorktree(worktreePath, id, lane, title, priority, type, o
|
|
|
245
209
|
risks: [],
|
|
246
210
|
notes: '',
|
|
247
211
|
requires_review: false,
|
|
248
|
-
// Initiative system fields - only include if provided (WU-1247)
|
|
249
212
|
...(initiative && { initiative }),
|
|
250
213
|
...(phase && { phase: parseInt(phase, 10) }),
|
|
251
214
|
...(blockedBy && { blocked_by: blockedBy.split(',').map((s) => s.trim()) }),
|
|
252
215
|
...(blocks && { blocks: blocks.split(',').map((s) => s.trim()) }),
|
|
253
216
|
...(labels && { labels: labels.split(',').map((s) => s.trim()) }),
|
|
254
|
-
// WU-1368: Default assigned_to from git config user.email
|
|
255
217
|
...(assignedTo && { assigned_to: assignedTo }),
|
|
256
|
-
// WU-1998: Exposure field options - only include if provided
|
|
257
218
|
...(exposure && { exposure }),
|
|
258
219
|
...(userJourney && { user_journey: userJourney }),
|
|
259
220
|
...(uiPairingWus && { ui_pairing_wus: parseCommaSeparated(uiPairingWus) }),
|
|
260
|
-
// WU-2320: Spec references - only include if provided
|
|
261
221
|
...(specRefs && { spec_refs: parseCommaSeparated(specRefs) }),
|
|
262
222
|
};
|
|
263
|
-
|
|
223
|
+
}
|
|
224
|
+
export function validateCreateSpec({ id, lane, title, priority, type, opts, }) {
|
|
225
|
+
const errors = [];
|
|
226
|
+
const effectiveType = type || DEFAULT_TYPE;
|
|
227
|
+
if (!opts.description) {
|
|
228
|
+
errors.push('--description is required');
|
|
229
|
+
}
|
|
230
|
+
if (!opts.acceptance || opts.acceptance.length === 0) {
|
|
231
|
+
errors.push('--acceptance is required (repeatable)');
|
|
232
|
+
}
|
|
233
|
+
if (!opts.exposure) {
|
|
234
|
+
errors.push('--exposure is required');
|
|
235
|
+
}
|
|
236
|
+
const hasTestPaths = opts.testPathsManual || opts.testPathsUnit || opts.testPathsE2e;
|
|
237
|
+
if (effectiveType !== 'documentation' && effectiveType !== 'process') {
|
|
238
|
+
if (!opts.codePaths) {
|
|
239
|
+
errors.push('--code-paths is required for non-documentation WUs');
|
|
240
|
+
}
|
|
241
|
+
if (!hasTestPaths) {
|
|
242
|
+
errors.push('At least one test path flag is required (--test-paths-manual, --test-paths-unit, or --test-paths-e2e)');
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (effectiveType === 'feature' && !opts.specRefs) {
|
|
246
|
+
errors.push('--spec-refs is required for type: feature WUs');
|
|
247
|
+
}
|
|
248
|
+
if (errors.length > 0) {
|
|
249
|
+
return { valid: false, errors };
|
|
250
|
+
}
|
|
251
|
+
const placeholderResult = validateNoPlaceholders({
|
|
252
|
+
description: opts.description,
|
|
253
|
+
acceptance: opts.acceptance,
|
|
254
|
+
});
|
|
255
|
+
if (!placeholderResult.valid) {
|
|
256
|
+
return {
|
|
257
|
+
valid: false,
|
|
258
|
+
errors: [buildPlaceholderErrorMessage('wu:create', placeholderResult)],
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
const today = todayISO();
|
|
262
|
+
const wuContent = buildWUContent({
|
|
263
|
+
id,
|
|
264
|
+
lane,
|
|
265
|
+
title,
|
|
266
|
+
priority,
|
|
267
|
+
type: effectiveType,
|
|
268
|
+
created: today,
|
|
269
|
+
opts,
|
|
270
|
+
});
|
|
271
|
+
const schemaResult = validateWU(wuContent);
|
|
272
|
+
if (!schemaResult.success) {
|
|
273
|
+
const schemaErrors = schemaResult.error.issues.map((issue) => `${issue.path.join('.')}: ${issue.message}`);
|
|
274
|
+
return { valid: false, errors: schemaErrors };
|
|
275
|
+
}
|
|
276
|
+
const completeness = validateSpecCompleteness(wuContent, id);
|
|
277
|
+
if (!completeness.valid) {
|
|
278
|
+
return { valid: false, errors: completeness.errors };
|
|
279
|
+
}
|
|
280
|
+
return { valid: true, errors: [] };
|
|
281
|
+
}
|
|
282
|
+
/**
|
|
283
|
+
* Create WU YAML file in micro-worktree
|
|
284
|
+
*
|
|
285
|
+
* @param {string} worktreePath - Path to micro-worktree
|
|
286
|
+
* @param {string} id - WU ID
|
|
287
|
+
* @param {string} lane - WU lane
|
|
288
|
+
* @param {string} title - WU title
|
|
289
|
+
* @param {string} priority - WU priority
|
|
290
|
+
* @param {string} type - WU type
|
|
291
|
+
* @param {Object} opts - Additional options
|
|
292
|
+
* @returns {string} Relative path to created YAML file
|
|
293
|
+
*/
|
|
294
|
+
function createWUYamlInWorktree(worktreePath, id, lane, title, priority, type, opts = {}) {
|
|
295
|
+
const wuRelativePath = WU_PATHS.WU(id);
|
|
296
|
+
const wuAbsolutePath = join(worktreePath, wuRelativePath);
|
|
297
|
+
const wuDir = join(worktreePath, WU_PATHS.WU_DIR());
|
|
298
|
+
mkdirSync(wuDir, { recursive: true });
|
|
299
|
+
// WU-1428: Use todayISO() for consistent YYYY-MM-DD format (library-first)
|
|
300
|
+
const today = todayISO();
|
|
301
|
+
const wuContent = buildWUContent({
|
|
302
|
+
id,
|
|
303
|
+
lane,
|
|
304
|
+
title,
|
|
305
|
+
priority,
|
|
306
|
+
type,
|
|
307
|
+
created: today,
|
|
308
|
+
opts,
|
|
309
|
+
});
|
|
310
|
+
// WU-1539: Validate WU structure before writing (fail-fast, no placeholders)
|
|
264
311
|
// WU-1750: Zod transforms normalize embedded newlines in arrays and strings
|
|
265
|
-
const validationResult =
|
|
312
|
+
const validationResult = validateWU(wuContent);
|
|
266
313
|
if (!validationResult.success) {
|
|
267
314
|
const errors = validationResult.error.issues
|
|
268
315
|
.map((issue) => ` • ${issue.path.join('.')}: ${issue.message}`)
|
|
@@ -270,6 +317,14 @@ function createWUYamlInWorktree(worktreePath, id, lane, title, priority, type, o
|
|
|
270
317
|
die(`${LOG_PREFIX} ❌ WU YAML validation failed:\n\n${errors}\n\n` +
|
|
271
318
|
`Fix the issues above and retry.`);
|
|
272
319
|
}
|
|
320
|
+
const completenessResult = validateSpecCompleteness(wuContent, id);
|
|
321
|
+
if (!completenessResult.valid) {
|
|
322
|
+
const errorList = completenessResult.errors
|
|
323
|
+
.map((error) => ` • ${error}`)
|
|
324
|
+
.join(STRING_LITERALS.NEWLINE);
|
|
325
|
+
die(`${LOG_PREFIX} ❌ WU SPEC INCOMPLETE:\n\n${errorList}\n\n` +
|
|
326
|
+
`Provide the missing fields and retry.`);
|
|
327
|
+
}
|
|
273
328
|
// WU-2253: Validate acceptance/code_paths consistency and invariants compliance
|
|
274
329
|
// This blocks WU creation if acceptance references paths not in code_paths
|
|
275
330
|
// or if code_paths conflicts with tools/invariants.yml
|
|
@@ -429,76 +484,95 @@ async function main() {
|
|
|
429
484
|
if (!assignedTo) {
|
|
430
485
|
console.warn(`${LOG_PREFIX} ⚠️ No assigned_to set - WU will need manual assignment`);
|
|
431
486
|
}
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
487
|
+
const createSpecValidation = validateCreateSpec({
|
|
488
|
+
id: args.id,
|
|
489
|
+
lane: args.lane,
|
|
490
|
+
title: args.title,
|
|
491
|
+
priority: args.priority || DEFAULT_PRIORITY,
|
|
492
|
+
type: args.type || DEFAULT_TYPE,
|
|
493
|
+
opts: {
|
|
494
|
+
description: args.description,
|
|
495
|
+
acceptance: args.acceptance,
|
|
496
|
+
codePaths: args.codePaths,
|
|
497
|
+
testPathsManual: args.testPathsManual,
|
|
498
|
+
testPathsUnit: args.testPathsUnit,
|
|
499
|
+
testPathsE2e: args.testPathsE2e,
|
|
500
|
+
exposure: args.exposure,
|
|
501
|
+
userJourney: args.userJourney,
|
|
502
|
+
uiPairingWus: args.uiPairingWus,
|
|
503
|
+
specRefs: args.specRefs,
|
|
504
|
+
initiative: args.initiative,
|
|
505
|
+
phase: args.phase,
|
|
506
|
+
blockedBy: args.blockedBy,
|
|
507
|
+
blocks: args.blocks,
|
|
508
|
+
labels: args.labels,
|
|
509
|
+
assignedTo,
|
|
510
|
+
},
|
|
511
|
+
});
|
|
512
|
+
if (!createSpecValidation.valid) {
|
|
513
|
+
const errorList = createSpecValidation.errors
|
|
514
|
+
.map((error) => ` • ${error}`)
|
|
515
|
+
.join(STRING_LITERALS.NEWLINE);
|
|
516
|
+
die(`${LOG_PREFIX} ❌ Spec validation failed:\n\n${errorList}`);
|
|
456
517
|
}
|
|
518
|
+
console.log(`${LOG_PREFIX} ✅ Spec validation passed`);
|
|
457
519
|
// Transaction: micro-worktree isolation (WU-1439)
|
|
458
520
|
try {
|
|
459
521
|
const priority = args.priority || DEFAULT_PRIORITY;
|
|
460
522
|
const type = args.type || DEFAULT_TYPE;
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
commitMessage,
|
|
498
|
-
files
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
523
|
+
const previousWuTool = process.env.LUMENFLOW_WU_TOOL;
|
|
524
|
+
process.env.LUMENFLOW_WU_TOOL = OPERATION_NAME;
|
|
525
|
+
try {
|
|
526
|
+
await withMicroWorktree({
|
|
527
|
+
operation: OPERATION_NAME,
|
|
528
|
+
id: args.id,
|
|
529
|
+
logPrefix: LOG_PREFIX,
|
|
530
|
+
execute: async ({ worktreePath }) => {
|
|
531
|
+
// Create WU YAML in micro-worktree
|
|
532
|
+
const wuPath = createWUYamlInWorktree(worktreePath, args.id, args.lane, args.title, priority, type, {
|
|
533
|
+
// Initiative system fields (WU-1247)
|
|
534
|
+
initiative: args.initiative,
|
|
535
|
+
phase: args.phase,
|
|
536
|
+
blockedBy: args.blockedBy,
|
|
537
|
+
blocks: args.blocks,
|
|
538
|
+
labels: args.labels,
|
|
539
|
+
// WU-1368: Assigned to
|
|
540
|
+
assignedTo,
|
|
541
|
+
// WU-1364: Full spec inline options
|
|
542
|
+
description: args.description,
|
|
543
|
+
acceptance: args.acceptance,
|
|
544
|
+
codePaths: args.codePaths,
|
|
545
|
+
testPathsManual: args.testPathsManual,
|
|
546
|
+
testPathsUnit: args.testPathsUnit,
|
|
547
|
+
testPathsE2e: args.testPathsE2e,
|
|
548
|
+
// WU-1998: Exposure field options
|
|
549
|
+
exposure: args.exposure,
|
|
550
|
+
userJourney: args.userJourney,
|
|
551
|
+
uiPairingWus: args.uiPairingWus,
|
|
552
|
+
// WU-2320: Spec references
|
|
553
|
+
specRefs: args.specRefs,
|
|
554
|
+
});
|
|
555
|
+
// Update backlog.md in micro-worktree
|
|
556
|
+
const backlogPath = updateBacklogInWorktree(worktreePath, args.id, args.lane, args.title);
|
|
557
|
+
// Build commit message
|
|
558
|
+
const shortTitle = truncateTitle(args.title);
|
|
559
|
+
const commitMessage = COMMIT_FORMATS.CREATE(args.id, shortTitle);
|
|
560
|
+
// Return commit message and files to commit
|
|
561
|
+
return {
|
|
562
|
+
commitMessage,
|
|
563
|
+
files: [wuPath, backlogPath],
|
|
564
|
+
};
|
|
565
|
+
},
|
|
566
|
+
});
|
|
567
|
+
}
|
|
568
|
+
finally {
|
|
569
|
+
if (previousWuTool === undefined) {
|
|
570
|
+
delete process.env.LUMENFLOW_WU_TOOL;
|
|
571
|
+
}
|
|
572
|
+
else {
|
|
573
|
+
process.env.LUMENFLOW_WU_TOOL = previousWuTool;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
502
576
|
console.log(`\n${LOG_PREFIX} ✅ Transaction complete!`);
|
|
503
577
|
console.log(`\nWU ${args.id} created successfully:`);
|
|
504
578
|
console.log(` File: ${WU_PATHS.WU(args.id)}`);
|