@runcofactor/cli 0.10.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 (150) hide show
  1. package/README.md +125 -0
  2. package/dist/api-catalog-GFGCLVS4.js +401 -0
  3. package/dist/api-catalog-GFGCLVS4.js.map +1 -0
  4. package/dist/attachment-SJC7D7FY.js +276 -0
  5. package/dist/attachment-SJC7D7FY.js.map +1 -0
  6. package/dist/auth-EN6NQCJY.js +31 -0
  7. package/dist/auth-EN6NQCJY.js.map +1 -0
  8. package/dist/bin.js +7 -0
  9. package/dist/bin.js.map +1 -0
  10. package/dist/chunk-3CZU7XCS.js +272 -0
  11. package/dist/chunk-3CZU7XCS.js.map +1 -0
  12. package/dist/chunk-4NRDONSC.js +1048 -0
  13. package/dist/chunk-4NRDONSC.js.map +1 -0
  14. package/dist/chunk-4PNOV7OV.js +51980 -0
  15. package/dist/chunk-4PNOV7OV.js.map +1 -0
  16. package/dist/chunk-52IO7ACJ.js +2941 -0
  17. package/dist/chunk-52IO7ACJ.js.map +1 -0
  18. package/dist/chunk-6LEZCKKV.js +663 -0
  19. package/dist/chunk-6LEZCKKV.js.map +1 -0
  20. package/dist/chunk-A4OFTUVV.js +170 -0
  21. package/dist/chunk-A4OFTUVV.js.map +1 -0
  22. package/dist/chunk-B2VISN2V.js +2459 -0
  23. package/dist/chunk-B2VISN2V.js.map +1 -0
  24. package/dist/chunk-CLAWT7BJ.js +271 -0
  25. package/dist/chunk-CLAWT7BJ.js.map +1 -0
  26. package/dist/chunk-GKY2KXO5.js +281 -0
  27. package/dist/chunk-GKY2KXO5.js.map +1 -0
  28. package/dist/chunk-I4QLI3JO.js +413 -0
  29. package/dist/chunk-I4QLI3JO.js.map +1 -0
  30. package/dist/chunk-IMPZAX6L.js +180 -0
  31. package/dist/chunk-IMPZAX6L.js.map +1 -0
  32. package/dist/chunk-J6SH7GQT.js +241 -0
  33. package/dist/chunk-J6SH7GQT.js.map +1 -0
  34. package/dist/chunk-JDBCZ3Z2.js +298 -0
  35. package/dist/chunk-JDBCZ3Z2.js.map +1 -0
  36. package/dist/chunk-JICSYFRJ.js +46 -0
  37. package/dist/chunk-JICSYFRJ.js.map +1 -0
  38. package/dist/chunk-JWHYXEA2.js +32 -0
  39. package/dist/chunk-JWHYXEA2.js.map +1 -0
  40. package/dist/chunk-N7HFALX3.js +88 -0
  41. package/dist/chunk-N7HFALX3.js.map +1 -0
  42. package/dist/chunk-Q4BO4Z5V.js +178 -0
  43. package/dist/chunk-Q4BO4Z5V.js.map +1 -0
  44. package/dist/chunk-QFDOWABX.js +195 -0
  45. package/dist/chunk-QFDOWABX.js.map +1 -0
  46. package/dist/chunk-SJJW77WN.js +605 -0
  47. package/dist/chunk-SJJW77WN.js.map +1 -0
  48. package/dist/chunk-VKVL7WBN.js +50 -0
  49. package/dist/chunk-VKVL7WBN.js.map +1 -0
  50. package/dist/chunk-WOHL4FTB.js +353 -0
  51. package/dist/chunk-WOHL4FTB.js.map +1 -0
  52. package/dist/chunk-XQXVG7RA.js +426 -0
  53. package/dist/chunk-XQXVG7RA.js.map +1 -0
  54. package/dist/chunk-ZD3KHESI.js +94 -0
  55. package/dist/chunk-ZD3KHESI.js.map +1 -0
  56. package/dist/credential-COLTBV6D.js +450 -0
  57. package/dist/credential-COLTBV6D.js.map +1 -0
  58. package/dist/credential-template-EEPYFG7R.js +291 -0
  59. package/dist/credential-template-EEPYFG7R.js.map +1 -0
  60. package/dist/debug-workflow-KOVH5GOP.js +259 -0
  61. package/dist/debug-workflow-KOVH5GOP.js.map +1 -0
  62. package/dist/dist-44PZR7BQ.js +423 -0
  63. package/dist/dist-44PZR7BQ.js.map +1 -0
  64. package/dist/docs-3SSORHB5.js +366 -0
  65. package/dist/docs-3SSORHB5.js.map +1 -0
  66. package/dist/doctor-OTSIWV6G.js +132 -0
  67. package/dist/doctor-OTSIWV6G.js.map +1 -0
  68. package/dist/feature-flag-T2LRZME3.js +283 -0
  69. package/dist/feature-flag-T2LRZME3.js.map +1 -0
  70. package/dist/file-type-S3UUBVCT.js +4205 -0
  71. package/dist/file-type-S3UUBVCT.js.map +1 -0
  72. package/dist/index.d.ts +3 -0
  73. package/dist/index.js +982 -0
  74. package/dist/index.js.map +1 -0
  75. package/dist/init-TGWRECT2.js +208 -0
  76. package/dist/init-TGWRECT2.js.map +1 -0
  77. package/dist/install-DXSNWZKO.js +295 -0
  78. package/dist/install-DXSNWZKO.js.map +1 -0
  79. package/dist/issues-XIZOPX6T.js +564 -0
  80. package/dist/issues-XIZOPX6T.js.map +1 -0
  81. package/dist/knobs-NBINZIUB.js +295 -0
  82. package/dist/knobs-NBINZIUB.js.map +1 -0
  83. package/dist/list-3TDHK637.js +59 -0
  84. package/dist/list-3TDHK637.js.map +1 -0
  85. package/dist/local-HICVD6PU.js +100 -0
  86. package/dist/local-HICVD6PU.js.map +1 -0
  87. package/dist/login-UOIUXVUK.js +315 -0
  88. package/dist/login-UOIUXVUK.js.map +1 -0
  89. package/dist/mcp-54IJEOUA.js +1956 -0
  90. package/dist/mcp-54IJEOUA.js.map +1 -0
  91. package/dist/pdf-extract-ABWV3L5X.js +13 -0
  92. package/dist/pdf-extract-ABWV3L5X.js.map +1 -0
  93. package/dist/pdfjs-DQ2YA5S3.js +41561 -0
  94. package/dist/pdfjs-DQ2YA5S3.js.map +1 -0
  95. package/dist/property-UXLOLPTD.js +701 -0
  96. package/dist/property-UXLOLPTD.js.map +1 -0
  97. package/dist/property-skill-guide.md +189 -0
  98. package/dist/psql-BYUUNLGG.js +115 -0
  99. package/dist/psql-BYUUNLGG.js.map +1 -0
  100. package/dist/record-4TR2UIIS.js +233 -0
  101. package/dist/record-4TR2UIIS.js.map +1 -0
  102. package/dist/redis-35VBUYW7.js +116 -0
  103. package/dist/redis-35VBUYW7.js.map +1 -0
  104. package/dist/release-OOLTUBUT.js +354 -0
  105. package/dist/release-OOLTUBUT.js.map +1 -0
  106. package/dist/sandbox-XGSUU6G7.js +2046 -0
  107. package/dist/sandbox-XGSUU6G7.js.map +1 -0
  108. package/dist/scenarios-GWLJEGHA.js +280 -0
  109. package/dist/scenarios-GWLJEGHA.js.map +1 -0
  110. package/dist/session-MYFNZPRP.js +2414 -0
  111. package/dist/session-MYFNZPRP.js.map +1 -0
  112. package/dist/skill-KM34LDMO.js +1839 -0
  113. package/dist/skill-KM34LDMO.js.map +1 -0
  114. package/dist/skills/debug-run/SKILL.md +262 -0
  115. package/dist/skills/debug-run/history/1.0.0.md +244 -0
  116. package/dist/skills/debug-run/history/1.0.1.md +245 -0
  117. package/dist/skills/debug-run/history/1.0.2.md +254 -0
  118. package/dist/skills/debug-run/history/1.1.0.md +262 -0
  119. package/dist/skills/debug-run/version.json +3 -0
  120. package/dist/spec-RA3CFEKG.js +951 -0
  121. package/dist/spec-RA3CFEKG.js.map +1 -0
  122. package/dist/src-LB4HBTJQ.js +1516 -0
  123. package/dist/src-LB4HBTJQ.js.map +1 -0
  124. package/dist/src-N3TPKGTY.js +244 -0
  125. package/dist/src-N3TPKGTY.js.map +1 -0
  126. package/dist/src-UVDX5UP6.js +17 -0
  127. package/dist/src-UVDX5UP6.js.map +1 -0
  128. package/dist/start-PSEQSQA3.js +151 -0
  129. package/dist/start-PSEQSQA3.js.map +1 -0
  130. package/dist/tag-YY6YAABQ.js +22 -0
  131. package/dist/tag-YY6YAABQ.js.map +1 -0
  132. package/dist/task-IQC3YR5K.js +922 -0
  133. package/dist/task-IQC3YR5K.js.map +1 -0
  134. package/dist/test-suite-DZNJFXDW.js +394 -0
  135. package/dist/test-suite-DZNJFXDW.js.map +1 -0
  136. package/dist/trace-HXIW7U2D.js +14 -0
  137. package/dist/trace-HXIW7U2D.js.map +1 -0
  138. package/dist/triage-ORG45R5W.js +16 -0
  139. package/dist/triage-ORG45R5W.js.map +1 -0
  140. package/dist/upgrade-L2VYMP2V.js +61 -0
  141. package/dist/upgrade-L2VYMP2V.js.map +1 -0
  142. package/dist/workflow-XYFH5LTP.js +3708 -0
  143. package/dist/workflow-XYFH5LTP.js.map +1 -0
  144. package/dist/workflow-cache-NQJQFWMV.js +253 -0
  145. package/dist/workflow-cache-NQJQFWMV.js.map +1 -0
  146. package/dist/workflow-debug-BGD4UIXU.js +927 -0
  147. package/dist/workflow-debug-BGD4UIXU.js.map +1 -0
  148. package/dist/workflow-proposals-MTUDX46O.js +382 -0
  149. package/dist/workflow-proposals-MTUDX46O.js.map +1 -0
  150. package/package.json +61 -0
