@lumenflow/core 1.3.4 → 1.3.6
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/adapters/filesystem-metrics.adapter.d.ts +1 -1
- package/dist/adapters/filesystem-metrics.adapter.js +1 -1
- package/dist/beacon-migration.d.ts +56 -0
- package/dist/beacon-migration.js +101 -0
- package/dist/cleanup-lock.js +3 -3
- package/dist/commands-logger.d.ts +2 -2
- package/dist/commands-logger.js +5 -5
- package/dist/core/tool-runner.d.ts +1 -1
- package/dist/core/tool-runner.js +2 -2
- package/dist/docs-path-validator.d.ts +2 -2
- package/dist/docs-path-validator.js +4 -4
- package/dist/domain/orchestration.constants.js +3 -3
- package/dist/force-bypass-audit.d.ts +2 -2
- package/dist/force-bypass-audit.js +8 -7
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/lane-lock.d.ts +1 -1
- package/dist/lane-lock.js +3 -4
- package/dist/logs-lib.d.ts +2 -2
- package/dist/logs-lib.js +5 -4
- package/dist/lumenflow-config-schema.d.ts +1 -1
- package/dist/lumenflow-config-schema.js +19 -19
- package/dist/lumenflow-config.js +1 -1
- package/dist/merge-lock.js +7 -7
- package/dist/prompt-linter.js +3 -3
- package/dist/prompt-monitor.d.ts +1 -1
- package/dist/prompt-monitor.js +5 -5
- package/dist/rebase-artifact-cleanup.d.ts +1 -1
- package/dist/rebase-artifact-cleanup.js +1 -1
- package/dist/spawn-recovery.d.ts +2 -2
- package/dist/spawn-recovery.js +6 -6
- package/dist/spawn-registry-store.d.ts +2 -2
- package/dist/spawn-registry-store.js +2 -2
- package/dist/spawn-tree.d.ts +2 -2
- package/dist/spawn-tree.js +2 -2
- package/dist/stamp-utils.d.ts +1 -1
- package/dist/stamp-utils.js +1 -1
- package/dist/state-machine.d.ts +1 -0
- package/dist/state-machine.js +2 -1
- package/dist/telemetry.d.ts +1 -1
- package/dist/telemetry.js +1 -1
- package/dist/wu-checkpoint.js +4 -4
- package/dist/wu-consistency-checker.d.ts +22 -2
- package/dist/wu-consistency-checker.js +260 -30
- package/dist/wu-constants.d.ts +67 -4
- package/dist/wu-constants.js +41 -15
- package/dist/wu-done-branch-only.js +2 -2
- package/dist/wu-done-inputs.js +1 -1
- package/dist/wu-done-validation.js +2 -2
- package/dist/wu-done-worktree.js +4 -4
- package/dist/wu-paths.js +1 -1
- package/dist/wu-recovery.d.ts +4 -4
- package/dist/wu-recovery.js +8 -8
- package/dist/wu-repair-core.js +4 -4
- package/dist/wu-spawn-helpers.d.ts +1 -1
- package/dist/wu-spawn-helpers.js +3 -2
- package/dist/wu-spawn.js +7 -7
- package/dist/wu-state-schema.d.ts +24 -1
- package/dist/wu-state-schema.js +13 -0
- package/dist/wu-state-store.d.ts +23 -2
- package/dist/wu-state-store.js +56 -2
- package/package.json +3 -3
- package/dist/spec-branch-helpers.d.ts +0 -118
- package/dist/spec-branch-helpers.js +0 -199
|
@@ -13,13 +13,14 @@
|
|
|
13
13
|
* @see {@link ../wu-repair.mjs} CLI interface
|
|
14
14
|
*/
|
|
15
15
|
import { readFile, writeFile, readdir, mkdir, access } from 'node:fs/promises';
|
|
16
|
-
import { constants } from 'node:fs';
|
|
16
|
+
import { constants, existsSync, mkdirSync, writeFileSync, readFileSync } from 'node:fs';
|
|
17
17
|
import path from 'node:path';
|
|
18
18
|
import { parseYAML, stringifyYAML } from './wu-yaml.js';
|
|
19
19
|
import { WU_PATHS } from './wu-paths.js';
|
|
20
20
|
import { CONSISTENCY_TYPES, CONSISTENCY_MESSAGES, LOG_PREFIX, REMOTES, STRING_LITERALS, toKebab, WU_STATUS, YAML_OPTIONS, } from './wu-constants.js';
|
|
21
21
|
import { todayISO } from './date-utils.js';
|
|
22
22
|
import { createGitForPath } from './git-adapter.js';
|
|
23
|
+
import { withMicroWorktree } from './micro-worktree.js';
|
|
23
24
|
/**
|
|
24
25
|
* Check a single WU for state inconsistencies
|
|
25
26
|
*
|
|
@@ -238,7 +239,34 @@ export async function checkLaneForOrphanDoneWU(lane, excludeId, projectRoot = pr
|
|
|
238
239
|
};
|
|
239
240
|
}
|
|
240
241
|
/**
|
|
241
|
-
*
|
|
242
|
+
* Categorize errors into file-based repairs (need micro-worktree) and git-only repairs
|
|
243
|
+
*/
|
|
244
|
+
function categorizeErrors(errors) {
|
|
245
|
+
const fileRepairs = [];
|
|
246
|
+
const gitOnlyRepairs = [];
|
|
247
|
+
const nonRepairable = [];
|
|
248
|
+
for (const error of errors) {
|
|
249
|
+
if (!error.canAutoRepair) {
|
|
250
|
+
nonRepairable.push(error);
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
// Git-only repairs: worktree/branch cleanup doesn't need micro-worktree
|
|
254
|
+
if (error.type === CONSISTENCY_TYPES.ORPHAN_WORKTREE_DONE) {
|
|
255
|
+
gitOnlyRepairs.push(error);
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
// All file-based repairs need micro-worktree isolation
|
|
259
|
+
fileRepairs.push(error);
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return { fileRepairs, gitOnlyRepairs, nonRepairable };
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Repair WU inconsistencies using micro-worktree isolation (WU-1078)
|
|
266
|
+
*
|
|
267
|
+
* All file modifications (stamps, YAML, markdown) are made atomically
|
|
268
|
+
* in a micro-worktree, then committed and pushed to origin/main.
|
|
269
|
+
* This prevents direct writes to the main checkout.
|
|
242
270
|
*
|
|
243
271
|
* @param {object} report - Report from checkWUConsistency()
|
|
244
272
|
* @param {RepairWUInconsistencyOptions} [options={}] - Repair options
|
|
@@ -249,20 +277,72 @@ export async function repairWUInconsistency(report, options = {}) {
|
|
|
249
277
|
if (report.valid) {
|
|
250
278
|
return { repaired: 0, skipped: 0, failed: 0 };
|
|
251
279
|
}
|
|
280
|
+
const { fileRepairs, gitOnlyRepairs, nonRepairable } = categorizeErrors(report.errors);
|
|
252
281
|
let repaired = 0;
|
|
253
|
-
let skipped =
|
|
282
|
+
let skipped = nonRepairable.length;
|
|
254
283
|
let failed = 0;
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
284
|
+
// Dry run mode: just count
|
|
285
|
+
if (dryRun) {
|
|
286
|
+
return {
|
|
287
|
+
repaired: fileRepairs.length + gitOnlyRepairs.length,
|
|
288
|
+
skipped,
|
|
289
|
+
failed: 0,
|
|
290
|
+
};
|
|
291
|
+
}
|
|
292
|
+
// Step 1: Process file-based repairs via micro-worktree (batched)
|
|
293
|
+
if (fileRepairs.length > 0) {
|
|
294
|
+
try {
|
|
295
|
+
// Generate a batch ID from the WU IDs being repaired
|
|
296
|
+
const batchId = `batch-${fileRepairs.map((e) => e.wuId).join('-')}`.slice(0, 50);
|
|
297
|
+
await withMicroWorktree({
|
|
298
|
+
operation: 'wu-repair',
|
|
299
|
+
id: batchId,
|
|
300
|
+
logPrefix: LOG_PREFIX.REPAIR,
|
|
301
|
+
execute: async ({ worktreePath }) => {
|
|
302
|
+
const filesModified = [];
|
|
303
|
+
for (const error of fileRepairs) {
|
|
304
|
+
try {
|
|
305
|
+
const result = await repairSingleErrorInWorktree(error, worktreePath, projectRoot);
|
|
306
|
+
if (result.success && result.files) {
|
|
307
|
+
filesModified.push(...result.files);
|
|
308
|
+
repaired++;
|
|
309
|
+
}
|
|
310
|
+
else if (result.skipped) {
|
|
311
|
+
skipped++;
|
|
312
|
+
if (result.reason) {
|
|
313
|
+
console.warn(`${LOG_PREFIX.REPAIR} Skipped ${error.type}: ${result.reason}`);
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
else {
|
|
317
|
+
failed++;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
catch (err) {
|
|
321
|
+
const errMessage = err instanceof Error ? err.message : String(err);
|
|
322
|
+
console.error(`${LOG_PREFIX.REPAIR} Failed to repair ${error.type}: ${errMessage}`);
|
|
323
|
+
failed++;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
// Deduplicate files
|
|
327
|
+
const uniqueFiles = [...new Set(filesModified)];
|
|
328
|
+
return {
|
|
329
|
+
commitMessage: `fix: repair ${repaired} WU inconsistencies`,
|
|
330
|
+
files: uniqueFiles,
|
|
331
|
+
};
|
|
332
|
+
},
|
|
333
|
+
});
|
|
259
334
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
335
|
+
catch (err) {
|
|
336
|
+
// If micro-worktree fails, mark all file repairs as failed
|
|
337
|
+
const errMessage = err instanceof Error ? err.message : String(err);
|
|
338
|
+
console.error(`${LOG_PREFIX.REPAIR} Micro-worktree operation failed: ${errMessage}`);
|
|
339
|
+
failed += fileRepairs.length - repaired;
|
|
263
340
|
}
|
|
341
|
+
}
|
|
342
|
+
// Step 2: Process git-only repairs (worktree/branch cleanup) directly
|
|
343
|
+
for (const error of gitOnlyRepairs) {
|
|
264
344
|
try {
|
|
265
|
-
const result = await
|
|
345
|
+
const result = await repairGitOnlyError(error, projectRoot);
|
|
266
346
|
if (result.success) {
|
|
267
347
|
repaired++;
|
|
268
348
|
}
|
|
@@ -285,34 +365,85 @@ export async function repairWUInconsistency(report, options = {}) {
|
|
|
285
365
|
return { repaired, skipped, failed };
|
|
286
366
|
}
|
|
287
367
|
/**
|
|
288
|
-
* Repair a single
|
|
368
|
+
* Repair a single file-based error inside a micro-worktree (WU-1078)
|
|
369
|
+
*
|
|
370
|
+
* This function performs file modifications inside the worktree path,
|
|
371
|
+
* which is then committed and pushed atomically by withMicroWorktree.
|
|
372
|
+
*
|
|
373
|
+
* @param {ConsistencyError} error - Error object from checkWUConsistency()
|
|
374
|
+
* @param {string} worktreePath - Path to the micro-worktree
|
|
375
|
+
* @param {string} projectRoot - Original project root (for reading source files)
|
|
376
|
+
* @returns {Promise<RepairResult>} Result with success, skipped, reason, and files modified
|
|
377
|
+
*/
|
|
378
|
+
async function repairSingleErrorInWorktree(error, worktreePath, projectRoot) {
|
|
379
|
+
switch (error.type) {
|
|
380
|
+
case CONSISTENCY_TYPES.YAML_DONE_NO_STAMP: {
|
|
381
|
+
const files = await createStampInWorktree(error.wuId, error.title || `WU ${error.wuId}`, worktreePath);
|
|
382
|
+
return { success: true, files };
|
|
383
|
+
}
|
|
384
|
+
case CONSISTENCY_TYPES.YAML_DONE_STATUS_IN_PROGRESS: {
|
|
385
|
+
const files = await removeWUFromSectionInWorktree(WU_PATHS.STATUS(), error.wuId, '## In Progress', worktreePath, projectRoot);
|
|
386
|
+
return { success: true, files };
|
|
387
|
+
}
|
|
388
|
+
case CONSISTENCY_TYPES.BACKLOG_DUAL_SECTION: {
|
|
389
|
+
const files = await removeWUFromSectionInWorktree(WU_PATHS.BACKLOG(), error.wuId, '## 🔧 In progress', worktreePath, projectRoot);
|
|
390
|
+
return { success: true, files };
|
|
391
|
+
}
|
|
392
|
+
case CONSISTENCY_TYPES.STAMP_EXISTS_YAML_NOT_DONE: {
|
|
393
|
+
const files = await updateYamlToDoneInWorktree(error.wuId, worktreePath, projectRoot);
|
|
394
|
+
return { success: true, files };
|
|
395
|
+
}
|
|
396
|
+
default:
|
|
397
|
+
return { skipped: true, reason: `Unknown error type: ${error.type}` };
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
/**
|
|
401
|
+
* Repair git-only errors (worktree/branch cleanup) without micro-worktree
|
|
402
|
+
*
|
|
403
|
+
* These operations don't modify files in the repo, they only manage git worktrees
|
|
404
|
+
* and branches, so they can run directly.
|
|
289
405
|
*
|
|
290
|
-
* @param {
|
|
406
|
+
* @param {ConsistencyError} error - Error object
|
|
291
407
|
* @param {string} projectRoot - Project root directory
|
|
292
408
|
* @returns {Promise<RepairResult>} Result with success, skipped, and reason
|
|
293
409
|
*/
|
|
294
|
-
async function
|
|
410
|
+
async function repairGitOnlyError(error, projectRoot) {
|
|
295
411
|
switch (error.type) {
|
|
296
|
-
case CONSISTENCY_TYPES.YAML_DONE_NO_STAMP:
|
|
297
|
-
await createStampInProject(error.wuId, error.title || `WU ${error.wuId}`, projectRoot);
|
|
298
|
-
return { success: true };
|
|
299
|
-
case CONSISTENCY_TYPES.YAML_DONE_STATUS_IN_PROGRESS:
|
|
300
|
-
await removeWUFromSection(path.join(projectRoot, WU_PATHS.STATUS()), error.wuId, '## In Progress');
|
|
301
|
-
return { success: true };
|
|
302
|
-
case CONSISTENCY_TYPES.BACKLOG_DUAL_SECTION:
|
|
303
|
-
await removeWUFromSection(path.join(projectRoot, WU_PATHS.BACKLOG()), error.wuId, '## 🔧 In progress');
|
|
304
|
-
return { success: true };
|
|
305
412
|
case CONSISTENCY_TYPES.ORPHAN_WORKTREE_DONE:
|
|
306
413
|
return await removeOrphanWorktree(error.wuId, error.lane, projectRoot);
|
|
307
|
-
case CONSISTENCY_TYPES.STAMP_EXISTS_YAML_NOT_DONE:
|
|
308
|
-
await updateYamlToDone(error.wuId, projectRoot);
|
|
309
|
-
return { success: true };
|
|
310
414
|
default:
|
|
311
|
-
return { skipped: true, reason: `Unknown error type: ${error.type}` };
|
|
415
|
+
return { skipped: true, reason: `Unknown git-only error type: ${error.type}` };
|
|
312
416
|
}
|
|
313
417
|
}
|
|
314
418
|
/**
|
|
315
|
-
* Create stamp file
|
|
419
|
+
* Create stamp file inside a micro-worktree (WU-1078)
|
|
420
|
+
*
|
|
421
|
+
* @param {string} id - WU ID
|
|
422
|
+
* @param {string} title - WU title
|
|
423
|
+
* @param {string} worktreePath - Path to the micro-worktree
|
|
424
|
+
* @returns {Promise<string[]>} List of files created (relative paths)
|
|
425
|
+
*/
|
|
426
|
+
async function createStampInWorktree(id, title, worktreePath) {
|
|
427
|
+
const stampsDir = path.join(worktreePath, WU_PATHS.STAMPS_DIR());
|
|
428
|
+
const stampRelPath = WU_PATHS.STAMP(id);
|
|
429
|
+
const stampAbsPath = path.join(worktreePath, stampRelPath);
|
|
430
|
+
// Ensure stamps directory exists
|
|
431
|
+
if (!existsSync(stampsDir)) {
|
|
432
|
+
mkdirSync(stampsDir, { recursive: true });
|
|
433
|
+
}
|
|
434
|
+
// Don't overwrite existing stamp
|
|
435
|
+
if (existsSync(stampAbsPath)) {
|
|
436
|
+
return []; // Stamp already exists
|
|
437
|
+
}
|
|
438
|
+
// Create stamp file
|
|
439
|
+
const body = `WU ${id} — ${title}\nCompleted: ${todayISO()}\n`;
|
|
440
|
+
writeFileSync(stampAbsPath, body, { encoding: 'utf-8' });
|
|
441
|
+
return [stampRelPath];
|
|
442
|
+
}
|
|
443
|
+
/**
|
|
444
|
+
* Create stamp file in a specific project root (DEPRECATED - use createStampInWorktree)
|
|
445
|
+
*
|
|
446
|
+
* Kept for backwards compatibility with code that doesn't use micro-worktree.
|
|
316
447
|
*
|
|
317
448
|
* @param {string} id - WU ID
|
|
318
449
|
* @param {string} title - WU title
|
|
@@ -342,7 +473,7 @@ async function createStampInProject(id, title, projectRoot) {
|
|
|
342
473
|
await writeFile(stampPath, body, { encoding: 'utf-8' });
|
|
343
474
|
}
|
|
344
475
|
/**
|
|
345
|
-
* Update WU YAML to done+locked+completed state (WU-
|
|
476
|
+
* Update WU YAML to done+locked+completed state inside a micro-worktree (WU-1078)
|
|
346
477
|
*
|
|
347
478
|
* Repairs STAMP_EXISTS_YAML_NOT_DONE by setting:
|
|
348
479
|
* - status: done
|
|
@@ -350,6 +481,43 @@ async function createStampInProject(id, title, projectRoot) {
|
|
|
350
481
|
* - completed: YYYY-MM-DD (today, unless already set)
|
|
351
482
|
*
|
|
352
483
|
* @param {string} id - WU ID
|
|
484
|
+
* @param {string} worktreePath - Path to the micro-worktree
|
|
485
|
+
* @param {string} projectRoot - Original project root (for reading source file)
|
|
486
|
+
* @returns {Promise<string[]>} List of files modified (relative paths)
|
|
487
|
+
*/
|
|
488
|
+
async function updateYamlToDoneInWorktree(id, worktreePath, projectRoot) {
|
|
489
|
+
const wuRelPath = WU_PATHS.WU(id);
|
|
490
|
+
const wuSrcPath = path.join(projectRoot, wuRelPath);
|
|
491
|
+
const wuDestPath = path.join(worktreePath, wuRelPath);
|
|
492
|
+
// Read current YAML from project root
|
|
493
|
+
const content = readFileSync(wuSrcPath, { encoding: 'utf-8' });
|
|
494
|
+
const wuDoc = parseYAML(content);
|
|
495
|
+
if (!wuDoc) {
|
|
496
|
+
throw new Error(`Failed to parse WU YAML: ${wuSrcPath}`);
|
|
497
|
+
}
|
|
498
|
+
// Update fields
|
|
499
|
+
wuDoc.status = WU_STATUS.DONE;
|
|
500
|
+
wuDoc.locked = true;
|
|
501
|
+
// Preserve existing completed date if present, otherwise set to today
|
|
502
|
+
if (!wuDoc.completed) {
|
|
503
|
+
wuDoc.completed = todayISO();
|
|
504
|
+
}
|
|
505
|
+
// Ensure directory exists in worktree
|
|
506
|
+
const wuDir = path.dirname(wuDestPath);
|
|
507
|
+
if (!existsSync(wuDir)) {
|
|
508
|
+
mkdirSync(wuDir, { recursive: true });
|
|
509
|
+
}
|
|
510
|
+
// Write updated YAML to worktree
|
|
511
|
+
const updatedContent = stringifyYAML(wuDoc, { lineWidth: YAML_OPTIONS.LINE_WIDTH });
|
|
512
|
+
writeFileSync(wuDestPath, updatedContent, { encoding: 'utf-8' });
|
|
513
|
+
return [wuRelPath];
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
* Update WU YAML to done+locked+completed state (DEPRECATED - use updateYamlToDoneInWorktree)
|
|
517
|
+
*
|
|
518
|
+
* Kept for backwards compatibility.
|
|
519
|
+
*
|
|
520
|
+
* @param {string} id - WU ID
|
|
353
521
|
* @param {string} projectRoot - Project root directory
|
|
354
522
|
* @returns {Promise<void>}
|
|
355
523
|
*/
|
|
@@ -373,7 +541,69 @@ async function updateYamlToDone(id, projectRoot) {
|
|
|
373
541
|
await writeFile(wuPath, updatedContent, { encoding: 'utf-8' });
|
|
374
542
|
}
|
|
375
543
|
/**
|
|
376
|
-
* Remove WU entry from a specific section in a markdown file
|
|
544
|
+
* Remove WU entry from a specific section in a markdown file inside a micro-worktree (WU-1078)
|
|
545
|
+
*
|
|
546
|
+
* @param {string} relFilePath - Relative path to the markdown file
|
|
547
|
+
* @param {string} id - WU ID to remove
|
|
548
|
+
* @param {string} sectionHeading - Section heading to target
|
|
549
|
+
* @param {string} worktreePath - Path to the micro-worktree
|
|
550
|
+
* @param {string} projectRoot - Original project root (for reading source file)
|
|
551
|
+
* @returns {Promise<string[]>} List of files modified (relative paths)
|
|
552
|
+
*/
|
|
553
|
+
async function removeWUFromSectionInWorktree(relFilePath, id, sectionHeading, worktreePath, projectRoot) {
|
|
554
|
+
const srcPath = path.join(projectRoot, relFilePath);
|
|
555
|
+
const destPath = path.join(worktreePath, relFilePath);
|
|
556
|
+
// Check if source file exists
|
|
557
|
+
if (!existsSync(srcPath)) {
|
|
558
|
+
return []; // File doesn't exist
|
|
559
|
+
}
|
|
560
|
+
const content = readFileSync(srcPath, { encoding: 'utf-8' });
|
|
561
|
+
const lines = content.split(/\r?\n/);
|
|
562
|
+
let inTargetSection = false;
|
|
563
|
+
let nextSectionIdx = -1;
|
|
564
|
+
let sectionStartIdx = -1;
|
|
565
|
+
// Normalize heading for comparison (lowercase, trim)
|
|
566
|
+
const normalizedHeading = sectionHeading.toLowerCase().trim();
|
|
567
|
+
// Find section boundaries
|
|
568
|
+
for (let i = 0; i < lines.length; i++) {
|
|
569
|
+
const normalizedLine = lines[i].toLowerCase().trim();
|
|
570
|
+
if (normalizedLine === normalizedHeading || normalizedLine.startsWith(normalizedHeading)) {
|
|
571
|
+
inTargetSection = true;
|
|
572
|
+
sectionStartIdx = i;
|
|
573
|
+
continue;
|
|
574
|
+
}
|
|
575
|
+
if (inTargetSection && lines[i].trim().startsWith('## ')) {
|
|
576
|
+
nextSectionIdx = i;
|
|
577
|
+
break;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
if (sectionStartIdx === -1)
|
|
581
|
+
return [];
|
|
582
|
+
const endIdx = nextSectionIdx === -1 ? lines.length : nextSectionIdx;
|
|
583
|
+
// Filter out lines containing the WU ID in the target section
|
|
584
|
+
const newLines = [];
|
|
585
|
+
let modified = false;
|
|
586
|
+
for (let i = 0; i < lines.length; i++) {
|
|
587
|
+
if (i > sectionStartIdx && i < endIdx && lines[i].includes(id)) {
|
|
588
|
+
modified = true;
|
|
589
|
+
continue; // Skip this line
|
|
590
|
+
}
|
|
591
|
+
newLines.push(lines[i]);
|
|
592
|
+
}
|
|
593
|
+
if (!modified)
|
|
594
|
+
return [];
|
|
595
|
+
// Ensure directory exists in worktree
|
|
596
|
+
const destDir = path.dirname(destPath);
|
|
597
|
+
if (!existsSync(destDir)) {
|
|
598
|
+
mkdirSync(destDir, { recursive: true });
|
|
599
|
+
}
|
|
600
|
+
writeFileSync(destPath, newLines.join(STRING_LITERALS.NEWLINE), { encoding: 'utf-8' });
|
|
601
|
+
return [relFilePath];
|
|
602
|
+
}
|
|
603
|
+
/**
|
|
604
|
+
* Remove WU entry from a specific section in a markdown file (DEPRECATED)
|
|
605
|
+
*
|
|
606
|
+
* Kept for backwards compatibility.
|
|
377
607
|
*
|
|
378
608
|
* @param {string} filePath - Path to the markdown file
|
|
379
609
|
* @param {string} id - WU ID to remove
|
package/dist/wu-constants.d.ts
CHANGED
|
@@ -1102,7 +1102,7 @@ export declare const GIT_COMMAND_STRINGS: {
|
|
|
1102
1102
|
export declare const PATH_PATTERNS: {
|
|
1103
1103
|
/** Matches WU YAML paths in both legacy and current locations */
|
|
1104
1104
|
WU_YAML: RegExp;
|
|
1105
|
-
/** Matches stamp file paths */
|
|
1105
|
+
/** Matches stamp file paths (supports both .beacon and .lumenflow for migration) */
|
|
1106
1106
|
STAMP: RegExp;
|
|
1107
1107
|
};
|
|
1108
1108
|
/**
|
|
@@ -1208,12 +1208,57 @@ export declare const ERROR_CODES: {
|
|
|
1208
1208
|
ETIMEDOUT: string;
|
|
1209
1209
|
};
|
|
1210
1210
|
/**
|
|
1211
|
-
*
|
|
1211
|
+
* LumenFlow directory paths
|
|
1212
1212
|
*
|
|
1213
|
-
* Centralized paths for .
|
|
1214
|
-
* Used by telemetry, agent-session, agent-incidents, and commands-logger modules.
|
|
1213
|
+
* Centralized paths for .lumenflow directory structure to eliminate hardcoded strings.
|
|
1214
|
+
* Used by telemetry, agent-session, agent-incidents, memory, and commands-logger modules.
|
|
1215
|
+
*
|
|
1216
|
+
* @since 1.4.0 Renamed from BEACON_PATHS (WU-1075)
|
|
1217
|
+
*/
|
|
1218
|
+
export declare const LUMENFLOW_PATHS: {
|
|
1219
|
+
/** Base directory for all LumenFlow runtime data */
|
|
1220
|
+
BASE: string;
|
|
1221
|
+
/** WU state store directory */
|
|
1222
|
+
STATE_DIR: string;
|
|
1223
|
+
/** Stamp directory (WU completion markers) */
|
|
1224
|
+
STAMPS_DIR: string;
|
|
1225
|
+
/** Merge lock file (runtime coordination, WU-1747) */
|
|
1226
|
+
MERGE_LOCK: string;
|
|
1227
|
+
/** Base telemetry directory */
|
|
1228
|
+
TELEMETRY: string;
|
|
1229
|
+
/** Flow log file (WU flow events) */
|
|
1230
|
+
FLOW_LOG: string;
|
|
1231
|
+
/** Agent sessions directory */
|
|
1232
|
+
SESSIONS: string;
|
|
1233
|
+
/** Agent incidents directory */
|
|
1234
|
+
INCIDENTS: string;
|
|
1235
|
+
/** Git commands log file */
|
|
1236
|
+
COMMANDS_LOG: string;
|
|
1237
|
+
/** Memory layer directory */
|
|
1238
|
+
MEMORY_DIR: string;
|
|
1239
|
+
/** Memory layer JSONL file */
|
|
1240
|
+
MEMORY_JSONL: string;
|
|
1241
|
+
/** Audit log for tool calls */
|
|
1242
|
+
AUDIT_LOG: string;
|
|
1243
|
+
/** Feedback drafts directory */
|
|
1244
|
+
FEEDBACK_DRAFTS: string;
|
|
1245
|
+
/** Feedback index file */
|
|
1246
|
+
FEEDBACK_INDEX: string;
|
|
1247
|
+
/** Current session file */
|
|
1248
|
+
SESSION_CURRENT: string;
|
|
1249
|
+
/** WU events log */
|
|
1250
|
+
WU_EVENTS: string;
|
|
1251
|
+
/** Lock files directory */
|
|
1252
|
+
LOCKS_DIR: string;
|
|
1253
|
+
/** Force bypass audit log */
|
|
1254
|
+
FORCE_BYPASSES: string;
|
|
1255
|
+
};
|
|
1256
|
+
/**
|
|
1257
|
+
* @deprecated Use LUMENFLOW_PATHS instead. Will be removed in v2.0.
|
|
1215
1258
|
*/
|
|
1216
1259
|
export declare const BEACON_PATHS: {
|
|
1260
|
+
/** Base directory for all LumenFlow runtime data */
|
|
1261
|
+
BASE: string;
|
|
1217
1262
|
/** WU state store directory */
|
|
1218
1263
|
STATE_DIR: string;
|
|
1219
1264
|
/** Stamp directory (WU completion markers) */
|
|
@@ -1230,6 +1275,24 @@ export declare const BEACON_PATHS: {
|
|
|
1230
1275
|
INCIDENTS: string;
|
|
1231
1276
|
/** Git commands log file */
|
|
1232
1277
|
COMMANDS_LOG: string;
|
|
1278
|
+
/** Memory layer directory */
|
|
1279
|
+
MEMORY_DIR: string;
|
|
1280
|
+
/** Memory layer JSONL file */
|
|
1281
|
+
MEMORY_JSONL: string;
|
|
1282
|
+
/** Audit log for tool calls */
|
|
1283
|
+
AUDIT_LOG: string;
|
|
1284
|
+
/** Feedback drafts directory */
|
|
1285
|
+
FEEDBACK_DRAFTS: string;
|
|
1286
|
+
/** Feedback index file */
|
|
1287
|
+
FEEDBACK_INDEX: string;
|
|
1288
|
+
/** Current session file */
|
|
1289
|
+
SESSION_CURRENT: string;
|
|
1290
|
+
/** WU events log */
|
|
1291
|
+
WU_EVENTS: string;
|
|
1292
|
+
/** Lock files directory */
|
|
1293
|
+
LOCKS_DIR: string;
|
|
1294
|
+
/** Force bypass audit log */
|
|
1295
|
+
FORCE_BYPASSES: string;
|
|
1233
1296
|
};
|
|
1234
1297
|
/**
|
|
1235
1298
|
* File extensions
|
package/dist/wu-constants.js
CHANGED
|
@@ -1145,8 +1145,8 @@ export const GIT_COMMAND_STRINGS = {
|
|
|
1145
1145
|
export const PATH_PATTERNS = {
|
|
1146
1146
|
/** Matches WU YAML paths in both legacy and current locations */
|
|
1147
1147
|
WU_YAML: /(?:memory-bank|docs\/04-operations)\/tasks\/wu\/(WU-\d+)\.ya?ml$/i,
|
|
1148
|
-
/** Matches stamp file paths */
|
|
1149
|
-
STAMP: /\.beacon\/stamps\/(WU-\d+)\.done$/i,
|
|
1148
|
+
/** Matches stamp file paths (supports both .beacon and .lumenflow for migration) */
|
|
1149
|
+
STAMP: /\.(?:beacon|lumenflow)\/stamps\/(WU-\d+)\.done$/i,
|
|
1150
1150
|
};
|
|
1151
1151
|
/**
|
|
1152
1152
|
* Common shell commands
|
|
@@ -1251,29 +1251,55 @@ export const ERROR_CODES = {
|
|
|
1251
1251
|
ETIMEDOUT: 'ETIMEDOUT',
|
|
1252
1252
|
};
|
|
1253
1253
|
/**
|
|
1254
|
-
*
|
|
1254
|
+
* LumenFlow directory paths
|
|
1255
1255
|
*
|
|
1256
|
-
* Centralized paths for .
|
|
1257
|
-
* Used by telemetry, agent-session, agent-incidents, and commands-logger modules.
|
|
1256
|
+
* Centralized paths for .lumenflow directory structure to eliminate hardcoded strings.
|
|
1257
|
+
* Used by telemetry, agent-session, agent-incidents, memory, and commands-logger modules.
|
|
1258
|
+
*
|
|
1259
|
+
* @since 1.4.0 Renamed from BEACON_PATHS (WU-1075)
|
|
1258
1260
|
*/
|
|
1259
|
-
export const
|
|
1261
|
+
export const LUMENFLOW_PATHS = {
|
|
1262
|
+
/** Base directory for all LumenFlow runtime data */
|
|
1263
|
+
BASE: '.lumenflow',
|
|
1260
1264
|
/** WU state store directory */
|
|
1261
|
-
STATE_DIR: '.
|
|
1265
|
+
STATE_DIR: '.lumenflow/state',
|
|
1262
1266
|
/** Stamp directory (WU completion markers) */
|
|
1263
|
-
STAMPS_DIR: '.
|
|
1267
|
+
STAMPS_DIR: '.lumenflow/stamps',
|
|
1264
1268
|
/** Merge lock file (runtime coordination, WU-1747) */
|
|
1265
|
-
MERGE_LOCK: '.
|
|
1269
|
+
MERGE_LOCK: '.lumenflow/merge.lock',
|
|
1266
1270
|
/** Base telemetry directory */
|
|
1267
|
-
TELEMETRY: '.
|
|
1271
|
+
TELEMETRY: '.lumenflow/telemetry',
|
|
1268
1272
|
/** Flow log file (WU flow events) */
|
|
1269
|
-
FLOW_LOG: '.
|
|
1273
|
+
FLOW_LOG: '.lumenflow/flow.log',
|
|
1270
1274
|
/** Agent sessions directory */
|
|
1271
|
-
SESSIONS: '.
|
|
1275
|
+
SESSIONS: '.lumenflow/sessions',
|
|
1272
1276
|
/** Agent incidents directory */
|
|
1273
|
-
INCIDENTS: '.
|
|
1277
|
+
INCIDENTS: '.lumenflow/incidents',
|
|
1274
1278
|
/** Git commands log file */
|
|
1275
|
-
COMMANDS_LOG: '.
|
|
1276
|
-
|
|
1279
|
+
COMMANDS_LOG: '.lumenflow/commands.log',
|
|
1280
|
+
/** Memory layer directory */
|
|
1281
|
+
MEMORY_DIR: '.lumenflow/memory',
|
|
1282
|
+
/** Memory layer JSONL file */
|
|
1283
|
+
MEMORY_JSONL: '.lumenflow/memory/memory.jsonl',
|
|
1284
|
+
/** Audit log for tool calls */
|
|
1285
|
+
AUDIT_LOG: '.lumenflow/telemetry/tools.ndjson',
|
|
1286
|
+
/** Feedback drafts directory */
|
|
1287
|
+
FEEDBACK_DRAFTS: '.lumenflow/feedback-drafts',
|
|
1288
|
+
/** Feedback index file */
|
|
1289
|
+
FEEDBACK_INDEX: '.lumenflow/feedback-index.ndjson',
|
|
1290
|
+
/** Current session file */
|
|
1291
|
+
SESSION_CURRENT: '.lumenflow/sessions/current.json',
|
|
1292
|
+
/** WU events log */
|
|
1293
|
+
WU_EVENTS: '.lumenflow/state/wu-events.jsonl',
|
|
1294
|
+
/** Lock files directory */
|
|
1295
|
+
LOCKS_DIR: '.lumenflow/locks',
|
|
1296
|
+
/** Force bypass audit log */
|
|
1297
|
+
FORCE_BYPASSES: '.lumenflow/force-bypasses.log',
|
|
1298
|
+
};
|
|
1299
|
+
/**
|
|
1300
|
+
* @deprecated Use LUMENFLOW_PATHS instead. Will be removed in v2.0.
|
|
1301
|
+
*/
|
|
1302
|
+
export const BEACON_PATHS = LUMENFLOW_PATHS;
|
|
1277
1303
|
/**
|
|
1278
1304
|
* File extensions
|
|
1279
1305
|
*
|
|
@@ -17,7 +17,7 @@ import path from 'node:path';
|
|
|
17
17
|
import { defaultBranchFrom, branchExists, generateCommitMessage, updateMetadataFiles, stageAndFormatMetadata, } from './wu-done-validators.js';
|
|
18
18
|
import { getGitForCwd } from './git-adapter.js';
|
|
19
19
|
import { readWU } from './wu-yaml.js';
|
|
20
|
-
import { BRANCHES, REMOTES, LOG_PREFIX, EMOJI, STRING_LITERALS } from './wu-constants.js';
|
|
20
|
+
import { BRANCHES, REMOTES, LOG_PREFIX, EMOJI, STRING_LITERALS, LUMENFLOW_PATHS, } from './wu-constants.js';
|
|
21
21
|
import { RECOVERY } from './wu-done-messages.js';
|
|
22
22
|
import { die, createError, ErrorCodes } from './error-handler.js';
|
|
23
23
|
import { validateWU, validateDoneWU } from './wu-schema.js';
|
|
@@ -78,7 +78,7 @@ export async function executeBranchOnlyCompletion(context) {
|
|
|
78
78
|
const metadataWUPath = path.join(metadataBasePath, 'docs', '04-operations', 'tasks', 'wu', `${id}.yaml`);
|
|
79
79
|
const metadataStatusPath = path.join(metadataBasePath, 'docs', '04-operations', 'tasks', 'status.md');
|
|
80
80
|
const metadataBacklogPath = path.join(metadataBasePath, 'docs', '04-operations', 'tasks', 'backlog.md');
|
|
81
|
-
const metadataStampsDir = path.join(metadataBasePath,
|
|
81
|
+
const metadataStampsDir = path.join(metadataBasePath, LUMENFLOW_PATHS.STAMPS_DIR);
|
|
82
82
|
const metadataStampPath = path.join(metadataStampsDir, `${id}.done`);
|
|
83
83
|
// Step 3: Read WU YAML and validate current state
|
|
84
84
|
const docForUpdate = readWU(metadataWUPath, id);
|
package/dist/wu-done-inputs.js
CHANGED
|
@@ -36,7 +36,7 @@ export function validateInputs(argv) {
|
|
|
36
36
|
' • A separate WU exists to fix those failures (specify with --fix-wu)\n' +
|
|
37
37
|
' • Your WU work is genuinely complete\n\n' +
|
|
38
38
|
' NEVER use --skip-gates for failures introduced by your WU!\n' +
|
|
39
|
-
' All skip-gates events are logged to .
|
|
39
|
+
' All skip-gates events are logged to .lumenflow/skip-gates-audit.log\n\n' +
|
|
40
40
|
'📝 WU VALIDATOR:\n' +
|
|
41
41
|
' Automatically scans code_paths for:\n' +
|
|
42
42
|
' • TODO/FIXME/HACK/XXX comments (fails validation unless --allow-todo)\n' +
|
|
@@ -260,7 +260,7 @@ const DOCS_ONLY_ALLOWED_PATTERNS = [
|
|
|
260
260
|
/^memory-bank\//i,
|
|
261
261
|
/^docs\//i,
|
|
262
262
|
/\.md$/i,
|
|
263
|
-
/^\.beacon\/stamps\//i,
|
|
263
|
+
/^\.(?:beacon|lumenflow)\/stamps\//i, // Support both legacy .beacon and .lumenflow
|
|
264
264
|
/^\.claude\//i,
|
|
265
265
|
/^ai\//i,
|
|
266
266
|
/^README\.md$/i,
|
|
@@ -332,7 +332,7 @@ Allowed paths for documentation WUs:
|
|
|
332
332
|
- ai/
|
|
333
333
|
- .claude/
|
|
334
334
|
- memory-bank/
|
|
335
|
-
- .beacon/stamps/
|
|
335
|
+
- .lumenflow/stamps/ (or legacy .beacon/stamps/)
|
|
336
336
|
- *.md files
|
|
337
337
|
|
|
338
338
|
After fixing, retry: pnpm wu:done --id ${id}
|
package/dist/wu-done-worktree.js
CHANGED
|
@@ -115,7 +115,7 @@ export async function executeWorktreeCompletion(context) {
|
|
|
115
115
|
console.log(`${BOX.SIDE} 4. Return to main and retry wu:done`);
|
|
116
116
|
console.log(BOX.SIDE);
|
|
117
117
|
console.log(`${BOX.SIDE} Or reset the recovery counter:`);
|
|
118
|
-
console.log(`${BOX.SIDE} rm .
|
|
118
|
+
console.log(`${BOX.SIDE} rm .lumenflow/recovery/${id}.recovery`);
|
|
119
119
|
console.log(BOX.BOT);
|
|
120
120
|
throw createRecoveryError(`Recovery loop detected for ${id} after ${attemptCount} attempts. Manual intervention required.`, { wuId: id, attemptCount, maxAttempts: MAX_RECOVERY_ATTEMPTS });
|
|
121
121
|
}
|
|
@@ -232,7 +232,7 @@ export async function executeWorktreeCompletion(context) {
|
|
|
232
232
|
// WU-2310: Capture file state before transaction commit
|
|
233
233
|
// This allows rollback if git commit fails AFTER files are written
|
|
234
234
|
// Note: We use the relative paths since we're already chdir'd into the worktree
|
|
235
|
-
const workingEventsPath = path.join('.
|
|
235
|
+
const workingEventsPath = path.join('.lumenflow', 'state', WU_EVENTS_FILE_NAME);
|
|
236
236
|
const pathsToSnapshot = [
|
|
237
237
|
workingWUPath,
|
|
238
238
|
workingStatusPath,
|
|
@@ -571,12 +571,12 @@ export async function checkBranchDrift(branch) {
|
|
|
571
571
|
*/
|
|
572
572
|
const APPEND_ONLY_FILES = [
|
|
573
573
|
// State store events file (append-only by design)
|
|
574
|
-
path.join('.
|
|
574
|
+
path.join('.lumenflow', 'state', WU_EVENTS_FILE_NAME),
|
|
575
575
|
// Status and backlog are generated from state store but may conflict during rebase
|
|
576
576
|
WU_PATHS.STATUS(),
|
|
577
577
|
WU_PATHS.BACKLOG(),
|
|
578
578
|
];
|
|
579
|
-
const WU_EVENTS_PATH = path.join('.
|
|
579
|
+
const WU_EVENTS_PATH = path.join('.lumenflow', 'state', WU_EVENTS_FILE_NAME);
|
|
580
580
|
function normalizeEventForKey(event) {
|
|
581
581
|
const normalized = {};
|
|
582
582
|
for (const key of Object.keys(event).sort()) {
|
package/dist/wu-paths.js
CHANGED
|
@@ -19,7 +19,7 @@ const PATH_DEPTHS = {
|
|
|
19
19
|
STATUS: 4,
|
|
20
20
|
/** WU YAML files are 5 levels deep: docs/04-operations/tasks/wu/{id}.yaml */
|
|
21
21
|
WU_YAML: 5,
|
|
22
|
-
/** State store is 3 levels deep: .
|
|
22
|
+
/** State store is 3 levels deep: .lumenflow/state/wu-events.jsonl */
|
|
23
23
|
STATE_STORE: 3,
|
|
24
24
|
};
|
|
25
25
|
/**
|
package/dist/wu-recovery.d.ts
CHANGED
|
@@ -23,7 +23,7 @@ export declare const MAX_RECOVERY_ATTEMPTS: 4;
|
|
|
23
23
|
* WU-1335: Get the path to the recovery marker file for a WU
|
|
24
24
|
*
|
|
25
25
|
* @param {string} id - WU ID
|
|
26
|
-
* @param {string} [baseDir=process.cwd()] - Base directory for .
|
|
26
|
+
* @param {string} [baseDir=process.cwd()] - Base directory for .lumenflow
|
|
27
27
|
* @returns {string} Path to recovery marker file
|
|
28
28
|
*/
|
|
29
29
|
export declare function getRecoveryMarkerPath(id: any, baseDir?: string): string;
|
|
@@ -31,7 +31,7 @@ export declare function getRecoveryMarkerPath(id: any, baseDir?: string): string
|
|
|
31
31
|
* WU-1335: Get the current recovery attempt count for a WU
|
|
32
32
|
*
|
|
33
33
|
* @param {string} id - WU ID
|
|
34
|
-
* @param {string} [baseDir=process.cwd()] - Base directory for .
|
|
34
|
+
* @param {string} [baseDir=process.cwd()] - Base directory for .lumenflow
|
|
35
35
|
* @returns {number} Current attempt count (0 if no marker exists)
|
|
36
36
|
*/
|
|
37
37
|
export declare function getRecoveryAttemptCount(id: any, baseDir?: string): any;
|
|
@@ -39,7 +39,7 @@ export declare function getRecoveryAttemptCount(id: any, baseDir?: string): any;
|
|
|
39
39
|
* WU-1335: Increment recovery attempt count for a WU
|
|
40
40
|
*
|
|
41
41
|
* @param {string} id - WU ID
|
|
42
|
-
* @param {string} [baseDir=process.cwd()] - Base directory for .
|
|
42
|
+
* @param {string} [baseDir=process.cwd()] - Base directory for .lumenflow
|
|
43
43
|
* @returns {number} New attempt count
|
|
44
44
|
*/
|
|
45
45
|
export declare function incrementRecoveryAttempt(id: any, baseDir?: string): any;
|
|
@@ -47,7 +47,7 @@ export declare function incrementRecoveryAttempt(id: any, baseDir?: string): any
|
|
|
47
47
|
* WU-1335: Clear recovery attempts for a WU (called on successful recovery)
|
|
48
48
|
*
|
|
49
49
|
* @param {string} id - WU ID
|
|
50
|
-
* @param {string} [baseDir=process.cwd()] - Base directory for .
|
|
50
|
+
* @param {string} [baseDir=process.cwd()] - Base directory for .lumenflow
|
|
51
51
|
*/
|
|
52
52
|
export declare function clearRecoveryAttempts(id: any, baseDir?: string): void;
|
|
53
53
|
/**
|