@lumenflow/cli 3.16.0 → 3.16.1
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/docs-sync.js +97 -46
- package/dist/docs-sync.js.map +1 -1
- package/dist/lumenflow-upgrade.js +19 -13
- package/dist/lumenflow-upgrade.js.map +1 -1
- package/package.json +8 -8
- package/packs/sidekick/.turbo/turbo-build.log +1 -1
- package/packs/sidekick/package.json +1 -1
- package/packs/software-delivery/.turbo/turbo-build.log +1 -1
- package/packs/software-delivery/package.json +1 -1
- package/dist/chunk-2D2VOCA4.js +0 -37
- package/dist/chunk-2D5KFYGX.js +0 -284
- package/dist/chunk-2GXVIN57.js +0 -14072
- package/dist/chunk-2MQ7HZWZ.js +0 -26
- package/dist/chunk-2UFQ3A3C.js +0 -643
- package/dist/chunk-3RG5ZIWI.js +0 -10
- package/dist/chunk-4N74J3UT.js +0 -15
- package/dist/chunk-5GTOXFYR.js +0 -392
- package/dist/chunk-5VY6MQMC.js +0 -240
- package/dist/chunk-67XVPMRY.js +0 -1297
- package/dist/chunk-6HO4GWJE.js +0 -164
- package/dist/chunk-6W5XHWYV.js +0 -1890
- package/dist/chunk-6X4EMYJQ.js +0 -64
- package/dist/chunk-6XYXI2NQ.js +0 -772
- package/dist/chunk-7ANSOV6Q.js +0 -285
- package/dist/chunk-A624LFLB.js +0 -1380
- package/dist/chunk-ADN5NHG4.js +0 -126
- package/dist/chunk-B7YJYJKG.js +0 -33
- package/dist/chunk-CCLHCPKG.js +0 -210
- package/dist/chunk-CK36VROC.js +0 -1584
- package/dist/chunk-D3UOFRSB.js +0 -81
- package/dist/chunk-DFR4DJBM.js +0 -230
- package/dist/chunk-DSYBDHYH.js +0 -79
- package/dist/chunk-DWMLTXKQ.js +0 -1176
- package/dist/chunk-E3REJTAJ.js +0 -28
- package/dist/chunk-EA3IVO64.js +0 -633
- package/dist/chunk-EK2AKZKD.js +0 -55
- package/dist/chunk-ELD7JTTT.js +0 -343
- package/dist/chunk-EX6TT2XI.js +0 -195
- package/dist/chunk-EXINSFZE.js +0 -82
- package/dist/chunk-EZ6ZBYBM.js +0 -510
- package/dist/chunk-FBKAPTJ2.js +0 -16
- package/dist/chunk-FVLV5RYH.js +0 -1118
- package/dist/chunk-GDNSBQVK.js +0 -2485
- package/dist/chunk-GPQHMBNN.js +0 -278
- package/dist/chunk-GTFJB67L.js +0 -68
- package/dist/chunk-HANJXVKW.js +0 -1127
- package/dist/chunk-HEVS5YLD.js +0 -269
- package/dist/chunk-HMEVZKPQ.js +0 -9
- package/dist/chunk-HRGSYNLM.js +0 -3511
- package/dist/chunk-ISZR5N4K.js +0 -60
- package/dist/chunk-J6SUPR2C.js +0 -226
- package/dist/chunk-JERYVEIZ.js +0 -244
- package/dist/chunk-JHHWGL2N.js +0 -87
- package/dist/chunk-JONWQUB5.js +0 -775
- package/dist/chunk-K2DIWWDM.js +0 -1766
- package/dist/chunk-KY4PGL5V.js +0 -969
- package/dist/chunk-L737LQ4C.js +0 -1285
- package/dist/chunk-LFTWYIB2.js +0 -497
- package/dist/chunk-LV47RFNJ.js +0 -41
- package/dist/chunk-MKSAITI7.js +0 -15
- package/dist/chunk-MZ7RKIX4.js +0 -212
- package/dist/chunk-NAP6CFSO.js +0 -84
- package/dist/chunk-ND6MY37M.js +0 -16
- package/dist/chunk-NMG736UR.js +0 -683
- package/dist/chunk-NRAXROED.js +0 -32
- package/dist/chunk-NRIZR3A7.js +0 -690
- package/dist/chunk-NX43BG3M.js +0 -233
- package/dist/chunk-O645XLSI.js +0 -297
- package/dist/chunk-OMJD6A3S.js +0 -235
- package/dist/chunk-QB6SJD4T.js +0 -430
- package/dist/chunk-QFSTL4J3.js +0 -276
- package/dist/chunk-QLGDFMFX.js +0 -212
- package/dist/chunk-RIAAGL2E.js +0 -13
- package/dist/chunk-RWO5XMZ6.js +0 -86
- package/dist/chunk-RXRKBBSM.js +0 -149
- package/dist/chunk-RZOZMML6.js +0 -363
- package/dist/chunk-U7I7FS7T.js +0 -113
- package/dist/chunk-UI42RODY.js +0 -717
- package/dist/chunk-UTVMVSCO.js +0 -519
- package/dist/chunk-V6OJGLBA.js +0 -1746
- package/dist/chunk-W2JHVH7D.js +0 -152
- package/dist/chunk-WD3Y7VQN.js +0 -280
- package/dist/chunk-WOCTQ5MS.js +0 -303
- package/dist/chunk-WZR3ZUNN.js +0 -696
- package/dist/chunk-XGI665H7.js +0 -150
- package/dist/chunk-XKY65P2T.js +0 -304
- package/dist/chunk-Y4CQZY65.js +0 -57
- package/dist/chunk-YFEXKLVE.js +0 -194
- package/dist/chunk-YHO3HS5X.js +0 -287
- package/dist/chunk-YLS7AZSX.js +0 -738
- package/dist/chunk-ZE473AO6.js +0 -49
- package/dist/chunk-ZF747T3O.js +0 -644
- package/dist/chunk-ZHCZHZH3.js +0 -43
- package/dist/chunk-ZZNZX2XY.js +0 -87
- package/dist/constants-7QAP3VQ4.js +0 -23
- package/dist/dist-IY3UUMWK.js +0 -33
- package/dist/invariants-runner-W5RGHCSU.js +0 -27
- package/dist/lane-lock-6J36HD5O.js +0 -35
- package/dist/mem-checkpoint-core-EANG2GVN.js +0 -14
- package/dist/mem-signal-core-2LZ2WYHW.js +0 -19
- package/dist/memory-store-OLB5FO7K.js +0 -18
- package/dist/service-6BYCOCO5.js +0 -13
- package/dist/spawn-policy-resolver-NTSZYQ6R.js +0 -17
- package/dist/spawn-task-builder-R4E2BHSW.js +0 -22
- package/dist/wu-done-pr-WLFFFEPJ.js +0 -25
- package/dist/wu-done-validation-3J5E36FE.js +0 -30
- package/dist/wu-duplicate-id-detector-5S7JHELK.js +0 -232
- package/packs/sidekick/.turbo/turbo-typecheck.log +0 -4
- package/packs/software-delivery/.turbo/turbo-typecheck.log +0 -4
package/dist/chunk-FVLV5RYH.js
DELETED
|
@@ -1,1118 +0,0 @@
|
|
|
1
|
-
import {
|
|
2
|
-
findInitiative,
|
|
3
|
-
getInitiativeWUs
|
|
4
|
-
} from "./chunk-MZ7RKIX4.js";
|
|
5
|
-
import {
|
|
6
|
-
buildDependencyGraph,
|
|
7
|
-
buildDependencyGraphAsync,
|
|
8
|
-
validateGraph
|
|
9
|
-
} from "./chunk-YHO3HS5X.js";
|
|
10
|
-
import {
|
|
11
|
-
SpawnStrategyFactory
|
|
12
|
-
} from "./chunk-2GXVIN57.js";
|
|
13
|
-
import {
|
|
14
|
-
generateTaskInvocation
|
|
15
|
-
} from "./chunk-6W5XHWYV.js";
|
|
16
|
-
import {
|
|
17
|
-
parseYAML
|
|
18
|
-
} from "./chunk-NRIZR3A7.js";
|
|
19
|
-
import {
|
|
20
|
-
WU_PATHS
|
|
21
|
-
} from "./chunk-6HO4GWJE.js";
|
|
22
|
-
import {
|
|
23
|
-
STRING_LITERALS
|
|
24
|
-
} from "./chunk-DWMLTXKQ.js";
|
|
25
|
-
import {
|
|
26
|
-
WU_STATUS
|
|
27
|
-
} from "./chunk-V6OJGLBA.js";
|
|
28
|
-
import {
|
|
29
|
-
ErrorCodes,
|
|
30
|
-
createError
|
|
31
|
-
} from "./chunk-RXRKBBSM.js";
|
|
32
|
-
|
|
33
|
-
// ../initiatives/dist/orchestrator/shared.js
|
|
34
|
-
import { existsSync } from "fs";
|
|
35
|
-
import { join } from "path";
|
|
36
|
-
var WAVE_MANIFEST_DIR = ".lumenflow/artifacts/waves";
|
|
37
|
-
var STAMPS_DIR = ".lumenflow/stamps";
|
|
38
|
-
var LOG_PREFIX = "[orchestrate:initiative]";
|
|
39
|
-
var DEFAULT_DEFERRED_REASON = "waiting for dependencies";
|
|
40
|
-
function hasStamp(wuId) {
|
|
41
|
-
const stampPath = join(STAMPS_DIR, `${wuId}.done`);
|
|
42
|
-
return existsSync(stampPath);
|
|
43
|
-
}
|
|
44
|
-
function getAllDependencies(doc) {
|
|
45
|
-
const blockedBy = doc.blocked_by ?? [];
|
|
46
|
-
const dependencies = doc.dependencies ?? [];
|
|
47
|
-
const allDeps = /* @__PURE__ */ new Set([...blockedBy, ...dependencies]);
|
|
48
|
-
return Array.from(allDeps);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
// ../initiatives/dist/orchestrator/lane-policy.js
|
|
52
|
-
function getLockPolicyForLane(lane, laneConfigs) {
|
|
53
|
-
if (!laneConfigs) {
|
|
54
|
-
return "all";
|
|
55
|
-
}
|
|
56
|
-
const config = laneConfigs[lane];
|
|
57
|
-
if (!config || !config.lock_policy) {
|
|
58
|
-
return "all";
|
|
59
|
-
}
|
|
60
|
-
return config.lock_policy;
|
|
61
|
-
}
|
|
62
|
-
function getLaneAvailability(wus, options = {}) {
|
|
63
|
-
const { laneConfigs = {} } = options;
|
|
64
|
-
const result = {};
|
|
65
|
-
const wusByLane = /* @__PURE__ */ new Map();
|
|
66
|
-
for (const wu of wus) {
|
|
67
|
-
const lane = wu.doc.lane;
|
|
68
|
-
if (lane) {
|
|
69
|
-
const laneWUs = wusByLane.get(lane);
|
|
70
|
-
if (laneWUs) {
|
|
71
|
-
laneWUs.push(wu);
|
|
72
|
-
} else {
|
|
73
|
-
wusByLane.set(lane, [wu]);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
for (const [lane, laneWUs] of wusByLane) {
|
|
78
|
-
const policy = getLockPolicyForLane(lane, laneConfigs);
|
|
79
|
-
let inProgressCount = 0;
|
|
80
|
-
let blockedCount = 0;
|
|
81
|
-
let occupiedBy;
|
|
82
|
-
for (const wu of laneWUs) {
|
|
83
|
-
const status = wu.doc.status ?? "unknown";
|
|
84
|
-
if (status === WU_STATUS.IN_PROGRESS) {
|
|
85
|
-
inProgressCount++;
|
|
86
|
-
if (!occupiedBy) {
|
|
87
|
-
occupiedBy = wu.id;
|
|
88
|
-
}
|
|
89
|
-
} else if (status === WU_STATUS.BLOCKED) {
|
|
90
|
-
blockedCount++;
|
|
91
|
-
if (policy === "all" && !occupiedBy) {
|
|
92
|
-
occupiedBy = wu.id;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
let available;
|
|
97
|
-
if (policy === "none") {
|
|
98
|
-
available = true;
|
|
99
|
-
occupiedBy = void 0;
|
|
100
|
-
} else if (policy === "active") {
|
|
101
|
-
available = inProgressCount === 0;
|
|
102
|
-
if (available) {
|
|
103
|
-
occupiedBy = void 0;
|
|
104
|
-
}
|
|
105
|
-
} else {
|
|
106
|
-
available = inProgressCount === 0 && blockedCount === 0;
|
|
107
|
-
}
|
|
108
|
-
result[lane] = {
|
|
109
|
-
available,
|
|
110
|
-
policy,
|
|
111
|
-
occupiedBy,
|
|
112
|
-
blockedCount,
|
|
113
|
-
inProgressCount
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
return result;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// ../initiatives/dist/orchestrator/execution-planning.js
|
|
120
|
-
async function buildExecutionPlanAsync(wus) {
|
|
121
|
-
const { readyWUs, skipped, skippedWithReasons, deferred, doneStatuses, allWuMap, allWuIds } = categoriseWUs(wus);
|
|
122
|
-
if (readyWUs.length === 0) {
|
|
123
|
-
return { waves: [], skipped, skippedWithReasons, deferred };
|
|
124
|
-
}
|
|
125
|
-
const wuMap = new Map(readyWUs.map((wu) => [wu.id, wu]));
|
|
126
|
-
const wuIds = new Set(wuMap.keys());
|
|
127
|
-
const graph = await buildDependencyGraphAsync();
|
|
128
|
-
validateCycles(graph, wuIds);
|
|
129
|
-
const deferredIds = processDeferrals(readyWUs, allWuMap, allWuIds, doneStatuses, deferred);
|
|
130
|
-
const schedulableWUs = readyWUs.filter((wu) => !deferredIds.has(wu.id));
|
|
131
|
-
const schedulableMap = new Map(schedulableWUs.map((wu) => [wu.id, wu]));
|
|
132
|
-
const schedulableIds = new Set(schedulableMap.keys());
|
|
133
|
-
if (schedulableIds.size === 0) {
|
|
134
|
-
return { waves: [], skipped, skippedWithReasons, deferred };
|
|
135
|
-
}
|
|
136
|
-
const waves = buildWaves(schedulableMap, schedulableIds, skipped, wus, allWuIds);
|
|
137
|
-
return { waves, skipped, skippedWithReasons, deferred };
|
|
138
|
-
}
|
|
139
|
-
function buildExecutionPlanWithLockPolicy(wus, options = {}) {
|
|
140
|
-
const { laneConfigs = {} } = options;
|
|
141
|
-
const { readyWUs, skipped, skippedWithReasons, deferred, doneStatuses, allWuMap, allWuIds } = categoriseWUs(wus);
|
|
142
|
-
if (readyWUs.length === 0) {
|
|
143
|
-
return { waves: [], skipped, skippedWithReasons, deferred };
|
|
144
|
-
}
|
|
145
|
-
const wuMap = new Map(readyWUs.map((wu) => [wu.id, wu]));
|
|
146
|
-
const wuIds = new Set(wuMap.keys());
|
|
147
|
-
const graph = buildDependencyGraph();
|
|
148
|
-
validateCycles(graph, wuIds);
|
|
149
|
-
const deferredIds = processDeferrals(readyWUs, allWuMap, allWuIds, doneStatuses, deferred);
|
|
150
|
-
const schedulableWUs = readyWUs.filter((wu) => !deferredIds.has(wu.id));
|
|
151
|
-
const schedulableMap = new Map(schedulableWUs.map((wu) => [wu.id, wu]));
|
|
152
|
-
const schedulableIds = new Set(schedulableMap.keys());
|
|
153
|
-
if (schedulableIds.size === 0) {
|
|
154
|
-
return { waves: [], skipped, skippedWithReasons, deferred };
|
|
155
|
-
}
|
|
156
|
-
const lanesOccupiedByInProgress = /* @__PURE__ */ new Set();
|
|
157
|
-
const lanesOccupiedByBlocked = /* @__PURE__ */ new Set();
|
|
158
|
-
for (const wu of wus) {
|
|
159
|
-
const status = wu.doc.status ?? "unknown";
|
|
160
|
-
const lane = wu.doc.lane;
|
|
161
|
-
if (lane) {
|
|
162
|
-
if (status === WU_STATUS.IN_PROGRESS) {
|
|
163
|
-
lanesOccupiedByInProgress.add(lane);
|
|
164
|
-
} else if (status === WU_STATUS.BLOCKED) {
|
|
165
|
-
lanesOccupiedByBlocked.add(lane);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
const waves = [];
|
|
170
|
-
const remaining = new Set(schedulableIds);
|
|
171
|
-
const completed = new Set(skipped);
|
|
172
|
-
addStampedExternalDeps(wus, allWuIds, completed);
|
|
173
|
-
while (remaining.size > 0) {
|
|
174
|
-
const wave = [];
|
|
175
|
-
const lanesInWave = /* @__PURE__ */ new Set();
|
|
176
|
-
const deferredToNextWave = [];
|
|
177
|
-
for (const id of remaining) {
|
|
178
|
-
const wu = schedulableMap.get(id);
|
|
179
|
-
if (!wu)
|
|
180
|
-
continue;
|
|
181
|
-
const blockers = getAllDependencies(wu.doc);
|
|
182
|
-
const allBlockersDone = blockers.every((blockerId) => completed.has(blockerId));
|
|
183
|
-
if (allBlockersDone) {
|
|
184
|
-
const lane = wu.doc.lane ?? "";
|
|
185
|
-
const policy = getLockPolicyForLane(lane, laneConfigs);
|
|
186
|
-
if (policy !== "none" && lanesInWave.has(lane)) {
|
|
187
|
-
deferredToNextWave.push(wu);
|
|
188
|
-
continue;
|
|
189
|
-
}
|
|
190
|
-
let laneBlocked = false;
|
|
191
|
-
if (policy === "active") {
|
|
192
|
-
laneBlocked = lanesOccupiedByInProgress.has(lane);
|
|
193
|
-
} else if (policy === "all") {
|
|
194
|
-
laneBlocked = lanesOccupiedByInProgress.has(lane) || lanesOccupiedByBlocked.has(lane);
|
|
195
|
-
}
|
|
196
|
-
if (laneBlocked) {
|
|
197
|
-
deferredToNextWave.push(wu);
|
|
198
|
-
} else {
|
|
199
|
-
wave.push(wu);
|
|
200
|
-
lanesInWave.add(lane);
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
if (wave.length === 0 && remaining.size > 0 && deferredToNextWave.length === 0) {
|
|
205
|
-
const stuckIds = Array.from(remaining);
|
|
206
|
-
throw createError(ErrorCodes.VALIDATION_ERROR, `Circular or unresolvable dependencies detected. Stuck WUs: ${stuckIds.join(", ")}`, { stuckIds });
|
|
207
|
-
}
|
|
208
|
-
if (wave.length > 0) {
|
|
209
|
-
waves.push(wave);
|
|
210
|
-
for (const wu of wave) {
|
|
211
|
-
remaining.delete(wu.id);
|
|
212
|
-
completed.add(wu.id);
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
if (wave.length === 0 && deferredToNextWave.length > 0) {
|
|
216
|
-
const processedLanes = /* @__PURE__ */ new Set();
|
|
217
|
-
for (const wu of deferredToNextWave) {
|
|
218
|
-
const lane = wu.doc.lane ?? "";
|
|
219
|
-
if (!processedLanes.has(lane)) {
|
|
220
|
-
wave.push(wu);
|
|
221
|
-
processedLanes.add(lane);
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
if (wave.length > 0) {
|
|
225
|
-
waves.push(wave);
|
|
226
|
-
for (const wu of wave) {
|
|
227
|
-
remaining.delete(wu.id);
|
|
228
|
-
completed.add(wu.id);
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
return { waves, skipped, skippedWithReasons, deferred };
|
|
234
|
-
}
|
|
235
|
-
function categoriseWUs(wus) {
|
|
236
|
-
const skipped = [];
|
|
237
|
-
const skippedWithReasons = [];
|
|
238
|
-
const deferred = [];
|
|
239
|
-
const doneStatuses = /* @__PURE__ */ new Set([WU_STATUS.DONE, WU_STATUS.COMPLETED]);
|
|
240
|
-
for (const wu of wus) {
|
|
241
|
-
const status = wu.doc.status ?? "unknown";
|
|
242
|
-
if (doneStatuses.has(status)) {
|
|
243
|
-
skipped.push(wu.id);
|
|
244
|
-
} else if (status !== WU_STATUS.READY) {
|
|
245
|
-
skippedWithReasons.push({ id: wu.id, reason: `status: ${status}` });
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
const readyWUs = wus.filter((wu) => wu.doc.status === WU_STATUS.READY);
|
|
249
|
-
const allWuMap = new Map(wus.map((wu) => [wu.id, wu]));
|
|
250
|
-
const allWuIds = new Set(allWuMap.keys());
|
|
251
|
-
return { readyWUs, skipped, skippedWithReasons, deferred, doneStatuses, allWuMap, allWuIds };
|
|
252
|
-
}
|
|
253
|
-
function validateCycles(graph, wuIds) {
|
|
254
|
-
const { cycles } = validateGraph(graph);
|
|
255
|
-
const relevantCycles = cycles.filter((cycle) => cycle.some((id) => wuIds.has(id)));
|
|
256
|
-
if (relevantCycles.length > 0) {
|
|
257
|
-
const cycleStr = relevantCycles.map((c) => c.join(" \u2192 ")).join("; ");
|
|
258
|
-
throw createError(ErrorCodes.VALIDATION_ERROR, `Circular dependencies detected: ${cycleStr}`, {
|
|
259
|
-
cycles: relevantCycles
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
function processDeferrals(readyWUs, allWuMap, allWuIds, doneStatuses, deferred) {
|
|
264
|
-
const deferredIds = /* @__PURE__ */ new Set();
|
|
265
|
-
const deferredReasons = /* @__PURE__ */ new Map();
|
|
266
|
-
const deferredBlockers = /* @__PURE__ */ new Map();
|
|
267
|
-
const addDeferredEntry = (wuId, blockers, reason) => {
|
|
268
|
-
deferredIds.add(wuId);
|
|
269
|
-
if (!deferredReasons.has(wuId)) {
|
|
270
|
-
deferredReasons.set(wuId, /* @__PURE__ */ new Set());
|
|
271
|
-
}
|
|
272
|
-
if (!deferredBlockers.has(wuId)) {
|
|
273
|
-
deferredBlockers.set(wuId, /* @__PURE__ */ new Set());
|
|
274
|
-
}
|
|
275
|
-
const reasonSet = deferredReasons.get(wuId);
|
|
276
|
-
const blockerSet = deferredBlockers.get(wuId);
|
|
277
|
-
for (const blockerId of blockers) {
|
|
278
|
-
blockerSet.add(blockerId);
|
|
279
|
-
}
|
|
280
|
-
reasonSet.add(reason);
|
|
281
|
-
};
|
|
282
|
-
for (const wu of readyWUs) {
|
|
283
|
-
const blockers = getAllDependencies(wu.doc);
|
|
284
|
-
const externalBlockers = blockers.filter((blockerId) => !allWuIds.has(blockerId));
|
|
285
|
-
const internalBlockers = blockers.filter((blockerId) => allWuIds.has(blockerId));
|
|
286
|
-
if (externalBlockers.length > 0) {
|
|
287
|
-
const unstampedBlockers = externalBlockers.filter((blockerId) => !hasStamp(blockerId));
|
|
288
|
-
if (unstampedBlockers.length > 0) {
|
|
289
|
-
addDeferredEntry(wu.id, unstampedBlockers, `waiting for external: ${unstampedBlockers.join(", ")}`);
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
if (internalBlockers.length > 0) {
|
|
293
|
-
const nonReadyInternal = internalBlockers.filter((blockerId) => {
|
|
294
|
-
const blocker = allWuMap.get(blockerId);
|
|
295
|
-
const status = blocker?.doc?.status ?? "unknown";
|
|
296
|
-
if (status === WU_STATUS.READY) {
|
|
297
|
-
return false;
|
|
298
|
-
}
|
|
299
|
-
return !doneStatuses.has(status);
|
|
300
|
-
});
|
|
301
|
-
if (nonReadyInternal.length > 0) {
|
|
302
|
-
const details = nonReadyInternal.map((blockerId) => {
|
|
303
|
-
const status = allWuMap.get(blockerId)?.doc?.status ?? "unknown";
|
|
304
|
-
return `${blockerId} (status: ${status})`;
|
|
305
|
-
});
|
|
306
|
-
addDeferredEntry(wu.id, nonReadyInternal, `waiting for internal: ${details.join(", ")}`);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
let hasNewDeferral = true;
|
|
311
|
-
while (hasNewDeferral) {
|
|
312
|
-
hasNewDeferral = false;
|
|
313
|
-
for (const wu of readyWUs) {
|
|
314
|
-
if (deferredIds.has(wu.id)) {
|
|
315
|
-
continue;
|
|
316
|
-
}
|
|
317
|
-
const blockers = getAllDependencies(wu.doc);
|
|
318
|
-
const deferredInternal = blockers.filter((blockerId) => allWuIds.has(blockerId) && deferredIds.has(blockerId));
|
|
319
|
-
if (deferredInternal.length > 0) {
|
|
320
|
-
const details = deferredInternal.map((blockerId) => {
|
|
321
|
-
const status = allWuMap.get(blockerId)?.doc?.status ?? "unknown";
|
|
322
|
-
return `${blockerId} (status: ${status})`;
|
|
323
|
-
});
|
|
324
|
-
addDeferredEntry(wu.id, deferredInternal, `waiting for internal: ${details.join(", ")}`);
|
|
325
|
-
hasNewDeferral = true;
|
|
326
|
-
}
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
for (const wu of readyWUs) {
|
|
330
|
-
if (deferredIds.has(wu.id)) {
|
|
331
|
-
const blockerSet = deferredBlockers.get(wu.id) || /* @__PURE__ */ new Set();
|
|
332
|
-
const reasonSet = deferredReasons.get(wu.id) || /* @__PURE__ */ new Set();
|
|
333
|
-
deferred.push({
|
|
334
|
-
id: wu.id,
|
|
335
|
-
blockedBy: Array.from(blockerSet),
|
|
336
|
-
reason: reasonSet.size > 0 ? Array.from(reasonSet).join("; ") : DEFAULT_DEFERRED_REASON
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
return deferredIds;
|
|
341
|
-
}
|
|
342
|
-
function addStampedExternalDeps(wus, allWuIds, completed) {
|
|
343
|
-
for (const wu of wus) {
|
|
344
|
-
const blockers = getAllDependencies(wu.doc);
|
|
345
|
-
for (const blockerId of blockers) {
|
|
346
|
-
if (!allWuIds.has(blockerId) && hasStamp(blockerId)) {
|
|
347
|
-
completed.add(blockerId);
|
|
348
|
-
}
|
|
349
|
-
}
|
|
350
|
-
}
|
|
351
|
-
}
|
|
352
|
-
function buildWaves(schedulableMap, schedulableIds, skipped, allWUs, allWuIds) {
|
|
353
|
-
const waves = [];
|
|
354
|
-
const remaining = new Set(schedulableIds);
|
|
355
|
-
const completed = new Set(skipped);
|
|
356
|
-
addStampedExternalDeps(allWUs, allWuIds, completed);
|
|
357
|
-
while (remaining.size > 0) {
|
|
358
|
-
const wave = [];
|
|
359
|
-
const lanesInWave = /* @__PURE__ */ new Set();
|
|
360
|
-
const deferredToNextWave = [];
|
|
361
|
-
for (const id of remaining) {
|
|
362
|
-
const wu = schedulableMap.get(id);
|
|
363
|
-
const blockers = getAllDependencies(wu.doc);
|
|
364
|
-
const allBlockersDone = blockers.every((blockerId) => completed.has(blockerId));
|
|
365
|
-
if (allBlockersDone) {
|
|
366
|
-
const lane = wu.doc.lane;
|
|
367
|
-
if (lanesInWave.has(lane)) {
|
|
368
|
-
deferredToNextWave.push(wu);
|
|
369
|
-
} else {
|
|
370
|
-
wave.push(wu);
|
|
371
|
-
lanesInWave.add(lane);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
if (wave.length === 0 && remaining.size > 0 && deferredToNextWave.length === 0) {
|
|
376
|
-
const stuckIds = Array.from(remaining);
|
|
377
|
-
throw createError(ErrorCodes.VALIDATION_ERROR, `Circular or unresolvable dependencies detected. Stuck WUs: ${stuckIds.join(", ")}`, { stuckIds });
|
|
378
|
-
}
|
|
379
|
-
waves.push(wave);
|
|
380
|
-
for (const wu of wave) {
|
|
381
|
-
remaining.delete(wu.id);
|
|
382
|
-
completed.add(wu.id);
|
|
383
|
-
}
|
|
384
|
-
}
|
|
385
|
-
return waves;
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
// ../initiatives/dist/orchestrator/checkpoint.js
|
|
389
|
-
import { existsSync as existsSync2, mkdirSync, writeFileSync, readFileSync, readdirSync } from "fs";
|
|
390
|
-
import { join as join2 } from "path";
|
|
391
|
-
var MANIFEST_WU_STATUS = "queued";
|
|
392
|
-
var CHECKPOINT_AUTO_THRESHOLDS = {
|
|
393
|
-
/** Auto-enable checkpoint mode if pending WU count exceeds this (>3 = 4+) */
|
|
394
|
-
WU_COUNT: 3,
|
|
395
|
-
/** Auto-enable checkpoint mode if wave count exceeds this (>2 = 3+) */
|
|
396
|
-
WAVE_COUNT: 2
|
|
397
|
-
};
|
|
398
|
-
function filterByDependencyStamps(candidates) {
|
|
399
|
-
const spawnable = [];
|
|
400
|
-
const blocked = [];
|
|
401
|
-
const blockingDeps = /* @__PURE__ */ new Set();
|
|
402
|
-
for (const wu of candidates) {
|
|
403
|
-
const deps = getAllDependencies(wu.doc);
|
|
404
|
-
const unmetDeps = deps.filter((depId) => !hasStamp(depId));
|
|
405
|
-
if (unmetDeps.length === 0) {
|
|
406
|
-
spawnable.push(wu);
|
|
407
|
-
} else {
|
|
408
|
-
blocked.push(wu);
|
|
409
|
-
for (const depId of unmetDeps) {
|
|
410
|
-
blockingDeps.add(depId);
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
let waitingMessage = "";
|
|
415
|
-
if (spawnable.length === 0 && blockingDeps.size > 0) {
|
|
416
|
-
const depsArray = Array.from(blockingDeps);
|
|
417
|
-
waitingMessage = `Waiting for ${depsArray.join(", ")} to complete. No WUs can spawn until ${depsArray.length === 1 ? "this dependency has" : "these dependencies have"} a stamp.`;
|
|
418
|
-
}
|
|
419
|
-
return {
|
|
420
|
-
spawnable,
|
|
421
|
-
blocked,
|
|
422
|
-
blockingDeps: Array.from(blockingDeps),
|
|
423
|
-
waitingMessage
|
|
424
|
-
};
|
|
425
|
-
}
|
|
426
|
-
async function shouldAutoEnableCheckpointAsync(wus) {
|
|
427
|
-
const pendingWUs = wus.filter((wu) => wu.doc.status !== WU_STATUS.DONE);
|
|
428
|
-
const pendingCount = pendingWUs.length;
|
|
429
|
-
if (pendingCount > CHECKPOINT_AUTO_THRESHOLDS.WU_COUNT) {
|
|
430
|
-
return {
|
|
431
|
-
autoEnabled: true,
|
|
432
|
-
reason: `${pendingCount} pending WUs exceeds threshold (>${CHECKPOINT_AUTO_THRESHOLDS.WU_COUNT})`,
|
|
433
|
-
pendingCount,
|
|
434
|
-
waveCount: -1
|
|
435
|
-
// Not computed (early return)
|
|
436
|
-
};
|
|
437
|
-
}
|
|
438
|
-
if (pendingCount === 0) {
|
|
439
|
-
return {
|
|
440
|
-
autoEnabled: false,
|
|
441
|
-
reason: "No pending WUs",
|
|
442
|
-
pendingCount: 0,
|
|
443
|
-
waveCount: 0
|
|
444
|
-
};
|
|
445
|
-
}
|
|
446
|
-
const plan = await buildExecutionPlanAsync(wus);
|
|
447
|
-
const waveCount = plan.waves.length;
|
|
448
|
-
if (waveCount > CHECKPOINT_AUTO_THRESHOLDS.WAVE_COUNT) {
|
|
449
|
-
return {
|
|
450
|
-
autoEnabled: true,
|
|
451
|
-
reason: `${waveCount} waves exceeds threshold (>${CHECKPOINT_AUTO_THRESHOLDS.WAVE_COUNT})`,
|
|
452
|
-
pendingCount,
|
|
453
|
-
waveCount
|
|
454
|
-
};
|
|
455
|
-
}
|
|
456
|
-
return {
|
|
457
|
-
autoEnabled: false,
|
|
458
|
-
reason: `${pendingCount} pending WUs and ${waveCount} waves within thresholds`,
|
|
459
|
-
pendingCount,
|
|
460
|
-
waveCount
|
|
461
|
-
};
|
|
462
|
-
}
|
|
463
|
-
async function resolveCheckpointModeAsync(options, wus) {
|
|
464
|
-
const { checkpointPerWave = false, noCheckpoint = false, dryRun = false } = options;
|
|
465
|
-
if (checkpointPerWave) {
|
|
466
|
-
return {
|
|
467
|
-
enabled: true,
|
|
468
|
-
source: "explicit",
|
|
469
|
-
reason: "Enabled via -c/--checkpoint-per-wave flag"
|
|
470
|
-
};
|
|
471
|
-
}
|
|
472
|
-
if (noCheckpoint) {
|
|
473
|
-
return {
|
|
474
|
-
enabled: false,
|
|
475
|
-
source: "override",
|
|
476
|
-
reason: "Disabled via --no-checkpoint flag"
|
|
477
|
-
};
|
|
478
|
-
}
|
|
479
|
-
if (dryRun) {
|
|
480
|
-
return {
|
|
481
|
-
enabled: false,
|
|
482
|
-
source: "dryrun",
|
|
483
|
-
reason: "Disabled in dry-run mode (preview uses polling mode)"
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
const autoResult = await shouldAutoEnableCheckpointAsync(wus);
|
|
487
|
-
return {
|
|
488
|
-
enabled: autoResult.autoEnabled,
|
|
489
|
-
source: "auto",
|
|
490
|
-
reason: autoResult.reason
|
|
491
|
-
};
|
|
492
|
-
}
|
|
493
|
-
function validateCheckpointFlags(options) {
|
|
494
|
-
if (options.checkpointPerWave && options.dryRun) {
|
|
495
|
-
throw createError(ErrorCodes.VALIDATION_ERROR, "Cannot combine --checkpoint-per-wave (-c) with --dry-run (-d). Checkpoint mode writes manifests and spawns agents.", { flags: { checkpointPerWave: true, dryRun: true } });
|
|
496
|
-
}
|
|
497
|
-
if (options.checkpointPerWave && options.noCheckpoint) {
|
|
498
|
-
throw createError(ErrorCodes.VALIDATION_ERROR, "Cannot combine --checkpoint-per-wave (-c) with --no-checkpoint. These flags are mutually exclusive.", { flags: { checkpointPerWave: true, noCheckpoint: true } });
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
function buildCheckpointWave(initRef, options = {}) {
|
|
502
|
-
const { dryRun = false } = options;
|
|
503
|
-
const initData = findInitiative(initRef);
|
|
504
|
-
if (!initData) {
|
|
505
|
-
throw createError(ErrorCodes.INIT_NOT_FOUND, `Initiative '${initRef}' not found.`, { initRef });
|
|
506
|
-
}
|
|
507
|
-
const initId = initData.id;
|
|
508
|
-
const wus = getInitiativeWUs(initRef);
|
|
509
|
-
const readyCandidates = wus.filter((wu) => {
|
|
510
|
-
if (wu.doc.status !== WU_STATUS.READY) {
|
|
511
|
-
return false;
|
|
512
|
-
}
|
|
513
|
-
if (hasStamp(wu.id)) {
|
|
514
|
-
return false;
|
|
515
|
-
}
|
|
516
|
-
return true;
|
|
517
|
-
});
|
|
518
|
-
if (readyCandidates.length === 0) {
|
|
519
|
-
return null;
|
|
520
|
-
}
|
|
521
|
-
const depResult = filterByDependencyStamps(readyCandidates);
|
|
522
|
-
if (depResult.spawnable.length === 0) {
|
|
523
|
-
return {
|
|
524
|
-
initiative: initId,
|
|
525
|
-
wave: -1,
|
|
526
|
-
wus: [],
|
|
527
|
-
manifestPath: null,
|
|
528
|
-
blockedBy: depResult.blockingDeps,
|
|
529
|
-
waitingMessage: depResult.waitingMessage
|
|
530
|
-
};
|
|
531
|
-
}
|
|
532
|
-
const selectedWUs = [];
|
|
533
|
-
const usedLanes = /* @__PURE__ */ new Set();
|
|
534
|
-
for (const wu of depResult.spawnable) {
|
|
535
|
-
const lane = wu.doc.lane;
|
|
536
|
-
if (!usedLanes.has(lane)) {
|
|
537
|
-
selectedWUs.push(wu);
|
|
538
|
-
usedLanes.add(lane);
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
const waveNum = getNextWaveNumber(initId);
|
|
542
|
-
const manifest = {
|
|
543
|
-
initiative: initId,
|
|
544
|
-
wave: waveNum,
|
|
545
|
-
created_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
546
|
-
wus: selectedWUs.map((wu) => ({
|
|
547
|
-
id: wu.id,
|
|
548
|
-
lane: wu.doc.lane,
|
|
549
|
-
status: MANIFEST_WU_STATUS
|
|
550
|
-
})),
|
|
551
|
-
lane_validation: "pass",
|
|
552
|
-
done_criteria: "All stamps exist in .lumenflow/stamps/"
|
|
553
|
-
};
|
|
554
|
-
const manifestPath = join2(WAVE_MANIFEST_DIR, `${initId}-wave-${waveNum}.json`);
|
|
555
|
-
if (!dryRun) {
|
|
556
|
-
if (!existsSync2(WAVE_MANIFEST_DIR)) {
|
|
557
|
-
mkdirSync(WAVE_MANIFEST_DIR, { recursive: true });
|
|
558
|
-
}
|
|
559
|
-
writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), "utf8");
|
|
560
|
-
}
|
|
561
|
-
return {
|
|
562
|
-
initiative: initId,
|
|
563
|
-
wave: waveNum,
|
|
564
|
-
wus: manifest.wus,
|
|
565
|
-
manifestPath
|
|
566
|
-
};
|
|
567
|
-
}
|
|
568
|
-
function getExistingWaveManifests(initId) {
|
|
569
|
-
if (!existsSync2(WAVE_MANIFEST_DIR)) {
|
|
570
|
-
return [];
|
|
571
|
-
}
|
|
572
|
-
const files = readdirSync(WAVE_MANIFEST_DIR);
|
|
573
|
-
const pattern = new RegExp(`^${initId}-wave-(\\d+)\\.json$`);
|
|
574
|
-
const manifests = [];
|
|
575
|
-
for (const file of files) {
|
|
576
|
-
const match = file.match(pattern);
|
|
577
|
-
if (match) {
|
|
578
|
-
try {
|
|
579
|
-
const content = readFileSync(join2(WAVE_MANIFEST_DIR, file), "utf8");
|
|
580
|
-
const manifest = JSON.parse(content);
|
|
581
|
-
manifests.push(manifest);
|
|
582
|
-
} catch {
|
|
583
|
-
}
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
return manifests.sort((a, b) => a.wave - b.wave);
|
|
587
|
-
}
|
|
588
|
-
function getNextWaveNumber(initId) {
|
|
589
|
-
const manifests = getExistingWaveManifests(initId);
|
|
590
|
-
if (manifests.length === 0) {
|
|
591
|
-
return 0;
|
|
592
|
-
}
|
|
593
|
-
const maxWave = Math.max(...manifests.map((m) => m.wave));
|
|
594
|
-
return maxWave + 1;
|
|
595
|
-
}
|
|
596
|
-
|
|
597
|
-
// ../initiatives/dist/orchestrator/formatting.js
|
|
598
|
-
import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
|
|
599
|
-
var BANNER_SEPARATOR = "==============================================================================";
|
|
600
|
-
var ANTML_NS = "antml:";
|
|
601
|
-
var XML_PATTERNS = {
|
|
602
|
-
FUNCTION_CALLS_OPEN: `<${ANTML_NS}function_calls>`,
|
|
603
|
-
FUNCTION_CALLS_CLOSE: `</${ANTML_NS}function_calls>`,
|
|
604
|
-
INVOKE_OPEN: `<${ANTML_NS}invoke`,
|
|
605
|
-
INVOKE_CLOSE: `</${ANTML_NS}invoke>`
|
|
606
|
-
};
|
|
607
|
-
function formatExecutionPlan(initiative, plan) {
|
|
608
|
-
const lines = [];
|
|
609
|
-
lines.push(`Initiative: ${initiative.id} \u2014 ${initiative.title}`);
|
|
610
|
-
lines.push("");
|
|
611
|
-
if (plan.skipped.length > 0) {
|
|
612
|
-
lines.push(`Skipped (already done): ${plan.skipped.join(", ")}`);
|
|
613
|
-
lines.push("");
|
|
614
|
-
}
|
|
615
|
-
if (plan.skippedWithReasons && plan.skippedWithReasons.length > 0) {
|
|
616
|
-
lines.push("Skipped (not ready):");
|
|
617
|
-
for (const entry of plan.skippedWithReasons) {
|
|
618
|
-
lines.push(` - ${entry.id}: ${entry.reason}`);
|
|
619
|
-
}
|
|
620
|
-
lines.push("");
|
|
621
|
-
}
|
|
622
|
-
if (plan.deferred && plan.deferred.length > 0) {
|
|
623
|
-
lines.push("Deferred (waiting for dependencies):");
|
|
624
|
-
for (const entry of plan.deferred) {
|
|
625
|
-
lines.push(` - ${entry.id}: ${entry.reason}`);
|
|
626
|
-
if (entry.blockedBy && entry.blockedBy.length > 0) {
|
|
627
|
-
lines.push(` blocked by: ${entry.blockedBy.join(", ")}`);
|
|
628
|
-
}
|
|
629
|
-
}
|
|
630
|
-
lines.push("");
|
|
631
|
-
}
|
|
632
|
-
if (plan.waves.length === 0) {
|
|
633
|
-
const hasPending = plan.deferred.length > 0 || plan.skippedWithReasons && plan.skippedWithReasons.length > 0;
|
|
634
|
-
if (hasPending) {
|
|
635
|
-
const pendingCount = plan.deferred.length + (plan.skippedWithReasons ? plan.skippedWithReasons.length : 0);
|
|
636
|
-
lines.push(`${pendingCount} WU(s) still pending but none are unblocked.`);
|
|
637
|
-
} else {
|
|
638
|
-
lines.push("All WUs are complete.");
|
|
639
|
-
}
|
|
640
|
-
return lines.join(STRING_LITERALS.NEWLINE);
|
|
641
|
-
}
|
|
642
|
-
lines.push(`Execution Plan: ${plan.waves.length} wave(s)`);
|
|
643
|
-
lines.push("");
|
|
644
|
-
const allWUs = plan.waves.flat();
|
|
645
|
-
const bottleneckWUs = getBottleneckWUs(allWUs);
|
|
646
|
-
if (bottleneckWUs.length > 0) {
|
|
647
|
-
lines.push("Bottleneck WUs (prioritise these for fastest unblocking):");
|
|
648
|
-
for (const bottleneck of bottleneckWUs) {
|
|
649
|
-
lines.push(` - ${bottleneck.id}: ${bottleneck.title} [blocks ${bottleneck.blocksCount} WU${bottleneck.blocksCount !== 1 ? "s" : ""}]`);
|
|
650
|
-
}
|
|
651
|
-
lines.push("");
|
|
652
|
-
}
|
|
653
|
-
for (let i = 0; i < plan.waves.length; i++) {
|
|
654
|
-
const wave = plan.waves[i];
|
|
655
|
-
lines.push(`Wave ${i} (${wave.length} WU${wave.length !== 1 ? "s" : ""} in parallel):`);
|
|
656
|
-
for (const wu of wave) {
|
|
657
|
-
const blockers = getAllDependencies(wu.doc);
|
|
658
|
-
const blockerStr = blockers.length > 0 ? ` [blocked by: ${blockers.join(", ")}]` : "";
|
|
659
|
-
const isBottleneck = bottleneckWUs.some((b) => b.id === wu.id);
|
|
660
|
-
const bottleneckMarker = isBottleneck ? " *BOTTLENECK*" : "";
|
|
661
|
-
lines.push(` - ${wu.id}: ${wu.doc.title}${blockerStr}${bottleneckMarker}`);
|
|
662
|
-
}
|
|
663
|
-
lines.push("");
|
|
664
|
-
}
|
|
665
|
-
if (plan.waves.length > 1) {
|
|
666
|
-
lines.push("Coordination Guidance:");
|
|
667
|
-
lines.push(" - Poll mem:inbox between waves: pnpm mem:inbox --since 10m");
|
|
668
|
-
lines.push(" - Check for bug discoveries from sub-agents");
|
|
669
|
-
lines.push(" - Review signals before proceeding to next wave");
|
|
670
|
-
lines.push("");
|
|
671
|
-
}
|
|
672
|
-
return lines.join(STRING_LITERALS.NEWLINE);
|
|
673
|
-
}
|
|
674
|
-
function calculateProgress(wus) {
|
|
675
|
-
const stats = {
|
|
676
|
-
total: wus.length,
|
|
677
|
-
done: 0,
|
|
678
|
-
active: 0,
|
|
679
|
-
pending: 0,
|
|
680
|
-
blocked: 0,
|
|
681
|
-
percentage: 0
|
|
682
|
-
};
|
|
683
|
-
for (const { doc } of wus) {
|
|
684
|
-
switch (doc.status) {
|
|
685
|
-
case WU_STATUS.DONE:
|
|
686
|
-
stats.done++;
|
|
687
|
-
break;
|
|
688
|
-
case WU_STATUS.IN_PROGRESS:
|
|
689
|
-
stats.active++;
|
|
690
|
-
break;
|
|
691
|
-
case WU_STATUS.BLOCKED:
|
|
692
|
-
stats.blocked++;
|
|
693
|
-
break;
|
|
694
|
-
case WU_STATUS.READY:
|
|
695
|
-
stats.pending++;
|
|
696
|
-
break;
|
|
697
|
-
default:
|
|
698
|
-
break;
|
|
699
|
-
}
|
|
700
|
-
}
|
|
701
|
-
stats.percentage = stats.total > 0 ? Math.round(stats.done / stats.total * 100) : 0;
|
|
702
|
-
return stats;
|
|
703
|
-
}
|
|
704
|
-
function formatProgress(progress) {
|
|
705
|
-
const bar = createProgressBar(progress.percentage);
|
|
706
|
-
return [
|
|
707
|
-
`Progress: ${bar} ${progress.percentage}%`,
|
|
708
|
-
` Done: ${progress.done}/${progress.total}`,
|
|
709
|
-
` Active: ${progress.active}`,
|
|
710
|
-
` Pending: ${progress.pending}`,
|
|
711
|
-
` Blocked: ${progress.blocked}`
|
|
712
|
-
].join(STRING_LITERALS.NEWLINE);
|
|
713
|
-
}
|
|
714
|
-
function createProgressBar(percentage, width = 20) {
|
|
715
|
-
const filled = Math.round(percentage / 100 * width);
|
|
716
|
-
const empty = width - filled;
|
|
717
|
-
return `[${"\u2588".repeat(filled)}${"\u2591".repeat(empty)}]`;
|
|
718
|
-
}
|
|
719
|
-
function getBottleneckWUs(wus, limit = 5) {
|
|
720
|
-
const blocksCounts = /* @__PURE__ */ new Map();
|
|
721
|
-
for (const wu of wus) {
|
|
722
|
-
blocksCounts.set(wu.id, 0);
|
|
723
|
-
}
|
|
724
|
-
for (const wu of wus) {
|
|
725
|
-
const blockers = getAllDependencies(wu.doc);
|
|
726
|
-
for (const blockerId of blockers) {
|
|
727
|
-
if (blocksCounts.has(blockerId)) {
|
|
728
|
-
blocksCounts.set(blockerId, blocksCounts.get(blockerId) + 1);
|
|
729
|
-
}
|
|
730
|
-
}
|
|
731
|
-
}
|
|
732
|
-
const bottlenecks = [];
|
|
733
|
-
for (const wu of wus) {
|
|
734
|
-
const blocksCount = blocksCounts.get(wu.id);
|
|
735
|
-
if (blocksCount !== void 0 && blocksCount > 0) {
|
|
736
|
-
bottlenecks.push({
|
|
737
|
-
id: wu.id,
|
|
738
|
-
title: wu.doc.title ?? wu.id,
|
|
739
|
-
blocksCount
|
|
740
|
-
});
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
bottlenecks.sort((a, b) => b.blocksCount - a.blocksCount);
|
|
744
|
-
return bottlenecks.slice(0, limit);
|
|
745
|
-
}
|
|
746
|
-
function formatCheckpointOutput(waveData) {
|
|
747
|
-
const lines = [];
|
|
748
|
-
const isDryRun = waveData.dryRun === true;
|
|
749
|
-
if (waveData.blockedBy && waveData.blockedBy.length > 0) {
|
|
750
|
-
lines.push(`Waiting for dependencies to complete:`);
|
|
751
|
-
for (const depId of waveData.blockedBy) {
|
|
752
|
-
lines.push(` - ${depId}`);
|
|
753
|
-
}
|
|
754
|
-
lines.push("");
|
|
755
|
-
lines.push(waveData.waitingMessage || "No WUs can spawn until dependencies have stamps.");
|
|
756
|
-
lines.push("");
|
|
757
|
-
lines.push("Check dependency progress with:");
|
|
758
|
-
lines.push(` pnpm mem:inbox --since 10m`);
|
|
759
|
-
lines.push(` pnpm orchestrate:initiative -i ${waveData.initiative} -c`);
|
|
760
|
-
return lines.join(STRING_LITERALS.NEWLINE);
|
|
761
|
-
}
|
|
762
|
-
if (isDryRun) {
|
|
763
|
-
lines.push("[DRY-RUN PREVIEW] Checkpoint mode output (no manifest written)");
|
|
764
|
-
lines.push("");
|
|
765
|
-
}
|
|
766
|
-
lines.push(`Wave ${waveData.wave} manifest: ${waveData.manifestPath}`);
|
|
767
|
-
lines.push(`WUs in this wave: ${waveData.wus.length}`);
|
|
768
|
-
for (const wu of waveData.wus) {
|
|
769
|
-
lines.push(` - ${wu.id} (${wu.lane})`);
|
|
770
|
-
}
|
|
771
|
-
lines.push("");
|
|
772
|
-
lines.push(BANNER_SEPARATOR);
|
|
773
|
-
lines.push("ACTION REQUIRED: Agents have NOT been spawned yet.");
|
|
774
|
-
lines.push("");
|
|
775
|
-
lines.push("To spawn agents, copy the XML below and invoke the Task tool.");
|
|
776
|
-
lines.push("The output below is documentation only - it will NOT execute automatically.");
|
|
777
|
-
lines.push(BANNER_SEPARATOR);
|
|
778
|
-
lines.push("");
|
|
779
|
-
lines.push("```xml");
|
|
780
|
-
const xmlLines = [];
|
|
781
|
-
xmlLines.push(XML_PATTERNS.FUNCTION_CALLS_OPEN);
|
|
782
|
-
for (const wu of waveData.wus) {
|
|
783
|
-
try {
|
|
784
|
-
const fullInvocation = generateEmbeddedSpawnPrompt(wu.id);
|
|
785
|
-
const startIdx = fullInvocation.indexOf(XML_PATTERNS.INVOKE_OPEN);
|
|
786
|
-
const endIdx = fullInvocation.indexOf(XML_PATTERNS.INVOKE_CLOSE);
|
|
787
|
-
if (startIdx !== -1 && endIdx !== -1) {
|
|
788
|
-
const invokeBlock = fullInvocation.substring(startIdx, endIdx + XML_PATTERNS.INVOKE_CLOSE.length);
|
|
789
|
-
xmlLines.push(invokeBlock);
|
|
790
|
-
}
|
|
791
|
-
} catch {
|
|
792
|
-
xmlLines.push(`<!-- Could not generate Task invocation for ${wu.id} -->`);
|
|
793
|
-
}
|
|
794
|
-
}
|
|
795
|
-
xmlLines.push(XML_PATTERNS.FUNCTION_CALLS_CLOSE);
|
|
796
|
-
lines.push(xmlLines.join(STRING_LITERALS.NEWLINE));
|
|
797
|
-
lines.push("```");
|
|
798
|
-
lines.push("");
|
|
799
|
-
lines.push("Resume with:");
|
|
800
|
-
lines.push(` pnpm mem:ready --wu WU-ORCHESTRATOR`);
|
|
801
|
-
lines.push(` pnpm orchestrate:initiative -i ${waveData.initiative} -c`);
|
|
802
|
-
return lines.join(STRING_LITERALS.NEWLINE);
|
|
803
|
-
}
|
|
804
|
-
function generateEmbeddedSpawnPrompt(wuId) {
|
|
805
|
-
const wuPath = WU_PATHS.WU(wuId);
|
|
806
|
-
if (!existsSync3(wuPath)) {
|
|
807
|
-
throw createError(ErrorCodes.WU_NOT_FOUND, `WU file not found: ${wuPath}`, {
|
|
808
|
-
wuId,
|
|
809
|
-
path: wuPath
|
|
810
|
-
});
|
|
811
|
-
}
|
|
812
|
-
const text = readFileSync2(wuPath, "utf8");
|
|
813
|
-
const doc = parseYAML(text);
|
|
814
|
-
return generateTaskInvocation(doc, wuId, SpawnStrategyFactory.create("claude-code"));
|
|
815
|
-
}
|
|
816
|
-
function formatExecutionPlanWithEmbeddedSpawns(plan) {
|
|
817
|
-
const lines = [];
|
|
818
|
-
if (plan.waves.length === 0) {
|
|
819
|
-
const hasPending = plan.deferred.length > 0 || plan.skippedWithReasons && plan.skippedWithReasons.length > 0;
|
|
820
|
-
if (hasPending) {
|
|
821
|
-
const pendingCount = plan.deferred.length + (plan.skippedWithReasons ? plan.skippedWithReasons.length : 0);
|
|
822
|
-
return `${pendingCount} WU(s) still pending but none are unblocked.`;
|
|
823
|
-
}
|
|
824
|
-
return "All WUs are complete.";
|
|
825
|
-
}
|
|
826
|
-
for (let waveIndex = 0; waveIndex < plan.waves.length; waveIndex++) {
|
|
827
|
-
const wave = plan.waves[waveIndex];
|
|
828
|
-
lines.push(`## Wave ${waveIndex} (${wave.length} WU${wave.length !== 1 ? "s" : ""} in parallel)`);
|
|
829
|
-
lines.push("");
|
|
830
|
-
lines.push(BANNER_SEPARATOR);
|
|
831
|
-
lines.push("ACTION REQUIRED: Agents have NOT been spawned yet.");
|
|
832
|
-
lines.push("");
|
|
833
|
-
lines.push("To spawn agents, copy the XML below and invoke the Task tool.");
|
|
834
|
-
lines.push("The output below is documentation only - it will NOT execute automatically.");
|
|
835
|
-
lines.push(BANNER_SEPARATOR);
|
|
836
|
-
lines.push("");
|
|
837
|
-
lines.push("```xml");
|
|
838
|
-
const xmlLines = [];
|
|
839
|
-
const openTag = "<antml:function_calls>";
|
|
840
|
-
const closeTag = "</antml:function_calls>";
|
|
841
|
-
xmlLines.push(openTag);
|
|
842
|
-
for (const wu of wave) {
|
|
843
|
-
const fullInvocation = generateTaskInvocation(wu.doc, wu.id, SpawnStrategyFactory.create("claude-code"));
|
|
844
|
-
const startPattern = "<antml:invoke";
|
|
845
|
-
const endPattern = "</antml:invoke>";
|
|
846
|
-
const startIdx = fullInvocation.indexOf(startPattern);
|
|
847
|
-
const endIdx = fullInvocation.indexOf(endPattern);
|
|
848
|
-
if (startIdx !== -1 && endIdx !== -1) {
|
|
849
|
-
let invokeBlock = fullInvocation.substring(startIdx, endIdx + endPattern.length);
|
|
850
|
-
if (!invokeBlock.includes("run_in_background")) {
|
|
851
|
-
const paramOpen = '<antml:parameter name="';
|
|
852
|
-
const paramClose = "</antml:parameter>";
|
|
853
|
-
const invokeTag = '<antml:invoke name="Task">';
|
|
854
|
-
invokeBlock = invokeBlock.replace(invokeTag, `${invokeTag}
|
|
855
|
-
${paramOpen}run_in_background">true${paramClose}`);
|
|
856
|
-
}
|
|
857
|
-
xmlLines.push(invokeBlock);
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
xmlLines.push(closeTag);
|
|
861
|
-
lines.push(xmlLines.join(STRING_LITERALS.NEWLINE));
|
|
862
|
-
lines.push("```");
|
|
863
|
-
lines.push("");
|
|
864
|
-
if (waveIndex < plan.waves.length - 1) {
|
|
865
|
-
lines.push(`After all Wave ${waveIndex} agents complete, proceed to Wave ${waveIndex + 1}.`);
|
|
866
|
-
lines.push("Before next wave: pnpm mem:inbox --since 10m (check for bug discoveries)");
|
|
867
|
-
lines.push("");
|
|
868
|
-
}
|
|
869
|
-
}
|
|
870
|
-
return lines.join(STRING_LITERALS.NEWLINE);
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
// ../initiatives/dist/orchestrator/initiative-loading.js
|
|
874
|
-
function loadInitiativeWUs(initRef) {
|
|
875
|
-
const initiative = findInitiative(initRef);
|
|
876
|
-
if (!initiative) {
|
|
877
|
-
throw createError(ErrorCodes.INIT_NOT_FOUND, `Initiative '${initRef}' not found. Check the ID or slug.`, { initRef });
|
|
878
|
-
}
|
|
879
|
-
const wus = getInitiativeWUs(initRef);
|
|
880
|
-
return {
|
|
881
|
-
initiative: initiative.doc,
|
|
882
|
-
wus
|
|
883
|
-
};
|
|
884
|
-
}
|
|
885
|
-
function loadMultipleInitiatives(initRefs) {
|
|
886
|
-
const allWUs = [];
|
|
887
|
-
const seenIds = /* @__PURE__ */ new Set();
|
|
888
|
-
for (const ref of initRefs) {
|
|
889
|
-
const { wus } = loadInitiativeWUs(ref);
|
|
890
|
-
for (const wu of wus) {
|
|
891
|
-
if (!seenIds.has(wu.id)) {
|
|
892
|
-
seenIds.add(wu.id);
|
|
893
|
-
allWUs.push(wu);
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
}
|
|
897
|
-
return allWUs;
|
|
898
|
-
}
|
|
899
|
-
|
|
900
|
-
// ../initiatives/dist/orchestrator/scope-advisory.js
|
|
901
|
-
var SCOPE_ADVISORY_THRESHOLDS = {
|
|
902
|
-
/**
|
|
903
|
-
* WU-to-unique-file ratio above which the initiative is flagged as over-granular.
|
|
904
|
-
* A ratio of 2.0 means there are twice as many WUs as unique files.
|
|
905
|
-
*/
|
|
906
|
-
OVER_GRANULAR_RATIO: 2,
|
|
907
|
-
/**
|
|
908
|
-
* Percentage of WUs that share the same code path before flagging overlap.
|
|
909
|
-
* 0.5 = 50% of WUs touch at least one common file.
|
|
910
|
-
*/
|
|
911
|
-
OVERLAP_PERCENTAGE: 0.5,
|
|
912
|
-
/**
|
|
913
|
-
* Percentage of WUs in a single lane before flagging lane concentration.
|
|
914
|
-
* 0.7 = 70% of WUs are in the same lane.
|
|
915
|
-
*/
|
|
916
|
-
LANE_CONCENTRATION_PERCENTAGE: 0.7,
|
|
917
|
-
/**
|
|
918
|
-
* Minimum number of WUs required before lane concentration check fires.
|
|
919
|
-
* Small initiatives (< 4 WUs) naturally have high lane concentration.
|
|
920
|
-
*/
|
|
921
|
-
MIN_WUS_FOR_LANE_CHECK: 4
|
|
922
|
-
};
|
|
923
|
-
function analyseScopeShape(wus) {
|
|
924
|
-
const advisories = [];
|
|
925
|
-
if (wus.length <= 1) {
|
|
926
|
-
return { advisories, clean: true };
|
|
927
|
-
}
|
|
928
|
-
const overGranularAdvisory = detectOverGranular(wus);
|
|
929
|
-
if (overGranularAdvisory) {
|
|
930
|
-
advisories.push(overGranularAdvisory);
|
|
931
|
-
}
|
|
932
|
-
const overlapAdvisory = detectOverlapConcentration(wus);
|
|
933
|
-
if (overlapAdvisory) {
|
|
934
|
-
advisories.push(overlapAdvisory);
|
|
935
|
-
}
|
|
936
|
-
const laneAdvisory = detectLaneConcentration(wus);
|
|
937
|
-
if (laneAdvisory) {
|
|
938
|
-
advisories.push(laneAdvisory);
|
|
939
|
-
}
|
|
940
|
-
return {
|
|
941
|
-
advisories,
|
|
942
|
-
clean: advisories.length === 0
|
|
943
|
-
};
|
|
944
|
-
}
|
|
945
|
-
function formatScopeAdvisory(result) {
|
|
946
|
-
if (result.clean) {
|
|
947
|
-
return "";
|
|
948
|
-
}
|
|
949
|
-
const lines = [];
|
|
950
|
-
lines.push("Scope Advisory:");
|
|
951
|
-
for (const advisory of result.advisories) {
|
|
952
|
-
lines.push(` [${advisory.severity}] ${advisory.type}: ${advisory.detail}`);
|
|
953
|
-
lines.push(` -> ${advisory.suggestion}`);
|
|
954
|
-
}
|
|
955
|
-
return lines.join("\n");
|
|
956
|
-
}
|
|
957
|
-
function collectCodePaths(wus) {
|
|
958
|
-
const uniqueFiles = /* @__PURE__ */ new Set();
|
|
959
|
-
const fileToWuCount = /* @__PURE__ */ new Map();
|
|
960
|
-
let wusWithPaths = 0;
|
|
961
|
-
for (const wu of wus) {
|
|
962
|
-
const paths = wu.doc.code_paths;
|
|
963
|
-
if (!paths || paths.length === 0) {
|
|
964
|
-
continue;
|
|
965
|
-
}
|
|
966
|
-
wusWithPaths++;
|
|
967
|
-
for (const p of paths) {
|
|
968
|
-
uniqueFiles.add(p);
|
|
969
|
-
fileToWuCount.set(p, (fileToWuCount.get(p) ?? 0) + 1);
|
|
970
|
-
}
|
|
971
|
-
}
|
|
972
|
-
return { uniqueFiles, wusWithPaths, fileToWuCount };
|
|
973
|
-
}
|
|
974
|
-
function detectOverGranular(wus) {
|
|
975
|
-
const { uniqueFiles, wusWithPaths } = collectCodePaths(wus);
|
|
976
|
-
if (uniqueFiles.size === 0 || wusWithPaths === 0) {
|
|
977
|
-
return null;
|
|
978
|
-
}
|
|
979
|
-
const ratio = wusWithPaths / uniqueFiles.size;
|
|
980
|
-
if (ratio > SCOPE_ADVISORY_THRESHOLDS.OVER_GRANULAR_RATIO) {
|
|
981
|
-
return {
|
|
982
|
-
type: "over-granular",
|
|
983
|
-
severity: "warning",
|
|
984
|
-
detail: `${wusWithPaths} WUs touch only ${uniqueFiles.size} unique files (ratio: ${ratio.toFixed(1)})`,
|
|
985
|
-
suggestion: "Consider merging related WUs to reduce context-switching overhead."
|
|
986
|
-
};
|
|
987
|
-
}
|
|
988
|
-
return null;
|
|
989
|
-
}
|
|
990
|
-
function detectOverlapConcentration(wus) {
|
|
991
|
-
const { wusWithPaths, fileToWuCount } = collectCodePaths(wus);
|
|
992
|
-
if (wusWithPaths < 2) {
|
|
993
|
-
return null;
|
|
994
|
-
}
|
|
995
|
-
const threshold = SCOPE_ADVISORY_THRESHOLDS.OVERLAP_PERCENTAGE;
|
|
996
|
-
for (const [filePath, count] of fileToWuCount) {
|
|
997
|
-
const percentage = count / wusWithPaths;
|
|
998
|
-
if (percentage > threshold) {
|
|
999
|
-
return {
|
|
1000
|
-
type: "overlap-heavy",
|
|
1001
|
-
severity: "warning",
|
|
1002
|
-
detail: `${count} of ${wusWithPaths} WUs (${Math.round(percentage * 100)}%) touch ${filePath}`,
|
|
1003
|
-
suggestion: "High overlap suggests these WUs could be consolidated or the shared file should be split first."
|
|
1004
|
-
};
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
return null;
|
|
1008
|
-
}
|
|
1009
|
-
function detectLaneConcentration(wus) {
|
|
1010
|
-
if (wus.length < SCOPE_ADVISORY_THRESHOLDS.MIN_WUS_FOR_LANE_CHECK) {
|
|
1011
|
-
return null;
|
|
1012
|
-
}
|
|
1013
|
-
const laneCounts = /* @__PURE__ */ new Map();
|
|
1014
|
-
for (const wu of wus) {
|
|
1015
|
-
const lane = wu.doc.lane ?? "unknown";
|
|
1016
|
-
laneCounts.set(lane, (laneCounts.get(lane) ?? 0) + 1);
|
|
1017
|
-
}
|
|
1018
|
-
const threshold = SCOPE_ADVISORY_THRESHOLDS.LANE_CONCENTRATION_PERCENTAGE;
|
|
1019
|
-
for (const [lane, count] of laneCounts) {
|
|
1020
|
-
const percentage = count / wus.length;
|
|
1021
|
-
if (percentage > threshold) {
|
|
1022
|
-
return {
|
|
1023
|
-
type: "lane-heavy",
|
|
1024
|
-
severity: "warning",
|
|
1025
|
-
detail: `${count} of ${wus.length} WUs (${Math.round(percentage * 100)}%) are in lane "${lane}"`,
|
|
1026
|
-
suggestion: "Lane concentration creates a serialisation bottleneck. Consider splitting work across lanes or increasing WIP limits for this lane."
|
|
1027
|
-
};
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
return null;
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
// ../initiatives/dist/orchestrator/spawn-status.js
|
|
1034
|
-
import { existsSync as existsSync4, readFileSync as readFileSync3 } from "fs";
|
|
1035
|
-
|
|
1036
|
-
// ../initiatives/dist/lane-config-resolver.js
|
|
1037
|
-
var LANE_SECTION_KEYS = ["definitions", "engineering", "business"];
|
|
1038
|
-
function isRecord(value) {
|
|
1039
|
-
return typeof value === "object" && value !== null;
|
|
1040
|
-
}
|
|
1041
|
-
function isLaneConfigContainer(config) {
|
|
1042
|
-
return isRecord(config);
|
|
1043
|
-
}
|
|
1044
|
-
function isLaneDefinition(value) {
|
|
1045
|
-
return isRecord(value);
|
|
1046
|
-
}
|
|
1047
|
-
function collectLaneDefinitions(value, target) {
|
|
1048
|
-
if (!Array.isArray(value)) {
|
|
1049
|
-
return;
|
|
1050
|
-
}
|
|
1051
|
-
for (const entry of value) {
|
|
1052
|
-
if (isLaneDefinition(entry)) {
|
|
1053
|
-
target.push(entry);
|
|
1054
|
-
}
|
|
1055
|
-
}
|
|
1056
|
-
}
|
|
1057
|
-
function extractLaneDefinitions(config) {
|
|
1058
|
-
if (!isLaneConfigContainer(config)) {
|
|
1059
|
-
return [];
|
|
1060
|
-
}
|
|
1061
|
-
const lanes = config.lanes;
|
|
1062
|
-
if (!lanes) {
|
|
1063
|
-
return [];
|
|
1064
|
-
}
|
|
1065
|
-
if (Array.isArray(lanes)) {
|
|
1066
|
-
const flat = [];
|
|
1067
|
-
collectLaneDefinitions(lanes, flat);
|
|
1068
|
-
return flat;
|
|
1069
|
-
}
|
|
1070
|
-
if (!isRecord(lanes)) {
|
|
1071
|
-
return [];
|
|
1072
|
-
}
|
|
1073
|
-
const grouped = [];
|
|
1074
|
-
for (const key of LANE_SECTION_KEYS) {
|
|
1075
|
-
collectLaneDefinitions(lanes[key], grouped);
|
|
1076
|
-
}
|
|
1077
|
-
return grouped;
|
|
1078
|
-
}
|
|
1079
|
-
function isLockPolicy(value) {
|
|
1080
|
-
return value === "all" || value === "active" || value === "none";
|
|
1081
|
-
}
|
|
1082
|
-
function resolveLaneConfigsFromConfig(config) {
|
|
1083
|
-
const result = {};
|
|
1084
|
-
const laneDefinitions = extractLaneDefinitions(config);
|
|
1085
|
-
for (const lane of laneDefinitions) {
|
|
1086
|
-
if (!lane.name || typeof lane.name !== "string") {
|
|
1087
|
-
continue;
|
|
1088
|
-
}
|
|
1089
|
-
const entry = {};
|
|
1090
|
-
if (isLockPolicy(lane.lock_policy)) {
|
|
1091
|
-
entry.lock_policy = lane.lock_policy;
|
|
1092
|
-
}
|
|
1093
|
-
if (typeof lane.wip_limit === "number") {
|
|
1094
|
-
entry.wip_limit = lane.wip_limit;
|
|
1095
|
-
}
|
|
1096
|
-
result[lane.name] = entry;
|
|
1097
|
-
}
|
|
1098
|
-
return result;
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
export {
|
|
1102
|
-
LOG_PREFIX,
|
|
1103
|
-
getLaneAvailability,
|
|
1104
|
-
buildExecutionPlanWithLockPolicy,
|
|
1105
|
-
resolveCheckpointModeAsync,
|
|
1106
|
-
validateCheckpointFlags,
|
|
1107
|
-
buildCheckpointWave,
|
|
1108
|
-
formatExecutionPlan,
|
|
1109
|
-
calculateProgress,
|
|
1110
|
-
formatProgress,
|
|
1111
|
-
formatCheckpointOutput,
|
|
1112
|
-
formatExecutionPlanWithEmbeddedSpawns,
|
|
1113
|
-
loadInitiativeWUs,
|
|
1114
|
-
loadMultipleInitiatives,
|
|
1115
|
-
analyseScopeShape,
|
|
1116
|
-
formatScopeAdvisory,
|
|
1117
|
-
resolveLaneConfigsFromConfig
|
|
1118
|
-
};
|