@lumenflow/core 2.10.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 +2 -2
- package/dist/index.js +3 -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 +31 -57
- package/dist/wu-constants.js +32 -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
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
|
@@ -1163,7 +1163,7 @@ export declare const GIT_COMMAND_STRINGS: {
|
|
|
1163
1163
|
export declare const PATH_PATTERNS: {
|
|
1164
1164
|
/** Matches WU YAML paths in both legacy and current locations */
|
|
1165
1165
|
WU_YAML: RegExp;
|
|
1166
|
-
/** Matches stamp file paths
|
|
1166
|
+
/** Matches stamp file paths */
|
|
1167
1167
|
STAMP: RegExp;
|
|
1168
1168
|
};
|
|
1169
1169
|
/**
|
|
@@ -1278,8 +1278,6 @@ export declare const LOCK_DIR_NAME = ".lumenflow-locks";
|
|
|
1278
1278
|
*
|
|
1279
1279
|
* Centralized paths for .lumenflow directory structure to eliminate hardcoded strings.
|
|
1280
1280
|
* Used by telemetry, agent-session, agent-incidents, memory, and commands-logger modules.
|
|
1281
|
-
*
|
|
1282
|
-
* @since 1.4.0 Renamed from BEACON_PATHS (WU-1075)
|
|
1283
1281
|
*/
|
|
1284
1282
|
export declare const LUMENFLOW_PATHS: {
|
|
1285
1283
|
/** Base directory for all LumenFlow runtime data */
|
|
@@ -1288,6 +1286,8 @@ export declare const LUMENFLOW_PATHS: {
|
|
|
1288
1286
|
STATE_DIR: string;
|
|
1289
1287
|
/** Stamp directory (WU completion markers) */
|
|
1290
1288
|
STAMPS_DIR: string;
|
|
1289
|
+
/** Archive directory for old WU events (WU-1430) */
|
|
1290
|
+
ARCHIVE_DIR: string;
|
|
1291
1291
|
/** Merge lock file (runtime coordination, WU-1747) */
|
|
1292
1292
|
MERGE_LOCK: string;
|
|
1293
1293
|
/** Base telemetry directory */
|
|
@@ -1318,60 +1318,30 @@ export declare const LUMENFLOW_PATHS: {
|
|
|
1318
1318
|
LOCKS_DIR: string;
|
|
1319
1319
|
/** Force bypass audit log */
|
|
1320
1320
|
FORCE_BYPASSES: string;
|
|
1321
|
-
/**
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
/**
|
|
1336
|
-
|
|
1337
|
-
*/
|
|
1338
|
-
|
|
1339
|
-
/**
|
|
1340
|
-
|
|
1341
|
-
/**
|
|
1342
|
-
|
|
1343
|
-
/**
|
|
1344
|
-
|
|
1345
|
-
/** Merge lock file (runtime coordination, WU-1747) */
|
|
1346
|
-
MERGE_LOCK: string;
|
|
1347
|
-
/** Base telemetry directory */
|
|
1348
|
-
TELEMETRY: string;
|
|
1349
|
-
/** Flow log file (WU flow events) */
|
|
1350
|
-
FLOW_LOG: string;
|
|
1351
|
-
/** Agent sessions directory */
|
|
1352
|
-
SESSIONS: string;
|
|
1353
|
-
/** Agent incidents directory */
|
|
1354
|
-
INCIDENTS: string;
|
|
1355
|
-
/** Git commands log file */
|
|
1356
|
-
COMMANDS_LOG: string;
|
|
1357
|
-
/** Memory layer directory */
|
|
1358
|
-
MEMORY_DIR: string;
|
|
1359
|
-
/** Memory layer JSONL file */
|
|
1360
|
-
MEMORY_JSONL: string;
|
|
1361
|
-
/** Audit log for tool calls */
|
|
1362
|
-
AUDIT_LOG: string;
|
|
1363
|
-
/** Feedback drafts directory */
|
|
1364
|
-
FEEDBACK_DRAFTS: string;
|
|
1365
|
-
/** Feedback index file */
|
|
1366
|
-
FEEDBACK_INDEX: string;
|
|
1367
|
-
/** Current session file */
|
|
1368
|
-
SESSION_CURRENT: string;
|
|
1369
|
-
/** WU events log */
|
|
1370
|
-
WU_EVENTS: string;
|
|
1371
|
-
/** Lock files directory (lane locks - persisted) */
|
|
1372
|
-
LOCKS_DIR: string;
|
|
1373
|
-
/** Force bypass audit log */
|
|
1374
|
-
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;
|
|
1375
1345
|
/**
|
|
1376
1346
|
* WU-1174: Runtime lock directory for merge/cleanup locks
|
|
1377
1347
|
*
|
|
@@ -1443,6 +1413,10 @@ export declare const PATH_LITERALS: {
|
|
|
1443
1413
|
PLAN_FILE_SUFFIX: string;
|
|
1444
1414
|
/** Trailing slash regex pattern */
|
|
1445
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;
|
|
1446
1420
|
};
|
|
1447
1421
|
/**
|
|
1448
1422
|
* Slice lengths for path operations
|
package/dist/wu-constants.js
CHANGED
|
@@ -1209,8 +1209,8 @@ export const GIT_COMMAND_STRINGS = {
|
|
|
1209
1209
|
export const PATH_PATTERNS = {
|
|
1210
1210
|
/** Matches WU YAML paths in both legacy and current locations */
|
|
1211
1211
|
WU_YAML: /(?:memory-bank|docs\/04-operations)\/tasks\/wu\/(WU-\d+)\.ya?ml$/i,
|
|
1212
|
-
/** Matches stamp file paths
|
|
1213
|
-
STAMP: /\.
|
|
1212
|
+
/** Matches stamp file paths */
|
|
1213
|
+
STAMP: /\.lumenflow\/stamps\/(WU-\d+)\.done$/i,
|
|
1214
1214
|
};
|
|
1215
1215
|
/**
|
|
1216
1216
|
* Common shell commands
|
|
@@ -1324,8 +1324,6 @@ export const LOCK_DIR_NAME = '.lumenflow-locks';
|
|
|
1324
1324
|
*
|
|
1325
1325
|
* Centralized paths for .lumenflow directory structure to eliminate hardcoded strings.
|
|
1326
1326
|
* Used by telemetry, agent-session, agent-incidents, memory, and commands-logger modules.
|
|
1327
|
-
*
|
|
1328
|
-
* @since 1.4.0 Renamed from BEACON_PATHS (WU-1075)
|
|
1329
1327
|
*/
|
|
1330
1328
|
export const LUMENFLOW_PATHS = {
|
|
1331
1329
|
/** Base directory for all LumenFlow runtime data */
|
|
@@ -1334,6 +1332,8 @@ export const LUMENFLOW_PATHS = {
|
|
|
1334
1332
|
STATE_DIR: '.lumenflow/state',
|
|
1335
1333
|
/** Stamp directory (WU completion markers) */
|
|
1336
1334
|
STAMPS_DIR: '.lumenflow/stamps',
|
|
1335
|
+
/** Archive directory for old WU events (WU-1430) */
|
|
1336
|
+
ARCHIVE_DIR: '.lumenflow/archive',
|
|
1337
1337
|
/** Merge lock file (runtime coordination, WU-1747) */
|
|
1338
1338
|
MERGE_LOCK: '.lumenflow/merge.lock',
|
|
1339
1339
|
/** Base telemetry directory */
|
|
@@ -1364,6 +1364,30 @@ export const LUMENFLOW_PATHS = {
|
|
|
1364
1364
|
LOCKS_DIR: '.lumenflow/locks',
|
|
1365
1365
|
/** Force bypass audit log */
|
|
1366
1366
|
FORCE_BYPASSES: '.lumenflow/force-bypasses.log',
|
|
1367
|
+
/** Test baseline file for ratchet pattern (WU-1430) */
|
|
1368
|
+
TEST_BASELINE: '.lumenflow/test-baseline.json',
|
|
1369
|
+
/** Templates directory (WU-1430) */
|
|
1370
|
+
TEMPLATES_DIR: '.lumenflow/templates',
|
|
1371
|
+
/** Spawn prompt templates (WU-1430) */
|
|
1372
|
+
SPAWN_PROMPT_DIR: '.lumenflow/templates/spawn-prompt',
|
|
1373
|
+
/** Template manifest file (WU-1430) */
|
|
1374
|
+
TEMPLATE_MANIFEST: '.lumenflow/templates/manifest.yaml',
|
|
1375
|
+
/** Skills directory for agent skills (WU-1430) */
|
|
1376
|
+
SKILLS_DIR: '.lumenflow/skills',
|
|
1377
|
+
/** Agents directory for agent definitions (WU-1430) */
|
|
1378
|
+
AGENTS_DIR: '.lumenflow/agents',
|
|
1379
|
+
/** Methodology log for spawn telemetry (WU-1430) */
|
|
1380
|
+
METHODOLOGY_LOG: '.lumenflow/telemetry/methodology.ndjson',
|
|
1381
|
+
/** Prompt metrics cache (WU-1430) */
|
|
1382
|
+
PROMPT_METRICS: '.lumenflow/telemetry/prompt-metrics.json',
|
|
1383
|
+
/** Prompt lint results (WU-1430) */
|
|
1384
|
+
PROMPT_LINT: '.lumenflow/telemetry/prompt-lint.ndjson',
|
|
1385
|
+
/** Recovery markers directory (WU-1430) */
|
|
1386
|
+
RECOVERY_DIR: '.lumenflow/recovery',
|
|
1387
|
+
/** Checkpoints directory (WU-1430) */
|
|
1388
|
+
CHECKPOINTS_DIR: '.lumenflow/checkpoints',
|
|
1389
|
+
/** Cache directory under user home (WU-1430) */
|
|
1390
|
+
HOME_CACHE: 'cache',
|
|
1367
1391
|
/**
|
|
1368
1392
|
* WU-1174: Runtime lock directory for merge/cleanup locks
|
|
1369
1393
|
*
|
|
@@ -1378,10 +1402,6 @@ export const LUMENFLOW_PATHS = {
|
|
|
1378
1402
|
*/
|
|
1379
1403
|
LOCK_DIR: path.join(tmpdir(), LOCK_DIR_NAME),
|
|
1380
1404
|
};
|
|
1381
|
-
/**
|
|
1382
|
-
* @deprecated Use LUMENFLOW_PATHS instead. Will be removed in v2.0.
|
|
1383
|
-
*/
|
|
1384
|
-
export const BEACON_PATHS = LUMENFLOW_PATHS;
|
|
1385
1405
|
/**
|
|
1386
1406
|
* File extensions
|
|
1387
1407
|
*
|
|
@@ -1439,6 +1459,10 @@ export const PATH_LITERALS = {
|
|
|
1439
1459
|
PLAN_FILE_SUFFIX: '-plan.md',
|
|
1440
1460
|
/** Trailing slash regex pattern */
|
|
1441
1461
|
TRAILING_SLASH_REGEX: /\/+$/,
|
|
1462
|
+
/** .lumenflow path prefix for internal path detection (WU-1430) */
|
|
1463
|
+
LUMENFLOW_PREFIX: '.lumenflow/',
|
|
1464
|
+
/** Current directory prefix for repo-internal paths (WU-1430) */
|
|
1465
|
+
CURRENT_DIR_PREFIX: './',
|
|
1442
1466
|
};
|
|
1443
1467
|
/**
|
|
1444
1468
|
* Slice lengths for path operations
|
|
@@ -86,6 +86,13 @@ export declare function validateSpecRefs(specRefs: string[]): {
|
|
|
86
86
|
* @returns {boolean} True if any spec_ref is an external path
|
|
87
87
|
*/
|
|
88
88
|
export declare function hasExternalSpecRefs(specRefs: string[]): boolean;
|
|
89
|
+
/**
|
|
90
|
+
* WU-1429: Check if spec_refs is non-empty
|
|
91
|
+
*
|
|
92
|
+
* @param {string[]|undefined} specRefs - Array of spec reference paths
|
|
93
|
+
* @returns {boolean} True if spec_refs contains at least one entry
|
|
94
|
+
*/
|
|
95
|
+
export declare function hasSpecRefs(specRefs: string[] | undefined): boolean;
|
|
89
96
|
/**
|
|
90
97
|
* WU-1062: Normalize all spec_refs paths
|
|
91
98
|
*
|