@shipfox/client-workflows 16.0.0 → 17.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/.turbo/turbo-type.log +1 -0
  3. package/CHANGELOG.md +20 -0
  4. package/dist/components/identifier/identifier.js +2 -2
  5. package/dist/components/identifier/identifier.js.map +1 -1
  6. package/dist/components/job-detail/agent-config-failure-callout.d.ts.map +1 -1
  7. package/dist/components/job-detail/agent-config-failure-callout.js +1 -1
  8. package/dist/components/job-detail/agent-config-failure-callout.js.map +1 -1
  9. package/dist/components/job-detail/job-context-panel.d.ts +6 -0
  10. package/dist/components/job-detail/job-context-panel.d.ts.map +1 -0
  11. package/dist/components/job-detail/job-context-panel.js +224 -0
  12. package/dist/components/job-detail/job-context-panel.js.map +1 -0
  13. package/dist/components/job-detail/job-detail-header.d.ts +3 -1
  14. package/dist/components/job-detail/job-detail-header.d.ts.map +1 -1
  15. package/dist/components/job-detail/job-detail-header.js +54 -48
  16. package/dist/components/job-detail/job-detail-header.js.map +1 -1
  17. package/dist/components/job-detail/job-detail-view.d.ts +1 -1
  18. package/dist/components/job-detail/job-detail-view.d.ts.map +1 -1
  19. package/dist/components/job-detail/job-detail-view.js +80 -44
  20. package/dist/components/job-detail/job-detail-view.js.map +1 -1
  21. package/dist/components/job-detail/job-empty-states.d.ts.map +1 -1
  22. package/dist/components/job-detail/job-empty-states.js +19 -10
  23. package/dist/components/job-detail/job-empty-states.js.map +1 -1
  24. package/dist/components/job-detail/job-execution-switcher.js +4 -4
  25. package/dist/components/job-detail/job-execution-switcher.js.map +1 -1
  26. package/dist/components/job-detail/json-code.d.ts +14 -0
  27. package/dist/components/job-detail/json-code.d.ts.map +1 -0
  28. package/dist/components/job-detail/json-code.js +93 -0
  29. package/dist/components/job-detail/json-code.js.map +1 -0
  30. package/dist/components/job-detail/step-attempt-log-panel.d.ts.map +1 -1
  31. package/dist/components/job-detail/step-attempt-log-panel.js +9 -6
  32. package/dist/components/job-detail/step-attempt-log-panel.js.map +1 -1
  33. package/dist/components/job-detail/step-troubleshooting.d.ts +18 -0
  34. package/dist/components/job-detail/step-troubleshooting.d.ts.map +1 -0
  35. package/dist/components/job-detail/step-troubleshooting.js +493 -0
  36. package/dist/components/job-detail/step-troubleshooting.js.map +1 -0
  37. package/dist/components/job-graph/job-graph-content.d.ts.map +1 -1
  38. package/dist/components/job-graph/job-graph-content.js +5 -4
  39. package/dist/components/job-graph/job-graph-content.js.map +1 -1
  40. package/dist/components/job-graph/job-node.js +3 -3
  41. package/dist/components/job-graph/job-node.js.map +1 -1
  42. package/dist/components/step-list/index.d.ts +1 -0
  43. package/dist/components/step-list/index.d.ts.map +1 -1
  44. package/dist/components/step-list/index.js.map +1 -1
  45. package/dist/components/step-list/step-list-model.d.ts.map +1 -1
  46. package/dist/components/step-list/step-list-model.js +5 -0
  47. package/dist/components/step-list/step-list-model.js.map +1 -1
  48. package/dist/components/step-list/step-list.d.ts +5 -1
  49. package/dist/components/step-list/step-list.d.ts.map +1 -1
  50. package/dist/components/step-list/step-list.js +117 -82
  51. package/dist/components/step-list/step-list.js.map +1 -1
  52. package/dist/components/workflow-run-duration-label.js +1 -1
  53. package/dist/components/workflow-run-duration-label.js.map +1 -1
  54. package/dist/components/workflow-run-list/job-status-strip.js +6 -6
  55. package/dist/components/workflow-run-list/job-status-strip.js.map +1 -1
  56. package/dist/components/workflow-run-list/workflow-run-filter-menu.js +1 -1
  57. package/dist/components/workflow-run-list/workflow-run-filter-menu.js.map +1 -1
  58. package/dist/components/workflow-run-list/workflow-run-filters.js +4 -4
  59. package/dist/components/workflow-run-list/workflow-run-filters.js.map +1 -1
  60. package/dist/components/workflow-run-list/workflow-run-list-states.js +6 -6
  61. package/dist/components/workflow-run-list/workflow-run-list-states.js.map +1 -1
  62. package/dist/components/workflow-run-list/workflow-run-list-view.js +1 -1
  63. package/dist/components/workflow-run-list/workflow-run-list-view.js.map +1 -1
  64. package/dist/components/workflow-run-list/workflow-run-row.js +7 -7
  65. package/dist/components/workflow-run-list/workflow-run-row.js.map +1 -1
  66. package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.js +1 -1
  67. package/dist/components/workflow-run-summary/workflow-run-attempt-switcher.js.map +1 -1
  68. package/dist/components/workflow-run-summary/workflow-run-summary.d.ts +0 -1
  69. package/dist/components/workflow-run-summary/workflow-run-summary.d.ts.map +1 -1
  70. package/dist/components/workflow-run-summary/workflow-run-summary.js +8 -13
  71. package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
  72. package/dist/components/workflow-run-tabs/index.d.ts +1 -1
  73. package/dist/components/workflow-run-tabs/index.d.ts.map +1 -1
  74. package/dist/components/workflow-run-tabs/index.js.map +1 -1
  75. package/dist/components/workflow-run-tabs/run-annotation-count-chip.js +2 -2
  76. package/dist/components/workflow-run-tabs/run-annotation-count-chip.js.map +1 -1
  77. package/dist/components/workflow-run-tabs/run-annotation-list.d.ts +9 -2
  78. package/dist/components/workflow-run-tabs/run-annotation-list.d.ts.map +1 -1
  79. package/dist/components/workflow-run-tabs/run-annotation-list.js +28 -19
  80. package/dist/components/workflow-run-tabs/run-annotation-list.js.map +1 -1
  81. package/dist/components/workflow-run-tabs/run-annotation-summary-line.d.ts.map +1 -1
  82. package/dist/components/workflow-run-tabs/run-annotation-summary-line.js +5 -5
  83. package/dist/components/workflow-run-tabs/run-annotation-summary-line.js.map +1 -1
  84. package/dist/components/workflow-run-view/run-workspace-nav.js +7 -7
  85. package/dist/components/workflow-run-view/run-workspace-nav.js.map +1 -1
  86. package/dist/components/workflow-run-view/workflow-run-states.js +6 -6
  87. package/dist/components/workflow-run-view/workflow-run-states.js.map +1 -1
  88. package/dist/components/workflow-run-view/workflow-run-view.d.ts.map +1 -1
  89. package/dist/components/workflow-run-view/workflow-run-view.js +72 -12
  90. package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
  91. package/dist/core/entities/job-execution.d.ts +7 -0
  92. package/dist/core/entities/job-execution.d.ts.map +1 -1
  93. package/dist/core/entities/job-execution.js.map +1 -1
  94. package/dist/core/entities/job.d.ts +9 -0
  95. package/dist/core/entities/job.d.ts.map +1 -1
  96. package/dist/core/entities/job.js.map +1 -1
  97. package/dist/core/entities/step-attempt.d.ts +29 -0
  98. package/dist/core/entities/step-attempt.d.ts.map +1 -1
  99. package/dist/core/entities/step-attempt.js.map +1 -1
  100. package/dist/core/entities/step.d.ts +3 -1
  101. package/dist/core/entities/step.d.ts.map +1 -1
  102. package/dist/core/entities/step.js.map +1 -1
  103. package/dist/core/run-annotation.d.ts +6 -0
  104. package/dist/core/run-annotation.d.ts.map +1 -1
  105. package/dist/core/run-annotation.js.map +1 -1
  106. package/dist/core/workflow-run.d.ts +1 -1
  107. package/dist/core/workflow-run.d.ts.map +1 -1
  108. package/dist/core/workflow-run.js.map +1 -1
  109. package/dist/hooks/api/annotations.d.ts +63 -0
  110. package/dist/hooks/api/annotations.d.ts.map +1 -0
  111. package/dist/hooks/api/annotations.js +145 -0
  112. package/dist/hooks/api/annotations.js.map +1 -0
  113. package/dist/hooks/api/step-attempt-detail.d.ts +14 -0
  114. package/dist/hooks/api/step-attempt-detail.d.ts.map +1 -0
  115. package/dist/hooks/api/step-attempt-detail.js +43 -0
  116. package/dist/hooks/api/step-attempt-detail.js.map +1 -0
  117. package/dist/hooks/api/workflow-run-mapper.d.ts +9 -2
  118. package/dist/hooks/api/workflow-run-mapper.d.ts.map +1 -1
  119. package/dist/hooks/api/workflow-run-mapper.js +47 -0
  120. package/dist/hooks/api/workflow-run-mapper.js.map +1 -1
  121. package/dist/pages/project-workflows-page.js +19 -19
  122. package/dist/pages/project-workflows-page.js.map +1 -1
  123. package/dist/pages/workflow-run-list-page.js +1 -1
  124. package/dist/pages/workflow-run-list-page.js.map +1 -1
  125. package/dist/tsconfig.test.tsbuildinfo +1 -1
  126. package/package.json +10 -10
  127. package/src/components/identifier/identifier.tsx +2 -2
  128. package/src/components/job-detail/agent-config-failure-callout.tsx +5 -1
  129. package/src/components/job-detail/job-context-panel.test.tsx +72 -0
  130. package/src/components/job-detail/job-context-panel.tsx +237 -0
  131. package/src/components/job-detail/job-detail-header.tsx +52 -46
  132. package/src/components/job-detail/job-detail-view.stories.tsx +555 -53
  133. package/src/components/job-detail/job-detail-view.tsx +87 -45
  134. package/src/components/job-detail/job-empty-states.tsx +23 -10
  135. package/src/components/job-detail/job-execution-switcher.tsx +5 -5
  136. package/src/components/job-detail/json-code.tsx +120 -0
  137. package/src/components/job-detail/step-attempt-log-panel.test.tsx +1 -0
  138. package/src/components/job-detail/step-attempt-log-panel.tsx +17 -6
  139. package/src/components/job-detail/step-troubleshooting.stories.tsx +120 -0
  140. package/src/components/job-detail/step-troubleshooting.test.tsx +337 -0
  141. package/src/components/job-detail/step-troubleshooting.tsx +537 -0
  142. package/src/components/job-graph/job-graph-content.tsx +4 -3
  143. package/src/components/job-graph/job-node.tsx +3 -3
  144. package/src/components/step-list/index.ts +1 -0
  145. package/src/components/step-list/step-list-model.ts +5 -0
  146. package/src/components/step-list/step-list.test.tsx +75 -2
  147. package/src/components/step-list/step-list.tsx +73 -20
  148. package/src/components/workflow-run-duration-label.tsx +1 -1
  149. package/src/components/workflow-run-list/job-status-strip.tsx +6 -6
  150. package/src/components/workflow-run-list/workflow-run-filter-menu.tsx +1 -1
  151. package/src/components/workflow-run-list/workflow-run-filters.tsx +4 -4
  152. package/src/components/workflow-run-list/workflow-run-list-states.tsx +6 -6
  153. package/src/components/workflow-run-list/workflow-run-list-view.tsx +1 -1
  154. package/src/components/workflow-run-list/workflow-run-row.tsx +7 -7
  155. package/src/components/workflow-run-summary/workflow-run-attempt-switcher.tsx +1 -1
  156. package/src/components/workflow-run-summary/workflow-run-summary.test.tsx +1 -1
  157. package/src/components/workflow-run-summary/workflow-run-summary.tsx +11 -11
  158. package/src/components/workflow-run-tabs/index.ts +5 -1
  159. package/src/components/workflow-run-tabs/run-annotation-count-chip.tsx +2 -2
  160. package/src/components/workflow-run-tabs/run-annotation-list.tsx +25 -10
  161. package/src/components/workflow-run-tabs/run-annotation-summary-line.tsx +5 -5
  162. package/src/components/workflow-run-view/run-workspace-nav.tsx +7 -7
  163. package/src/components/workflow-run-view/workflow-run-states.tsx +6 -6
  164. package/src/components/workflow-run-view/workflow-run-view.tsx +114 -14
  165. package/src/core/entities/job-execution.ts +7 -0
  166. package/src/core/entities/job.ts +9 -0
  167. package/src/core/entities/step-attempt.ts +33 -0
  168. package/src/core/entities/step.ts +3 -1
  169. package/src/core/run-annotation.ts +6 -0
  170. package/src/core/workflow-run.ts +4 -0
  171. package/src/hooks/api/annotations.test.ts +84 -0
  172. package/src/hooks/api/annotations.ts +240 -0
  173. package/src/hooks/api/step-attempt-detail.ts +67 -0
  174. package/src/hooks/api/workflow-run-mapper.ts +46 -0
  175. package/src/hooks/api/workflow-runs.test.tsx +61 -1
  176. package/src/pages/project-workflows-page.tsx +19 -19
  177. package/src/pages/workflow-job-detail-page.test.tsx +52 -1
  178. package/src/pages/workflow-run-list-page.tsx +1 -1
  179. package/test/fixtures/workflow-run.ts +7 -0
  180. package/tsconfig.build.tsbuildinfo +1 -1
