@lumenflow/cli 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.
Files changed (131) hide show
  1. package/README.md +30 -27
  2. package/dist/config-set.js +54 -36
  3. package/dist/config-set.js.map +1 -1
  4. package/dist/delegation-list.js +86 -53
  5. package/dist/delegation-list.js.map +1 -1
  6. package/dist/gate-conditional.js +476 -0
  7. package/dist/gate-conditional.js.map +1 -0
  8. package/dist/gates-plan-resolvers.js +24 -1
  9. package/dist/gates-plan-resolvers.js.map +1 -1
  10. package/dist/init-templates.js +13 -0
  11. package/dist/init-templates.js.map +1 -1
  12. package/dist/initiative-create.js +1 -1
  13. package/dist/orchestrate-init-status.js +24 -31
  14. package/dist/orchestrate-init-status.js.map +1 -1
  15. package/dist/orchestrate-initiative.js +31 -2
  16. package/dist/orchestrate-initiative.js.map +1 -1
  17. package/dist/orchestrate-monitor.js +433 -1
  18. package/dist/orchestrate-monitor.js.map +1 -1
  19. package/dist/public-manifest.js +11 -4
  20. package/dist/public-manifest.js.map +1 -1
  21. package/package.json +9 -8
  22. package/packs/agent-runtime/.turbo/turbo-build.log +1 -1
  23. package/packs/agent-runtime/package.json +1 -1
  24. package/packs/sidekick/.turbo/turbo-build.log +1 -1
  25. package/packs/sidekick/package.json +1 -1
  26. package/packs/software-delivery/.turbo/turbo-build.log +1 -1
  27. package/packs/software-delivery/package.json +1 -1
  28. package/templates/core/LUMENFLOW.md.template +6 -3
  29. package/templates/core/ai/onboarding/first-wu-mistakes.md.template +2 -2
  30. package/templates/core/ai/onboarding/initiative-orchestration.md.template +83 -27
  31. package/templates/core/ai/onboarding/quick-ref-commands.md.template +9 -5
  32. package/templates/core/ai/onboarding/starting-prompt.md.template +1 -1
  33. package/templates/core/ai/onboarding/vendor-support.md.template +13 -0
  34. package/dist/chunk-2D2VOCA4.js +0 -37
  35. package/dist/chunk-2D5KFYGX.js +0 -284
  36. package/dist/chunk-2GXVIN57.js +0 -14072
  37. package/dist/chunk-2MQ7HZWZ.js +0 -26
  38. package/dist/chunk-2UFQ3A3C.js +0 -643
  39. package/dist/chunk-3RG5ZIWI.js +0 -10
  40. package/dist/chunk-4N74J3UT.js +0 -15
  41. package/dist/chunk-5GTOXFYR.js +0 -392
  42. package/dist/chunk-5VY6MQMC.js +0 -240
  43. package/dist/chunk-67XVPMRY.js +0 -1297
  44. package/dist/chunk-6HO4GWJE.js +0 -164
  45. package/dist/chunk-6W5XHWYV.js +0 -1890
  46. package/dist/chunk-6X4EMYJQ.js +0 -64
  47. package/dist/chunk-6XYXI2NQ.js +0 -772
  48. package/dist/chunk-7ANSOV6Q.js +0 -285
  49. package/dist/chunk-A624LFLB.js +0 -1380
  50. package/dist/chunk-ADN5NHG4.js +0 -126
  51. package/dist/chunk-B7YJYJKG.js +0 -33
  52. package/dist/chunk-CCLHCPKG.js +0 -210
  53. package/dist/chunk-CK36VROC.js +0 -1584
  54. package/dist/chunk-D3UOFRSB.js +0 -81
  55. package/dist/chunk-DFR4DJBM.js +0 -230
  56. package/dist/chunk-DSYBDHYH.js +0 -79
  57. package/dist/chunk-DWMLTXKQ.js +0 -1176
  58. package/dist/chunk-E3REJTAJ.js +0 -28
  59. package/dist/chunk-EA3IVO64.js +0 -633
  60. package/dist/chunk-EK2AKZKD.js +0 -55
  61. package/dist/chunk-ELD7JTTT.js +0 -343
  62. package/dist/chunk-EX6TT2XI.js +0 -195
  63. package/dist/chunk-EXINSFZE.js +0 -82
  64. package/dist/chunk-EZ6ZBYBM.js +0 -510
  65. package/dist/chunk-FBKAPTJ2.js +0 -16
  66. package/dist/chunk-FVLV5RYH.js +0 -1118
  67. package/dist/chunk-GDNSBQVK.js +0 -2485
  68. package/dist/chunk-GPQHMBNN.js +0 -278
  69. package/dist/chunk-GTFJB67L.js +0 -68
  70. package/dist/chunk-HANJXVKW.js +0 -1127
  71. package/dist/chunk-HEVS5YLD.js +0 -269
  72. package/dist/chunk-HMEVZKPQ.js +0 -9
  73. package/dist/chunk-HRGSYNLM.js +0 -3511
  74. package/dist/chunk-ISZR5N4K.js +0 -60
  75. package/dist/chunk-J6SUPR2C.js +0 -226
  76. package/dist/chunk-JERYVEIZ.js +0 -244
  77. package/dist/chunk-JHHWGL2N.js +0 -87
  78. package/dist/chunk-JONWQUB5.js +0 -775
  79. package/dist/chunk-K2DIWWDM.js +0 -1766
  80. package/dist/chunk-KY4PGL5V.js +0 -969
  81. package/dist/chunk-L737LQ4C.js +0 -1285
  82. package/dist/chunk-LFTWYIB2.js +0 -497
  83. package/dist/chunk-LV47RFNJ.js +0 -41
  84. package/dist/chunk-MKSAITI7.js +0 -15
  85. package/dist/chunk-MZ7RKIX4.js +0 -212
  86. package/dist/chunk-NAP6CFSO.js +0 -84
  87. package/dist/chunk-ND6MY37M.js +0 -16
  88. package/dist/chunk-NMG736UR.js +0 -683
  89. package/dist/chunk-NRAXROED.js +0 -32
  90. package/dist/chunk-NRIZR3A7.js +0 -690
  91. package/dist/chunk-NX43BG3M.js +0 -233
  92. package/dist/chunk-O645XLSI.js +0 -297
  93. package/dist/chunk-OMJD6A3S.js +0 -235
  94. package/dist/chunk-QB6SJD4T.js +0 -430
  95. package/dist/chunk-QFSTL4J3.js +0 -276
  96. package/dist/chunk-QLGDFMFX.js +0 -212
  97. package/dist/chunk-RIAAGL2E.js +0 -13
  98. package/dist/chunk-RWO5XMZ6.js +0 -86
  99. package/dist/chunk-RXRKBBSM.js +0 -149
  100. package/dist/chunk-RZOZMML6.js +0 -363
  101. package/dist/chunk-U7I7FS7T.js +0 -113
  102. package/dist/chunk-UI42RODY.js +0 -717
  103. package/dist/chunk-UTVMVSCO.js +0 -519
  104. package/dist/chunk-V6OJGLBA.js +0 -1746
  105. package/dist/chunk-W2JHVH7D.js +0 -152
  106. package/dist/chunk-WD3Y7VQN.js +0 -280
  107. package/dist/chunk-WOCTQ5MS.js +0 -303
  108. package/dist/chunk-WZR3ZUNN.js +0 -696
  109. package/dist/chunk-XGI665H7.js +0 -150
  110. package/dist/chunk-XKY65P2T.js +0 -304
  111. package/dist/chunk-Y4CQZY65.js +0 -57
  112. package/dist/chunk-YFEXKLVE.js +0 -194
  113. package/dist/chunk-YHO3HS5X.js +0 -287
  114. package/dist/chunk-YLS7AZSX.js +0 -738
  115. package/dist/chunk-ZE473AO6.js +0 -49
  116. package/dist/chunk-ZF747T3O.js +0 -644
  117. package/dist/chunk-ZHCZHZH3.js +0 -43
  118. package/dist/chunk-ZZNZX2XY.js +0 -87
  119. package/dist/constants-7QAP3VQ4.js +0 -23
  120. package/dist/dist-IY3UUMWK.js +0 -33
  121. package/dist/invariants-runner-W5RGHCSU.js +0 -27
  122. package/dist/lane-lock-6J36HD5O.js +0 -35
  123. package/dist/mem-checkpoint-core-EANG2GVN.js +0 -14
  124. package/dist/mem-signal-core-2LZ2WYHW.js +0 -19
  125. package/dist/memory-store-OLB5FO7K.js +0 -18
  126. package/dist/service-6BYCOCO5.js +0 -13
  127. package/dist/spawn-policy-resolver-NTSZYQ6R.js +0 -17
  128. package/dist/spawn-task-builder-R4E2BHSW.js +0 -22
  129. package/dist/wu-done-pr-WLFFFEPJ.js +0 -25
  130. package/dist/wu-done-validation-3J5E36FE.js +0 -30
  131. package/dist/wu-duplicate-id-detector-5S7JHELK.js +0 -232
