@lumenflow/core 2.9.0 → 2.11.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/agent-patterns-registry.js +4 -2
- package/dist/arg-parser.js +5 -0
- package/dist/constants/linter-constants.d.ts +1 -1
- package/dist/constants/linter-constants.js +1 -1
- package/dist/docs-path-validator.js +3 -3
- package/dist/domain/context.schemas.d.ts +3 -3
- package/dist/domain/orchestration.constants.d.ts +1 -1
- package/dist/domain/orchestration.constants.js +1 -1
- package/dist/domain/orchestration.types.d.ts +2 -2
- package/dist/domain/validation.schemas.d.ts +4 -4
- package/dist/hardcoded-strings.js +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.js +5 -3
- package/dist/invariants/check-automated-tests.js +3 -1
- package/dist/lumenflow-config-schema.d.ts +5 -5
- package/dist/lumenflow-config-schema.js +5 -5
- package/dist/lumenflow-config.d.ts +1 -1
- package/dist/lumenflow-config.js +7 -7
- package/dist/micro-worktree.d.ts +2 -2
- package/dist/micro-worktree.js +112 -77
- package/dist/orchestration-rules.js +1 -1
- package/dist/prompt-linter.js +5 -5
- package/dist/spawn-escalation.d.ts +2 -2
- package/dist/spawn-escalation.js +7 -3
- package/dist/spawn-monitor.js +3 -1
- package/dist/state-doctor-core.d.ts +29 -1
- package/dist/state-doctor-core.js +142 -2
- package/dist/telemetry.js +3 -3
- package/dist/template-loader.js +6 -3
- package/dist/test-baseline.d.ts +2 -2
- package/dist/test-baseline.js +3 -2
- package/dist/wu-constants.d.ts +69 -57
- package/dist/wu-constants.js +70 -8
- package/dist/wu-create-validators.d.ts +7 -0
- package/dist/wu-create-validators.js +12 -2
- package/dist/wu-done-concurrent-merge.js +2 -2
- package/dist/wu-done-metadata.js +2 -2
- package/dist/wu-done-validation.js +2 -2
- package/dist/wu-done-worktree.js +6 -5
- package/dist/wu-events-cleanup.js +2 -5
- package/dist/wu-list.d.ts +92 -0
- package/dist/wu-list.js +177 -0
- package/dist/wu-paths.js +4 -4
- package/dist/wu-spawn-context.js +3 -2
- package/dist/wu-spawn-skills.js +8 -5
- package/dist/wu-spawn.js +4 -5
- package/package.json +2 -2
- package/dist/beacon-migration.d.ts +0 -56
- package/dist/beacon-migration.js +0 -101
|
@@ -127,7 +127,7 @@ const AGENT_TRIGGER_DESCRIPTIONS = {
|
|
|
127
127
|
// No mandatory agent triggers for LumenFlow framework development.
|
|
128
128
|
// Example for application-specific triggers:
|
|
129
129
|
// 'security-auditor': 'supabase/migrations/**, auth/**, rls/**',
|
|
130
|
-
// '
|
|
130
|
+
// 'llm-reviewer': 'prompts/**, llm/**',
|
|
131
131
|
};
|
|
132
132
|
/**
|
|
133
133
|
* WU-1542: Build a formatted error message for mandatory agent enforcement failures.
|
package/dist/prompt-linter.js
CHANGED
|
@@ -17,14 +17,14 @@ import { resolve, dirname } from 'path';
|
|
|
17
17
|
import { fileURLToPath } from 'url';
|
|
18
18
|
import { glob } from 'glob';
|
|
19
19
|
import yaml from 'yaml';
|
|
20
|
-
import { EXIT_CODES, STRING_LITERALS } from './wu-constants.js';
|
|
20
|
+
import { EXIT_CODES, STRING_LITERALS, LUMENFLOW_PATHS } from './wu-constants.js';
|
|
21
21
|
const __filename = fileURLToPath(import.meta.url);
|
|
22
22
|
const __dirname = dirname(__filename);
|
|
23
23
|
const ROOT_DIR = resolve(__dirname, '../..');
|
|
24
24
|
// Default config path
|
|
25
25
|
const DEFAULT_CONFIG_PATH = resolve(ROOT_DIR, 'config/prompts/linter.yml');
|
|
26
|
-
// Telemetry cache path (for storing previous metrics)
|
|
27
|
-
const METRICS_CACHE_PATH = resolve(ROOT_DIR,
|
|
26
|
+
// Telemetry cache path (for storing previous metrics) - WU-1430: Use centralized constant
|
|
27
|
+
const METRICS_CACHE_PATH = resolve(ROOT_DIR, LUMENFLOW_PATHS.PROMPT_METRICS);
|
|
28
28
|
/**
|
|
29
29
|
* Load config from YAML file with fallback to defaults
|
|
30
30
|
* @param {string} configPath - Path to config file (optional)
|
|
@@ -139,8 +139,8 @@ async function log(level, event, data, output = {}) {
|
|
|
139
139
|
event,
|
|
140
140
|
...data,
|
|
141
141
|
};
|
|
142
|
-
// For CLI, write to
|
|
143
|
-
const ndjsonPath = resolve(ROOT_DIR,
|
|
142
|
+
// For CLI, write to telemetry prompt lint file - WU-1430: Use centralized constant
|
|
143
|
+
const ndjsonPath = resolve(ROOT_DIR, LUMENFLOW_PATHS.PROMPT_LINT);
|
|
144
144
|
const line = `${JSON.stringify(entry)}${STRING_LITERALS.NEWLINE}`;
|
|
145
145
|
try {
|
|
146
146
|
const dir = dirname(ndjsonPath);
|
|
@@ -52,7 +52,7 @@ export declare const SuggestedAction: Readonly<{
|
|
|
52
52
|
*
|
|
53
53
|
* @param {string} spawnId - ID of the stuck spawn
|
|
54
54
|
* @param {Object} options - Options
|
|
55
|
-
* @param {string} options.baseDir - Base directory for .
|
|
55
|
+
* @param {string} options.baseDir - Base directory for .lumenflow/
|
|
56
56
|
* @param {boolean} [options.dryRun=false] - If true, returns signal without sending
|
|
57
57
|
* @returns {Promise<EscalationResult>} Escalation result with signal details
|
|
58
58
|
*
|
|
@@ -66,7 +66,7 @@ export declare const SuggestedAction: Readonly<{
|
|
|
66
66
|
* console.log(`Signal sent: ${result.signalId}, action: ${result.signal.suggested_action}`);
|
|
67
67
|
*/
|
|
68
68
|
export interface EscalateStuckSpawnOptions {
|
|
69
|
-
/** Base directory for .
|
|
69
|
+
/** Base directory for .lumenflow/ */
|
|
70
70
|
baseDir?: string;
|
|
71
71
|
/** If true, return spec only without sending signal */
|
|
72
72
|
dryRun?: boolean;
|
package/dist/spawn-escalation.js
CHANGED
|
@@ -23,6 +23,7 @@ import path from 'node:path';
|
|
|
23
23
|
import { SpawnRegistryStore } from './spawn-registry-store.js';
|
|
24
24
|
import { SpawnStatus } from './spawn-registry-schema.js';
|
|
25
25
|
import { RECOVERY_DIR_NAME } from './spawn-recovery.js';
|
|
26
|
+
import { LUMENFLOW_PATHS } from './wu-constants.js';
|
|
26
27
|
let createSignal = null;
|
|
27
28
|
try {
|
|
28
29
|
const mod = await import('@lumenflow/memory/signal');
|
|
@@ -91,7 +92,8 @@ export const SuggestedAction = Object.freeze({
|
|
|
91
92
|
* @returns {Promise<number>} Number of previous escalation attempts
|
|
92
93
|
*/
|
|
93
94
|
async function countEscalationAttempts(baseDir, spawnId) {
|
|
94
|
-
|
|
95
|
+
// WU-1421: Use LUMENFLOW_PATHS.BASE for consistency
|
|
96
|
+
const recoveryDir = path.join(baseDir, LUMENFLOW_PATHS.BASE, RECOVERY_DIR_NAME);
|
|
95
97
|
try {
|
|
96
98
|
const files = await fs.readdir(recoveryDir);
|
|
97
99
|
const spawnFiles = files.filter((f) => f.startsWith(`${spawnId}-`) && f.endsWith('.json'));
|
|
@@ -138,7 +140,8 @@ function determineEscalationLevel(attempts) {
|
|
|
138
140
|
* @returns {Promise<AuditLogEntry|null>} Audit log entry or null if not found
|
|
139
141
|
*/
|
|
140
142
|
async function findEscalationAuditLog(baseDir, spawnId) {
|
|
141
|
-
|
|
143
|
+
// WU-1421: Use LUMENFLOW_PATHS.BASE for consistency
|
|
144
|
+
const recoveryDir = path.join(baseDir, LUMENFLOW_PATHS.BASE, RECOVERY_DIR_NAME);
|
|
142
145
|
try {
|
|
143
146
|
const files = await fs.readdir(recoveryDir);
|
|
144
147
|
// Filter files for this spawn ID, sorted by name (timestamp-based)
|
|
@@ -188,7 +191,8 @@ function buildSpawnFailureSignal(spawn, auditLog, attempts) {
|
|
|
188
191
|
}
|
|
189
192
|
export async function escalateStuckSpawn(spawnId, options = {}) {
|
|
190
193
|
const { baseDir = process.cwd(), dryRun = false } = options;
|
|
191
|
-
|
|
194
|
+
// WU-1421: Use LUMENFLOW_PATHS.STATE_DIR for consistency
|
|
195
|
+
const registryDir = path.join(baseDir, LUMENFLOW_PATHS.STATE_DIR);
|
|
192
196
|
// Load spawn registry
|
|
193
197
|
const store = new SpawnRegistryStore(registryDir);
|
|
194
198
|
try {
|
package/dist/spawn-monitor.js
CHANGED
|
@@ -26,6 +26,7 @@ import { SpawnStatus } from './spawn-registry-schema.js';
|
|
|
26
26
|
import { isZombieLock, readLockMetadata } from './lane-lock.js';
|
|
27
27
|
import { recoverStuckSpawn, RecoveryAction } from './spawn-recovery.js';
|
|
28
28
|
import { escalateStuckSpawn, SPAWN_FAILURE_SIGNAL_TYPE, SuggestedAction, } from './spawn-escalation.js';
|
|
29
|
+
import { LUMENFLOW_PATHS } from './wu-constants.js';
|
|
29
30
|
let loadSignals = null;
|
|
30
31
|
let markSignalsAsRead = null;
|
|
31
32
|
try {
|
|
@@ -163,7 +164,8 @@ export function detectStuckSpawns(spawns, thresholdMinutes = DEFAULT_THRESHOLD_M
|
|
|
163
164
|
}
|
|
164
165
|
export async function checkZombieLocks(options = {}) {
|
|
165
166
|
const { baseDir = process.cwd() } = options;
|
|
166
|
-
|
|
167
|
+
// WU-1421: Use LUMENFLOW_PATHS.LOCKS_DIR (same as lane-lock.ts) for consistency
|
|
168
|
+
const locksDir = path.join(baseDir, LUMENFLOW_PATHS.LOCKS_DIR);
|
|
167
169
|
const zombies = [];
|
|
168
170
|
try {
|
|
169
171
|
// Check if locks directory exists
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* State Doctor Core (WU-1209)
|
|
2
|
+
* State Doctor Core (WU-1209, WU-1420)
|
|
3
3
|
*
|
|
4
4
|
* Integrity checker for LumenFlow state that detects:
|
|
5
5
|
* - Orphaned WUs (done status but no stamp)
|
|
6
6
|
* - Dangling signals (reference non-existent WUs)
|
|
7
7
|
* - Broken memory relationships (events for missing WU specs)
|
|
8
|
+
* - Status mismatches between WU YAML and state store (WU-1420)
|
|
8
9
|
*
|
|
9
10
|
* Inspired by Beads bd doctor command.
|
|
10
11
|
*
|
|
@@ -27,6 +28,8 @@ export declare const ISSUE_TYPES: {
|
|
|
27
28
|
readonly DANGLING_SIGNAL: "dangling_signal";
|
|
28
29
|
/** Event references a WU that doesn't exist */
|
|
29
30
|
readonly BROKEN_EVENT: "broken_event";
|
|
31
|
+
/** WU YAML status differs from state store derived status (WU-1420) */
|
|
32
|
+
readonly STATUS_MISMATCH: "status_mismatch";
|
|
30
33
|
};
|
|
31
34
|
/**
|
|
32
35
|
* Issue severity levels
|
|
@@ -72,6 +75,25 @@ export interface MockEvent {
|
|
|
72
75
|
wuId: string;
|
|
73
76
|
type: string;
|
|
74
77
|
timestamp?: string;
|
|
78
|
+
lane?: string;
|
|
79
|
+
title?: string;
|
|
80
|
+
reason?: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Event to emit for fixing status mismatches (WU-1420)
|
|
84
|
+
*/
|
|
85
|
+
export interface EmitEventPayload {
|
|
86
|
+
wuId: string;
|
|
87
|
+
type: 'release' | 'complete';
|
|
88
|
+
reason?: string;
|
|
89
|
+
timestamp?: string;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Status mismatch details for fixing (WU-1420)
|
|
93
|
+
*/
|
|
94
|
+
export interface StatusMismatchDetails {
|
|
95
|
+
yamlStatus: string;
|
|
96
|
+
derivedStatus: string;
|
|
75
97
|
}
|
|
76
98
|
/**
|
|
77
99
|
* Dependencies for state doctor (injectable for testing)
|
|
@@ -91,6 +113,8 @@ export interface StateDoctorDeps {
|
|
|
91
113
|
removeEvent?: (wuId: string) => Promise<void>;
|
|
92
114
|
/** Create a stamp for a WU (for --fix) */
|
|
93
115
|
createStamp?: (wuId: string, title: string) => Promise<void>;
|
|
116
|
+
/** Emit an event to fix status mismatch (WU-1420) */
|
|
117
|
+
emitEvent?: (event: EmitEventPayload) => Promise<void>;
|
|
94
118
|
}
|
|
95
119
|
/**
|
|
96
120
|
* A detected issue in the state
|
|
@@ -110,6 +134,8 @@ export interface DiagnosisIssue {
|
|
|
110
134
|
suggestion: string;
|
|
111
135
|
/** Whether this issue can be auto-fixed */
|
|
112
136
|
canAutoFix: boolean;
|
|
137
|
+
/** Status mismatch details for fixing (WU-1420) */
|
|
138
|
+
statusMismatch?: StatusMismatchDetails;
|
|
113
139
|
}
|
|
114
140
|
/**
|
|
115
141
|
* A fix error that occurred during auto-repair
|
|
@@ -134,6 +160,8 @@ export interface DiagnosisSummary {
|
|
|
134
160
|
danglingSignals: number;
|
|
135
161
|
/** Number of broken events */
|
|
136
162
|
brokenEvents: number;
|
|
163
|
+
/** Number of status mismatches (WU-1420) */
|
|
164
|
+
statusMismatches: number;
|
|
137
165
|
/** Total number of issues */
|
|
138
166
|
totalIssues: number;
|
|
139
167
|
}
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* State Doctor Core (WU-1209)
|
|
2
|
+
* State Doctor Core (WU-1209, WU-1420)
|
|
3
3
|
*
|
|
4
4
|
* Integrity checker for LumenFlow state that detects:
|
|
5
5
|
* - Orphaned WUs (done status but no stamp)
|
|
6
6
|
* - Dangling signals (reference non-existent WUs)
|
|
7
7
|
* - Broken memory relationships (events for missing WU specs)
|
|
8
|
+
* - Status mismatches between WU YAML and state store (WU-1420)
|
|
8
9
|
*
|
|
9
10
|
* Inspired by Beads bd doctor command.
|
|
10
11
|
*
|
|
@@ -27,6 +28,8 @@ export const ISSUE_TYPES = {
|
|
|
27
28
|
DANGLING_SIGNAL: 'dangling_signal',
|
|
28
29
|
/** Event references a WU that doesn't exist */
|
|
29
30
|
BROKEN_EVENT: 'broken_event',
|
|
31
|
+
/** WU YAML status differs from state store derived status (WU-1420) */
|
|
32
|
+
STATUS_MISMATCH: 'status_mismatch',
|
|
30
33
|
};
|
|
31
34
|
/**
|
|
32
35
|
* Issue severity levels
|
|
@@ -39,6 +42,86 @@ export const ISSUE_SEVERITY = {
|
|
|
39
42
|
/** Informational findings */
|
|
40
43
|
INFO: 'info',
|
|
41
44
|
};
|
|
45
|
+
/**
|
|
46
|
+
* Derive WU status from events (WU-1420)
|
|
47
|
+
*
|
|
48
|
+
* Replays events to determine the current derived status:
|
|
49
|
+
* - claim/create -> in_progress
|
|
50
|
+
* - release -> ready
|
|
51
|
+
* - complete -> done
|
|
52
|
+
* - block -> blocked
|
|
53
|
+
* - unblock -> in_progress
|
|
54
|
+
*
|
|
55
|
+
* @param events - All events for this WU
|
|
56
|
+
* @returns Derived status or undefined if no events
|
|
57
|
+
*/
|
|
58
|
+
function deriveStatusFromEvents(events) {
|
|
59
|
+
if (events.length === 0) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
let status = undefined;
|
|
63
|
+
for (const event of events) {
|
|
64
|
+
switch (event.type) {
|
|
65
|
+
case 'claim':
|
|
66
|
+
case 'create':
|
|
67
|
+
status = 'in_progress';
|
|
68
|
+
break;
|
|
69
|
+
case 'release':
|
|
70
|
+
status = 'ready';
|
|
71
|
+
break;
|
|
72
|
+
case 'complete':
|
|
73
|
+
status = 'done';
|
|
74
|
+
break;
|
|
75
|
+
case 'block':
|
|
76
|
+
status = 'blocked';
|
|
77
|
+
break;
|
|
78
|
+
case 'unblock':
|
|
79
|
+
status = 'in_progress';
|
|
80
|
+
break;
|
|
81
|
+
// checkpoint doesn't change status
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return status;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Detect status mismatches between WU YAML and state store (WU-1420)
|
|
88
|
+
*
|
|
89
|
+
* Compares the status field in WU YAML against the derived status from events.
|
|
90
|
+
* Only reports issues for WUs that have events in the state store.
|
|
91
|
+
*/
|
|
92
|
+
function detectStatusMismatches(wus, events) {
|
|
93
|
+
const issues = [];
|
|
94
|
+
// Group events by WU ID
|
|
95
|
+
const eventsByWu = new Map();
|
|
96
|
+
for (const event of events) {
|
|
97
|
+
const existing = eventsByWu.get(event.wuId) || [];
|
|
98
|
+
existing.push(event);
|
|
99
|
+
eventsByWu.set(event.wuId, existing);
|
|
100
|
+
}
|
|
101
|
+
for (const wu of wus) {
|
|
102
|
+
const wuEvents = eventsByWu.get(wu.id);
|
|
103
|
+
if (!wuEvents || wuEvents.length === 0) {
|
|
104
|
+
// No events for this WU - nothing to compare
|
|
105
|
+
continue;
|
|
106
|
+
}
|
|
107
|
+
const derivedStatus = deriveStatusFromEvents(wuEvents);
|
|
108
|
+
if (derivedStatus && derivedStatus !== wu.status) {
|
|
109
|
+
issues.push({
|
|
110
|
+
type: ISSUE_TYPES.STATUS_MISMATCH,
|
|
111
|
+
severity: ISSUE_SEVERITY.WARNING,
|
|
112
|
+
wuId: wu.id,
|
|
113
|
+
description: `WU ${wu.id} YAML status is '${wu.status}' but state store says '${derivedStatus}'`,
|
|
114
|
+
suggestion: `Emit corrective event using: pnpm state:doctor --fix`,
|
|
115
|
+
canAutoFix: true,
|
|
116
|
+
statusMismatch: {
|
|
117
|
+
yamlStatus: wu.status,
|
|
118
|
+
derivedStatus,
|
|
119
|
+
},
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return issues;
|
|
124
|
+
}
|
|
42
125
|
/**
|
|
43
126
|
* Detect orphaned WUs (done status but no stamp)
|
|
44
127
|
*/
|
|
@@ -114,6 +197,7 @@ function calculateSummary(issues) {
|
|
|
114
197
|
let orphanedWUs = 0;
|
|
115
198
|
let danglingSignals = 0;
|
|
116
199
|
let brokenEvents = 0;
|
|
200
|
+
let statusMismatches = 0;
|
|
117
201
|
for (const issue of issues) {
|
|
118
202
|
switch (issue.type) {
|
|
119
203
|
case ISSUE_TYPES.ORPHANED_WU:
|
|
@@ -125,15 +209,42 @@ function calculateSummary(issues) {
|
|
|
125
209
|
case ISSUE_TYPES.BROKEN_EVENT:
|
|
126
210
|
brokenEvents++;
|
|
127
211
|
break;
|
|
212
|
+
case ISSUE_TYPES.STATUS_MISMATCH:
|
|
213
|
+
statusMismatches++;
|
|
214
|
+
break;
|
|
128
215
|
}
|
|
129
216
|
}
|
|
130
217
|
return {
|
|
131
218
|
orphanedWUs,
|
|
132
219
|
danglingSignals,
|
|
133
220
|
brokenEvents,
|
|
221
|
+
statusMismatches,
|
|
134
222
|
totalIssues: issues.length,
|
|
135
223
|
};
|
|
136
224
|
}
|
|
225
|
+
/**
|
|
226
|
+
* Determine the corrective event type for a status mismatch (WU-1420)
|
|
227
|
+
*
|
|
228
|
+
* When YAML says X but state says Y, emit event to transition state to X:
|
|
229
|
+
* - YAML=ready, state=in_progress -> emit release
|
|
230
|
+
* - YAML=done, state=in_progress -> emit complete
|
|
231
|
+
* - YAML=in_progress, state=ready -> cannot fix (would need claim with lane/title)
|
|
232
|
+
* - YAML=in_progress, state=done -> cannot fix (cannot un-complete)
|
|
233
|
+
*/
|
|
234
|
+
function getCorrectiveEventType(yamlStatus, derivedStatus) {
|
|
235
|
+
// Transition from in_progress to ready: emit release
|
|
236
|
+
if (yamlStatus === 'ready' && derivedStatus === 'in_progress') {
|
|
237
|
+
return 'release';
|
|
238
|
+
}
|
|
239
|
+
// Transition from in_progress to done: emit complete
|
|
240
|
+
if (yamlStatus === 'done' && derivedStatus === 'in_progress') {
|
|
241
|
+
return 'complete';
|
|
242
|
+
}
|
|
243
|
+
// Other transitions are not auto-fixable by emitting events
|
|
244
|
+
// - ready -> in_progress would need claim (requires lane/title context)
|
|
245
|
+
// - done -> in_progress would need to revert complete (not supported)
|
|
246
|
+
return null;
|
|
247
|
+
}
|
|
137
248
|
/**
|
|
138
249
|
* Attempt to fix an issue
|
|
139
250
|
*/
|
|
@@ -159,6 +270,29 @@ async function fixIssue(issue, deps, wus) {
|
|
|
159
270
|
return { fixed: true };
|
|
160
271
|
}
|
|
161
272
|
return { fixed: false, error: 'No createStamp function provided' };
|
|
273
|
+
case ISSUE_TYPES.STATUS_MISMATCH: {
|
|
274
|
+
if (!deps.emitEvent) {
|
|
275
|
+
return { fixed: false, error: 'No emitEvent function provided' };
|
|
276
|
+
}
|
|
277
|
+
if (!issue.wuId || !issue.statusMismatch) {
|
|
278
|
+
return { fixed: false, error: 'Missing WU ID or status mismatch details' };
|
|
279
|
+
}
|
|
280
|
+
const { yamlStatus, derivedStatus } = issue.statusMismatch;
|
|
281
|
+
const eventType = getCorrectiveEventType(yamlStatus, derivedStatus);
|
|
282
|
+
if (!eventType) {
|
|
283
|
+
return {
|
|
284
|
+
fixed: false,
|
|
285
|
+
error: `Cannot auto-fix: transition from '${derivedStatus}' to '${yamlStatus}' requires manual intervention`,
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
await deps.emitEvent({
|
|
289
|
+
wuId: issue.wuId,
|
|
290
|
+
type: eventType,
|
|
291
|
+
reason: `state:doctor --fix: reconciling state store with YAML status '${yamlStatus}'`,
|
|
292
|
+
timestamp: new Date().toISOString(),
|
|
293
|
+
});
|
|
294
|
+
return { fixed: true };
|
|
295
|
+
}
|
|
162
296
|
default:
|
|
163
297
|
return { fixed: false, error: `Unknown issue type: ${issue.type}` };
|
|
164
298
|
}
|
|
@@ -229,7 +363,13 @@ export async function diagnoseState(_baseDir, deps, options = {}) {
|
|
|
229
363
|
const orphanedWUissues = detectOrphanedWUs(wus, stampIds);
|
|
230
364
|
const danglingSignalIssues = detectDanglingSignals(signals, wuIds);
|
|
231
365
|
const brokenEventIssues = detectBrokenEvents(events, wuIds);
|
|
232
|
-
const
|
|
366
|
+
const statusMismatchIssues = detectStatusMismatches(wus, events);
|
|
367
|
+
const issues = [
|
|
368
|
+
...orphanedWUissues,
|
|
369
|
+
...danglingSignalIssues,
|
|
370
|
+
...brokenEventIssues,
|
|
371
|
+
...statusMismatchIssues,
|
|
372
|
+
];
|
|
233
373
|
const summary = calculateSummary(issues);
|
|
234
374
|
// Initialize result
|
|
235
375
|
const result = {
|
package/dist/telemetry.js
CHANGED
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
import { appendFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
9
9
|
import { execSync } from 'node:child_process';
|
|
10
10
|
import path from 'node:path';
|
|
11
|
-
import {
|
|
12
|
-
const TELEMETRY_DIR =
|
|
11
|
+
import { LUMENFLOW_PATHS, FILE_EXTENSIONS, STDIO, STRING_LITERALS, } from './wu-constants.js';
|
|
12
|
+
const TELEMETRY_DIR = LUMENFLOW_PATHS.TELEMETRY;
|
|
13
13
|
const GATES_LOG = `${TELEMETRY_DIR}/gates${FILE_EXTENSIONS.NDJSON}`;
|
|
14
14
|
const LLM_CLASSIFICATION_LOG = `${TELEMETRY_DIR}/llm-classification${FILE_EXTENSIONS.NDJSON}`;
|
|
15
|
-
const FLOW_LOG =
|
|
15
|
+
const FLOW_LOG = LUMENFLOW_PATHS.FLOW_LOG;
|
|
16
16
|
/**
|
|
17
17
|
* Ensure telemetry directory exists
|
|
18
18
|
*/
|
package/dist/template-loader.js
CHANGED
|
@@ -19,8 +19,10 @@ import { join } from 'node:path';
|
|
|
19
19
|
import matter from 'gray-matter';
|
|
20
20
|
import yaml from 'yaml';
|
|
21
21
|
import { createError, ErrorCodes } from './error-handler.js';
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
import { LUMENFLOW_PATHS } from './wu-constants.js';
|
|
23
|
+
/** WU-1430: Use centralized constants for template paths */
|
|
24
|
+
const MANIFEST_PATH = LUMENFLOW_PATHS.TEMPLATE_MANIFEST;
|
|
25
|
+
const TEMPLATES_DIR = LUMENFLOW_PATHS.SPAWN_PROMPT_DIR;
|
|
24
26
|
/**
|
|
25
27
|
* Validate a template entry from the manifest.
|
|
26
28
|
* @throws If entry is missing required fields
|
|
@@ -172,7 +174,8 @@ export function loadTemplate(templatePath) {
|
|
|
172
174
|
export function loadTemplatesWithOverrides(baseDir, clientName) {
|
|
173
175
|
const templates = new Map();
|
|
174
176
|
const baseTemplatesDir = join(baseDir, TEMPLATES_DIR);
|
|
175
|
-
|
|
177
|
+
// WU-1430: Construct client templates path from constants
|
|
178
|
+
const clientTemplatesDir = join(baseDir, `${LUMENFLOW_PATHS.BASE}/templates.${clientName}/spawn-prompt`);
|
|
176
179
|
// Load base templates first
|
|
177
180
|
if (existsSync(baseTemplatesDir)) {
|
|
178
181
|
loadTemplatesFromDir(baseTemplatesDir, templates);
|
package/dist/test-baseline.d.ts
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
* @see https://lumenflow.dev/reference/test-ratchet/
|
|
14
14
|
*/
|
|
15
15
|
import { z } from 'zod';
|
|
16
|
-
/** Default path for the test baseline file */
|
|
17
|
-
export declare const DEFAULT_BASELINE_PATH
|
|
16
|
+
/** Default path for the test baseline file (WU-1430: Use centralized constant) */
|
|
17
|
+
export declare const DEFAULT_BASELINE_PATH: string;
|
|
18
18
|
/** Environment variable to override baseline path */
|
|
19
19
|
export declare const BASELINE_PATH_ENV = "LUMENFLOW_TEST_BASELINE";
|
|
20
20
|
/** Current schema version */
|
package/dist/test-baseline.js
CHANGED
|
@@ -14,11 +14,12 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import { z } from 'zod';
|
|
16
16
|
import { parseISO, isValid } from 'date-fns';
|
|
17
|
+
import { LUMENFLOW_PATHS } from './wu-constants.js';
|
|
17
18
|
// ============================================================================
|
|
18
19
|
// Constants
|
|
19
20
|
// ============================================================================
|
|
20
|
-
/** Default path for the test baseline file */
|
|
21
|
-
export const DEFAULT_BASELINE_PATH =
|
|
21
|
+
/** Default path for the test baseline file (WU-1430: Use centralized constant) */
|
|
22
|
+
export const DEFAULT_BASELINE_PATH = LUMENFLOW_PATHS.TEST_BASELINE;
|
|
22
23
|
/** Environment variable to override baseline path */
|
|
23
24
|
export const BASELINE_PATH_ENV = 'LUMENFLOW_TEST_BASELINE';
|
|
24
25
|
/** Current schema version */
|
package/dist/wu-constants.d.ts
CHANGED
|
@@ -1021,6 +1021,7 @@ export declare const DIRECTORIES: {
|
|
|
1021
1021
|
WORKTREES: string;
|
|
1022
1022
|
AI: string;
|
|
1023
1023
|
CLAUDE: string;
|
|
1024
|
+
CLAUDE_HOOKS: string;
|
|
1024
1025
|
DOCS: string;
|
|
1025
1026
|
PACKAGES: string;
|
|
1026
1027
|
TOOLS: string;
|
|
@@ -1030,6 +1031,43 @@ export declare const DIRECTORIES: {
|
|
|
1030
1031
|
BACKLOG_PATH: string;
|
|
1031
1032
|
STATUS_PATH: string;
|
|
1032
1033
|
};
|
|
1034
|
+
/**
|
|
1035
|
+
* Claude Code hook script constants (WU-1394)
|
|
1036
|
+
*
|
|
1037
|
+
* Centralized constants for Claude Code enforcement and recovery hooks.
|
|
1038
|
+
* Used by enforcement-generator.ts, enforcement-sync.ts, and init.ts.
|
|
1039
|
+
*
|
|
1040
|
+
* @see packages/@lumenflow/cli/src/hooks/enforcement-generator.ts
|
|
1041
|
+
* @see packages/@lumenflow/cli/src/hooks/enforcement-sync.ts
|
|
1042
|
+
*/
|
|
1043
|
+
export declare const CLAUDE_HOOKS: {
|
|
1044
|
+
/** Hook script filenames */
|
|
1045
|
+
readonly SCRIPTS: {
|
|
1046
|
+
readonly ENFORCE_WORKTREE: "enforce-worktree.sh";
|
|
1047
|
+
readonly REQUIRE_WU: "require-wu.sh";
|
|
1048
|
+
readonly WARN_INCOMPLETE: "warn-incomplete.sh";
|
|
1049
|
+
readonly PRE_COMPACT_CHECKPOINT: "pre-compact-checkpoint.sh";
|
|
1050
|
+
readonly SESSION_START_RECOVERY: "session-start-recovery.sh";
|
|
1051
|
+
};
|
|
1052
|
+
/** Hook command path prefix (uses Claude Code's $CLAUDE_PROJECT_DIR variable) */
|
|
1053
|
+
readonly PATH_PREFIX: "$CLAUDE_PROJECT_DIR/.claude/hooks";
|
|
1054
|
+
/** Hook matchers for settings.json */
|
|
1055
|
+
readonly MATCHERS: {
|
|
1056
|
+
readonly ALL: ".*";
|
|
1057
|
+
readonly WRITE_EDIT: "Write|Edit";
|
|
1058
|
+
readonly COMPACT: "compact";
|
|
1059
|
+
readonly RESUME: "resume";
|
|
1060
|
+
readonly CLEAR: "clear";
|
|
1061
|
+
};
|
|
1062
|
+
/** Template paths (relative to templates directory) */
|
|
1063
|
+
readonly TEMPLATES: {
|
|
1064
|
+
readonly SETTINGS: "vendors/claude/.claude/settings.json.template";
|
|
1065
|
+
readonly PRE_COMPACT: "vendors/claude/.claude/hooks/pre-compact-checkpoint.sh";
|
|
1066
|
+
readonly SESSION_START: "vendors/claude/.claude/hooks/session-start-recovery.sh";
|
|
1067
|
+
};
|
|
1068
|
+
};
|
|
1069
|
+
/** Build full hook command path from script name */
|
|
1070
|
+
export declare const getHookCommand: (scriptName: string) => string;
|
|
1033
1071
|
/**
|
|
1034
1072
|
* ESLint cache strategy values
|
|
1035
1073
|
*/
|
|
@@ -1125,7 +1163,7 @@ export declare const GIT_COMMAND_STRINGS: {
|
|
|
1125
1163
|
export declare const PATH_PATTERNS: {
|
|
1126
1164
|
/** Matches WU YAML paths in both legacy and current locations */
|
|
1127
1165
|
WU_YAML: RegExp;
|
|
1128
|
-
/** Matches stamp file paths
|
|
1166
|
+
/** Matches stamp file paths */
|
|
1129
1167
|
STAMP: RegExp;
|
|
1130
1168
|
};
|
|
1131
1169
|
/**
|
|
@@ -1240,8 +1278,6 @@ export declare const LOCK_DIR_NAME = ".lumenflow-locks";
|
|
|
1240
1278
|
*
|
|
1241
1279
|
* Centralized paths for .lumenflow directory structure to eliminate hardcoded strings.
|
|
1242
1280
|
* Used by telemetry, agent-session, agent-incidents, memory, and commands-logger modules.
|
|
1243
|
-
*
|
|
1244
|
-
* @since 1.4.0 Renamed from BEACON_PATHS (WU-1075)
|
|
1245
1281
|
*/
|
|
1246
1282
|
export declare const LUMENFLOW_PATHS: {
|
|
1247
1283
|
/** Base directory for all LumenFlow runtime data */
|
|
@@ -1250,6 +1286,8 @@ export declare const LUMENFLOW_PATHS: {
|
|
|
1250
1286
|
STATE_DIR: string;
|
|
1251
1287
|
/** Stamp directory (WU completion markers) */
|
|
1252
1288
|
STAMPS_DIR: string;
|
|
1289
|
+
/** Archive directory for old WU events (WU-1430) */
|
|
1290
|
+
ARCHIVE_DIR: string;
|
|
1253
1291
|
/** Merge lock file (runtime coordination, WU-1747) */
|
|
1254
1292
|
MERGE_LOCK: string;
|
|
1255
1293
|
/** Base telemetry directory */
|
|
@@ -1280,60 +1318,30 @@ export declare const LUMENFLOW_PATHS: {
|
|
|
1280
1318
|
LOCKS_DIR: string;
|
|
1281
1319
|
/** Force bypass audit log */
|
|
1282
1320
|
FORCE_BYPASSES: string;
|
|
1283
|
-
/**
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
/**
|
|
1298
|
-
|
|
1299
|
-
*/
|
|
1300
|
-
|
|
1301
|
-
/**
|
|
1302
|
-
|
|
1303
|
-
/**
|
|
1304
|
-
|
|
1305
|
-
/**
|
|
1306
|
-
|
|
1307
|
-
/** Merge lock file (runtime coordination, WU-1747) */
|
|
1308
|
-
MERGE_LOCK: string;
|
|
1309
|
-
/** Base telemetry directory */
|
|
1310
|
-
TELEMETRY: string;
|
|
1311
|
-
/** Flow log file (WU flow events) */
|
|
1312
|
-
FLOW_LOG: string;
|
|
1313
|
-
/** Agent sessions directory */
|
|
1314
|
-
SESSIONS: string;
|
|
1315
|
-
/** Agent incidents directory */
|
|
1316
|
-
INCIDENTS: string;
|
|
1317
|
-
/** Git commands log file */
|
|
1318
|
-
COMMANDS_LOG: string;
|
|
1319
|
-
/** Memory layer directory */
|
|
1320
|
-
MEMORY_DIR: string;
|
|
1321
|
-
/** Memory layer JSONL file */
|
|
1322
|
-
MEMORY_JSONL: string;
|
|
1323
|
-
/** Audit log for tool calls */
|
|
1324
|
-
AUDIT_LOG: string;
|
|
1325
|
-
/** Feedback drafts directory */
|
|
1326
|
-
FEEDBACK_DRAFTS: string;
|
|
1327
|
-
/** Feedback index file */
|
|
1328
|
-
FEEDBACK_INDEX: string;
|
|
1329
|
-
/** Current session file */
|
|
1330
|
-
SESSION_CURRENT: string;
|
|
1331
|
-
/** WU events log */
|
|
1332
|
-
WU_EVENTS: string;
|
|
1333
|
-
/** Lock files directory (lane locks - persisted) */
|
|
1334
|
-
LOCKS_DIR: string;
|
|
1335
|
-
/** Force bypass audit log */
|
|
1336
|
-
FORCE_BYPASSES: string;
|
|
1321
|
+
/** Test baseline file for ratchet pattern (WU-1430) */
|
|
1322
|
+
TEST_BASELINE: string;
|
|
1323
|
+
/** Templates directory (WU-1430) */
|
|
1324
|
+
TEMPLATES_DIR: string;
|
|
1325
|
+
/** Spawn prompt templates (WU-1430) */
|
|
1326
|
+
SPAWN_PROMPT_DIR: string;
|
|
1327
|
+
/** Template manifest file (WU-1430) */
|
|
1328
|
+
TEMPLATE_MANIFEST: string;
|
|
1329
|
+
/** Skills directory for agent skills (WU-1430) */
|
|
1330
|
+
SKILLS_DIR: string;
|
|
1331
|
+
/** Agents directory for agent definitions (WU-1430) */
|
|
1332
|
+
AGENTS_DIR: string;
|
|
1333
|
+
/** Methodology log for spawn telemetry (WU-1430) */
|
|
1334
|
+
METHODOLOGY_LOG: string;
|
|
1335
|
+
/** Prompt metrics cache (WU-1430) */
|
|
1336
|
+
PROMPT_METRICS: string;
|
|
1337
|
+
/** Prompt lint results (WU-1430) */
|
|
1338
|
+
PROMPT_LINT: string;
|
|
1339
|
+
/** Recovery markers directory (WU-1430) */
|
|
1340
|
+
RECOVERY_DIR: string;
|
|
1341
|
+
/** Checkpoints directory (WU-1430) */
|
|
1342
|
+
CHECKPOINTS_DIR: string;
|
|
1343
|
+
/** Cache directory under user home (WU-1430) */
|
|
1344
|
+
HOME_CACHE: string;
|
|
1337
1345
|
/**
|
|
1338
1346
|
* WU-1174: Runtime lock directory for merge/cleanup locks
|
|
1339
1347
|
*
|
|
@@ -1405,6 +1413,10 @@ export declare const PATH_LITERALS: {
|
|
|
1405
1413
|
PLAN_FILE_SUFFIX: string;
|
|
1406
1414
|
/** Trailing slash regex pattern */
|
|
1407
1415
|
TRAILING_SLASH_REGEX: RegExp;
|
|
1416
|
+
/** .lumenflow path prefix for internal path detection (WU-1430) */
|
|
1417
|
+
LUMENFLOW_PREFIX: string;
|
|
1418
|
+
/** Current directory prefix for repo-internal paths (WU-1430) */
|
|
1419
|
+
CURRENT_DIR_PREFIX: string;
|
|
1408
1420
|
};
|
|
1409
1421
|
/**
|
|
1410
1422
|
* Slice lengths for path operations
|