@shipfox/client-workflows 5.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 (121) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +53 -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 +13 -0
  50. package/dist/feature.d.ts.map +1 -1
  51. package/dist/feature.js +17 -16
  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 +2 -2
  62. package/dist/index.d.ts.map +1 -1
  63. package/dist/index.js +1 -1
  64. package/dist/index.js.map +1 -1
  65. package/dist/pages/project-workflows-page.d.ts.map +1 -1
  66. package/dist/pages/project-workflows-page.js +14 -14
  67. package/dist/pages/project-workflows-page.js.map +1 -1
  68. package/dist/pages/workflow-run-page.d.ts +3 -1
  69. package/dist/pages/workflow-run-page.d.ts.map +1 -1
  70. package/dist/pages/workflow-run-page.js +21 -14
  71. package/dist/pages/workflow-run-page.js.map +1 -1
  72. package/dist/routes/inputs.d.ts +22 -0
  73. package/dist/routes/inputs.d.ts.map +1 -0
  74. package/dist/routes/inputs.js +76 -0
  75. package/dist/routes/inputs.js.map +1 -0
  76. package/dist/routes/run-detail.d.ts +2 -0
  77. package/dist/routes/run-detail.d.ts.map +1 -1
  78. package/dist/routes/run-detail.js +6 -6
  79. package/dist/routes/run-detail.js.map +1 -1
  80. package/dist/routes/runs.d.ts +2 -0
  81. package/dist/routes/runs.d.ts.map +1 -1
  82. package/dist/routes/runs.js +6 -6
  83. package/dist/routes/runs.js.map +1 -1
  84. package/dist/routes/workflows.js +3 -5
  85. package/dist/routes/workflows.js.map +1 -1
  86. package/dist/tsconfig.test.tsbuildinfo +1 -1
  87. package/package.json +13 -14
  88. package/src/components/workflow-run-list/types.ts +6 -0
  89. package/src/components/workflow-run-list/workflow-run-list-view.tsx +27 -11
  90. package/src/components/workflow-run-list/workflow-run-list.tsx +6 -0
  91. package/src/components/workflow-run-summary/workflow-run-attempt-switcher.test.tsx +5 -6
  92. package/src/components/workflow-run-summary/workflow-run-summary.tsx +3 -3
  93. package/src/components/workflow-run-view/job-card.tsx +20 -11
  94. package/src/components/workflow-run-view/workflow-run-view.test.tsx +3 -3
  95. package/src/components/workflow-run-view/workflow-run-view.tsx +2 -2
  96. package/src/core/entities/job-execution.ts +12 -28
  97. package/src/core/entities/job.ts +44 -45
  98. package/src/core/entities/step-attempt.ts +9 -20
  99. package/src/core/entities/step.ts +38 -66
  100. package/src/core/entities/workflow-run-attempt.ts +0 -14
  101. package/src/core/entities/workflow-run.ts +8 -86
  102. package/src/core/workflow-run.test.ts +13 -11
  103. package/src/core/workflow-run.ts +8 -13
  104. package/src/feature.ts +19 -17
  105. package/src/hooks/api/workflow-run-mapper.ts +246 -0
  106. package/src/hooks/api/workflow-runs.test.tsx +57 -59
  107. package/src/hooks/api/workflow-runs.ts +187 -88
  108. package/src/index.ts +4 -0
  109. package/src/pages/project-workflows-page.test.tsx +1 -1
  110. package/src/pages/project-workflows-page.tsx +31 -26
  111. package/src/pages/workflow-run-page.test.tsx +4 -2
  112. package/src/pages/workflow-run-page.tsx +22 -17
  113. package/src/routes/inputs.test.ts +22 -0
  114. package/src/routes/inputs.ts +58 -0
  115. package/src/routes/run-detail.tsx +12 -8
  116. package/src/routes/runs.tsx +11 -4
  117. package/src/routes/workflows.tsx +3 -3
  118. package/test/fixtures/workflow-run.ts +9 -7
  119. package/test/pages.tsx +20 -5
  120. package/tsconfig.build.tsbuildinfo +1 -1
  121. package/vercel.json +5 -0
@@ -1,4 +1,3 @@
1
- import type {WorkflowRunAttemptDto} from '@shipfox/api-workflows-dto';
2
1
  import {type Duration, intervalToDuration} from 'date-fns';
3
2
  import type {WorkflowRunStatus} from './workflow-run.js';
4
3
 
@@ -48,19 +47,6 @@ export class WorkflowRunAttempt extends WorkflowRunAttemptSummary {
48
47
  }
49
48
  }
50
49
 
51
- export function toWorkflowRunAttempt(dto: WorkflowRunAttemptDto): WorkflowRunAttempt {
52
- return new WorkflowRunAttempt({
53
- id: dto.id,
54
- workflowRunId: dto.workflow_run_id,
55
- attempt: dto.attempt,
56
- status: dto.status,
57
- createdAt: dto.created_at,
58
- startedAt: dto.started_at ?? null,
59
- finishedAt: dto.finished_at ?? null,
60
- rerunMode: dto.rerun_mode,
61
- });
62
- }
63
-
64
50
  export function workflowRunAttemptDisplayDurationFromTimestamps({
65
51
  startedAt,
66
52
  finishedAt,
@@ -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,4 +1,21 @@
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',
@@ -19,20 +36,5 @@ export const workflowsFeature = defineClientFeature({
19
36
  impl: '@shipfox/client-workflows/routes/run-detail',
20
37
  },
21
38
  ],
22
- navigation: [
23
- {
24
- id: 'nav.runs',
25
- scope: 'project',
26
- label: 'Runs',
27
- to: '/workspaces/$wid/projects/$pid/runs',
28
- order: 100,
29
- },
30
- {
31
- id: 'nav.workflows',
32
- scope: 'project',
33
- label: 'Workflows',
34
- to: '/workspaces/$wid/projects/$pid/workflows',
35
- order: 200,
36
- },
37
- ],
39
+ navigation: workflowsNavigation,
38
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
+ }