@lumenflow/core 2.5.0 → 2.6.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/gates-config.d.ts +72 -0
- package/dist/gates-config.js +190 -0
- package/dist/lumenflow-config-schema.d.ts +252 -0
- package/dist/lumenflow-config-schema.js +196 -0
- package/dist/micro-worktree.d.ts +18 -4
- package/dist/micro-worktree.js +41 -33
- package/dist/wu-constants.d.ts +69 -0
- package/dist/wu-constants.js +78 -0
- package/package.json +2 -2
package/dist/gates-config.d.ts
CHANGED
|
@@ -204,3 +204,75 @@ export interface TestPolicy extends CoverageConfig {
|
|
|
204
204
|
* @returns Resolved test policy including tests_required
|
|
205
205
|
*/
|
|
206
206
|
export declare function resolveTestPolicy(projectRoot: string): TestPolicy;
|
|
207
|
+
/**
|
|
208
|
+
* WU-1356: Supported package managers type
|
|
209
|
+
* Re-exported from lumenflow-config-schema to avoid circular import
|
|
210
|
+
*/
|
|
211
|
+
type PackageManager = 'pnpm' | 'npm' | 'yarn' | 'bun';
|
|
212
|
+
/**
|
|
213
|
+
* WU-1356: Supported test runners type
|
|
214
|
+
* Re-exported from lumenflow-config-schema to avoid circular import
|
|
215
|
+
*/
|
|
216
|
+
type TestRunner = 'vitest' | 'jest' | 'mocha';
|
|
217
|
+
/**
|
|
218
|
+
* WU-1356: Gates commands configuration type
|
|
219
|
+
*/
|
|
220
|
+
export interface GatesCommands {
|
|
221
|
+
test_full: string;
|
|
222
|
+
test_docs_only: string;
|
|
223
|
+
test_incremental: string;
|
|
224
|
+
lint?: string;
|
|
225
|
+
typecheck?: string;
|
|
226
|
+
format?: string;
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* WU-1356: Resolve package manager from configuration
|
|
230
|
+
*
|
|
231
|
+
* Reads the package_manager field from .lumenflow.config.yaml.
|
|
232
|
+
* Returns 'pnpm' as default if not configured.
|
|
233
|
+
*
|
|
234
|
+
* @param projectRoot - Project root directory
|
|
235
|
+
* @returns Resolved package manager ('pnpm', 'npm', 'yarn', or 'bun')
|
|
236
|
+
*/
|
|
237
|
+
export declare function resolvePackageManager(projectRoot: string): PackageManager;
|
|
238
|
+
/**
|
|
239
|
+
* WU-1356: Resolve test runner from configuration
|
|
240
|
+
*
|
|
241
|
+
* Reads the test_runner field from .lumenflow.config.yaml.
|
|
242
|
+
* Returns 'vitest' as default if not configured.
|
|
243
|
+
*
|
|
244
|
+
* @param projectRoot - Project root directory
|
|
245
|
+
* @returns Resolved test runner ('vitest', 'jest', or 'mocha')
|
|
246
|
+
*/
|
|
247
|
+
export declare function resolveTestRunner(projectRoot: string): TestRunner;
|
|
248
|
+
/**
|
|
249
|
+
* WU-1356: Resolve build command from configuration
|
|
250
|
+
*
|
|
251
|
+
* Reads the build_command field from .lumenflow.config.yaml.
|
|
252
|
+
* If not configured, uses default based on package_manager.
|
|
253
|
+
*
|
|
254
|
+
* @param projectRoot - Project root directory
|
|
255
|
+
* @returns Resolved build command
|
|
256
|
+
*/
|
|
257
|
+
export declare function resolveBuildCommand(projectRoot: string): string;
|
|
258
|
+
/**
|
|
259
|
+
* WU-1356: Resolve gates commands from configuration
|
|
260
|
+
*
|
|
261
|
+
* Reads gates.commands from .lumenflow.config.yaml.
|
|
262
|
+
* Merges with defaults based on package_manager if not fully specified.
|
|
263
|
+
*
|
|
264
|
+
* @param projectRoot - Project root directory
|
|
265
|
+
* @returns Resolved gates commands configuration
|
|
266
|
+
*/
|
|
267
|
+
export declare function resolveGatesCommands(projectRoot: string): GatesCommands;
|
|
268
|
+
/**
|
|
269
|
+
* WU-1356: Get ignore patterns for test runner
|
|
270
|
+
*
|
|
271
|
+
* Returns patterns to ignore when detecting changed tests,
|
|
272
|
+
* based on the test runner configuration.
|
|
273
|
+
*
|
|
274
|
+
* @param testRunner - Test runner type (vitest, jest, mocha)
|
|
275
|
+
* @returns Array of ignore patterns
|
|
276
|
+
*/
|
|
277
|
+
export declare function getIgnorePatterns(testRunner: TestRunner): string[];
|
|
278
|
+
export {};
|
package/dist/gates-config.js
CHANGED
|
@@ -453,3 +453,193 @@ export function resolveTestPolicy(projectRoot) {
|
|
|
453
453
|
tests_required: policy.tests_required,
|
|
454
454
|
};
|
|
455
455
|
}
|
|
456
|
+
/**
|
|
457
|
+
* WU-1356: Default gates commands by package manager
|
|
458
|
+
*
|
|
459
|
+
* Provides sensible defaults for different package manager and test runner combinations.
|
|
460
|
+
*/
|
|
461
|
+
const DEFAULT_GATES_COMMANDS = {
|
|
462
|
+
pnpm: {
|
|
463
|
+
test_full: 'pnpm turbo run test',
|
|
464
|
+
test_docs_only: '',
|
|
465
|
+
test_incremental: 'pnpm vitest run --changed origin/main',
|
|
466
|
+
lint: 'pnpm lint',
|
|
467
|
+
typecheck: 'pnpm typecheck',
|
|
468
|
+
format: 'pnpm format:check',
|
|
469
|
+
},
|
|
470
|
+
npm: {
|
|
471
|
+
test_full: 'npm test',
|
|
472
|
+
test_docs_only: '',
|
|
473
|
+
test_incremental: 'npm test -- --onlyChanged',
|
|
474
|
+
lint: 'npm run lint',
|
|
475
|
+
typecheck: 'npm run typecheck',
|
|
476
|
+
format: 'npm run format:check',
|
|
477
|
+
},
|
|
478
|
+
yarn: {
|
|
479
|
+
test_full: 'yarn test',
|
|
480
|
+
test_docs_only: '',
|
|
481
|
+
test_incremental: 'yarn test --onlyChanged',
|
|
482
|
+
lint: 'yarn lint',
|
|
483
|
+
typecheck: 'yarn typecheck',
|
|
484
|
+
format: 'yarn format:check',
|
|
485
|
+
},
|
|
486
|
+
bun: {
|
|
487
|
+
test_full: 'bun test',
|
|
488
|
+
test_docs_only: '',
|
|
489
|
+
test_incremental: 'bun test --changed',
|
|
490
|
+
lint: 'bun run lint',
|
|
491
|
+
typecheck: 'bun run typecheck',
|
|
492
|
+
format: 'bun run format:check',
|
|
493
|
+
},
|
|
494
|
+
};
|
|
495
|
+
/**
|
|
496
|
+
* WU-1356: Default build commands by package manager
|
|
497
|
+
*/
|
|
498
|
+
const DEFAULT_BUILD_COMMANDS = {
|
|
499
|
+
pnpm: 'pnpm --filter @lumenflow/cli build',
|
|
500
|
+
npm: 'npm run build --workspace @lumenflow/cli',
|
|
501
|
+
yarn: 'yarn workspace @lumenflow/cli build',
|
|
502
|
+
bun: 'bun run --filter @lumenflow/cli build',
|
|
503
|
+
};
|
|
504
|
+
/**
|
|
505
|
+
* WU-1356: Ignore patterns by test runner
|
|
506
|
+
*
|
|
507
|
+
* Different test runners use different cache directories that should be ignored.
|
|
508
|
+
*/
|
|
509
|
+
const IGNORE_PATTERNS_BY_RUNNER = {
|
|
510
|
+
vitest: ['.turbo'],
|
|
511
|
+
jest: ['coverage', '.jest-cache'],
|
|
512
|
+
mocha: ['coverage', '.nyc_output'],
|
|
513
|
+
};
|
|
514
|
+
/**
|
|
515
|
+
* WU-1356: Resolve package manager from configuration
|
|
516
|
+
*
|
|
517
|
+
* Reads the package_manager field from .lumenflow.config.yaml.
|
|
518
|
+
* Returns 'pnpm' as default if not configured.
|
|
519
|
+
*
|
|
520
|
+
* @param projectRoot - Project root directory
|
|
521
|
+
* @returns Resolved package manager ('pnpm', 'npm', 'yarn', or 'bun')
|
|
522
|
+
*/
|
|
523
|
+
export function resolvePackageManager(projectRoot) {
|
|
524
|
+
const configPath = path.join(projectRoot, CONFIG_FILE_NAME);
|
|
525
|
+
if (!fs.existsSync(configPath)) {
|
|
526
|
+
return 'pnpm';
|
|
527
|
+
}
|
|
528
|
+
try {
|
|
529
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
530
|
+
const data = yaml.parse(content);
|
|
531
|
+
const pm = data?.package_manager;
|
|
532
|
+
if (pm && ['pnpm', 'npm', 'yarn', 'bun'].includes(pm)) {
|
|
533
|
+
return pm;
|
|
534
|
+
}
|
|
535
|
+
return 'pnpm';
|
|
536
|
+
}
|
|
537
|
+
catch {
|
|
538
|
+
return 'pnpm';
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* WU-1356: Resolve test runner from configuration
|
|
543
|
+
*
|
|
544
|
+
* Reads the test_runner field from .lumenflow.config.yaml.
|
|
545
|
+
* Returns 'vitest' as default if not configured.
|
|
546
|
+
*
|
|
547
|
+
* @param projectRoot - Project root directory
|
|
548
|
+
* @returns Resolved test runner ('vitest', 'jest', or 'mocha')
|
|
549
|
+
*/
|
|
550
|
+
export function resolveTestRunner(projectRoot) {
|
|
551
|
+
const configPath = path.join(projectRoot, CONFIG_FILE_NAME);
|
|
552
|
+
if (!fs.existsSync(configPath)) {
|
|
553
|
+
return 'vitest';
|
|
554
|
+
}
|
|
555
|
+
try {
|
|
556
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
557
|
+
const data = yaml.parse(content);
|
|
558
|
+
const runner = data?.test_runner;
|
|
559
|
+
if (runner && ['vitest', 'jest', 'mocha'].includes(runner)) {
|
|
560
|
+
return runner;
|
|
561
|
+
}
|
|
562
|
+
return 'vitest';
|
|
563
|
+
}
|
|
564
|
+
catch {
|
|
565
|
+
return 'vitest';
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
/**
|
|
569
|
+
* WU-1356: Resolve build command from configuration
|
|
570
|
+
*
|
|
571
|
+
* Reads the build_command field from .lumenflow.config.yaml.
|
|
572
|
+
* If not configured, uses default based on package_manager.
|
|
573
|
+
*
|
|
574
|
+
* @param projectRoot - Project root directory
|
|
575
|
+
* @returns Resolved build command
|
|
576
|
+
*/
|
|
577
|
+
export function resolveBuildCommand(projectRoot) {
|
|
578
|
+
const configPath = path.join(projectRoot, CONFIG_FILE_NAME);
|
|
579
|
+
const defaultPm = resolvePackageManager(projectRoot);
|
|
580
|
+
if (!fs.existsSync(configPath)) {
|
|
581
|
+
return DEFAULT_BUILD_COMMANDS[defaultPm];
|
|
582
|
+
}
|
|
583
|
+
try {
|
|
584
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
585
|
+
const data = yaml.parse(content);
|
|
586
|
+
// If explicit build_command is set, use it
|
|
587
|
+
if (data?.build_command && typeof data.build_command === 'string') {
|
|
588
|
+
return data.build_command;
|
|
589
|
+
}
|
|
590
|
+
// Otherwise, use default for the configured package manager
|
|
591
|
+
return DEFAULT_BUILD_COMMANDS[defaultPm];
|
|
592
|
+
}
|
|
593
|
+
catch {
|
|
594
|
+
return DEFAULT_BUILD_COMMANDS[defaultPm];
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* WU-1356: Resolve gates commands from configuration
|
|
599
|
+
*
|
|
600
|
+
* Reads gates.commands from .lumenflow.config.yaml.
|
|
601
|
+
* Merges with defaults based on package_manager if not fully specified.
|
|
602
|
+
*
|
|
603
|
+
* @param projectRoot - Project root directory
|
|
604
|
+
* @returns Resolved gates commands configuration
|
|
605
|
+
*/
|
|
606
|
+
export function resolveGatesCommands(projectRoot) {
|
|
607
|
+
const configPath = path.join(projectRoot, CONFIG_FILE_NAME);
|
|
608
|
+
const pm = resolvePackageManager(projectRoot);
|
|
609
|
+
const defaults = DEFAULT_GATES_COMMANDS[pm];
|
|
610
|
+
if (!fs.existsSync(configPath)) {
|
|
611
|
+
return defaults;
|
|
612
|
+
}
|
|
613
|
+
try {
|
|
614
|
+
const content = fs.readFileSync(configPath, 'utf8');
|
|
615
|
+
const data = yaml.parse(content);
|
|
616
|
+
const commands = data?.gates?.commands;
|
|
617
|
+
if (!commands) {
|
|
618
|
+
return defaults;
|
|
619
|
+
}
|
|
620
|
+
// Merge user config with defaults (user config wins)
|
|
621
|
+
return {
|
|
622
|
+
test_full: commands.test_full ?? defaults.test_full,
|
|
623
|
+
test_docs_only: commands.test_docs_only ?? defaults.test_docs_only,
|
|
624
|
+
test_incremental: commands.test_incremental ?? defaults.test_incremental,
|
|
625
|
+
lint: commands.lint ?? defaults.lint,
|
|
626
|
+
typecheck: commands.typecheck ?? defaults.typecheck,
|
|
627
|
+
format: commands.format ?? defaults.format,
|
|
628
|
+
};
|
|
629
|
+
}
|
|
630
|
+
catch {
|
|
631
|
+
return defaults;
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* WU-1356: Get ignore patterns for test runner
|
|
636
|
+
*
|
|
637
|
+
* Returns patterns to ignore when detecting changed tests,
|
|
638
|
+
* based on the test runner configuration.
|
|
639
|
+
*
|
|
640
|
+
* @param testRunner - Test runner type (vitest, jest, mocha)
|
|
641
|
+
* @returns Array of ignore patterns
|
|
642
|
+
*/
|
|
643
|
+
export function getIgnorePatterns(testRunner) {
|
|
644
|
+
return IGNORE_PATTERNS_BY_RUNNER[testRunner] ?? ['.turbo'];
|
|
645
|
+
}
|
|
@@ -7,6 +7,68 @@
|
|
|
7
7
|
* @module lumenflow-config-schema
|
|
8
8
|
*/
|
|
9
9
|
import { z } from 'zod';
|
|
10
|
+
/**
|
|
11
|
+
* WU-1356: Package manager options
|
|
12
|
+
*
|
|
13
|
+
* Supported package managers for LumenFlow CLI operations.
|
|
14
|
+
* Used for build commands, dependency installation, and script execution.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```yaml
|
|
18
|
+
* package_manager: npm
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export declare const PackageManagerSchema: z.ZodDefault<z.ZodEnum<{
|
|
22
|
+
pnpm: "pnpm";
|
|
23
|
+
npm: "npm";
|
|
24
|
+
yarn: "yarn";
|
|
25
|
+
bun: "bun";
|
|
26
|
+
}>>;
|
|
27
|
+
/** WU-1356: TypeScript type for package manager */
|
|
28
|
+
export type PackageManager = z.infer<typeof PackageManagerSchema>;
|
|
29
|
+
/**
|
|
30
|
+
* WU-1356: Test runner options
|
|
31
|
+
*
|
|
32
|
+
* Supported test runners for incremental test detection and execution.
|
|
33
|
+
* Determines how changed tests are detected and ignore patterns are derived.
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```yaml
|
|
37
|
+
* test_runner: jest
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export declare const TestRunnerSchema: z.ZodDefault<z.ZodEnum<{
|
|
41
|
+
vitest: "vitest";
|
|
42
|
+
jest: "jest";
|
|
43
|
+
mocha: "mocha";
|
|
44
|
+
}>>;
|
|
45
|
+
/** WU-1356: TypeScript type for test runner */
|
|
46
|
+
export type TestRunner = z.infer<typeof TestRunnerSchema>;
|
|
47
|
+
/**
|
|
48
|
+
* WU-1356: Gates commands configuration
|
|
49
|
+
*
|
|
50
|
+
* Configurable test commands for gates execution.
|
|
51
|
+
* Replaces hard-coded turbo/vitest commands with user-configurable alternatives.
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```yaml
|
|
55
|
+
* gates:
|
|
56
|
+
* commands:
|
|
57
|
+
* test_full: 'npm test'
|
|
58
|
+
* test_docs_only: 'npm test -- --testPathPattern=docs'
|
|
59
|
+
* test_incremental: 'npm test -- --onlyChanged'
|
|
60
|
+
* ```
|
|
61
|
+
*/
|
|
62
|
+
export declare const GatesCommandsConfigSchema: z.ZodObject<{
|
|
63
|
+
test_full: z.ZodDefault<z.ZodString>;
|
|
64
|
+
test_docs_only: z.ZodDefault<z.ZodString>;
|
|
65
|
+
test_incremental: z.ZodDefault<z.ZodString>;
|
|
66
|
+
lint: z.ZodOptional<z.ZodString>;
|
|
67
|
+
typecheck: z.ZodOptional<z.ZodString>;
|
|
68
|
+
format: z.ZodOptional<z.ZodString>;
|
|
69
|
+
}, z.core.$strip>;
|
|
70
|
+
/** WU-1356: TypeScript type for gates commands config */
|
|
71
|
+
export type GatesCommandsConfig = z.infer<typeof GatesCommandsConfigSchema>;
|
|
10
72
|
/**
|
|
11
73
|
* WU-1325: Lock policy for lane-level WIP enforcement
|
|
12
74
|
*
|
|
@@ -172,6 +234,20 @@ export declare const GatesConfigSchema: z.ZodObject<{
|
|
|
172
234
|
threshold: z.ZodOptional<z.ZodNumber>;
|
|
173
235
|
}, z.core.$strip>]>>;
|
|
174
236
|
}, z.core.$strip>>;
|
|
237
|
+
commands: z.ZodDefault<z.ZodObject<{
|
|
238
|
+
test_full: z.ZodDefault<z.ZodString>;
|
|
239
|
+
test_docs_only: z.ZodDefault<z.ZodString>;
|
|
240
|
+
test_incremental: z.ZodDefault<z.ZodString>;
|
|
241
|
+
lint: z.ZodOptional<z.ZodString>;
|
|
242
|
+
typecheck: z.ZodOptional<z.ZodString>;
|
|
243
|
+
format: z.ZodOptional<z.ZodString>;
|
|
244
|
+
}, z.core.$strip>>;
|
|
245
|
+
ignore_patterns: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
246
|
+
lane_health: z.ZodDefault<z.ZodEnum<{
|
|
247
|
+
error: "error";
|
|
248
|
+
off: "off";
|
|
249
|
+
warn: "warn";
|
|
250
|
+
}>>;
|
|
175
251
|
}, z.core.$strip>;
|
|
176
252
|
/**
|
|
177
253
|
* WU-1203: Progress signals configuration for sub-agent coordination
|
|
@@ -357,6 +433,15 @@ export declare const TelemetryConfigSchema: z.ZodObject<{
|
|
|
357
433
|
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
358
434
|
}, z.core.$strip>>;
|
|
359
435
|
}, z.core.$strip>;
|
|
436
|
+
/**
|
|
437
|
+
* WU-1345: Lane enforcement configuration schema
|
|
438
|
+
*
|
|
439
|
+
* Controls how lane format validation behaves.
|
|
440
|
+
*/
|
|
441
|
+
export declare const LanesEnforcementSchema: z.ZodObject<{
|
|
442
|
+
require_parent: z.ZodDefault<z.ZodBoolean>;
|
|
443
|
+
allow_custom: z.ZodDefault<z.ZodBoolean>;
|
|
444
|
+
}, z.core.$strip>;
|
|
360
445
|
/**
|
|
361
446
|
* WU-1322: Lane definition schema for .lumenflow.config.yaml
|
|
362
447
|
*
|
|
@@ -374,6 +459,66 @@ export declare const LaneDefinitionSchema: z.ZodObject<{
|
|
|
374
459
|
}>>>;
|
|
375
460
|
code_paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
376
461
|
}, z.core.$strip>;
|
|
462
|
+
/**
|
|
463
|
+
* WU-1345: Complete lanes configuration schema
|
|
464
|
+
*
|
|
465
|
+
* Supports three formats:
|
|
466
|
+
* 1. definitions array (recommended)
|
|
467
|
+
* 2. engineering + business arrays (legacy/alternate)
|
|
468
|
+
* 3. flat array (simple format - parsed as definitions)
|
|
469
|
+
*
|
|
470
|
+
* @example
|
|
471
|
+
* ```yaml
|
|
472
|
+
* lanes:
|
|
473
|
+
* enforcement:
|
|
474
|
+
* require_parent: true
|
|
475
|
+
* allow_custom: false
|
|
476
|
+
* definitions:
|
|
477
|
+
* - name: 'Framework: Core'
|
|
478
|
+
* wip_limit: 1
|
|
479
|
+
* code_paths:
|
|
480
|
+
* - 'packages/@lumenflow/core/**'
|
|
481
|
+
* ```
|
|
482
|
+
*/
|
|
483
|
+
export declare const LanesConfigSchema: z.ZodObject<{
|
|
484
|
+
enforcement: z.ZodOptional<z.ZodObject<{
|
|
485
|
+
require_parent: z.ZodDefault<z.ZodBoolean>;
|
|
486
|
+
allow_custom: z.ZodDefault<z.ZodBoolean>;
|
|
487
|
+
}, z.core.$strip>>;
|
|
488
|
+
definitions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
489
|
+
name: z.ZodString;
|
|
490
|
+
wip_limit: z.ZodOptional<z.ZodNumber>;
|
|
491
|
+
wip_justification: z.ZodOptional<z.ZodString>;
|
|
492
|
+
lock_policy: z.ZodDefault<z.ZodDefault<z.ZodEnum<{
|
|
493
|
+
none: "none";
|
|
494
|
+
all: "all";
|
|
495
|
+
active: "active";
|
|
496
|
+
}>>>;
|
|
497
|
+
code_paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
498
|
+
}, z.core.$strip>>>;
|
|
499
|
+
engineering: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
500
|
+
name: z.ZodString;
|
|
501
|
+
wip_limit: z.ZodOptional<z.ZodNumber>;
|
|
502
|
+
wip_justification: z.ZodOptional<z.ZodString>;
|
|
503
|
+
lock_policy: z.ZodDefault<z.ZodDefault<z.ZodEnum<{
|
|
504
|
+
none: "none";
|
|
505
|
+
all: "all";
|
|
506
|
+
active: "active";
|
|
507
|
+
}>>>;
|
|
508
|
+
code_paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
509
|
+
}, z.core.$strip>>>;
|
|
510
|
+
business: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
511
|
+
name: z.ZodString;
|
|
512
|
+
wip_limit: z.ZodOptional<z.ZodNumber>;
|
|
513
|
+
wip_justification: z.ZodOptional<z.ZodString>;
|
|
514
|
+
lock_policy: z.ZodDefault<z.ZodDefault<z.ZodEnum<{
|
|
515
|
+
none: "none";
|
|
516
|
+
all: "all";
|
|
517
|
+
active: "active";
|
|
518
|
+
}>>>;
|
|
519
|
+
code_paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
520
|
+
}, z.core.$strip>>>;
|
|
521
|
+
}, z.core.$strip>;
|
|
377
522
|
/**
|
|
378
523
|
* Complete LumenFlow configuration schema
|
|
379
524
|
*/
|
|
@@ -481,6 +626,20 @@ export declare const LumenFlowConfigSchema: z.ZodObject<{
|
|
|
481
626
|
threshold: z.ZodOptional<z.ZodNumber>;
|
|
482
627
|
}, z.core.$strip>]>>;
|
|
483
628
|
}, z.core.$strip>>;
|
|
629
|
+
commands: z.ZodDefault<z.ZodObject<{
|
|
630
|
+
test_full: z.ZodDefault<z.ZodString>;
|
|
631
|
+
test_docs_only: z.ZodDefault<z.ZodString>;
|
|
632
|
+
test_incremental: z.ZodDefault<z.ZodString>;
|
|
633
|
+
lint: z.ZodOptional<z.ZodString>;
|
|
634
|
+
typecheck: z.ZodOptional<z.ZodString>;
|
|
635
|
+
format: z.ZodOptional<z.ZodString>;
|
|
636
|
+
}, z.core.$strip>>;
|
|
637
|
+
ignore_patterns: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
638
|
+
lane_health: z.ZodDefault<z.ZodEnum<{
|
|
639
|
+
error: "error";
|
|
640
|
+
off: "off";
|
|
641
|
+
warn: "warn";
|
|
642
|
+
}>>;
|
|
484
643
|
}, z.core.$strip>>;
|
|
485
644
|
memory: z.ZodDefault<z.ZodObject<{
|
|
486
645
|
directory: z.ZodDefault<z.ZodString>;
|
|
@@ -571,6 +730,57 @@ export declare const LumenFlowConfigSchema: z.ZodObject<{
|
|
|
571
730
|
}>>;
|
|
572
731
|
}, z.core.$strip>>;
|
|
573
732
|
}, z.core.$strip>>;
|
|
733
|
+
lanes: z.ZodOptional<z.ZodObject<{
|
|
734
|
+
enforcement: z.ZodOptional<z.ZodObject<{
|
|
735
|
+
require_parent: z.ZodDefault<z.ZodBoolean>;
|
|
736
|
+
allow_custom: z.ZodDefault<z.ZodBoolean>;
|
|
737
|
+
}, z.core.$strip>>;
|
|
738
|
+
definitions: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
739
|
+
name: z.ZodString;
|
|
740
|
+
wip_limit: z.ZodOptional<z.ZodNumber>;
|
|
741
|
+
wip_justification: z.ZodOptional<z.ZodString>;
|
|
742
|
+
lock_policy: z.ZodDefault<z.ZodDefault<z.ZodEnum<{
|
|
743
|
+
none: "none";
|
|
744
|
+
all: "all";
|
|
745
|
+
active: "active";
|
|
746
|
+
}>>>;
|
|
747
|
+
code_paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
748
|
+
}, z.core.$strip>>>;
|
|
749
|
+
engineering: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
750
|
+
name: z.ZodString;
|
|
751
|
+
wip_limit: z.ZodOptional<z.ZodNumber>;
|
|
752
|
+
wip_justification: z.ZodOptional<z.ZodString>;
|
|
753
|
+
lock_policy: z.ZodDefault<z.ZodDefault<z.ZodEnum<{
|
|
754
|
+
none: "none";
|
|
755
|
+
all: "all";
|
|
756
|
+
active: "active";
|
|
757
|
+
}>>>;
|
|
758
|
+
code_paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
759
|
+
}, z.core.$strip>>>;
|
|
760
|
+
business: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
761
|
+
name: z.ZodString;
|
|
762
|
+
wip_limit: z.ZodOptional<z.ZodNumber>;
|
|
763
|
+
wip_justification: z.ZodOptional<z.ZodString>;
|
|
764
|
+
lock_policy: z.ZodDefault<z.ZodDefault<z.ZodEnum<{
|
|
765
|
+
none: "none";
|
|
766
|
+
all: "all";
|
|
767
|
+
active: "active";
|
|
768
|
+
}>>>;
|
|
769
|
+
code_paths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
770
|
+
}, z.core.$strip>>>;
|
|
771
|
+
}, z.core.$strip>>;
|
|
772
|
+
package_manager: z.ZodDefault<z.ZodEnum<{
|
|
773
|
+
pnpm: "pnpm";
|
|
774
|
+
npm: "npm";
|
|
775
|
+
yarn: "yarn";
|
|
776
|
+
bun: "bun";
|
|
777
|
+
}>>;
|
|
778
|
+
test_runner: z.ZodDefault<z.ZodEnum<{
|
|
779
|
+
vitest: "vitest";
|
|
780
|
+
jest: "jest";
|
|
781
|
+
mocha: "mocha";
|
|
782
|
+
}>>;
|
|
783
|
+
build_command: z.ZodDefault<z.ZodString>;
|
|
574
784
|
}, z.core.$strip>;
|
|
575
785
|
/**
|
|
576
786
|
* TypeScript types inferred from schemas
|
|
@@ -598,6 +808,8 @@ export type MethodologyTelemetryConfig = z.infer<typeof MethodologyTelemetryConf
|
|
|
598
808
|
export type TelemetryConfig = z.infer<typeof TelemetryConfigSchema>;
|
|
599
809
|
export type LumenFlowConfig = z.infer<typeof LumenFlowConfigSchema>;
|
|
600
810
|
export type LaneDefinition = z.infer<typeof LaneDefinitionSchema>;
|
|
811
|
+
export type LanesEnforcement = z.infer<typeof LanesEnforcementSchema>;
|
|
812
|
+
export type LanesConfig = z.infer<typeof LanesConfigSchema>;
|
|
601
813
|
export type { MethodologyConfig, MethodologyOverrides } from './resolve-policy.js';
|
|
602
814
|
/**
|
|
603
815
|
* Validate configuration data
|
|
@@ -677,6 +889,15 @@ export declare function validateConfig(data: unknown): z.ZodSafeParseResult<{
|
|
|
677
889
|
minCoverage: number;
|
|
678
890
|
enableSafetyCriticalTests: boolean;
|
|
679
891
|
enableInvariants: boolean;
|
|
892
|
+
commands: {
|
|
893
|
+
test_full: string;
|
|
894
|
+
test_docs_only: string;
|
|
895
|
+
test_incremental: string;
|
|
896
|
+
lint?: string;
|
|
897
|
+
typecheck?: string;
|
|
898
|
+
format?: string;
|
|
899
|
+
};
|
|
900
|
+
lane_health: "error" | "off" | "warn";
|
|
680
901
|
execution?: {
|
|
681
902
|
preset?: string;
|
|
682
903
|
setup?: string | {
|
|
@@ -709,6 +930,7 @@ export declare function validateConfig(data: unknown): z.ZodSafeParseResult<{
|
|
|
709
930
|
threshold?: number;
|
|
710
931
|
};
|
|
711
932
|
};
|
|
933
|
+
ignore_patterns?: string[];
|
|
712
934
|
};
|
|
713
935
|
memory: {
|
|
714
936
|
directory: string;
|
|
@@ -772,6 +994,9 @@ export declare function validateConfig(data: unknown): z.ZodSafeParseResult<{
|
|
|
772
994
|
enabled: boolean;
|
|
773
995
|
};
|
|
774
996
|
};
|
|
997
|
+
package_manager: "pnpm" | "npm" | "yarn" | "bun";
|
|
998
|
+
test_runner: "vitest" | "jest" | "mocha";
|
|
999
|
+
build_command: string;
|
|
775
1000
|
methodology?: {
|
|
776
1001
|
testing: "tdd" | "test-after" | "none";
|
|
777
1002
|
architecture: "none" | "hexagonal" | "layered";
|
|
@@ -780,6 +1005,33 @@ export declare function validateConfig(data: unknown): z.ZodSafeParseResult<{
|
|
|
780
1005
|
coverage_mode?: "off" | "warn" | "block";
|
|
781
1006
|
};
|
|
782
1007
|
};
|
|
1008
|
+
lanes?: {
|
|
1009
|
+
enforcement?: {
|
|
1010
|
+
require_parent: boolean;
|
|
1011
|
+
allow_custom: boolean;
|
|
1012
|
+
};
|
|
1013
|
+
definitions?: {
|
|
1014
|
+
name: string;
|
|
1015
|
+
lock_policy: "none" | "all" | "active";
|
|
1016
|
+
wip_limit?: number;
|
|
1017
|
+
wip_justification?: string;
|
|
1018
|
+
code_paths?: string[];
|
|
1019
|
+
}[];
|
|
1020
|
+
engineering?: {
|
|
1021
|
+
name: string;
|
|
1022
|
+
lock_policy: "none" | "all" | "active";
|
|
1023
|
+
wip_limit?: number;
|
|
1024
|
+
wip_justification?: string;
|
|
1025
|
+
code_paths?: string[];
|
|
1026
|
+
}[];
|
|
1027
|
+
business?: {
|
|
1028
|
+
name: string;
|
|
1029
|
+
lock_policy: "none" | "all" | "active";
|
|
1030
|
+
wip_limit?: number;
|
|
1031
|
+
wip_justification?: string;
|
|
1032
|
+
code_paths?: string[];
|
|
1033
|
+
}[];
|
|
1034
|
+
};
|
|
783
1035
|
}>;
|
|
784
1036
|
/**
|
|
785
1037
|
* Parse configuration with defaults
|
|
@@ -11,6 +11,77 @@ import { z } from 'zod';
|
|
|
11
11
|
import { GatesExecutionConfigSchema } from './gates-config.js';
|
|
12
12
|
// WU-1259: Import methodology config schema for resolvePolicy()
|
|
13
13
|
import { MethodologyConfigSchema } from './resolve-policy.js';
|
|
14
|
+
/**
|
|
15
|
+
* WU-1356: Package manager options
|
|
16
|
+
*
|
|
17
|
+
* Supported package managers for LumenFlow CLI operations.
|
|
18
|
+
* Used for build commands, dependency installation, and script execution.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```yaml
|
|
22
|
+
* package_manager: npm
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export const PackageManagerSchema = z.enum(['pnpm', 'npm', 'yarn', 'bun']).default('pnpm');
|
|
26
|
+
/**
|
|
27
|
+
* WU-1356: Test runner options
|
|
28
|
+
*
|
|
29
|
+
* Supported test runners for incremental test detection and execution.
|
|
30
|
+
* Determines how changed tests are detected and ignore patterns are derived.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```yaml
|
|
34
|
+
* test_runner: jest
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export const TestRunnerSchema = z.enum(['vitest', 'jest', 'mocha']).default('vitest');
|
|
38
|
+
/**
|
|
39
|
+
* WU-1356: Gates commands configuration
|
|
40
|
+
*
|
|
41
|
+
* Configurable test commands for gates execution.
|
|
42
|
+
* Replaces hard-coded turbo/vitest commands with user-configurable alternatives.
|
|
43
|
+
*
|
|
44
|
+
* @example
|
|
45
|
+
* ```yaml
|
|
46
|
+
* gates:
|
|
47
|
+
* commands:
|
|
48
|
+
* test_full: 'npm test'
|
|
49
|
+
* test_docs_only: 'npm test -- --testPathPattern=docs'
|
|
50
|
+
* test_incremental: 'npm test -- --onlyChanged'
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export const GatesCommandsConfigSchema = z.object({
|
|
54
|
+
/**
|
|
55
|
+
* Command to run full test suite.
|
|
56
|
+
* Default: 'pnpm turbo run test'
|
|
57
|
+
*/
|
|
58
|
+
test_full: z.string().default('pnpm turbo run test'),
|
|
59
|
+
/**
|
|
60
|
+
* Command to run tests in docs-only mode.
|
|
61
|
+
* Default: empty (skip tests in docs-only mode)
|
|
62
|
+
*/
|
|
63
|
+
test_docs_only: z.string().default(''),
|
|
64
|
+
/**
|
|
65
|
+
* Command to run incremental tests (changed files only).
|
|
66
|
+
* Default: 'pnpm vitest run --changed origin/main'
|
|
67
|
+
*/
|
|
68
|
+
test_incremental: z.string().default('pnpm vitest run --changed origin/main'),
|
|
69
|
+
/**
|
|
70
|
+
* Command to run lint checks.
|
|
71
|
+
* Default: 'pnpm lint'
|
|
72
|
+
*/
|
|
73
|
+
lint: z.string().optional(),
|
|
74
|
+
/**
|
|
75
|
+
* Command to run type checks.
|
|
76
|
+
* Default: 'pnpm typecheck'
|
|
77
|
+
*/
|
|
78
|
+
typecheck: z.string().optional(),
|
|
79
|
+
/**
|
|
80
|
+
* Command to run format checks.
|
|
81
|
+
* Default: 'pnpm format:check'
|
|
82
|
+
*/
|
|
83
|
+
format: z.string().optional(),
|
|
84
|
+
});
|
|
14
85
|
/**
|
|
15
86
|
* WU-1325: Lock policy for lane-level WIP enforcement
|
|
16
87
|
*
|
|
@@ -306,6 +377,26 @@ export const GatesConfigSchema = z.object({
|
|
|
306
377
|
* When set, gates runner uses these instead of hardcoded commands.
|
|
307
378
|
*/
|
|
308
379
|
execution: GatesExecutionConfigSchema.optional(),
|
|
380
|
+
/**
|
|
381
|
+
* WU-1356: Configurable gate commands
|
|
382
|
+
* Replaces hard-coded turbo/vitest commands with user-configurable alternatives.
|
|
383
|
+
* Enables LumenFlow to work with npm/yarn/bun, Nx/plain scripts, Jest/Mocha, etc.
|
|
384
|
+
*/
|
|
385
|
+
commands: GatesCommandsConfigSchema.default(() => GatesCommandsConfigSchema.parse({})),
|
|
386
|
+
/**
|
|
387
|
+
* WU-1356: Ignore patterns for test runners
|
|
388
|
+
* Patterns to ignore when detecting changed tests.
|
|
389
|
+
* Default: ['.turbo'] for vitest (derived from test_runner if not specified)
|
|
390
|
+
*/
|
|
391
|
+
ignore_patterns: z.array(z.string()).optional(),
|
|
392
|
+
/**
|
|
393
|
+
* WU-1191: Lane health gate mode
|
|
394
|
+
* Controls how lane health check behaves during gates.
|
|
395
|
+
* - 'warn': Log warning if issues found (default)
|
|
396
|
+
* - 'error': Fail gates if issues found
|
|
397
|
+
* - 'off': Skip lane health check
|
|
398
|
+
*/
|
|
399
|
+
lane_health: z.enum(['warn', 'error', 'off']).default('warn'),
|
|
309
400
|
});
|
|
310
401
|
/**
|
|
311
402
|
* WU-1203: Progress signals configuration for sub-agent coordination
|
|
@@ -582,6 +673,24 @@ export const TelemetryConfigSchema = z.object({
|
|
|
582
673
|
*/
|
|
583
674
|
methodology: MethodologyTelemetryConfigSchema.default(() => MethodologyTelemetryConfigSchema.parse({})),
|
|
584
675
|
});
|
|
676
|
+
/**
|
|
677
|
+
* WU-1345: Lane enforcement configuration schema
|
|
678
|
+
*
|
|
679
|
+
* Controls how lane format validation behaves.
|
|
680
|
+
*/
|
|
681
|
+
export const LanesEnforcementSchema = z.object({
|
|
682
|
+
/**
|
|
683
|
+
* When true, lanes MUST use "Parent: Sublane" format if parent has taxonomy.
|
|
684
|
+
* @default true
|
|
685
|
+
*/
|
|
686
|
+
require_parent: z.boolean().default(true),
|
|
687
|
+
/**
|
|
688
|
+
* When false, only lanes in the taxonomy are allowed.
|
|
689
|
+
* When true, custom lanes can be used.
|
|
690
|
+
* @default false
|
|
691
|
+
*/
|
|
692
|
+
allow_custom: z.boolean().default(false),
|
|
693
|
+
});
|
|
585
694
|
/**
|
|
586
695
|
* WU-1322: Lane definition schema for .lumenflow.config.yaml
|
|
587
696
|
*
|
|
@@ -616,6 +725,37 @@ export const LaneDefinitionSchema = z.object({
|
|
|
616
725
|
/** Code paths associated with this lane (glob patterns) */
|
|
617
726
|
code_paths: z.array(z.string()).optional(),
|
|
618
727
|
});
|
|
728
|
+
/**
|
|
729
|
+
* WU-1345: Complete lanes configuration schema
|
|
730
|
+
*
|
|
731
|
+
* Supports three formats:
|
|
732
|
+
* 1. definitions array (recommended)
|
|
733
|
+
* 2. engineering + business arrays (legacy/alternate)
|
|
734
|
+
* 3. flat array (simple format - parsed as definitions)
|
|
735
|
+
*
|
|
736
|
+
* @example
|
|
737
|
+
* ```yaml
|
|
738
|
+
* lanes:
|
|
739
|
+
* enforcement:
|
|
740
|
+
* require_parent: true
|
|
741
|
+
* allow_custom: false
|
|
742
|
+
* definitions:
|
|
743
|
+
* - name: 'Framework: Core'
|
|
744
|
+
* wip_limit: 1
|
|
745
|
+
* code_paths:
|
|
746
|
+
* - 'packages/@lumenflow/core/**'
|
|
747
|
+
* ```
|
|
748
|
+
*/
|
|
749
|
+
export const LanesConfigSchema = z.object({
|
|
750
|
+
/** Lane enforcement configuration (validation rules) */
|
|
751
|
+
enforcement: LanesEnforcementSchema.optional(),
|
|
752
|
+
/** Primary lane definitions array (recommended format) */
|
|
753
|
+
definitions: z.array(LaneDefinitionSchema).optional(),
|
|
754
|
+
/** Engineering lanes (alternate format) */
|
|
755
|
+
engineering: z.array(LaneDefinitionSchema).optional(),
|
|
756
|
+
/** Business lanes (alternate format) */
|
|
757
|
+
business: z.array(LaneDefinitionSchema).optional(),
|
|
758
|
+
});
|
|
619
759
|
/**
|
|
620
760
|
* Complete LumenFlow configuration schema
|
|
621
761
|
*/
|
|
@@ -663,6 +803,62 @@ export const LumenFlowConfigSchema = z.object({
|
|
|
663
803
|
* ```
|
|
664
804
|
*/
|
|
665
805
|
methodology: MethodologyConfigSchema.optional(),
|
|
806
|
+
/**
|
|
807
|
+
* WU-1345: Lanes configuration
|
|
808
|
+
* Defines delivery lanes with WIP limits, code paths, and lock policies.
|
|
809
|
+
* Required for resolveLaneConfigsFromConfig() to work with getConfig().
|
|
810
|
+
*
|
|
811
|
+
* @example
|
|
812
|
+
* ```yaml
|
|
813
|
+
* lanes:
|
|
814
|
+
* enforcement:
|
|
815
|
+
* require_parent: true
|
|
816
|
+
* allow_custom: false
|
|
817
|
+
* definitions:
|
|
818
|
+
* - name: 'Framework: Core'
|
|
819
|
+
* wip_limit: 1
|
|
820
|
+
* code_paths:
|
|
821
|
+
* - 'packages/@lumenflow/core/**'
|
|
822
|
+
* ```
|
|
823
|
+
*/
|
|
824
|
+
lanes: LanesConfigSchema.optional(),
|
|
825
|
+
/**
|
|
826
|
+
* WU-1356: Package manager for CLI operations
|
|
827
|
+
* Determines which package manager is used for build commands,
|
|
828
|
+
* dependency installation, and script execution.
|
|
829
|
+
*
|
|
830
|
+
* @default 'pnpm'
|
|
831
|
+
*
|
|
832
|
+
* @example
|
|
833
|
+
* ```yaml
|
|
834
|
+
* package_manager: npm
|
|
835
|
+
* ```
|
|
836
|
+
*/
|
|
837
|
+
package_manager: PackageManagerSchema,
|
|
838
|
+
/**
|
|
839
|
+
* WU-1356: Test runner for incremental test detection
|
|
840
|
+
* Determines how changed tests are detected and which ignore patterns to use.
|
|
841
|
+
*
|
|
842
|
+
* @default 'vitest'
|
|
843
|
+
*
|
|
844
|
+
* @example
|
|
845
|
+
* ```yaml
|
|
846
|
+
* test_runner: jest
|
|
847
|
+
* ```
|
|
848
|
+
*/
|
|
849
|
+
test_runner: TestRunnerSchema,
|
|
850
|
+
/**
|
|
851
|
+
* WU-1356: Custom build command for CLI bootstrap
|
|
852
|
+
* Overrides the default build command used in cli-entry.mjs.
|
|
853
|
+
*
|
|
854
|
+
* @default 'pnpm --filter @lumenflow/cli build'
|
|
855
|
+
*
|
|
856
|
+
* @example
|
|
857
|
+
* ```yaml
|
|
858
|
+
* build_command: 'npm run build'
|
|
859
|
+
* ```
|
|
860
|
+
*/
|
|
861
|
+
build_command: z.string().default('pnpm --filter @lumenflow/cli build'),
|
|
666
862
|
});
|
|
667
863
|
/**
|
|
668
864
|
* Validate configuration data
|
package/dist/micro-worktree.d.ts
CHANGED
|
@@ -306,11 +306,16 @@ export declare function mergeWithRetry(tempBranchName: string, microWorktreePath
|
|
|
306
306
|
* Push to origin/main with retry logic for race conditions
|
|
307
307
|
*
|
|
308
308
|
* WU-1179: When push fails because origin/main advanced (race condition with
|
|
309
|
-
* parallel agents), this function
|
|
310
|
-
* retries the full sequence: fetch -> rebase temp branch -> re-merge -> push.
|
|
309
|
+
* parallel agents), this function retries with fetch and rebase.
|
|
311
310
|
*
|
|
312
|
-
*
|
|
313
|
-
*
|
|
311
|
+
* WU-1348: The retry logic no longer resets the main checkout. Instead, it:
|
|
312
|
+
* 1. Fetches origin/main to get latest remote state
|
|
313
|
+
* 2. Rebases the temp branch onto origin/main (in the micro-worktree)
|
|
314
|
+
* 3. Re-merges the rebased temp branch to local main (ff-only)
|
|
315
|
+
* 4. Retries the push
|
|
316
|
+
*
|
|
317
|
+
* This preserves micro-worktree isolation - the main checkout files are never
|
|
318
|
+
* hard-reset, preventing file flash and preserving any uncommitted work.
|
|
314
319
|
*
|
|
315
320
|
* @param {Object} mainGit - GitAdapter instance for main checkout
|
|
316
321
|
* @param {Object} worktreeGit - GitAdapter instance for micro-worktree
|
|
@@ -328,6 +333,15 @@ export declare function pushWithRetry(mainGit: GitAdapter, worktreeGit: GitAdapt
|
|
|
328
333
|
* and supports configuration via PushRetryConfig. When push fails due to
|
|
329
334
|
* non-fast-forward (origin moved), automatically rebases and retries.
|
|
330
335
|
*
|
|
336
|
+
* WU-1348: The retry logic no longer resets the main checkout. Instead, it:
|
|
337
|
+
* 1. Fetches origin/main to get latest remote state
|
|
338
|
+
* 2. Rebases the temp branch onto origin/main (in the micro-worktree)
|
|
339
|
+
* 3. Re-merges the rebased temp branch to local main (ff-only)
|
|
340
|
+
* 4. Retries the push
|
|
341
|
+
*
|
|
342
|
+
* This preserves micro-worktree isolation - the main checkout files are never
|
|
343
|
+
* hard-reset, preventing file flash and preserving any uncommitted work.
|
|
344
|
+
*
|
|
331
345
|
* @param {Object} mainGit - GitAdapter instance for main checkout
|
|
332
346
|
* @param {Object} worktreeGit - GitAdapter instance for micro-worktree
|
|
333
347
|
* @param {string} remote - Remote name (e.g., 'origin')
|
package/dist/micro-worktree.js
CHANGED
|
@@ -518,11 +518,16 @@ export async function mergeWithRetry(tempBranchName, microWorktreePath, logPrefi
|
|
|
518
518
|
* Push to origin/main with retry logic for race conditions
|
|
519
519
|
*
|
|
520
520
|
* WU-1179: When push fails because origin/main advanced (race condition with
|
|
521
|
-
* parallel agents), this function
|
|
522
|
-
* retries the full sequence: fetch -> rebase temp branch -> re-merge -> push.
|
|
521
|
+
* parallel agents), this function retries with fetch and rebase.
|
|
523
522
|
*
|
|
524
|
-
*
|
|
525
|
-
*
|
|
523
|
+
* WU-1348: The retry logic no longer resets the main checkout. Instead, it:
|
|
524
|
+
* 1. Fetches origin/main to get latest remote state
|
|
525
|
+
* 2. Rebases the temp branch onto origin/main (in the micro-worktree)
|
|
526
|
+
* 3. Re-merges the rebased temp branch to local main (ff-only)
|
|
527
|
+
* 4. Retries the push
|
|
528
|
+
*
|
|
529
|
+
* This preserves micro-worktree isolation - the main checkout files are never
|
|
530
|
+
* hard-reset, preventing file flash and preserving any uncommitted work.
|
|
526
531
|
*
|
|
527
532
|
* @param {Object} mainGit - GitAdapter instance for main checkout
|
|
528
533
|
* @param {Object} worktreeGit - GitAdapter instance for micro-worktree
|
|
@@ -544,27 +549,27 @@ export async function pushWithRetry(mainGit, worktreeGit, remote, branch, tempBr
|
|
|
544
549
|
}
|
|
545
550
|
catch (pushErr) {
|
|
546
551
|
if (attempt < maxRetries) {
|
|
547
|
-
console.log(`${logPrefix} ⚠️ Push failed (origin moved).
|
|
548
|
-
//
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
// Step 2: Fetch latest origin/main
|
|
552
|
+
console.log(`${logPrefix} ⚠️ Push failed (origin moved). Fetching and rebasing before retry...`);
|
|
553
|
+
// WU-1348: Do NOT reset main checkout - preserve micro-worktree isolation
|
|
554
|
+
// Instead, fetch latest remote state and rebase the temp branch
|
|
555
|
+
// Step 1: Fetch latest origin/main
|
|
552
556
|
console.log(`${logPrefix} Fetching ${remote}/${branch}...`);
|
|
553
557
|
await mainGit.fetch(remote, branch);
|
|
554
|
-
// Step
|
|
555
|
-
console.log(`${logPrefix}
|
|
556
|
-
await
|
|
557
|
-
// Step
|
|
558
|
-
|
|
559
|
-
await worktreeGit.rebase(branch);
|
|
560
|
-
// Step 5: Re-merge temp branch to local main
|
|
558
|
+
// Step 2: Rebase temp branch onto updated origin/main
|
|
559
|
+
console.log(`${logPrefix} Rebasing temp branch onto ${remote}/${branch}...`);
|
|
560
|
+
await worktreeGit.rebase(`${remote}/${branch}`);
|
|
561
|
+
// Step 3: Re-merge temp branch to local main (ff-only)
|
|
562
|
+
// This updates local main to include the rebased commits
|
|
561
563
|
console.log(`${logPrefix} Re-merging temp branch to ${branch}...`);
|
|
562
564
|
await mainGit.merge(tempBranchName, { ffOnly: true });
|
|
563
565
|
}
|
|
564
566
|
else {
|
|
565
567
|
const errMsg = pushErr instanceof Error ? pushErr.message : String(pushErr);
|
|
566
568
|
throw new Error(`Push failed after ${maxRetries} attempts. ` +
|
|
567
|
-
`Origin ${branch} may have significant traffic.\n` +
|
|
569
|
+
`Origin ${branch} may have significant traffic.\n\n` +
|
|
570
|
+
`Suggestions:\n` +
|
|
571
|
+
` - Wait a few seconds and retry the operation\n` +
|
|
572
|
+
` - Check if another agent is rapidly pushing changes\n` +
|
|
568
573
|
`Error: ${errMsg}`);
|
|
569
574
|
}
|
|
570
575
|
}
|
|
@@ -577,6 +582,15 @@ export async function pushWithRetry(mainGit, worktreeGit, remote, branch, tempBr
|
|
|
577
582
|
* and supports configuration via PushRetryConfig. When push fails due to
|
|
578
583
|
* non-fast-forward (origin moved), automatically rebases and retries.
|
|
579
584
|
*
|
|
585
|
+
* WU-1348: The retry logic no longer resets the main checkout. Instead, it:
|
|
586
|
+
* 1. Fetches origin/main to get latest remote state
|
|
587
|
+
* 2. Rebases the temp branch onto origin/main (in the micro-worktree)
|
|
588
|
+
* 3. Re-merges the rebased temp branch to local main (ff-only)
|
|
589
|
+
* 4. Retries the push
|
|
590
|
+
*
|
|
591
|
+
* This preserves micro-worktree isolation - the main checkout files are never
|
|
592
|
+
* hard-reset, preventing file flash and preserving any uncommitted work.
|
|
593
|
+
*
|
|
580
594
|
* @param {Object} mainGit - GitAdapter instance for main checkout
|
|
581
595
|
* @param {Object} worktreeGit - GitAdapter instance for micro-worktree
|
|
582
596
|
* @param {string} remote - Remote name (e.g., 'origin')
|
|
@@ -603,20 +617,17 @@ export async function pushWithRetryConfig(mainGit, worktreeGit, remote, branch,
|
|
|
603
617
|
console.log(`${logPrefix} ✅ Pushed to ${remote}/${branch}`);
|
|
604
618
|
}
|
|
605
619
|
catch (pushErr) {
|
|
606
|
-
console.log(`${logPrefix} ⚠️ Push failed (origin moved).
|
|
607
|
-
//
|
|
608
|
-
|
|
609
|
-
await mainGit.reset(`${remote}/${branch}`, { hard: true });
|
|
620
|
+
console.log(`${logPrefix} ⚠️ Push failed (origin moved). Fetching and rebasing before retry...`);
|
|
621
|
+
// WU-1348: Do NOT reset main checkout - preserve micro-worktree isolation
|
|
622
|
+
// Instead, fetch latest remote state and rebase the temp branch
|
|
610
623
|
// Fetch latest origin/main
|
|
611
624
|
console.log(`${logPrefix} Fetching ${remote}/${branch}...`);
|
|
612
625
|
await mainGit.fetch(remote, branch);
|
|
613
|
-
//
|
|
614
|
-
console.log(`${logPrefix}
|
|
615
|
-
await
|
|
616
|
-
//
|
|
617
|
-
|
|
618
|
-
await worktreeGit.rebase(branch);
|
|
619
|
-
// Re-merge temp branch to local main
|
|
626
|
+
// Rebase temp branch onto updated origin/main
|
|
627
|
+
console.log(`${logPrefix} Rebasing temp branch onto ${remote}/${branch}...`);
|
|
628
|
+
await worktreeGit.rebase(`${remote}/${branch}`);
|
|
629
|
+
// Re-merge temp branch to local main (ff-only)
|
|
630
|
+
// This updates local main to include the rebased commits
|
|
620
631
|
console.log(`${logPrefix} Re-merging temp branch to ${branch}...`);
|
|
621
632
|
await mainGit.merge(tempBranchName, { ffOnly: true });
|
|
622
633
|
// Re-throw to trigger p-retry
|
|
@@ -627,11 +638,8 @@ export async function pushWithRetryConfig(mainGit, worktreeGit, remote, branch,
|
|
|
627
638
|
minTimeout: config.min_delay_ms,
|
|
628
639
|
maxTimeout: config.max_delay_ms,
|
|
629
640
|
randomize: config.jitter,
|
|
630
|
-
onFailedAttempt: (
|
|
631
|
-
//
|
|
632
|
-
if (error.retriesLeft === 0) {
|
|
633
|
-
// This will be the final failure
|
|
634
|
-
}
|
|
641
|
+
onFailedAttempt: () => {
|
|
642
|
+
// Logging is handled in the try/catch above
|
|
635
643
|
},
|
|
636
644
|
}).catch(() => {
|
|
637
645
|
// p-retry exhausted all retries, throw descriptive error
|
package/dist/wu-constants.d.ts
CHANGED
|
@@ -1718,6 +1718,75 @@ export declare const CONTEXT_VALIDATION: {
|
|
|
1718
1718
|
readonly GATES: "gates";
|
|
1719
1719
|
};
|
|
1720
1720
|
};
|
|
1721
|
+
/**
|
|
1722
|
+
* Git hook error messages (WU-1357)
|
|
1723
|
+
*
|
|
1724
|
+
* Educational, structured messages for git hook blocks.
|
|
1725
|
+
* Follows the "message bag" pattern: TITLE, WHY, ACTIONS, HELP, BYPASS.
|
|
1726
|
+
*
|
|
1727
|
+
* Design principles:
|
|
1728
|
+
* - Explain WHY before showing WHAT to do
|
|
1729
|
+
* - Provide multiple paths forward (not just one command)
|
|
1730
|
+
* - Put emergency bypass LAST with clear warnings
|
|
1731
|
+
* - Include help resources for learning
|
|
1732
|
+
*
|
|
1733
|
+
* @see .husky/hooks/pre-commit.mjs - Primary consumer
|
|
1734
|
+
*/
|
|
1735
|
+
export declare const HOOK_MESSAGES: {
|
|
1736
|
+
/**
|
|
1737
|
+
* Main branch protection block message components
|
|
1738
|
+
*/
|
|
1739
|
+
readonly MAIN_BRANCH_BLOCK: {
|
|
1740
|
+
/** Box drawing for visual structure */
|
|
1741
|
+
readonly BOX: {
|
|
1742
|
+
readonly TOP: "══════════════════════════════════════════════════════════════";
|
|
1743
|
+
readonly DIVIDER: "──────────────────────────────────────────────────────────────";
|
|
1744
|
+
};
|
|
1745
|
+
/** Title shown at the top */
|
|
1746
|
+
readonly TITLE: (branch: string) => string;
|
|
1747
|
+
/** Educational explanation of WHY the block exists */
|
|
1748
|
+
readonly WHY: {
|
|
1749
|
+
readonly HEADER: "WHY THIS HAPPENS";
|
|
1750
|
+
readonly LINES: readonly ["LumenFlow protects main from direct commits to ensure:", " • All work is tracked in Work Units (WUs)", " • Changes can be reviewed and coordinated", " • Parallel work across lanes stays isolated"];
|
|
1751
|
+
};
|
|
1752
|
+
/** Action paths - multiple ways forward */
|
|
1753
|
+
readonly ACTIONS: {
|
|
1754
|
+
readonly HEADER: "WHAT TO DO";
|
|
1755
|
+
readonly HAVE_WU: {
|
|
1756
|
+
readonly HEADER: "1. If you have a Work Unit to implement:";
|
|
1757
|
+
readonly COMMANDS: readonly ["pnpm wu:claim --id WU-XXXX --lane \"<Lane>\"", "cd worktrees/<lane>-wu-xxxx"];
|
|
1758
|
+
readonly NOTE: "Then make your commits there";
|
|
1759
|
+
};
|
|
1760
|
+
readonly NEED_WU: {
|
|
1761
|
+
readonly HEADER: "2. If you need to create a new Work Unit:";
|
|
1762
|
+
readonly COMMANDS: readonly ["pnpm wu:create --lane \"<Lane>\" --title \"Your task\""];
|
|
1763
|
+
readonly NOTE: "This generates a WU ID, then claim it as above";
|
|
1764
|
+
};
|
|
1765
|
+
readonly LIST_LANES: {
|
|
1766
|
+
readonly HEADER: "3. Not sure what lane to use?";
|
|
1767
|
+
readonly COMMANDS: readonly ["pnpm wu:list-lanes"];
|
|
1768
|
+
};
|
|
1769
|
+
};
|
|
1770
|
+
/** Help resources */
|
|
1771
|
+
readonly HELP: {
|
|
1772
|
+
readonly HEADER: "NEED HELP?";
|
|
1773
|
+
readonly RESOURCES: readonly ["• Read: LUMENFLOW.md (workflow overview)", "• Read: docs/04-operations/_frameworks/lumenflow/agent/onboarding/", "• Run: pnpm wu:help"];
|
|
1774
|
+
};
|
|
1775
|
+
/** Emergency bypass (shown last, with warnings) */
|
|
1776
|
+
readonly BYPASS: {
|
|
1777
|
+
readonly HEADER: "EMERGENCY BYPASS (logged, use sparingly)";
|
|
1778
|
+
readonly WARNING: "Bypasses are audit-logged. Only use for genuine emergencies.";
|
|
1779
|
+
readonly COMMAND: "LUMENFLOW_FORCE=1 LUMENFLOW_FORCE_REASON=\"<reason>\" git commit ...";
|
|
1780
|
+
};
|
|
1781
|
+
};
|
|
1782
|
+
/**
|
|
1783
|
+
* Worktree discipline block message components
|
|
1784
|
+
*/
|
|
1785
|
+
readonly WORKTREE_BLOCK: {
|
|
1786
|
+
readonly TITLE: "LANE BRANCH WORK SHOULD BE IN WORKTREE";
|
|
1787
|
+
readonly WHY: "Worktrees provide isolation for parallel work. Working on a lane branch from the main checkout bypasses this isolation.";
|
|
1788
|
+
};
|
|
1789
|
+
};
|
|
1721
1790
|
/** Type for location types */
|
|
1722
1791
|
export type LocationType = (typeof CONTEXT_VALIDATION.LOCATION_TYPES)[keyof typeof CONTEXT_VALIDATION.LOCATION_TYPES];
|
|
1723
1792
|
/** Type for validation error codes */
|
package/dist/wu-constants.js
CHANGED
|
@@ -1789,3 +1789,81 @@ export const CONTEXT_VALIDATION = {
|
|
|
1789
1789
|
GATES: 'gates',
|
|
1790
1790
|
},
|
|
1791
1791
|
};
|
|
1792
|
+
/**
|
|
1793
|
+
* Git hook error messages (WU-1357)
|
|
1794
|
+
*
|
|
1795
|
+
* Educational, structured messages for git hook blocks.
|
|
1796
|
+
* Follows the "message bag" pattern: TITLE, WHY, ACTIONS, HELP, BYPASS.
|
|
1797
|
+
*
|
|
1798
|
+
* Design principles:
|
|
1799
|
+
* - Explain WHY before showing WHAT to do
|
|
1800
|
+
* - Provide multiple paths forward (not just one command)
|
|
1801
|
+
* - Put emergency bypass LAST with clear warnings
|
|
1802
|
+
* - Include help resources for learning
|
|
1803
|
+
*
|
|
1804
|
+
* @see .husky/hooks/pre-commit.mjs - Primary consumer
|
|
1805
|
+
*/
|
|
1806
|
+
export const HOOK_MESSAGES = {
|
|
1807
|
+
/**
|
|
1808
|
+
* Main branch protection block message components
|
|
1809
|
+
*/
|
|
1810
|
+
MAIN_BRANCH_BLOCK: {
|
|
1811
|
+
/** Box drawing for visual structure */
|
|
1812
|
+
BOX: {
|
|
1813
|
+
TOP: '══════════════════════════════════════════════════════════════',
|
|
1814
|
+
DIVIDER: '──────────────────────────────────────────────────────────────',
|
|
1815
|
+
},
|
|
1816
|
+
/** Title shown at the top */
|
|
1817
|
+
TITLE: (branch) => `DIRECT COMMIT TO ${branch.toUpperCase()} BLOCKED`,
|
|
1818
|
+
/** Educational explanation of WHY the block exists */
|
|
1819
|
+
WHY: {
|
|
1820
|
+
HEADER: 'WHY THIS HAPPENS',
|
|
1821
|
+
LINES: [
|
|
1822
|
+
'LumenFlow protects main from direct commits to ensure:',
|
|
1823
|
+
' • All work is tracked in Work Units (WUs)',
|
|
1824
|
+
' • Changes can be reviewed and coordinated',
|
|
1825
|
+
' • Parallel work across lanes stays isolated',
|
|
1826
|
+
],
|
|
1827
|
+
},
|
|
1828
|
+
/** Action paths - multiple ways forward */
|
|
1829
|
+
ACTIONS: {
|
|
1830
|
+
HEADER: 'WHAT TO DO',
|
|
1831
|
+
HAVE_WU: {
|
|
1832
|
+
HEADER: '1. If you have a Work Unit to implement:',
|
|
1833
|
+
COMMANDS: ['pnpm wu:claim --id WU-XXXX --lane "<Lane>"', 'cd worktrees/<lane>-wu-xxxx'],
|
|
1834
|
+
NOTE: 'Then make your commits there',
|
|
1835
|
+
},
|
|
1836
|
+
NEED_WU: {
|
|
1837
|
+
HEADER: '2. If you need to create a new Work Unit:',
|
|
1838
|
+
COMMANDS: ['pnpm wu:create --lane "<Lane>" --title "Your task"'],
|
|
1839
|
+
NOTE: 'This generates a WU ID, then claim it as above',
|
|
1840
|
+
},
|
|
1841
|
+
LIST_LANES: {
|
|
1842
|
+
HEADER: '3. Not sure what lane to use?',
|
|
1843
|
+
COMMANDS: ['pnpm wu:list-lanes'],
|
|
1844
|
+
},
|
|
1845
|
+
},
|
|
1846
|
+
/** Help resources */
|
|
1847
|
+
HELP: {
|
|
1848
|
+
HEADER: 'NEED HELP?',
|
|
1849
|
+
RESOURCES: [
|
|
1850
|
+
'• Read: LUMENFLOW.md (workflow overview)',
|
|
1851
|
+
'• Read: docs/04-operations/_frameworks/lumenflow/agent/onboarding/',
|
|
1852
|
+
'• Run: pnpm wu:help',
|
|
1853
|
+
],
|
|
1854
|
+
},
|
|
1855
|
+
/** Emergency bypass (shown last, with warnings) */
|
|
1856
|
+
BYPASS: {
|
|
1857
|
+
HEADER: 'EMERGENCY BYPASS (logged, use sparingly)',
|
|
1858
|
+
WARNING: 'Bypasses are audit-logged. Only use for genuine emergencies.',
|
|
1859
|
+
COMMAND: 'LUMENFLOW_FORCE=1 LUMENFLOW_FORCE_REASON="<reason>" git commit ...',
|
|
1860
|
+
},
|
|
1861
|
+
},
|
|
1862
|
+
/**
|
|
1863
|
+
* Worktree discipline block message components
|
|
1864
|
+
*/
|
|
1865
|
+
WORKTREE_BLOCK: {
|
|
1866
|
+
TITLE: 'LANE BRANCH WORK SHOULD BE IN WORKTREE',
|
|
1867
|
+
WHY: 'Worktrees provide isolation for parallel work. Working on a lane branch from the main checkout bypasses this isolation.',
|
|
1868
|
+
},
|
|
1869
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumenflow/core",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Core WU lifecycle tools for LumenFlow workflow framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lumenflow",
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"vitest": "^4.0.17"
|
|
100
100
|
},
|
|
101
101
|
"peerDependencies": {
|
|
102
|
-
"@lumenflow/memory": "2.
|
|
102
|
+
"@lumenflow/memory": "2.6.0"
|
|
103
103
|
},
|
|
104
104
|
"peerDependenciesMeta": {
|
|
105
105
|
"@lumenflow/memory": {
|