@lumenflow/initiatives 4.20.2 → 4.22.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/initiative-orchestrator.d.ts +3 -1
- package/dist/initiative-orchestrator.d.ts.map +1 -1
- package/dist/initiative-orchestrator.js +4 -0
- package/dist/initiative-orchestrator.js.map +1 -1
- package/dist/orchestrator/artifacts.d.ts +17 -0
- package/dist/orchestrator/artifacts.d.ts.map +1 -0
- package/dist/orchestrator/artifacts.js +248 -0
- package/dist/orchestrator/artifacts.js.map +1 -0
- package/dist/orchestrator/checkpoint.d.ts.map +1 -1
- package/dist/orchestrator/checkpoint.js +151 -25
- package/dist/orchestrator/checkpoint.js.map +1 -1
- package/dist/orchestrator/formatting.d.ts.map +1 -1
- package/dist/orchestrator/formatting.js +56 -39
- package/dist/orchestrator/formatting.js.map +1 -1
- package/dist/orchestrator/reconciliation.d.ts +14 -0
- package/dist/orchestrator/reconciliation.d.ts.map +1 -0
- package/dist/orchestrator/reconciliation.js +233 -0
- package/dist/orchestrator/reconciliation.js.map +1 -0
- package/dist/orchestrator/shared.d.ts +4 -0
- package/dist/orchestrator/shared.d.ts.map +1 -1
- package/dist/orchestrator/shared.js +4 -0
- package/dist/orchestrator/shared.js.map +1 -1
- package/dist/orchestrator/types.d.ts +106 -1
- package/dist/orchestrator/types.d.ts.map +1 -1
- package/dist/orchestrator/types.js +12 -1
- package/dist/orchestrator/types.js.map +1 -1
- package/package.json +2 -2
|
@@ -17,13 +17,15 @@
|
|
|
17
17
|
* @see {@link packages/@lumenflow/cli/src/lib/initiative-yaml.ts} - Initiative loading
|
|
18
18
|
* @see {@link packages/@lumenflow/cli/src/lib/dependency-graph.ts} - Dependency graph utilities
|
|
19
19
|
*/
|
|
20
|
-
export type { CheckpointOptions, CheckpointModeResult, AutoCheckpointResult, SkippedWUEntry, DeferredWUEntry, ExecutionPlan, ProgressStats, BottleneckWU, WaveManifestWU, WaveManifest, CheckpointWaveResult, DependencyFilterResult, LockPolicy, LaneConfig, LockPolicyOptions, LaneAvailabilityResult, } from './orchestrator/types.js';
|
|
20
|
+
export type { CheckpointOptions, CheckpointModeResult, AutoCheckpointResult, SkippedWUEntry, DeferredWUEntry, ExecutionPlan, ProgressStats, BottleneckWU, WaveManifestWU, WaveManifest, CheckpointWaveResult, DependencyFilterResult, LockPolicy, LaneConfig, LockPolicyOptions, LaneAvailabilityResult, HandoffFormat, HandoffReceipt, OrchestrationArtifactBundle, OrchestrationExecutionState, OrchestrationActionType, WuExecutionEvidence, OrchestrationNextAction, ReconciledInitiativeWU, InitiativeExecutionSummary, } from './orchestrator/types.js';
|
|
21
21
|
export { LOG_PREFIX } from './orchestrator/shared.js';
|
|
22
22
|
export { buildExecutionPlan, buildExecutionPlanAsync, buildExecutionPlanWithLockPolicy, } from './orchestrator/execution-planning.js';
|
|
23
23
|
export { CHECKPOINT_AUTO_THRESHOLDS, filterByDependencyStamps, shouldAutoEnableCheckpoint, shouldAutoEnableCheckpointAsync, resolveCheckpointMode, resolveCheckpointModeAsync, validateCheckpointFlags, buildCheckpointWave, } from './orchestrator/checkpoint.js';
|
|
24
|
+
export { isXmlCapableClient, renderHandoffArtifact, writeCheckpointArtifacts, writeExecutionPlanArtifacts, } from './orchestrator/artifacts.js';
|
|
24
25
|
export { formatExecutionPlan, generateSpawnCommands, calculateProgress, formatProgress, getBottleneckWUs, formatCheckpointOutput, generateEmbeddedSpawnPrompt, formatTaskInvocationWithEmbeddedSpawn, formatExecutionPlanWithEmbeddedSpawns, } from './orchestrator/formatting.js';
|
|
25
26
|
export { getManifestWUStatus, isWUActuallySpawned, getSpawnCandidatesWithYAMLCheck, } from './orchestrator/spawn-status.js';
|
|
26
27
|
export { getLockPolicyForLane, getLaneAvailability } from './orchestrator/lane-policy.js';
|
|
28
|
+
export { reconcileInitiativeExecution } from './orchestrator/reconciliation.js';
|
|
27
29
|
export { loadInitiativeWUs, loadMultipleInitiatives } from './orchestrator/initiative-loading.js';
|
|
28
30
|
export { analyseScopeShape, formatScopeAdvisory, SCOPE_ADVISORY_THRESHOLDS, type ScopeAdvisory, type ScopeAdvisoryResult, type ScopeAdvisoryType, type ScopeAdvisorySeverity, } from './orchestrator/scope-advisory.js';
|
|
29
31
|
//# sourceMappingURL=initiative-orchestrator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initiative-orchestrator.d.ts","sourceRoot":"","sources":["../src/initiative-orchestrator.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,YAAY,EACV,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,aAAa,EACb,aAAa,EACb,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,sBAAsB,EACtB,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,sBAAsB,
|
|
1
|
+
{"version":3,"file":"initiative-orchestrator.d.ts","sourceRoot":"","sources":["../src/initiative-orchestrator.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;GAkBG;AAGH,YAAY,EACV,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,eAAe,EACf,aAAa,EACb,aAAa,EACb,YAAY,EACZ,cAAc,EACd,YAAY,EACZ,oBAAoB,EACpB,sBAAsB,EACtB,UAAU,EACV,UAAU,EACV,iBAAiB,EACjB,sBAAsB,EACtB,aAAa,EACb,cAAc,EACd,2BAA2B,EAC3B,2BAA2B,EAC3B,uBAAuB,EACvB,mBAAmB,EACnB,uBAAuB,EACvB,sBAAsB,EACtB,0BAA0B,GAC3B,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAGtD,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,gCAAgC,GACjC,MAAM,sCAAsC,CAAC;AAG9C,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,0BAA0B,EAC1B,+BAA+B,EAC/B,qBAAqB,EACrB,0BAA0B,EAC1B,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,6BAA6B,CAAC;AAGrC,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,2BAA2B,EAC3B,qCAAqC,EACrC,qCAAqC,GACtC,MAAM,8BAA8B,CAAC;AAGtC,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,+BAA+B,GAChC,MAAM,gCAAgC,CAAC;AAGxC,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAG1F,OAAO,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAGhF,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAGlG,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,yBAAyB,EACzB,KAAK,aAAa,EAClB,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,qBAAqB,GAC3B,MAAM,kCAAkC,CAAC"}
|
|
@@ -6,12 +6,16 @@ export { LOG_PREFIX } from './orchestrator/shared.js';
|
|
|
6
6
|
export { buildExecutionPlan, buildExecutionPlanAsync, buildExecutionPlanWithLockPolicy, } from './orchestrator/execution-planning.js';
|
|
7
7
|
// ── Checkpoint ────────────────────────────────────────────────────────────────
|
|
8
8
|
export { CHECKPOINT_AUTO_THRESHOLDS, filterByDependencyStamps, shouldAutoEnableCheckpoint, shouldAutoEnableCheckpointAsync, resolveCheckpointMode, resolveCheckpointModeAsync, validateCheckpointFlags, buildCheckpointWave, } from './orchestrator/checkpoint.js';
|
|
9
|
+
// ── Durable artifacts ────────────────────────────────────────────────────────
|
|
10
|
+
export { isXmlCapableClient, renderHandoffArtifact, writeCheckpointArtifacts, writeExecutionPlanArtifacts, } from './orchestrator/artifacts.js';
|
|
9
11
|
// ── Formatting ────────────────────────────────────────────────────────────────
|
|
10
12
|
export { formatExecutionPlan, generateSpawnCommands, calculateProgress, formatProgress, getBottleneckWUs, formatCheckpointOutput, generateEmbeddedSpawnPrompt, formatTaskInvocationWithEmbeddedSpawn, formatExecutionPlanWithEmbeddedSpawns, } from './orchestrator/formatting.js';
|
|
11
13
|
// ── Spawn status ──────────────────────────────────────────────────────────────
|
|
12
14
|
export { getManifestWUStatus, isWUActuallySpawned, getSpawnCandidatesWithYAMLCheck, } from './orchestrator/spawn-status.js';
|
|
13
15
|
// ── Lane policy ───────────────────────────────────────────────────────────────
|
|
14
16
|
export { getLockPolicyForLane, getLaneAvailability } from './orchestrator/lane-policy.js';
|
|
17
|
+
// ── Reconciliation / advancement ─────────────────────────────────────────────
|
|
18
|
+
export { reconcileInitiativeExecution } from './orchestrator/reconciliation.js';
|
|
15
19
|
// ── Initiative loading ────────────────────────────────────────────────────────
|
|
16
20
|
export { loadInitiativeWUs, loadMultipleInitiatives } from './orchestrator/initiative-loading.js';
|
|
17
21
|
// ── Scope advisory (WU-2142/WU-2155) ────────────────────────────────────────
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"initiative-orchestrator.js","sourceRoot":"","sources":["../src/initiative-orchestrator.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,yCAAyC;
|
|
1
|
+
{"version":3,"file":"initiative-orchestrator.js","sourceRoot":"","sources":["../src/initiative-orchestrator.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,yCAAyC;AAmDzC,iFAAiF;AACjF,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,iFAAiF;AACjF,OAAO,EACL,kBAAkB,EAClB,uBAAuB,EACvB,gCAAgC,GACjC,MAAM,sCAAsC,CAAC;AAE9C,iFAAiF;AACjF,OAAO,EACL,0BAA0B,EAC1B,wBAAwB,EACxB,0BAA0B,EAC1B,+BAA+B,EAC/B,qBAAqB,EACrB,0BAA0B,EAC1B,uBAAuB,EACvB,mBAAmB,GACpB,MAAM,8BAA8B,CAAC;AAEtC,gFAAgF;AAChF,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,wBAAwB,EACxB,2BAA2B,GAC5B,MAAM,6BAA6B,CAAC;AAErC,iFAAiF;AACjF,OAAO,EACL,mBAAmB,EACnB,qBAAqB,EACrB,iBAAiB,EACjB,cAAc,EACd,gBAAgB,EAChB,sBAAsB,EACtB,2BAA2B,EAC3B,qCAAqC,EACrC,qCAAqC,GACtC,MAAM,8BAA8B,CAAC;AAEtC,iFAAiF;AACjF,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,+BAA+B,GAChC,MAAM,gCAAgC,CAAC;AAExC,iFAAiF;AACjF,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,+BAA+B,CAAC;AAE1F,gFAAgF;AAChF,OAAO,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAEhF,iFAAiF;AACjF,OAAO,EAAE,iBAAiB,EAAE,uBAAuB,EAAE,MAAM,sCAAsC,CAAC;AAElG,+EAA+E;AAC/E,OAAO,EACL,iBAAiB,EACjB,mBAAmB,EACnB,yBAAyB,GAK1B,MAAM,kCAAkC,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { WUEntry } from '../initiative-yaml.js';
|
|
2
|
+
import type { CheckpointOptions, ExecutionPlan, HandoffFormat, OrchestrationArtifactBundle } from './types.js';
|
|
3
|
+
interface RenderedHandoffArtifact {
|
|
4
|
+
content: string;
|
|
5
|
+
extension: string;
|
|
6
|
+
format: HandoffFormat;
|
|
7
|
+
}
|
|
8
|
+
interface HandoffWU {
|
|
9
|
+
id: string;
|
|
10
|
+
doc: WUEntry['doc'];
|
|
11
|
+
}
|
|
12
|
+
export declare function isXmlCapableClient(clientName?: string): boolean;
|
|
13
|
+
export declare function renderHandoffArtifact(wu: HandoffWU, clientName?: string): RenderedHandoffArtifact;
|
|
14
|
+
export declare function writeExecutionPlanArtifacts(initId: string, allWUs: WUEntry[], plan: ExecutionPlan, options?: CheckpointOptions): OrchestrationArtifactBundle;
|
|
15
|
+
export declare function writeCheckpointArtifacts(initId: string, allWUs: WUEntry[], selectedWUs: WUEntry[], options?: CheckpointOptions): OrchestrationArtifactBundle;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=artifacts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifacts.d.ts","sourceRoot":"","sources":["../../src/orchestrator/artifacts.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACb,aAAa,EAEb,2BAA2B,EAC5B,MAAM,YAAY,CAAC;AAgBpB,UAAU,uBAAuB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,aAAa,CAAC;CACvB;AAOD,UAAU,SAAS;IACjB,EAAE,EAAE,MAAM,CAAC;IACX,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,CAAC;CACrB;AAQD,wBAAgB,kBAAkB,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAE/D;AAED,wBAAgB,qBAAqB,CAAC,EAAE,EAAE,SAAS,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,uBAAuB,CAiBjG;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EAAE,EACjB,IAAI,EAAE,aAAa,EACnB,OAAO,GAAE,iBAAsB,GAC9B,2BAA2B,CAG7B;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EAAE,EACjB,WAAW,EAAE,OAAO,EAAE,EACtB,OAAO,GAAE,iBAAsB,GAC9B,2BAA2B,CAO7B"}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
// Copyright (c) 2026 Hellmai Ltd
|
|
2
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
3
|
+
/**
|
|
4
|
+
* Durable artifact writing for initiative orchestration.
|
|
5
|
+
*
|
|
6
|
+
* WU-2617: Persist plan/launch/status artifacts and per-WU handoff receipts so
|
|
7
|
+
* orchestration can distinguish dependency waves from repeated launch attempts.
|
|
8
|
+
*
|
|
9
|
+
* @module orchestrator/artifacts
|
|
10
|
+
*/
|
|
11
|
+
import { existsSync, mkdirSync, readdirSync, writeFileSync } from 'node:fs';
|
|
12
|
+
import { join } from 'node:path';
|
|
13
|
+
import { getAllDependencies, ORCHESTRATION_ARTIFACT_DIR, WAVE_MANIFEST_DIR } from './shared.js';
|
|
14
|
+
import { generateCodexPrompt, generateTaskInvocation } from '@lumenflow/core/wu-spawn';
|
|
15
|
+
import { SpawnStrategyFactory } from '@lumenflow/core/spawn-strategy';
|
|
16
|
+
const XML_CAPABLE_CLIENTS = new Set(['claude-code', 'claude']);
|
|
17
|
+
const ATTEMPT_PREFIX = 'attempt-';
|
|
18
|
+
const HANDOFFS_DIRNAME = 'handoffs';
|
|
19
|
+
const PLAN_FILENAME = 'plan.json';
|
|
20
|
+
const LAUNCH_FILENAME = 'launch.json';
|
|
21
|
+
const STATUS_FILENAME = 'status.json';
|
|
22
|
+
const MARKDOWN_EXTENSION = 'md';
|
|
23
|
+
const XML_EXTENSION = 'xml';
|
|
24
|
+
const FALLBACK_LOGICAL_WAVE = 0;
|
|
25
|
+
const FALLBACK_ATTEMPT = -1;
|
|
26
|
+
export function isXmlCapableClient(clientName) {
|
|
27
|
+
return clientName !== undefined && XML_CAPABLE_CLIENTS.has(clientName.toLowerCase());
|
|
28
|
+
}
|
|
29
|
+
export function renderHandoffArtifact(wu, clientName) {
|
|
30
|
+
const resolvedClient = clientName || 'generic';
|
|
31
|
+
const strategy = SpawnStrategyFactory.create(resolvedClient);
|
|
32
|
+
if (isXmlCapableClient(resolvedClient)) {
|
|
33
|
+
return {
|
|
34
|
+
content: generateTaskInvocation(wu.doc, wu.id, strategy),
|
|
35
|
+
extension: XML_EXTENSION,
|
|
36
|
+
format: 'xml',
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
content: generateCodexPrompt(wu.doc, wu.id, strategy),
|
|
41
|
+
extension: MARKDOWN_EXTENSION,
|
|
42
|
+
format: 'markdown',
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
export function writeExecutionPlanArtifacts(initId, allWUs, plan, options = {}) {
|
|
46
|
+
const waveGroups = plan.waves.map((wus, plannedWave) => ({ plannedWave, wus }));
|
|
47
|
+
return writeOrchestrationAttemptArtifacts(initId, allWUs, waveGroups, options);
|
|
48
|
+
}
|
|
49
|
+
export function writeCheckpointArtifacts(initId, allWUs, selectedWUs, options = {}) {
|
|
50
|
+
return writeOrchestrationAttemptArtifacts(initId, allWUs, [{ plannedWave: 0, wus: selectedWUs }], options);
|
|
51
|
+
}
|
|
52
|
+
function writeOrchestrationAttemptArtifacts(initId, allWUs, waveGroups, options = {}) {
|
|
53
|
+
const { clientName, dryRun = false } = options;
|
|
54
|
+
const executionSummary = options.executionSummary;
|
|
55
|
+
const launchAttempt = getNextLaunchAttempt(initId);
|
|
56
|
+
const artifactDir = join(ORCHESTRATION_ARTIFACT_DIR, initId, `${ATTEMPT_PREFIX}${launchAttempt}`);
|
|
57
|
+
const planPath = join(artifactDir, PLAN_FILENAME);
|
|
58
|
+
const launchPath = join(artifactDir, LAUNCH_FILENAME);
|
|
59
|
+
const statusPath = join(artifactDir, STATUS_FILENAME);
|
|
60
|
+
const handoffDir = join(artifactDir, HANDOFFS_DIRNAME);
|
|
61
|
+
const createdAt = new Date().toISOString();
|
|
62
|
+
const logicalWaveMap = calculateLogicalWaveMap(allWUs);
|
|
63
|
+
const launchableWUs = flattenWaveGroups(waveGroups, logicalWaveMap);
|
|
64
|
+
const logicalWaves = Array.from(new Set(launchableWUs.map((entry) => entry.logicalWave))).sort((left, right) => left - right);
|
|
65
|
+
const handoffReceipts = launchableWUs.map((entry) => createHandoffReceipt(entry, launchAttempt, handoffDir, clientName, createdAt, dryRun));
|
|
66
|
+
if (!dryRun) {
|
|
67
|
+
mkdirSync(handoffDir, { recursive: true });
|
|
68
|
+
for (let index = 0; index < handoffReceipts.length; index++) {
|
|
69
|
+
const receipt = handoffReceipts[index];
|
|
70
|
+
const launchableWU = launchableWUs[index];
|
|
71
|
+
const rendered = renderHandoffArtifact(launchableWU.wu, clientName);
|
|
72
|
+
writeFileSync(receipt.handoff_artifact_path, rendered.content, 'utf8');
|
|
73
|
+
}
|
|
74
|
+
const planData = {
|
|
75
|
+
initiative: initId,
|
|
76
|
+
created_at: createdAt,
|
|
77
|
+
launch_attempt: launchAttempt,
|
|
78
|
+
logical_waves: logicalWaves,
|
|
79
|
+
waves: waveGroups.map((group) => {
|
|
80
|
+
const groupEntries = launchableWUs.filter((entry) => entry.plannedWave === group.plannedWave);
|
|
81
|
+
const groupLogicalWaves = Array.from(new Set(groupEntries.map((entry) => entry.logicalWave))).sort((left, right) => left - right);
|
|
82
|
+
return {
|
|
83
|
+
planned_wave: group.plannedWave,
|
|
84
|
+
logical_wave: groupLogicalWaves[0] ?? FALLBACK_LOGICAL_WAVE,
|
|
85
|
+
logical_waves: groupLogicalWaves,
|
|
86
|
+
wus: groupEntries.map((entry) => ({
|
|
87
|
+
id: entry.wu.id,
|
|
88
|
+
lane: entry.wu.doc.lane,
|
|
89
|
+
logical_wave: entry.logicalWave,
|
|
90
|
+
})),
|
|
91
|
+
};
|
|
92
|
+
}),
|
|
93
|
+
};
|
|
94
|
+
const launchData = {
|
|
95
|
+
initiative: initId,
|
|
96
|
+
created_at: createdAt,
|
|
97
|
+
launch_attempt: launchAttempt,
|
|
98
|
+
logical_waves: logicalWaves,
|
|
99
|
+
handoffs: handoffReceipts,
|
|
100
|
+
};
|
|
101
|
+
const statusData = {
|
|
102
|
+
initiative: initId,
|
|
103
|
+
created_at: createdAt,
|
|
104
|
+
launch_attempt: launchAttempt,
|
|
105
|
+
logical_waves: logicalWaves,
|
|
106
|
+
actual_launch_confirmed: false,
|
|
107
|
+
treat_handoff_as_completed: false,
|
|
108
|
+
available_capacity: executionSummary?.availableCapacity ?? null,
|
|
109
|
+
max_active_workers: executionSummary?.maxActiveWorkers ?? null,
|
|
110
|
+
blocked_by_integrity: executionSummary?.blockedByIntegrity ?? false,
|
|
111
|
+
next_safe_actions: executionSummary?.nextSafeActions.map((action) => ({
|
|
112
|
+
type: action.type,
|
|
113
|
+
wu_id: action.wuId,
|
|
114
|
+
reason: action.reason,
|
|
115
|
+
logical_wave: action.logicalWave,
|
|
116
|
+
})) ?? [],
|
|
117
|
+
wus: allWUs.map((wu) => {
|
|
118
|
+
const summaryEntry = executionSummary?.wus.find((entry) => entry.wuId === wu.id);
|
|
119
|
+
const launchableEntry = launchableWUs.find((entry) => entry.wu.id === wu.id);
|
|
120
|
+
const handoffState = handoffReceipts.find((receipt) => receipt.wu_id === wu.id);
|
|
121
|
+
return {
|
|
122
|
+
wu_id: wu.id,
|
|
123
|
+
lane: wu.doc.lane,
|
|
124
|
+
logical_wave: summaryEntry?.logicalWave ?? launchableEntry?.logicalWave ?? FALLBACK_LOGICAL_WAVE,
|
|
125
|
+
orchestration_state: launchableEntry || handoffState ? 'handoff_emitted' : (summaryEntry?.state ?? 'ready'),
|
|
126
|
+
yaml_status: wu.doc.status ?? 'unknown',
|
|
127
|
+
};
|
|
128
|
+
}),
|
|
129
|
+
};
|
|
130
|
+
writeFileSync(planPath, JSON.stringify(planData, null, 2), 'utf8');
|
|
131
|
+
writeFileSync(launchPath, JSON.stringify(launchData, null, 2), 'utf8');
|
|
132
|
+
writeFileSync(statusPath, JSON.stringify(statusData, null, 2), 'utf8');
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
artifactDir,
|
|
136
|
+
planPath,
|
|
137
|
+
launchPath,
|
|
138
|
+
statusPath,
|
|
139
|
+
logicalWaves,
|
|
140
|
+
launchAttempt,
|
|
141
|
+
handoffReceipts,
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
function flattenWaveGroups(waveGroups, logicalWaveMap) {
|
|
145
|
+
return waveGroups.flatMap((group) => group.wus.map((wu) => ({
|
|
146
|
+
logicalWave: logicalWaveMap.get(wu.id) ?? FALLBACK_LOGICAL_WAVE,
|
|
147
|
+
plannedWave: group.plannedWave,
|
|
148
|
+
wu,
|
|
149
|
+
})));
|
|
150
|
+
}
|
|
151
|
+
function createHandoffReceipt(entry, launchAttempt, handoffDir, clientName, emittedAt, dryRun) {
|
|
152
|
+
const rendered = renderHandoffArtifact(entry.wu, clientName);
|
|
153
|
+
const handoffArtifactPath = join(handoffDir, `${entry.wu.id}.${rendered.extension}`);
|
|
154
|
+
if (!dryRun && !existsSync(handoffDir)) {
|
|
155
|
+
mkdirSync(handoffDir, { recursive: true });
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
wu_id: entry.wu.id,
|
|
159
|
+
lane: entry.wu.doc.lane,
|
|
160
|
+
logical_wave: entry.logicalWave,
|
|
161
|
+
launch_attempt: launchAttempt,
|
|
162
|
+
handoff_artifact_path: handoffArtifactPath,
|
|
163
|
+
handoff_format: rendered.format,
|
|
164
|
+
orchestration_state: 'handoff_emitted',
|
|
165
|
+
emitted_at: emittedAt,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
function calculateLogicalWaveMap(wus) {
|
|
169
|
+
const logicalWaveMap = new Map();
|
|
170
|
+
const allWuIds = new Set(wus.map((wu) => wu.id));
|
|
171
|
+
const adjacency = new Map();
|
|
172
|
+
const inDegree = new Map();
|
|
173
|
+
for (const wu of wus) {
|
|
174
|
+
adjacency.set(wu.id, []);
|
|
175
|
+
inDegree.set(wu.id, 0);
|
|
176
|
+
}
|
|
177
|
+
for (const wu of wus) {
|
|
178
|
+
const internalDeps = getAllDependencies(wu.doc).filter((depId) => allWuIds.has(depId));
|
|
179
|
+
inDegree.set(wu.id, internalDeps.length);
|
|
180
|
+
for (const depId of internalDeps) {
|
|
181
|
+
const dependants = adjacency.get(depId);
|
|
182
|
+
if (dependants) {
|
|
183
|
+
dependants.push(wu.id);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
const queue = Array.from(inDegree.entries())
|
|
188
|
+
.filter(([, degree]) => degree === 0)
|
|
189
|
+
.map(([wuId]) => wuId)
|
|
190
|
+
.sort();
|
|
191
|
+
for (const wuId of queue) {
|
|
192
|
+
logicalWaveMap.set(wuId, FALLBACK_LOGICAL_WAVE);
|
|
193
|
+
}
|
|
194
|
+
while (queue.length > 0) {
|
|
195
|
+
const currentId = queue.shift();
|
|
196
|
+
if (!currentId) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
const currentWave = logicalWaveMap.get(currentId) ?? FALLBACK_LOGICAL_WAVE;
|
|
200
|
+
const dependants = adjacency.get(currentId) ?? [];
|
|
201
|
+
for (const dependantId of dependants) {
|
|
202
|
+
const nextWave = currentWave + 1;
|
|
203
|
+
logicalWaveMap.set(dependantId, Math.max(logicalWaveMap.get(dependantId) ?? 0, nextWave));
|
|
204
|
+
const remainingDegree = (inDegree.get(dependantId) ?? 1) - 1;
|
|
205
|
+
inDegree.set(dependantId, remainingDegree);
|
|
206
|
+
if (remainingDegree === 0) {
|
|
207
|
+
queue.push(dependantId);
|
|
208
|
+
queue.sort();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
for (const wu of wus) {
|
|
213
|
+
if (!logicalWaveMap.has(wu.id)) {
|
|
214
|
+
logicalWaveMap.set(wu.id, FALLBACK_LOGICAL_WAVE);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
return logicalWaveMap;
|
|
218
|
+
}
|
|
219
|
+
function getNextLaunchAttempt(initId) {
|
|
220
|
+
const attemptDirsPath = join(ORCHESTRATION_ARTIFACT_DIR, initId);
|
|
221
|
+
const legacyPattern = new RegExp(`^${initId}-wave-(\\d+)\\.json$`);
|
|
222
|
+
let maxAttempt = FALLBACK_ATTEMPT;
|
|
223
|
+
if (existsSync(attemptDirsPath)) {
|
|
224
|
+
for (const entry of readdirSync(attemptDirsPath, { withFileTypes: true })) {
|
|
225
|
+
if (!entry.isDirectory() || !entry.name.startsWith(ATTEMPT_PREFIX)) {
|
|
226
|
+
continue;
|
|
227
|
+
}
|
|
228
|
+
const parsed = Number.parseInt(entry.name.slice(ATTEMPT_PREFIX.length), 10);
|
|
229
|
+
if (!Number.isNaN(parsed)) {
|
|
230
|
+
maxAttempt = Math.max(maxAttempt, parsed);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (existsSync(WAVE_MANIFEST_DIR)) {
|
|
235
|
+
for (const file of readdirSync(WAVE_MANIFEST_DIR)) {
|
|
236
|
+
const match = file.match(legacyPattern);
|
|
237
|
+
if (!match) {
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
const parsed = Number.parseInt(match[1] ?? '', 10);
|
|
241
|
+
if (!Number.isNaN(parsed)) {
|
|
242
|
+
maxAttempt = Math.max(maxAttempt, parsed);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
return maxAttempt + 1;
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=artifacts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifacts.js","sourceRoot":"","sources":["../../src/orchestrator/artifacts.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"checkpoint.d.ts","sourceRoot":"","sources":["../../src/orchestrator/checkpoint.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,OAAO,KAAK,EACV,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EAEpB,sBAAsB,EACvB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"checkpoint.d.ts","sourceRoot":"","sources":["../../src/orchestrator/checkpoint.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,OAAO,KAAK,EACV,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,oBAAoB,EAEpB,sBAAsB,EACvB,MAAM,YAAY,CAAC;AAapB;;;;;;;GAOG;AACH,eAAO,MAAM,0BAA0B;IACrC,6EAA6E;;IAE7E,uEAAuE;;CAExE,CAAC;AAEF;;;;;;;;;GASG;AACH,wBAAgB,wBAAwB,CAAC,UAAU,EAAE,OAAO,EAAE,GAAG,sBAAsB,CAqCtF;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,oBAAoB,CA6C/E;AAED;;;;;GAKG;AACH,wBAAsB,+BAA+B,CACnD,GAAG,EAAE,OAAO,EAAE,GACb,OAAO,CAAC,oBAAoB,CAAC,CA6C/B;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,qBAAqB,CACnC,OAAO,EAAE,iBAAiB,EAC1B,GAAG,EAAE,OAAO,EAAE,GACb,oBAAoB,CAqCtB;AAED;;;;;;GAMG;AACH,wBAAsB,0BAA0B,CAC9C,OAAO,EAAE,iBAAiB,EAC1B,GAAG,EAAE,OAAO,EAAE,GACb,OAAO,CAAC,oBAAoB,CAAC,CAqC/B;AAED;;;;;;;GAOG;AACH,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAmBxE;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,iBAAsB,GAC9B,oBAAoB,GAAG,IAAI,CAoP7B"}
|
|
@@ -13,6 +13,8 @@ import { join } from 'node:path';
|
|
|
13
13
|
import { findInitiative, getInitiativeWUs } from '../initiative-yaml.js';
|
|
14
14
|
import { WAVE_MANIFEST_DIR, hasStamp, getAllDependencies } from './shared.js';
|
|
15
15
|
import { buildExecutionPlan, buildExecutionPlanAsync } from './execution-planning.js';
|
|
16
|
+
import { writeCheckpointArtifacts } from './artifacts.js';
|
|
17
|
+
import { reconcileInitiativeExecution } from './reconciliation.js';
|
|
16
18
|
import { createError, ErrorCodes } from '@lumenflow/core/error-handler';
|
|
17
19
|
import { WU_STATUS } from '@lumenflow/core/wu-constants';
|
|
18
20
|
/**
|
|
@@ -302,7 +304,7 @@ export function validateCheckpointFlags(options) {
|
|
|
302
304
|
* Wave data or null if all WUs complete
|
|
303
305
|
*/
|
|
304
306
|
export function buildCheckpointWave(initRef, options = {}) {
|
|
305
|
-
const { dryRun = false } = options;
|
|
307
|
+
const { dryRun = false, clientName, executionEvidence = [], maxActiveWorkers, blockOnIntegrity = true, } = options;
|
|
306
308
|
// Load initiative and WUs
|
|
307
309
|
const initData = findInitiative(initRef);
|
|
308
310
|
if (!initData) {
|
|
@@ -310,6 +312,18 @@ export function buildCheckpointWave(initRef, options = {}) {
|
|
|
310
312
|
}
|
|
311
313
|
const initId = initData.id;
|
|
312
314
|
const wus = getInitiativeWUs(initRef);
|
|
315
|
+
const stampAwareEvidence = wus.map((wu) => {
|
|
316
|
+
const existing = executionEvidence.find((entry) => entry.wuId === wu.id);
|
|
317
|
+
return {
|
|
318
|
+
wuId: wu.id,
|
|
319
|
+
stampPresent: hasStamp(wu.id),
|
|
320
|
+
...existing,
|
|
321
|
+
};
|
|
322
|
+
});
|
|
323
|
+
const executionSummary = reconcileInitiativeExecution(wus, stampAwareEvidence, {
|
|
324
|
+
maxActiveWorkers,
|
|
325
|
+
blockOnIntegrity,
|
|
326
|
+
});
|
|
313
327
|
// Filter to spawn candidates:
|
|
314
328
|
// 1. status: ready only (from YAML - authoritative)
|
|
315
329
|
// 2. No stamp exists (idempotency)
|
|
@@ -322,9 +336,48 @@ export function buildCheckpointWave(initRef, options = {}) {
|
|
|
322
336
|
}
|
|
323
337
|
return true;
|
|
324
338
|
});
|
|
325
|
-
// If no ready candidates, all work is done
|
|
326
339
|
if (readyCandidates.length === 0) {
|
|
327
|
-
|
|
340
|
+
const unfinishedActions = executionSummary.nextSafeActions.filter((action) => action.type !== 'launch');
|
|
341
|
+
const hasIncompleteExecution = executionSummary.wus.some((wu) => wu.state !== 'done');
|
|
342
|
+
if (!hasIncompleteExecution) {
|
|
343
|
+
return null;
|
|
344
|
+
}
|
|
345
|
+
return {
|
|
346
|
+
initiative: initId,
|
|
347
|
+
wave: -1,
|
|
348
|
+
wus: [],
|
|
349
|
+
manifestPath: null,
|
|
350
|
+
artifactDir: '',
|
|
351
|
+
planPath: '',
|
|
352
|
+
launchPath: '',
|
|
353
|
+
statusPath: '',
|
|
354
|
+
waitingMessage: 'No ready WUs can launch yet. Finish or recover in-flight work first.',
|
|
355
|
+
logicalWaves: [],
|
|
356
|
+
launchAttempt: -1,
|
|
357
|
+
handoffReceipts: [],
|
|
358
|
+
availableCapacity: executionSummary.availableCapacity,
|
|
359
|
+
nextSafeActions: unfinishedActions,
|
|
360
|
+
executionSummary,
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
if (executionSummary.blockedByIntegrity) {
|
|
364
|
+
return {
|
|
365
|
+
initiative: initId,
|
|
366
|
+
wave: -1,
|
|
367
|
+
wus: [],
|
|
368
|
+
manifestPath: null,
|
|
369
|
+
artifactDir: '',
|
|
370
|
+
planPath: '',
|
|
371
|
+
launchPath: '',
|
|
372
|
+
statusPath: '',
|
|
373
|
+
waitingMessage: 'Unsafe to advance while orchestration integrity issues remain.',
|
|
374
|
+
logicalWaves: [],
|
|
375
|
+
launchAttempt: -1,
|
|
376
|
+
handoffReceipts: [],
|
|
377
|
+
availableCapacity: executionSummary.availableCapacity,
|
|
378
|
+
nextSafeActions: executionSummary.nextSafeActions,
|
|
379
|
+
executionSummary,
|
|
380
|
+
};
|
|
328
381
|
}
|
|
329
382
|
// WU-2040: Filter by dependency stamps (wait-for-completion pattern)
|
|
330
383
|
const depResult = filterByDependencyStamps(readyCandidates);
|
|
@@ -335,34 +388,111 @@ export function buildCheckpointWave(initRef, options = {}) {
|
|
|
335
388
|
wave: -1,
|
|
336
389
|
wus: [],
|
|
337
390
|
manifestPath: null,
|
|
391
|
+
artifactDir: '',
|
|
392
|
+
planPath: '',
|
|
393
|
+
launchPath: '',
|
|
394
|
+
statusPath: '',
|
|
338
395
|
blockedBy: depResult.blockingDeps,
|
|
339
396
|
waitingMessage: depResult.waitingMessage,
|
|
397
|
+
logicalWaves: [],
|
|
398
|
+
launchAttempt: -1,
|
|
399
|
+
handoffReceipts: [],
|
|
400
|
+
availableCapacity: executionSummary.availableCapacity,
|
|
401
|
+
nextSafeActions: executionSummary.nextSafeActions,
|
|
402
|
+
executionSummary,
|
|
403
|
+
};
|
|
404
|
+
}
|
|
405
|
+
const launchableIds = new Set(executionSummary.launchableWuIds);
|
|
406
|
+
const launchableCandidates = depResult.spawnable.filter((wu) => launchableIds.has(wu.id));
|
|
407
|
+
if (launchableCandidates.length === 0) {
|
|
408
|
+
return {
|
|
409
|
+
initiative: initId,
|
|
410
|
+
wave: -1,
|
|
411
|
+
wus: [],
|
|
412
|
+
manifestPath: null,
|
|
413
|
+
artifactDir: '',
|
|
414
|
+
planPath: '',
|
|
415
|
+
launchPath: '',
|
|
416
|
+
statusPath: '',
|
|
417
|
+
waitingMessage: executionSummary.nextSafeActions.length > 0
|
|
418
|
+
? 'No WUs can launch yet. Follow the next safe actions before advancing.'
|
|
419
|
+
: 'No WUs are currently eligible to launch.',
|
|
420
|
+
logicalWaves: [],
|
|
421
|
+
launchAttempt: -1,
|
|
422
|
+
handoffReceipts: [],
|
|
423
|
+
availableCapacity: executionSummary.availableCapacity,
|
|
424
|
+
nextSafeActions: executionSummary.nextSafeActions,
|
|
425
|
+
executionSummary,
|
|
340
426
|
};
|
|
341
427
|
}
|
|
428
|
+
const capacityLimit = executionSummary.availableCapacity === null
|
|
429
|
+
? Number.POSITIVE_INFINITY
|
|
430
|
+
: executionSummary.availableCapacity;
|
|
342
431
|
// Apply lane WIP=1 constraint: max one WU per lane per wave
|
|
343
432
|
const selectedWUs = [];
|
|
344
433
|
const usedLanes = new Set();
|
|
345
434
|
for (const wu of depResult.spawnable) {
|
|
435
|
+
if (!launchableIds.has(wu.id)) {
|
|
436
|
+
continue;
|
|
437
|
+
}
|
|
438
|
+
if (selectedWUs.length >= capacityLimit) {
|
|
439
|
+
break;
|
|
440
|
+
}
|
|
346
441
|
const lane = wu.doc.lane;
|
|
347
442
|
if (!usedLanes.has(lane)) {
|
|
348
443
|
selectedWUs.push(wu);
|
|
349
444
|
usedLanes.add(lane);
|
|
350
445
|
}
|
|
351
446
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
447
|
+
if (selectedWUs.length === 0) {
|
|
448
|
+
return {
|
|
449
|
+
initiative: initId,
|
|
450
|
+
wave: -1,
|
|
451
|
+
wus: [],
|
|
452
|
+
manifestPath: null,
|
|
453
|
+
artifactDir: '',
|
|
454
|
+
planPath: '',
|
|
455
|
+
launchPath: '',
|
|
456
|
+
statusPath: '',
|
|
457
|
+
waitingMessage: 'No WUs fit the remaining capacity or lane limits in this launch.',
|
|
458
|
+
logicalWaves: [],
|
|
459
|
+
launchAttempt: -1,
|
|
460
|
+
handoffReceipts: [],
|
|
461
|
+
availableCapacity: executionSummary.availableCapacity,
|
|
462
|
+
nextSafeActions: executionSummary.nextSafeActions,
|
|
463
|
+
executionSummary,
|
|
464
|
+
};
|
|
465
|
+
}
|
|
466
|
+
const artifactBundle = writeCheckpointArtifacts(initId, wus, selectedWUs, {
|
|
467
|
+
clientName,
|
|
468
|
+
dryRun,
|
|
469
|
+
executionSummary,
|
|
470
|
+
});
|
|
471
|
+
const waveNum = artifactBundle.launchAttempt;
|
|
472
|
+
// Build compatibility manifest
|
|
355
473
|
const manifest = {
|
|
356
474
|
initiative: initId,
|
|
357
475
|
wave: waveNum,
|
|
476
|
+
launch_attempt: artifactBundle.launchAttempt,
|
|
477
|
+
logical_waves: artifactBundle.logicalWaves,
|
|
358
478
|
created_at: new Date().toISOString(),
|
|
359
|
-
wus: selectedWUs.map((wu) =>
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
479
|
+
wus: selectedWUs.map((wu) => {
|
|
480
|
+
const receipt = artifactBundle.handoffReceipts.find((entry) => entry.wu_id === wu.id);
|
|
481
|
+
return {
|
|
482
|
+
id: wu.id,
|
|
483
|
+
lane: wu.doc.lane,
|
|
484
|
+
status: MANIFEST_WU_STATUS,
|
|
485
|
+
logical_wave: receipt?.logical_wave,
|
|
486
|
+
handoff_artifact_path: receipt?.handoff_artifact_path,
|
|
487
|
+
handoff_format: receipt?.handoff_format,
|
|
488
|
+
};
|
|
489
|
+
}),
|
|
364
490
|
lane_validation: 'pass',
|
|
365
491
|
done_criteria: 'All stamps exist in .lumenflow/stamps/',
|
|
492
|
+
artifact_dir: artifactBundle.artifactDir,
|
|
493
|
+
plan_path: artifactBundle.planPath,
|
|
494
|
+
launch_path: artifactBundle.launchPath,
|
|
495
|
+
status_path: artifactBundle.statusPath,
|
|
366
496
|
};
|
|
367
497
|
// WU-2277: Skip file creation in dry-run mode
|
|
368
498
|
const manifestPath = join(WAVE_MANIFEST_DIR, `${initId}-wave-${waveNum}.json`);
|
|
@@ -379,6 +509,16 @@ export function buildCheckpointWave(initRef, options = {}) {
|
|
|
379
509
|
wave: waveNum,
|
|
380
510
|
wus: manifest.wus,
|
|
381
511
|
manifestPath,
|
|
512
|
+
artifactDir: artifactBundle.artifactDir,
|
|
513
|
+
planPath: artifactBundle.planPath,
|
|
514
|
+
launchPath: artifactBundle.launchPath,
|
|
515
|
+
statusPath: artifactBundle.statusPath,
|
|
516
|
+
logicalWaves: artifactBundle.logicalWaves,
|
|
517
|
+
launchAttempt: artifactBundle.launchAttempt,
|
|
518
|
+
handoffReceipts: artifactBundle.handoffReceipts,
|
|
519
|
+
availableCapacity: executionSummary.availableCapacity,
|
|
520
|
+
nextSafeActions: executionSummary.nextSafeActions,
|
|
521
|
+
executionSummary,
|
|
382
522
|
};
|
|
383
523
|
}
|
|
384
524
|
// ── Internal helpers ──────────────────────────────────────────────────────────
|
|
@@ -429,18 +569,4 @@ function _getSpawnedWUIds(initId) {
|
|
|
429
569
|
}
|
|
430
570
|
return spawnedIds;
|
|
431
571
|
}
|
|
432
|
-
/**
|
|
433
|
-
* Determine the next wave number for an initiative.
|
|
434
|
-
*
|
|
435
|
-
* @param {string} initId - Initiative ID
|
|
436
|
-
* @returns {number} Next wave number (0-indexed)
|
|
437
|
-
*/
|
|
438
|
-
function getNextWaveNumber(initId) {
|
|
439
|
-
const manifests = getExistingWaveManifests(initId);
|
|
440
|
-
if (manifests.length === 0) {
|
|
441
|
-
return 0;
|
|
442
|
-
}
|
|
443
|
-
const maxWave = Math.max(...manifests.map((m) => m.wave));
|
|
444
|
-
return maxWave + 1;
|
|
445
|
-
}
|
|
446
572
|
//# sourceMappingURL=checkpoint.js.map
|