@hexabot-ai/api 3.2.2-alpha.14 → 3.2.2-alpha.16

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 (89) hide show
  1. package/dist/mcp/mcp-api.module.js +2 -2
  2. package/dist/mcp/mcp-api.module.js.map +1 -1
  3. package/dist/mcp/tools/catalog-mcp.tools.d.ts +63 -0
  4. package/dist/mcp/tools/catalog-mcp.tools.js +135 -0
  5. package/dist/mcp/tools/catalog-mcp.tools.js.map +1 -0
  6. package/dist/mcp/tools/cms-mcp.tools.d.ts +128 -0
  7. package/dist/mcp/tools/cms-mcp.tools.js +242 -0
  8. package/dist/mcp/tools/cms-mcp.tools.js.map +1 -0
  9. package/dist/mcp/tools/credential-mcp.tools.d.ts +19 -0
  10. package/dist/mcp/tools/credential-mcp.tools.js +82 -0
  11. package/dist/mcp/tools/credential-mcp.tools.js.map +1 -0
  12. package/dist/mcp/tools/hexabot-mcp-tool.base.d.ts +22 -0
  13. package/dist/mcp/tools/hexabot-mcp-tool.base.js +48 -0
  14. package/dist/mcp/tools/hexabot-mcp-tool.base.js.map +1 -0
  15. package/dist/mcp/tools/hexabot-mcp.schemas.d.ts +41 -0
  16. package/dist/mcp/tools/hexabot-mcp.schemas.js +36 -0
  17. package/dist/mcp/tools/hexabot-mcp.schemas.js.map +1 -0
  18. package/dist/mcp/tools/hexabot-mcp.tools.d.ts +1 -1329
  19. package/dist/mcp/tools/hexabot-mcp.tools.js +14 -1097
  20. package/dist/mcp/tools/hexabot-mcp.tools.js.map +1 -1
  21. package/dist/mcp/tools/hexabot-mcp.utils.d.ts +1 -0
  22. package/dist/mcp/tools/hexabot-mcp.utils.js +9 -0
  23. package/dist/mcp/tools/hexabot-mcp.utils.js.map +1 -0
  24. package/dist/mcp/tools/index.d.ts +22 -0
  25. package/dist/mcp/tools/index.js +50 -0
  26. package/dist/mcp/tools/index.js.map +1 -0
  27. package/dist/mcp/tools/mcp-server-mcp.tools.d.ts +77 -0
  28. package/dist/mcp/tools/mcp-server-mcp.tools.js +130 -0
  29. package/dist/mcp/tools/mcp-server-mcp.tools.js.map +1 -0
  30. package/dist/mcp/tools/memory-definition-mcp.tools.d.ts +57 -0
  31. package/dist/mcp/tools/memory-definition-mcp.tools.js +128 -0
  32. package/dist/mcp/tools/memory-definition-mcp.tools.js.map +1 -0
  33. package/dist/mcp/tools/workflow-mcp.helper.d.ts +141 -0
  34. package/dist/mcp/tools/workflow-mcp.helper.js +108 -0
  35. package/dist/mcp/tools/workflow-mcp.helper.js.map +1 -0
  36. package/dist/mcp/tools/workflow-mcp.tools.d.ts +468 -0
  37. package/dist/mcp/tools/workflow-mcp.tools.js +222 -0
  38. package/dist/mcp/tools/workflow-mcp.tools.js.map +1 -0
  39. package/dist/mcp/tools/workflow-run-mcp.tools.d.ts +347 -0
  40. package/dist/mcp/tools/workflow-run-mcp.tools.js +229 -0
  41. package/dist/mcp/tools/workflow-run-mcp.tools.js.map +1 -0
  42. package/dist/mcp/tools/workflow-version-mcp.tools.d.ts +230 -0
  43. package/dist/mcp/tools/workflow-version-mcp.tools.js +211 -0
  44. package/dist/mcp/tools/workflow-version-mcp.tools.js.map +1 -0
  45. package/dist/static/assets/{browser-ponyfill-D3QB7SUD.js → browser-ponyfill-CBXq65SP.js} +1 -1
  46. package/dist/static/assets/{cssMode-Bk0-m_Ij.js → cssMode-CN8f6H-j.js} +1 -1
  47. package/dist/static/assets/{freemarker2-D1tTqqt8.js → freemarker2-Dfrb95Lt.js} +1 -1
  48. package/dist/static/assets/{handlebars-D3VQYLDj.js → handlebars-B2cershf.js} +1 -1
  49. package/dist/static/assets/{html-Cmhr3-6_.js → html-CfjuUmTR.js} +1 -1
  50. package/dist/static/assets/{htmlMode-Bb5Kynv_.js → htmlMode-pl8CUTaA.js} +1 -1
  51. package/dist/static/assets/{index-JPQj6OiL.js → index-Cq8K5Poc.js} +2131 -2131
  52. package/dist/static/assets/{index-BI1BtkYv.css → index-D-b9KTZd.css} +1 -1
  53. package/dist/static/assets/{javascript-BkQdNyFT.js → javascript-Be45wN2i.js} +1 -1
  54. package/dist/static/assets/{jsonMode-CS1296LF.js → jsonMode-yPU1rg8t.js} +1 -1
  55. package/dist/static/assets/{liquid-C9ufUE-r.js → liquid-BMJibvBr.js} +1 -1
  56. package/dist/static/assets/{lspLanguageFeatures-Dxd2SsrE.js → lspLanguageFeatures-Cxz6b29K.js} +1 -1
  57. package/dist/static/assets/{mdx-Dm4bC48D.js → mdx-DpvXygi3.js} +1 -1
  58. package/dist/static/assets/{python-ZvBWpr_q.js → python-BHEnNcMm.js} +1 -1
  59. package/dist/static/assets/{razor-DBj-LyWR.js → razor-B6-tNhh_.js} +1 -1
  60. package/dist/static/assets/{tsMode-DzMlJB2i.js → tsMode-J4SJIY5C.js} +1 -1
  61. package/dist/static/assets/{typescript-Cfo3bzpy.js → typescript-Df82IAgp.js} +1 -1
  62. package/dist/static/assets/{xml-ZyceR0L3.js → xml-C8jr31yy.js} +1 -1
  63. package/dist/static/assets/{yaml-oyu_gOar.js → yaml-BEd1RzBW.js} +1 -1
  64. package/dist/static/index.html +2 -2
  65. package/dist/tsconfig.build.tsbuildinfo +1 -1
  66. package/dist/websocket/websocket.gateway.d.ts +2 -1
  67. package/dist/websocket/websocket.gateway.js.map +1 -1
  68. package/dist/workflow/services/workflow.service.d.ts +9 -8
  69. package/dist/workflow/services/workflow.service.js +50 -35
  70. package/dist/workflow/services/workflow.service.js.map +1 -1
  71. package/package.json +4 -4
  72. package/src/mcp/README.md +12 -2
  73. package/src/mcp/mcp-api.module.ts +2 -2
  74. package/src/mcp/tools/catalog-mcp.tools.ts +122 -0
  75. package/src/mcp/tools/cms-mcp.tools.ts +239 -0
  76. package/src/mcp/tools/credential-mcp.tools.ts +81 -0
  77. package/src/mcp/tools/hexabot-mcp-tool.base.ts +74 -0
  78. package/src/mcp/tools/hexabot-mcp.schemas.ts +55 -0
  79. package/src/mcp/tools/hexabot-mcp.tools.ts +1 -1194
  80. package/src/mcp/tools/hexabot-mcp.utils.ts +13 -0
  81. package/src/mcp/tools/index.ts +51 -0
  82. package/src/mcp/tools/mcp-server-mcp.tools.ts +135 -0
  83. package/src/mcp/tools/memory-definition-mcp.tools.ts +125 -0
  84. package/src/mcp/tools/workflow-mcp.helper.ts +166 -0
  85. package/src/mcp/tools/workflow-mcp.tools.ts +254 -0
  86. package/src/mcp/tools/workflow-run-mcp.tools.ts +274 -0
  87. package/src/mcp/tools/workflow-version-mcp.tools.ts +226 -0
  88. package/src/websocket/websocket.gateway.ts +2 -1
  89. package/src/workflow/services/workflow.service.ts +58 -30