@@ -0,0 +1,1516 @@
1
+ import { createRequire as __cr } from "module"; const require = __cr(import.meta.url);
2
+ import {
3
+ parseTraceActions,
4
+ reconstructSnapshots
5
+ } from "./chunk-52IO7ACJ.js";
6
+ import "./chunk-VKVL7WBN.js";
7
+
8
+ // ../diagnostic-workspace/src/assemble-workspace.ts
9
+ import * as fs10 from "fs/promises";
10
+
11
+ // ../diagnostic-workspace/src/_shared.ts
12
+ var NAVIGATION_ACTIONS = /* @__PURE__ */ new Set([
13
+ "navigate",
14
+ "navigation",
15
+ "pushstate",
16
+ "popstate",
17
+ "pushState",
18
+ "popState",
19
+ "redirect",
20
+ "load"
21
+ ]);
22
+ var hostOf = (raw) => {
23
+ if (typeof raw !== "string" || raw.length === 0) return null;
24
+ try {
25
+ return new URL(raw).hostname.toLowerCase().replace(/^www\./, "");
26
+ } catch {
27
+ return null;
28
+ }
29
+ };
30
+ var formatRelative = (ms) => {
31
+ const sign = ms < 0 ? "-" : "+";
32
+ const abs = Math.abs(ms);
33
+ const seconds = Math.floor(abs / 1e3);
34
+ const millis = abs % 1e3;
35
+ return `T${sign}${seconds}.${String(millis).padStart(3, "0")}s`;
36
+ };
37
+ var formatAbsolute = (ms) => {
38
+ const d = new Date(ms);
39
+ const hh = String(d.getUTCHours()).padStart(2, "0");
40
+ const mm = String(d.getUTCMinutes()).padStart(2, "0");
41
+ const ss = String(d.getUTCSeconds()).padStart(2, "0");
42
+ const mil = String(d.getUTCMilliseconds()).padStart(3, "0");
43
+ return `${hh}:${mm}:${ss}.${mil}`;
44
+ };
45
+ var formatPrefix = (timestampMs, baselineMs) => {
46
+ if (timestampMs === null) return "[unknown @ unknown]";
47
+ const rel = baselineMs !== null ? formatRelative(timestampMs - baselineMs) : "T+?";
48
+ const abs = formatAbsolute(timestampMs);
49
+ return `[${rel} @ ${abs}]`;
50
+ };
51
+ var oneLine = (s) => s.replace(/\s+/g, " ").trim();
52
+ var truncate = (s, max) => s.length <= max ? s : `${s.slice(0, max - 1)}\u2026`;
53
+
54
+ // ../diagnostic-workspace/src/paths.ts
55
+ import * as path from "path";
56
+ var WORKSPACE_PATHS = {
57
+ manifest: "manifest.json",
58
+ reportedFailure: "reported-failure.md",
59
+ summary: "summary.md",
60
+ ledger: "ledger.md",
61
+ ledgerIndex: "ledger-index.md",
62
+ steps: "steps",
63
+ // steps/<NNN>-<stepId>.md
64
+ timeline: "timeline",
65
+ timelineSteps: "timeline/steps.jsonl",
66
+ timelineActions: "timeline/actions.jsonl",
67
+ timelineNavigation: "timeline/navigation.jsonl",
68
+ timelineAssertions: "timeline/assertions.jsonl",
69
+ timelineCacheDecisions: "timeline/cache-decisions.jsonl",
70
+ thoughts: "thoughts",
71
+ thoughtsAll: "thoughts/all.jsonl",
72
+ thoughtsByStep: "thoughts/by-step",
73
+ // thoughts/by-step/<stepId>.md
74
+ browser: "browser",
75
+ browserTraceZip: "browser/trace.zip",
76
+ browserActions: "browser/actions.jsonl",
77
+ browserDoms: "browser/doms",
78
+ // browser/doms/<NNNN>-<timestamp>.html
79
+ browserFrames: "browser/frames",
80
+ // browser/frames/<NNNN>-<timestamp>.png
81
+ browserA11y: "browser/a11y",
82
+ // browser/a11y/<NNNN>-<timestamp>.yaml
83
+ browserResources: "browser/resources",
84
+ logs: "logs",
85
+ logsNetwork: "logs/network.jsonl",
86
+ logsNetworkErrors: "logs/network-errors.jsonl",
87
+ logsConsole: "logs/console.jsonl",
88
+ logsConsoleErrors: "logs/console-errors.jsonl",
89
+ logsSentry: "logs/sentry-logs.jsonl",
90
+ logsSentrySpans: "logs/sentry-spans.jsonl",
91
+ workflow: "workflow",
92
+ workflowDefinition: "workflow/definition.json",
93
+ workflowSnapshot: "workflow/snapshot.json",
94
+ workflowNodes: "workflow/nodes",
95
+ // workflow/nodes/<nodeId>.json
96
+ variables: "variables",
97
+ variablesInputs: "variables/inputs.json",
98
+ variablesLineage: "variables/lineage.jsonl",
99
+ history: "history",
100
+ historyRecentRuns: "history/recent-runs.jsonl",
101
+ historyLastGreen: "history/last-green",
102
+ notes: "notes"
103
+ };
104
+ var WORKSPACE_DIRS = [
105
+ WORKSPACE_PATHS.steps,
106
+ WORKSPACE_PATHS.timeline,
107
+ WORKSPACE_PATHS.thoughts,
108
+ WORKSPACE_PATHS.thoughtsByStep,
109
+ WORKSPACE_PATHS.browser,
110
+ WORKSPACE_PATHS.browserDoms,
111
+ WORKSPACE_PATHS.browserFrames,
112
+ WORKSPACE_PATHS.browserA11y,
113
+ WORKSPACE_PATHS.browserResources,
114
+ WORKSPACE_PATHS.logs,
115
+ WORKSPACE_PATHS.workflow,
116
+ WORKSPACE_PATHS.workflowNodes,
117
+ WORKSPACE_PATHS.variables,
118
+ WORKSPACE_PATHS.history,
119
+ WORKSPACE_PATHS.notes
120
+ ];
121
+ var resolveWorkspacePath = (root, relative) => path.join(root, relative);
122
+ var stepRollupRelativePath = (orderIndex, stepId) => path.join(WORKSPACE_PATHS.steps, `${String(orderIndex).padStart(3, "0")}-${stepId}.md`);
123
+ var thoughtsByStepRelativePath = (stepId) => path.join(WORKSPACE_PATHS.thoughtsByStep, `${stepId}.md`);
124
+ var workflowNodeRelativePath = (nodeId) => path.join(WORKSPACE_PATHS.workflowNodes, `${nodeId}.json`);
125
+ var actionArtifactBasename = (actionIndex, absoluteTsMs, ext) => `${String(actionIndex).padStart(4, "0")}-${absoluteTsMs}.${ext}`;
126
+
127
+ // ../diagnostic-workspace/src/manifest-builder.ts
128
+ import * as fs from "fs/promises";
129
+ var writeManifest = async (input) => {
130
+ const startedMs = input.startedAt ? Date.parse(input.startedAt) : null;
131
+ const finishedMs = input.finishedAt ? Date.parse(input.finishedAt) : null;
132
+ const durationMs = startedMs !== null && finishedMs !== null ? finishedMs - startedMs : null;
133
+ const manifest = {
134
+ runId: input.runId,
135
+ workflowId: input.workflowId,
136
+ orgId: input.orgId,
137
+ status: input.status,
138
+ startedAt: input.startedAt,
139
+ finishedAt: input.finishedAt,
140
+ durationMs,
141
+ errorMessage: input.errorMessage,
142
+ workflowName: input.workflowName,
143
+ failedStepId: input.failedStepId,
144
+ failedNodeId: input.failedNodeId,
145
+ failedStepName: input.failedStepName,
146
+ traceStorageKey: input.traceStorageKey,
147
+ diagnosticsStorageKey: input.diagnosticsStorageKey,
148
+ videoStorageKey: input.videoStorageKey,
149
+ materializedAt: (/* @__PURE__ */ new Date()).toISOString(),
150
+ partial: input.partial
151
+ };
152
+ await fs.writeFile(
153
+ resolveWorkspacePath(input.workspaceRoot, WORKSPACE_PATHS.manifest),
154
+ `${JSON.stringify(manifest, null, 2)}
155
+ `,
156
+ "utf-8"
157
+ );
158
+ return manifest;
159
+ };
160
+
161
+ // ../diagnostic-workspace/src/reported-failure-builder.ts
162
+ import * as fs2 from "fs/promises";
163
+ var writeReportedFailure = async (input) => {
164
+ const lines = [];
165
+ lines.push("# Reported Failure");
166
+ lines.push("");
167
+ lines.push(
168
+ "**This is the test runner's hypothesis. Verify with evidence before trusting it \u2014 the root cause is often upstream of the visible failure.**"
169
+ );
170
+ lines.push("");
171
+ lines.push(`Run status: \`${input.runStatus}\``);
172
+ lines.push("");
173
+ if (input.runStatus !== "failed") {
174
+ lines.push(
175
+ `> The run did not end in a \`failed\` status. The test runner did not designate a failed step.`
176
+ );
177
+ lines.push("");
178
+ } else if (!input.failedStepName) {
179
+ lines.push(
180
+ `> The run is \`failed\` but no failed step was identified. Investigate the run-level error message and walk the timeline.`
181
+ );
182
+ lines.push("");
183
+ } else {
184
+ const ordinal = input.failedStepOrderIndex !== null ? ` (step ${input.failedStepOrderIndex})` : "";
185
+ lines.push(`Failed step${ordinal}: **${input.failedStepName}**`);
186
+ lines.push("");
187
+ }
188
+ if (input.errorMessage) {
189
+ lines.push("## Error message");
190
+ lines.push("");
191
+ lines.push("```");
192
+ lines.push(input.errorMessage);
193
+ lines.push("```");
194
+ lines.push("");
195
+ }
196
+ lines.push("## What to do next");
197
+ lines.push("");
198
+ lines.push(
199
+ "1. Read `summary.md` for the run-level overview and step table."
200
+ );
201
+ lines.push(
202
+ "2. Open the failed step's rollup at `steps/<NNN>-<stepId>.md` to gather evidence at the failure point."
203
+ );
204
+ lines.push(
205
+ "3. Walk backwards through prior `steps/*.md` rollups \u2014 the divergence often happens upstream."
206
+ );
207
+ lines.push("");
208
+ await fs2.writeFile(
209
+ resolveWorkspacePath(input.workspaceRoot, WORKSPACE_PATHS.reportedFailure),
210
+ `${lines.join("\n")}
211
+ `,
212
+ "utf-8"
213
+ );
214
+ };
215
+
216
+ // ../diagnostic-workspace/src/jsonl-writers.ts
217
+ import * as fs3 from "fs/promises";
218
+ var writeJsonl = (absolutePath, lines) => fs3.writeFile(
219
+ absolutePath,
220
+ lines.length === 0 ? "" : `${lines.map((l) => JSON.stringify(l)).join("\n")}
221
+ `,
222
+ "utf-8"
223
+ );
224
+ var writeJson = (absolutePath, value) => fs3.writeFile(absolutePath, `${JSON.stringify(value, null, 2)}
225
+ `, "utf-8");
226
+ var writeText = (absolutePath, text) => fs3.writeFile(absolutePath, text, "utf-8");
227
+ var isoToMs = (iso) => {
228
+ if (!iso) return null;
229
+ const parsed = Date.parse(iso);
230
+ return Number.isFinite(parsed) ? parsed : null;
231
+ };
232
+ var isObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
233
+ var writeTimelineSteps = async (workspaceRoot, steps) => {
234
+ const lines = steps.slice().sort((a, b) => a.orderIndex - b.orderIndex).map((step) => {
235
+ const meta = isObject(step.metadataJson) ? step.metadataJson : {};
236
+ const startedMs = isoToMs(step.startedAt);
237
+ const finishedMs = isoToMs(step.finishedAt);
238
+ return {
239
+ id: step.id,
240
+ nodeId: step.nodeId,
241
+ orderIndex: step.orderIndex,
242
+ name: step.nodeName,
243
+ nodeType: step.nodeType,
244
+ status: step.status,
245
+ startedAt: step.startedAt,
246
+ finishedAt: step.finishedAt,
247
+ startedAtMs: startedMs,
248
+ finishedAtMs: finishedMs,
249
+ durationMs: startedMs !== null && finishedMs !== null ? finishedMs - startedMs : null,
250
+ errorMessage: step.errorMessage,
251
+ cacheOutcome: meta.cacheOutcome ?? null,
252
+ cacheHitSource: meta.cacheHitSource ?? null,
253
+ cacheProcessingStatus: meta.cacheProcessingStatus ?? null,
254
+ cacheOutcomeReason: meta.cacheOutcomeReason ?? null
255
+ };
256
+ });
257
+ await writeJsonl(
258
+ resolveWorkspacePath(workspaceRoot, WORKSPACE_PATHS.timelineSteps),
259
+ lines
260
+ );
261
+ };
262
+ var writeTimelineActionsAndNavigation = async (workspaceRoot, timeline) => {
263
+ const baselineMs = timeline.startTimestamp ? Date.parse(timeline.startTimestamp) : null;
264
+ const actions = timeline.entries.map((e) => ({
265
+ action: e.action,
266
+ target: e.target ?? null,
267
+ value: e.value ?? null,
268
+ url: e.url ?? null,
269
+ relativeTimestampMs: e.timestampMs,
270
+ timestampMs: baselineMs !== null ? baselineMs + e.timestampMs : null,
271
+ success: e.success,
272
+ isAnnotation: e.isAnnotation ?? false
273
+ }));
274
+ await writeJsonl(
275
+ resolveWorkspacePath(workspaceRoot, WORKSPACE_PATHS.timelineActions),
276
+ actions
277
+ );
278
+ const navRows = [];
279
+ let prevUrl = null;
280
+ for (const a of actions) {
281
+ const isNavAction = NAVIGATION_ACTIONS.has(a.action);
282
+ const urlChanged = a.url !== null && prevUrl !== null && a.url !== prevUrl;
283
+ if (!isNavAction && !urlChanged) {
284
+ if (a.url) prevUrl = a.url;
285
+ continue;
286
+ }
287
+ const fromHost = hostOf(prevUrl);
288
+ const toHost = hostOf(a.url);
289
+ navRows.push({
290
+ relativeTimestampMs: a.relativeTimestampMs,
291
+ timestampMs: a.timestampMs,
292
+ action: a.action,
293
+ from: prevUrl,
294
+ to: a.url,
295
+ crossHost: fromHost !== null && toHost !== null && fromHost !== toHost
296
+ });
297
+ if (a.url) prevUrl = a.url;
298
+ }
299
+ await writeJsonl(
300
+ resolveWorkspacePath(workspaceRoot, WORKSPACE_PATHS.timelineNavigation),
301
+ navRows
302
+ );
303
+ };
304
+ var writeAssertionsAndCacheDecisions = async (workspaceRoot, steps) => {
305
+ const sortedSteps = steps.slice().sort((a, b) => a.orderIndex - b.orderIndex);
306
+ const assertions = [];
307
+ const cacheDecisions = [];
308
+ for (const step of sortedSteps) {
309
+ const meta = isObject(step.metadataJson) ? step.metadataJson : {};
310
+ const startedMs = isoToMs(step.startedAt);
311
+ const rawAssertions = Array.isArray(meta.assertionResults) ? meta.assertionResults : [];
312
+ for (const r of rawAssertions) {
313
+ if (!isObject(r)) continue;
314
+ assertions.push({
315
+ stepId: step.id,
316
+ nodeId: step.nodeId,
317
+ orderIndex: step.orderIndex,
318
+ stepStatus: step.status,
319
+ timestampMs: startedMs,
320
+ assertionId: r.inlineAssertionId ?? r.assertionId ?? r.key ?? null,
321
+ condition: r.condition ?? null,
322
+ severity: r.severity ?? null,
323
+ nonBlocking: Boolean(r.nonBlocking),
324
+ passed: Boolean(r.passed),
325
+ reason: r.reason ?? null
326
+ });
327
+ }
328
+ cacheDecisions.push({
329
+ stepId: step.id,
330
+ nodeId: step.nodeId,
331
+ orderIndex: step.orderIndex,
332
+ stepStatus: step.status,
333
+ timestampMs: startedMs,
334
+ cacheOutcome: meta.cacheOutcome ?? null,
335
+ cacheHitSource: meta.cacheHitSource ?? null,
336
+ cacheProcessingStatus: meta.cacheProcessingStatus ?? null,
337
+ cacheOutcomeReason: meta.cacheOutcomeReason ?? null
338
+ });
339
+ }
340
+ await writeJsonl(
341
+ resolveWorkspacePath(workspaceRoot, WORKSPACE_PATHS.timelineAssertions),
342
+ assertions
343
+ );
344
+ await writeJsonl(
345
+ resolveWorkspacePath(workspaceRoot, WORKSPACE_PATHS.timelineCacheDecisions),
346
+ cacheDecisions
347
+ );
348
+ };
349
+ var writeThoughts = async (workspaceRoot, thoughts) => {
350
+ const sorted = thoughts.slice().sort((a, b) => a.orderIndex - b.orderIndex);
351
+ const allRows = sorted.map((t) => ({
352
+ id: t.id,
353
+ stepId: t.stepId,
354
+ nodeId: t.nodeId,
355
+ toolName: t.toolName,
356
+ orderIndex: t.orderIndex,
357
+ timestampMs: isoToMs(t.createdAt),
358
+ createdAt: t.createdAt,
359
+ content: t.content
360
+ }));
361
+ await writeJsonl(
362
+ resolveWorkspacePath(workspaceRoot, WORKSPACE_PATHS.thoughtsAll),
363
+ allRows
364
+ );
365
+ const byStep = /* @__PURE__ */ new Map();
366
+ for (const t of sorted) {
367
+ const key = t.stepId ?? "_no-step";
368
+ const list = byStep.get(key) ?? [];
369
+ list.push(t);
370
+ byStep.set(key, list);
371
+ }
372
+ const renderStep = ([stepId, stepThoughts]) => {
373
+ const md = [];
374
+ md.push(`# Thoughts for ${stepId === "_no-step" ? "(no step)" : `step ${stepId}`}`);
375
+ md.push("");
376
+ for (const t of stepThoughts) {
377
+ const tool = t.toolName ? ` [tool: ${t.toolName}]` : "";
378
+ md.push(`## ${t.createdAt}${tool}`);
379
+ md.push("");
380
+ md.push(t.content);
381
+ md.push("");
382
+ }
383
+ return {
384
+ relativePath: thoughtsByStepRelativePath(stepId),
385
+ body: `${md.join("\n")}
386
+ `
387
+ };
388
+ };
389
+ const rendered = [...byStep.entries()].map(renderStep);
390
+ await Promise.all(
391
+ rendered.map(
392
+ ({ relativePath, body }) => writeText(resolveWorkspacePath(workspaceRoot, relativePath), body)
393
+ )
394
+ );
395
+ };
396
+ var normalizeTimestamp = (ts) => {
397
+ if (ts === null || ts === void 0) return null;
398
+ if (typeof ts === "number") return ts;
399
+ const parsed = Date.parse(ts);
400
+ return Number.isFinite(parsed) ? parsed : null;
401
+ };
402
+ var writeLogs = async (workspaceRoot, network, consoleLogs) => {
403
+ const networkRows = network.map((e) => ({
404
+ timestampMs: normalizeTimestamp(e.timestamp ?? null),
405
+ url: e.url,
406
+ method: e.method,
407
+ status: e.status ?? null,
408
+ durationMs: e.durationMs ?? null,
409
+ requestBody: e.requestBody ?? null,
410
+ responseBody: e.responseBody ?? null,
411
+ contentType: e.contentType ?? null
412
+ }));
413
+ const networkErrors = networkRows.filter(
414
+ (r) => typeof r.status === "number" && r.status >= 400
415
+ );
416
+ await writeJsonl(
417
+ resolveWorkspacePath(workspaceRoot, WORKSPACE_PATHS.logsNetwork),
418
+ networkRows
419
+ );
420
+ await writeJsonl(
421
+ resolveWorkspacePath(workspaceRoot, WORKSPACE_PATHS.logsNetworkErrors),
422
+ networkErrors
423
+ );
424
+ const consoleRows = consoleLogs.map((e) => ({
425
+ timestampMs: normalizeTimestamp(e.timestamp),
426
+ type: e.type,
427
+ text: e.text,
428
+ location: e.location ?? null
429
+ }));
430
+ const consoleErrors = consoleRows.filter(
431
+ (r) => r.type === "error" || r.type === "warning"
432
+ );
433
+ await writeJsonl(
434
+ resolveWorkspacePath(workspaceRoot, WORKSPACE_PATHS.logsConsole),
435
+ consoleRows
436
+ );
437
+ await writeJsonl(
438
+ resolveWorkspacePath(workspaceRoot, WORKSPACE_PATHS.logsConsoleErrors),
439
+ consoleErrors
440
+ );
441
+ };
442
+ var writeVariables = async (workspaceRoot, runMetadata, steps) => {
443
+ const inputs = isObject(runMetadata) && isObject(runMetadata.workflowInputValues) ? runMetadata.workflowInputValues : {};
444
+ await writeJson(
445
+ resolveWorkspacePath(workspaceRoot, WORKSPACE_PATHS.variablesInputs),
446
+ inputs
447
+ );
448
+ const sortedSteps = steps.slice().sort((a, b) => a.orderIndex - b.orderIndex);
449
+ const lineageRows = [];
450
+ for (const step of sortedSteps) {
451
+ const meta = isObject(step.metadataJson) ? step.metadataJson : {};
452
+ const captures = Array.isArray(meta.variablesSet) ? meta.variablesSet : [];
453
+ const startedMs = isoToMs(step.startedAt);
454
+ for (const c of captures) {
455
+ if (!isObject(c)) continue;
456
+ lineageRows.push({
457
+ name: c.name ?? c.key ?? null,
458
+ value: c.value ?? null,
459
+ definedAtStepId: step.id,
460
+ definedAtNodeId: step.nodeId,
461
+ definedAtOrderIndex: step.orderIndex,
462
+ definedAtTimestampMs: startedMs
463
+ });
464
+ }
465
+ }
466
+ await writeJsonl(
467
+ resolveWorkspacePath(workspaceRoot, WORKSPACE_PATHS.variablesLineage),
468
+ lineageRows
469
+ );
470
+ };
471
+ var writeRecentRuns = async (workspaceRoot, runs) => {
472
+ const rows = runs.map((r) => ({
473
+ testRunId: r.id,
474
+ workflowRunId: r.workflowRunId,
475
+ status: r.status,
476
+ startedAt: r.startedAt,
477
+ finishedAt: r.finishedAt,
478
+ startedAtMs: isoToMs(r.startedAt),
479
+ finishedAtMs: isoToMs(r.finishedAt),
480
+ errorMessage: r.errorMessage
481
+ }));
482
+ await writeJsonl(
483
+ resolveWorkspacePath(workspaceRoot, WORKSPACE_PATHS.historyRecentRuns),
484
+ rows
485
+ );
486
+ };
487
+
488
+ // ../diagnostic-workspace/src/workflow-writer.ts
489
+ import * as fs4 from "fs/promises";
490
+ var writeWorkflowDefinition = async (input) => {
491
+ const sortedNodes = input.nodes.slice().sort((a, b) => a.orderIndex - b.orderIndex);
492
+ const definition = {
493
+ workflowId: input.workflowId,
494
+ name: input.workflowName,
495
+ nodes: sortedNodes.map((n) => ({
496
+ id: n.id,
497
+ nodeType: n.nodeType,
498
+ orderIndex: n.orderIndex,
499
+ summary: n.summary
500
+ })),
501
+ edges: input.edges.map((e) => ({
502
+ id: e.id,
503
+ source: e.source,
504
+ target: e.target
505
+ }))
506
+ };
507
+ await fs4.writeFile(
508
+ resolveWorkspacePath(input.workspaceRoot, WORKSPACE_PATHS.workflowDefinition),
509
+ `${JSON.stringify(definition, null, 2)}
510
+ `,
511
+ "utf-8"
512
+ );
513
+ const snapshot = {
514
+ workflowId: input.workflowId,
515
+ name: input.workflowName,
516
+ nodes: sortedNodes.map((n) => ({
517
+ id: n.id,
518
+ nodeType: n.nodeType,
519
+ orderIndex: n.orderIndex,
520
+ configJson: n.configJson
521
+ })),
522
+ edges: input.edges.map((e) => ({ id: e.id, source: e.source, target: e.target }))
523
+ };
524
+ await fs4.writeFile(
525
+ resolveWorkspacePath(input.workspaceRoot, WORKSPACE_PATHS.workflowSnapshot),
526
+ `${JSON.stringify(snapshot, null, 2)}
527
+ `,
528
+ "utf-8"
529
+ );
530
+ await Promise.all(
531
+ sortedNodes.map((node) => {
532
+ const filePath = resolveWorkspacePath(
533
+ input.workspaceRoot,
534
+ workflowNodeRelativePath(node.id)
535
+ );
536
+ const body = {
537
+ id: node.id,
538
+ nodeType: node.nodeType,
539
+ orderIndex: node.orderIndex,
540
+ summary: node.summary,
541
+ configJson: node.configJson
542
+ };
543
+ return fs4.writeFile(filePath, `${JSON.stringify(body, null, 2)}
544
+ `, "utf-8");
545
+ })
546
+ );
547
+ };
548
+
549
+ // ../diagnostic-workspace/src/sentry-writer.ts
550
+ import * as fs5 from "fs/promises";
551
+ var writeJsonlWithSentinel = async (absolutePath, partial, rows) => {
552
+ const lines = [];
553
+ if (partial) lines.push(JSON.stringify(partial));
554
+ for (const r of rows) lines.push(JSON.stringify(r));
555
+ await fs5.writeFile(
556
+ absolutePath,
557
+ lines.length === 0 ? "" : `${lines.join("\n")}
558
+ `,
559
+ "utf-8"
560
+ );
561
+ };
562
+ var writeSentryLogsAndSpans = async (input) => {
563
+ await writeJsonlWithSentinel(
564
+ resolveWorkspacePath(input.workspaceRoot, WORKSPACE_PATHS.logsSentry),
565
+ input.logs.partial,
566
+ input.logs.rows
567
+ );
568
+ await writeJsonlWithSentinel(
569
+ resolveWorkspacePath(input.workspaceRoot, WORKSPACE_PATHS.logsSentrySpans),
570
+ input.spans.partial,
571
+ input.spans.spans
572
+ );
573
+ return Boolean(input.logs.partial || input.spans.partial);
574
+ };
575
+
576
+ // ../diagnostic-workspace/src/trace-extractor.ts
577
+ import * as fs6 from "fs/promises";
578
+ var writeTrace = async (input) => {
579
+ if (!input.traceZipPath) {
580
+ await writePartialMarker(input.workspaceRoot, "no-trace");
581
+ return true;
582
+ }
583
+ const destTraceZip = resolveWorkspacePath(input.workspaceRoot, WORKSPACE_PATHS.browserTraceZip);
584
+ try {
585
+ await fs6.copyFile(input.traceZipPath, destTraceZip);
586
+ } catch {
587
+ await writePartialMarker(input.workspaceRoot, "trace-copy-failed");
588
+ return true;
589
+ }
590
+ let actions;
591
+ try {
592
+ actions = parseTraceActions(input.traceZipPath);
593
+ } catch {
594
+ await writePartialMarker(input.workspaceRoot, "trace-parse-failed");
595
+ return true;
596
+ }
597
+ await writeActionsJsonl(input.workspaceRoot, actions, input.runStartedAtMs);
598
+ return reconstructAndWriteArtifacts({
599
+ workspaceRoot: input.workspaceRoot,
600
+ tracePath: input.traceZipPath,
601
+ actions,
602
+ runStartedAtMs: input.runStartedAtMs
603
+ });
604
+ };
605
+ var writePartialMarker = async (workspaceRoot, reason) => {
606
+ await fs6.writeFile(
607
+ resolveWorkspacePath(workspaceRoot, WORKSPACE_PATHS.browserActions),
608
+ `${JSON.stringify({ partial: true, reason })}
609
+ `,
610
+ "utf-8"
611
+ );
612
+ };
613
+ var reconstructAndWriteArtifacts = async (input) => {
614
+ const traceBase = input.actions.length > 0 ? input.actions[0].startTime : 0;
615
+ const computeAbsoluteTs = (action) => {
616
+ if (input.runStartedAtMs === null) return 0;
617
+ return input.runStartedAtMs + (action.startTime - traceBase);
618
+ };
619
+ let results;
620
+ try {
621
+ results = await reconstructSnapshots({
622
+ traceZipPath: input.tracePath,
623
+ filter: "after",
624
+ includeScreenshots: true,
625
+ includeHtml: true,
626
+ raw: false
627
+ });
628
+ } catch {
629
+ return true;
630
+ }
631
+ const byActionIndex = /* @__PURE__ */ new Map();
632
+ for (const result of results) {
633
+ if (!byActionIndex.has(result.actionIndex)) {
634
+ byActionIndex.set(result.actionIndex, result);
635
+ }
636
+ }
637
+ const domsDir = resolveWorkspacePath(input.workspaceRoot, WORKSPACE_PATHS.browserDoms);
638
+ const framesDir = resolveWorkspacePath(input.workspaceRoot, WORKSPACE_PATHS.browserFrames);
639
+ const a11yDir = resolveWorkspacePath(input.workspaceRoot, WORKSPACE_PATHS.browserA11y);
640
+ const writeAction = async (i) => {
641
+ const action = input.actions[i];
642
+ const result = byActionIndex.get(i);
643
+ if (!result) return false;
644
+ const tsMs = computeAbsoluteTs(action);
645
+ try {
646
+ await Promise.all([
647
+ result.html ? fs6.writeFile(
648
+ `${domsDir}/${actionArtifactBasename(i, tsMs, "html")}`,
649
+ result.html,
650
+ "utf-8"
651
+ ) : Promise.resolve(),
652
+ result.screenshotBuffer ? fs6.writeFile(
653
+ `${framesDir}/${actionArtifactBasename(i, tsMs, "png")}`,
654
+ result.screenshotBuffer
655
+ ) : Promise.resolve(),
656
+ result.yaml ? fs6.writeFile(
657
+ `${a11yDir}/${actionArtifactBasename(i, tsMs, "yaml")}`,
658
+ result.yaml,
659
+ "utf-8"
660
+ ) : Promise.resolve()
661
+ ]);
662
+ return true;
663
+ } catch {
664
+ return false;
665
+ }
666
+ };
667
+ const indexes = Array.from({ length: input.actions.length }, (_, i) => i);
668
+ const missingResults = indexes.filter((i) => !byActionIndex.has(i)).length;
669
+ const writeOutcomes = await Promise.all(indexes.map((i) => writeAction(i)));
670
+ const writeFailures = writeOutcomes.filter((ok) => !ok).length;
671
+ return missingResults > 0 || writeFailures > 0;
672
+ };
673
+ var writeActionsJsonl = async (workspaceRoot, actions, runStartedAtMs) => {
674
+ const traceBase = actions.length > 0 ? actions[0].startTime : 0;
675
+ const lines = actions.map((a, idx) => ({
676
+ actionIndex: idx,
677
+ callId: a.callId,
678
+ title: a.title,
679
+ startTimeRelativeMs: a.startTime - traceBase,
680
+ endTimeRelativeMs: a.endTime - traceBase,
681
+ timestampMs: runStartedAtMs !== null ? runStartedAtMs + (a.startTime - traceBase) : null,
682
+ params: a.params ?? null,
683
+ beforeSnapshot: a.beforeSnapshot ?? null,
684
+ afterSnapshot: a.afterSnapshot ?? null,
685
+ inputSnapshot: a.inputSnapshot ?? null,
686
+ pageId: a.pageId,
687
+ error: a.error ?? null,
688
+ point: a.point ?? null
689
+ }));
690
+ await fs6.writeFile(
691
+ resolveWorkspacePath(workspaceRoot, WORKSPACE_PATHS.browserActions),
692
+ lines.length === 0 ? "" : `${lines.map((l) => JSON.stringify(l)).join("\n")}
693
+ `,
694
+ "utf-8"
695
+ );
696
+ };
697
+
698
+ // ../diagnostic-workspace/src/ledger-builder.ts
699
+ import * as fs7 from "fs/promises";
700
+ var writeLedger = async (input) => {
701
+ const baselineMs = input.runStartedAt ? Date.parse(input.runStartedAt) : null;
702
+ const events = [];
703
+ for (const step of input.steps) {
704
+ events.push({ kind: "step", step, timestampMs: step.startedAtMs });
705
+ }
706
+ for (const thought of input.thoughts) {
707
+ events.push({ kind: "thought", thought, stepId: thought.stepId });
708
+ }
709
+ for (const action of input.actions) {
710
+ events.push({ kind: "action", action });
711
+ }
712
+ for (const nav of input.navigation) {
713
+ events.push({ kind: "nav", nav });
714
+ }
715
+ for (const net of input.network) {
716
+ events.push({ kind: "network", net });
717
+ }
718
+ for (const con of input.consoleLogs) {
719
+ events.push({ kind: "console", con });
720
+ }
721
+ for (const assertion of input.assertions) {
722
+ events.push({ kind: "assertion", assertion });
723
+ }
724
+ events.sort((a, b) => {
725
+ const ta = eventTimestamp(a);
726
+ const tb = eventTimestamp(b);
727
+ if (ta === null && tb === null) return 0;
728
+ if (ta === null) return 1;
729
+ if (tb === null) return -1;
730
+ if (ta !== tb) return ta - tb;
731
+ const ra = eventRank(a);
732
+ const rb = eventRank(b);
733
+ return ra - rb;
734
+ });
735
+ const lines = [];
736
+ const indexEntries = [];
737
+ lines.push(`# Run Ledger \u2014 runId: ${input.runId} \u2014 workflow: ${input.workflowName} \u2014 status: ${input.runStatus}`);
738
+ if (baselineMs !== null) {
739
+ lines.push(`runStartedAt: ${input.runStartedAt} (all T+ values are relative to this)`);
740
+ } else {
741
+ lines.push(`runStartedAt: (unknown \u2014 relative timestamps unavailable)`);
742
+ }
743
+ lines.push("");
744
+ if (input.runStatus === "failed" && input.reportedFailure.failedStepName) {
745
+ const ordinalPart = input.reportedFailure.failedStepOrderIndex !== null ? ` (step ${input.reportedFailure.failedStepOrderIndex})` : "";
746
+ lines.push(`## \u26A0 Reported failure`);
747
+ lines.push(`Step${ordinalPart}: **${input.reportedFailure.failedStepName}**`);
748
+ if (input.reportedFailure.errorMessage) {
749
+ lines.push("");
750
+ lines.push("```");
751
+ lines.push(input.reportedFailure.errorMessage);
752
+ lines.push("```");
753
+ }
754
+ lines.push("");
755
+ lines.push("**Verify before trusting \u2014 root cause may be upstream.**");
756
+ lines.push("");
757
+ lines.push("---");
758
+ lines.push("");
759
+ }
760
+ for (const event of events) {
761
+ const ts = eventTimestamp(event);
762
+ const prefix = formatPrefix(ts, baselineMs);
763
+ if (event.kind === "step") {
764
+ const s = event.step;
765
+ const meta = [
766
+ `status: ${s.status}`,
767
+ s.durationMs !== null ? `dur ${s.durationMs}ms` : null,
768
+ s.cacheOutcome ? `cache: ${s.cacheOutcome}${s.cacheHitSource ? `/${s.cacheHitSource}` : ""}` : null
769
+ ].filter((x) => x !== null).join(", ");
770
+ const heading = `## ${prefix} Step ${s.orderIndex}: ${s.name ?? s.nodeId} (${meta})`;
771
+ if (lines.length > 0 && lines[lines.length - 1] !== "") lines.push("");
772
+ indexEntries.push({
773
+ orderIndex: s.orderIndex,
774
+ name: s.name,
775
+ line: lines.length + 1
776
+ // 1-indexed
777
+ });
778
+ lines.push(heading);
779
+ if (s.errorMessage) {
780
+ lines.push(`${prefix} step.error: ${oneLine(s.errorMessage)}`);
781
+ }
782
+ continue;
783
+ }
784
+ if (event.kind === "thought") {
785
+ const t = event.thought;
786
+ const tool = t.toolName ? ` [${t.toolName}]` : "";
787
+ lines.push(`${prefix} thought${tool}: ${oneLine(t.content)}`);
788
+ continue;
789
+ }
790
+ if (event.kind === "action") {
791
+ const a = event.action;
792
+ const target = a.target ? ` ${oneLine(a.target)}` : "";
793
+ const url = a.url ? ` \u2192 ${a.url}` : "";
794
+ const status = a.success ? "" : " (failed)";
795
+ const annotation = a.isAnnotation ? " [annotation]" : "";
796
+ lines.push(`${prefix} action.${a.action}${annotation}:${target}${url}${status}`);
797
+ continue;
798
+ }
799
+ if (event.kind === "nav") {
800
+ const n = event.nav;
801
+ const cross = n.crossHost ? " \u26A0 cross-host" : "";
802
+ lines.push(`${prefix} nav.${n.action}: ${n.from ?? "?"} \u2192 ${n.to ?? "?"}${cross}`);
803
+ continue;
804
+ }
805
+ if (event.kind === "network") {
806
+ const n = event.net;
807
+ const status = n.status !== null ? ` ${n.status}` : "";
808
+ lines.push(`${prefix} network: ${n.method} ${n.url}${status}`);
809
+ continue;
810
+ }
811
+ if (event.kind === "console") {
812
+ const c = event.con;
813
+ lines.push(`${prefix} console.${c.type}: ${oneLine(c.text)}`);
814
+ continue;
815
+ }
816
+ if (event.kind === "assertion") {
817
+ const a = event.assertion;
818
+ const tag = a.passed ? "assertion.passed" : "assertion.failed";
819
+ const severity = a.severity ? ` [${a.severity}${a.nonBlocking ? " nonBlocking" : ""}]` : "";
820
+ const cond = a.condition ? oneLine(a.condition) : "(no condition)";
821
+ const reason = a.reason ? ` \u2014 ${oneLine(a.reason)}` : "";
822
+ lines.push(`${prefix} ${tag}${severity}: ${cond}${reason}`);
823
+ continue;
824
+ }
825
+ }
826
+ if (lines[lines.length - 1] !== "") lines.push("");
827
+ await fs7.writeFile(
828
+ resolveWorkspacePath(input.workspaceRoot, WORKSPACE_PATHS.ledger),
829
+ `${lines.join("\n")}`,
830
+ "utf-8"
831
+ );
832
+ const indexLines = [];
833
+ indexLines.push(`# Ledger Index \u2014 runId: ${input.runId}`);
834
+ indexLines.push("");
835
+ indexLines.push("Use `bash(\"sed -n '<a>,<b>p' ledger.md\")` to read a step's window.");
836
+ indexLines.push("");
837
+ if (indexEntries.length === 0) {
838
+ indexLines.push("(no steps recorded for this run)");
839
+ } else {
840
+ for (let i = 0; i < indexEntries.length; i++) {
841
+ const entry = indexEntries[i];
842
+ const next = indexEntries[i + 1];
843
+ const startLine = entry.line;
844
+ const endLine = next ? next.line - 1 : lines.length;
845
+ const name = entry.name ?? "(unnamed step)";
846
+ indexLines.push(`Step ${entry.orderIndex}: ${name} \u2014 lines ${startLine}-${endLine}`);
847
+ }
848
+ }
849
+ indexLines.push("");
850
+ await fs7.writeFile(
851
+ resolveWorkspacePath(input.workspaceRoot, WORKSPACE_PATHS.ledgerIndex),
852
+ `${indexLines.join("\n")}`,
853
+ "utf-8"
854
+ );
855
+ };
856
+ var eventTimestamp = (e) => {
857
+ switch (e.kind) {
858
+ case "step":
859
+ return e.timestampMs;
860
+ case "thought":
861
+ return e.thought.timestampMs;
862
+ case "action":
863
+ return e.action.timestampMs;
864
+ case "nav":
865
+ return e.nav.timestampMs;
866
+ case "network":
867
+ return e.net.timestampMs;
868
+ case "console":
869
+ return e.con.timestampMs;
870
+ case "assertion":
871
+ return e.assertion.timestampMs;
872
+ }
873
+ };
874
+ var eventRank = (e) => {
875
+ switch (e.kind) {
876
+ case "step":
877
+ return 0;
878
+ case "nav":
879
+ return 1;
880
+ case "action":
881
+ return 2;
882
+ case "thought":
883
+ return 3;
884
+ case "network":
885
+ return 4;
886
+ case "console":
887
+ return 5;
888
+ case "assertion":
889
+ return 6;
890
+ }
891
+ };
892
+
893
+ // ../diagnostic-workspace/src/step-rollup-builder.ts
894
+ import * as fs8 from "fs/promises";
895
+ var writeStepRollups = async (input) => {
896
+ const baselineMs = input.runStartedAt ? Date.parse(input.runStartedAt) : null;
897
+ const sortedSteps = input.steps.slice().sort((a, b) => a.orderIndex - b.orderIndex);
898
+ const thoughtsByStepId = /* @__PURE__ */ new Map();
899
+ for (const t of input.thoughts) {
900
+ if (!t.stepId) continue;
901
+ const list = thoughtsByStepId.get(t.stepId) ?? [];
902
+ list.push(t);
903
+ thoughtsByStepId.set(t.stepId, list);
904
+ }
905
+ const assertionsByStepId = /* @__PURE__ */ new Map();
906
+ for (const a of input.assertions) {
907
+ const list = assertionsByStepId.get(a.stepId) ?? [];
908
+ list.push(a);
909
+ assertionsByStepId.set(a.stepId, list);
910
+ }
911
+ const bounds = computeStepBounds(sortedSteps);
912
+ const writes = [];
913
+ for (let i = 0; i < sortedSteps.length; i++) {
914
+ const step = sortedSteps[i];
915
+ const window = bounds[i];
916
+ const lines = [];
917
+ const startPrefix = formatPrefix(step.startedAtMs, baselineMs);
918
+ const finishPrefix = formatPrefix(step.finishedAtMs, baselineMs);
919
+ lines.push(
920
+ `# Step ${step.orderIndex}: ${step.name ?? step.nodeId}`
921
+ );
922
+ lines.push("");
923
+ lines.push(`- nodeId: \`${step.nodeId}\``);
924
+ if (step.nodeType) lines.push(`- nodeType: \`${step.nodeType}\``);
925
+ lines.push(`- status: **${step.status}**`);
926
+ lines.push(`- started: ${startPrefix}`);
927
+ lines.push(`- finished: ${finishPrefix}`);
928
+ if (step.durationMs !== null) lines.push(`- duration: ${step.durationMs}ms`);
929
+ if (step.cacheOutcome) {
930
+ const src = step.cacheHitSource ? `/${step.cacheHitSource}` : "";
931
+ lines.push(`- cache: ${step.cacheOutcome}${src}`);
932
+ }
933
+ if (step.errorMessage) {
934
+ lines.push("");
935
+ lines.push("## Error message");
936
+ lines.push("");
937
+ lines.push("```");
938
+ lines.push(step.errorMessage);
939
+ lines.push("```");
940
+ }
941
+ const stepThoughts = (thoughtsByStepId.get(step.id) ?? []).slice().sort(
942
+ (a, b) => a.timestampMs - b.timestampMs
943
+ );
944
+ if (stepThoughts.length > 0) {
945
+ lines.push("");
946
+ lines.push("## Agent thoughts");
947
+ lines.push("");
948
+ for (const t of stepThoughts) {
949
+ const tool = t.toolName ? ` [${t.toolName}]` : "";
950
+ lines.push(`${formatPrefix(t.timestampMs, baselineMs)} thought${tool}: ${oneLine(t.content)}`);
951
+ }
952
+ }
953
+ const stepAssertions = (assertionsByStepId.get(step.id) ?? []).slice();
954
+ if (stepAssertions.length > 0) {
955
+ lines.push("");
956
+ lines.push("## Assertions");
957
+ lines.push("");
958
+ for (const a of stepAssertions) {
959
+ const tag = a.passed ? "passed" : "FAILED";
960
+ const severity = a.severity ? ` [${a.severity}${a.nonBlocking ? " nonBlocking" : ""}]` : "";
961
+ const cond = a.condition ?? "(no condition)";
962
+ const reason = a.reason ? ` \u2014 ${oneLine(a.reason)}` : "";
963
+ lines.push(`- ${tag}${severity}: ${oneLine(cond)}${reason}`);
964
+ }
965
+ }
966
+ const inWindow = (ts) => {
967
+ if (ts === null) return false;
968
+ if (window.startMs !== null && ts < window.startMs) return false;
969
+ if (window.endMs !== null && ts >= window.endMs) return false;
970
+ return true;
971
+ };
972
+ const windowActions = input.actions.filter((a) => inWindow(a.timestampMs)).slice().sort(byTs);
973
+ if (windowActions.length > 0) {
974
+ lines.push("");
975
+ lines.push("## Action timeline (in step window)");
976
+ lines.push("");
977
+ for (const a of windowActions) {
978
+ const target = a.target ? ` ${oneLine(a.target)}` : "";
979
+ const url = a.url ? ` \u2192 ${a.url}` : "";
980
+ const fail = a.success ? "" : " (failed)";
981
+ lines.push(`${formatPrefix(a.timestampMs, baselineMs)} action.${a.action}:${target}${url}${fail}`);
982
+ }
983
+ }
984
+ const windowNav = input.navigation.filter((n) => inWindow(n.timestampMs)).slice().sort(byTs);
985
+ if (windowNav.length > 0) {
986
+ lines.push("");
987
+ lines.push("## Navigation (in step window)");
988
+ lines.push("");
989
+ for (const n of windowNav) {
990
+ const cross = n.crossHost ? " \u26A0 cross-host" : "";
991
+ lines.push(
992
+ `${formatPrefix(n.timestampMs, baselineMs)} nav.${n.action}: ${n.from ?? "?"} \u2192 ${n.to ?? "?"}${cross}`
993
+ );
994
+ }
995
+ }
996
+ const windowNet = input.network.filter((n) => inWindow(n.timestampMs)).slice().sort(byTs);
997
+ if (windowNet.length > 0) {
998
+ lines.push("");
999
+ lines.push("## Network (in step window)");
1000
+ lines.push("");
1001
+ for (const n of windowNet) {
1002
+ const status = n.status !== null ? ` ${n.status}` : "";
1003
+ lines.push(`${formatPrefix(n.timestampMs, baselineMs)} ${n.method} ${n.url}${status}`);
1004
+ }
1005
+ }
1006
+ const windowCon = input.consoleLogs.filter((c) => inWindow(c.timestampMs)).slice().sort(byTs);
1007
+ if (windowCon.length > 0) {
1008
+ lines.push("");
1009
+ lines.push("## Console (in step window)");
1010
+ lines.push("");
1011
+ for (const c of windowCon) {
1012
+ lines.push(`${formatPrefix(c.timestampMs, baselineMs)} console.${c.type}: ${oneLine(c.text)}`);
1013
+ }
1014
+ }
1015
+ lines.push("");
1016
+ lines.push("## Evidence files");
1017
+ lines.push("");
1018
+ lines.push(`- Thoughts: \`${thoughtsByStepRelativePath(step.id)}\``);
1019
+ lines.push(`- Workflow node: \`${workflowNodeRelativePath(step.nodeId)}\``);
1020
+ lines.push(
1021
+ `- Browser snapshots (if available): grep this step's timestamp in \`${WORKSPACE_PATHS.browserActions}\`, then \`browser/doms/...\` / \`browser/frames/...\` / \`browser/a11y/...\``
1022
+ );
1023
+ lines.push("");
1024
+ writes.push({
1025
+ relativePath: stepRollupRelativePath(step.orderIndex, step.id),
1026
+ body: lines.join("\n")
1027
+ });
1028
+ }
1029
+ await Promise.all(
1030
+ writes.map(
1031
+ ({ relativePath, body }) => fs8.writeFile(resolveWorkspacePath(input.workspaceRoot, relativePath), body, "utf-8")
1032
+ )
1033
+ );
1034
+ };
1035
+ var computeStepBounds = (sorted) => {
1036
+ const bounds = [];
1037
+ for (let i = 0; i < sorted.length; i++) {
1038
+ const step = sorted[i];
1039
+ const next = sorted[i + 1];
1040
+ const startMs = step.startedAtMs;
1041
+ let endMs = step.finishedAtMs;
1042
+ if (endMs === null && next?.startedAtMs !== void 0) endMs = next.startedAtMs;
1043
+ bounds.push({ startMs, endMs });
1044
+ }
1045
+ return bounds;
1046
+ };
1047
+ var byTs = (a, b) => {
1048
+ if (a.timestampMs === null && b.timestampMs === null) return 0;
1049
+ if (a.timestampMs === null) return 1;
1050
+ if (b.timestampMs === null) return -1;
1051
+ return a.timestampMs - b.timestampMs;
1052
+ };
1053
+
1054
+ // ../diagnostic-workspace/src/summary-builder.ts
1055
+ import * as fs9 from "fs/promises";
1056
+ var MAX_NOTABLE_EVENTS = 5;
1057
+ var MAX_HISTORY_LOOKBACK = 10;
1058
+ var isCleanPassStatus = (s) => s === "passed" || s === "success";
1059
+ var isFlakyPassStatus = (s) => s === "flaky_success";
1060
+ var isPassStatus = (s) => isCleanPassStatus(s) || isFlakyPassStatus(s);
1061
+ var isFailStatus = (s) => s === "failed" || s === "timeout" || s === "degraded";
1062
+ var classifyHistoryRegime = (others) => {
1063
+ const seq = others.map((r) => r.status).filter((s) => isPassStatus(s) || isFailStatus(s));
1064
+ if (seq.length < 2) return "NEW";
1065
+ const passes = seq.filter(isPassStatus).length;
1066
+ if (passes === 0) return "PERSISTENT_FAIL";
1067
+ const fails = seq.filter(isFailStatus).length;
1068
+ const hasFlaky = seq.some(isFlakyPassStatus);
1069
+ let cleanGreenStreak = 0;
1070
+ for (const s of seq) {
1071
+ if (isCleanPassStatus(s)) cleanGreenStreak++;
1072
+ else break;
1073
+ }
1074
+ if (fails === 0 && !hasFlaky || cleanGreenStreak >= 3) return "STABLE_REGRESSION";
1075
+ return "FLAKY";
1076
+ };
1077
+ var writeSummary = async (input) => {
1078
+ const baselineMs = input.runStartedAt ? Date.parse(input.runStartedAt) : null;
1079
+ const finishedMs = input.runFinishedAt ? Date.parse(input.runFinishedAt) : null;
1080
+ const durationMs = baselineMs !== null && finishedMs !== null ? finishedMs - baselineMs : null;
1081
+ const lines = [];
1082
+ lines.push(
1083
+ `# Run ${input.runId} \u2014 workflow "${input.workflowName}" \u2014 status: ${input.runStatus}`
1084
+ );
1085
+ const durationStr = durationMs !== null ? `${(durationMs / 1e3).toFixed(3)}s` : "unknown";
1086
+ lines.push(
1087
+ `runStartedAt: ${input.runStartedAt ?? "unknown"} duration: ${durationStr}`
1088
+ );
1089
+ lines.push("");
1090
+ if (input.runStatus === "failed") {
1091
+ lines.push("## Reported failure");
1092
+ if (input.reportedFailure.failedStepName) {
1093
+ const ordinal = input.reportedFailure.failedStepOrderIndex !== null ? ` (step ${input.reportedFailure.failedStepOrderIndex})` : "";
1094
+ const err = input.reportedFailure.errorMessage ? ` \u2014 ${oneLine(input.reportedFailure.errorMessage)}` : "";
1095
+ lines.push(
1096
+ `Step${ordinal}: **${input.reportedFailure.failedStepName}**${err}`
1097
+ );
1098
+ } else if (input.reportedFailure.errorMessage) {
1099
+ lines.push(`Run-level error: ${oneLine(input.reportedFailure.errorMessage)}`);
1100
+ } else {
1101
+ lines.push("(no failed step identified \u2014 investigate run-level state)");
1102
+ }
1103
+ lines.push("**Hypothesis. Verify before trusting \u2014 root cause may be upstream.**");
1104
+ lines.push("");
1105
+ }
1106
+ const sortedSteps = input.steps.slice().sort((a, b) => a.orderIndex - b.orderIndex);
1107
+ const counts = countByStatus(sortedSteps);
1108
+ const summaryLine = `${sortedSteps.length} total \u2014 ${formatCounts(counts)}`;
1109
+ lines.push(`## Steps (${summaryLine})`);
1110
+ const renderedSteps = sortedSteps.map((s) => formatStepRow(s, baselineMs));
1111
+ const visibleSteps = renderedSteps.length > 30 ? [
1112
+ ...renderedSteps.slice(0, 25),
1113
+ ` \u2026 (${renderedSteps.length - 30} more steps elided \u2014 see ledger.md)`,
1114
+ ...renderedSteps.slice(-5)
1115
+ ] : renderedSteps;
1116
+ for (const row of visibleSteps) lines.push(row);
1117
+ lines.push("");
1118
+ const networkErrors = input.network.filter(
1119
+ (n) => typeof n.status === "number" && n.status >= 400
1120
+ );
1121
+ const consoleErrors = input.consoleLogs.filter(
1122
+ (c) => c.type === "error" || c.type === "warning"
1123
+ );
1124
+ if (networkErrors.length > 0 || consoleErrors.length > 0) {
1125
+ lines.push("## Errors observed");
1126
+ const ne = networkErrors.length;
1127
+ const ce = consoleErrors.length;
1128
+ if (ne > 0) {
1129
+ const sample = networkErrors[0];
1130
+ lines.push(
1131
+ `- ${ne}\xD7 network ${sample.status ?? "?"}: ${sample.method} ${sample.url}${sample.timestampMs !== null ? ` ${formatRelativePrefix(sample.timestampMs, baselineMs)}` : ""}${ne > 1 ? ` (+${ne - 1} more \u2014 see logs/network-errors.jsonl)` : ""}`
1132
+ );
1133
+ }
1134
+ if (ce > 0) {
1135
+ const sample = consoleErrors[0];
1136
+ lines.push(
1137
+ `- ${ce}\xD7 console.${sample.type}: ${truncate(oneLine(sample.text), 100)}${sample.timestampMs !== null ? ` ${formatRelativePrefix(sample.timestampMs, baselineMs)}` : ""}${ce > 1 ? ` (+${ce - 1} more \u2014 see logs/console-errors.jsonl)` : ""}`
1138
+ );
1139
+ }
1140
+ lines.push("");
1141
+ }
1142
+ const notables = [];
1143
+ const crossHost = input.navigation.filter((n) => n.crossHost);
1144
+ for (const n of crossHost.slice(0, MAX_NOTABLE_EVENTS)) {
1145
+ notables.push(
1146
+ `- cross-host nav: ${n.from ?? "?"} \u2192 ${n.to ?? "?"}${n.timestampMs !== null ? ` ${formatRelativePrefix(n.timestampMs, baselineMs)}` : ""}`
1147
+ );
1148
+ }
1149
+ const failedStep = sortedSteps.find((s) => s.status === "failed");
1150
+ if (failedStep && failedStep.cacheOutcome) {
1151
+ notables.push(
1152
+ `- failed step cache outcome: ${failedStep.cacheOutcome}${failedStep.cacheHitSource ? `/${failedStep.cacheHitSource}` : ""}`
1153
+ );
1154
+ }
1155
+ if (notables.length > 0) {
1156
+ lines.push("## Notable events");
1157
+ for (const n of notables) lines.push(n);
1158
+ lines.push("");
1159
+ }
1160
+ const historyHint = buildHistoryHint(
1161
+ input.recentRuns,
1162
+ input.runId,
1163
+ input.lastGreenComparison ?? null
1164
+ );
1165
+ if (historyHint.length > 0) {
1166
+ lines.push("## History");
1167
+ for (const h of historyHint) lines.push(h);
1168
+ lines.push("");
1169
+ }
1170
+ lines.push("## Drill-down");
1171
+ const failedRollup = input.reportedFailure.failedStepId && failedStep ? stepRollupRelativePath(failedStep.orderIndex, failedStep.id) : null;
1172
+ if (failedRollup) {
1173
+ lines.push(`- Failed step rollup: \`${failedRollup}\``);
1174
+ }
1175
+ lines.push(`- Per-step rollups: \`${WORKSPACE_PATHS.steps}/*.md\` (ls steps/ for the full list)`);
1176
+ lines.push(`- Full ledger TOC: \`${WORKSPACE_PATHS.ledgerIndex}\` (read before windowing into ledger.md)`);
1177
+ lines.push(`- Screenshots: \`${WORKSPACE_PATHS.browserFrames}/<NNNN>-...png\` (read with vision)`);
1178
+ lines.push(`- Workflow nodes: \`${WORKSPACE_PATHS.workflowNodes}/<nodeId>.json\``);
1179
+ lines.push("");
1180
+ await fs9.writeFile(
1181
+ resolveWorkspacePath(input.workspaceRoot, WORKSPACE_PATHS.summary),
1182
+ lines.join("\n"),
1183
+ "utf-8"
1184
+ );
1185
+ };
1186
+ var STATUS_GLYPH = {
1187
+ success: "\u2713",
1188
+ passed: "\u2713",
1189
+ failed: "\u2717",
1190
+ skipped: "-",
1191
+ pending: "\xB7",
1192
+ running: "\u22EF",
1193
+ waiting: "\u22EF",
1194
+ canceled: "\u2298"
1195
+ };
1196
+ var formatStepRow = (s, baselineMs) => {
1197
+ const glyph = STATUS_GLYPH[s.status] ?? "?";
1198
+ const ord = String(s.orderIndex).padStart(3, " ");
1199
+ const tplus = s.startedAtMs !== null && baselineMs !== null ? formatRelative(s.startedAtMs - baselineMs).padStart(11, " ") : " ?";
1200
+ const name = s.name ?? "(unnamed)";
1201
+ const namePadded = truncate(name, 35).padEnd(35, " ");
1202
+ const dur = s.status === "failed" ? `FAILED${s.errorMessage ? ` \u2014 ${truncate(oneLine(s.errorMessage), 40)}` : ""}` : s.status === "skipped" ? "skipped" : s.durationMs !== null ? `${s.durationMs}ms` : "?";
1203
+ const cache = s.cacheOutcome ? ` cache: ${s.cacheOutcome}${s.cacheHitSource ? `/${s.cacheHitSource}` : ""}` : "";
1204
+ return ` ${ord} ${glyph} ${tplus} ${namePadded} ${dur}${cache}`;
1205
+ };
1206
+ var countByStatus = (steps) => {
1207
+ const m = /* @__PURE__ */ new Map();
1208
+ for (const s of steps) m.set(s.status, (m.get(s.status) ?? 0) + 1);
1209
+ return m;
1210
+ };
1211
+ var formatCounts = (counts) => {
1212
+ const order = ["success", "passed", "failed", "skipped", "pending", "running", "waiting", "canceled"];
1213
+ const parts = [];
1214
+ const seen = /* @__PURE__ */ new Set();
1215
+ for (const key of order) {
1216
+ if (counts.has(key)) {
1217
+ const count = counts.get(key);
1218
+ const emphasis = key === "failed" && count > 0 ? `**${count} ${key.toUpperCase()}**` : `${count} ${key}`;
1219
+ parts.push(emphasis);
1220
+ seen.add(key);
1221
+ }
1222
+ }
1223
+ for (const [k, v] of counts) {
1224
+ if (!seen.has(k)) parts.push(`${v} ${k}`);
1225
+ }
1226
+ return parts.join(", ");
1227
+ };
1228
+ var buildHistoryHint = (runs, currentRunId, lastGreenComparison) => {
1229
+ const lookback = runs.slice(0, MAX_HISTORY_LOOKBACK);
1230
+ if (lookback.length <= 1) return [];
1231
+ const others = lookback.filter((r) => r.workflowRunId !== currentRunId);
1232
+ if (others.length === 0) return [];
1233
+ const passed = others.filter((r) => isPassStatus(r.status)).length;
1234
+ const failed = others.filter((r) => isFailStatus(r.status)).length;
1235
+ const lastGreen = others.find((r) => isPassStatus(r.status));
1236
+ const regime = classifyHistoryRegime(others);
1237
+ const out = [];
1238
+ out.push(
1239
+ `${passed} of last ${others.length} ran passed; ${failed} failed. Regime: ${regime}.`
1240
+ );
1241
+ if (lastGreen) {
1242
+ out.push(
1243
+ `Most recent green: testRunId=${lastGreen.testRunId}${lastGreen.startedAt ? ` (${lastGreen.startedAt.slice(0, 10)})` : ""}`
1244
+ );
1245
+ const greenRunId = lastGreen.workflowRunId ?? lastGreen.testRunId;
1246
+ out.push(
1247
+ `Comparison is REQUIRED \u2014 materialize via: canary workflow debug materialize ${greenRunId} --out history/last-green/`
1248
+ );
1249
+ }
1250
+ const authoredUnchanged = lastGreenComparison?.authoredUnchanged ?? null;
1251
+ const greenDate = lastGreen?.startedAt ? ` (${lastGreen.startedAt.slice(0, 10)})` : "";
1252
+ if (regime === "STABLE_REGRESSION" && lastGreen) {
1253
+ if (authoredUnchanged === true) {
1254
+ out.push(
1255
+ `AUTHORED TEST UNCHANGED since last green${greenDate} \u2014 the authored workflow is byte-identical across this pass\u2192fail boundary, so this CANNOT be test_underspecified. A pass\u2192fail here means APP BEHAVIOR CHANGED: classify app_changed (or software_bug if the delta is clearly a defect), name the concrete behavior delta, and note in openQuestions that intent could not be verified from the sandbox.`
1256
+ );
1257
+ } else if (authoredUnchanged === false) {
1258
+ out.push(
1259
+ `AUTHORED TEST CHANGED since last green${greenDate} \u2014 the test definition was edited. Compare to judge whether the new instructions are ambiguous (test_underspecified) before blaming the app.`
1260
+ );
1261
+ } else {
1262
+ out.push(
1263
+ `Stably green before this break \u2014 comparison REQUIRED. If the authored workflow is unchanged vs the green run, a pass\u2192fail means APP BEHAVIOR CHANGED (app_changed), not the test.`
1264
+ );
1265
+ }
1266
+ } else if (regime === "FLAKY") {
1267
+ out.push(
1268
+ `This test is FLAKY (pass/fail oscillated over the window) \u2014 a single green\u2192red does NOT imply an app change. Weigh agent_confusion / intermittent dependency_issue / data_collision. Comparison may still help, but do not force an app_changed verdict without a clear, persistent behavior delta.`
1269
+ );
1270
+ }
1271
+ return out;
1272
+ };
1273
+ var formatRelativePrefix = (timestampMs, baselineMs) => baselineMs !== null ? `[${formatRelative(timestampMs - baselineMs)}]` : "[T+?]";
1274
+
1275
+ // ../diagnostic-workspace/src/assemble-workspace.ts
1276
+ var assembleWorkspace = async (input) => {
1277
+ const { runData, workspaceRoot, traceZipPath } = input;
1278
+ await fs10.mkdir(workspaceRoot, { recursive: true, mode: 448 });
1279
+ for (const dir of WORKSPACE_DIRS) {
1280
+ await fs10.mkdir(resolveWorkspacePath(workspaceRoot, dir), { recursive: true, mode: 448 });
1281
+ }
1282
+ let partial = runData.partial;
1283
+ await writeReportedFailure({
1284
+ workspaceRoot,
1285
+ runStatus: runData.status,
1286
+ failedStepName: runData.failedStepName,
1287
+ failedStepOrderIndex: runData.failedStepOrderIndex,
1288
+ errorMessage: runData.errorMessage
1289
+ });
1290
+ await Promise.all([
1291
+ writeTimelineSteps(workspaceRoot, runData.steps),
1292
+ writeTimelineActionsAndNavigation(workspaceRoot, runData.timeline),
1293
+ writeAssertionsAndCacheDecisions(workspaceRoot, runData.steps),
1294
+ writeThoughts(workspaceRoot, runData.thoughts),
1295
+ writeLogs(workspaceRoot, runData.networkLogs, runData.consoleLogs),
1296
+ writeVariables(workspaceRoot, runData.metadataJson, runData.steps),
1297
+ writeRecentRuns(workspaceRoot, recentRunsToWriterShape(runData.recentRuns)),
1298
+ writeWorkflowDefinition({
1299
+ workspaceRoot,
1300
+ workflowId: runData.workflowId,
1301
+ workflowName: runData.workflowName,
1302
+ nodes: runData.nodes,
1303
+ edges: runData.edges
1304
+ })
1305
+ ]);
1306
+ const sentryPartial = await writeSentryLogsAndSpans({
1307
+ workspaceRoot,
1308
+ logs: runData.sentryLogs,
1309
+ spans: runData.sentrySpans
1310
+ });
1311
+ if (sentryPartial) partial = true;
1312
+ const tracePartial = await writeTrace({
1313
+ workspaceRoot,
1314
+ traceZipPath,
1315
+ runStartedAtMs: runData.startedAt ? Date.parse(runData.startedAt) : null
1316
+ });
1317
+ if (tracePartial) partial = true;
1318
+ const eventProjection = projectEvents(runData);
1319
+ await writeLedger({
1320
+ workspaceRoot,
1321
+ runId: runData.runId,
1322
+ workflowId: runData.workflowId,
1323
+ workflowName: runData.workflowName,
1324
+ runStatus: runData.status,
1325
+ runStartedAt: runData.startedAt,
1326
+ reportedFailure: {
1327
+ failedStepName: runData.failedStepName,
1328
+ failedStepOrderIndex: runData.failedStepOrderIndex,
1329
+ errorMessage: runData.errorMessage
1330
+ },
1331
+ steps: eventProjection.steps,
1332
+ thoughts: eventProjection.thoughts,
1333
+ actions: eventProjection.actions,
1334
+ navigation: eventProjection.navigation,
1335
+ network: eventProjection.network,
1336
+ consoleLogs: eventProjection.consoleLogs,
1337
+ assertions: eventProjection.assertions
1338
+ });
1339
+ await writeStepRollups({
1340
+ workspaceRoot,
1341
+ runStartedAt: runData.startedAt,
1342
+ steps: eventProjection.steps,
1343
+ thoughts: eventProjection.thoughts,
1344
+ actions: eventProjection.actions,
1345
+ navigation: eventProjection.navigation,
1346
+ network: eventProjection.network,
1347
+ consoleLogs: eventProjection.consoleLogs,
1348
+ assertions: eventProjection.assertions
1349
+ });
1350
+ await writeSummary({
1351
+ workspaceRoot,
1352
+ runId: runData.runId,
1353
+ workflowName: runData.workflowName,
1354
+ runStatus: runData.status,
1355
+ runStartedAt: runData.startedAt,
1356
+ runFinishedAt: runData.finishedAt,
1357
+ reportedFailure: {
1358
+ failedStepId: runData.failedStepId,
1359
+ failedStepName: runData.failedStepName,
1360
+ failedStepOrderIndex: runData.failedStepOrderIndex,
1361
+ errorMessage: runData.errorMessage
1362
+ },
1363
+ steps: eventProjection.steps.map((s) => ({
1364
+ id: s.id,
1365
+ orderIndex: s.orderIndex,
1366
+ name: s.name,
1367
+ status: s.status,
1368
+ startedAtMs: s.startedAtMs,
1369
+ durationMs: s.durationMs,
1370
+ cacheOutcome: s.cacheOutcome,
1371
+ cacheHitSource: s.cacheHitSource,
1372
+ errorMessage: s.errorMessage
1373
+ })),
1374
+ network: eventProjection.network,
1375
+ consoleLogs: eventProjection.consoleLogs,
1376
+ navigation: eventProjection.navigation,
1377
+ recentRuns: runData.recentRuns,
1378
+ lastGreenComparison: runData.lastGreenComparison
1379
+ });
1380
+ await writeManifest({
1381
+ workspaceRoot,
1382
+ runId: runData.runId,
1383
+ workflowId: runData.workflowId,
1384
+ orgId: runData.orgId,
1385
+ status: runData.status,
1386
+ startedAt: runData.startedAt,
1387
+ finishedAt: runData.finishedAt,
1388
+ errorMessage: runData.errorMessage,
1389
+ workflowName: runData.workflowName,
1390
+ failedStepId: runData.failedStepId,
1391
+ failedNodeId: runData.failedNodeId,
1392
+ failedStepName: runData.failedStepName,
1393
+ traceStorageKey: runData.traceStorageKey,
1394
+ diagnosticsStorageKey: runData.diagnosticsStorageKey,
1395
+ videoStorageKey: runData.videoStorageKey,
1396
+ partial
1397
+ });
1398
+ return {
1399
+ root: workspaceRoot,
1400
+ runId: runData.runId,
1401
+ orgId: runData.orgId,
1402
+ materializedAt: (/* @__PURE__ */ new Date()).toISOString(),
1403
+ runStartedAt: runData.startedAt
1404
+ };
1405
+ };
1406
+ var isPlainObject = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
1407
+ var stringField = (v) => typeof v === "string" && v.length > 0 ? v : null;
1408
+ var normalizeTs = (ts) => {
1409
+ if (ts === null || ts === void 0) return null;
1410
+ if (typeof ts === "number") return ts;
1411
+ const parsed = Date.parse(ts);
1412
+ return Number.isFinite(parsed) ? parsed : null;
1413
+ };
1414
+ var projectEvents = (runData) => {
1415
+ const baselineMs = runData.timeline.startTimestamp ? Date.parse(runData.timeline.startTimestamp) : null;
1416
+ const steps = runData.steps.map((s) => {
1417
+ const meta = isPlainObject(s.metadataJson) ? s.metadataJson : {};
1418
+ const startedAtMs = s.startedAt ? Date.parse(s.startedAt) : null;
1419
+ const finishedAtMs = s.finishedAt ? Date.parse(s.finishedAt) : null;
1420
+ return {
1421
+ id: s.id,
1422
+ nodeId: s.nodeId,
1423
+ orderIndex: s.orderIndex,
1424
+ name: s.nodeName,
1425
+ nodeType: s.nodeType,
1426
+ status: s.status,
1427
+ startedAtMs,
1428
+ finishedAtMs,
1429
+ durationMs: startedAtMs !== null && finishedAtMs !== null ? finishedAtMs - startedAtMs : null,
1430
+ errorMessage: s.errorMessage,
1431
+ cacheOutcome: stringField(meta.cacheOutcome),
1432
+ cacheHitSource: stringField(meta.cacheHitSource)
1433
+ };
1434
+ });
1435
+ const thoughts = runData.thoughts.map((t) => ({
1436
+ stepId: t.stepId,
1437
+ timestampMs: Date.parse(t.createdAt),
1438
+ toolName: t.toolName,
1439
+ content: t.content
1440
+ }));
1441
+ const actions = runData.timeline.entries.map((e) => ({
1442
+ action: e.action,
1443
+ target: e.target ?? null,
1444
+ url: e.url ?? null,
1445
+ timestampMs: baselineMs !== null ? baselineMs + e.timestampMs : null,
1446
+ success: e.success,
1447
+ isAnnotation: e.isAnnotation ?? false
1448
+ }));
1449
+ const navigation = [];
1450
+ let prevUrl = null;
1451
+ for (const a of actions) {
1452
+ const isNav = NAVIGATION_ACTIONS.has(a.action);
1453
+ const urlChanged = a.url !== null && prevUrl !== null && a.url !== prevUrl;
1454
+ if (!isNav && !urlChanged) {
1455
+ if (a.url) prevUrl = a.url;
1456
+ continue;
1457
+ }
1458
+ navigation.push({
1459
+ timestampMs: a.timestampMs,
1460
+ action: a.action,
1461
+ from: prevUrl,
1462
+ to: a.url,
1463
+ crossHost: hostOf(prevUrl) !== null && hostOf(a.url) !== null && hostOf(prevUrl) !== hostOf(a.url)
1464
+ });
1465
+ if (a.url) prevUrl = a.url;
1466
+ }
1467
+ const network = runData.networkLogs.map((n) => ({
1468
+ timestampMs: normalizeTs(n.timestamp ?? null),
1469
+ url: n.url,
1470
+ method: n.method,
1471
+ status: n.status ?? null
1472
+ }));
1473
+ const consoleLogs = runData.consoleLogs.map((c) => ({
1474
+ timestampMs: normalizeTs(c.timestamp),
1475
+ type: c.type,
1476
+ text: c.text
1477
+ }));
1478
+ const assertions = [];
1479
+ for (const s of runData.steps) {
1480
+ const meta = isPlainObject(s.metadataJson) ? s.metadataJson : {};
1481
+ const raw = Array.isArray(meta.assertionResults) ? meta.assertionResults : [];
1482
+ for (const r of raw) {
1483
+ if (!isPlainObject(r)) continue;
1484
+ assertions.push({
1485
+ stepId: s.id,
1486
+ timestampMs: s.startedAt ? Date.parse(s.startedAt) : null,
1487
+ condition: stringField(r.condition),
1488
+ severity: stringField(r.severity),
1489
+ nonBlocking: Boolean(r.nonBlocking),
1490
+ passed: Boolean(r.passed),
1491
+ reason: stringField(r.reason)
1492
+ });
1493
+ }
1494
+ }
1495
+ return { steps, thoughts, actions, navigation, network, consoleLogs, assertions };
1496
+ };
1497
+ var recentRunsToWriterShape = (runs) => runs.map((r) => ({
1498
+ id: r.testRunId,
1499
+ workflowRunId: r.workflowRunId,
1500
+ status: r.status,
1501
+ startedAt: r.startedAt,
1502
+ finishedAt: r.finishedAt,
1503
+ errorMessage: r.errorMessage
1504
+ }));
1505
+ export {
1506
+ WORKSPACE_DIRS,
1507
+ WORKSPACE_PATHS,
1508
+ assembleWorkspace,
1509
+ classifyHistoryRegime,
1510
+ resolveWorkspacePath,
1511
+ writeLedger,
1512
+ writeManifest,
1513
+ writeStepRollups,
1514
+ writeSummary
1515
+ };
1516
+ //# sourceMappingURL=src-LB4HBTJQ.js.map