@@ -1,772 +0,0 @@
1
- import {
2
- CONFIG_FILES,
3
- FILE_EXTENSIONS,
4
- LUMENFLOW_PATHS,
5
- STDIO,
6
- STRING_LITERALS
7
- } from "./chunk-DWMLTXKQ.js";
8
-
9
- // ../core/dist/telemetry.js
10
- import { appendFileSync, mkdirSync, existsSync, readFileSync, writeFileSync } from "fs";
11
- import { execSync } from "child_process";
12
- import path from "path";
13
- import YAML from "yaml";
14
- var TELEMETRY_DIR = LUMENFLOW_PATHS.TELEMETRY;
15
- var GATES_LOG = `${TELEMETRY_DIR}/gates${FILE_EXTENSIONS.NDJSON}`;
16
- var LLM_CLASSIFICATION_LOG = `${TELEMETRY_DIR}/llm-classification${FILE_EXTENSIONS.NDJSON}`;
17
- var COSTS_LOG = `${TELEMETRY_DIR}/costs${FILE_EXTENSIONS.NDJSON}`;
18
- var FLOW_LOG = LUMENFLOW_PATHS.FLOW_LOG;
19
- var DORA_LOG = `${TELEMETRY_DIR}/dora${FILE_EXTENSIONS.NDJSON}`;
20
- var WORKSPACE_FILE = CONFIG_FILES.WORKSPACE_CONFIG;
21
- var CLOUD_SYNC_STATE_FILE = `${TELEMETRY_DIR}/cloud-sync-state${FILE_EXTENSIONS.JSON}`;
22
- var CLOUD_SYNC_LOG_PREFIX = "[telemetry:cloud-sync]";
23
- var PACK_KEY_SOFTWARE_DELIVERY = "software_delivery";
24
- var CONTROL_PLANE_FIELD = "control_plane";
25
- var CONTROL_PLANE_AUTH_FIELD = "auth";
26
- var CONTROL_PLANE_ENDPOINT_FIELD = "endpoint";
27
- var CONTROL_PLANE_SYNC_INTERVAL_FIELD = "sync_interval";
28
- var CONTROL_PLANE_BATCH_SIZE_FIELD = "batch_size";
29
- var CONTROL_PLANE_TIMEOUT_MS_FIELD = "timeout_ms";
30
- var CONTROL_PLANE_TOKEN_ENV_FIELD = "token_env";
31
- var WORKSPACE_ID_FIELD = "id";
32
- var HTTP = {
33
- METHOD_POST: "POST",
34
- HEADER_AUTHORIZATION: "authorization",
35
- HEADER_CONTENT_TYPE: "content-type",
36
- CONTENT_TYPE_JSON: "application/json"
37
- };
38
- var CONTROL_PLANE_API_PATH = {
39
- TELEMETRY: "/api/v1/telemetry"
40
- };
41
- var DEFAULT_BATCH_SIZE = 100;
42
- var DEFAULT_TIMEOUT_MS = 1e4;
43
- var MS_PER_SECOND = 1e3;
44
- var ERROR_NAME = {
45
- ABORT: "AbortError"
46
- };
47
- var CONTROL_PLANE_TOKEN_ENV_PATTERN = /^[A-Z][A-Z0-9_]*$/;
48
- var METRIC_NAME = {
49
- GATES_DURATION_MS: "gates.duration_ms",
50
- FLOW_EVENT: "flow.event",
51
- DORA_METRIC: "dora",
52
- COST_USD: "cost.usd",
53
- RAW_GATES: "telemetry.raw.gates",
54
- RAW_FLOW: "telemetry.raw.flow",
55
- RAW_DORA: "telemetry.raw.dora",
56
- RAW_COSTS: "telemetry.raw.costs"
57
- };
58
- var TELEMETRY_SOURCE = {
59
- GATES: "gates",
60
- FLOW: "flow",
61
- DORA: "dora",
62
- COSTS: "costs"
63
- };
64
- function ensureTelemetryDir() {
65
- try {
66
- mkdirSync(TELEMETRY_DIR, { recursive: true });
67
- } catch {
68
- }
69
- }
70
- function emit(filePath, event) {
71
- ensureTelemetryDir();
72
- const line = `${JSON.stringify(event)}${STRING_LITERALS.NEWLINE}`;
73
- try {
74
- appendFileSync(filePath, line, { encoding: "utf-8" });
75
- } catch (err) {
76
- const message = err instanceof Error ? err.message : String(err);
77
- console.error(`[telemetry] Failed to emit to ${filePath}:`, message);
78
- }
79
- }
80
- function emitGateEvent(data) {
81
- const event = {
82
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
83
- wu_id: data.wu_id || null,
84
- lane: data.lane || null,
85
- gate_name: data.gate_name,
86
- passed: data.passed,
87
- duration_ms: data.duration_ms
88
- };
89
- emit(GATES_LOG, event);
90
- }
91
- function getCurrentWU() {
92
- try {
93
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
94
- encoding: "utf-8",
95
- stdio: [STDIO.PIPE, STDIO.PIPE, STDIO.IGNORE]
96
- }).trim();
97
- const match = branch.match(/wu-(\d+)/i);
98
- if (match) {
99
- return `WU-${match[1]}`.toUpperCase();
100
- }
101
- } catch {
102
- }
103
- return null;
104
- }
105
- function getCurrentLane() {
106
- try {
107
- const branch = execSync("git rev-parse --abbrev-ref HEAD", {
108
- encoding: "utf-8",
109
- stdio: [STDIO.PIPE, STDIO.PIPE, STDIO.IGNORE]
110
- }).trim();
111
- const match = branch.match(/^lane\/([^/]+)\//i);
112
- const laneSegment = match?.[1];
113
- if (laneSegment) {
114
- return laneSegment.charAt(0).toUpperCase() + laneSegment.slice(1).toLowerCase();
115
- }
116
- } catch {
117
- }
118
- return null;
119
- }
120
- function emitWUFlowEvent(event, logPath = FLOW_LOG) {
121
- const logDir = path.dirname(logPath);
122
- if (!existsSync(logDir)) {
123
- mkdirSync(logDir, { recursive: true });
124
- }
125
- const line = JSON.stringify({ timestamp: (/* @__PURE__ */ new Date()).toISOString(), ...event });
126
- try {
127
- appendFileSync(logPath, `${line}${STRING_LITERALS.NEWLINE}`, { encoding: "utf-8" });
128
- } catch (err) {
129
- const message = err instanceof Error ? err.message : String(err);
130
- console.error(`[telemetry] Failed to emit flow event: ${message}`);
131
- }
132
- }
133
- function emitDoraTelemetry(record) {
134
- ensureTelemetryDir();
135
- const line = JSON.stringify({
136
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
137
- metric: record.metric,
138
- value: record.value,
139
- tier: record.tier
140
- });
141
- try {
142
- appendFileSync(DORA_LOG, `${line}${STRING_LITERALS.NEWLINE}`, { encoding: "utf-8" });
143
- } catch (err) {
144
- const message = err instanceof Error ? err.message : String(err);
145
- console.error(`[telemetry] Failed to emit DORA telemetry: ${message}`);
146
- }
147
- }
148
- function isRecord(value) {
149
- return typeof value === "object" && value !== null;
150
- }
151
- function asNonEmptyString(value) {
152
- if (typeof value !== "string") {
153
- return void 0;
154
- }
155
- const trimmed = value.trim();
156
- return trimmed.length > 0 ? trimmed : void 0;
157
- }
158
- function asPositiveInteger(value) {
159
- if (typeof value !== "number" || !Number.isInteger(value) || value <= 0) {
160
- return void 0;
161
- }
162
- return value;
163
- }
164
- function asFiniteNumber(value) {
165
- return typeof value === "number" && Number.isFinite(value) ? value : void 0;
166
- }
167
- function asPrimitiveTagValue(value) {
168
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
169
- return value;
170
- }
171
- return void 0;
172
- }
173
- function normalizeEndpoint(endpoint) {
174
- return endpoint.endsWith("/") ? endpoint.slice(0, endpoint.length - 1) : endpoint;
175
- }
176
- function normalizeTimestamp(value, fallbackIso) {
177
- const rawTimestamp = asNonEmptyString(value);
178
- return rawTimestamp ?? fallbackIso;
179
- }
180
- function warnCloudSync(logger, message) {
181
- logger?.warn?.(`${CLOUD_SYNC_LOG_PREFIX} ${message}`);
182
- }
183
- function createDefaultCloudSyncState() {
184
- return {
185
- version: 1,
186
- lastSyncAtMs: 0,
187
- files: {
188
- gates: {
189
- offset: 0
190
- },
191
- flow: {
192
- offset: 0
193
- },
194
- dora: {
195
- offset: 0
196
- },
197
- costs: {
198
- offset: 0
199
- }
200
- }
201
- };
202
- }
203
- function normalizeStateOffset(value) {
204
- if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
205
- return 0;
206
- }
207
- return value;
208
- }
209
- function loadCloudSyncState(statePath) {
210
- if (!existsSync(statePath)) {
211
- return createDefaultCloudSyncState();
212
- }
213
- try {
214
- const raw = readFileSync(statePath, "utf-8");
215
- const parsed = JSON.parse(raw);
216
- if (!isRecord(parsed)) {
217
- return createDefaultCloudSyncState();
218
- }
219
- const filesRaw = Reflect.get(parsed, "files");
220
- const gatesRaw = isRecord(filesRaw) ? Reflect.get(filesRaw, TELEMETRY_SOURCE.GATES) : void 0;
221
- const flowRaw = isRecord(filesRaw) ? Reflect.get(filesRaw, TELEMETRY_SOURCE.FLOW) : void 0;
222
- const doraRaw = isRecord(filesRaw) ? Reflect.get(filesRaw, TELEMETRY_SOURCE.DORA) : void 0;
223
- const costsRaw = isRecord(filesRaw) ? Reflect.get(filesRaw, TELEMETRY_SOURCE.COSTS) : void 0;
224
- const gatesOffset = isRecord(gatesRaw) ? normalizeStateOffset(Reflect.get(gatesRaw, "offset")) : 0;
225
- const flowOffset = isRecord(flowRaw) ? normalizeStateOffset(Reflect.get(flowRaw, "offset")) : 0;
226
- const doraOffset = isRecord(doraRaw) ? normalizeStateOffset(Reflect.get(doraRaw, "offset")) : 0;
227
- const costsOffset = isRecord(costsRaw) ? normalizeStateOffset(Reflect.get(costsRaw, "offset")) : 0;
228
- const lastSyncAtMs = normalizeStateOffset(Reflect.get(parsed, "lastSyncAtMs"));
229
- return {
230
- version: 1,
231
- lastSyncAtMs,
232
- files: {
233
- gates: {
234
- offset: gatesOffset
235
- },
236
- flow: {
237
- offset: flowOffset
238
- },
239
- dora: {
240
- offset: doraOffset
241
- },
242
- costs: {
243
- offset: costsOffset
244
- }
245
- }
246
- };
247
- } catch {
248
- return createDefaultCloudSyncState();
249
- }
250
- }
251
- function saveCloudSyncState(statePath, state) {
252
- mkdirSync(path.dirname(statePath), { recursive: true });
253
- writeFileSync(statePath, `${JSON.stringify(state, null, 2)}${STRING_LITERALS.NEWLINE}`, {
254
- encoding: "utf-8"
255
- });
256
- }
257
- function getSourceOffset(state, source) {
258
- if (source === TELEMETRY_SOURCE.GATES) {
259
- return state.files.gates.offset;
260
- }
261
- if (source === TELEMETRY_SOURCE.DORA) {
262
- return state.files.dora.offset;
263
- }
264
- if (source === TELEMETRY_SOURCE.COSTS) {
265
- return state.files.costs.offset;
266
- }
267
- return state.files.flow.offset;
268
- }
269
- function setSourceOffset(state, source, offset) {
270
- if (source === TELEMETRY_SOURCE.GATES) {
271
- state.files.gates.offset = offset;
272
- return;
273
- }
274
- if (source === TELEMETRY_SOURCE.DORA) {
275
- state.files.dora.offset = offset;
276
- return;
277
- }
278
- if (source === TELEMETRY_SOURCE.COSTS) {
279
- state.files.costs.offset = offset;
280
- return;
281
- }
282
- state.files.flow.offset = offset;
283
- }
284
- function resolveTelemetryPath(workspaceRoot, source) {
285
- if (source === TELEMETRY_SOURCE.GATES) {
286
- return path.join(workspaceRoot, GATES_LOG);
287
- }
288
- if (source === TELEMETRY_SOURCE.DORA) {
289
- return path.join(workspaceRoot, DORA_LOG);
290
- }
291
- if (source === TELEMETRY_SOURCE.COSTS) {
292
- return path.join(workspaceRoot, COSTS_LOG);
293
- }
294
- return path.join(workspaceRoot, FLOW_LOG);
295
- }
296
- function mapGatesEventToTelemetryRecord(payload, fallbackIso) {
297
- const gateName = asNonEmptyString(Reflect.get(payload, "gate_name")) ?? "unknown";
298
- const passedRaw = Reflect.get(payload, "passed");
299
- const passed = typeof passedRaw === "boolean" ? passedRaw : false;
300
- const durationMs = asFiniteNumber(Reflect.get(payload, "duration_ms")) ?? 0;
301
- const wuId = asPrimitiveTagValue(Reflect.get(payload, "wu_id"));
302
- const lane = asPrimitiveTagValue(Reflect.get(payload, "lane"));
303
- const tags = {
304
- source: TELEMETRY_SOURCE.GATES,
305
- gate_name: gateName,
306
- passed
307
- };
308
- if (wuId !== void 0) {
309
- tags.wu_id = wuId;
310
- }
311
- if (lane !== void 0) {
312
- tags.lane = lane;
313
- }
314
- return {
315
- metric: METRIC_NAME.GATES_DURATION_MS,
316
- value: durationMs,
317
- timestamp: normalizeTimestamp(Reflect.get(payload, "timestamp"), fallbackIso),
318
- tags
319
- };
320
- }
321
- function mapFlowEventToTelemetryRecord(payload, fallbackIso) {
322
- const script = asNonEmptyString(Reflect.get(payload, "script")) ?? "unknown";
323
- const step = asNonEmptyString(Reflect.get(payload, "step")) ?? asNonEmptyString(Reflect.get(payload, "event_type")) ?? "event";
324
- const value = asFiniteNumber(Reflect.get(payload, "duration_ms")) ?? 1;
325
- const status = asPrimitiveTagValue(Reflect.get(payload, "status"));
326
- const wuId = asPrimitiveTagValue(Reflect.get(payload, "wu_id"));
327
- const lane = asPrimitiveTagValue(Reflect.get(payload, "lane"));
328
- const tags = {
329
- source: TELEMETRY_SOURCE.FLOW,
330
- script,
331
- step
332
- };
333
- if (status !== void 0) {
334
- tags.status = status;
335
- }
336
- if (wuId !== void 0) {
337
- tags.wu_id = wuId;
338
- }
339
- if (lane !== void 0) {
340
- tags.lane = lane;
341
- }
342
- return {
343
- metric: METRIC_NAME.FLOW_EVENT,
344
- value,
345
- timestamp: normalizeTimestamp(Reflect.get(payload, "timestamp"), fallbackIso),
346
- tags
347
- };
348
- }
349
- function mapDoraEventToTelemetryRecord(payload, fallbackIso) {
350
- const metric = asNonEmptyString(Reflect.get(payload, "metric")) ?? "dora.unknown";
351
- const value = asFiniteNumber(Reflect.get(payload, "value")) ?? 0;
352
- const tier = asNonEmptyString(Reflect.get(payload, "tier"));
353
- const tags = {
354
- source: TELEMETRY_SOURCE.DORA
355
- };
356
- if (tier !== void 0) {
357
- tags.tier = tier;
358
- }
359
- return {
360
- metric,
361
- value,
362
- timestamp: normalizeTimestamp(Reflect.get(payload, "timestamp"), fallbackIso),
363
- tags
364
- };
365
- }
366
- function mapCostEventToTelemetryRecord(payload, fallbackIso) {
367
- const costUsd = asFiniteNumber(Reflect.get(payload, "cost_usd")) ?? 0;
368
- const inputTokens = asFiniteNumber(Reflect.get(payload, "input_tokens"));
369
- const outputTokens = asFiniteNumber(Reflect.get(payload, "output_tokens"));
370
- const operation = asPrimitiveTagValue(Reflect.get(payload, "operation"));
371
- const model = asPrimitiveTagValue(Reflect.get(payload, "model"));
372
- const wuId = asPrimitiveTagValue(Reflect.get(payload, "wu_id"));
373
- const agentId = asPrimitiveTagValue(Reflect.get(payload, "agent_id"));
374
- const sessionId = asPrimitiveTagValue(Reflect.get(payload, "session_id"));
375
- const tags = {
376
- source: TELEMETRY_SOURCE.COSTS,
377
- source_type: "cost"
378
- };
379
- if (operation !== void 0) {
380
- tags.operation = operation;
381
- }
382
- if (model !== void 0) {
383
- tags.model = model;
384
- }
385
- if (wuId !== void 0) {
386
- tags.wu_id = wuId;
387
- }
388
- if (agentId !== void 0) {
389
- tags.agent_id = agentId;
390
- }
391
- if (sessionId !== void 0) {
392
- tags.session_id = sessionId;
393
- }
394
- if (inputTokens !== void 0) {
395
- tags.input_tokens = inputTokens;
396
- }
397
- if (outputTokens !== void 0) {
398
- tags.output_tokens = outputTokens;
399
- }
400
- return {
401
- metric: METRIC_NAME.COST_USD,
402
- value: costUsd,
403
- timestamp: normalizeTimestamp(Reflect.get(payload, "timestamp"), fallbackIso),
404
- tags
405
- };
406
- }
407
- function resolveRawMetricName(source) {
408
- if (source === TELEMETRY_SOURCE.GATES)
409
- return METRIC_NAME.RAW_GATES;
410
- if (source === TELEMETRY_SOURCE.DORA)
411
- return METRIC_NAME.RAW_DORA;
412
- if (source === TELEMETRY_SOURCE.COSTS)
413
- return METRIC_NAME.RAW_COSTS;
414
- return METRIC_NAME.RAW_FLOW;
415
- }
416
- function mapTelemetryLineToRecord(source, payload, fallbackIso) {
417
- if (!isRecord(payload)) {
418
- return {
419
- metric: resolveRawMetricName(source),
420
- value: 1,
421
- timestamp: fallbackIso,
422
- tags: {
423
- source
424
- }
425
- };
426
- }
427
- if (source === TELEMETRY_SOURCE.GATES) {
428
- return mapGatesEventToTelemetryRecord(payload, fallbackIso);
429
- }
430
- if (source === TELEMETRY_SOURCE.DORA) {
431
- return mapDoraEventToTelemetryRecord(payload, fallbackIso);
432
- }
433
- if (source === TELEMETRY_SOURCE.COSTS) {
434
- return mapCostEventToTelemetryRecord(payload, fallbackIso);
435
- }
436
- return mapFlowEventToTelemetryRecord(payload, fallbackIso);
437
- }
438
- function readTelemetryLinesFromOffset(input) {
439
- if (!existsSync(input.filePath)) {
440
- return {
441
- items: [],
442
- malformedLines: 0,
443
- effectiveOffset: 0
444
- };
445
- }
446
- const fileBuffer = readFileSync(input.filePath);
447
- const fileSize = fileBuffer.byteLength;
448
- const effectiveOffset = Math.min(input.initialOffset, fileSize);
449
- const sliceBuffer = fileBuffer.subarray(effectiveOffset);
450
- const content = sliceBuffer.toString("utf-8");
451
- let malformedLines = 0;
452
- const items = [];
453
- let cursor = 0;
454
- let runningOffset = effectiveOffset;
455
- while (cursor < content.length) {
456
- const newlineIndex = content.indexOf(STRING_LITERALS.NEWLINE, cursor);
457
- if (newlineIndex < 0) {
458
- break;
459
- }
460
- const lineWithNewline = content.slice(cursor, newlineIndex + 1);
461
- runningOffset += Buffer.byteLength(lineWithNewline, "utf8");
462
- const line = content.slice(cursor, newlineIndex).trim();
463
- cursor = newlineIndex + 1;
464
- if (line.length === 0) {
465
- items.push({
466
- record: null,
467
- offsetAfterLine: runningOffset
468
- });
469
- continue;
470
- }
471
- try {
472
- const parsed = JSON.parse(line);
473
- items.push({
474
- record: mapTelemetryLineToRecord(input.source, parsed, input.fallbackIso),
475
- offsetAfterLine: runningOffset
476
- });
477
- } catch {
478
- malformedLines += 1;
479
- warnCloudSync(input.logger, `Skipping malformed NDJSON line in ${input.filePath} at offset ${runningOffset}.`);
480
- items.push({
481
- record: null,
482
- offsetAfterLine: runningOffset
483
- });
484
- }
485
- }
486
- return {
487
- items,
488
- malformedLines,
489
- effectiveOffset
490
- };
491
- }
492
- function safeResponseText(response) {
493
- return response.text().catch(() => "");
494
- }
495
- async function pushTelemetryBatch(input) {
496
- const controller = new AbortController();
497
- const timeout = setTimeout(() => controller.abort(), input.timeoutMs);
498
- try {
499
- const response = await input.fetchFn(`${input.endpoint}${CONTROL_PLANE_API_PATH.TELEMETRY}`, {
500
- method: HTTP.METHOD_POST,
501
- headers: {
502
- [HTTP.HEADER_AUTHORIZATION]: `Bearer ${input.token}`,
503
- [HTTP.HEADER_CONTENT_TYPE]: HTTP.CONTENT_TYPE_JSON
504
- },
505
- body: JSON.stringify({
506
- workspace_id: input.workspaceId,
507
- records: input.records
508
- }),
509
- signal: controller.signal
510
- });
511
- if (!response.ok) {
512
- const responseText = await safeResponseText(response);
513
- const suffix = responseText.length > 0 ? `: ${responseText}` : "";
514
- throw new Error(`HTTP ${response.status}${suffix}`);
515
- }
516
- } catch (error) {
517
- if (error instanceof Error && error.name === ERROR_NAME.ABORT) {
518
- throw new Error(`request timed out after ${input.timeoutMs}ms`, { cause: error });
519
- }
520
- throw error;
521
- } finally {
522
- clearTimeout(timeout);
523
- }
524
- }
525
- function detectMisnestedControlPlane(workspace) {
526
- const rootControlPlane = Reflect.get(workspace, CONTROL_PLANE_FIELD);
527
- if (isRecord(rootControlPlane)) {
528
- return null;
529
- }
530
- const softwareDelivery = Reflect.get(workspace, PACK_KEY_SOFTWARE_DELIVERY);
531
- if (!isRecord(softwareDelivery)) {
532
- return null;
533
- }
534
- const nestedControlPlane = Reflect.get(softwareDelivery, CONTROL_PLANE_FIELD);
535
- if (!isRecord(nestedControlPlane)) {
536
- return null;
537
- }
538
- const detectedPath = `${PACK_KEY_SOFTWARE_DELIVERY}.${CONTROL_PLANE_FIELD}`;
539
- return {
540
- message: `${CONTROL_PLANE_FIELD} is misnested under ${PACK_KEY_SOFTWARE_DELIVERY}. It must be a root-level key in workspace.yaml.`,
541
- detectedPath,
542
- remediation: `Move ${CONTROL_PLANE_FIELD} to the workspace root. Run: pnpm config:set --key control_plane.<sub-key> --value <value>`
543
- };
544
- }
545
- function resolveCloudSyncConfig(input) {
546
- const workspacePath = path.join(input.workspaceRoot, WORKSPACE_FILE);
547
- if (!existsSync(workspacePath)) {
548
- return null;
549
- }
550
- let parsedWorkspace;
551
- try {
552
- parsedWorkspace = YAML.parse(readFileSync(workspacePath, "utf-8"));
553
- } catch (error) {
554
- const message = error instanceof Error ? error.message : String(error);
555
- warnCloudSync(input.logger, `Unable to parse workspace config: ${message}`);
556
- return null;
557
- }
558
- if (!isRecord(parsedWorkspace)) {
559
- return null;
560
- }
561
- const workspaceId = asNonEmptyString(Reflect.get(parsedWorkspace, WORKSPACE_ID_FIELD));
562
- if (!workspaceId) {
563
- warnCloudSync(input.logger, "Skipping sync: workspace id is missing in workspace.yaml.");
564
- return null;
565
- }
566
- const controlPlaneRaw = Reflect.get(parsedWorkspace, CONTROL_PLANE_FIELD);
567
- if (!isRecord(controlPlaneRaw)) {
568
- const misnesting = detectMisnestedControlPlane(parsedWorkspace);
569
- if (misnesting) {
570
- warnCloudSync(input.logger, misnesting.message);
571
- warnCloudSync(input.logger, misnesting.remediation);
572
- }
573
- return null;
574
- }
575
- const endpoint = asNonEmptyString(Reflect.get(controlPlaneRaw, CONTROL_PLANE_ENDPOINT_FIELD));
576
- const syncIntervalSeconds = asPositiveInteger(Reflect.get(controlPlaneRaw, CONTROL_PLANE_SYNC_INTERVAL_FIELD));
577
- const batchSize = asPositiveInteger(Reflect.get(controlPlaneRaw, CONTROL_PLANE_BATCH_SIZE_FIELD)) ?? DEFAULT_BATCH_SIZE;
578
- const timeoutMs = asPositiveInteger(Reflect.get(controlPlaneRaw, CONTROL_PLANE_TIMEOUT_MS_FIELD)) ?? DEFAULT_TIMEOUT_MS;
579
- if (!endpoint || !syncIntervalSeconds) {
580
- warnCloudSync(input.logger, "Skipping sync: control_plane endpoint and sync_interval must be configured.");
581
- return null;
582
- }
583
- const authRaw = Reflect.get(controlPlaneRaw, CONTROL_PLANE_AUTH_FIELD);
584
- if (!isRecord(authRaw)) {
585
- warnCloudSync(input.logger, "Skipping sync: control_plane.auth is missing.");
586
- return null;
587
- }
588
- const tokenEnv = asNonEmptyString(Reflect.get(authRaw, CONTROL_PLANE_TOKEN_ENV_FIELD));
589
- if (!tokenEnv || !CONTROL_PLANE_TOKEN_ENV_PATTERN.test(tokenEnv)) {
590
- warnCloudSync(input.logger, "Skipping sync: control_plane.auth.token_env is invalid.");
591
- return null;
592
- }
593
- const tokenValue = input.environment[tokenEnv];
594
- const token = typeof tokenValue === "string" ? tokenValue.trim() : "";
595
- if (token.length === 0) {
596
- warnCloudSync(input.logger, `Skipping sync: missing cloud auth token in env "${tokenEnv}".`);
597
- return null;
598
- }
599
- try {
600
- void new URL(endpoint);
601
- } catch {
602
- warnCloudSync(input.logger, `Skipping sync: invalid control_plane endpoint "${endpoint}".`);
603
- return null;
604
- }
605
- return {
606
- workspaceId,
607
- endpoint: normalizeEndpoint(endpoint),
608
- token,
609
- syncIntervalMs: syncIntervalSeconds * MS_PER_SECOND,
610
- batchSize,
611
- timeoutMs
612
- };
613
- }
614
- async function syncNdjsonTelemetryToCloud(options = {}) {
615
- const workspaceRoot = options.workspaceRoot ?? process.cwd();
616
- const logger = options.logger;
617
- const fetchFn = options.fetchFn ?? fetch;
618
- const now = options.now ?? Date.now;
619
- const environment = options.environment ?? process.env;
620
- const statePath = path.join(workspaceRoot, CLOUD_SYNC_STATE_FILE);
621
- const config = resolveCloudSyncConfig({
622
- workspaceRoot,
623
- environment,
624
- logger
625
- });
626
- if (config === null) {
627
- return {
628
- recordsRead: 0,
629
- recordsSent: 0,
630
- malformedLines: 0,
631
- batchesAttempted: 0,
632
- batchesSucceeded: 0,
633
- skippedReason: "control-plane-unavailable"
634
- };
635
- }
636
- const state = loadCloudSyncState(statePath);
637
- const nowMs = now();
638
- if (state.lastSyncAtMs > 0 && nowMs - state.lastSyncAtMs < config.syncIntervalMs) {
639
- return {
640
- recordsRead: 0,
641
- recordsSent: 0,
642
- malformedLines: 0,
643
- batchesAttempted: 0,
644
- batchesSucceeded: 0,
645
- skippedReason: "sync-interval-not-elapsed"
646
- };
647
- }
648
- const fallbackIso = new Date(nowMs).toISOString();
649
- const nextState = {
650
- version: 1,
651
- lastSyncAtMs: state.lastSyncAtMs,
652
- files: {
653
- gates: { offset: state.files.gates.offset },
654
- flow: { offset: state.files.flow.offset },
655
- dora: { offset: state.files.dora.offset },
656
- costs: { offset: state.files.costs.offset }
657
- }
658
- };
659
- let malformedLines = 0;
660
- let recordsRead = 0;
661
- let recordsSent = 0;
662
- let batchesAttempted = 0;
663
- let batchesSucceeded = 0;
664
- let syncFailed = false;
665
- let stateChanged = false;
666
- for (const source of [
667
- TELEMETRY_SOURCE.GATES,
668
- TELEMETRY_SOURCE.FLOW,
669
- TELEMETRY_SOURCE.DORA,
670
- TELEMETRY_SOURCE.COSTS
671
- ]) {
672
- const filePath = resolveTelemetryPath(workspaceRoot, source);
673
- const sourceLines = readTelemetryLinesFromOffset({
674
- filePath,
675
- source,
676
- initialOffset: getSourceOffset(nextState, source),
677
- logger,
678
- fallbackIso
679
- });
680
- malformedLines += sourceLines.malformedLines;
681
- let acknowledgedOffset = sourceLines.effectiveOffset;
682
- let index = 0;
683
- while (index < sourceLines.items.length) {
684
- const currentLine = sourceLines.items[index];
685
- if (currentLine?.record === null) {
686
- acknowledgedOffset = currentLine.offsetAfterLine;
687
- stateChanged = true;
688
- index += 1;
689
- continue;
690
- }
691
- const batch = [];
692
- let lastBatchOffset = acknowledgedOffset;
693
- while (index < sourceLines.items.length && sourceLines.items[index]?.record !== null && batch.length < config.batchSize) {
694
- const line = sourceLines.items[index];
695
- if (!line || line.record === null) {
696
- break;
697
- }
698
- batch.push(line.record);
699
- lastBatchOffset = line.offsetAfterLine;
700
- index += 1;
701
- }
702
- recordsRead += batch.length;
703
- batchesAttempted += 1;
704
- try {
705
- await pushTelemetryBatch({
706
- endpoint: config.endpoint,
707
- workspaceId: config.workspaceId,
708
- token: config.token,
709
- timeoutMs: config.timeoutMs,
710
- records: batch,
711
- fetchFn
712
- });
713
- recordsSent += batch.length;
714
- batchesSucceeded += 1;
715
- acknowledgedOffset = lastBatchOffset;
716
- stateChanged = true;
717
- } catch (error) {
718
- const message = error instanceof Error ? error.message : String(error);
719
- warnCloudSync(logger, `Telemetry sync failed: ${message}`);
720
- syncFailed = true;
721
- break;
722
- }
723
- }
724
- setSourceOffset(nextState, source, acknowledgedOffset);
725
- if (syncFailed) {
726
- break;
727
- }
728
- }
729
- if (stateChanged) {
730
- if (!syncFailed) {
731
- nextState.lastSyncAtMs = nowMs;
732
- }
733
- saveCloudSyncState(statePath, nextState);
734
- } else if (!syncFailed) {
735
- nextState.lastSyncAtMs = nowMs;
736
- saveCloudSyncState(statePath, nextState);
737
- }
738
- return {
739
- recordsRead,
740
- recordsSent,
741
- malformedLines,
742
- batchesAttempted,
743
- batchesSucceeded,
744
- ...syncFailed ? { skippedReason: "sync-failed" } : {}
745
- };
746
- }
747
-
748
- // ../core/dist/spawn-policy-resolver.js
749
- function emitMethodologyTelemetry(config, policy) {
750
- if (!config.telemetry?.methodology?.enabled) {
751
- return;
752
- }
753
- const event = {
754
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
755
- event_type: "methodology.selection",
756
- methodology_testing: policy.testing,
757
- methodology_architecture: policy.architecture,
758
- event_context: "spawn"
759
- };
760
- emit(LUMENFLOW_PATHS.METHODOLOGY_LOG, event);
761
- }
762
-
763
- export {
764
- emit,
765
- emitGateEvent,
766
- getCurrentWU,
767
- getCurrentLane,
768
- emitWUFlowEvent,
769
- emitDoraTelemetry,
770
- syncNdjsonTelemetryToCloud,
771
- emitMethodologyTelemetry
772
- };