@shipfox/client-workflows 4.0.0 → 6.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (125) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +68 -0
  3. package/dist/components/workflow-run-list/types.d.ts +12 -0
  4. package/dist/components/workflow-run-list/types.d.ts.map +1 -1
  5. package/dist/components/workflow-run-list/types.js.map +1 -1
  6. package/dist/components/workflow-run-list/workflow-run-list-view.d.ts +1 -1
  7. package/dist/components/workflow-run-list/workflow-run-list-view.d.ts.map +1 -1
  8. package/dist/components/workflow-run-list/workflow-run-list-view.js +32 -11
  9. package/dist/components/workflow-run-list/workflow-run-list-view.js.map +1 -1
  10. package/dist/components/workflow-run-list/workflow-run-list.d.ts +1 -1
  11. package/dist/components/workflow-run-list/workflow-run-list.d.ts.map +1 -1
  12. package/dist/components/workflow-run-list/workflow-run-list.js +7 -2
  13. package/dist/components/workflow-run-list/workflow-run-list.js.map +1 -1
  14. package/dist/components/workflow-run-summary/workflow-run-summary.d.ts +2 -3
  15. package/dist/components/workflow-run-summary/workflow-run-summary.d.ts.map +1 -1
  16. package/dist/components/workflow-run-summary/workflow-run-summary.js.map +1 -1
  17. package/dist/components/workflow-run-view/job-card.d.ts.map +1 -1
  18. package/dist/components/workflow-run-view/job-card.js +9 -8
  19. package/dist/components/workflow-run-view/job-card.js.map +1 -1
  20. package/dist/components/workflow-run-view/workflow-run-view.js.map +1 -1
  21. package/dist/core/entities/job-execution.d.ts +11 -6
  22. package/dist/core/entities/job-execution.d.ts.map +1 -1
  23. package/dist/core/entities/job-execution.js +0 -19
  24. package/dist/core/entities/job-execution.js.map +1 -1
  25. package/dist/core/entities/job.d.ts +32 -10
  26. package/dist/core/entities/job.d.ts.map +1 -1
  27. package/dist/core/entities/job.js +0 -22
  28. package/dist/core/entities/job.js.map +1 -1
  29. package/dist/core/entities/step-attempt.d.ts +28 -3
  30. package/dist/core/entities/step-attempt.d.ts.map +1 -1
  31. package/dist/core/entities/step-attempt.js +0 -17
  32. package/dist/core/entities/step-attempt.js.map +1 -1
  33. package/dist/core/entities/step.d.ts +6 -6
  34. package/dist/core/entities/step.d.ts.map +1 -1
  35. package/dist/core/entities/step.js +19 -49
  36. package/dist/core/entities/step.js.map +1 -1
  37. package/dist/core/entities/workflow-run-attempt.d.ts +0 -2
  38. package/dist/core/entities/workflow-run-attempt.d.ts.map +1 -1
  39. package/dist/core/entities/workflow-run-attempt.js +0 -12
  40. package/dist/core/entities/workflow-run-attempt.js.map +1 -1
  41. package/dist/core/entities/workflow-run.d.ts +6 -7
  42. package/dist/core/entities/workflow-run.d.ts.map +1 -1
  43. package/dist/core/entities/workflow-run.js +1 -67
  44. package/dist/core/entities/workflow-run.js.map +1 -1
  45. package/dist/core/workflow-run.d.ts +9 -9
  46. package/dist/core/workflow-run.d.ts.map +1 -1
  47. package/dist/core/workflow-run.js +6 -6
  48. package/dist/core/workflow-run.js.map +1 -1
  49. package/dist/feature.d.ts +23 -0
  50. package/dist/feature.d.ts.map +1 -1
  51. package/dist/feature.js +22 -9
  52. package/dist/feature.js.map +1 -1
  53. package/dist/hooks/api/workflow-run-mapper.d.ts +12 -0
  54. package/dist/hooks/api/workflow-run-mapper.d.ts.map +1 -0
  55. package/dist/hooks/api/workflow-run-mapper.js +207 -0
  56. package/dist/hooks/api/workflow-run-mapper.js.map +1 -0
  57. package/dist/hooks/api/workflow-runs.d.ts +25 -55
  58. package/dist/hooks/api/workflow-runs.d.ts.map +1 -1
  59. package/dist/hooks/api/workflow-runs.js +95 -51
  60. package/dist/hooks/api/workflow-runs.js.map +1 -1
  61. package/dist/index.d.ts +3 -2
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +2 -1
  64. package/dist/index.js.map +1 -1
  65. package/dist/pages/project-workflows-page.d.ts +4 -0
  66. package/dist/pages/project-workflows-page.d.ts.map +1 -0
  67. package/dist/pages/project-workflows-page.js +479 -0
  68. package/dist/pages/project-workflows-page.js.map +1 -0
  69. package/dist/pages/workflow-run-page.d.ts +3 -1
  70. package/dist/pages/workflow-run-page.d.ts.map +1 -1
  71. package/dist/pages/workflow-run-page.js +21 -14
  72. package/dist/pages/workflow-run-page.js.map +1 -1
  73. package/dist/routes/inputs.d.ts +22 -0
  74. package/dist/routes/inputs.d.ts.map +1 -0
  75. package/dist/routes/inputs.js +76 -0
  76. package/dist/routes/inputs.js.map +1 -0
  77. package/dist/routes/run-detail.d.ts +2 -0
  78. package/dist/routes/run-detail.d.ts.map +1 -1
  79. package/dist/routes/run-detail.js +6 -6
  80. package/dist/routes/run-detail.js.map +1 -1
  81. package/dist/routes/runs.d.ts +2 -0
  82. package/dist/routes/runs.d.ts.map +1 -1
  83. package/dist/routes/runs.js +6 -6
  84. package/dist/routes/runs.js.map +1 -1
  85. package/dist/routes/workflows.d.ts +5 -0
  86. package/dist/routes/workflows.d.ts.map +1 -0
  87. package/dist/routes/workflows.js +14 -0
  88. package/dist/routes/workflows.js.map +1 -0
  89. package/dist/tsconfig.test.tsbuildinfo +1 -1
  90. package/package.json +13 -12
  91. package/src/components/workflow-run-list/types.ts +6 -0
  92. package/src/components/workflow-run-list/workflow-run-list-view.tsx +27 -11
  93. package/src/components/workflow-run-list/workflow-run-list.tsx +6 -0
  94. package/src/components/workflow-run-summary/workflow-run-attempt-switcher.test.tsx +5 -6
  95. package/src/components/workflow-run-summary/workflow-run-summary.tsx +3 -3
  96. package/src/components/workflow-run-view/job-card.tsx +20 -11
  97. package/src/components/workflow-run-view/workflow-run-view.test.tsx +3 -3
  98. package/src/components/workflow-run-view/workflow-run-view.tsx +2 -2
  99. package/src/core/entities/job-execution.ts +12 -28
  100. package/src/core/entities/job.ts +44 -45
  101. package/src/core/entities/step-attempt.ts +9 -20
  102. package/src/core/entities/step.ts +38 -66
  103. package/src/core/entities/workflow-run-attempt.ts +0 -14
  104. package/src/core/entities/workflow-run.ts +8 -86
  105. package/src/core/workflow-run.test.ts +13 -11
  106. package/src/core/workflow-run.ts +8 -13
  107. package/src/feature.ts +24 -10
  108. package/src/hooks/api/workflow-run-mapper.ts +246 -0
  109. package/src/hooks/api/workflow-runs.test.tsx +57 -59
  110. package/src/hooks/api/workflow-runs.ts +187 -88
  111. package/src/index.ts +5 -0
  112. package/src/page-harness-budget.test.ts +1 -0
  113. package/src/pages/project-workflows-page.test.tsx +247 -0
  114. package/src/pages/project-workflows-page.tsx +448 -0
  115. package/src/pages/workflow-run-page.test.tsx +4 -2
  116. package/src/pages/workflow-run-page.tsx +22 -17
  117. package/src/routes/inputs.test.ts +22 -0
  118. package/src/routes/inputs.ts +58 -0
  119. package/src/routes/run-detail.tsx +12 -8
  120. package/src/routes/runs.tsx +11 -4
  121. package/src/routes/workflows.tsx +10 -0
  122. package/test/fixtures/workflow-run.ts +9 -7
  123. package/test/pages.tsx +48 -6
  124. package/tsconfig.build.tsbuildinfo +1 -1
  125. package/vercel.json +5 -0
