@lumenflow/cli 2.3.2 → 2.5.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__/init-config-lanes.test.js +131 -0
- package/dist/__tests__/init-docs-structure.test.js +119 -0
- package/dist/__tests__/init-lane-inference.test.js +125 -0
- package/dist/__tests__/init-onboarding-docs.test.js +132 -0
- package/dist/__tests__/init-quick-ref.test.js +145 -0
- package/dist/__tests__/init-scripts.test.js +96 -0
- package/dist/__tests__/init-template-portability.test.js +97 -0
- package/dist/__tests__/init.test.js +199 -3
- package/dist/__tests__/initiative-add-wu.test.js +420 -0
- package/dist/__tests__/initiative-plan-replacement.test.js +162 -0
- package/dist/__tests__/initiative-remove-wu.test.js +458 -0
- package/dist/__tests__/onboarding-smoke-test.test.js +211 -0
- package/dist/__tests__/path-centralization-cli.test.js +234 -0
- package/dist/__tests__/plan-create.test.js +126 -0
- package/dist/__tests__/plan-edit.test.js +157 -0
- package/dist/__tests__/plan-link.test.js +239 -0
- package/dist/__tests__/plan-promote.test.js +181 -0
- package/dist/__tests__/wu-create-strict.test.js +118 -0
- package/dist/__tests__/wu-edit-strict.test.js +109 -0
- package/dist/__tests__/wu-validate-strict.test.js +113 -0
- package/dist/flow-bottlenecks.js +4 -2
- package/dist/flow-report.js +3 -2
- package/dist/gates.js +202 -2
- package/dist/init.js +720 -40
- package/dist/initiative-add-wu.js +112 -16
- package/dist/initiative-plan.js +3 -2
- package/dist/initiative-remove-wu.js +248 -0
- package/dist/mem-context.js +0 -0
- package/dist/metrics-snapshot.js +3 -2
- package/dist/onboarding-smoke-test.js +400 -0
- package/dist/plan-create.js +199 -0
- package/dist/plan-edit.js +235 -0
- package/dist/plan-link.js +233 -0
- package/dist/plan-promote.js +231 -0
- package/dist/rotate-progress.js +8 -5
- package/dist/spawn-list.js +4 -3
- package/dist/state-bootstrap.js +6 -4
- package/dist/state-doctor-fix.js +5 -4
- package/dist/state-doctor.js +32 -2
- package/dist/trace-gen.js +6 -3
- package/dist/wu-block.js +16 -5
- package/dist/wu-claim.js +15 -9
- package/dist/wu-create.js +50 -2
- package/dist/wu-deps.js +3 -1
- package/dist/wu-done.js +14 -5
- package/dist/wu-edit.js +35 -0
- package/dist/wu-infer-lane.js +3 -1
- package/dist/wu-spawn.js +8 -0
- package/dist/wu-unblock.js +34 -2
- package/dist/wu-validate.js +25 -17
- package/package.json +12 -6
- package/templates/core/AGENTS.md.template +2 -2
- package/dist/__tests__/init-plan.test.js +0 -340
- package/dist/agent-issues-query.d.ts +0 -16
- package/dist/agent-log-issue.d.ts +0 -10
- package/dist/agent-session-end.d.ts +0 -10
- package/dist/agent-session.d.ts +0 -10
- package/dist/backlog-prune.d.ts +0 -84
- package/dist/cli-entry-point.d.ts +0 -8
- package/dist/deps-add.d.ts +0 -91
- package/dist/deps-remove.d.ts +0 -17
- package/dist/docs-sync.d.ts +0 -50
- package/dist/file-delete.d.ts +0 -84
- package/dist/file-edit.d.ts +0 -82
- package/dist/file-read.d.ts +0 -92
- package/dist/file-write.d.ts +0 -90
- package/dist/flow-bottlenecks.d.ts +0 -16
- package/dist/flow-report.d.ts +0 -16
- package/dist/gates.d.ts +0 -94
- package/dist/git-branch.d.ts +0 -65
- package/dist/git-diff.d.ts +0 -58
- package/dist/git-log.d.ts +0 -69
- package/dist/git-status.d.ts +0 -58
- package/dist/guard-locked.d.ts +0 -62
- package/dist/guard-main-branch.d.ts +0 -50
- package/dist/guard-worktree-commit.d.ts +0 -59
- package/dist/index.d.ts +0 -10
- package/dist/init-plan.d.ts +0 -80
- package/dist/init-plan.js +0 -337
- package/dist/init.d.ts +0 -46
- package/dist/initiative-add-wu.d.ts +0 -22
- package/dist/initiative-bulk-assign-wus.d.ts +0 -16
- package/dist/initiative-create.d.ts +0 -28
- package/dist/initiative-edit.d.ts +0 -34
- package/dist/initiative-list.d.ts +0 -12
- package/dist/initiative-status.d.ts +0 -11
- package/dist/lumenflow-upgrade.d.ts +0 -103
- package/dist/mem-checkpoint.d.ts +0 -16
- package/dist/mem-cleanup.d.ts +0 -29
- package/dist/mem-create.d.ts +0 -17
- package/dist/mem-export.d.ts +0 -10
- package/dist/mem-inbox.d.ts +0 -35
- package/dist/mem-init.d.ts +0 -15
- package/dist/mem-ready.d.ts +0 -16
- package/dist/mem-signal.d.ts +0 -16
- package/dist/mem-start.d.ts +0 -16
- package/dist/mem-summarize.d.ts +0 -22
- package/dist/mem-triage.d.ts +0 -22
- package/dist/metrics-cli.d.ts +0 -90
- package/dist/metrics-snapshot.d.ts +0 -18
- package/dist/orchestrate-init-status.d.ts +0 -11
- package/dist/orchestrate-initiative.d.ts +0 -12
- package/dist/orchestrate-monitor.d.ts +0 -11
- package/dist/release.d.ts +0 -117
- package/dist/rotate-progress.d.ts +0 -48
- package/dist/session-coordinator.d.ts +0 -74
- package/dist/spawn-list.d.ts +0 -16
- package/dist/state-bootstrap.d.ts +0 -92
- package/dist/sync-templates.d.ts +0 -52
- package/dist/trace-gen.d.ts +0 -84
- package/dist/validate-agent-skills.d.ts +0 -50
- package/dist/validate-agent-sync.d.ts +0 -36
- package/dist/validate-backlog-sync.d.ts +0 -37
- package/dist/validate-skills-spec.d.ts +0 -40
- package/dist/validate.d.ts +0 -60
- package/dist/wu-block.d.ts +0 -16
- package/dist/wu-claim.d.ts +0 -74
- package/dist/wu-cleanup.d.ts +0 -35
- package/dist/wu-create.d.ts +0 -69
- package/dist/wu-delete.d.ts +0 -21
- package/dist/wu-deps.d.ts +0 -13
- package/dist/wu-done.d.ts +0 -225
- package/dist/wu-edit.d.ts +0 -63
- package/dist/wu-infer-lane.d.ts +0 -17
- package/dist/wu-preflight.d.ts +0 -47
- package/dist/wu-prune.d.ts +0 -16
- package/dist/wu-recover.d.ts +0 -37
- package/dist/wu-release.d.ts +0 -19
- package/dist/wu-repair.d.ts +0 -60
- package/dist/wu-spawn-completion.d.ts +0 -10
- package/dist/wu-spawn.d.ts +0 -192
- package/dist/wu-status.d.ts +0 -25
- package/dist/wu-unblock.d.ts +0 -16
- package/dist/wu-unlock-lane.d.ts +0 -19
- package/dist/wu-validate.d.ts +0 -16
package/dist/rotate-progress.js
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
import { readFileSync, writeFileSync, existsSync, readdirSync } from 'node:fs';
|
|
16
16
|
import { join } from 'node:path';
|
|
17
17
|
import { parse as parseYaml } from 'yaml';
|
|
18
|
-
import { EXIT_CODES, STATUS_SECTIONS,
|
|
18
|
+
import { EXIT_CODES, STATUS_SECTIONS, FILE_SYSTEM, } from '@lumenflow/core/dist/wu-constants.js';
|
|
19
|
+
import { WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
19
20
|
import { runCLI } from './cli-entry-point.js';
|
|
20
21
|
/** Log prefix for console output */
|
|
21
22
|
const LOG_PREFIX = '[rotate:progress]';
|
|
@@ -49,7 +50,8 @@ export function parseRotateArgs(argv) {
|
|
|
49
50
|
* Get WU status from YAML file
|
|
50
51
|
*/
|
|
51
52
|
function getWuStatus(wuId, baseDir = process.cwd()) {
|
|
52
|
-
|
|
53
|
+
// WU-1301: Use config-based paths
|
|
54
|
+
const yamlPath = join(baseDir, WU_PATHS.WU(wuId));
|
|
53
55
|
if (!existsSync(yamlPath)) {
|
|
54
56
|
return null;
|
|
55
57
|
}
|
|
@@ -67,7 +69,8 @@ function getWuStatus(wuId, baseDir = process.cwd()) {
|
|
|
67
69
|
*/
|
|
68
70
|
function getAllWuStatuses(baseDir = process.cwd()) {
|
|
69
71
|
const statuses = new Map();
|
|
70
|
-
|
|
72
|
+
// WU-1301: Use config-based paths
|
|
73
|
+
const wuDir = join(baseDir, WU_PATHS.WU_DIR());
|
|
71
74
|
if (!existsSync(wuDir)) {
|
|
72
75
|
return statuses;
|
|
73
76
|
}
|
|
@@ -203,8 +206,8 @@ async function main() {
|
|
|
203
206
|
printHelp();
|
|
204
207
|
process.exit(EXIT_CODES.SUCCESS);
|
|
205
208
|
}
|
|
206
|
-
// Read status.md
|
|
207
|
-
const statusPath = join(process.cwd(),
|
|
209
|
+
// Read status.md - WU-1301: Use config-based paths
|
|
210
|
+
const statusPath = join(process.cwd(), WU_PATHS.STATUS());
|
|
208
211
|
if (!existsSync(statusPath)) {
|
|
209
212
|
console.error(`${LOG_PREFIX} Error: ${statusPath} not found`);
|
|
210
213
|
process.exit(EXIT_CODES.ERROR);
|
package/dist/spawn-list.js
CHANGED
|
@@ -15,7 +15,8 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { createWUParser, WU_OPTIONS } from '@lumenflow/core/dist/arg-parser.js';
|
|
17
17
|
import { die } from '@lumenflow/core/dist/error-handler.js';
|
|
18
|
-
import { PATTERNS, LUMENFLOW_PATHS
|
|
18
|
+
import { PATTERNS, LUMENFLOW_PATHS } from '@lumenflow/core/dist/wu-constants.js';
|
|
19
|
+
import { WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
19
20
|
/** Local EMOJI constants for spawn-list output */
|
|
20
21
|
const EMOJI = {
|
|
21
22
|
WARNING: '⚠️',
|
|
@@ -38,10 +39,10 @@ const SPAWN_LIST_OPTIONS = {
|
|
|
38
39
|
import { buildSpawnTree, formatSpawnTree, getSpawnsByWU, getSpawnsByInitiative, treeToJSON, STATUS_INDICATORS, } from '@lumenflow/core/dist/spawn-tree.js';
|
|
39
40
|
import { SpawnStatus } from '@lumenflow/core/dist/spawn-registry-schema.js';
|
|
40
41
|
const LOG_PREFIX = '[spawn:list]';
|
|
41
|
-
/** Default paths for spawn registry and WU files */
|
|
42
|
+
/** Default paths for spawn registry and WU files (WU-1301: uses config-based paths) */
|
|
42
43
|
const DEFAULT_PATHS = Object.freeze({
|
|
43
44
|
REGISTRY_DIR: LUMENFLOW_PATHS.STATE_DIR,
|
|
44
|
-
WU_DIR:
|
|
45
|
+
WU_DIR: WU_PATHS.WU_DIR(),
|
|
45
46
|
});
|
|
46
47
|
/** Initiative ID pattern */
|
|
47
48
|
const INIT_PATTERN = /^INIT-\d+$/;
|
package/dist/state-bootstrap.js
CHANGED
|
@@ -15,18 +15,20 @@ import { readdirSync, existsSync, writeFileSync, mkdirSync } from 'node:fs';
|
|
|
15
15
|
import path from 'node:path';
|
|
16
16
|
import { parse as parseYaml } from 'yaml';
|
|
17
17
|
import { readFileSync } from 'node:fs';
|
|
18
|
+
import { WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
18
19
|
import { CLI_FLAGS, EXIT_CODES, EMOJI, STRING_LITERALS, } from '@lumenflow/core/dist/wu-constants.js';
|
|
19
20
|
/* eslint-disable security/detect-non-literal-fs-filename */
|
|
20
21
|
/** Log prefix for consistent output */
|
|
21
22
|
const LOG_PREFIX = '[state-bootstrap]';
|
|
22
23
|
/**
|
|
23
24
|
* Default configuration for state bootstrap
|
|
25
|
+
* WU-1301: Uses config-based paths instead of hardcoded values
|
|
24
26
|
*/
|
|
25
27
|
export const STATE_BOOTSTRAP_DEFAULTS = {
|
|
26
|
-
/** Default WU directory path */
|
|
27
|
-
wuDir:
|
|
28
|
-
/** Default state directory path */
|
|
29
|
-
stateDir:
|
|
28
|
+
/** Default WU directory path (from config) */
|
|
29
|
+
wuDir: WU_PATHS.WU_DIR(),
|
|
30
|
+
/** Default state directory path (from config) */
|
|
31
|
+
stateDir: WU_PATHS.STATE_DIR(),
|
|
30
32
|
};
|
|
31
33
|
/**
|
|
32
34
|
* Parse command line arguments for state-bootstrap
|
package/dist/state-doctor-fix.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
import fs from 'node:fs/promises';
|
|
15
15
|
import path from 'node:path';
|
|
16
16
|
import { withMicroWorktree } from '@lumenflow/core/dist/micro-worktree.js';
|
|
17
|
+
import { WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
17
18
|
/**
|
|
18
19
|
* Operation name for micro-worktree isolation
|
|
19
20
|
*/
|
|
@@ -31,13 +32,13 @@ const SIGNALS_FILE = '.lumenflow/memory/signals.jsonl';
|
|
|
31
32
|
*/
|
|
32
33
|
const WU_EVENTS_FILE = '.lumenflow/state/wu-events.jsonl';
|
|
33
34
|
/**
|
|
34
|
-
* Backlog file path (
|
|
35
|
+
* Backlog file path (WU-1301: uses config-based paths)
|
|
35
36
|
*/
|
|
36
|
-
const BACKLOG_FILE =
|
|
37
|
+
const BACKLOG_FILE = WU_PATHS.BACKLOG();
|
|
37
38
|
/**
|
|
38
|
-
* Status file path (
|
|
39
|
+
* Status file path (WU-1301: uses config-based paths)
|
|
39
40
|
*/
|
|
40
|
-
const STATUS_FILE =
|
|
41
|
+
const STATUS_FILE = WU_PATHS.STATUS();
|
|
41
42
|
/**
|
|
42
43
|
* Remove lines containing a WU reference from markdown content
|
|
43
44
|
*
|
package/dist/state-doctor.js
CHANGED
|
@@ -32,7 +32,8 @@ import { parse as parseYaml } from 'yaml';
|
|
|
32
32
|
import { diagnoseState, ISSUE_TYPES, ISSUE_SEVERITY, } from '@lumenflow/core/dist/state-doctor-core.js';
|
|
33
33
|
import { createWUParser } from '@lumenflow/core/dist/arg-parser.js';
|
|
34
34
|
import { EXIT_CODES, LUMENFLOW_PATHS } from '@lumenflow/core/dist/wu-constants.js';
|
|
35
|
-
import { getConfig } from '@lumenflow/core/dist/lumenflow-config.js';
|
|
35
|
+
import { getConfig, getResolvedPaths } from '@lumenflow/core/dist/lumenflow-config.js';
|
|
36
|
+
import { existsSync } from 'node:fs';
|
|
36
37
|
import { createStamp } from '@lumenflow/core/dist/stamp-utils.js';
|
|
37
38
|
import { createStateDoctorFixDeps } from './state-doctor-fix.js';
|
|
38
39
|
/**
|
|
@@ -170,10 +171,11 @@ async function createDeps(baseDir) {
|
|
|
170
171
|
},
|
|
171
172
|
/**
|
|
172
173
|
* List all stamp file IDs
|
|
174
|
+
* WU-1301: Use config-based paths instead of LUMENFLOW_PATHS
|
|
173
175
|
*/
|
|
174
176
|
listStamps: async () => {
|
|
175
177
|
try {
|
|
176
|
-
const stampsDir = path.join(baseDir,
|
|
178
|
+
const stampsDir = path.join(baseDir, config.beacon.stampsDir);
|
|
177
179
|
const stampFiles = await fg('WU-*.done', { cwd: stampsDir });
|
|
178
180
|
return stampFiles.map((file) => file.replace('.done', ''));
|
|
179
181
|
}
|
|
@@ -438,6 +440,32 @@ function buildAuditOutput(result) {
|
|
|
438
440
|
dryRun: result.dryRun,
|
|
439
441
|
};
|
|
440
442
|
}
|
|
443
|
+
/**
|
|
444
|
+
* WU-1301: Warn if configured paths don't exist
|
|
445
|
+
* This helps consumers detect misconfiguration early.
|
|
446
|
+
*/
|
|
447
|
+
function warnMissingPaths(baseDir, quiet) {
|
|
448
|
+
if (quiet)
|
|
449
|
+
return;
|
|
450
|
+
const paths = getResolvedPaths({ projectRoot: baseDir });
|
|
451
|
+
const missing = [];
|
|
452
|
+
if (!existsSync(paths.wuDir)) {
|
|
453
|
+
missing.push(`WU directory: ${paths.wuDir}`);
|
|
454
|
+
}
|
|
455
|
+
if (!existsSync(paths.stampsDir)) {
|
|
456
|
+
missing.push(`Stamps directory: ${paths.stampsDir}`);
|
|
457
|
+
}
|
|
458
|
+
if (!existsSync(paths.stateDir)) {
|
|
459
|
+
missing.push(`State directory: ${paths.stateDir}`);
|
|
460
|
+
}
|
|
461
|
+
if (missing.length > 0) {
|
|
462
|
+
console.warn(`${LOG_PREFIX} ${EMOJI.WARNING} Configured paths not found:`);
|
|
463
|
+
for (const p of missing) {
|
|
464
|
+
console.warn(` - ${p}`);
|
|
465
|
+
}
|
|
466
|
+
console.warn(' Tip: Run `pnpm setup` or check .lumenflow.config.yaml');
|
|
467
|
+
}
|
|
468
|
+
}
|
|
441
469
|
/**
|
|
442
470
|
* Main CLI entry point
|
|
443
471
|
*/
|
|
@@ -446,6 +474,8 @@ async function main() {
|
|
|
446
474
|
const baseDir = args.baseDir || process.cwd();
|
|
447
475
|
const startedAt = new Date().toISOString();
|
|
448
476
|
const startTime = Date.now();
|
|
477
|
+
// WU-1301: Warn about missing configured paths
|
|
478
|
+
warnMissingPaths(baseDir, args.quiet ?? false);
|
|
449
479
|
let result = null;
|
|
450
480
|
let error = null;
|
|
451
481
|
try {
|
package/dist/trace-gen.js
CHANGED
|
@@ -17,7 +17,8 @@ import { readFileSync, writeFileSync, existsSync, readdirSync } from 'node:fs';
|
|
|
17
17
|
import { join } from 'node:path';
|
|
18
18
|
import { execSync } from 'node:child_process';
|
|
19
19
|
import { parse as parseYaml } from 'yaml';
|
|
20
|
-
import { EXIT_CODES,
|
|
20
|
+
import { EXIT_CODES, FILE_SYSTEM } from '@lumenflow/core/dist/wu-constants.js';
|
|
21
|
+
import { WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
21
22
|
import { runCLI } from './cli-entry-point.js';
|
|
22
23
|
/** Log prefix for console output */
|
|
23
24
|
const LOG_PREFIX = '[trace:gen]';
|
|
@@ -131,7 +132,8 @@ function getWuFiles(wuId) {
|
|
|
131
132
|
* Get WU info from YAML file
|
|
132
133
|
*/
|
|
133
134
|
function getWuInfo(wuId) {
|
|
134
|
-
|
|
135
|
+
// WU-1301: Use config-based paths
|
|
136
|
+
const yamlPath = join(process.cwd(), WU_PATHS.WU(wuId));
|
|
135
137
|
if (!existsSync(yamlPath)) {
|
|
136
138
|
return null;
|
|
137
139
|
}
|
|
@@ -268,7 +270,8 @@ async function main() {
|
|
|
268
270
|
else {
|
|
269
271
|
// Trace all WUs
|
|
270
272
|
console.error(`${LOG_PREFIX} Scanning all WUs...`);
|
|
271
|
-
|
|
273
|
+
// WU-1301: Use config-based paths
|
|
274
|
+
const wuDir = join(process.cwd(), WU_PATHS.WU_DIR());
|
|
272
275
|
if (!existsSync(wuDir)) {
|
|
273
276
|
console.error(`${LOG_PREFIX} Error: WU directory not found`);
|
|
274
277
|
process.exit(EXIT_CODES.ERROR);
|
package/dist/wu-block.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 Block Helper
|
|
4
5
|
*
|
|
@@ -32,6 +33,8 @@ import { withMicroWorktree } from '@lumenflow/core/dist/micro-worktree.js';
|
|
|
32
33
|
import { WUStateStore } from '@lumenflow/core/dist/wu-state-store.js';
|
|
33
34
|
// WU-1603: Atomic lane locking - release lock when WU is blocked
|
|
34
35
|
import { releaseLaneLock } from '@lumenflow/core/dist/lane-lock.js';
|
|
36
|
+
// WU-1325: Import lock policy getter to determine release behavior
|
|
37
|
+
import { getLockPolicyForLane } from '@lumenflow/core/dist/lane-checker.js';
|
|
35
38
|
// ensureOnMain() moved to wu-helpers.ts (WU-1256)
|
|
36
39
|
// ensureStaged() moved to git-staged-validator.ts (WU-1341)
|
|
37
40
|
// defaultWorktreeFrom() moved to wu-paths.ts (WU-1341)
|
|
@@ -215,15 +218,23 @@ async function main() {
|
|
|
215
218
|
await getGitForCwd().push(REMOTES.ORIGIN, BRANCHES.MAIN);
|
|
216
219
|
}
|
|
217
220
|
await handleWorktreeRemoval(args, doc);
|
|
218
|
-
// WU-
|
|
219
|
-
//
|
|
221
|
+
// WU-1325: Release lane lock when WU is blocked (only for lock_policy=active)
|
|
222
|
+
// For policy=all, lock is held through block/unblock cycle
|
|
223
|
+
// For policy=none, no lock exists to release
|
|
220
224
|
try {
|
|
221
225
|
const lane = doc.lane;
|
|
222
226
|
if (lane) {
|
|
223
|
-
const
|
|
224
|
-
if (
|
|
225
|
-
|
|
227
|
+
const lockPolicy = getLockPolicyForLane(lane);
|
|
228
|
+
if (lockPolicy === 'active') {
|
|
229
|
+
const releaseResult = releaseLaneLock(lane, { wuId: id });
|
|
230
|
+
if (releaseResult.released && !releaseResult.notFound) {
|
|
231
|
+
console.log(`${LOG_PREFIX.BLOCK} Lane lock released for "${lane}" (lock_policy=active)`);
|
|
232
|
+
}
|
|
226
233
|
}
|
|
234
|
+
else if (lockPolicy === 'all') {
|
|
235
|
+
console.log(`${LOG_PREFIX.BLOCK} Lane lock retained for "${lane}" (lock_policy=all)`);
|
|
236
|
+
}
|
|
237
|
+
// For policy=none, no lock exists - nothing to do
|
|
227
238
|
}
|
|
228
239
|
}
|
|
229
240
|
catch (err) {
|
package/dist/wu-claim.js
CHANGED
|
@@ -67,9 +67,13 @@ async function ensureCleanOrClaimOnlyWhenNoAuto() {
|
|
|
67
67
|
.split(STRING_LITERALS.NEWLINE)
|
|
68
68
|
.filter(Boolean)
|
|
69
69
|
.filter((l) => l.startsWith('A ') || l.startsWith('M ') || l.startsWith('R '));
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
// WU-1311: Use config-based paths instead of hardcoded docs/04-operations paths
|
|
71
|
+
const config = getConfig();
|
|
72
|
+
const wuDirPattern = config.directories.wuDir.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
73
|
+
const wuYamlRegex = new RegExp(`${wuDirPattern}/WU-\\d+\\.yaml`);
|
|
74
|
+
const hasClaimFiles = staged.some((l) => l.includes(config.directories.statusPath) ||
|
|
75
|
+
l.includes(config.directories.backlogPath) ||
|
|
76
|
+
wuYamlRegex.test(l));
|
|
73
77
|
if (!hasClaimFiles) {
|
|
74
78
|
console.error(status);
|
|
75
79
|
die('Stage claim-related files (status/backlog/WU YAML) before running with --no-auto.');
|
|
@@ -400,12 +404,12 @@ async function appendClaimEventOnly(stateDir, id, title, lane) {
|
|
|
400
404
|
* @returns {string[]} List of files to commit
|
|
401
405
|
*/
|
|
402
406
|
export function getWorktreeCommitFiles(wuId) {
|
|
407
|
+
// WU-1311: Use config-based paths instead of hardcoded docs/04-operations paths
|
|
408
|
+
const config = getConfig();
|
|
403
409
|
return [
|
|
404
|
-
|
|
410
|
+
`${config.directories.wuDir}/${wuId}.yaml`,
|
|
405
411
|
LUMENFLOW_PATHS.WU_EVENTS, // WU-1740: Event store is source of truth
|
|
406
|
-
// WU-1746: Explicitly NOT including
|
|
407
|
-
// - docs/04-operations/tasks/backlog.md
|
|
408
|
-
// - docs/04-operations/tasks/status.md
|
|
412
|
+
// WU-1746: Explicitly NOT including backlog.md and status.md
|
|
409
413
|
// These generated files cause merge conflicts when main advances
|
|
410
414
|
];
|
|
411
415
|
}
|
|
@@ -694,7 +698,8 @@ function handleLaneOccupancy(laneCheck, lane, id, force) {
|
|
|
694
698
|
` 2. Choose a different lane\n` +
|
|
695
699
|
` 3. Increase wip_limit in .lumenflow.config.yaml\n` +
|
|
696
700
|
` 4. Use --force to override (P0 emergencies only)\n\n` +
|
|
697
|
-
|
|
701
|
+
// WU-1311: Use config-based status path
|
|
702
|
+
`To check lane status: grep "${STATUS_SECTIONS.IN_PROGRESS}" ${getConfig().directories.statusPath}`);
|
|
698
703
|
}
|
|
699
704
|
/**
|
|
700
705
|
* Handle code path overlap detection (WU-901)
|
|
@@ -726,13 +731,14 @@ function handleCodePathOverlap(WU_PATH, STATUS_PATH, id, args) {
|
|
|
726
731
|
return ` - ${c.wuid}: ${displayedOverlaps}${suffix}`;
|
|
727
732
|
})
|
|
728
733
|
.join(STRING_LITERALS.NEWLINE);
|
|
734
|
+
// WU-1311: Use config-based status path in error message
|
|
729
735
|
die(`Code path overlap detected with in-progress WUs:\n\n${conflictList}\n\n` +
|
|
730
736
|
`Merge conflicts are guaranteed if both WUs proceed.\n\n` +
|
|
731
737
|
`Options:\n` +
|
|
732
738
|
` 1. Wait for conflicting WU(s) to complete\n` +
|
|
733
739
|
` 2. Coordinate with agent working on conflicting WU\n` +
|
|
734
740
|
` 3. Use --force-overlap --reason "..." (emits telemetry for audit)\n\n` +
|
|
735
|
-
`To check WU status: grep "${STATUS_SECTIONS.IN_PROGRESS}"
|
|
741
|
+
`To check WU status: grep "${STATUS_SECTIONS.IN_PROGRESS}" ${getConfig().directories.statusPath}`);
|
|
736
742
|
}
|
|
737
743
|
if (args.forceOverlap) {
|
|
738
744
|
if (!args.reason) {
|
package/dist/wu-create.js
CHANGED
|
@@ -41,6 +41,7 @@ import { inferSubLane } from '@lumenflow/core/dist/lane-inference.js';
|
|
|
41
41
|
import { parseBacklogFrontmatter } from '@lumenflow/core/dist/backlog-parser.js';
|
|
42
42
|
import { createWUParser, WU_CREATE_OPTIONS, WU_OPTIONS } from '@lumenflow/core/dist/arg-parser.js';
|
|
43
43
|
import { WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
44
|
+
import { getConfig } from '@lumenflow/core/dist/lumenflow-config.js';
|
|
44
45
|
import { validateWU } from '@lumenflow/core/dist/wu-schema.js';
|
|
45
46
|
import { getPlanPath, getPlanProtocolRef, getPlansDir, } from '@lumenflow/core/dist/lumenflow-home.js';
|
|
46
47
|
import { validateSpecRefs } from '@lumenflow/core/dist/wu-create-validators.js';
|
|
@@ -57,6 +58,8 @@ import { validateSpecCompleteness } from '@lumenflow/core/dist/wu-done-validator
|
|
|
57
58
|
import { readWU } from '@lumenflow/core/dist/wu-yaml.js';
|
|
58
59
|
// WU-2253: Import WU spec linter for acceptance/code_paths validation
|
|
59
60
|
import { lintWUSpec, formatLintErrors } from '@lumenflow/core/dist/wu-lint.js';
|
|
61
|
+
// WU-1329: Import path existence validators for strict mode
|
|
62
|
+
import { validateCodePathsExistence, validateTestPathsExistence, } from '@lumenflow/core/dist/wu-preflight-validators.js';
|
|
60
63
|
// WU-1025: Import placeholder validator for inline content validation
|
|
61
64
|
import { validateNoPlaceholders, buildPlaceholderErrorMessage, } from '@lumenflow/core/dist/wu-validator.js';
|
|
62
65
|
// WU-1211: Import initiative validation for phase check
|
|
@@ -247,9 +250,24 @@ function buildWUContent({ id, lane, title, priority, type, created, opts, }) {
|
|
|
247
250
|
...(specRefs?.length && { spec_refs: specRefs }),
|
|
248
251
|
};
|
|
249
252
|
}
|
|
253
|
+
/**
|
|
254
|
+
* Validate WU spec for creation
|
|
255
|
+
*
|
|
256
|
+
* WU-1329: Strict mode (default) validates that code_paths and test_paths exist on disk.
|
|
257
|
+
* Use opts.strict = false to bypass path existence checks.
|
|
258
|
+
*
|
|
259
|
+
* @param params - Validation parameters
|
|
260
|
+
* @returns {{ valid: boolean, errors: string[] }}
|
|
261
|
+
*/
|
|
250
262
|
export function validateCreateSpec({ id, lane, title, priority, type, opts, }) {
|
|
251
263
|
const errors = [];
|
|
252
264
|
const effectiveType = type || DEFAULT_TYPE;
|
|
265
|
+
// WU-1329: Strict mode is the default
|
|
266
|
+
const strict = opts.strict !== false;
|
|
267
|
+
// WU-1329: Log when strict validation is bypassed
|
|
268
|
+
if (!strict) {
|
|
269
|
+
console.warn(`${LOG_PREFIX} WARNING: strict validation bypassed (--no-strict). Path existence checks skipped.`);
|
|
270
|
+
}
|
|
253
271
|
if (!opts.description) {
|
|
254
272
|
errors.push('--description is required');
|
|
255
273
|
}
|
|
@@ -269,7 +287,9 @@ export function validateCreateSpec({ id, lane, title, priority, type, opts, }) {
|
|
|
269
287
|
}
|
|
270
288
|
}
|
|
271
289
|
if (effectiveType === 'feature' && !opts.specRefs) {
|
|
272
|
-
errors.push('--spec-refs is required for type: feature WUs'
|
|
290
|
+
errors.push('--spec-refs is required for type: feature WUs\n' +
|
|
291
|
+
' Tip: Create a plan first with: pnpm plan:create --id <WU-ID> --title "..."\n' +
|
|
292
|
+
' Then use --plan flag or --spec-refs lumenflow://plans/<WU-ID>-plan.md');
|
|
273
293
|
}
|
|
274
294
|
if (errors.length > 0) {
|
|
275
295
|
return { valid: false, errors };
|
|
@@ -303,6 +323,29 @@ export function validateCreateSpec({ id, lane, title, priority, type, opts, }) {
|
|
|
303
323
|
if (!completeness.valid) {
|
|
304
324
|
return { valid: false, errors: completeness.errors };
|
|
305
325
|
}
|
|
326
|
+
// WU-1329: Strict mode validates path existence
|
|
327
|
+
if (strict) {
|
|
328
|
+
const rootDir = process.cwd();
|
|
329
|
+
// Validate code_paths exist
|
|
330
|
+
if (opts.codePaths && opts.codePaths.length > 0) {
|
|
331
|
+
const codePathsResult = validateCodePathsExistence(opts.codePaths, rootDir);
|
|
332
|
+
if (!codePathsResult.valid) {
|
|
333
|
+
errors.push(...codePathsResult.errors);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
// Validate test_paths exist (unit, e2e - not manual)
|
|
337
|
+
const testsObj = {
|
|
338
|
+
unit: opts.testPathsUnit || [],
|
|
339
|
+
e2e: opts.testPathsE2e || [],
|
|
340
|
+
};
|
|
341
|
+
const testPathsResult = validateTestPathsExistence(testsObj, rootDir);
|
|
342
|
+
if (!testPathsResult.valid) {
|
|
343
|
+
errors.push(...testPathsResult.errors);
|
|
344
|
+
}
|
|
345
|
+
if (errors.length > 0) {
|
|
346
|
+
return { valid: false, errors };
|
|
347
|
+
}
|
|
348
|
+
}
|
|
306
349
|
return { valid: true, errors: [] };
|
|
307
350
|
}
|
|
308
351
|
/**
|
|
@@ -382,9 +425,10 @@ function updateBacklogInWorktree(worktreePath, id, lane, title) {
|
|
|
382
425
|
const backlogRelativePath = WU_PATHS.BACKLOG();
|
|
383
426
|
const backlogAbsolutePath = join(worktreePath, backlogRelativePath);
|
|
384
427
|
if (!existsSync(backlogAbsolutePath)) {
|
|
428
|
+
// WU-1311: Use config-based backlog path in error message
|
|
385
429
|
die(`Backlog not found in micro-worktree: ${backlogAbsolutePath}\n\n` +
|
|
386
430
|
`Options:\n` +
|
|
387
|
-
` 1. Ensure backlog.md exists at
|
|
431
|
+
` 1. Ensure backlog.md exists at ${getConfig().directories.backlogPath}\n` +
|
|
388
432
|
` 2. Run from repository root directory`);
|
|
389
433
|
}
|
|
390
434
|
const { frontmatter, markdown } = parseBacklogFrontmatter(backlogAbsolutePath);
|
|
@@ -482,6 +526,8 @@ async function main() {
|
|
|
482
526
|
WU_OPTIONS.uiPairingWus,
|
|
483
527
|
// WU-1062: External plan options for wu:create
|
|
484
528
|
WU_CREATE_OPTIONS.plan,
|
|
529
|
+
// WU-1329: Strict validation is default, --no-strict bypasses
|
|
530
|
+
WU_OPTIONS.noStrict,
|
|
485
531
|
],
|
|
486
532
|
required: ['lane', 'title'], // WU-1246: --id is now optional (auto-generated if not provided)
|
|
487
533
|
allowPositionalId: false,
|
|
@@ -558,6 +604,8 @@ async function main() {
|
|
|
558
604
|
blocks: args.blocks,
|
|
559
605
|
labels: args.labels,
|
|
560
606
|
assignedTo,
|
|
607
|
+
// WU-1329: Strict validation is default, --no-strict bypasses
|
|
608
|
+
strict: !args.noStrict,
|
|
561
609
|
},
|
|
562
610
|
});
|
|
563
611
|
if (!createSpecValidation.valid) {
|
package/dist/wu-deps.js
CHANGED
|
@@ -15,6 +15,7 @@ import { die } from '@lumenflow/core/dist/error-handler.js';
|
|
|
15
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
|
+
import { getConfig } from '@lumenflow/core/dist/lumenflow-config.js';
|
|
18
19
|
async function main() {
|
|
19
20
|
const args = createWUParser({
|
|
20
21
|
name: 'wu-deps',
|
|
@@ -33,7 +34,8 @@ async function main() {
|
|
|
33
34
|
console.log(`[wu:deps] Building dependency graph...`);
|
|
34
35
|
const graph = await buildDependencyGraphAsync();
|
|
35
36
|
if (!graph.has(wuId)) {
|
|
36
|
-
|
|
37
|
+
// WU-1311: Use config-based WU directory path
|
|
38
|
+
die(`WU not found in graph: ${wuId}\n\nEnsure the WU exists in ${getConfig().directories.wuDir}/`);
|
|
37
39
|
}
|
|
38
40
|
const format = args.format || OUTPUT_FORMATS.ASCII;
|
|
39
41
|
const depth = args.depth ? parseInt(args.depth, 10) : 3;
|
package/dist/wu-done.js
CHANGED
|
@@ -65,6 +65,7 @@ CONTEXT_VALIDATION, } from '@lumenflow/core/dist/wu-constants.js';
|
|
|
65
65
|
import { printGateFailureBox, printStatusPreview } from '@lumenflow/core/dist/wu-done-ui.js';
|
|
66
66
|
import { ensureOnMain } from '@lumenflow/core/dist/wu-helpers.js';
|
|
67
67
|
import { WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
68
|
+
import { getConfig } from '@lumenflow/core/dist/lumenflow-config.js';
|
|
68
69
|
import { writeWU, appendNote, parseYAML } from '@lumenflow/core/dist/wu-yaml.js';
|
|
69
70
|
import { PLACEHOLDER_SENTINEL, validateWU, validateDoneWU, validateApprovalGates, } from '@lumenflow/core/dist/wu-schema.js';
|
|
70
71
|
import { validateBacklogSync } from '@lumenflow/core/dist/backlog-sync-validator.js';
|
|
@@ -969,11 +970,14 @@ async function runGatesInWorktree(worktreePath, id, options = {}) {
|
|
|
969
970
|
}
|
|
970
971
|
async function validateStagedFiles(id, isDocsOnly = false) {
|
|
971
972
|
const staged = await listStaged();
|
|
973
|
+
// WU-1311: Use config-based paths instead of hardcoded docs/04-operations paths
|
|
974
|
+
const config = getConfig();
|
|
975
|
+
const wuPath = `${config.directories.wuDir}/${id}.yaml`;
|
|
972
976
|
// WU-1740: Include wu-events.jsonl to persist state store events
|
|
973
977
|
const whitelist = [
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
978
|
+
wuPath,
|
|
979
|
+
config.directories.statusPath,
|
|
980
|
+
config.directories.backlogPath,
|
|
977
981
|
WU_EVENTS_PATH,
|
|
978
982
|
];
|
|
979
983
|
if (isDocsOnly) {
|
|
@@ -998,7 +1002,10 @@ async function validateStagedFiles(id, isDocsOnly = false) {
|
|
|
998
1002
|
return true;
|
|
999
1003
|
});
|
|
1000
1004
|
if (unexpected.length > 0) {
|
|
1001
|
-
|
|
1005
|
+
// WU-1311: Use config-based pattern for WU YAML detection
|
|
1006
|
+
const wuDirPattern = config.directories.wuDir.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
1007
|
+
const wuYamlRegex = new RegExp(`^${wuDirPattern}/WU-\\d+\\.yaml$`);
|
|
1008
|
+
const otherWuYamlOnly = unexpected.every((f) => wuYamlRegex.test(f));
|
|
1002
1009
|
if (otherWuYamlOnly) {
|
|
1003
1010
|
console.warn(`${LOG_PREFIX.DONE} Warning: other WU YAMLs are staged; proceeding and committing only current WU files.`);
|
|
1004
1011
|
}
|
|
@@ -1620,8 +1627,10 @@ async function executePreFlightChecks({ id, args, isBranchOnly, isDocsOnly, docM
|
|
|
1620
1627
|
if (!specResult.valid) {
|
|
1621
1628
|
console.error(`\n❌ Spec completeness validation failed for ${id}:\n`);
|
|
1622
1629
|
specResult.errors.forEach((err) => console.error(` - ${err}`));
|
|
1630
|
+
// WU-1311: Use config-based path in error message
|
|
1631
|
+
const specConfig = getConfig();
|
|
1623
1632
|
console.error(`\nFix these issues before running wu:done:\n` +
|
|
1624
|
-
` 1. Update
|
|
1633
|
+
` 1. Update ${specConfig.directories.wuDir}/${id}.yaml\n` +
|
|
1625
1634
|
` 2. Fill description with Context/Problem/Solution\n` +
|
|
1626
1635
|
` 3. Replace ${PLACEHOLDER_SENTINEL} text with specific criteria\n` +
|
|
1627
1636
|
` 4. List all modified files in code_paths\n` +
|
package/dist/wu-edit.js
CHANGED
|
@@ -57,6 +57,8 @@ import { readInitiative, writeInitiative } from '@lumenflow/initiatives/dist/ini
|
|
|
57
57
|
import { normalizeWUSchema } from '@lumenflow/core/dist/wu-schema-normalization.js';
|
|
58
58
|
// WU-2253: Import WU spec linter for acceptance/code_paths validation
|
|
59
59
|
import { lintWUSpec, formatLintErrors } from '@lumenflow/core/dist/wu-lint.js';
|
|
60
|
+
// WU-1329: Import path existence validators for strict validation
|
|
61
|
+
import { validateCodePathsExistence, validateTestPathsExistence, } from '@lumenflow/core/dist/wu-preflight-validators.js';
|
|
60
62
|
/* eslint-disable security/detect-object-injection */
|
|
61
63
|
const PREFIX = LOG_PREFIX.EDIT;
|
|
62
64
|
/**
|
|
@@ -377,6 +379,8 @@ function parseArgs() {
|
|
|
377
379
|
EDIT_OPTIONS.replaceDependencies,
|
|
378
380
|
// WU-1039: Add exposure for done WU metadata updates
|
|
379
381
|
WU_OPTIONS.exposure,
|
|
382
|
+
// WU-1329: Strict validation is default, --no-strict bypasses
|
|
383
|
+
WU_OPTIONS.noStrict,
|
|
380
384
|
],
|
|
381
385
|
required: ['id'],
|
|
382
386
|
allowPositionalId: true,
|
|
@@ -921,6 +925,37 @@ async function main() {
|
|
|
921
925
|
// WU-1750: CRITICAL - Use transformed data for all subsequent operations
|
|
922
926
|
// This ensures embedded newlines are normalized before YAML output
|
|
923
927
|
const normalizedWU = validationResult.data;
|
|
928
|
+
// WU-1329: Strict validation of path existence (default behavior)
|
|
929
|
+
// --no-strict bypasses these checks
|
|
930
|
+
const strict = !opts.noStrict;
|
|
931
|
+
if (!strict) {
|
|
932
|
+
console.warn(`${PREFIX} WARNING: strict validation bypassed (--no-strict). Path existence checks skipped.`);
|
|
933
|
+
}
|
|
934
|
+
if (strict) {
|
|
935
|
+
const rootDir = process.cwd();
|
|
936
|
+
const strictErrors = [];
|
|
937
|
+
// Validate code_paths exist
|
|
938
|
+
if (normalizedWU.code_paths && normalizedWU.code_paths.length > 0) {
|
|
939
|
+
const codePathsResult = validateCodePathsExistence(normalizedWU.code_paths, rootDir);
|
|
940
|
+
if (!codePathsResult.valid) {
|
|
941
|
+
strictErrors.push(...codePathsResult.errors);
|
|
942
|
+
}
|
|
943
|
+
}
|
|
944
|
+
// Validate test_paths exist (unit, e2e - not manual)
|
|
945
|
+
if (normalizedWU.tests) {
|
|
946
|
+
const testPathsResult = validateTestPathsExistence(normalizedWU.tests, rootDir);
|
|
947
|
+
if (!testPathsResult.valid) {
|
|
948
|
+
strictErrors.push(...testPathsResult.errors);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
if (strictErrors.length > 0) {
|
|
952
|
+
const errorList = strictErrors.map((e) => ` • ${e}`).join('\n');
|
|
953
|
+
die(`${PREFIX} ❌ Strict validation failed:\n\n${errorList}\n\n` +
|
|
954
|
+
`Options:\n` +
|
|
955
|
+
` 1. Fix the paths in the WU spec to match actual files\n` +
|
|
956
|
+
` 2. Use --no-strict to bypass path existence checks (not recommended)`);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
924
959
|
// Validate lane format if present (WU-923: block parent-only lanes with taxonomy)
|
|
925
960
|
if (normalizedWU.lane) {
|
|
926
961
|
validateLaneFormat(normalizedWU.lane);
|
package/dist/wu-infer-lane.js
CHANGED
|
@@ -20,6 +20,7 @@ import { parseYAML } from '@lumenflow/core/dist/wu-yaml.js';
|
|
|
20
20
|
import { inferSubLane } from '@lumenflow/core/dist/lane-inference.js';
|
|
21
21
|
import { die } from '@lumenflow/core/dist/error-handler.js';
|
|
22
22
|
import { FILE_SYSTEM, EXIT_CODES } from '@lumenflow/core/dist/wu-constants.js';
|
|
23
|
+
import { WU_PATHS } from '@lumenflow/core/dist/wu-paths.js';
|
|
23
24
|
function parseArgs(argv) {
|
|
24
25
|
const args = { paths: [], desc: '', id: null };
|
|
25
26
|
for (let i = 2; i < argv.length; i++) {
|
|
@@ -62,7 +63,8 @@ Options:
|
|
|
62
63
|
return args;
|
|
63
64
|
}
|
|
64
65
|
function loadWuYaml(id) {
|
|
65
|
-
|
|
66
|
+
// WU-1301: Use config-based paths instead of hardcoded path
|
|
67
|
+
const wuPath = path.join(process.cwd(), WU_PATHS.WU(id));
|
|
66
68
|
if (!existsSync(wuPath)) {
|
|
67
69
|
die(`WU file not found: ${wuPath}\n\n` +
|
|
68
70
|
`Options:\n` +
|
package/dist/wu-spawn.js
CHANGED
|
@@ -36,7 +36,9 @@ import { parseYAML } from '@lumenflow/core/dist/wu-yaml.js';
|
|
|
36
36
|
import { die } from '@lumenflow/core/dist/error-handler.js';
|
|
37
37
|
import { WU_STATUS, PATTERNS, FILE_SYSTEM, EMOJI } from '@lumenflow/core/dist/wu-constants.js';
|
|
38
38
|
// WU-1603: Check lane lock status before spawning
|
|
39
|
+
// WU-1325: Import lock policy getter for lane availability check
|
|
39
40
|
import { checkLaneLock } from '@lumenflow/core/dist/lane-lock.js';
|
|
41
|
+
import { getLockPolicyForLane } from '@lumenflow/core/dist/lane-checker.js';
|
|
40
42
|
import { minimatch } from 'minimatch';
|
|
41
43
|
// WU-2252: Import invariants loader for spawn output injection
|
|
42
44
|
import { loadInvariants, INVARIANT_TYPES } from '@lumenflow/core/dist/invariants-runner.js';
|
|
@@ -1146,11 +1148,17 @@ ${SPAWN_END_SENTINEL}
|
|
|
1146
1148
|
}
|
|
1147
1149
|
/**
|
|
1148
1150
|
* WU-1603: Check if a lane is currently occupied by another WU
|
|
1151
|
+
* WU-1325: Now considers lock_policy - lanes with policy=none are never occupied
|
|
1149
1152
|
*
|
|
1150
1153
|
* @param {string} lane - Lane name (e.g., "Operations: Tooling")
|
|
1151
1154
|
* @returns {import('@lumenflow/core/dist/lane-lock.js').LockMetadata|null} Lock metadata if occupied, null otherwise
|
|
1152
1155
|
*/
|
|
1153
1156
|
export function checkLaneOccupation(lane) {
|
|
1157
|
+
// WU-1325: Lanes with lock_policy=none never report as occupied
|
|
1158
|
+
const lockPolicy = getLockPolicyForLane(lane);
|
|
1159
|
+
if (lockPolicy === 'none') {
|
|
1160
|
+
return null;
|
|
1161
|
+
}
|
|
1154
1162
|
const lockStatus = checkLaneLock(lane);
|
|
1155
1163
|
if (lockStatus.locked && lockStatus.metadata) {
|
|
1156
1164
|
return lockStatus.metadata;
|