@lumenflow/cli 2.2.1 → 2.3.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/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 +28 -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 +468 -116
- package/dist/guard-locked.js +4 -3
- package/dist/guard-worktree-commit.js +4 -3
- package/dist/init.js +508 -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/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 +7 -84
- package/dist/validate-skills-spec.js +4 -3
- package/dist/validate.js +7 -107
- 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 +60 -24
- 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/wu-create.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
/* eslint-disable no-console -- CLI tool requires console output */
|
|
2
3
|
/**
|
|
3
4
|
* WU Create Helper (WU-1262, WU-1439)
|
|
4
5
|
*
|
|
@@ -30,7 +31,7 @@ import { getGitForCwd } from '@lumenflow/core/dist/git-adapter.js';
|
|
|
30
31
|
import { die } from '@lumenflow/core/dist/error-handler.js';
|
|
31
32
|
import { existsSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
32
33
|
import { join } from 'node:path';
|
|
33
|
-
// WU-1352: Use centralized YAML functions from wu-yaml.
|
|
34
|
+
// WU-1352: Use centralized YAML functions from wu-yaml.ts
|
|
34
35
|
import { stringifyYAML } from '@lumenflow/core/dist/wu-yaml.js';
|
|
35
36
|
// WU-1428: Use date-utils for consistent YYYY-MM-DD format (library-first)
|
|
36
37
|
import { todayISO } from '@lumenflow/core/dist/date-utils.js';
|
|
@@ -48,6 +49,8 @@ import { COMMIT_FORMATS, FILE_SYSTEM, READINESS_UI, STRING_LITERALS, } from '@lu
|
|
|
48
49
|
import { ensureOnMain, validateWUIDFormat } from '@lumenflow/core/dist/wu-helpers.js';
|
|
49
50
|
// WU-1439: Use shared micro-worktree helper
|
|
50
51
|
import { withMicroWorktree } from '@lumenflow/core/dist/micro-worktree.js';
|
|
52
|
+
// WU-1246: Auto-generate WU IDs when --id not provided
|
|
53
|
+
import { generateWuIdWithRetry } from '@lumenflow/core/dist/wu-id-generator.js';
|
|
51
54
|
// WU-1620: Import spec completeness validator for readiness summary
|
|
52
55
|
import { validateSpecCompleteness } from '@lumenflow/core/dist/wu-done-validators.js';
|
|
53
56
|
// WU-1620: Import readWU to read back created YAML for validation
|
|
@@ -56,6 +59,8 @@ import { readWU } from '@lumenflow/core/dist/wu-yaml.js';
|
|
|
56
59
|
import { lintWUSpec, formatLintErrors } from '@lumenflow/core/dist/wu-lint.js';
|
|
57
60
|
// WU-1025: Import placeholder validator for inline content validation
|
|
58
61
|
import { validateNoPlaceholders, buildPlaceholderErrorMessage, } from '@lumenflow/core/dist/wu-validator.js';
|
|
62
|
+
// WU-1211: Import initiative validation for phase check
|
|
63
|
+
import { checkInitiativePhases, findInitiative } from '@lumenflow/initiatives/dist/index.js';
|
|
59
64
|
/** Log prefix for console output */
|
|
60
65
|
const LOG_PREFIX = '[wu:create]';
|
|
61
66
|
/** Micro-worktree operation name */
|
|
@@ -77,21 +82,16 @@ const MIN_CONFIDENCE_FOR_WARNING = 30;
|
|
|
77
82
|
* Non-blocking - just logs a warning if a better lane is suggested.
|
|
78
83
|
*
|
|
79
84
|
* @param {string} providedLane - Lane provided by the user
|
|
80
|
-
* @param {string|undefined}
|
|
85
|
+
* @param {string[]|undefined} codePathsArray - Code paths array from Commander
|
|
81
86
|
* @param {string} title - WU title (used as fallback description)
|
|
82
87
|
* @param {string|undefined} description - WU description
|
|
83
88
|
*/
|
|
84
|
-
export function warnIfBetterLaneExists(providedLane,
|
|
85
|
-
if (!
|
|
89
|
+
export function warnIfBetterLaneExists(providedLane, codePathsArray, title, description) {
|
|
90
|
+
if (!codePathsArray?.length && !description) {
|
|
86
91
|
return;
|
|
87
92
|
}
|
|
88
93
|
try {
|
|
89
|
-
const codePaths =
|
|
90
|
-
? codePathsRaw
|
|
91
|
-
.split(',')
|
|
92
|
-
.map((s) => s.trim())
|
|
93
|
-
.filter(Boolean)
|
|
94
|
-
: [];
|
|
94
|
+
const codePaths = codePathsArray ?? [];
|
|
95
95
|
const descForInference = description || title;
|
|
96
96
|
const suggestion = inferSubLane(codePaths, descForInference);
|
|
97
97
|
// Only warn if suggestion differs and confidence is meaningful
|
|
@@ -105,7 +105,7 @@ export function warnIfBetterLaneExists(providedLane, codePathsRaw, title, descri
|
|
|
105
105
|
const isDifferentLane = providedParent !== suggestedParent;
|
|
106
106
|
if (isMoreSpecific || isDifferentLane) {
|
|
107
107
|
console.warn(`${LOG_PREFIX} Consider using "${suggestion.lane}" (${suggestion.confidence}% match) instead of "${providedLane}"`);
|
|
108
|
-
console.warn(`${LOG_PREFIX} Run: pnpm wu:infer-lane --paths "${
|
|
108
|
+
console.warn(`${LOG_PREFIX} Run: pnpm wu:infer-lane --paths "${codePaths.join(' ')}" --desc "${title}"`);
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
catch {
|
|
@@ -179,19 +179,12 @@ function displayReadinessSummary(id) {
|
|
|
179
179
|
console.warn(`${LOG_PREFIX} ⚠️ Could not validate readiness: ${err.message}`);
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
|
-
// Helper to parse comma-separated strings into arrays (DRY)
|
|
183
|
-
const parseCommaSeparated = (value) => value
|
|
184
|
-
? value
|
|
185
|
-
.split(',')
|
|
186
|
-
.map((s) => s.trim())
|
|
187
|
-
.filter(Boolean)
|
|
188
|
-
: [];
|
|
189
182
|
function mergeSpecRefs(specRefs, extraRef) {
|
|
190
|
-
const refs =
|
|
183
|
+
const refs = specRefs ? [...specRefs] : [];
|
|
191
184
|
if (extraRef && !refs.includes(extraRef)) {
|
|
192
185
|
refs.push(extraRef);
|
|
193
186
|
}
|
|
194
|
-
return refs
|
|
187
|
+
return refs;
|
|
195
188
|
}
|
|
196
189
|
function createPlanTemplate(wuId, title) {
|
|
197
190
|
const plansDir = getPlansDir();
|
|
@@ -218,11 +211,12 @@ function createPlanTemplate(wuId, title) {
|
|
|
218
211
|
}
|
|
219
212
|
function buildWUContent({ id, lane, title, priority, type, created, opts, }) {
|
|
220
213
|
const { description, acceptance, codePaths, testPathsManual, testPathsUnit, testPathsE2e, initiative, phase, blockedBy, blocks, labels, assignedTo, exposure, userJourney, uiPairingWus, specRefs, } = opts;
|
|
221
|
-
|
|
214
|
+
// Arrays come directly from Commander.js repeatable options - no parsing needed
|
|
215
|
+
const code_paths = codePaths ?? [];
|
|
222
216
|
const tests = {
|
|
223
|
-
manual:
|
|
224
|
-
unit:
|
|
225
|
-
e2e:
|
|
217
|
+
manual: testPathsManual ?? [],
|
|
218
|
+
unit: testPathsUnit ?? [],
|
|
219
|
+
e2e: testPathsE2e ?? [],
|
|
226
220
|
};
|
|
227
221
|
return {
|
|
228
222
|
id,
|
|
@@ -243,14 +237,14 @@ function buildWUContent({ id, lane, title, priority, type, created, opts, }) {
|
|
|
243
237
|
requires_review: false,
|
|
244
238
|
...(initiative && { initiative }),
|
|
245
239
|
...(phase && { phase: parseInt(phase, 10) }),
|
|
246
|
-
...(blockedBy && { blocked_by: blockedBy
|
|
247
|
-
...(blocks && { blocks
|
|
248
|
-
...(labels && { labels
|
|
240
|
+
...(blockedBy?.length && { blocked_by: blockedBy }),
|
|
241
|
+
...(blocks?.length && { blocks }),
|
|
242
|
+
...(labels?.length && { labels }),
|
|
249
243
|
...(assignedTo && { assigned_to: assignedTo }),
|
|
250
244
|
...(exposure && { exposure }),
|
|
251
245
|
...(userJourney && { user_journey: userJourney }),
|
|
252
|
-
...(uiPairingWus && { ui_pairing_wus:
|
|
253
|
-
...(specRefs && { spec_refs:
|
|
246
|
+
...(uiPairingWus?.length && { ui_pairing_wus: uiPairingWus }),
|
|
247
|
+
...(specRefs?.length && { spec_refs: specRefs }),
|
|
254
248
|
};
|
|
255
249
|
}
|
|
256
250
|
export function validateCreateSpec({ id, lane, title, priority, type, opts, }) {
|
|
@@ -453,6 +447,7 @@ async function getDefaultAssignedTo() {
|
|
|
453
447
|
return '';
|
|
454
448
|
}
|
|
455
449
|
}
|
|
450
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity -- main() orchestrates multi-step WU creation workflow
|
|
456
451
|
async function main() {
|
|
457
452
|
const args = createWUParser({
|
|
458
453
|
name: 'wu-create',
|
|
@@ -488,12 +483,32 @@ async function main() {
|
|
|
488
483
|
// WU-1062: External plan options for wu:create
|
|
489
484
|
WU_CREATE_OPTIONS.plan,
|
|
490
485
|
],
|
|
491
|
-
required: ['
|
|
486
|
+
required: ['lane', 'title'], // WU-1246: --id is now optional (auto-generated if not provided)
|
|
492
487
|
allowPositionalId: false,
|
|
493
488
|
});
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
489
|
+
// WU-1246: Auto-generate WU ID if not provided
|
|
490
|
+
let wuId;
|
|
491
|
+
if (args.id) {
|
|
492
|
+
wuId = args.id;
|
|
493
|
+
// Validate explicitly provided ID
|
|
494
|
+
validateWUIDFormat(wuId);
|
|
495
|
+
}
|
|
496
|
+
else {
|
|
497
|
+
// Auto-generate next sequential ID
|
|
498
|
+
console.log(`${LOG_PREFIX} Auto-generating WU ID...`);
|
|
499
|
+
try {
|
|
500
|
+
wuId = await generateWuIdWithRetry();
|
|
501
|
+
console.log(`${LOG_PREFIX} Generated WU ID: ${wuId}`);
|
|
502
|
+
}
|
|
503
|
+
catch (error) {
|
|
504
|
+
die(`Failed to auto-generate WU ID: ${error.message}\n\n` +
|
|
505
|
+
`Options:\n` +
|
|
506
|
+
` 1. Retry the command (transient file system issue)\n` +
|
|
507
|
+
` 2. Provide an explicit ID: --id WU-XXXX\n` +
|
|
508
|
+
` 3. Check for race conditions if running parallel wu:create`);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
console.log(`${LOG_PREFIX} Creating WU ${wuId} in ${args.lane} lane...`);
|
|
497
512
|
// Validate lane format (sub-lane or parent-only)
|
|
498
513
|
try {
|
|
499
514
|
validateLaneFormat(args.lane);
|
|
@@ -512,16 +527,16 @@ async function main() {
|
|
|
512
527
|
// WU-2330: Warn if a more specific sub-lane matches code_paths or description
|
|
513
528
|
warnIfBetterLaneExists(args.lane, args.codePaths, args.title, args.description);
|
|
514
529
|
await ensureOnMain(getGitForCwd());
|
|
515
|
-
checkWUExists(
|
|
530
|
+
checkWUExists(wuId);
|
|
516
531
|
// WU-1368: Get assigned_to from flag or git config user.email
|
|
517
532
|
const assignedTo = args.assignedTo || (await getDefaultAssignedTo());
|
|
518
533
|
if (!assignedTo) {
|
|
519
534
|
console.warn(`${LOG_PREFIX} ⚠️ No assigned_to set - WU will need manual assignment`);
|
|
520
535
|
}
|
|
521
|
-
const planSpecRef = args.plan ? getPlanProtocolRef(
|
|
536
|
+
const planSpecRef = args.plan ? getPlanProtocolRef(wuId) : undefined;
|
|
522
537
|
const mergedSpecRefs = mergeSpecRefs(args.specRefs, planSpecRef);
|
|
523
538
|
const createSpecValidation = validateCreateSpec({
|
|
524
|
-
id:
|
|
539
|
+
id: wuId,
|
|
525
540
|
lane: args.lane,
|
|
526
541
|
title: args.title,
|
|
527
542
|
priority: args.priority || DEFAULT_PRIORITY,
|
|
@@ -552,7 +567,17 @@ async function main() {
|
|
|
552
567
|
die(`${LOG_PREFIX} ❌ Spec validation failed:\n\n${errorList}`);
|
|
553
568
|
}
|
|
554
569
|
console.log(`${LOG_PREFIX} ✅ Spec validation passed`);
|
|
555
|
-
|
|
570
|
+
// WU-1211: Warn if linking to initiative with no phases defined
|
|
571
|
+
if (args.initiative) {
|
|
572
|
+
const initiative = findInitiative(args.initiative);
|
|
573
|
+
if (initiative) {
|
|
574
|
+
const phaseCheck = checkInitiativePhases(initiative.doc);
|
|
575
|
+
if (!phaseCheck.hasPhases && phaseCheck.warning) {
|
|
576
|
+
console.warn(`${LOG_PREFIX} ⚠️ ${phaseCheck.warning}`);
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
const specRefsList = mergedSpecRefs;
|
|
556
581
|
const specRefsValidation = validateSpecRefs(specRefsList);
|
|
557
582
|
if (!specRefsValidation.valid) {
|
|
558
583
|
const errorList = specRefsValidation.errors
|
|
@@ -566,7 +591,7 @@ async function main() {
|
|
|
566
591
|
}
|
|
567
592
|
}
|
|
568
593
|
if (args.plan) {
|
|
569
|
-
createPlanTemplate(
|
|
594
|
+
createPlanTemplate(wuId, args.title);
|
|
570
595
|
}
|
|
571
596
|
// Transaction: micro-worktree isolation (WU-1439)
|
|
572
597
|
try {
|
|
@@ -577,11 +602,11 @@ async function main() {
|
|
|
577
602
|
try {
|
|
578
603
|
await withMicroWorktree({
|
|
579
604
|
operation: OPERATION_NAME,
|
|
580
|
-
id:
|
|
605
|
+
id: wuId,
|
|
581
606
|
logPrefix: LOG_PREFIX,
|
|
582
607
|
execute: async ({ worktreePath }) => {
|
|
583
608
|
// Create WU YAML in micro-worktree
|
|
584
|
-
const wuPath = createWUYamlInWorktree(worktreePath,
|
|
609
|
+
const wuPath = createWUYamlInWorktree(worktreePath, wuId, args.lane, args.title, priority, type, {
|
|
585
610
|
// Initiative system fields (WU-1247)
|
|
586
611
|
initiative: args.initiative,
|
|
587
612
|
phase: args.phase,
|
|
@@ -605,10 +630,10 @@ async function main() {
|
|
|
605
630
|
specRefs: mergedSpecRefs,
|
|
606
631
|
});
|
|
607
632
|
// Update backlog.md in micro-worktree
|
|
608
|
-
const backlogPath = updateBacklogInWorktree(worktreePath,
|
|
633
|
+
const backlogPath = updateBacklogInWorktree(worktreePath, wuId, args.lane, args.title);
|
|
609
634
|
// Build commit message
|
|
610
635
|
const shortTitle = truncateTitle(args.title);
|
|
611
|
-
const commitMessage = COMMIT_FORMATS.CREATE(
|
|
636
|
+
const commitMessage = COMMIT_FORMATS.CREATE(wuId, shortTitle);
|
|
612
637
|
// Return commit message and files to commit
|
|
613
638
|
return {
|
|
614
639
|
commitMessage,
|
|
@@ -626,12 +651,12 @@ async function main() {
|
|
|
626
651
|
}
|
|
627
652
|
}
|
|
628
653
|
console.log(`\n${LOG_PREFIX} ✅ Transaction complete!`);
|
|
629
|
-
console.log(`\nWU ${
|
|
630
|
-
console.log(` File: ${WU_PATHS.WU(
|
|
654
|
+
console.log(`\nWU ${wuId} created successfully:`);
|
|
655
|
+
console.log(` File: ${WU_PATHS.WU(wuId)}`);
|
|
631
656
|
console.log(` Lane: ${args.lane}`);
|
|
632
657
|
console.log(` Status: ready`);
|
|
633
658
|
// WU-1620: Display readiness summary
|
|
634
|
-
displayReadinessSummary(
|
|
659
|
+
displayReadinessSummary(wuId);
|
|
635
660
|
}
|
|
636
661
|
catch (error) {
|
|
637
662
|
die(`Transaction failed: ${error.message}\n\n` +
|
|
@@ -645,5 +670,5 @@ async function main() {
|
|
|
645
670
|
// path but import.meta.url resolves to the real path - they never match
|
|
646
671
|
import { runCLI } from './cli-entry-point.js';
|
|
647
672
|
if (import.meta.main) {
|
|
648
|
-
runCLI(main);
|
|
673
|
+
void runCLI(main);
|
|
649
674
|
}
|
package/dist/wu-delete.js
CHANGED
|
@@ -122,35 +122,49 @@ async function deleteSingleWU(id, dryRun) {
|
|
|
122
122
|
await ensureCleanWorkingTree();
|
|
123
123
|
await ensureMainUpToDate(getGitForCwd(), 'wu:delete');
|
|
124
124
|
console.log(`${PREFIX} Deleting via micro-worktree...`);
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
unlinkSync(
|
|
137
|
-
console.log(`${PREFIX} ✅ Deleted
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
125
|
+
// WU-1245: Set LUMENFLOW_WU_TOOL for pre-push hook allowlist
|
|
126
|
+
const previousWuTool = process.env.LUMENFLOW_WU_TOOL;
|
|
127
|
+
process.env.LUMENFLOW_WU_TOOL = MICRO_WORKTREE_OPERATIONS.WU_DELETE;
|
|
128
|
+
try {
|
|
129
|
+
await withMicroWorktree({
|
|
130
|
+
operation: MICRO_WORKTREE_OPERATIONS.WU_DELETE,
|
|
131
|
+
id: id,
|
|
132
|
+
logPrefix: PREFIX,
|
|
133
|
+
execute: async ({ worktreePath, gitWorktree }) => {
|
|
134
|
+
const wuFilePath = join(worktreePath, wuPath);
|
|
135
|
+
const backlogFilePath = join(worktreePath, WU_PATHS.BACKLOG());
|
|
136
|
+
unlinkSync(wuFilePath);
|
|
137
|
+
console.log(`${PREFIX} ✅ Deleted ${id}.yaml`);
|
|
138
|
+
const stampPath = join(worktreePath, getStampPath(id));
|
|
139
|
+
if (existsSync(stampPath)) {
|
|
140
|
+
unlinkSync(stampPath);
|
|
141
|
+
console.log(`${PREFIX} ✅ Deleted stamp ${id}.done`);
|
|
142
|
+
}
|
|
143
|
+
const removedFromBacklog = removeFromBacklog(backlogFilePath, id);
|
|
144
|
+
if (removedFromBacklog) {
|
|
145
|
+
console.log(`${PREFIX} ✅ Removed ${id} from backlog.md`);
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
console.log(`${PREFIX} ℹ️ ${id} was not found in backlog.md`);
|
|
149
|
+
}
|
|
150
|
+
await gitWorktree.add('.');
|
|
151
|
+
const commitMessage = `docs: delete ${id.toLowerCase()}`;
|
|
152
|
+
return {
|
|
153
|
+
commitMessage,
|
|
154
|
+
files: [],
|
|
155
|
+
};
|
|
156
|
+
},
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
finally {
|
|
160
|
+
// Restore previous LUMENFLOW_WU_TOOL value
|
|
161
|
+
if (previousWuTool === undefined) {
|
|
162
|
+
delete process.env.LUMENFLOW_WU_TOOL;
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
process.env.LUMENFLOW_WU_TOOL = previousWuTool;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
154
168
|
console.log(`${PREFIX} ✅ Successfully deleted ${id}`);
|
|
155
169
|
console.log(`${PREFIX} Changes pushed to origin/main`);
|
|
156
170
|
}
|
|
@@ -179,39 +193,53 @@ async function deleteBatchWUs(ids, dryRun) {
|
|
|
179
193
|
await ensureCleanWorkingTree();
|
|
180
194
|
await ensureMainUpToDate(getGitForCwd(), 'wu:delete --batch');
|
|
181
195
|
console.log(`${PREFIX} Deleting ${ids.length} WU(s) via micro-worktree...`);
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
unlinkSync(stampPath);
|
|
197
|
-
console.log(`${PREFIX} ✅ Deleted stamp ${id}.done`);
|
|
196
|
+
// WU-1245: Set LUMENFLOW_WU_TOOL for pre-push hook allowlist
|
|
197
|
+
const previousWuTool = process.env.LUMENFLOW_WU_TOOL;
|
|
198
|
+
process.env.LUMENFLOW_WU_TOOL = MICRO_WORKTREE_OPERATIONS.WU_DELETE;
|
|
199
|
+
try {
|
|
200
|
+
await withMicroWorktree({
|
|
201
|
+
operation: MICRO_WORKTREE_OPERATIONS.WU_DELETE,
|
|
202
|
+
id: `batch-${ids.length}`,
|
|
203
|
+
logPrefix: PREFIX,
|
|
204
|
+
execute: async ({ worktreePath, gitWorktree }) => {
|
|
205
|
+
const backlogFilePath = join(worktreePath, WU_PATHS.BACKLOG());
|
|
206
|
+
for (const { id, wuPath } of wusToDelete) {
|
|
207
|
+
const wuFilePath = join(worktreePath, wuPath);
|
|
208
|
+
unlinkSync(wuFilePath);
|
|
209
|
+
console.log(`${PREFIX} ✅ Deleted ${id}.yaml`);
|
|
198
210
|
}
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
211
|
+
for (const id of stampsToDelete) {
|
|
212
|
+
const stampPath = join(worktreePath, getStampPath(id));
|
|
213
|
+
if (existsSync(stampPath)) {
|
|
214
|
+
unlinkSync(stampPath);
|
|
215
|
+
console.log(`${PREFIX} ✅ Deleted stamp ${id}.done`);
|
|
216
|
+
}
|
|
204
217
|
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
218
|
+
for (const { id } of wusToDelete) {
|
|
219
|
+
const removed = removeFromBacklog(backlogFilePath, id);
|
|
220
|
+
if (removed) {
|
|
221
|
+
console.log(`${PREFIX} ✅ Removed ${id} from backlog.md`);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
await gitWorktree.add('.');
|
|
225
|
+
const idList = ids.map((id) => id.toLowerCase()).join(', ');
|
|
226
|
+
const commitMessage = `chore(repair): delete ${ids.length} orphaned wus (${idList})`;
|
|
227
|
+
return {
|
|
228
|
+
commitMessage,
|
|
229
|
+
files: [],
|
|
230
|
+
};
|
|
231
|
+
},
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
finally {
|
|
235
|
+
// Restore previous LUMENFLOW_WU_TOOL value
|
|
236
|
+
if (previousWuTool === undefined) {
|
|
237
|
+
delete process.env.LUMENFLOW_WU_TOOL;
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
process.env.LUMENFLOW_WU_TOOL = previousWuTool;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
215
243
|
console.log(`${PREFIX} ✅ Successfully deleted ${ids.length} WU(s)`);
|
|
216
244
|
console.log(`${PREFIX} Changes pushed to origin/main`);
|
|
217
245
|
}
|
package/dist/wu-deps.js
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { createWUParser, WU_OPTIONS } from '@lumenflow/core/dist/arg-parser.js';
|
|
14
14
|
import { die } from '@lumenflow/core/dist/error-handler.js';
|
|
15
|
-
import {
|
|
15
|
+
import { buildDependencyGraphAsync, renderASCII, renderMermaid, validateGraph, } from '@lumenflow/core/dist/dependency-graph.js';
|
|
16
16
|
import { OUTPUT_FORMATS } from '@lumenflow/initiatives/dist/initiative-constants.js';
|
|
17
17
|
import { PATTERNS } from '@lumenflow/core/dist/wu-constants.js';
|
|
18
18
|
async function main() {
|
|
@@ -31,7 +31,7 @@ async function main() {
|
|
|
31
31
|
die(`Invalid WU ID format: "${wuId}"\n\nExpected format: WU-<number> (e.g., WU-1247)`);
|
|
32
32
|
}
|
|
33
33
|
console.log(`[wu:deps] Building dependency graph...`);
|
|
34
|
-
const graph =
|
|
34
|
+
const graph = await buildDependencyGraphAsync();
|
|
35
35
|
if (!graph.has(wuId)) {
|
|
36
36
|
die(`WU not found in graph: ${wuId}\n\nEnsure the WU exists in docs/04-operations/tasks/wu/`);
|
|
37
37
|
}
|
|
@@ -112,9 +112,10 @@ function renderGraphJSON(graph, rootId, depth, direction) {
|
|
|
112
112
|
}
|
|
113
113
|
return JSON.stringify(output, null, 2);
|
|
114
114
|
}
|
|
115
|
-
//
|
|
116
|
-
|
|
115
|
+
// WU-1181: Use import.meta.main instead of process.argv[1] comparison
|
|
116
|
+
// The old pattern fails with pnpm symlinks because process.argv[1] is the symlink
|
|
117
|
+
// path but import.meta.url resolves to the real path - they never match
|
|
117
118
|
import { runCLI } from './cli-entry-point.js';
|
|
118
|
-
if (
|
|
119
|
+
if (import.meta.main) {
|
|
119
120
|
runCLI(main);
|
|
120
121
|
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { createGitForPath } from '@lumenflow/core/git-adapter';
|
|
2
|
+
import { die } from '@lumenflow/core/error-handler';
|
|
3
|
+
import { LOG_PREFIX } from '@lumenflow/core/dist/wu-constants.js';
|
|
4
|
+
/**
|
|
5
|
+
* WU-1169: Ensure worktree is clean before wu:done operations.
|
|
6
|
+
*
|
|
7
|
+
* Prevents WU-1943 rollback loops where uncommitted changes in the worktree
|
|
8
|
+
* cause auto-rebase to fail, triggering an expensive restoration that wipes
|
|
9
|
+
* the uncommitted changes.
|
|
10
|
+
*
|
|
11
|
+
* This check HALTS wu:done immediately if the worktree is dirty.
|
|
12
|
+
*
|
|
13
|
+
* @param {string} worktreePath - Absolute path to the worktree
|
|
14
|
+
*/
|
|
15
|
+
export async function ensureCleanWorktree(worktreePath) {
|
|
16
|
+
try {
|
|
17
|
+
const git = createGitForPath(worktreePath);
|
|
18
|
+
const status = await git.getStatus();
|
|
19
|
+
if (status.trim()) {
|
|
20
|
+
die(`Worktree has uncommitted changes. Cannot proceed with wu:done.\n\n` +
|
|
21
|
+
`Path: ${worktreePath}\n\n` +
|
|
22
|
+
`Uncommitted changes:\n${status}\n\n` +
|
|
23
|
+
`❌ BLOCKING: Uncommitted changes would be lost during auto-rebase.\n\n` +
|
|
24
|
+
`Fix:\n` +
|
|
25
|
+
` 1. cd worktrees/<lane>-wu-xxx\n` +
|
|
26
|
+
` 2. git add . && git commit -m "wip: ..."\n` +
|
|
27
|
+
` 3. Retry pnpm wu:done --id WU-XXXX`);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
// If worktree is missing or git fails, let the flow continue (handled by other checks)
|
|
32
|
+
console.warn(`${LOG_PREFIX.DONE} Warning: Could not check worktree status: ${err.message}`);
|
|
33
|
+
}
|
|
34
|
+
}
|