@lumenflow/core 1.3.4 → 1.3.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adapters/filesystem-metrics.adapter.d.ts +1 -1
- package/dist/adapters/filesystem-metrics.adapter.js +1 -1
- package/dist/beacon-migration.d.ts +56 -0
- package/dist/beacon-migration.js +101 -0
- package/dist/cleanup-lock.js +3 -3
- package/dist/commands-logger.d.ts +2 -2
- package/dist/commands-logger.js +5 -5
- package/dist/core/tool-runner.d.ts +1 -1
- package/dist/core/tool-runner.js +2 -2
- package/dist/docs-path-validator.d.ts +2 -2
- package/dist/docs-path-validator.js +4 -4
- package/dist/domain/orchestration.constants.js +3 -3
- package/dist/force-bypass-audit.d.ts +2 -2
- package/dist/force-bypass-audit.js +8 -7
- package/dist/index.d.ts +2 -0
- package/dist/index.js +4 -0
- package/dist/lane-lock.d.ts +1 -1
- package/dist/lane-lock.js +3 -4
- package/dist/logs-lib.d.ts +2 -2
- package/dist/logs-lib.js +5 -4
- package/dist/lumenflow-config-schema.d.ts +1 -1
- package/dist/lumenflow-config-schema.js +19 -19
- package/dist/lumenflow-config.js +1 -1
- package/dist/merge-lock.js +7 -7
- package/dist/prompt-linter.js +3 -3
- package/dist/prompt-monitor.d.ts +1 -1
- package/dist/prompt-monitor.js +5 -5
- package/dist/rebase-artifact-cleanup.d.ts +1 -1
- package/dist/rebase-artifact-cleanup.js +1 -1
- package/dist/spawn-recovery.d.ts +2 -2
- package/dist/spawn-recovery.js +6 -6
- package/dist/spawn-registry-store.d.ts +2 -2
- package/dist/spawn-registry-store.js +2 -2
- package/dist/spawn-tree.d.ts +2 -2
- package/dist/spawn-tree.js +2 -2
- package/dist/stamp-utils.d.ts +1 -1
- package/dist/stamp-utils.js +1 -1
- package/dist/state-machine.d.ts +1 -0
- package/dist/state-machine.js +2 -1
- package/dist/telemetry.d.ts +1 -1
- package/dist/telemetry.js +1 -1
- package/dist/wu-checkpoint.js +4 -4
- package/dist/wu-consistency-checker.d.ts +22 -2
- package/dist/wu-consistency-checker.js +260 -30
- package/dist/wu-constants.d.ts +67 -4
- package/dist/wu-constants.js +41 -15
- package/dist/wu-done-branch-only.js +2 -2
- package/dist/wu-done-inputs.js +1 -1
- package/dist/wu-done-validation.js +2 -2
- package/dist/wu-done-worktree.js +4 -4
- package/dist/wu-paths.js +1 -1
- package/dist/wu-recovery.d.ts +4 -4
- package/dist/wu-recovery.js +8 -8
- package/dist/wu-repair-core.js +4 -4
- package/dist/wu-spawn-helpers.d.ts +1 -1
- package/dist/wu-spawn-helpers.js +3 -2
- package/dist/wu-spawn.js +7 -7
- package/dist/wu-state-schema.d.ts +24 -1
- package/dist/wu-state-schema.js +13 -0
- package/dist/wu-state-store.d.ts +23 -2
- package/dist/wu-state-store.js +56 -2
- package/package.json +3 -3
- package/dist/spec-branch-helpers.d.ts +0 -118
- package/dist/spec-branch-helpers.js +0 -199
package/dist/wu-recovery.js
CHANGED
|
@@ -25,7 +25,7 @@ import { moveWUToDoneBacklog } from './wu-backlog-updater.js';
|
|
|
25
25
|
import { getGitForCwd } from './git-adapter.js';
|
|
26
26
|
import { createError, ErrorCodes } from './error-handler.js';
|
|
27
27
|
import { rollbackFiles } from './rollback-utils.js';
|
|
28
|
-
import { LOG_PREFIX, EMOJI, WU_STATUS, getProjectRoot } from './wu-constants.js';
|
|
28
|
+
import { LOG_PREFIX, EMOJI, WU_STATUS, getProjectRoot, LUMENFLOW_PATHS, } from './wu-constants.js';
|
|
29
29
|
import { RETRY_PRESETS } from './retry-strategy.js';
|
|
30
30
|
/**
|
|
31
31
|
* WU-1335: Maximum number of recovery attempts before escalating to manual intervention
|
|
@@ -33,24 +33,24 @@ import { RETRY_PRESETS } from './retry-strategy.js';
|
|
|
33
33
|
*/
|
|
34
34
|
export const MAX_RECOVERY_ATTEMPTS = RETRY_PRESETS.recovery.maxAttempts;
|
|
35
35
|
/**
|
|
36
|
-
* WU-1335: Recovery marker subdirectory within .
|
|
36
|
+
* WU-1335: Recovery marker subdirectory within .lumenflow
|
|
37
37
|
*/
|
|
38
38
|
const RECOVERY_MARKER_DIR = 'recovery';
|
|
39
39
|
/**
|
|
40
40
|
* WU-1335: Get the path to the recovery marker file for a WU
|
|
41
41
|
*
|
|
42
42
|
* @param {string} id - WU ID
|
|
43
|
-
* @param {string} [baseDir=process.cwd()] - Base directory for .
|
|
43
|
+
* @param {string} [baseDir=process.cwd()] - Base directory for .lumenflow
|
|
44
44
|
* @returns {string} Path to recovery marker file
|
|
45
45
|
*/
|
|
46
46
|
export function getRecoveryMarkerPath(id, baseDir = process.cwd()) {
|
|
47
|
-
return join(baseDir,
|
|
47
|
+
return join(baseDir, LUMENFLOW_PATHS.BASE, RECOVERY_MARKER_DIR, `${id}.recovery`);
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
50
|
* WU-1335: Get the current recovery attempt count for a WU
|
|
51
51
|
*
|
|
52
52
|
* @param {string} id - WU ID
|
|
53
|
-
* @param {string} [baseDir=process.cwd()] - Base directory for .
|
|
53
|
+
* @param {string} [baseDir=process.cwd()] - Base directory for .lumenflow
|
|
54
54
|
* @returns {number} Current attempt count (0 if no marker exists)
|
|
55
55
|
*/
|
|
56
56
|
export function getRecoveryAttemptCount(id, baseDir = process.cwd()) {
|
|
@@ -71,12 +71,12 @@ export function getRecoveryAttemptCount(id, baseDir = process.cwd()) {
|
|
|
71
71
|
* WU-1335: Increment recovery attempt count for a WU
|
|
72
72
|
*
|
|
73
73
|
* @param {string} id - WU ID
|
|
74
|
-
* @param {string} [baseDir=process.cwd()] - Base directory for .
|
|
74
|
+
* @param {string} [baseDir=process.cwd()] - Base directory for .lumenflow
|
|
75
75
|
* @returns {number} New attempt count
|
|
76
76
|
*/
|
|
77
77
|
export function incrementRecoveryAttempt(id, baseDir = process.cwd()) {
|
|
78
78
|
const markerPath = getRecoveryMarkerPath(id, baseDir);
|
|
79
|
-
const markerDir = join(baseDir,
|
|
79
|
+
const markerDir = join(baseDir, LUMENFLOW_PATHS.BASE, RECOVERY_MARKER_DIR);
|
|
80
80
|
// Ensure directory exists
|
|
81
81
|
if (!existsSync(markerDir)) {
|
|
82
82
|
mkdirSync(markerDir, { recursive: true });
|
|
@@ -95,7 +95,7 @@ export function incrementRecoveryAttempt(id, baseDir = process.cwd()) {
|
|
|
95
95
|
* WU-1335: Clear recovery attempts for a WU (called on successful recovery)
|
|
96
96
|
*
|
|
97
97
|
* @param {string} id - WU ID
|
|
98
|
-
* @param {string} [baseDir=process.cwd()] - Base directory for .
|
|
98
|
+
* @param {string} [baseDir=process.cwd()] - Base directory for .lumenflow
|
|
99
99
|
*/
|
|
100
100
|
export function clearRecoveryAttempts(id, baseDir = process.cwd()) {
|
|
101
101
|
const markerPath = getRecoveryMarkerPath(id, baseDir);
|
package/dist/wu-repair-core.js
CHANGED
|
@@ -21,7 +21,7 @@ import { readWU, writeWU, parseYAML, stringifyYAML } from './wu-yaml.js';
|
|
|
21
21
|
import { WU_PATHS } from './wu-paths.js';
|
|
22
22
|
import { WUStateStore, WU_EVENTS_FILE_NAME } from './wu-state-store.js';
|
|
23
23
|
import { getGitForCwd, createGitForPath } from './git-adapter.js';
|
|
24
|
-
import { EXIT_CODES, LOG_PREFIX, EMOJI, WU_STATUS } from './wu-constants.js';
|
|
24
|
+
import { EXIT_CODES, LOG_PREFIX, EMOJI, WU_STATUS, LUMENFLOW_PATHS, } from './wu-constants.js';
|
|
25
25
|
import { die } from './error-handler.js';
|
|
26
26
|
import { ensureOnMain, ensureMainUpToDate, validateWUIDFormat } from './wu-helpers.js';
|
|
27
27
|
import { withMicroWorktree } from './micro-worktree.js';
|
|
@@ -103,7 +103,7 @@ export async function checkClaimMetadata(id, worktreePath) {
|
|
|
103
103
|
errors.push(`WU YAML not found at: ${wuPath}`);
|
|
104
104
|
}
|
|
105
105
|
// Check state store
|
|
106
|
-
const stateDir = path.join(worktreePath,
|
|
106
|
+
const stateDir = path.join(worktreePath, LUMENFLOW_PATHS.STATE_DIR);
|
|
107
107
|
const eventsPath = path.join(stateDir, WU_EVENTS_FILE_NAME);
|
|
108
108
|
if (existsSync(eventsPath)) {
|
|
109
109
|
try {
|
|
@@ -174,7 +174,7 @@ export async function repairClaimMetadata(id, worktreePath, checkResult) {
|
|
|
174
174
|
// Repair 2: Add claim event to state store if missing
|
|
175
175
|
if (!checkResult.stateStoreHasClaim) {
|
|
176
176
|
try {
|
|
177
|
-
const stateDir = path.join(worktreePath,
|
|
177
|
+
const stateDir = path.join(worktreePath, LUMENFLOW_PATHS.STATE_DIR);
|
|
178
178
|
const eventsPath = path.join(stateDir, WU_EVENTS_FILE_NAME);
|
|
179
179
|
// Ensure directory exists
|
|
180
180
|
mkdirSync(stateDir, { recursive: true });
|
|
@@ -201,7 +201,7 @@ export async function repairClaimMetadata(id, worktreePath, checkResult) {
|
|
|
201
201
|
const gitWorktree = createGitForPath(worktreePath);
|
|
202
202
|
// Stage repaired files
|
|
203
203
|
const filesToStage = [wuPath];
|
|
204
|
-
const stateDir = path.join(worktreePath,
|
|
204
|
+
const stateDir = path.join(worktreePath, LUMENFLOW_PATHS.STATE_DIR);
|
|
205
205
|
const eventsPath = path.join(stateDir, WU_EVENTS_FILE_NAME);
|
|
206
206
|
if (existsSync(eventsPath)) {
|
|
207
207
|
filesToStage.push(eventsPath);
|
|
@@ -79,7 +79,7 @@ export declare function getHelpText(): string;
|
|
|
79
79
|
* @param {string} options.parentWuId - Parent WU ID (orchestrator)
|
|
80
80
|
* @param {string} options.targetWuId - Target WU ID (spawned work)
|
|
81
81
|
* @param {string} options.lane - Lane for the spawned work
|
|
82
|
-
* @param {string} [options.baseDir] - Base directory for registry (defaults to .
|
|
82
|
+
* @param {string} [options.baseDir] - Base directory for registry (defaults to LUMENFLOW_PATHS.STATE_DIR)
|
|
83
83
|
* @returns {Promise<{success: boolean, spawnId: string|null, error?: string}>}
|
|
84
84
|
*
|
|
85
85
|
* @example
|
package/dist/wu-spawn-helpers.js
CHANGED
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
*/
|
|
13
13
|
import { Command } from 'commander';
|
|
14
14
|
import { SpawnRegistryStore } from './spawn-registry-store.js';
|
|
15
|
+
import { LUMENFLOW_PATHS } from './wu-constants.js';
|
|
15
16
|
/**
|
|
16
17
|
* Option definitions for thinking mode configuration.
|
|
17
18
|
*
|
|
@@ -210,7 +211,7 @@ const LOG_PREFIX = '[wu:spawn]';
|
|
|
210
211
|
* @param {string} options.parentWuId - Parent WU ID (orchestrator)
|
|
211
212
|
* @param {string} options.targetWuId - Target WU ID (spawned work)
|
|
212
213
|
* @param {string} options.lane - Lane for the spawned work
|
|
213
|
-
* @param {string} [options.baseDir] - Base directory for registry (defaults to .
|
|
214
|
+
* @param {string} [options.baseDir] - Base directory for registry (defaults to LUMENFLOW_PATHS.STATE_DIR)
|
|
214
215
|
* @returns {Promise<{success: boolean, spawnId: string|null, error?: string}>}
|
|
215
216
|
*
|
|
216
217
|
* @example
|
|
@@ -225,7 +226,7 @@ const LOG_PREFIX = '[wu:spawn]';
|
|
|
225
226
|
* }
|
|
226
227
|
*/
|
|
227
228
|
export async function recordSpawnToRegistry(options) {
|
|
228
|
-
const { parentWuId, targetWuId, lane, baseDir =
|
|
229
|
+
const { parentWuId, targetWuId, lane, baseDir = LUMENFLOW_PATHS.STATE_DIR } = options;
|
|
229
230
|
try {
|
|
230
231
|
const store = new SpawnRegistryStore(baseDir);
|
|
231
232
|
await store.load();
|
package/dist/wu-spawn.js
CHANGED
|
@@ -34,7 +34,7 @@ import { createWUParser, WU_OPTIONS } from './arg-parser.js';
|
|
|
34
34
|
import { WU_PATHS } from './wu-paths.js';
|
|
35
35
|
import { parseYAML } from './wu-yaml.js';
|
|
36
36
|
import { die } from './error-handler.js';
|
|
37
|
-
import { WU_STATUS, PATTERNS, EMOJI } from './wu-constants.js';
|
|
37
|
+
import { WU_STATUS, PATTERNS, EMOJI, LUMENFLOW_PATHS } from './wu-constants.js';
|
|
38
38
|
// WU-1603: Check lane lock status before spawning
|
|
39
39
|
import { checkLaneLock } from './lane-lock.js';
|
|
40
40
|
import { minimatch } from 'minimatch';
|
|
@@ -650,7 +650,7 @@ git rev-parse --show-toplevel
|
|
|
650
650
|
|
|
651
651
|
### Stamp Creation
|
|
652
652
|
|
|
653
|
-
When creating \`.
|
|
653
|
+
When creating \`.lumenflow/\` stamps or other artifacts:
|
|
654
654
|
|
|
655
655
|
1. **ALWAYS** create stamps in the **worktree**, not main
|
|
656
656
|
2. Use \`git rev-parse --show-toplevel\` to get the correct base path
|
|
@@ -659,11 +659,11 @@ When creating \`.beacon/\` stamps or other artifacts:
|
|
|
659
659
|
\`\`\`bash
|
|
660
660
|
# CORRECT: Create stamp in worktree
|
|
661
661
|
WORKTREE_ROOT=$(git rev-parse --show-toplevel)
|
|
662
|
-
mkdir -p "$WORKTREE_ROOT/.
|
|
663
|
-
touch "$WORKTREE_ROOT/.
|
|
662
|
+
mkdir -p "$WORKTREE_ROOT/.lumenflow/agent-runs"
|
|
663
|
+
touch "$WORKTREE_ROOT/.lumenflow/agent-runs/beacon-guardian.stamp"
|
|
664
664
|
|
|
665
665
|
# WRONG: Hardcoded path to main
|
|
666
|
-
# touch /path/to/main/.
|
|
666
|
+
# touch /path/to/main/.lumenflow/agent-runs/beacon-guardian.stamp
|
|
667
667
|
\`\`\`
|
|
668
668
|
|
|
669
669
|
### Why This Matters
|
|
@@ -789,7 +789,7 @@ cd worktrees/${laneSlug}-${id.toLowerCase()}
|
|
|
789
789
|
Then implement following all standards above.
|
|
790
790
|
|
|
791
791
|
**CRITICAL:** Never use \`git worktree add\` directly. Always use \`pnpm wu:claim\` to ensure:
|
|
792
|
-
- Event tracking in .
|
|
792
|
+
- Event tracking in ${LUMENFLOW_PATHS.WU_EVENTS}
|
|
793
793
|
- Lane lock acquisition (WIP=1 enforcement)
|
|
794
794
|
- Session tracking for context recovery`;
|
|
795
795
|
}
|
|
@@ -1229,7 +1229,7 @@ async function main() {
|
|
|
1229
1229
|
parentWuId: args.parentWu,
|
|
1230
1230
|
targetWuId: id,
|
|
1231
1231
|
lane: doc.lane || 'Unknown',
|
|
1232
|
-
baseDir:
|
|
1232
|
+
baseDir: LUMENFLOW_PATHS.STATE_DIR,
|
|
1233
1233
|
});
|
|
1234
1234
|
const registryMessage = formatSpawnRecordedMessage(registryResult.spawnId, registryResult.error);
|
|
1235
1235
|
console.log(`\n${registryMessage}`);
|
|
@@ -17,8 +17,9 @@ import { z } from 'zod';
|
|
|
17
17
|
* - complete: WU completed (transitions to done)
|
|
18
18
|
* - checkpoint: Progress checkpoint (WU-1748: cross-agent visibility)
|
|
19
19
|
* - spawn: WU spawned from parent (WU-1947: parent-child relationships)
|
|
20
|
+
* - release: WU released (WU-1080: transitions from in_progress to ready for orphan recovery)
|
|
20
21
|
*/
|
|
21
|
-
export declare const WU_EVENT_TYPES: readonly ["create", "claim", "block", "unblock", "complete", "checkpoint", "spawn"];
|
|
22
|
+
export declare const WU_EVENT_TYPES: readonly ["create", "claim", "block", "unblock", "complete", "checkpoint", "spawn", "release"];
|
|
22
23
|
/** Type for WU event types */
|
|
23
24
|
export type WUEventType = (typeof WU_EVENT_TYPES)[number];
|
|
24
25
|
/**
|
|
@@ -103,6 +104,17 @@ export declare const SpawnEventSchema: z.ZodObject<{
|
|
|
103
104
|
parentWuId: z.ZodString;
|
|
104
105
|
spawnId: z.ZodString;
|
|
105
106
|
}, z.core.$strip>;
|
|
107
|
+
/**
|
|
108
|
+
* Release event schema (WU-1080: orphan recovery)
|
|
109
|
+
* Releases an in_progress WU back to ready state when agent is interrupted.
|
|
110
|
+
* Allows another agent to reclaim the orphaned WU.
|
|
111
|
+
*/
|
|
112
|
+
export declare const ReleaseEventSchema: z.ZodObject<{
|
|
113
|
+
wuId: z.ZodString;
|
|
114
|
+
timestamp: z.ZodString;
|
|
115
|
+
type: z.ZodLiteral<"release">;
|
|
116
|
+
reason: z.ZodString;
|
|
117
|
+
}, z.core.$strip>;
|
|
106
118
|
/**
|
|
107
119
|
* Union schema for all event types
|
|
108
120
|
*/
|
|
@@ -145,6 +157,11 @@ export declare const WUEventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
145
157
|
type: z.ZodLiteral<"spawn">;
|
|
146
158
|
parentWuId: z.ZodString;
|
|
147
159
|
spawnId: z.ZodString;
|
|
160
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
161
|
+
wuId: z.ZodString;
|
|
162
|
+
timestamp: z.ZodString;
|
|
163
|
+
type: z.ZodLiteral<"release">;
|
|
164
|
+
reason: z.ZodString;
|
|
148
165
|
}, z.core.$strip>], "type">;
|
|
149
166
|
/**
|
|
150
167
|
* TypeScript types inferred from schemas
|
|
@@ -156,6 +173,7 @@ export type UnblockEvent = z.infer<typeof UnblockEventSchema>;
|
|
|
156
173
|
export type CompleteEvent = z.infer<typeof CompleteEventSchema>;
|
|
157
174
|
export type CheckpointEvent = z.infer<typeof CheckpointEventSchema>;
|
|
158
175
|
export type SpawnEvent = z.infer<typeof SpawnEventSchema>;
|
|
176
|
+
export type ReleaseEvent = z.infer<typeof ReleaseEventSchema>;
|
|
159
177
|
export type WUEvent = z.infer<typeof WUEventSchema>;
|
|
160
178
|
/**
|
|
161
179
|
* Validates WU event data against schema
|
|
@@ -210,4 +228,9 @@ export declare function validateWUEvent(data: any): z.ZodSafeParseResult<{
|
|
|
210
228
|
type: "spawn";
|
|
211
229
|
parentWuId: string;
|
|
212
230
|
spawnId: string;
|
|
231
|
+
} | {
|
|
232
|
+
wuId: string;
|
|
233
|
+
timestamp: string;
|
|
234
|
+
type: "release";
|
|
235
|
+
reason: string;
|
|
213
236
|
}>;
|
package/dist/wu-state-schema.js
CHANGED
|
@@ -17,6 +17,7 @@ import { z } from 'zod';
|
|
|
17
17
|
* - complete: WU completed (transitions to done)
|
|
18
18
|
* - checkpoint: Progress checkpoint (WU-1748: cross-agent visibility)
|
|
19
19
|
* - spawn: WU spawned from parent (WU-1947: parent-child relationships)
|
|
20
|
+
* - release: WU released (WU-1080: transitions from in_progress to ready for orphan recovery)
|
|
20
21
|
*/
|
|
21
22
|
export const WU_EVENT_TYPES = [
|
|
22
23
|
'create',
|
|
@@ -26,6 +27,7 @@ export const WU_EVENT_TYPES = [
|
|
|
26
27
|
'complete',
|
|
27
28
|
'checkpoint',
|
|
28
29
|
'spawn',
|
|
30
|
+
'release',
|
|
29
31
|
];
|
|
30
32
|
/**
|
|
31
33
|
* WU status values (matches LumenFlow state machine)
|
|
@@ -125,6 +127,16 @@ export const SpawnEventSchema = BaseEventSchema.extend({
|
|
|
125
127
|
/** Unique spawn identifier */
|
|
126
128
|
spawnId: z.string().min(1, { message: 'Spawn ID is required' }),
|
|
127
129
|
});
|
|
130
|
+
/**
|
|
131
|
+
* Release event schema (WU-1080: orphan recovery)
|
|
132
|
+
* Releases an in_progress WU back to ready state when agent is interrupted.
|
|
133
|
+
* Allows another agent to reclaim the orphaned WU.
|
|
134
|
+
*/
|
|
135
|
+
export const ReleaseEventSchema = BaseEventSchema.extend({
|
|
136
|
+
type: z.literal('release'),
|
|
137
|
+
/** Reason for releasing the WU */
|
|
138
|
+
reason: z.string().min(1, { message: ERROR_MESSAGES.REASON_REQUIRED }),
|
|
139
|
+
});
|
|
128
140
|
/**
|
|
129
141
|
* Union schema for all event types
|
|
130
142
|
*/
|
|
@@ -136,6 +148,7 @@ export const WUEventSchema = z.discriminatedUnion('type', [
|
|
|
136
148
|
CompleteEventSchema,
|
|
137
149
|
CheckpointEventSchema,
|
|
138
150
|
SpawnEventSchema,
|
|
151
|
+
ReleaseEventSchema,
|
|
139
152
|
]);
|
|
140
153
|
/**
|
|
141
154
|
* Validates WU event data against schema
|
package/dist/wu-state-store.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* WU State Store (WU-1570, WU-2240)
|
|
3
3
|
*
|
|
4
4
|
* Event-sourced state store for WU lifecycle following INIT-007 pattern.
|
|
5
|
-
* Stores events in .
|
|
5
|
+
* Stores events in .lumenflow/state/wu-events.jsonl (append-only, git-friendly).
|
|
6
6
|
*
|
|
7
7
|
* Features:
|
|
8
8
|
* - Event sourcing with replay for current state
|
|
@@ -217,6 +217,27 @@ export declare class WUStateStore {
|
|
|
217
217
|
* await store.spawn('WU-200', 'WU-100', 'spawn-abc123');
|
|
218
218
|
*/
|
|
219
219
|
spawn(childWuId: string, parentWuId: string, spawnId: string): Promise<void>;
|
|
220
|
+
/**
|
|
221
|
+
* Releases an in_progress WU back to ready state (WU-1080: orphan recovery).
|
|
222
|
+
*
|
|
223
|
+
* Use this when an agent is interrupted mid-WU and the WU needs to be
|
|
224
|
+
* made available for reclaiming by another agent.
|
|
225
|
+
*
|
|
226
|
+
* @throws Error If WU is not in_progress
|
|
227
|
+
*
|
|
228
|
+
* @example
|
|
229
|
+
* await store.release('WU-1080', 'Agent interrupted mid-WU');
|
|
230
|
+
*/
|
|
231
|
+
release(wuId: string, reason: string): Promise<void>;
|
|
232
|
+
/**
|
|
233
|
+
* Create a release event without writing to disk.
|
|
234
|
+
*
|
|
235
|
+
* Used by transactional flows where event log writes are staged and committed atomically.
|
|
236
|
+
* WU-1080: Orphan recovery support.
|
|
237
|
+
*
|
|
238
|
+
* @throws Error If WU is not in_progress or event fails validation
|
|
239
|
+
*/
|
|
240
|
+
createReleaseEvent(wuId: string, reason: string, timestamp?: string): WUEvent;
|
|
220
241
|
}
|
|
221
242
|
/**
|
|
222
243
|
* Check if a lock is stale (expired or dead process)
|
|
@@ -255,7 +276,7 @@ export declare function releaseLock(lockPath: string): void;
|
|
|
255
276
|
* - Returns detailed repair statistics
|
|
256
277
|
*
|
|
257
278
|
* @example
|
|
258
|
-
* const stateFilePath = path.join(process.cwd(), '.
|
|
279
|
+
* const stateFilePath = path.join(process.cwd(), '.lumenflow', 'state', 'wu-events.jsonl');
|
|
259
280
|
* const result = await repairStateFile(stateFilePath);
|
|
260
281
|
* if (result.success) {
|
|
261
282
|
* console.log(`Repaired: kept ${result.linesKept}, removed ${result.linesRemoved}`);
|
package/dist/wu-state-store.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* WU State Store (WU-1570, WU-2240)
|
|
3
3
|
*
|
|
4
4
|
* Event-sourced state store for WU lifecycle following INIT-007 pattern.
|
|
5
|
-
* Stores events in .
|
|
5
|
+
* Stores events in .lumenflow/state/wu-events.jsonl (append-only, git-friendly).
|
|
6
6
|
*
|
|
7
7
|
* Features:
|
|
8
8
|
* - Event sourcing with replay for current state
|
|
@@ -171,6 +171,11 @@ export class WUStateStore {
|
|
|
171
171
|
this.byParent.set(parentWuId, new Set());
|
|
172
172
|
}
|
|
173
173
|
this.byParent.get(parentWuId).add(wuId);
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
// WU-1080: Handle release event - transitions from in_progress to ready
|
|
177
|
+
if (type === 'release') {
|
|
178
|
+
this._transitionToStatus(wuId, 'ready');
|
|
174
179
|
}
|
|
175
180
|
}
|
|
176
181
|
/**
|
|
@@ -446,6 +451,55 @@ export class WUStateStore {
|
|
|
446
451
|
await this._appendEvent(event);
|
|
447
452
|
this._applyEvent(event);
|
|
448
453
|
}
|
|
454
|
+
/**
|
|
455
|
+
* Releases an in_progress WU back to ready state (WU-1080: orphan recovery).
|
|
456
|
+
*
|
|
457
|
+
* Use this when an agent is interrupted mid-WU and the WU needs to be
|
|
458
|
+
* made available for reclaiming by another agent.
|
|
459
|
+
*
|
|
460
|
+
* @throws Error If WU is not in_progress
|
|
461
|
+
*
|
|
462
|
+
* @example
|
|
463
|
+
* await store.release('WU-1080', 'Agent interrupted mid-WU');
|
|
464
|
+
*/
|
|
465
|
+
async release(wuId, reason) {
|
|
466
|
+
// Check state machine: can only release if in_progress
|
|
467
|
+
const currentState = this.wuState.get(wuId);
|
|
468
|
+
if (!currentState || currentState.status !== 'in_progress') {
|
|
469
|
+
throw new Error(`WU ${wuId} is not in_progress`);
|
|
470
|
+
}
|
|
471
|
+
const event = {
|
|
472
|
+
type: 'release',
|
|
473
|
+
wuId,
|
|
474
|
+
reason,
|
|
475
|
+
timestamp: new Date().toISOString(),
|
|
476
|
+
};
|
|
477
|
+
await this._appendEvent(event);
|
|
478
|
+
this._applyEvent(event);
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Create a release event without writing to disk.
|
|
482
|
+
*
|
|
483
|
+
* Used by transactional flows where event log writes are staged and committed atomically.
|
|
484
|
+
* WU-1080: Orphan recovery support.
|
|
485
|
+
*
|
|
486
|
+
* @throws Error If WU is not in_progress or event fails validation
|
|
487
|
+
*/
|
|
488
|
+
createReleaseEvent(wuId, reason, timestamp = new Date().toISOString()) {
|
|
489
|
+
const currentState = this.wuState.get(wuId);
|
|
490
|
+
if (!currentState || currentState.status !== 'in_progress') {
|
|
491
|
+
throw new Error(`WU ${wuId} is not in_progress`);
|
|
492
|
+
}
|
|
493
|
+
const event = { type: 'release', wuId, reason, timestamp };
|
|
494
|
+
const validation = validateWUEvent(event);
|
|
495
|
+
if (!validation.success) {
|
|
496
|
+
const issues = validation.error.issues
|
|
497
|
+
.map((issue) => `${issue.path.join('.')}: ${issue.message}`)
|
|
498
|
+
.join(', ');
|
|
499
|
+
throw new Error(`Validation error: ${issues}`);
|
|
500
|
+
}
|
|
501
|
+
return validation.data;
|
|
502
|
+
}
|
|
449
503
|
}
|
|
450
504
|
/**
|
|
451
505
|
* Check if a process with given PID is running
|
|
@@ -592,7 +646,7 @@ export function releaseLock(lockPath) {
|
|
|
592
646
|
* - Returns detailed repair statistics
|
|
593
647
|
*
|
|
594
648
|
* @example
|
|
595
|
-
* const stateFilePath = path.join(process.cwd(), '.
|
|
649
|
+
* const stateFilePath = path.join(process.cwd(), '.lumenflow', 'state', 'wu-events.jsonl');
|
|
596
650
|
* const result = await repairStateFile(stateFilePath);
|
|
597
651
|
* if (result.success) {
|
|
598
652
|
* console.log(`Repaired: kept ${result.linesKept}, removed ${result.linesRemoved}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lumenflow/core",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.6",
|
|
4
4
|
"description": "Core WU lifecycle tools for LumenFlow workflow framework",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"lumenflow",
|
|
@@ -91,8 +91,8 @@
|
|
|
91
91
|
"vitest": "^4.0.17"
|
|
92
92
|
},
|
|
93
93
|
"peerDependencies": {
|
|
94
|
-
"@lumenflow/memory": "1.3.
|
|
95
|
-
"@lumenflow/initiatives": "1.3.
|
|
94
|
+
"@lumenflow/memory": "1.3.6",
|
|
95
|
+
"@lumenflow/initiatives": "1.3.6"
|
|
96
96
|
},
|
|
97
97
|
"peerDependenciesMeta": {
|
|
98
98
|
"@lumenflow/memory": {
|
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Spec Branch Helpers
|
|
3
|
-
*
|
|
4
|
-
* WU-1062: External plan storage and no-main-write mode
|
|
5
|
-
*
|
|
6
|
-
* Provides helpers for working with spec branches (spec/wu-XXXX).
|
|
7
|
-
* wu:create writes to spec branches by default; wu:claim merges them to main.
|
|
8
|
-
*
|
|
9
|
-
* @module
|
|
10
|
-
*/
|
|
11
|
-
import type { GitAdapter } from './git-adapter.js';
|
|
12
|
-
/**
|
|
13
|
-
* Spec branch prefix
|
|
14
|
-
*/
|
|
15
|
-
export declare const SPEC_BRANCH_PREFIX = "spec/";
|
|
16
|
-
/**
|
|
17
|
-
* WU source location constants
|
|
18
|
-
*/
|
|
19
|
-
export declare const WU_SOURCE: {
|
|
20
|
-
/** WU exists on main branch only */
|
|
21
|
-
readonly MAIN: "main";
|
|
22
|
-
/** WU exists on spec branch only */
|
|
23
|
-
readonly SPEC_BRANCH: "spec_branch";
|
|
24
|
-
/** WU exists on both main and spec branch */
|
|
25
|
-
readonly BOTH: "both";
|
|
26
|
-
/** WU not found anywhere */
|
|
27
|
-
readonly NOT_FOUND: "not_found";
|
|
28
|
-
};
|
|
29
|
-
export type WUSourceType = (typeof WU_SOURCE)[keyof typeof WU_SOURCE];
|
|
30
|
-
/**
|
|
31
|
-
* Get the spec branch name for a WU
|
|
32
|
-
*
|
|
33
|
-
* @param {string} wuId - Work Unit ID (e.g., 'WU-1062')
|
|
34
|
-
* @returns {string} Spec branch name (e.g., 'spec/wu-1062')
|
|
35
|
-
*
|
|
36
|
-
* @example
|
|
37
|
-
* getSpecBranchName('WU-1062') // 'spec/wu-1062'
|
|
38
|
-
*/
|
|
39
|
-
export declare function getSpecBranchName(wuId: string): string;
|
|
40
|
-
/**
|
|
41
|
-
* Get the origin-qualified spec branch name
|
|
42
|
-
*
|
|
43
|
-
* @param {string} wuId - Work Unit ID
|
|
44
|
-
* @returns {string} Origin-qualified branch name (e.g., 'origin/spec/wu-1062')
|
|
45
|
-
*/
|
|
46
|
-
export declare function getOriginSpecBranch(wuId: string): string;
|
|
47
|
-
/**
|
|
48
|
-
* Check if a spec branch exists on origin
|
|
49
|
-
*
|
|
50
|
-
* @param {string} wuId - Work Unit ID
|
|
51
|
-
* @param {SimpleGit} git - Git adapter instance
|
|
52
|
-
* @returns {Promise<boolean>} True if spec branch exists
|
|
53
|
-
*
|
|
54
|
-
* @example
|
|
55
|
-
* const exists = await specBranchExists('WU-1062', git);
|
|
56
|
-
*/
|
|
57
|
-
export declare function specBranchExists(wuId: string, git: GitAdapter): Promise<boolean>;
|
|
58
|
-
/**
|
|
59
|
-
* Check if a WU exists on main branch
|
|
60
|
-
*
|
|
61
|
-
* @param {string} wuId - Work Unit ID
|
|
62
|
-
* @param {SimpleGit} git - Git adapter instance
|
|
63
|
-
* @returns {Promise<boolean>} True if WU YAML exists on main
|
|
64
|
-
*/
|
|
65
|
-
export declare function isWUOnMain(wuId: string, git: GitAdapter): Promise<boolean>;
|
|
66
|
-
/**
|
|
67
|
-
* Merge spec branch to main branch (fast-forward only)
|
|
68
|
-
*
|
|
69
|
-
* This is used by wu:claim when a WU exists only on a spec branch.
|
|
70
|
-
* The spec branch is merged to main before creating the worktree.
|
|
71
|
-
*
|
|
72
|
-
* @param {string} wuId - Work Unit ID
|
|
73
|
-
* @param {SimpleGit} git - Git adapter instance
|
|
74
|
-
* @throws {Error} If merge fails (e.g., due to conflicts)
|
|
75
|
-
*
|
|
76
|
-
* @example
|
|
77
|
-
* await mergeSpecBranchToMain('WU-1062', git);
|
|
78
|
-
*/
|
|
79
|
-
export declare function mergeSpecBranchToMain(wuId: string, git: GitAdapter): Promise<void>;
|
|
80
|
-
/**
|
|
81
|
-
* Delete spec branch after merge
|
|
82
|
-
*
|
|
83
|
-
* @param {string} wuId - Work Unit ID
|
|
84
|
-
* @param {SimpleGit} git - Git adapter instance
|
|
85
|
-
*/
|
|
86
|
-
export declare function deleteSpecBranch(wuId: string, git: GitAdapter): Promise<void>;
|
|
87
|
-
/**
|
|
88
|
-
* Determine the source of a WU (main, spec branch, both, or not found)
|
|
89
|
-
*
|
|
90
|
-
* Used by wu:claim to decide whether to merge spec branch before creating worktree.
|
|
91
|
-
*
|
|
92
|
-
* @param {string} wuId - Work Unit ID
|
|
93
|
-
* @param {SimpleGit} git - Git adapter instance
|
|
94
|
-
* @returns {Promise<WUSourceType>} Source location constant
|
|
95
|
-
*
|
|
96
|
-
* @example
|
|
97
|
-
* const source = await getWUSource('WU-1062', git);
|
|
98
|
-
* if (source === WU_SOURCE.SPEC_BRANCH) {
|
|
99
|
-
* await mergeSpecBranchToMain('WU-1062', git);
|
|
100
|
-
* }
|
|
101
|
-
*/
|
|
102
|
-
export declare function getWUSource(wuId: string, git: GitAdapter): Promise<WUSourceType>;
|
|
103
|
-
/**
|
|
104
|
-
* Create a spec branch from current HEAD
|
|
105
|
-
*
|
|
106
|
-
* Used by wu:create in default mode (no --direct flag).
|
|
107
|
-
*
|
|
108
|
-
* @param {string} wuId - Work Unit ID
|
|
109
|
-
* @param {SimpleGit} git - Git adapter instance
|
|
110
|
-
*/
|
|
111
|
-
export declare function createSpecBranch(wuId: string, git: GitAdapter): Promise<void>;
|
|
112
|
-
/**
|
|
113
|
-
* Push spec branch to origin
|
|
114
|
-
*
|
|
115
|
-
* @param {string} wuId - Work Unit ID
|
|
116
|
-
* @param {SimpleGit} git - Git adapter instance
|
|
117
|
-
*/
|
|
118
|
-
export declare function pushSpecBranch(wuId: string, git: GitAdapter): Promise<void>;
|