@lumenflow/core 1.0.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/LICENSE +190 -0
- package/README.md +119 -0
- package/dist/active-wu-detector.d.ts +33 -0
- package/dist/active-wu-detector.js +106 -0
- package/dist/adapters/filesystem-metrics.adapter.d.ts +108 -0
- package/dist/adapters/filesystem-metrics.adapter.js +519 -0
- package/dist/adapters/terminal-renderer.adapter.d.ts +106 -0
- package/dist/adapters/terminal-renderer.adapter.js +337 -0
- package/dist/arg-parser.d.ts +63 -0
- package/dist/arg-parser.js +560 -0
- package/dist/backlog-editor.d.ts +98 -0
- package/dist/backlog-editor.js +179 -0
- package/dist/backlog-generator.d.ts +111 -0
- package/dist/backlog-generator.js +381 -0
- package/dist/backlog-parser.d.ts +45 -0
- package/dist/backlog-parser.js +102 -0
- package/dist/backlog-sync-validator.d.ts +78 -0
- package/dist/backlog-sync-validator.js +294 -0
- package/dist/branch-drift.d.ts +34 -0
- package/dist/branch-drift.js +51 -0
- package/dist/cleanup-install-config.d.ts +33 -0
- package/dist/cleanup-install-config.js +37 -0
- package/dist/cleanup-lock.d.ts +139 -0
- package/dist/cleanup-lock.js +313 -0
- package/dist/code-path-validator.d.ts +146 -0
- package/dist/code-path-validator.js +537 -0
- package/dist/code-paths-overlap.d.ts +55 -0
- package/dist/code-paths-overlap.js +245 -0
- package/dist/commands-logger.d.ts +77 -0
- package/dist/commands-logger.js +254 -0
- package/dist/commit-message-utils.d.ts +25 -0
- package/dist/commit-message-utils.js +41 -0
- package/dist/compliance-parser.d.ts +150 -0
- package/dist/compliance-parser.js +507 -0
- package/dist/constants/backlog-patterns.d.ts +20 -0
- package/dist/constants/backlog-patterns.js +23 -0
- package/dist/constants/dora-constants.d.ts +49 -0
- package/dist/constants/dora-constants.js +53 -0
- package/dist/constants/gate-constants.d.ts +15 -0
- package/dist/constants/gate-constants.js +15 -0
- package/dist/constants/linter-constants.d.ts +16 -0
- package/dist/constants/linter-constants.js +16 -0
- package/dist/constants/tokenizer-constants.d.ts +15 -0
- package/dist/constants/tokenizer-constants.js +15 -0
- package/dist/core/scope-checker.d.ts +97 -0
- package/dist/core/scope-checker.js +163 -0
- package/dist/core/tool-runner.d.ts +161 -0
- package/dist/core/tool-runner.js +393 -0
- package/dist/core/tool.constants.d.ts +105 -0
- package/dist/core/tool.constants.js +101 -0
- package/dist/core/tool.schemas.d.ts +226 -0
- package/dist/core/tool.schemas.js +226 -0
- package/dist/core/worktree-guard.d.ts +130 -0
- package/dist/core/worktree-guard.js +242 -0
- package/dist/coverage-gate.d.ts +108 -0
- package/dist/coverage-gate.js +196 -0
- package/dist/date-utils.d.ts +75 -0
- package/dist/date-utils.js +140 -0
- package/dist/dependency-graph.d.ts +142 -0
- package/dist/dependency-graph.js +550 -0
- package/dist/dependency-guard.d.ts +54 -0
- package/dist/dependency-guard.js +142 -0
- package/dist/dependency-validator.d.ts +105 -0
- package/dist/dependency-validator.js +154 -0
- package/dist/docs-path-validator.d.ts +36 -0
- package/dist/docs-path-validator.js +95 -0
- package/dist/domain/orchestration.constants.d.ts +99 -0
- package/dist/domain/orchestration.constants.js +97 -0
- package/dist/domain/orchestration.schemas.d.ts +280 -0
- package/dist/domain/orchestration.schemas.js +211 -0
- package/dist/domain/orchestration.types.d.ts +133 -0
- package/dist/domain/orchestration.types.js +12 -0
- package/dist/error-handler.d.ts +116 -0
- package/dist/error-handler.js +136 -0
- package/dist/file-classifiers.d.ts +62 -0
- package/dist/file-classifiers.js +108 -0
- package/dist/gates-agent-mode.d.ts +81 -0
- package/dist/gates-agent-mode.js +94 -0
- package/dist/generate-traceability.d.ts +107 -0
- package/dist/generate-traceability.js +411 -0
- package/dist/git-adapter.d.ts +395 -0
- package/dist/git-adapter.js +649 -0
- package/dist/git-staged-validator.d.ts +32 -0
- package/dist/git-staged-validator.js +48 -0
- package/dist/hardcoded-strings.d.ts +61 -0
- package/dist/hardcoded-strings.js +270 -0
- package/dist/incremental-lint.d.ts +78 -0
- package/dist/incremental-lint.js +129 -0
- package/dist/incremental-test.d.ts +39 -0
- package/dist/incremental-test.js +61 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +61 -0
- package/dist/invariants/check-automated-tests.d.ts +50 -0
- package/dist/invariants/check-automated-tests.js +166 -0
- package/dist/invariants-runner.d.ts +103 -0
- package/dist/invariants-runner.js +527 -0
- package/dist/lane-checker.d.ts +50 -0
- package/dist/lane-checker.js +319 -0
- package/dist/lane-inference.d.ts +39 -0
- package/dist/lane-inference.js +195 -0
- package/dist/lane-lock.d.ts +211 -0
- package/dist/lane-lock.js +474 -0
- package/dist/lane-validator.d.ts +48 -0
- package/dist/lane-validator.js +114 -0
- package/dist/logs-lib.d.ts +104 -0
- package/dist/logs-lib.js +207 -0
- package/dist/lumenflow-config-schema.d.ts +272 -0
- package/dist/lumenflow-config-schema.js +207 -0
- package/dist/lumenflow-config.d.ts +95 -0
- package/dist/lumenflow-config.js +236 -0
- package/dist/manual-test-validator.d.ts +80 -0
- package/dist/manual-test-validator.js +200 -0
- package/dist/merge-lock.d.ts +115 -0
- package/dist/merge-lock.js +251 -0
- package/dist/micro-worktree.d.ts +159 -0
- package/dist/micro-worktree.js +427 -0
- package/dist/migration-deployer.d.ts +69 -0
- package/dist/migration-deployer.js +151 -0
- package/dist/orchestration-advisory-loader.d.ts +28 -0
- package/dist/orchestration-advisory-loader.js +87 -0
- package/dist/orchestration-advisory.d.ts +58 -0
- package/dist/orchestration-advisory.js +94 -0
- package/dist/orchestration-di.d.ts +48 -0
- package/dist/orchestration-di.js +57 -0
- package/dist/orchestration-rules.d.ts +57 -0
- package/dist/orchestration-rules.js +201 -0
- package/dist/orphan-detector.d.ts +131 -0
- package/dist/orphan-detector.js +226 -0
- package/dist/path-classifiers.d.ts +57 -0
- package/dist/path-classifiers.js +93 -0
- package/dist/piped-command-detector.d.ts +34 -0
- package/dist/piped-command-detector.js +64 -0
- package/dist/ports/dashboard-renderer.port.d.ts +112 -0
- package/dist/ports/dashboard-renderer.port.js +25 -0
- package/dist/ports/metrics-collector.port.d.ts +132 -0
- package/dist/ports/metrics-collector.port.js +26 -0
- package/dist/process-detector.d.ts +84 -0
- package/dist/process-detector.js +172 -0
- package/dist/prompt-linter.d.ts +72 -0
- package/dist/prompt-linter.js +312 -0
- package/dist/prompt-monitor.d.ts +15 -0
- package/dist/prompt-monitor.js +205 -0
- package/dist/rebase-artifact-cleanup.d.ts +145 -0
- package/dist/rebase-artifact-cleanup.js +433 -0
- package/dist/retry-strategy.d.ts +189 -0
- package/dist/retry-strategy.js +283 -0
- package/dist/risk-detector.d.ts +108 -0
- package/dist/risk-detector.js +252 -0
- package/dist/rollback-utils.d.ts +76 -0
- package/dist/rollback-utils.js +104 -0
- package/dist/section-headings.d.ts +43 -0
- package/dist/section-headings.js +49 -0
- package/dist/spawn-escalation.d.ts +90 -0
- package/dist/spawn-escalation.js +253 -0
- package/dist/spawn-monitor.d.ts +229 -0
- package/dist/spawn-monitor.js +672 -0
- package/dist/spawn-recovery.d.ts +82 -0
- package/dist/spawn-recovery.js +298 -0
- package/dist/spawn-registry-schema.d.ts +98 -0
- package/dist/spawn-registry-schema.js +108 -0
- package/dist/spawn-registry-store.d.ts +146 -0
- package/dist/spawn-registry-store.js +273 -0
- package/dist/spawn-tree.d.ts +121 -0
- package/dist/spawn-tree.js +285 -0
- package/dist/stamp-status-validator.d.ts +84 -0
- package/dist/stamp-status-validator.js +134 -0
- package/dist/stamp-utils.d.ts +100 -0
- package/dist/stamp-utils.js +229 -0
- package/dist/state-machine.d.ts +26 -0
- package/dist/state-machine.js +83 -0
- package/dist/system-map-validator.d.ts +80 -0
- package/dist/system-map-validator.js +272 -0
- package/dist/telemetry.d.ts +80 -0
- package/dist/telemetry.js +213 -0
- package/dist/token-counter.d.ts +51 -0
- package/dist/token-counter.js +145 -0
- package/dist/usecases/get-dashboard-data.usecase.d.ts +52 -0
- package/dist/usecases/get-dashboard-data.usecase.js +61 -0
- package/dist/usecases/get-suggestions.usecase.d.ts +100 -0
- package/dist/usecases/get-suggestions.usecase.js +153 -0
- package/dist/user-normalizer.d.ts +41 -0
- package/dist/user-normalizer.js +141 -0
- package/dist/validators/phi-constants.d.ts +97 -0
- package/dist/validators/phi-constants.js +152 -0
- package/dist/validators/phi-scanner.d.ts +58 -0
- package/dist/validators/phi-scanner.js +215 -0
- package/dist/worktree-ownership.d.ts +50 -0
- package/dist/worktree-ownership.js +74 -0
- package/dist/worktree-scanner.d.ts +103 -0
- package/dist/worktree-scanner.js +168 -0
- package/dist/worktree-symlink.d.ts +99 -0
- package/dist/worktree-symlink.js +359 -0
- package/dist/wu-backlog-updater.d.ts +17 -0
- package/dist/wu-backlog-updater.js +37 -0
- package/dist/wu-checkpoint.d.ts +124 -0
- package/dist/wu-checkpoint.js +233 -0
- package/dist/wu-claim-helpers.d.ts +26 -0
- package/dist/wu-claim-helpers.js +63 -0
- package/dist/wu-claim-resume.d.ts +106 -0
- package/dist/wu-claim-resume.js +276 -0
- package/dist/wu-consistency-checker.d.ts +95 -0
- package/dist/wu-consistency-checker.js +567 -0
- package/dist/wu-constants.d.ts +1275 -0
- package/dist/wu-constants.js +1382 -0
- package/dist/wu-create-validators.d.ts +42 -0
- package/dist/wu-create-validators.js +93 -0
- package/dist/wu-done-branch-only.d.ts +63 -0
- package/dist/wu-done-branch-only.js +191 -0
- package/dist/wu-done-messages.d.ts +119 -0
- package/dist/wu-done-messages.js +185 -0
- package/dist/wu-done-pr.d.ts +72 -0
- package/dist/wu-done-pr.js +174 -0
- package/dist/wu-done-retry-helpers.d.ts +85 -0
- package/dist/wu-done-retry-helpers.js +172 -0
- package/dist/wu-done-ui.d.ts +37 -0
- package/dist/wu-done-ui.js +69 -0
- package/dist/wu-done-validators.d.ts +411 -0
- package/dist/wu-done-validators.js +1229 -0
- package/dist/wu-done-worktree.d.ts +182 -0
- package/dist/wu-done-worktree.js +1097 -0
- package/dist/wu-helpers.d.ts +128 -0
- package/dist/wu-helpers.js +248 -0
- package/dist/wu-lint.d.ts +70 -0
- package/dist/wu-lint.js +234 -0
- package/dist/wu-paths.d.ts +171 -0
- package/dist/wu-paths.js +178 -0
- package/dist/wu-preflight-validators.d.ts +86 -0
- package/dist/wu-preflight-validators.js +251 -0
- package/dist/wu-recovery.d.ts +138 -0
- package/dist/wu-recovery.js +341 -0
- package/dist/wu-repair-core.d.ts +131 -0
- package/dist/wu-repair-core.js +669 -0
- package/dist/wu-schema-normalization.d.ts +17 -0
- package/dist/wu-schema-normalization.js +82 -0
- package/dist/wu-schema.d.ts +793 -0
- package/dist/wu-schema.js +881 -0
- package/dist/wu-spawn-helpers.d.ts +121 -0
- package/dist/wu-spawn-helpers.js +271 -0
- package/dist/wu-spawn.d.ts +158 -0
- package/dist/wu-spawn.js +1306 -0
- package/dist/wu-state-schema.d.ts +213 -0
- package/dist/wu-state-schema.js +156 -0
- package/dist/wu-state-store.d.ts +264 -0
- package/dist/wu-state-store.js +691 -0
- package/dist/wu-status-transition.d.ts +63 -0
- package/dist/wu-status-transition.js +382 -0
- package/dist/wu-status-updater.d.ts +25 -0
- package/dist/wu-status-updater.js +116 -0
- package/dist/wu-transaction-collectors.d.ts +116 -0
- package/dist/wu-transaction-collectors.js +272 -0
- package/dist/wu-transaction.d.ts +170 -0
- package/dist/wu-transaction.js +273 -0
- package/dist/wu-validation-constants.d.ts +60 -0
- package/dist/wu-validation-constants.js +66 -0
- package/dist/wu-validation.d.ts +118 -0
- package/dist/wu-validation.js +243 -0
- package/dist/wu-validator.d.ts +62 -0
- package/dist/wu-validator.js +325 -0
- package/dist/wu-yaml-fixer.d.ts +97 -0
- package/dist/wu-yaml-fixer.js +264 -0
- package/dist/wu-yaml.d.ts +86 -0
- package/dist/wu-yaml.js +222 -0
- package/package.json +114 -0
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spawn Registry Store (WU-1944)
|
|
3
|
+
*
|
|
4
|
+
* Event-sourced state store for tracking sub-agent spawns.
|
|
5
|
+
* Stores events in .beacon/state/spawn-registry.jsonl (append-only, git-friendly).
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Event sourcing with replay for current state
|
|
9
|
+
* - Atomic append operations
|
|
10
|
+
* - O(1) queries by parent WU, target WU, and status
|
|
11
|
+
*
|
|
12
|
+
* @see {@link tools/lib/__tests__/spawn-registry-store.test.mjs} - Tests
|
|
13
|
+
* @see {@link tools/lib/spawn-registry-schema.mjs} - Schema definitions
|
|
14
|
+
*/
|
|
15
|
+
import { type SpawnEvent } from './spawn-registry-schema.js';
|
|
16
|
+
/**
|
|
17
|
+
* Spawn registry file name constant
|
|
18
|
+
*/
|
|
19
|
+
export declare const SPAWN_REGISTRY_FILE_NAME = "spawn-registry.jsonl";
|
|
20
|
+
/**
|
|
21
|
+
* Spawn Registry Store class
|
|
22
|
+
*
|
|
23
|
+
* Manages spawn registry state via event sourcing pattern.
|
|
24
|
+
* Events are appended to JSONL file, state is rebuilt by replaying events.
|
|
25
|
+
*/
|
|
26
|
+
export declare class SpawnRegistryStore {
|
|
27
|
+
private readonly baseDir;
|
|
28
|
+
private readonly registryFilePath;
|
|
29
|
+
private readonly spawns;
|
|
30
|
+
private readonly byParent;
|
|
31
|
+
private readonly byTarget;
|
|
32
|
+
/**
|
|
33
|
+
* @param {string} baseDir - Directory containing .beacon/state/
|
|
34
|
+
*/
|
|
35
|
+
constructor(baseDir: string);
|
|
36
|
+
/**
|
|
37
|
+
* Loads and replays events from JSONL file into current state.
|
|
38
|
+
*
|
|
39
|
+
* Handles:
|
|
40
|
+
* - Missing file: returns empty state
|
|
41
|
+
* - Empty file: returns empty state
|
|
42
|
+
* - Empty lines: skipped gracefully
|
|
43
|
+
* - Malformed JSON: throws error with line info
|
|
44
|
+
* - Invalid events: throws validation error
|
|
45
|
+
*
|
|
46
|
+
* @returns {Promise<void>}
|
|
47
|
+
* @throws {Error} If file contains malformed JSON or invalid events
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* const store = new SpawnRegistryStore('/path/to/project');
|
|
51
|
+
* await store.load();
|
|
52
|
+
* const pending = store.getPending();
|
|
53
|
+
*/
|
|
54
|
+
load(): Promise<void>;
|
|
55
|
+
/**
|
|
56
|
+
* Applies an event to the in-memory state.
|
|
57
|
+
* If event for same spawn ID exists, updates it (latest wins).
|
|
58
|
+
*
|
|
59
|
+
* @private
|
|
60
|
+
*/
|
|
61
|
+
private _applyEvent;
|
|
62
|
+
/**
|
|
63
|
+
* Appends an event to the registry file.
|
|
64
|
+
*
|
|
65
|
+
* Uses append mode to avoid full file rewrite.
|
|
66
|
+
* Creates file and parent directories if they don't exist.
|
|
67
|
+
* Validates event before appending.
|
|
68
|
+
*
|
|
69
|
+
* @private
|
|
70
|
+
* @throws {Error} If event fails validation
|
|
71
|
+
*/
|
|
72
|
+
private _appendEvent;
|
|
73
|
+
/**
|
|
74
|
+
* Records a new spawn event with pending status.
|
|
75
|
+
*
|
|
76
|
+
* @param {string} parentWuId - Parent WU ID (orchestrator)
|
|
77
|
+
* @param {string} targetWuId - Target WU ID (spawned work)
|
|
78
|
+
* @param {string} lane - Lane for the spawned work
|
|
79
|
+
* @returns {Promise<string>} The generated spawn ID
|
|
80
|
+
* @throws {Error} If validation fails
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* const spawnId = await store.record('WU-1000', 'WU-1001', 'Operations: Tooling');
|
|
84
|
+
*/
|
|
85
|
+
record(parentWuId: string, targetWuId: string, lane: string): Promise<string>;
|
|
86
|
+
/**
|
|
87
|
+
* Updates the status of a spawn.
|
|
88
|
+
*
|
|
89
|
+
* @param {string} spawnId - Spawn ID to update
|
|
90
|
+
* @param {string} status - New status
|
|
91
|
+
* @returns {Promise<void>}
|
|
92
|
+
* @throws {Error} If spawn ID not found
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* await store.updateStatus('spawn-a1b2', 'completed');
|
|
96
|
+
*/
|
|
97
|
+
updateStatus(spawnId: string, status: string): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* Gets all spawns for a parent WU.
|
|
100
|
+
*
|
|
101
|
+
* @param {string} parentWuId - Parent WU ID
|
|
102
|
+
* @returns {SpawnEvent[]} Array of spawn events
|
|
103
|
+
*
|
|
104
|
+
* @example
|
|
105
|
+
* const spawns = store.getByParent('WU-1000');
|
|
106
|
+
*/
|
|
107
|
+
getByParent(parentWuId: string): SpawnEvent[];
|
|
108
|
+
/**
|
|
109
|
+
* Gets spawn for a target WU.
|
|
110
|
+
*
|
|
111
|
+
* @param {string} targetWuId - Target WU ID
|
|
112
|
+
* @returns {SpawnEvent | null} Spawn event or null
|
|
113
|
+
*
|
|
114
|
+
* @example
|
|
115
|
+
* const spawn = store.getByTarget('WU-1001');
|
|
116
|
+
*/
|
|
117
|
+
getByTarget(targetWuId: string): SpawnEvent | null;
|
|
118
|
+
/**
|
|
119
|
+
* Gets all pending spawns.
|
|
120
|
+
*
|
|
121
|
+
* @returns {SpawnEvent[]} Array of pending spawn events
|
|
122
|
+
*
|
|
123
|
+
* @example
|
|
124
|
+
* const pending = store.getPending();
|
|
125
|
+
*/
|
|
126
|
+
getPending(): SpawnEvent[];
|
|
127
|
+
/**
|
|
128
|
+
* Gets all spawns as an array.
|
|
129
|
+
*
|
|
130
|
+
* @returns {SpawnEvent[]} Array of all spawn events
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* const allSpawns = store.getAllSpawns();
|
|
134
|
+
*/
|
|
135
|
+
getAllSpawns(): SpawnEvent[];
|
|
136
|
+
/**
|
|
137
|
+
* Gets spawn by ID.
|
|
138
|
+
*
|
|
139
|
+
* @param {string} spawnId - Spawn ID
|
|
140
|
+
* @returns {SpawnEvent | null} Spawn event or null
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* const spawn = store.getById('spawn-a1b2');
|
|
144
|
+
*/
|
|
145
|
+
getById(spawnId: string): SpawnEvent | null;
|
|
146
|
+
}
|
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spawn Registry Store (WU-1944)
|
|
3
|
+
*
|
|
4
|
+
* Event-sourced state store for tracking sub-agent spawns.
|
|
5
|
+
* Stores events in .beacon/state/spawn-registry.jsonl (append-only, git-friendly).
|
|
6
|
+
*
|
|
7
|
+
* Features:
|
|
8
|
+
* - Event sourcing with replay for current state
|
|
9
|
+
* - Atomic append operations
|
|
10
|
+
* - O(1) queries by parent WU, target WU, and status
|
|
11
|
+
*
|
|
12
|
+
* @see {@link tools/lib/__tests__/spawn-registry-store.test.mjs} - Tests
|
|
13
|
+
* @see {@link tools/lib/spawn-registry-schema.mjs} - Schema definitions
|
|
14
|
+
*/
|
|
15
|
+
import fs from 'node:fs/promises';
|
|
16
|
+
import path from 'node:path';
|
|
17
|
+
import { validateSpawnEvent, generateSpawnId, SpawnStatus, } from './spawn-registry-schema.js';
|
|
18
|
+
/**
|
|
19
|
+
* Spawn registry file name constant
|
|
20
|
+
*/
|
|
21
|
+
export const SPAWN_REGISTRY_FILE_NAME = 'spawn-registry.jsonl';
|
|
22
|
+
/**
|
|
23
|
+
* Spawn Registry Store class
|
|
24
|
+
*
|
|
25
|
+
* Manages spawn registry state via event sourcing pattern.
|
|
26
|
+
* Events are appended to JSONL file, state is rebuilt by replaying events.
|
|
27
|
+
*/
|
|
28
|
+
export class SpawnRegistryStore {
|
|
29
|
+
baseDir;
|
|
30
|
+
registryFilePath;
|
|
31
|
+
spawns;
|
|
32
|
+
byParent;
|
|
33
|
+
byTarget;
|
|
34
|
+
/**
|
|
35
|
+
* @param {string} baseDir - Directory containing .beacon/state/
|
|
36
|
+
*/
|
|
37
|
+
constructor(baseDir) {
|
|
38
|
+
this.baseDir = baseDir;
|
|
39
|
+
this.registryFilePath = path.join(baseDir, SPAWN_REGISTRY_FILE_NAME);
|
|
40
|
+
// In-memory state (rebuilt from events)
|
|
41
|
+
this.spawns = new Map();
|
|
42
|
+
// Index: parentWuId -> spawnIds[]
|
|
43
|
+
this.byParent = new Map();
|
|
44
|
+
// Index: targetWuId -> spawnId
|
|
45
|
+
this.byTarget = new Map();
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Loads and replays events from JSONL file into current state.
|
|
49
|
+
*
|
|
50
|
+
* Handles:
|
|
51
|
+
* - Missing file: returns empty state
|
|
52
|
+
* - Empty file: returns empty state
|
|
53
|
+
* - Empty lines: skipped gracefully
|
|
54
|
+
* - Malformed JSON: throws error with line info
|
|
55
|
+
* - Invalid events: throws validation error
|
|
56
|
+
*
|
|
57
|
+
* @returns {Promise<void>}
|
|
58
|
+
* @throws {Error} If file contains malformed JSON or invalid events
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const store = new SpawnRegistryStore('/path/to/project');
|
|
62
|
+
* await store.load();
|
|
63
|
+
* const pending = store.getPending();
|
|
64
|
+
*/
|
|
65
|
+
async load() {
|
|
66
|
+
// Reset state
|
|
67
|
+
this.spawns.clear();
|
|
68
|
+
this.byParent.clear();
|
|
69
|
+
this.byTarget.clear();
|
|
70
|
+
// Check if file exists
|
|
71
|
+
let content;
|
|
72
|
+
try {
|
|
73
|
+
content = await fs.readFile(this.registryFilePath, 'utf-8');
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
if (error.code === 'ENOENT') {
|
|
77
|
+
// File doesn't exist - return empty state
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
throw error;
|
|
81
|
+
}
|
|
82
|
+
// Parse JSONL content
|
|
83
|
+
const lines = content.split('\n');
|
|
84
|
+
for (let i = 0; i < lines.length; i++) {
|
|
85
|
+
const line = lines[i].trim();
|
|
86
|
+
// Skip empty lines
|
|
87
|
+
if (!line) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
// Parse JSON line
|
|
91
|
+
let parsed;
|
|
92
|
+
try {
|
|
93
|
+
parsed = JSON.parse(line);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
throw new Error(`Malformed JSON on line ${i + 1}: ${error.message}`);
|
|
97
|
+
}
|
|
98
|
+
// Validate against schema
|
|
99
|
+
const validation = validateSpawnEvent(parsed);
|
|
100
|
+
if (!validation.success) {
|
|
101
|
+
const issues = validation.error.issues
|
|
102
|
+
.map((issue) => `${issue.path.join('.')}: ${issue.message}`)
|
|
103
|
+
.join(', ');
|
|
104
|
+
throw new Error(`Validation error on line ${i + 1}: ${issues}`);
|
|
105
|
+
}
|
|
106
|
+
const event = validation.data;
|
|
107
|
+
// Apply event to state (latest event for same ID wins)
|
|
108
|
+
this._applyEvent(event);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Applies an event to the in-memory state.
|
|
113
|
+
* If event for same spawn ID exists, updates it (latest wins).
|
|
114
|
+
*
|
|
115
|
+
* @private
|
|
116
|
+
*/
|
|
117
|
+
_applyEvent(event) {
|
|
118
|
+
const { id, parentWuId, targetWuId } = event;
|
|
119
|
+
// Update main state map
|
|
120
|
+
this.spawns.set(id, event);
|
|
121
|
+
// Update parent index
|
|
122
|
+
if (!this.byParent.has(parentWuId)) {
|
|
123
|
+
this.byParent.set(parentWuId, []);
|
|
124
|
+
}
|
|
125
|
+
const parentSpawns = this.byParent.get(parentWuId);
|
|
126
|
+
if (!parentSpawns.includes(id)) {
|
|
127
|
+
parentSpawns.push(id);
|
|
128
|
+
}
|
|
129
|
+
// Update target index
|
|
130
|
+
this.byTarget.set(targetWuId, id);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Appends an event to the registry file.
|
|
134
|
+
*
|
|
135
|
+
* Uses append mode to avoid full file rewrite.
|
|
136
|
+
* Creates file and parent directories if they don't exist.
|
|
137
|
+
* Validates event before appending.
|
|
138
|
+
*
|
|
139
|
+
* @private
|
|
140
|
+
* @throws {Error} If event fails validation
|
|
141
|
+
*/
|
|
142
|
+
async _appendEvent(event) {
|
|
143
|
+
// Validate event before appending
|
|
144
|
+
const validation = validateSpawnEvent(event);
|
|
145
|
+
if (!validation.success) {
|
|
146
|
+
const issues = validation.error.issues
|
|
147
|
+
.map((issue) => `${issue.path.join('.')}: ${issue.message}`)
|
|
148
|
+
.join(', ');
|
|
149
|
+
throw new Error(`Validation error: ${issues}`);
|
|
150
|
+
}
|
|
151
|
+
const line = JSON.stringify(event) + '\n';
|
|
152
|
+
// Ensure parent directory exists before appending
|
|
153
|
+
await fs.mkdir(this.baseDir, { recursive: true });
|
|
154
|
+
// Use append flag to avoid rewriting the file
|
|
155
|
+
await fs.appendFile(this.registryFilePath, line, 'utf-8');
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Records a new spawn event with pending status.
|
|
159
|
+
*
|
|
160
|
+
* @param {string} parentWuId - Parent WU ID (orchestrator)
|
|
161
|
+
* @param {string} targetWuId - Target WU ID (spawned work)
|
|
162
|
+
* @param {string} lane - Lane for the spawned work
|
|
163
|
+
* @returns {Promise<string>} The generated spawn ID
|
|
164
|
+
* @throws {Error} If validation fails
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* const spawnId = await store.record('WU-1000', 'WU-1001', 'Operations: Tooling');
|
|
168
|
+
*/
|
|
169
|
+
async record(parentWuId, targetWuId, lane) {
|
|
170
|
+
const id = generateSpawnId(parentWuId, targetWuId);
|
|
171
|
+
const event = {
|
|
172
|
+
id,
|
|
173
|
+
parentWuId,
|
|
174
|
+
targetWuId,
|
|
175
|
+
lane,
|
|
176
|
+
spawnedAt: new Date().toISOString(),
|
|
177
|
+
status: SpawnStatus.PENDING,
|
|
178
|
+
completedAt: null,
|
|
179
|
+
};
|
|
180
|
+
await this._appendEvent(event);
|
|
181
|
+
this._applyEvent(event);
|
|
182
|
+
return id;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Updates the status of a spawn.
|
|
186
|
+
*
|
|
187
|
+
* @param {string} spawnId - Spawn ID to update
|
|
188
|
+
* @param {string} status - New status
|
|
189
|
+
* @returns {Promise<void>}
|
|
190
|
+
* @throws {Error} If spawn ID not found
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* await store.updateStatus('spawn-a1b2', 'completed');
|
|
194
|
+
*/
|
|
195
|
+
async updateStatus(spawnId, status) {
|
|
196
|
+
const existing = this.spawns.get(spawnId);
|
|
197
|
+
if (!existing) {
|
|
198
|
+
throw new Error(`Spawn ID ${spawnId} not found`);
|
|
199
|
+
}
|
|
200
|
+
const event = {
|
|
201
|
+
...existing,
|
|
202
|
+
status: status,
|
|
203
|
+
completedAt: new Date().toISOString(),
|
|
204
|
+
};
|
|
205
|
+
await this._appendEvent(event);
|
|
206
|
+
this._applyEvent(event);
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Gets all spawns for a parent WU.
|
|
210
|
+
*
|
|
211
|
+
* @param {string} parentWuId - Parent WU ID
|
|
212
|
+
* @returns {SpawnEvent[]} Array of spawn events
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* const spawns = store.getByParent('WU-1000');
|
|
216
|
+
*/
|
|
217
|
+
getByParent(parentWuId) {
|
|
218
|
+
const spawnIds = this.byParent.get(parentWuId) ?? [];
|
|
219
|
+
return spawnIds
|
|
220
|
+
.map((id) => this.spawns.get(id))
|
|
221
|
+
.filter((event) => event !== undefined);
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Gets spawn for a target WU.
|
|
225
|
+
*
|
|
226
|
+
* @param {string} targetWuId - Target WU ID
|
|
227
|
+
* @returns {SpawnEvent | null} Spawn event or null
|
|
228
|
+
*
|
|
229
|
+
* @example
|
|
230
|
+
* const spawn = store.getByTarget('WU-1001');
|
|
231
|
+
*/
|
|
232
|
+
getByTarget(targetWuId) {
|
|
233
|
+
const spawnId = this.byTarget.get(targetWuId);
|
|
234
|
+
if (!spawnId) {
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
return this.spawns.get(spawnId) ?? null;
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Gets all pending spawns.
|
|
241
|
+
*
|
|
242
|
+
* @returns {SpawnEvent[]} Array of pending spawn events
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* const pending = store.getPending();
|
|
246
|
+
*/
|
|
247
|
+
getPending() {
|
|
248
|
+
return Array.from(this.spawns.values()).filter((spawn) => spawn.status === SpawnStatus.PENDING);
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Gets all spawns as an array.
|
|
252
|
+
*
|
|
253
|
+
* @returns {SpawnEvent[]} Array of all spawn events
|
|
254
|
+
*
|
|
255
|
+
* @example
|
|
256
|
+
* const allSpawns = store.getAllSpawns();
|
|
257
|
+
*/
|
|
258
|
+
getAllSpawns() {
|
|
259
|
+
return Array.from(this.spawns.values());
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Gets spawn by ID.
|
|
263
|
+
*
|
|
264
|
+
* @param {string} spawnId - Spawn ID
|
|
265
|
+
* @returns {SpawnEvent | null} Spawn event or null
|
|
266
|
+
*
|
|
267
|
+
* @example
|
|
268
|
+
* const spawn = store.getById('spawn-a1b2');
|
|
269
|
+
*/
|
|
270
|
+
getById(spawnId) {
|
|
271
|
+
return this.spawns.get(spawnId) ?? null;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spawn Tree Builder (WU-1950)
|
|
3
|
+
*
|
|
4
|
+
* Builds and formats spawn trees for visualization.
|
|
5
|
+
* Used by spawn:list command to display parent-child relationships.
|
|
6
|
+
*
|
|
7
|
+
* Note: Domain-specific tree visualization for spawn registry.
|
|
8
|
+
* Integrates with spawn-registry-store and spawn-registry-schema.
|
|
9
|
+
* No external tree library needed - logic is tightly coupled to spawn data model.
|
|
10
|
+
*
|
|
11
|
+
* @see {@link tools/__tests__/spawn-list.test.mjs} - Tests
|
|
12
|
+
* @see {@link tools/spawn-list.mjs} - CLI command
|
|
13
|
+
* @see {@link tools/lib/spawn-registry-store.mjs} - Data source
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Status indicators for terminal output.
|
|
17
|
+
* Using unicode symbols for clear visual distinction.
|
|
18
|
+
*/
|
|
19
|
+
export declare const STATUS_INDICATORS: Readonly<{
|
|
20
|
+
pending: "○";
|
|
21
|
+
completed: "✓";
|
|
22
|
+
timeout: "⏱";
|
|
23
|
+
crashed: "✗";
|
|
24
|
+
}>;
|
|
25
|
+
/**
|
|
26
|
+
* Tree node structure
|
|
27
|
+
* @typedef {object} SpawnTreeNode
|
|
28
|
+
* @property {string} wuId - WU ID for this node
|
|
29
|
+
* @property {string|null} spawnId - Spawn ID (null for root)
|
|
30
|
+
* @property {string|null} status - Spawn status (null for root)
|
|
31
|
+
* @property {string|null} lane - Lane (null for root)
|
|
32
|
+
* @property {string|null} spawnedAt - Spawn timestamp (null for root)
|
|
33
|
+
* @property {SpawnTreeNode[]} children - Child nodes
|
|
34
|
+
*/
|
|
35
|
+
/**
|
|
36
|
+
* Builds a spawn tree from flat spawn events.
|
|
37
|
+
*
|
|
38
|
+
* @param {import('./spawn-registry-schema.js').SpawnEvent[]} spawns - Array of spawn events
|
|
39
|
+
* @param {string} rootWuId - Root WU ID to build tree from
|
|
40
|
+
* @returns {SpawnTreeNode} Tree rooted at rootWuId
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* const tree = buildSpawnTree(spawns, 'WU-1000');
|
|
44
|
+
* // { wuId: 'WU-1000', children: [{ wuId: 'WU-1001', ... }] }
|
|
45
|
+
*/
|
|
46
|
+
export declare function buildSpawnTree(spawns: any, rootWuId: any): {
|
|
47
|
+
wuId: any;
|
|
48
|
+
spawnId: any;
|
|
49
|
+
status: any;
|
|
50
|
+
lane: any;
|
|
51
|
+
spawnedAt: any;
|
|
52
|
+
children: any[];
|
|
53
|
+
};
|
|
54
|
+
/**
|
|
55
|
+
* Formats a spawn tree for terminal display with indentation and tree characters.
|
|
56
|
+
*
|
|
57
|
+
* @param {SpawnTreeNode} tree - Tree to format
|
|
58
|
+
* @returns {string} Formatted tree string
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* const formatted = formatSpawnTree(tree);
|
|
62
|
+
* // WU-1000 (root)
|
|
63
|
+
* // ├── ○ WU-1001 [spawn-1111] (Operations: Tooling)
|
|
64
|
+
* // │ └── ✓ WU-1002 [spawn-2222] (Core: Backend)
|
|
65
|
+
* // └── ○ WU-1003 [spawn-3333] (Experience: Web)
|
|
66
|
+
*/
|
|
67
|
+
export declare function formatSpawnTree(tree: any): string;
|
|
68
|
+
/**
|
|
69
|
+
* Gets all spawns for a WU (both where WU is parent and descendants).
|
|
70
|
+
*
|
|
71
|
+
* Returns all spawns needed to build the full tree from this WU.
|
|
72
|
+
*
|
|
73
|
+
* @param {string} wuId - WU ID to get spawns for
|
|
74
|
+
* @param {string} baseDir - Directory containing spawn-registry.jsonl
|
|
75
|
+
* @returns {Promise<import('./spawn-registry-schema.js').SpawnEvent[]>} Array of spawn events
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* const spawns = await getSpawnsByWU('WU-1000', '.beacon/state');
|
|
79
|
+
*/
|
|
80
|
+
export declare function getSpawnsByWU(wuId: any, baseDir: any): Promise<any[]>;
|
|
81
|
+
/**
|
|
82
|
+
* Gets all spawns for an initiative.
|
|
83
|
+
*
|
|
84
|
+
* Reads WU YAML files to find which WUs belong to the initiative,
|
|
85
|
+
* then returns all spawns where parent or target WU belongs to initiative.
|
|
86
|
+
*
|
|
87
|
+
* @param {string} initiativeId - Initiative ID (e.g., 'INIT-001')
|
|
88
|
+
* @param {string} registryDir - Directory containing spawn-registry.jsonl
|
|
89
|
+
* @param {string} wuDir - Directory containing WU YAML files
|
|
90
|
+
* @returns {Promise<import('./spawn-registry-schema.js').SpawnEvent[]>} Array of spawn events
|
|
91
|
+
*
|
|
92
|
+
* @example
|
|
93
|
+
* const spawns = await getSpawnsByInitiative('INIT-001', '.beacon/state', 'docs/04-operations/tasks/wu');
|
|
94
|
+
*/
|
|
95
|
+
export declare function getSpawnsByInitiative(initiativeId: any, registryDir: any, wuDir: any): Promise<{
|
|
96
|
+
id: string;
|
|
97
|
+
parentWuId: string;
|
|
98
|
+
targetWuId: string;
|
|
99
|
+
lane: string;
|
|
100
|
+
spawnedAt: string;
|
|
101
|
+
status: "completed" | "timeout" | "pending" | "crashed" | "escalated";
|
|
102
|
+
completedAt?: string;
|
|
103
|
+
}[]>;
|
|
104
|
+
/**
|
|
105
|
+
* Converts a spawn tree to JSON format.
|
|
106
|
+
*
|
|
107
|
+
* @param {SpawnTreeNode} tree - Tree to convert
|
|
108
|
+
* @returns {object} JSON-serializable tree
|
|
109
|
+
*
|
|
110
|
+
* @example
|
|
111
|
+
* const json = treeToJSON(tree);
|
|
112
|
+
* console.log(JSON.stringify(json, null, 2));
|
|
113
|
+
*/
|
|
114
|
+
export declare function treeToJSON(tree: any): {
|
|
115
|
+
wuId: any;
|
|
116
|
+
spawnId: any;
|
|
117
|
+
status: any;
|
|
118
|
+
lane: any;
|
|
119
|
+
spawnedAt: any;
|
|
120
|
+
children: any;
|
|
121
|
+
};
|