@@ -0,0 +1,493 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Button } from '@shipfox/react-ui/button';
3
+ import { Callout, CalloutContent, CalloutDescription, CalloutTitle } from '@shipfox/react-ui/callout';
4
+ import { Sheet, SheetBody, SheetContent, SheetDescription, SheetHeader, SheetTitle } from '@shipfox/react-ui/sheet';
5
+ import { Skeleton } from '@shipfox/react-ui/skeleton';
6
+ import { Code, Text } from '@shipfox/react-ui/typography';
7
+ import { cn } from '@shipfox/react-ui/utils';
8
+ import { Link } from '@tanstack/react-router';
9
+ import { useStepAttemptDetailQuery } from '#hooks/api/step-attempt-detail.js';
10
+ import { workflowRunSearchParams } from '#routes/inputs.js';
11
+ import { humanizeStatus } from '../step-list/step-list-model.js';
12
+ import { AgentConfigFailureCallout } from './agent-config-failure-callout.js';
13
+ import { toSelectedAttemptError } from './job-empty-states.js';
14
+ import { JsonCode, JsonCodeTabs } from './json-code.js';
15
+ export function StepInspectorSheet({ entry, open, onOpenChange, workspaceSlug, projectSlug, workflowRunId, runAttempt, jobId, annotationCount }) {
16
+ const error = selectedStepError(entry.step, entry.error);
17
+ const inspectorQuery = useStepAttemptDetailQuery(entry.step.id, entry.attempt, {
18
+ enabled: open
19
+ });
20
+ return /*#__PURE__*/ _jsx(Sheet, {
21
+ open: open,
22
+ onOpenChange: onOpenChange,
23
+ children: /*#__PURE__*/ _jsxs(SheetContent, {
24
+ side: "right",
25
+ className: "w-full sm:max-w-[560px]",
26
+ children: [
27
+ /*#__PURE__*/ _jsxs(SheetHeader, {
28
+ children: [
29
+ /*#__PURE__*/ _jsx(SheetTitle, {
30
+ children: entry.step.label
31
+ }),
32
+ /*#__PURE__*/ _jsxs(SheetDescription, {
33
+ children: [
34
+ "Attempt #",
35
+ entry.attempt,
36
+ " · ",
37
+ humanizeStatus(entry.statusVisual.kind)
38
+ ]
39
+ })
40
+ ]
41
+ }),
42
+ /*#__PURE__*/ _jsx(SheetBody, {
43
+ className: "gap-section",
44
+ children: /*#__PURE__*/ _jsx(StepInspector, {
45
+ step: entry.step,
46
+ attempt: entry,
47
+ error: error,
48
+ showFailure: entry.statusVisual.kind === 'failed' || entry.error !== null,
49
+ query: inspectorQuery,
50
+ workspaceSlug: workspaceSlug,
51
+ projectSlug: projectSlug,
52
+ workflowRunId: workflowRunId,
53
+ runAttempt: runAttempt,
54
+ jobId: jobId,
55
+ annotationCount: annotationCount
56
+ })
57
+ })
58
+ ]
59
+ })
60
+ });
61
+ }
62
+ function StepFailureCallout({ step, attempt, error, workspaceSlug, projectSlug, workflowRunId, runAttempt }) {
63
+ const reason = error?.reason ?? step.statusReason ?? 'unknown';
64
+ const title = failureTitle(reason);
65
+ const sourceLink = sourceLinkForFailure(reason) && step.sourceLocation;
66
+ if (step.type === 'agent' && reason === 'agent_config_invalid') {
67
+ return /*#__PURE__*/ _jsx(AgentConfigFailureCallout, {
68
+ workspaceSlug: workspaceSlug,
69
+ config: step.agentConfig,
70
+ error: error
71
+ });
72
+ }
73
+ return /*#__PURE__*/ _jsx(Callout, {
74
+ role: "alert",
75
+ type: "error",
76
+ variant: "secondary",
77
+ className: "rounded-8 border border-tag-error-border p-panel-compact shadow-none",
78
+ children: /*#__PURE__*/ _jsxs(CalloutContent, {
79
+ children: [
80
+ /*#__PURE__*/ _jsx(CalloutTitle, {
81
+ children: title
82
+ }),
83
+ /*#__PURE__*/ _jsx(CalloutDescription, {
84
+ children: /*#__PURE__*/ _jsxs("div", {
85
+ className: "flex min-w-0 flex-wrap items-center gap-x-inline gap-y-tight",
86
+ children: [
87
+ /*#__PURE__*/ _jsxs("div", {
88
+ className: "flex min-w-0 flex-col gap-tight",
89
+ children: [
90
+ /*#__PURE__*/ _jsx("span", {
91
+ children: failureDescription(reason)
92
+ }),
93
+ error?.message ? /*#__PURE__*/ _jsx("span", {
94
+ className: "text-foreground-neutral-muted",
95
+ children: error.message
96
+ }) : null
97
+ ]
98
+ }),
99
+ /*#__PURE__*/ _jsx(Code, {
100
+ as: "span",
101
+ variant: "label",
102
+ className: "text-tag-error-text",
103
+ children: reason
104
+ }),
105
+ sourceLink ? /*#__PURE__*/ _jsx(Link, {
106
+ to: "/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId",
107
+ params: {
108
+ workspaceSlug,
109
+ projectSlug,
110
+ workflowRunId
111
+ },
112
+ search: workflowRunSearchParams({
113
+ tab: 'source'
114
+ }, {
115
+ stepId: step.id,
116
+ stepAttemptId: attempt.id,
117
+ runAttempt
118
+ }),
119
+ className: "font-medium text-foreground-highlight-interactive underline-offset-2 hover:underline",
120
+ children: "View in source"
121
+ }) : null
122
+ ]
123
+ })
124
+ })
125
+ ]
126
+ })
127
+ });
128
+ }
129
+ function StepInspector({ step, attempt, error, showFailure, query, workspaceSlug, projectSlug, workflowRunId, runAttempt, jobId, annotationCount }) {
130
+ const detail = query.data;
131
+ const trace = detail?.evaluationTrace ?? null;
132
+ const resolvedConfig = detail?.config ?? null;
133
+ const hasInputs = detail !== undefined && (countConfigValues(detail.authoredConfig) > 0 || countConfigValues(resolvedConfig) > 0);
134
+ const hasOutputs = attempt.outputs !== null || attempt.output !== null || attempt.response !== null;
135
+ const hasTrace = trace !== null && trace.length > 0;
136
+ const hasAnnotations = annotationCount !== undefined && annotationCount > 0;
137
+ const detailCount = Number(hasInputs) + Number(hasOutputs) + Number(hasTrace);
138
+ return /*#__PURE__*/ _jsxs("div", {
139
+ className: "flex min-w-0 flex-col gap-section",
140
+ children: [
141
+ showFailure ? /*#__PURE__*/ _jsx(StepFailureCallout, {
142
+ step: step,
143
+ attempt: attempt,
144
+ error: error,
145
+ workspaceSlug: workspaceSlug,
146
+ projectSlug: projectSlug,
147
+ workflowRunId: workflowRunId,
148
+ runAttempt: runAttempt
149
+ }) : null,
150
+ query.isPending ? /*#__PURE__*/ _jsx(InspectorLoading, {}) : null,
151
+ query.isError ? /*#__PURE__*/ _jsx(Callout, {
152
+ role: "alert",
153
+ type: "warning",
154
+ variant: "secondary",
155
+ className: "rounded-8 border border-tag-warning-border p-panel-compact shadow-none",
156
+ children: /*#__PURE__*/ _jsxs(CalloutContent, {
157
+ children: [
158
+ /*#__PURE__*/ _jsx(CalloutTitle, {
159
+ children: "Details unavailable"
160
+ }),
161
+ /*#__PURE__*/ _jsxs(CalloutDescription, {
162
+ className: "flex items-center justify-between gap-inline",
163
+ children: [
164
+ /*#__PURE__*/ _jsx("span", {
165
+ children: "We could not load the resolved configuration for this attempt."
166
+ }),
167
+ /*#__PURE__*/ _jsx(Button, {
168
+ type: "button",
169
+ size: "2xs",
170
+ variant: "secondary",
171
+ onClick: ()=>void query.refetch(),
172
+ children: "Retry"
173
+ })
174
+ ]
175
+ })
176
+ ]
177
+ })
178
+ }) : null,
179
+ detail ? /*#__PURE__*/ _jsxs("div", {
180
+ className: "flex min-w-0 flex-col gap-group",
181
+ children: [
182
+ hasInputs ? /*#__PURE__*/ _jsx(InspectorSection, {
183
+ title: "Inputs",
184
+ children: /*#__PURE__*/ _jsx(ConfigCode, {
185
+ authoredConfig: detail.authoredConfig,
186
+ resolvedConfig: resolvedConfig
187
+ })
188
+ }) : null,
189
+ hasOutputs ? /*#__PURE__*/ _jsxs(InspectorSection, {
190
+ title: "Outputs",
191
+ children: [
192
+ attempt.outputs !== null || attempt.output !== null ? /*#__PURE__*/ _jsx(JsonCode, {
193
+ value: attempt.outputs ?? attempt.output ?? {},
194
+ emptyMessage: "No outputs declared; the `outputs:` mapping is empty."
195
+ }) : null,
196
+ attempt.response !== null ? /*#__PURE__*/ _jsxs("div", {
197
+ className: "flex min-w-0 flex-col gap-tight",
198
+ children: [
199
+ /*#__PURE__*/ _jsx(Text, {
200
+ size: "xs",
201
+ className: "text-foreground-neutral-muted",
202
+ children: "Response"
203
+ }),
204
+ /*#__PURE__*/ _jsx("pre", {
205
+ className: "max-h-160 min-w-0 overflow-auto rounded-6 border border-border-neutral-base bg-background-neutral-subtle p-tight font-code text-xs leading-18 text-foreground-neutral-muted scrollbar",
206
+ children: attempt.response
207
+ })
208
+ ]
209
+ }) : null
210
+ ]
211
+ }) : null,
212
+ hasTrace ? /*#__PURE__*/ _jsx(InspectorSection, {
213
+ title: "Evaluation",
214
+ children: /*#__PURE__*/ _jsx(EvaluationTrace, {
215
+ trace: trace ?? []
216
+ })
217
+ }) : null,
218
+ detailCount === 0 && !showFailure && !hasAnnotations ? /*#__PURE__*/ _jsx(EmptyInspector, {}) : null
219
+ ]
220
+ }) : null,
221
+ hasAnnotations ? /*#__PURE__*/ _jsxs(Link, {
222
+ to: "/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId",
223
+ params: {
224
+ workspaceSlug,
225
+ projectSlug,
226
+ workflowRunId
227
+ },
228
+ search: workflowRunSearchParams({
229
+ tab: 'annotations'
230
+ }, {
231
+ jobId,
232
+ runAttempt
233
+ }),
234
+ className: "inline-flex w-fit rounded-4 text-xs text-foreground-highlight-interactive underline-offset-2 hover:underline focus-visible:shadow-button-neutral-focus",
235
+ children: [
236
+ "View ",
237
+ annotationCount,
238
+ " annotation",
239
+ annotationCount === 1 ? '' : 's'
240
+ ]
241
+ }) : null,
242
+ !query.isPending && !query.isError && !detail && !showFailure && !hasAnnotations ? /*#__PURE__*/ _jsx(EmptyInspector, {}) : null
243
+ ]
244
+ });
245
+ }
246
+ function InspectorSection({ title, children }) {
247
+ return /*#__PURE__*/ _jsxs("section", {
248
+ className: "flex min-w-0 flex-col gap-inline",
249
+ "aria-label": title,
250
+ children: [
251
+ /*#__PURE__*/ _jsx(Text, {
252
+ size: "xs",
253
+ bold: true,
254
+ className: "text-foreground-neutral-base",
255
+ children: title
256
+ }),
257
+ children
258
+ ]
259
+ });
260
+ }
261
+ function ConfigCode({ authoredConfig, resolvedConfig }) {
262
+ const entries = [
263
+ ...authoredConfig ? [
264
+ {
265
+ filename: 'authored.json',
266
+ label: 'Authored configuration',
267
+ value: authoredConfig
268
+ }
269
+ ] : [],
270
+ ...resolvedConfig ? [
271
+ {
272
+ filename: 'resolved.json',
273
+ label: 'Resolved configuration',
274
+ value: resolvedConfig
275
+ }
276
+ ] : []
277
+ ];
278
+ if (entries.length === 0) return null;
279
+ return /*#__PURE__*/ _jsx(JsonCodeTabs, {
280
+ entries: entries
281
+ });
282
+ }
283
+ export function EvaluationTrace({ trace }) {
284
+ const keyCounts = new Map();
285
+ return /*#__PURE__*/ _jsx("dl", {
286
+ className: "flex min-w-0 flex-col divide-y divide-border-neutral-base rounded-6 border border-border-neutral-base",
287
+ children: trace.map((entry)=>{
288
+ if ('dropped' in entry) {
289
+ const keyBase = `limit-${entry.dropped}`;
290
+ const occurrence = keyCounts.get(keyBase) ?? 0;
291
+ keyCounts.set(keyBase, occurrence + 1);
292
+ return /*#__PURE__*/ _jsxs("div", {
293
+ className: "px-row py-row text-xs text-foreground-neutral-muted",
294
+ children: [
295
+ entry.dropped,
296
+ " more evaluation",
297
+ entry.dropped === 1 ? '' : 's',
298
+ " not recorded"
299
+ ]
300
+ }, `${keyBase}-${occurrence}`);
301
+ }
302
+ const empty = entry.value === undefined || entry.value === '';
303
+ const keyBase = `evaluation-${entry.field}-${entry.expression}-${entry.evaluatedAt}-${entry.fillTarget}`;
304
+ const occurrence = keyCounts.get(keyBase) ?? 0;
305
+ keyCounts.set(keyBase, occurrence + 1);
306
+ return /*#__PURE__*/ _jsxs("div", {
307
+ className: cn('grid min-w-0 grid-cols-1 gap-inline px-row py-row min-[768px]:grid-cols-[160px_minmax(0,1fr)]', entry.degraded && 'border-l border-tag-error-icon'),
308
+ children: [
309
+ /*#__PURE__*/ _jsxs("dt", {
310
+ className: "flex min-w-0 flex-col gap-tight font-code text-xs text-foreground-neutral-muted",
311
+ title: entry.field,
312
+ children: [
313
+ /*#__PURE__*/ _jsx("span", {
314
+ className: "block truncate",
315
+ children: entry.field
316
+ }),
317
+ /*#__PURE__*/ _jsx("span", {
318
+ className: "block break-all text-foreground-neutral-subtle",
319
+ children: entry.expression
320
+ })
321
+ ]
322
+ }),
323
+ /*#__PURE__*/ _jsxs("dd", {
324
+ className: "flex min-w-0 flex-col gap-tight text-xs text-foreground-neutral-base",
325
+ children: [
326
+ entry.degraded ? /*#__PURE__*/ _jsx("span", {
327
+ className: "sr-only",
328
+ children: "Degraded evaluation"
329
+ }) : null,
330
+ /*#__PURE__*/ _jsx("div", {
331
+ className: "break-words font-code",
332
+ children: empty ? /*#__PURE__*/ _jsx("span", {
333
+ className: "text-tag-error-text",
334
+ children: "(empty)"
335
+ }) : entry.value
336
+ }),
337
+ /*#__PURE__*/ _jsxs("div", {
338
+ className: "flex min-w-0 flex-wrap gap-x-inline gap-y-tight text-foreground-neutral-muted",
339
+ children: [
340
+ entry.degraded ? /*#__PURE__*/ _jsx("span", {
341
+ className: "text-tag-error-text",
342
+ children: "degraded"
343
+ }) : null,
344
+ entry.truncated || entry.exprTruncated ? /*#__PURE__*/ _jsx("span", {
345
+ children: "truncated"
346
+ }) : null
347
+ ]
348
+ })
349
+ ]
350
+ })
351
+ ]
352
+ }, `${keyBase}-${occurrence}`);
353
+ })
354
+ });
355
+ }
356
+ function InspectorLoading() {
357
+ return /*#__PURE__*/ _jsxs("div", {
358
+ role: "status",
359
+ "aria-label": "Loading troubleshooting details",
360
+ className: "flex flex-col gap-inline",
361
+ children: [
362
+ /*#__PURE__*/ _jsx(Skeleton, {
363
+ className: "h-16 w-120"
364
+ }),
365
+ /*#__PURE__*/ _jsx(Skeleton, {
366
+ className: "h-120 w-full"
367
+ })
368
+ ]
369
+ });
370
+ }
371
+ function EmptyInspector() {
372
+ return /*#__PURE__*/ _jsx(Text, {
373
+ size: "xs",
374
+ className: "text-foreground-neutral-muted",
375
+ children: "No additional troubleshooting details were recorded."
376
+ });
377
+ }
378
+ function selectedStepError(step, attemptError) {
379
+ return toSelectedAttemptError(step, attemptError) ?? step.error;
380
+ }
381
+ function failureTitle(reason) {
382
+ switch(reason){
383
+ case 'checkout_failed':
384
+ return 'Checkout failed';
385
+ case 'checkout_auth_failed':
386
+ return 'Checkout authentication failed';
387
+ case 'checkout_unavailable':
388
+ return 'Checkout service unavailable';
389
+ case 'checkout_path_invalid':
390
+ return 'Checkout path is invalid';
391
+ case 'checkout_destination_occupied':
392
+ return 'Checkout destination is already occupied';
393
+ case 'git_unavailable':
394
+ return 'Git was unavailable';
395
+ case 'workspace_prep_failed':
396
+ return 'Workspace preparation failed';
397
+ case 'setup_aborted':
398
+ return 'Step setup was aborted';
399
+ case 'config_unresolvable':
400
+ return 'Step configuration could not be resolved';
401
+ case 'output_invalid':
402
+ return 'Step output was invalid';
403
+ case 'agent_config_invalid':
404
+ return 'Agent configuration is invalid';
405
+ case 'agent_invocation_failed':
406
+ return 'Agent invocation failed';
407
+ case 'agent_harness_unavailable':
408
+ return 'Agent harness was unavailable';
409
+ case 'runner_lost':
410
+ return 'Runner stopped responding';
411
+ case 'timed_out':
412
+ return 'Step timed out';
413
+ case 'step_failed':
414
+ return 'A step failed';
415
+ case 'dependency_not_completed':
416
+ return 'A dependency did not complete';
417
+ case 'condition_false':
418
+ return 'The job condition was false';
419
+ case 'default_gate_rejected':
420
+ return 'The default gate rejected this job';
421
+ case 'condition_rejected':
422
+ return 'The job condition rejected this job';
423
+ case 'condition_errored':
424
+ return 'The job condition could not be evaluated';
425
+ case 'user_cancelled':
426
+ return 'The job was cancelled by a user';
427
+ case 'run_cancelled':
428
+ return 'The run was cancelled';
429
+ case 'unknown':
430
+ return 'The failure reason was not recorded';
431
+ default:
432
+ return 'Step failed';
433
+ }
434
+ }
435
+ function failureDescription(reason) {
436
+ switch(reason){
437
+ case 'checkout_auth_failed':
438
+ return 'Checkout credentials were rejected. Verify repository access before re-running.';
439
+ case 'checkout_unavailable':
440
+ return 'The checkout service was unavailable. Retry after the service recovers.';
441
+ case 'git_unavailable':
442
+ return 'The runner could not start Git. Check the runner image before re-running.';
443
+ case 'workspace_prep_failed':
444
+ return 'The runner could not prepare its workspace. Review the runner setup details.';
445
+ case 'config_unresolvable':
446
+ return 'The resolved configuration contains a value that could not be evaluated.';
447
+ case 'output_invalid':
448
+ return 'The step returned output that did not match the declared contract.';
449
+ case 'agent_config_invalid':
450
+ return 'The agent configuration is not valid for this step.';
451
+ case 'agent_invocation_failed':
452
+ return 'The agent invocation failed after configuration was accepted.';
453
+ case 'agent_harness_unavailable':
454
+ return 'The runner could not start the agent harness.';
455
+ case 'runner_lost':
456
+ return 'The runner stopped responding before the step completed.';
457
+ case 'timed_out':
458
+ return 'The step exceeded its configured time limit.';
459
+ case 'dependency_not_completed':
460
+ return 'A required job did not complete, so this job could not start.';
461
+ case 'condition_false':
462
+ case 'condition_rejected':
463
+ return 'The job condition did not allow this job to run.';
464
+ case 'condition_errored':
465
+ return 'The job condition could not be evaluated.';
466
+ case 'default_gate_rejected':
467
+ return 'A required job did not succeed, so this job was not allowed to run.';
468
+ case 'step_failed':
469
+ return 'A step failed before this job could complete.';
470
+ case 'user_cancelled':
471
+ case 'run_cancelled':
472
+ return 'The run was cancelled before this work completed.';
473
+ case 'unknown':
474
+ return 'No machine-readable failure reason was recorded.';
475
+ default:
476
+ return `${humanize(reason)}. Review the details below and re-run after resolving the cause.`;
477
+ }
478
+ }
479
+ function sourceLinkForFailure(reason) {
480
+ return reason === 'config_unresolvable' || reason === 'agent_config_invalid' || reason === 'output_invalid' || reason === 'default_gate_rejected' || reason === 'condition_rejected' || reason === 'condition_errored';
481
+ }
482
+ function humanize(value) {
483
+ return value.replaceAll('_', ' ').replace(/\b\w/g, (letter)=>letter.toUpperCase());
484
+ }
485
+ function countConfigValues(value) {
486
+ if (Array.isArray(value)) return value.reduce((total, item)=>total + countConfigValues(item), 0);
487
+ if (value !== null && typeof value === 'object') {
488
+ return Object.values(value).reduce((total, item)=>total + countConfigValues(item), 0);
489
+ }
490
+ return value === undefined ? 0 : 1;
491
+ }
492
+
493
+ //# sourceMappingURL=step-troubleshooting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/components/job-detail/step-troubleshooting.tsx"],"sourcesContent":["import {Button} from '@shipfox/react-ui/button';\nimport {Callout, CalloutContent, CalloutDescription, CalloutTitle} from '@shipfox/react-ui/callout';\nimport {\n Sheet,\n SheetBody,\n SheetContent,\n SheetDescription,\n SheetHeader,\n SheetTitle,\n} from '@shipfox/react-ui/sheet';\nimport {Skeleton} from '@shipfox/react-ui/skeleton';\nimport {Code, Text} from '@shipfox/react-ui/typography';\nimport {cn} from '@shipfox/react-ui/utils';\nimport {Link} from '@tanstack/react-router';\nimport type {ReactNode} from 'react';\nimport type {\n EvaluationTraceEntry,\n JobStatusReason,\n Step,\n StepAttempt,\n StepError,\n} from '#core/workflow-run.js';\nimport {useStepAttemptDetailQuery} from '#hooks/api/step-attempt-detail.js';\nimport {workflowRunSearchParams} from '#routes/inputs.js';\nimport {humanizeStatus, type StepListEntryModel} from '../step-list/step-list-model.js';\nimport {AgentConfigFailureCallout} from './agent-config-failure-callout.js';\nimport {toSelectedAttemptError} from './job-empty-states.js';\nimport {JsonCode, type JsonCodeEntry, JsonCodeTabs} from './json-code.js';\n\nexport interface StepInspectorSheetProps {\n entry: StepListEntryModel;\n open: boolean;\n onOpenChange: (open: boolean) => void;\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n runAttempt: number;\n jobId: string;\n annotationCount?: number | undefined;\n}\n\nexport function StepInspectorSheet({\n entry,\n open,\n onOpenChange,\n workspaceSlug,\n projectSlug,\n workflowRunId,\n runAttempt,\n jobId,\n annotationCount,\n}: StepInspectorSheetProps) {\n const error = selectedStepError(entry.step, entry.error);\n const inspectorQuery = useStepAttemptDetailQuery(entry.step.id, entry.attempt, {\n enabled: open,\n });\n\n return (\n <Sheet open={open} onOpenChange={onOpenChange}>\n <SheetContent side=\"right\" className=\"w-full sm:max-w-[560px]\">\n <SheetHeader>\n <SheetTitle>{entry.step.label}</SheetTitle>\n <SheetDescription>\n Attempt #{entry.attempt} · {humanizeStatus(entry.statusVisual.kind)}\n </SheetDescription>\n </SheetHeader>\n <SheetBody className=\"gap-section\">\n <StepInspector\n step={entry.step}\n attempt={entry}\n error={error}\n showFailure={entry.statusVisual.kind === 'failed' || entry.error !== null}\n query={inspectorQuery}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={workflowRunId}\n runAttempt={runAttempt}\n jobId={jobId}\n annotationCount={annotationCount}\n />\n </SheetBody>\n </SheetContent>\n </Sheet>\n );\n}\n\nfunction StepFailureCallout({\n step,\n attempt,\n error,\n workspaceSlug,\n projectSlug,\n workflowRunId,\n runAttempt,\n}: {\n step: Step;\n attempt: StepAttempt;\n error: StepError | null;\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n runAttempt: number;\n}) {\n const reason = error?.reason ?? step.statusReason ?? 'unknown';\n const title = failureTitle(reason);\n const sourceLink = sourceLinkForFailure(reason) && step.sourceLocation;\n\n if (step.type === 'agent' && reason === 'agent_config_invalid') {\n return (\n <AgentConfigFailureCallout\n workspaceSlug={workspaceSlug}\n config={step.agentConfig}\n error={error}\n />\n );\n }\n\n return (\n <Callout\n role=\"alert\"\n type=\"error\"\n variant=\"secondary\"\n className=\"rounded-8 border border-tag-error-border p-panel-compact shadow-none\"\n >\n <CalloutContent>\n <CalloutTitle>{title}</CalloutTitle>\n <CalloutDescription>\n <div className=\"flex min-w-0 flex-wrap items-center gap-x-inline gap-y-tight\">\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <span>{failureDescription(reason)}</span>\n {error?.message ? (\n <span className=\"text-foreground-neutral-muted\">{error.message}</span>\n ) : null}\n </div>\n <Code as=\"span\" variant=\"label\" className=\"text-tag-error-text\">\n {reason}\n </Code>\n {sourceLink ? (\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId}}\n search={\n workflowRunSearchParams(\n {tab: 'source'},\n {stepId: step.id, stepAttemptId: attempt.id, runAttempt},\n ) as never\n }\n className=\"font-medium text-foreground-highlight-interactive underline-offset-2 hover:underline\"\n >\n View in source\n </Link>\n ) : null}\n </div>\n </CalloutDescription>\n </CalloutContent>\n </Callout>\n );\n}\n\nfunction StepInspector({\n step,\n attempt,\n error,\n showFailure,\n query,\n workspaceSlug,\n projectSlug,\n workflowRunId,\n runAttempt,\n jobId,\n annotationCount,\n}: {\n step: Step;\n attempt: StepAttempt;\n error: StepError | null;\n showFailure: boolean;\n query: ReturnType<typeof useStepAttemptDetailQuery>;\n workspaceSlug: string;\n projectSlug: string;\n workflowRunId: string;\n runAttempt: number;\n jobId: string;\n annotationCount: number | undefined;\n}) {\n const detail = query.data;\n const trace = detail?.evaluationTrace ?? null;\n const resolvedConfig = detail?.config ?? null;\n const hasInputs =\n detail !== undefined &&\n (countConfigValues(detail.authoredConfig) > 0 || countConfigValues(resolvedConfig) > 0);\n const hasOutputs =\n attempt.outputs !== null || attempt.output !== null || attempt.response !== null;\n const hasTrace = trace !== null && trace.length > 0;\n const hasAnnotations = annotationCount !== undefined && annotationCount > 0;\n const detailCount = Number(hasInputs) + Number(hasOutputs) + Number(hasTrace);\n\n return (\n <div className=\"flex min-w-0 flex-col gap-section\">\n {showFailure ? (\n <StepFailureCallout\n step={step}\n attempt={attempt}\n error={error}\n workspaceSlug={workspaceSlug}\n projectSlug={projectSlug}\n workflowRunId={workflowRunId}\n runAttempt={runAttempt}\n />\n ) : null}\n {query.isPending ? <InspectorLoading /> : null}\n {query.isError ? (\n <Callout\n role=\"alert\"\n type=\"warning\"\n variant=\"secondary\"\n className=\"rounded-8 border border-tag-warning-border p-panel-compact shadow-none\"\n >\n <CalloutContent>\n <CalloutTitle>Details unavailable</CalloutTitle>\n <CalloutDescription className=\"flex items-center justify-between gap-inline\">\n <span>We could not load the resolved configuration for this attempt.</span>\n <Button\n type=\"button\"\n size=\"2xs\"\n variant=\"secondary\"\n onClick={() => void query.refetch()}\n >\n Retry\n </Button>\n </CalloutDescription>\n </CalloutContent>\n </Callout>\n ) : null}\n {detail ? (\n <div className=\"flex min-w-0 flex-col gap-group\">\n {hasInputs ? (\n <InspectorSection title=\"Inputs\">\n <ConfigCode authoredConfig={detail.authoredConfig} resolvedConfig={resolvedConfig} />\n </InspectorSection>\n ) : null}\n {hasOutputs ? (\n <InspectorSection title=\"Outputs\">\n {attempt.outputs !== null || attempt.output !== null ? (\n <JsonCode\n value={attempt.outputs ?? attempt.output ?? {}}\n emptyMessage=\"No outputs declared; the `outputs:` mapping is empty.\"\n />\n ) : null}\n {attempt.response !== null ? (\n <div className=\"flex min-w-0 flex-col gap-tight\">\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n Response\n </Text>\n <pre className=\"max-h-160 min-w-0 overflow-auto rounded-6 border border-border-neutral-base bg-background-neutral-subtle p-tight font-code text-xs leading-18 text-foreground-neutral-muted scrollbar\">\n {attempt.response}\n </pre>\n </div>\n ) : null}\n </InspectorSection>\n ) : null}\n {hasTrace ? (\n <InspectorSection title=\"Evaluation\">\n <EvaluationTrace trace={trace ?? []} />\n </InspectorSection>\n ) : null}\n {detailCount === 0 && !showFailure && !hasAnnotations ? <EmptyInspector /> : null}\n </div>\n ) : null}\n {hasAnnotations ? (\n <Link\n to=\"/w/$workspaceSlug/p/$projectSlug/runs/$workflowRunId\"\n params={{workspaceSlug, projectSlug, workflowRunId}}\n search={workflowRunSearchParams({tab: 'annotations'}, {jobId, runAttempt}) as never}\n className=\"inline-flex w-fit rounded-4 text-xs text-foreground-highlight-interactive underline-offset-2 hover:underline focus-visible:shadow-button-neutral-focus\"\n >\n View {annotationCount} annotation{annotationCount === 1 ? '' : 's'}\n </Link>\n ) : null}\n {!query.isPending && !query.isError && !detail && !showFailure && !hasAnnotations ? (\n <EmptyInspector />\n ) : null}\n </div>\n );\n}\n\nfunction InspectorSection({title, children}: {title: string; children: ReactNode}) {\n return (\n <section className=\"flex min-w-0 flex-col gap-inline\" aria-label={title}>\n <Text size=\"xs\" bold className=\"text-foreground-neutral-base\">\n {title}\n </Text>\n {children}\n </section>\n );\n}\n\nfunction ConfigCode({\n authoredConfig,\n resolvedConfig,\n}: {\n authoredConfig: Record<string, unknown> | null;\n resolvedConfig: Record<string, unknown> | null;\n}) {\n const entries: JsonCodeEntry[] = [\n ...(authoredConfig\n ? [\n {\n filename: 'authored.json',\n label: 'Authored configuration',\n value: authoredConfig,\n },\n ]\n : []),\n ...(resolvedConfig\n ? [\n {\n filename: 'resolved.json',\n label: 'Resolved configuration',\n value: resolvedConfig,\n },\n ]\n : []),\n ];\n\n if (entries.length === 0) return null;\n return <JsonCodeTabs entries={entries} />;\n}\n\nexport function EvaluationTrace({trace}: {trace: readonly EvaluationTraceEntry[]}) {\n const keyCounts = new Map<string, number>();\n\n return (\n <dl className=\"flex min-w-0 flex-col divide-y divide-border-neutral-base rounded-6 border border-border-neutral-base\">\n {trace.map((entry) => {\n if ('dropped' in entry) {\n const keyBase = `limit-${entry.dropped}`;\n const occurrence = keyCounts.get(keyBase) ?? 0;\n keyCounts.set(keyBase, occurrence + 1);\n return (\n <div\n key={`${keyBase}-${occurrence}`}\n className=\"px-row py-row text-xs text-foreground-neutral-muted\"\n >\n {entry.dropped} more evaluation{entry.dropped === 1 ? '' : 's'} not recorded\n </div>\n );\n }\n\n const empty = entry.value === undefined || entry.value === '';\n const keyBase = `evaluation-${entry.field}-${entry.expression}-${entry.evaluatedAt}-${entry.fillTarget}`;\n const occurrence = keyCounts.get(keyBase) ?? 0;\n keyCounts.set(keyBase, occurrence + 1);\n return (\n <div\n key={`${keyBase}-${occurrence}`}\n className={cn(\n 'grid min-w-0 grid-cols-1 gap-inline px-row py-row min-[768px]:grid-cols-[160px_minmax(0,1fr)]',\n entry.degraded && 'border-l border-tag-error-icon',\n )}\n >\n <dt\n className=\"flex min-w-0 flex-col gap-tight font-code text-xs text-foreground-neutral-muted\"\n title={entry.field}\n >\n <span className=\"block truncate\">{entry.field}</span>\n <span className=\"block break-all text-foreground-neutral-subtle\">\n {entry.expression}\n </span>\n </dt>\n <dd className=\"flex min-w-0 flex-col gap-tight text-xs text-foreground-neutral-base\">\n {entry.degraded ? <span className=\"sr-only\">Degraded evaluation</span> : null}\n <div className=\"break-words font-code\">\n {empty ? <span className=\"text-tag-error-text\">(empty)</span> : entry.value}\n </div>\n <div className=\"flex min-w-0 flex-wrap gap-x-inline gap-y-tight text-foreground-neutral-muted\">\n {entry.degraded ? <span className=\"text-tag-error-text\">degraded</span> : null}\n {entry.truncated || entry.exprTruncated ? <span>truncated</span> : null}\n </div>\n </dd>\n </div>\n );\n })}\n </dl>\n );\n}\n\nfunction InspectorLoading() {\n return (\n <div\n role=\"status\"\n aria-label=\"Loading troubleshooting details\"\n className=\"flex flex-col gap-inline\"\n >\n <Skeleton className=\"h-16 w-120\" />\n <Skeleton className=\"h-120 w-full\" />\n </div>\n );\n}\n\nfunction EmptyInspector() {\n return (\n <Text size=\"xs\" className=\"text-foreground-neutral-muted\">\n No additional troubleshooting details were recorded.\n </Text>\n );\n}\n\nfunction selectedStepError(\n step: Step,\n attemptError: Record<string, unknown> | null,\n): StepError | null {\n return toSelectedAttemptError(step, attemptError) ?? step.error;\n}\n\nfunction failureTitle(reason: string | JobStatusReason): string {\n switch (reason) {\n case 'checkout_failed':\n return 'Checkout failed';\n case 'checkout_auth_failed':\n return 'Checkout authentication failed';\n case 'checkout_unavailable':\n return 'Checkout service unavailable';\n case 'checkout_path_invalid':\n return 'Checkout path is invalid';\n case 'checkout_destination_occupied':\n return 'Checkout destination is already occupied';\n case 'git_unavailable':\n return 'Git was unavailable';\n case 'workspace_prep_failed':\n return 'Workspace preparation failed';\n case 'setup_aborted':\n return 'Step setup was aborted';\n case 'config_unresolvable':\n return 'Step configuration could not be resolved';\n case 'output_invalid':\n return 'Step output was invalid';\n case 'agent_config_invalid':\n return 'Agent configuration is invalid';\n case 'agent_invocation_failed':\n return 'Agent invocation failed';\n case 'agent_harness_unavailable':\n return 'Agent harness was unavailable';\n case 'runner_lost':\n return 'Runner stopped responding';\n case 'timed_out':\n return 'Step timed out';\n case 'step_failed':\n return 'A step failed';\n case 'dependency_not_completed':\n return 'A dependency did not complete';\n case 'condition_false':\n return 'The job condition was false';\n case 'default_gate_rejected':\n return 'The default gate rejected this job';\n case 'condition_rejected':\n return 'The job condition rejected this job';\n case 'condition_errored':\n return 'The job condition could not be evaluated';\n case 'user_cancelled':\n return 'The job was cancelled by a user';\n case 'run_cancelled':\n return 'The run was cancelled';\n case 'unknown':\n return 'The failure reason was not recorded';\n default:\n return 'Step failed';\n }\n}\n\nfunction failureDescription(reason: string | JobStatusReason): string {\n switch (reason) {\n case 'checkout_auth_failed':\n return 'Checkout credentials were rejected. Verify repository access before re-running.';\n case 'checkout_unavailable':\n return 'The checkout service was unavailable. Retry after the service recovers.';\n case 'git_unavailable':\n return 'The runner could not start Git. Check the runner image before re-running.';\n case 'workspace_prep_failed':\n return 'The runner could not prepare its workspace. Review the runner setup details.';\n case 'config_unresolvable':\n return 'The resolved configuration contains a value that could not be evaluated.';\n case 'output_invalid':\n return 'The step returned output that did not match the declared contract.';\n case 'agent_config_invalid':\n return 'The agent configuration is not valid for this step.';\n case 'agent_invocation_failed':\n return 'The agent invocation failed after configuration was accepted.';\n case 'agent_harness_unavailable':\n return 'The runner could not start the agent harness.';\n case 'runner_lost':\n return 'The runner stopped responding before the step completed.';\n case 'timed_out':\n return 'The step exceeded its configured time limit.';\n case 'dependency_not_completed':\n return 'A required job did not complete, so this job could not start.';\n case 'condition_false':\n case 'condition_rejected':\n return 'The job condition did not allow this job to run.';\n case 'condition_errored':\n return 'The job condition could not be evaluated.';\n case 'default_gate_rejected':\n return 'A required job did not succeed, so this job was not allowed to run.';\n case 'step_failed':\n return 'A step failed before this job could complete.';\n case 'user_cancelled':\n case 'run_cancelled':\n return 'The run was cancelled before this work completed.';\n case 'unknown':\n return 'No machine-readable failure reason was recorded.';\n default:\n return `${humanize(reason)}. Review the details below and re-run after resolving the cause.`;\n }\n}\n\nfunction sourceLinkForFailure(reason: string | JobStatusReason): boolean {\n return (\n reason === 'config_unresolvable' ||\n reason === 'agent_config_invalid' ||\n reason === 'output_invalid' ||\n reason === 'default_gate_rejected' ||\n reason === 'condition_rejected' ||\n reason === 'condition_errored'\n );\n}\n\nfunction humanize(value: string): string {\n return value.replaceAll('_', ' ').replace(/\\b\\w/g, (letter) => letter.toUpperCase());\n}\n\nfunction countConfigValues(value: unknown): number {\n if (Array.isArray(value))\n return value.reduce((total, item) => total + countConfigValues(item), 0);\n if (value !== null && typeof value === 'object') {\n return Object.values(value).reduce((total, item) => total + countConfigValues(item), 0);\n }\n return value === undefined ? 0 : 1;\n}\n"],"names":["Button","Callout","CalloutContent","CalloutDescription","CalloutTitle","Sheet","SheetBody","SheetContent","SheetDescription","SheetHeader","SheetTitle","Skeleton","Code","Text","cn","Link","useStepAttemptDetailQuery","workflowRunSearchParams","humanizeStatus","AgentConfigFailureCallout","toSelectedAttemptError","JsonCode","JsonCodeTabs","StepInspectorSheet","entry","open","onOpenChange","workspaceSlug","projectSlug","workflowRunId","runAttempt","jobId","annotationCount","error","selectedStepError","step","inspectorQuery","id","attempt","enabled","side","className","label","statusVisual","kind","StepInspector","showFailure","query","StepFailureCallout","reason","statusReason","title","failureTitle","sourceLink","sourceLinkForFailure","sourceLocation","type","config","agentConfig","role","variant","div","span","failureDescription","message","as","to","params","search","tab","stepId","stepAttemptId","detail","data","trace","evaluationTrace","resolvedConfig","hasInputs","undefined","countConfigValues","authoredConfig","hasOutputs","outputs","output","response","hasTrace","length","hasAnnotations","detailCount","Number","isPending","InspectorLoading","isError","size","onClick","refetch","InspectorSection","ConfigCode","value","emptyMessage","pre","EvaluationTrace","EmptyInspector","children","section","aria-label","bold","entries","filename","keyCounts","Map","dl","map","keyBase","dropped","occurrence","get","set","empty","field","expression","evaluatedAt","fillTarget","degraded","dt","dd","truncated","exprTruncated","attemptError","humanize","replaceAll","replace","letter","toUpperCase","Array","isArray","reduce","total","item","Object","values"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"job-graph-content.d.ts","sourceRoot":"","sources":["../../../src/components/job-graph/job-graph-content.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAC,aAAa,EAAwB,MAAM,kBAAkB,CAAC;AAG3E,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,YAAY,CAAC;AASxD,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,OAAO,EACP,aAAa,EACb,WAAW,GACZ,EAAE;IACD,KAAK,EAAE,aAAa,CAAC;IACrB,OAAO,EAAE,IAAI,CACX,iBAAiB,EACjB,qBAAqB,GAAG,cAAc,GAAG,iBAAiB,GAAG,eAAe,CAC7E,CAAC;IACF,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,CAAC,EAAE,uBAAuB,KAAK,IAAI,CAAC;CACpF,+BAyFA"}
1
+ {"version":3,"file":"job-graph-content.d.ts","sourceRoot":"","sources":["../../../src/components/job-graph/job-graph-content.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAC,iBAAiB,EAAC,MAAM,uBAAuB,CAAC;AAC7D,OAAO,KAAK,EAAC,aAAa,EAAwB,MAAM,kBAAkB,CAAC;AAG3E,OAAO,KAAK,EAAC,uBAAuB,EAAC,MAAM,YAAY,CAAC;AAUxD,wBAAgB,eAAe,CAAC,EAC9B,KAAK,EACL,OAAO,EACP,aAAa,EACb,WAAW,GACZ,EAAE;IACD,KAAK,EAAE,aAAa,CAAC;IACrB,OAAO,EAAE,IAAI,CACX,iBAAiB,EACjB,qBAAqB,GAAG,cAAc,GAAG,iBAAiB,GAAG,eAAe,CAC7E,CAAC;IACF,aAAa,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,EAAE,MAAM,CAAC,EAAE,uBAAuB,KAAK,IAAI,CAAC;CACpF,+BAyFA"}
@@ -8,7 +8,7 @@ import { JobNode, TriggerNode } from './job-node.js';
8
8
  const NODE_WIDTH = 208;
9
9
  const NODE_HEIGHT = 48;
10
10
  const COLUMN_GAP = 64;
11
- const ROW_GAP = 20;
11
+ /** Fixed graph spacing shared by the DOM rows and the edge geometry below. */ const ROW_GAP = 20;
12
12
  const TRIGGER_WIDTH = 36;
13
13
  const PADDING = 16;
14
14
  export function JobGraphContent({ model, trigger, selectedJobId, onSelectJob }) {
@@ -16,7 +16,7 @@ export function JobGraphContent({ model, trigger, selectedJobId, onSelectJob })
16
16
  const [hoveredJobId, setHoveredJobId] = useState();
17
17
  if (model.nodes.length === 0) {
18
18
  return /*#__PURE__*/ _jsx(EmptyState, {
19
- className: "min-h-160 px-16 py-24",
19
+ className: "min-h-160 p-panel",
20
20
  icon: "componentLine",
21
21
  title: "No jobs yet",
22
22
  description: "This run has not materialized jobs.",
@@ -77,10 +77,11 @@ export function JobGraphContent({ model, trigger, selectedJobId, onSelectJob })
77
77
  })
78
78
  }),
79
79
  model.columns.map((column, columnIndex)=>/*#__PURE__*/ _jsx("div", {
80
- className: "absolute flex flex-col gap-20",
80
+ className: "absolute flex flex-col",
81
81
  style: {
82
82
  left: jobLeft(columnIndex),
83
- top: PADDING
83
+ top: PADDING,
84
+ rowGap: ROW_GAP
84
85
  },
85
86
  children: column.map((node)=>/*#__PURE__*/ _jsx(JobNode, {
86
87
  node: node,