@@ -1,17 +1,8 @@
1
- import type {
2
- WorkflowRunDetailResponseDto,
3
- WorkflowRunListResponseDto,
4
- WorkflowRunResponseDto,
5
- WorkflowRunStatusDto,
6
- } from '@shipfox/api-workflows-dto';
7
- import {type Job, toJob, WORKFLOW_JOB_STATUSES} from './job.js';
8
- import {
9
- toWorkflowRunAttempt,
10
- type WorkflowRunAttempt,
11
- WorkflowRunAttemptSummary,
12
- } from './workflow-run-attempt.js';
1
+ import {type Job, WORKFLOW_JOB_STATUSES} from './job.js';
2
+ import type {WorkflowRunAttempt, WorkflowRunAttemptSummary} from './workflow-run-attempt.js';
13
3
 
14
- export type WorkflowRunStatus = WorkflowRunStatusDto;
4
+ export type WorkflowRunStatus = 'pending' | 'running' | 'succeeded' | 'failed' | 'cancelled';
5
+ export type WorkflowRunRerunMode = 'all' | 'failed';
15
6
  export type WorkflowStatus = WorkflowRunStatus | (typeof WORKFLOW_JOB_STATUSES)[number];
16
7
 
17
8
  export const WORKFLOW_RUN_STATUSES = [
@@ -77,6 +68,10 @@ export interface WorkflowRunListPage {
77
68
  filteredTotalCount: number | null;
78
69
  }
79
70
 
71
+ export interface ManualWorkflowLaunch {
72
+ workflowRunId: string;
73
+ }
74
+
80
75
  export function workflowRunShortId(id: string): string {
81
76
  return id.length <= 8 ? id : id.slice(0, 8);
82
77
  }
@@ -108,76 +103,3 @@ export function isWorkflowRunTerminal(status: WorkflowRunStatus): boolean {
108
103
  export function isWorkflowStatus(status: string): status is WorkflowStatus {
109
104
  return WORKFLOW_STATUSES.has(status as WorkflowStatus);
110
105
  }
111
-
112
- export function toWorkflowRun(dto: WorkflowRunResponseDto): WorkflowRun {
113
- const triggerLabel = workflowRunTriggerLabel({
114
- triggerSource: dto.trigger_source,
115
- triggerEvent: dto.trigger_event,
116
- });
117
- const triggerDisplayLabel = workflowRunTriggerDisplayLabel({
118
- triggerSource: dto.trigger_source,
119
- triggerEvent: dto.trigger_event,
120
- });
121
-
122
- return {
123
- id: dto.id,
124
- projectId: dto.project_id,
125
- definitionId: dto.definition_id,
126
- name: dto.name,
127
- currentAttempt: dto.current_attempt,
128
- triggerProvider: dto.trigger_provider,
129
- triggerSource: dto.trigger_source,
130
- triggerEvent: dto.trigger_event,
131
- triggerDisplayLabel,
132
- triggerLabel,
133
- triggerPayload: dto.trigger_payload,
134
- inputs: dto.inputs ?? null,
135
- sourceSnapshot: dto.source_snapshot ? toWorkflowSourceSnapshot(dto.source_snapshot) : null,
136
- createdAt: dto.created_at,
137
- updatedAt: dto.updated_at,
138
- shortId: workflowRunShortId(dto.id),
139
- isTemporary: dto.id.startsWith('temp-'),
140
- };
141
- }
142
-
143
- export function toWorkflowRunListItem(dto: WorkflowRunResponseDto): WorkflowRunListItem {
144
- return {
145
- ...toWorkflowRun(dto),
146
- status: dto.status,
147
- latestAttempt: dto.latest_attempt,
148
- runAttempt: new WorkflowRunAttemptSummary({
149
- workflowRunId: dto.id,
150
- attempt: dto.current_attempt,
151
- status: dto.status,
152
- createdAt: dto.created_at,
153
- startedAt: dto.started_at ?? null,
154
- finishedAt: dto.finished_at ?? null,
155
- }),
156
- };
157
- }
158
-
159
- export function toWorkflowRunDetail(dto: WorkflowRunDetailResponseDto): WorkflowRunDetail {
160
- return {
161
- ...toWorkflowRun(dto),
162
- latestAttempt: dto.latest_attempt,
163
- runAttempt: toWorkflowRunAttempt(dto.run_attempt),
164
- jobs: dto.jobs.map(toJob),
165
- };
166
- }
167
-
168
- export function toWorkflowRunListPage(dto: WorkflowRunListResponseDto): WorkflowRunListPage {
169
- return {
170
- runs: dto.runs.map(toWorkflowRunListItem),
171
- nextCursor: dto.next_cursor,
172
- filteredTotalCount: dto.filtered_total_count,
173
- };
174
- }
175
-
176
- function toWorkflowSourceSnapshot(
177
- dto: NonNullable<WorkflowRunResponseDto['source_snapshot']>,
178
- ): WorkflowSourceSnapshot {
179
- return {
180
- content: dto.content,
181
- format: dto.format,
182
- };
183
- }
@@ -1,3 +1,10 @@
1
+ import {
2
+ toWorkflowRun,
3
+ toWorkflowRunAttempt,
4
+ toWorkflowRunDetail,
5
+ toWorkflowRunListItem,
6
+ toWorkflowRunListPage,
7
+ } from '#hooks/api/workflow-run-mapper.js';
1
8
  import {
2
9
  workflowJobDto,
3
10
  workflowJobExecutionDto,
@@ -11,11 +18,6 @@ import {
11
18
  import {
12
19
  isWorkflowRunTerminal,
13
20
  isWorkflowStatus,
14
- toWorkflowRun,
15
- toWorkflowRunAttempt,
16
- toWorkflowRunDetail,
17
- toWorkflowRunListItem,
18
- toWorkflowRunListPage,
19
21
  workflowRunShortId,
20
22
  workflowRunTriggerDisplayLabel,
21
23
  workflowRunTriggerLabel,
@@ -313,11 +315,11 @@ describe('workflow run model mapping', () => {
313
315
  listening: {
314
316
  on: [{source: 'github', event: 'deployment_status'}],
315
317
  until: [{source: 'slack', event: 'approval'}],
316
- timeout_ms: 1_800_000,
317
- max_executions: 10,
318
+ timeoutMs: 1_800_000,
319
+ maxExecutions: 10,
318
320
  batch: null,
319
- on_resolve: 'finish',
320
- execution_timeout_ms: null,
321
+ onResolve: 'finish',
322
+ executionTimeoutMs: null,
321
323
  name: null,
322
324
  },
323
325
  listenerStatus: 'listening',
@@ -328,8 +330,8 @@ describe('workflow run model mapping', () => {
328
330
  {
329
331
  source: 'github',
330
332
  event: 'deployment_status',
331
- delivery_id: 'delivery-1',
332
- received_at: '2026-05-07T01:00:00.000Z',
333
+ deliveryId: 'delivery-1',
334
+ receivedAt: '2026-05-07T01:00:00.000Z',
333
335
  data: {state: 'success'},
334
336
  },
335
337
  ],
@@ -1,5 +1,6 @@
1
1
  export type {
2
2
  JobDisplayDuration,
3
+ JobListening,
3
4
  JobMode,
4
5
  JobStatus,
5
6
  JobStatusReason,
@@ -12,15 +13,15 @@ export {
12
13
  Job,
13
14
  resolveJobExecution,
14
15
  TERMINAL_WORKFLOW_JOB_STATUSES,
15
- toJob,
16
16
  WORKFLOW_JOB_STATUSES,
17
17
  } from './entities/job.js';
18
18
  export type {
19
19
  JobExecutionDisplayDuration,
20
20
  JobExecutionStatus,
21
21
  JobExecutionTime,
22
+ WorkflowExecutionEvent,
22
23
  } from './entities/job-execution.js';
23
- export {JobExecution, toJobExecution} from './entities/job-execution.js';
24
+ export {JobExecution} from './entities/job-execution.js';
24
25
  export type {
25
26
  AgentConfigIssue,
26
27
  AgentStepConfig,
@@ -30,17 +31,19 @@ export type {
30
31
  StepErrorReason,
31
32
  StepSourceLocation,
32
33
  } from './entities/step.js';
33
- export {toStep} from './entities/step.js';
34
+ export {AGENT_CONFIG_ISSUES, STEP_ERROR_REASONS} from './entities/step.js';
34
35
  export type {
35
36
  StepAttemptDisplayDuration,
36
37
  StepGateResult,
37
38
  } from './entities/step-attempt.js';
38
- export {StepAttempt, toStepAttempt} from './entities/step-attempt.js';
39
+ export {StepAttempt} from './entities/step-attempt.js';
39
40
  export type {
41
+ ManualWorkflowLaunch,
40
42
  WorkflowRun,
41
43
  WorkflowRunDetail,
42
44
  WorkflowRunListItem,
43
45
  WorkflowRunListPage,
46
+ WorkflowRunRerunMode,
44
47
  WorkflowRunStatus,
45
48
  WorkflowSourceSnapshot,
46
49
  WorkflowStatus,
@@ -49,18 +52,10 @@ export {
49
52
  isWorkflowRunTerminal,
50
53
  isWorkflowStatus,
51
54
  TERMINAL_WORKFLOW_RUN_STATUSES,
52
- toWorkflowRun,
53
- toWorkflowRunDetail,
54
- toWorkflowRunListItem,
55
- toWorkflowRunListPage,
56
55
  WORKFLOW_RUN_STATUSES,
57
56
  workflowRunShortId,
58
57
  workflowRunTriggerDisplayLabel,
59
58
  workflowRunTriggerLabel,
60
59
  } from './entities/workflow-run.js';
61
60
  export type {WorkflowRunAttemptDisplayDuration} from './entities/workflow-run-attempt.js';
62
- export {
63
- toWorkflowRunAttempt,
64
- WorkflowRunAttempt,
65
- WorkflowRunAttemptSummary,
66
- } from './entities/workflow-run-attempt.js';
61
+ export {WorkflowRunAttempt, WorkflowRunAttemptSummary} from './entities/workflow-run-attempt.js';
package/src/feature.ts CHANGED
@@ -1,8 +1,30 @@
1
- import {defineClientFeature} from '@shipfox/client-shell';
1
+ import {defineClientFeature, type NavTabEntry} from '@shipfox/client-shell';
2
+
3
+ export const workflowsNavigation = [
4
+ {
5
+ id: 'nav.runs',
6
+ scope: 'project',
7
+ label: 'Runs',
8
+ to: '/workspaces/$wid/projects/$pid/runs',
9
+ order: 100,
10
+ },
11
+ {
12
+ id: 'nav.workflows',
13
+ scope: 'project',
14
+ label: 'Workflows',
15
+ to: '/workspaces/$wid/projects/$pid/workflows',
16
+ order: 200,
17
+ },
18
+ ] as const satisfies readonly NavTabEntry[];
2
19
 
3
20
  export const workflowsFeature = defineClientFeature({
4
21
  id: 'shipfox.workflows',
5
22
  routes: [
23
+ {
24
+ path: '/workspaces/$wid/projects/$pid/workflows',
25
+ parent: 'projectLayout',
26
+ impl: '@shipfox/client-workflows/routes/workflows',
27
+ },
6
28
  {
7
29
  path: '/workspaces/$wid/projects/$pid/runs',
8
30
  parent: 'projectLayout',
@@ -14,13 +36,5 @@ export const workflowsFeature = defineClientFeature({
14
36
  impl: '@shipfox/client-workflows/routes/run-detail',
15
37
  },
16
38
  ],
17
- navigation: [
18
- {
19
- id: 'nav.runs',
20
- scope: 'project',
21
- label: 'Runs',
22
- to: '/workspaces/$wid/projects/$pid/runs',
23
- order: 100,
24
- },
25
- ],
39
+ navigation: workflowsNavigation,
26
40
  });
@@ -0,0 +1,246 @@
1
+ import type {
2
+ JobListeningDto,
3
+ StepAttemptDto,
4
+ StepGateResultDto,
5
+ WorkflowExecutionEventDto,
6
+ WorkflowRunAttemptDto,
7
+ WorkflowRunDetailResponseDto,
8
+ WorkflowRunJobDetailDto,
9
+ WorkflowRunJobExecutionDetailDto,
10
+ WorkflowRunListResponseDto,
11
+ WorkflowRunResponseDto,
12
+ WorkflowRunStepDetailDto,
13
+ } from '@shipfox/api-workflows-dto';
14
+ import {
15
+ Job,
16
+ JobExecution,
17
+ type JobListening,
18
+ type Step,
19
+ StepAttempt,
20
+ type StepGateResult,
21
+ type WorkflowExecutionEvent,
22
+ type WorkflowRun,
23
+ WorkflowRunAttempt,
24
+ WorkflowRunAttemptSummary,
25
+ type WorkflowRunDetail,
26
+ type WorkflowRunListItem,
27
+ type WorkflowRunListPage,
28
+ workflowRunShortId,
29
+ workflowRunTriggerDisplayLabel,
30
+ workflowRunTriggerLabel,
31
+ } from '#core/workflow-run.js';
32
+
33
+ export function toWorkflowRun(dto: WorkflowRunResponseDto): WorkflowRun {
34
+ return {
35
+ id: dto.id,
36
+ projectId: dto.project_id,
37
+ definitionId: dto.definition_id,
38
+ name: dto.name,
39
+ currentAttempt: dto.current_attempt,
40
+ triggerProvider: dto.trigger_provider,
41
+ triggerSource: dto.trigger_source,
42
+ triggerEvent: dto.trigger_event,
43
+ triggerDisplayLabel: workflowRunTriggerDisplayLabel({
44
+ triggerSource: dto.trigger_source,
45
+ triggerEvent: dto.trigger_event,
46
+ }),
47
+ triggerLabel: workflowRunTriggerLabel({
48
+ triggerSource: dto.trigger_source,
49
+ triggerEvent: dto.trigger_event,
50
+ }),
51
+ triggerPayload: dto.trigger_payload,
52
+ inputs: dto.inputs ?? null,
53
+ sourceSnapshot: dto.source_snapshot
54
+ ? {content: dto.source_snapshot.content, format: dto.source_snapshot.format}
55
+ : null,
56
+ createdAt: dto.created_at,
57
+ updatedAt: dto.updated_at,
58
+ shortId: workflowRunShortId(dto.id),
59
+ isTemporary: dto.id.startsWith('temp-'),
60
+ };
61
+ }
62
+
63
+ export function toWorkflowRunAttempt(dto: WorkflowRunAttemptDto): WorkflowRunAttempt {
64
+ return new WorkflowRunAttempt({
65
+ id: dto.id,
66
+ workflowRunId: dto.workflow_run_id,
67
+ attempt: dto.attempt,
68
+ status: dto.status,
69
+ createdAt: dto.created_at,
70
+ startedAt: dto.started_at ?? null,
71
+ finishedAt: dto.finished_at ?? null,
72
+ rerunMode: dto.rerun_mode,
73
+ });
74
+ }
75
+
76
+ export function toWorkflowRunListItem(dto: WorkflowRunResponseDto): WorkflowRunListItem {
77
+ return {
78
+ ...toWorkflowRun(dto),
79
+ status: dto.status,
80
+ latestAttempt: dto.latest_attempt,
81
+ runAttempt: new WorkflowRunAttemptSummary({
82
+ workflowRunId: dto.id,
83
+ attempt: dto.current_attempt,
84
+ status: dto.status,
85
+ createdAt: dto.created_at,
86
+ startedAt: dto.started_at ?? null,
87
+ finishedAt: dto.finished_at ?? null,
88
+ }),
89
+ };
90
+ }
91
+
92
+ export function toWorkflowRunListPage(dto: WorkflowRunListResponseDto): WorkflowRunListPage {
93
+ return {
94
+ runs: dto.runs.map(toWorkflowRunListItem),
95
+ nextCursor: dto.next_cursor,
96
+ filteredTotalCount: dto.filtered_total_count,
97
+ };
98
+ }
99
+
100
+ export function toWorkflowRunDetail(dto: WorkflowRunDetailResponseDto): WorkflowRunDetail {
101
+ return {
102
+ ...toWorkflowRun(dto),
103
+ latestAttempt: dto.latest_attempt,
104
+ runAttempt: toWorkflowRunAttempt(dto.run_attempt),
105
+ jobs: dto.jobs.map(toJob),
106
+ };
107
+ }
108
+
109
+ export function toJob(dto: WorkflowRunJobDetailDto): Job {
110
+ return new Job({
111
+ id: dto.id,
112
+ runAttemptId: dto.run_attempt_id,
113
+ key: dto.key,
114
+ name: dto.name,
115
+ mode: dto.mode,
116
+ status: dto.status,
117
+ statusReason: dto.status_reason,
118
+ carriedOver: dto.carried_over,
119
+ listening: dto.listening ? toJobListening(dto.listening) : null,
120
+ listenerStatus: dto.listener_status,
121
+ resolutionReason: dto.resolution_reason,
122
+ dependencies: dto.dependencies,
123
+ position: dto.position,
124
+ createdAt: dto.created_at,
125
+ updatedAt: dto.updated_at,
126
+ jobExecutions: dto.job_executions.map(toJobExecution),
127
+ });
128
+ }
129
+
130
+ export function toJobExecution(dto: WorkflowRunJobExecutionDetailDto): JobExecution {
131
+ return new JobExecution({
132
+ id: dto.id,
133
+ jobId: dto.job_id,
134
+ sequence: dto.sequence,
135
+ name: dto.name,
136
+ status: dto.status,
137
+ statusReason: dto.status_reason,
138
+ triggerEvents: (dto.trigger_events ?? []).map(toWorkflowExecutionEvent),
139
+ queuedAt: dto.queued_at ?? null,
140
+ startedAt: dto.started_at ?? null,
141
+ finishedAt: dto.finished_at ?? null,
142
+ timedOutAt: dto.timed_out_at ?? null,
143
+ createdAt: dto.created_at,
144
+ updatedAt: dto.updated_at,
145
+ steps: dto.steps.map(toStep),
146
+ });
147
+ }
148
+
149
+ export function toStep(dto: WorkflowRunStepDetailDto): Step {
150
+ return {
151
+ id: dto.id,
152
+ jobExecutionId: dto.job_execution_id,
153
+ key: dto.key,
154
+ name: dto.name,
155
+ sourceLocation: dto.source_location
156
+ ? {startLine: dto.source_location.start_line, endLine: dto.source_location.end_line}
157
+ : null,
158
+ status: dto.status,
159
+ type: dto.type,
160
+ config: dto.config,
161
+ agentConfig: toAgentStepConfig(dto),
162
+ error: dto.error
163
+ ? {
164
+ message: dto.error.message,
165
+ exitCode: dto.error.exit_code ?? null,
166
+ signal: dto.error.signal,
167
+ reason: dto.error.reason,
168
+ agentConfigIssue: dto.error.agent_config_issue,
169
+ category: dto.error.category,
170
+ }
171
+ : null,
172
+ position: dto.position,
173
+ currentAttempt: dto.current_attempt,
174
+ createdAt: dto.created_at,
175
+ updatedAt: dto.updated_at,
176
+ attempts: dto.attempts.map((attempt) => toStepAttempt(attempt, dto.job_execution_id)),
177
+ };
178
+ }
179
+
180
+ export function toStepAttempt(dto: StepAttemptDto, jobExecutionId: string): StepAttempt {
181
+ return new StepAttempt({
182
+ id: dto.id,
183
+ stepId: dto.step_id,
184
+ jobExecutionId,
185
+ attempt: dto.attempt,
186
+ executionOrder: dto.execution_order,
187
+ status: dto.status,
188
+ exitCode: dto.exit_code ?? null,
189
+ output: dto.output ?? null,
190
+ error: dto.error ?? null,
191
+ gateResult: toStepGateResult(dto.gate_result),
192
+ restartFeedback: dto.restart_feedback ?? null,
193
+ startedAt: dto.started_at,
194
+ finishedAt: dto.finished_at ?? null,
195
+ });
196
+ }
197
+
198
+ function toJobListening(dto: JobListeningDto): JobListening {
199
+ return {
200
+ on: dto.on,
201
+ until: dto.until,
202
+ timeoutMs: dto.timeout_ms,
203
+ maxExecutions: dto.max_executions,
204
+ batch: dto.batch
205
+ ? {
206
+ debounceMs: dto.batch.debounce_ms,
207
+ maxSize: dto.batch.max_size,
208
+ maxWaitMs: dto.batch.max_wait_ms,
209
+ }
210
+ : null,
211
+ onResolve: dto.on_resolve,
212
+ executionTimeoutMs: dto.execution_timeout_ms,
213
+ name: dto.name,
214
+ };
215
+ }
216
+
217
+ function toWorkflowExecutionEvent(dto: WorkflowExecutionEventDto): WorkflowExecutionEvent {
218
+ return {
219
+ source: dto.source,
220
+ event: dto.event,
221
+ deliveryId: dto.delivery_id,
222
+ receivedAt: dto.received_at,
223
+ data: dto.data,
224
+ };
225
+ }
226
+
227
+ function toStepGateResult(dto: StepGateResultDto): StepGateResult {
228
+ if (dto === null || dto.kind === 'none' || dto.kind === 'not_evaluated') return dto;
229
+ if (dto.kind === 'passed' || dto.kind === 'failed') return {...dto, exitCode: dto.exit_code};
230
+ if (dto.kind === 'uncheckable' || dto.kind === 'evaluation_error')
231
+ return {...dto, exitCode: dto.exit_code};
232
+ return dto;
233
+ }
234
+
235
+ function toAgentStepConfig(dto: WorkflowRunStepDetailDto): Step['agentConfig'] {
236
+ if (dto.type !== 'agent') return null;
237
+ return {
238
+ provider: stringConfigValue(dto.config.provider),
239
+ model: stringConfigValue(dto.config.model),
240
+ thinking: stringConfigValue(dto.config.thinking),
241
+ };
242
+ }
243
+
244
+ function stringConfigValue(value: unknown): string | null {
245
+ return typeof value === 'string' && value.trim() ? value.trim() : null;
246
+ }