@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/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
|
+
}
|
package/dist/wu-done.js
CHANGED
|
@@ -31,11 +31,16 @@
|
|
|
31
31
|
* WU-2542: This script imports utilities from @lumenflow/core package.
|
|
32
32
|
* Full migration to thin shim pending @lumenflow/core CLI export implementation.
|
|
33
33
|
*/
|
|
34
|
+
// WU-1153: wu:done guard for uncommitted code_paths is implemented in core package
|
|
35
|
+
// The guard runs in executeWorktreeCompletion() before metadata transaction
|
|
36
|
+
// See: packages/@lumenflow/core/src/wu-done-validation.ts
|
|
34
37
|
import { execSync } from 'node:child_process';
|
|
35
38
|
import prettyMs from 'pretty-ms';
|
|
36
39
|
import { runGates } from './gates.js';
|
|
37
40
|
import { getGitForCwd } from '@lumenflow/core/dist/git-adapter.js';
|
|
38
41
|
import { die } from '@lumenflow/core/dist/error-handler.js';
|
|
42
|
+
// WU-1223: Location detection for worktree check
|
|
43
|
+
import { resolveLocation } from '@lumenflow/core/dist/context/location-resolver.js';
|
|
39
44
|
import { existsSync, readFileSync, mkdirSync, appendFileSync, unlinkSync, statSync } from 'node:fs';
|
|
40
45
|
import path from 'node:path';
|
|
41
46
|
// WU-1825: Import from unified code-path-validator (consolidates 3 validators)
|
|
@@ -54,7 +59,9 @@ validateAllPreCommitHooks,
|
|
|
54
59
|
validateTypeVsCodePathsPreflight, buildTypeVsCodePathsErrorMessage, } from '@lumenflow/core/dist/wu-done-validators.js';
|
|
55
60
|
// WU-1825: validateCodePathsExist moved to unified code-path-validator
|
|
56
61
|
import { validateCodePathsExist } from '@lumenflow/core/dist/code-path-validator.js';
|
|
57
|
-
import { BRANCHES, REMOTES, PATTERNS, DEFAULTS, LOG_PREFIX, EMOJI, GIT, SESSION, WU_STATUS, PKG_MANAGER, SCRIPTS, CLI_FLAGS, FILE_SYSTEM, EXIT_CODES, STRING_LITERALS, MICRO_WORKTREE_OPERATIONS, TELEMETRY_STEPS, SKIP_GATES_REASONS, CHECKPOINT_MESSAGES,
|
|
62
|
+
import { BRANCHES, REMOTES, PATTERNS, DEFAULTS, LOG_PREFIX, EMOJI, GIT, SESSION, WU_STATUS, PKG_MANAGER, SCRIPTS, CLI_FLAGS, FILE_SYSTEM, EXIT_CODES, STRING_LITERALS, MICRO_WORKTREE_OPERATIONS, TELEMETRY_STEPS, SKIP_GATES_REASONS, CHECKPOINT_MESSAGES,
|
|
63
|
+
// WU-1223: Location types for worktree detection
|
|
64
|
+
CONTEXT_VALIDATION, } from '@lumenflow/core/dist/wu-constants.js';
|
|
58
65
|
import { printGateFailureBox, printStatusPreview } from '@lumenflow/core/dist/wu-done-ui.js';
|
|
59
66
|
import { ensureOnMain } from '@lumenflow/core/dist/wu-helpers.js';
|
|
60
67
|
import { WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
@@ -86,6 +93,7 @@ import { SpawnStatus } from '@lumenflow/core/dist/spawn-registry-schema.js';
|
|
|
86
93
|
// WU-1999: Exposure validation for UI pairing
|
|
87
94
|
// WU-2022: Feature accessibility validation (blocking)
|
|
88
95
|
import { validateExposure, validateFeatureAccessibility, } from '@lumenflow/core/dist/wu-validation.js';
|
|
96
|
+
import { ensureCleanWorktree } from './wu-done-check.js';
|
|
89
97
|
// WU-1588: Memory layer constants
|
|
90
98
|
const MEMORY_SIGNAL_TYPES = {
|
|
91
99
|
WU_COMPLETION: 'wu_completion',
|
|
@@ -148,7 +156,7 @@ async function validateClaimMetadataBeforeGates(id, worktreePath, yamlStatus) {
|
|
|
148
156
|
` pnpm wu:repair-claim --id ${id}\n\n` +
|
|
149
157
|
`After repair, retry:\n` +
|
|
150
158
|
` pnpm wu:done --id ${id}\n\n` +
|
|
151
|
-
`See:
|
|
159
|
+
`See: https://lumenflow.dev/reference/troubleshooting-wu-done/ for more recovery options.`);
|
|
152
160
|
}
|
|
153
161
|
export function printExposureWarnings(wu, options = {}) {
|
|
154
162
|
// Validate exposure
|
|
@@ -445,7 +453,7 @@ export async function isBranchAlreadyMerged(branch) {
|
|
|
445
453
|
return false;
|
|
446
454
|
}
|
|
447
455
|
}
|
|
448
|
-
// WU-1281: isDocsOnlyByPaths removed - use shouldSkipWebTests from path-classifiers.
|
|
456
|
+
// WU-1281: isDocsOnlyByPaths removed - use shouldSkipWebTests from path-classifiers.ts
|
|
449
457
|
// The validators already use shouldSkipWebTests via detectDocsOnlyByPaths wrapper.
|
|
450
458
|
// Keeping the export for backward compatibility but re-exporting the canonical function.
|
|
451
459
|
export { shouldSkipWebTests as isDocsOnlyByPaths } from '@lumenflow/core/dist/path-classifiers.js';
|
|
@@ -501,7 +509,7 @@ function getCommitHeaderLimit() {
|
|
|
501
509
|
return DEFAULTS.MAX_COMMIT_SUBJECT; // Fallback if config is malformed or missing
|
|
502
510
|
}
|
|
503
511
|
}
|
|
504
|
-
// ensureOnMain() moved to wu-helpers.
|
|
512
|
+
// ensureOnMain() moved to wu-helpers.ts (WU-1256)
|
|
505
513
|
/**
|
|
506
514
|
* Ensure working tree is clean before wu:done operations.
|
|
507
515
|
*
|
|
@@ -719,7 +727,7 @@ async function ensureMainUpToDate() {
|
|
|
719
727
|
* by calling /usr/bin/git directly or if PATH was not set up correctly.
|
|
720
728
|
*
|
|
721
729
|
* Context: WU-630 (detective layer, Layer 3 of 4)
|
|
722
|
-
* See:
|
|
730
|
+
* See: https://lumenflow.dev/reference/playbook/ §4.6
|
|
723
731
|
*/
|
|
724
732
|
function runTripwireCheck() {
|
|
725
733
|
const violations = scanLogForViolations();
|
|
@@ -764,7 +772,7 @@ function runTripwireCheck() {
|
|
|
764
772
|
console.error(' 3. Escalate to human if critical files were deleted\n');
|
|
765
773
|
}
|
|
766
774
|
console.error('📖 See detailed recovery steps:');
|
|
767
|
-
console.error('
|
|
775
|
+
console.error(' https://lumenflow.dev/reference/playbook/ §4.6\n');
|
|
768
776
|
console.error('🚫 DO NOT proceed with wu:done until violations are remediated.\n');
|
|
769
777
|
console.error('Fix violations first, then retry wu:done.\n');
|
|
770
778
|
// Also rotate log (cleanup old entries)
|
|
@@ -847,7 +855,7 @@ async function auditSkipCosGates(id, reason) {
|
|
|
847
855
|
appendFileSync(auditPath, `${line}\n`, { encoding: FILE_SYSTEM.UTF8 });
|
|
848
856
|
console.log(`${LOG_PREFIX.DONE} ${EMOJI.MEMO} Skip-COS-gates event logged to ${auditPath}`);
|
|
849
857
|
}
|
|
850
|
-
// WU-2308: validateAllPreCommitHooks moved to wu-done-validators.
|
|
858
|
+
// WU-2308: validateAllPreCommitHooks moved to wu-done-validators.ts
|
|
851
859
|
// Now accepts worktreePath parameter to run audit from worktree context
|
|
852
860
|
/**
|
|
853
861
|
* Check if node_modules in worktree may be stale
|
|
@@ -1000,13 +1008,13 @@ async function validateStagedFiles(id, isDocsOnly = false) {
|
|
|
1000
1008
|
}
|
|
1001
1009
|
}
|
|
1002
1010
|
// Note: updateStatusRemoveInProgress, addToStatusCompleted, and moveWUToDoneBacklog
|
|
1003
|
-
// have been extracted to tools/lib/wu-status-updater.
|
|
1011
|
+
// have been extracted to tools/lib/wu-status-updater.ts and imported above (WU-1163)
|
|
1004
1012
|
//
|
|
1005
|
-
// Note: ensureStamp has been replaced with createStamp from tools/lib/stamp-utils.
|
|
1013
|
+
// Note: ensureStamp has been replaced with createStamp from tools/lib/stamp-utils.ts (WU-1163)
|
|
1006
1014
|
//
|
|
1007
1015
|
// Note: readWUPreferWorktree, detectCurrentWorktree, defaultWorktreeFrom, detectWorkspaceMode,
|
|
1008
1016
|
// defaultBranchFrom, branchExists, runCleanup have been extracted to
|
|
1009
|
-
// tools/lib/wu-done-validators.
|
|
1017
|
+
// tools/lib/wu-done-validators.ts and imported above (WU-1215)
|
|
1010
1018
|
/**
|
|
1011
1019
|
* Validate Branch-Only mode requirements before proceeding
|
|
1012
1020
|
* @param {string} laneBranch - Expected lane branch name
|
|
@@ -1862,7 +1870,7 @@ async function executeGates({ id, args, isBranchOnly, isDocsOnly, worktreePath,
|
|
|
1862
1870
|
console.error(`\n${LOG_PREFIX.DONE} ${EMOJI.FAILURE} COS governance gates failed`);
|
|
1863
1871
|
console.error('\nTo fix:');
|
|
1864
1872
|
console.error(' 1. Add required evidence to governance.evidence field in WU YAML');
|
|
1865
|
-
console.error(' 2. See:
|
|
1873
|
+
console.error(' 2. See: https://lumenflow.dev/reference/evidence-format/');
|
|
1866
1874
|
console.error('\nEmergency bypass (creates audit trail):');
|
|
1867
1875
|
console.error(` pnpm wu:done --id ${id} --skip-cos-gates --reason "explanation"`);
|
|
1868
1876
|
die('Abort: WU not completed. Fix governance evidence and retry pnpm wu:done.');
|
|
@@ -1915,8 +1923,22 @@ function printStateHUD({ id, docMain, isBranchOnly, isDocsOnly, derivedWorktree,
|
|
|
1915
1923
|
async function main() {
|
|
1916
1924
|
// Allow pre-push hook to recognize wu:done automation (WU-1030)
|
|
1917
1925
|
process.env.LUMENFLOW_WU_TOOL = 'wu-done';
|
|
1918
|
-
// Validate CLI arguments and WU ID format (extracted to wu-done-validators.
|
|
1926
|
+
// Validate CLI arguments and WU ID format (extracted to wu-done-validators.ts)
|
|
1919
1927
|
const { args, id } = validateInputs(process.argv);
|
|
1928
|
+
// WU-1223: Check if running from worktree - wu:done now requires main checkout
|
|
1929
|
+
// Agents should use wu:prep from worktree, then wu:done from main
|
|
1930
|
+
const { LOCATION_TYPES } = CONTEXT_VALIDATION;
|
|
1931
|
+
const currentLocation = await resolveLocation();
|
|
1932
|
+
if (currentLocation.type === LOCATION_TYPES.WORKTREE) {
|
|
1933
|
+
die(`${EMOJI.FAILURE} wu:done must be run from main checkout, not from a worktree.\n\n` +
|
|
1934
|
+
`Current location: ${currentLocation.cwd}\n\n` +
|
|
1935
|
+
`WU-1223 NEW WORKFLOW:\n` +
|
|
1936
|
+
` 1. From worktree, run: pnpm wu:prep --id ${id}\n` +
|
|
1937
|
+
` (This runs gates and prepares for completion)\n\n` +
|
|
1938
|
+
` 2. From main, run: cd ${currentLocation.mainCheckout} && pnpm wu:done --id ${id}\n` +
|
|
1939
|
+
` (This does merge + cleanup only)\n\n` +
|
|
1940
|
+
`Use wu:prep to run gates in the worktree, then wu:done from main for merge/cleanup.`);
|
|
1941
|
+
}
|
|
1920
1942
|
// Detect workspace mode and calculate paths (WU-1215: extracted to validators module)
|
|
1921
1943
|
const pathInfo = await detectModeAndPaths(id, args);
|
|
1922
1944
|
const { WU_PATH, STATUS_PATH, BACKLOG_PATH, STAMPS_DIR, docMain, isBranchOnly, derivedWorktree, docForValidation: initialDocForValidation, isDocsOnly, } = pathInfo;
|
|
@@ -1940,6 +1962,11 @@ async function main() {
|
|
|
1940
1962
|
}
|
|
1941
1963
|
const effectiveDerivedWorktree = effectiveBranchOnly ? null : derivedWorktree;
|
|
1942
1964
|
const effectiveWorktreePath = effectiveBranchOnly ? null : resolvedWorktreePath;
|
|
1965
|
+
// WU-1169: Ensure worktree is clean before proceeding
|
|
1966
|
+
// This prevents WU-1943 rollback loops if rebase fails due to dirty state
|
|
1967
|
+
if (effectiveWorktreePath && existsSync(effectiveWorktreePath)) {
|
|
1968
|
+
await ensureCleanWorktree(effectiveWorktreePath);
|
|
1969
|
+
}
|
|
1943
1970
|
// Pre-flight checks (WU-1215: extracted to executePreFlightChecks function)
|
|
1944
1971
|
const preFlightResult = await executePreFlightChecks({
|
|
1945
1972
|
id,
|