@@ -0,0 +1,254 @@
1
+ /*
2
+ * Hexabot — Fair Core License (FCL-1.0-ALv2)
3
+ * Copyright (c) 2026 Hexastack.
4
+ * Full terms: see LICENSE.md.
5
+ */
6
+
7
+ import { Action } from '@hexabot-ai/types';
8
+ import {
9
+ BadRequestException,
10
+ Injectable,
11
+ NotFoundException,
12
+ } from '@nestjs/common';
13
+ import { Tool, ToolGuards } from '@rekog/mcp-nest';
14
+ import { z } from 'zod';
15
+
16
+ import { WorkflowOrmEntity } from '@/workflow/entities/workflow.entity';
17
+ import { WorkflowService } from '@/workflow/services/workflow.service';
18
+ import {
19
+ DirectionType,
20
+ WorkflowType,
21
+ WorkflowVersionAction,
22
+ } from '@/workflow/types';
23
+
24
+ import { McpPermission } from '../decorators/mcp-permission.decorator';
25
+ import { McpPermissionGuard } from '../guards/mcp-permission.guard';
26
+ import { HexabotMcpRequest } from '../types';
27
+
28
+ import { HexabotMcpToolBase } from './hexabot-mcp-tool.base';
29
+ import {
30
+ PaginationArgs,
31
+ paginationSchema,
32
+ uuidSchema,
33
+ workflowPayloadSchema,
34
+ } from './hexabot-mcp.schemas';
35
+ import { HexabotWorkflowMcpHelper } from './workflow-mcp.helper';
36
+
37
+ @Injectable()
38
+ export class HexabotWorkflowMcpTools extends HexabotMcpToolBase {
39
+ constructor(
40
+ private readonly workflowService: WorkflowService,
41
+ private readonly workflowHelper: HexabotWorkflowMcpHelper,
42
+ ) {
43
+ super();
44
+ }
45
+
46
+ @McpPermission('workflow', Action.READ)
47
+ @ToolGuards([McpPermissionGuard])
48
+ @Tool({
49
+ name: 'hexabot_workflow_search',
50
+ description: 'Search Hexabot workflows by metadata.',
51
+ parameters: z.object({
52
+ query: z.string().optional(),
53
+ type: z.enum(WorkflowType).optional(),
54
+ createdById: uuidSchema.optional(),
55
+ ...paginationSchema,
56
+ }),
57
+ })
58
+ async searchWorkflows(
59
+ args: {
60
+ query?: string;
61
+ type?: WorkflowType;
62
+ createdById?: string;
63
+ } & PaginationArgs,
64
+ ) {
65
+ const where = this.buildWorkflowWhere(args);
66
+ const options = this.findOptions<WorkflowOrmEntity>(args, where);
67
+
68
+ return await this.listWithCount(this.workflowService, options);
69
+ }
70
+
71
+ @McpPermission('workflow', Action.READ)
72
+ @ToolGuards([McpPermissionGuard])
73
+ @Tool({
74
+ name: 'hexabot_workflow_get',
75
+ description: 'Read a Hexabot workflow with populated version metadata.',
76
+ parameters: z.object({
77
+ id: uuidSchema,
78
+ }),
79
+ })
80
+ async getWorkflow(args: { id: string }) {
81
+ return await this.workflowHelper.requireWorkflow(args.id);
82
+ }
83
+
84
+ @McpPermission('workflow', Action.READ)
85
+ @ToolGuards([McpPermissionGuard])
86
+ @Tool({
87
+ name: 'hexabot_workflow_version_status',
88
+ description:
89
+ 'Check the current and published version pointers for one workflow.',
90
+ parameters: z.object({
91
+ id: uuidSchema,
92
+ }),
93
+ })
94
+ async getWorkflowVersionStatus(args: { id: string }) {
95
+ const workflow = await this.workflowHelper.requireWorkflow(args.id);
96
+
97
+ return this.workflowHelper.buildWorkflowVersionStatus(workflow);
98
+ }
99
+
100
+ @McpPermission('workflow', Action.CREATE)
101
+ @ToolGuards([McpPermissionGuard])
102
+ @Tool({
103
+ name: 'hexabot_workflow_create',
104
+ description:
105
+ 'Create a Hexabot workflow. Optionally commit an initial workflow definition YAML.',
106
+ parameters: z.object({
107
+ ...workflowPayloadSchema,
108
+ name: z.string().min(1),
109
+ definitionYml: z.string().optional(),
110
+ versionMessage: z.string().optional(),
111
+ }),
112
+ })
113
+ async createWorkflow(
114
+ args: {
115
+ name: string;
116
+ description?: string;
117
+ type?: WorkflowType;
118
+ schedule?: string | null;
119
+ inputSchema?: Record<string, unknown>;
120
+ builtin?: boolean;
121
+ x?: number;
122
+ y?: number;
123
+ zoom?: number;
124
+ direction?: DirectionType;
125
+ definitionYml?: string;
126
+ versionMessage?: string;
127
+ },
128
+ _context: unknown,
129
+ request?: HexabotMcpRequest,
130
+ ) {
131
+ const actorId = this.getActorId(request);
132
+ const { definitionYml, versionMessage, ...workflowPayload } = args;
133
+ const workflow = await this.workflowService.create({
134
+ ...workflowPayload,
135
+ createdBy: actorId,
136
+ });
137
+
138
+ if (definitionYml) {
139
+ await this.workflowHelper.commitWorkflowDefinition({
140
+ workflowId: workflow.id,
141
+ definitionYml,
142
+ message: versionMessage,
143
+ action: WorkflowVersionAction.update,
144
+ createdBy: actorId,
145
+ });
146
+ }
147
+
148
+ return await this.workflowHelper.requireWorkflow(workflow.id);
149
+ }
150
+
151
+ @McpPermission('workflow', Action.UPDATE)
152
+ @ToolGuards([McpPermissionGuard])
153
+ @Tool({
154
+ name: 'hexabot_workflow_update',
155
+ description:
156
+ 'Update workflow metadata. Optionally commit a new workflow definition YAML version.',
157
+ parameters: z.object({
158
+ id: uuidSchema,
159
+ ...workflowPayloadSchema,
160
+ definitionYml: z.string().optional(),
161
+ versionMessage: z.string().optional(),
162
+ }),
163
+ })
164
+ async updateWorkflow(
165
+ args: {
166
+ id: string;
167
+ definitionYml?: string;
168
+ versionMessage?: string;
169
+ } & Record<string, unknown>,
170
+ _context: unknown,
171
+ request?: HexabotMcpRequest,
172
+ ) {
173
+ const actorId = this.getActorId(request);
174
+ const { id, definitionYml, versionMessage, ...updates } = args;
175
+ await this.workflowHelper.requireWorkflow(id);
176
+
177
+ if (Object.keys(updates).length > 0) {
178
+ await this.workflowService.updateOne(id, updates as any);
179
+ }
180
+
181
+ if (definitionYml) {
182
+ await this.workflowHelper.commitWorkflowDefinition({
183
+ workflowId: id,
184
+ definitionYml,
185
+ message: versionMessage,
186
+ action: WorkflowVersionAction.update,
187
+ createdBy: actorId,
188
+ });
189
+ }
190
+
191
+ return await this.workflowHelper.requireWorkflow(id);
192
+ }
193
+
194
+ @McpPermission('workflow', Action.UPDATE)
195
+ @ToolGuards([McpPermissionGuard])
196
+ @Tool({
197
+ name: 'hexabot_workflow_publish',
198
+ description: 'Publish the current workflow version.',
199
+ parameters: z.object({
200
+ id: uuidSchema,
201
+ }),
202
+ })
203
+ async publishWorkflow(args: { id: string }) {
204
+ const workflow = await this.workflowService.findOne(args.id);
205
+ if (!workflow) {
206
+ throw new NotFoundException(`Workflow ${args.id} not found`);
207
+ }
208
+ if (!workflow.currentVersion) {
209
+ throw new BadRequestException(
210
+ 'Workflow must have a current version to be published',
211
+ );
212
+ }
213
+
214
+ await this.workflowService.updateOne(args.id, {
215
+ publishedVersion: workflow.currentVersion,
216
+ });
217
+
218
+ return await this.workflowHelper.requireWorkflow(args.id);
219
+ }
220
+
221
+ @McpPermission('workflow', Action.UPDATE)
222
+ @ToolGuards([McpPermissionGuard])
223
+ @Tool({
224
+ name: 'hexabot_workflow_unpublish',
225
+ description: 'Clear the published workflow version.',
226
+ parameters: z.object({
227
+ id: uuidSchema,
228
+ }),
229
+ })
230
+ async unpublishWorkflow(args: { id: string }) {
231
+ await this.workflowHelper.requireWorkflow(args.id);
232
+ await this.workflowService.updateOne(args.id, { publishedVersion: null });
233
+
234
+ return await this.workflowHelper.requireWorkflow(args.id);
235
+ }
236
+
237
+ private buildWorkflowWhere(args: {
238
+ query?: string;
239
+ type?: WorkflowType;
240
+ createdById?: string;
241
+ }) {
242
+ const base = {
243
+ ...(args.type ? { type: args.type } : {}),
244
+ ...(args.createdById ? { createdBy: { id: args.createdById } } : {}),
245
+ };
246
+
247
+ return args.query
248
+ ? [
249
+ { ...base, name: this.contains(args.query) },
250
+ { ...base, description: this.contains(args.query) },
251
+ ]
252
+ : base;
253
+ }
254
+ }
@@ -0,0 +1,274 @@
1
+ /*
2
+ * Hexabot — Fair Core License (FCL-1.0-ALv2)
3
+ * Copyright (c) 2026 Hexastack.
4
+ * Full terms: see LICENSE.md.
5
+ */
6
+
7
+ import {
8
+ EWorkflowRunStatus,
9
+ type StepExecutionRecord,
10
+ type WorkflowRunStatus,
11
+ } from '@hexabot-ai/agentic';
12
+ import { Action, type WorkflowRunFull } from '@hexabot-ai/types';
13
+ import {
14
+ BadRequestException,
15
+ Injectable,
16
+ NotFoundException,
17
+ } from '@nestjs/common';
18
+ import { Tool, ToolGuards } from '@rekog/mcp-nest';
19
+ import { z } from 'zod';
20
+
21
+ import { WorkflowRunOrmEntity } from '@/workflow/entities/workflow-run.entity';
22
+ import {
23
+ ManualEventWrapper,
24
+ ScheduledEventWrapper,
25
+ } from '@/workflow/lib/trigger-event-wrapper';
26
+ import { AgenticService } from '@/workflow/services/agentic.service';
27
+ import { WorkflowRunService } from '@/workflow/services/workflow-run.service';
28
+ import { WorkflowService } from '@/workflow/services/workflow.service';
29
+ import { WorkflowType } from '@/workflow/types';
30
+
31
+ import { McpPermission } from '../decorators/mcp-permission.decorator';
32
+ import { McpPermissionGuard } from '../guards/mcp-permission.guard';
33
+ import { HexabotMcpRequest } from '../types';
34
+
35
+ import { HexabotMcpToolBase } from './hexabot-mcp-tool.base';
36
+ import {
37
+ jsonObjectSchema,
38
+ PaginationArgs,
39
+ paginationSchema,
40
+ uuidSchema,
41
+ } from './hexabot-mcp.schemas';
42
+
43
+ @Injectable()
44
+ export class HexabotWorkflowRunMcpTools extends HexabotMcpToolBase {
45
+ constructor(
46
+ private readonly workflowService: WorkflowService,
47
+ private readonly workflowRunService: WorkflowRunService,
48
+ private readonly agenticService: AgenticService,
49
+ ) {
50
+ super();
51
+ }
52
+
53
+ @McpPermission('workflowrun', Action.CREATE)
54
+ @ToolGuards([McpPermissionGuard])
55
+ @Tool({
56
+ name: 'hexabot_workflow_run',
57
+ description:
58
+ 'Run a manual or scheduled workflow and return the run summary.',
59
+ parameters: z.object({
60
+ workflowId: uuidSchema,
61
+ input: jsonObjectSchema.default({}),
62
+ }),
63
+ })
64
+ async runWorkflow(
65
+ args: { workflowId: string; input: Record<string, unknown> },
66
+ _context: unknown,
67
+ request?: HexabotMcpRequest,
68
+ ) {
69
+ const actor = this.getActor(request);
70
+ const workflow = await this.workflowService.findOne(args.workflowId);
71
+ if (!workflow) {
72
+ throw new NotFoundException(`Workflow ${args.workflowId} not found`);
73
+ }
74
+
75
+ if (
76
+ workflow.type !== WorkflowType.manual &&
77
+ workflow.type !== WorkflowType.scheduled
78
+ ) {
79
+ throw new BadRequestException(
80
+ 'Workflow must be manual or scheduled to run manually',
81
+ );
82
+ }
83
+
84
+ const event =
85
+ workflow.type === WorkflowType.scheduled
86
+ ? new ScheduledEventWrapper({
87
+ schedule: workflow.schedule ?? null,
88
+ triggeredAt: new Date(),
89
+ })
90
+ : new ManualEventWrapper(
91
+ this.workflowService.validateManualInput(
92
+ args.input ?? {},
93
+ workflow.inputSchema,
94
+ ),
95
+ actor.id,
96
+ );
97
+ event.setInitiator(actor);
98
+ event.setWorkflowId(workflow.id);
99
+
100
+ const run = await this.agenticService.handleEvent(event);
101
+
102
+ return { accepted: true, run };
103
+ }
104
+
105
+ @McpPermission('workflowrun', Action.READ)
106
+ @ToolGuards([McpPermissionGuard])
107
+ @Tool({
108
+ name: 'hexabot_workflow_run_search',
109
+ description: 'Search workflow runs by workflow and status.',
110
+ parameters: z.object({
111
+ workflowId: uuidSchema.optional(),
112
+ status: z.string().optional(),
113
+ ...paginationSchema,
114
+ }),
115
+ })
116
+ async searchWorkflowRuns(
117
+ args: { workflowId?: string; status?: string } & PaginationArgs,
118
+ ) {
119
+ const where = {
120
+ ...(args.workflowId ? { workflow: { id: args.workflowId } } : {}),
121
+ ...(args.status ? { status: args.status } : {}),
122
+ } as any;
123
+
124
+ return await this.listWithCount(
125
+ this.workflowRunService,
126
+ this.findOptions<WorkflowRunOrmEntity>(args, where),
127
+ );
128
+ }
129
+
130
+ @McpPermission('workflowrun', Action.READ)
131
+ @ToolGuards([McpPermissionGuard])
132
+ @Tool({
133
+ name: 'hexabot_workflow_run_get',
134
+ description: 'Read one workflow run with populated workflow metadata.',
135
+ parameters: z.object({
136
+ id: uuidSchema,
137
+ }),
138
+ })
139
+ async getWorkflowRun(args: { id: string }) {
140
+ const run = await this.workflowRunService.findOneAndPopulate(args.id);
141
+ if (!run) {
142
+ throw new NotFoundException(`Workflow run ${args.id} not found`);
143
+ }
144
+
145
+ return run;
146
+ }
147
+
148
+ @McpPermission('workflowrun', Action.READ)
149
+ @ToolGuards([McpPermissionGuard])
150
+ @Tool({
151
+ name: 'hexabot_workflow_run_debug',
152
+ description:
153
+ 'Inspect one workflow run for debugging with execution state, workflow YAML, and related parent/child runs.',
154
+ parameters: z.object({
155
+ id: uuidSchema,
156
+ includeWorkflowDefinition: z.boolean().default(true),
157
+ includeRelatedRuns: z.boolean().default(true),
158
+ childRunsLimit: z.number().int().min(1).max(50).default(10),
159
+ }),
160
+ })
161
+ async debugWorkflowRun(args: {
162
+ id: string;
163
+ includeWorkflowDefinition?: boolean;
164
+ includeRelatedRuns?: boolean;
165
+ childRunsLimit?: number;
166
+ }) {
167
+ const run = await this.workflowRunService.findOneAndPopulate(args.id);
168
+ if (!run) {
169
+ throw new NotFoundException(`Workflow run ${args.id} not found`);
170
+ }
171
+
172
+ const includeRelatedRuns = args.includeRelatedRuns ?? true;
173
+ const childRunsLimit = args.childRunsLimit ?? 10;
174
+ const parentRunId = this.resolveRelationId(run.parentRun);
175
+ const childWhere = { parentRun: { id: run.id } } as any;
176
+ const [parentRun, childRuns, childRunTotal] = includeRelatedRuns
177
+ ? await Promise.all([
178
+ parentRunId
179
+ ? this.workflowRunService.findOneAndPopulate(parentRunId)
180
+ : Promise.resolve(null),
181
+ this.workflowRunService.findAndPopulate({
182
+ where: childWhere,
183
+ order: { createdAt: 'ASC' },
184
+ take: childRunsLimit,
185
+ }),
186
+ this.workflowRunService.count({ where: childWhere }),
187
+ ])
188
+ : ([null, [], 0] as const);
189
+ const response: Record<string, unknown> = {
190
+ run,
191
+ relatedRuns: {
192
+ parent: parentRun,
193
+ children: childRuns,
194
+ childRunTotal,
195
+ childRunsLimit: includeRelatedRuns ? childRunsLimit : 0,
196
+ },
197
+ summary: this.buildWorkflowRunDebugSummary(run, childRunTotal),
198
+ };
199
+
200
+ if (args.includeWorkflowDefinition ?? true) {
201
+ response.workflowDefinitionYml =
202
+ run.workflowVersion?.definitionYml ?? null;
203
+ }
204
+
205
+ return response;
206
+ }
207
+
208
+ private buildWorkflowRunDebugSummary(
209
+ run: WorkflowRunFull,
210
+ childRunTotal: number,
211
+ ) {
212
+ const stepEntries = Object.entries(run.stepLog ?? {}) as [
213
+ string,
214
+ StepExecutionRecord,
215
+ ][];
216
+ const stepStatusCounts = stepEntries.reduce<Record<string, number>>(
217
+ (counts, [, step]) => ({
218
+ ...counts,
219
+ [step.status]: (counts[step.status] ?? 0) + 1,
220
+ }),
221
+ {},
222
+ );
223
+ const failedSteps = stepEntries
224
+ .filter(
225
+ ([, step]) =>
226
+ step.status === EWorkflowRunStatus.FAILED || Boolean(step.error),
227
+ )
228
+ .map(([stepId, step]) => ({
229
+ id: step.id ?? stepId,
230
+ name: step.name ?? stepId,
231
+ action: step.action ?? null,
232
+ status: step.status,
233
+ error: step.error ?? null,
234
+ reason: step.reason ?? null,
235
+ }));
236
+
237
+ return {
238
+ id: run.id,
239
+ status: run.status as WorkflowRunStatus,
240
+ workflow: {
241
+ id: run.workflow.id,
242
+ name: run.workflow.name,
243
+ type: run.workflow.type,
244
+ },
245
+ workflowVersion: run.workflowVersion
246
+ ? {
247
+ id: run.workflowVersion.id,
248
+ version: run.workflowVersion.version,
249
+ checksum: run.workflowVersion.checksum,
250
+ }
251
+ : null,
252
+ error: run.error ?? null,
253
+ duration: run.duration ?? null,
254
+ createdAt: run.createdAt,
255
+ updatedAt: run.updatedAt,
256
+ suspendedAt: run.suspendedAt ?? null,
257
+ finishedAt: run.finishedAt ?? null,
258
+ failedAt: run.failedAt ?? null,
259
+ suspension:
260
+ run.status === EWorkflowRunStatus.SUSPENDED
261
+ ? {
262
+ step: run.suspendedStep ?? null,
263
+ reason: run.suspensionReason ?? null,
264
+ stepExecId: run.suspensionStepExecId ?? null,
265
+ index: run.suspensionIndex ?? null,
266
+ key: run.suspensionKey ?? null,
267
+ }
268
+ : null,
269
+ stepStatusCounts,
270
+ failedSteps,
271
+ childRunTotal,
272
+ };
273
+ }
274
+ }