@herdctl/core 0.0.2 → 0.2.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 (101) hide show
  1. package/LICENSE +21 -0
  2. package/dist/config/__tests__/agent.test.js +30 -0
  3. package/dist/config/__tests__/agent.test.js.map +1 -1
  4. package/dist/config/__tests__/merge.test.js +1 -1
  5. package/dist/config/__tests__/merge.test.js.map +1 -1
  6. package/dist/config/index.d.ts +1 -1
  7. package/dist/config/index.d.ts.map +1 -1
  8. package/dist/config/index.js +3 -1
  9. package/dist/config/index.js.map +1 -1
  10. package/dist/config/schema.d.ts +1005 -3
  11. package/dist/config/schema.d.ts.map +1 -1
  12. package/dist/config/schema.js +87 -4
  13. package/dist/config/schema.js.map +1 -1
  14. package/dist/fleet-manager/__tests__/coverage.test.js +6 -2
  15. package/dist/fleet-manager/__tests__/coverage.test.js.map +1 -1
  16. package/dist/fleet-manager/__tests__/integration.test.js +5 -0
  17. package/dist/fleet-manager/__tests__/integration.test.js.map +1 -1
  18. package/dist/fleet-manager/__tests__/job-control.test.js +13 -14
  19. package/dist/fleet-manager/__tests__/job-control.test.js.map +1 -1
  20. package/dist/fleet-manager/__tests__/reload.test.js +13 -3
  21. package/dist/fleet-manager/__tests__/reload.test.js.map +1 -1
  22. package/dist/fleet-manager/__tests__/status-queries.test.js +6 -0
  23. package/dist/fleet-manager/__tests__/status-queries.test.js.map +1 -1
  24. package/dist/fleet-manager/__tests__/trigger.test.js +10 -2
  25. package/dist/fleet-manager/__tests__/trigger.test.js.map +1 -1
  26. package/dist/fleet-manager/config-reload.d.ts +1 -1
  27. package/dist/fleet-manager/config-reload.js +1 -1
  28. package/dist/fleet-manager/fleet-manager.d.ts +1 -0
  29. package/dist/fleet-manager/fleet-manager.d.ts.map +1 -1
  30. package/dist/fleet-manager/fleet-manager.js +1 -0
  31. package/dist/fleet-manager/fleet-manager.js.map +1 -1
  32. package/dist/fleet-manager/job-control.d.ts +41 -0
  33. package/dist/fleet-manager/job-control.d.ts.map +1 -1
  34. package/dist/fleet-manager/job-control.js +243 -20
  35. package/dist/fleet-manager/job-control.js.map +1 -1
  36. package/dist/fleet-manager/schedule-executor.d.ts +20 -0
  37. package/dist/fleet-manager/schedule-executor.d.ts.map +1 -1
  38. package/dist/fleet-manager/schedule-executor.js +113 -3
  39. package/dist/fleet-manager/schedule-executor.js.map +1 -1
  40. package/dist/fleet-manager/types.d.ts +18 -0
  41. package/dist/fleet-manager/types.d.ts.map +1 -1
  42. package/dist/hooks/__tests__/discord-runner.test.d.ts +5 -0
  43. package/dist/hooks/__tests__/discord-runner.test.d.ts.map +1 -0
  44. package/dist/hooks/__tests__/discord-runner.test.js +606 -0
  45. package/dist/hooks/__tests__/discord-runner.test.js.map +1 -0
  46. package/dist/hooks/__tests__/hook-executor.test.d.ts +5 -0
  47. package/dist/hooks/__tests__/hook-executor.test.d.ts.map +1 -0
  48. package/dist/hooks/__tests__/hook-executor.test.js +443 -0
  49. package/dist/hooks/__tests__/hook-executor.test.js.map +1 -0
  50. package/dist/hooks/__tests__/shell-runner.test.d.ts +5 -0
  51. package/dist/hooks/__tests__/shell-runner.test.d.ts.map +1 -0
  52. package/dist/hooks/__tests__/shell-runner.test.js +201 -0
  53. package/dist/hooks/__tests__/shell-runner.test.js.map +1 -0
  54. package/dist/hooks/__tests__/webhook-runner.test.d.ts +5 -0
  55. package/dist/hooks/__tests__/webhook-runner.test.d.ts.map +1 -0
  56. package/dist/hooks/__tests__/webhook-runner.test.js +453 -0
  57. package/dist/hooks/__tests__/webhook-runner.test.js.map +1 -0
  58. package/dist/hooks/hook-executor.d.ts +129 -0
  59. package/dist/hooks/hook-executor.d.ts.map +1 -0
  60. package/dist/hooks/hook-executor.js +195 -0
  61. package/dist/hooks/hook-executor.js.map +1 -0
  62. package/dist/hooks/index.d.ts +15 -0
  63. package/dist/hooks/index.d.ts.map +1 -0
  64. package/dist/hooks/index.js +18 -0
  65. package/dist/hooks/index.js.map +1 -0
  66. package/dist/hooks/runners/discord.d.ts +66 -0
  67. package/dist/hooks/runners/discord.d.ts.map +1 -0
  68. package/dist/hooks/runners/discord.js +294 -0
  69. package/dist/hooks/runners/discord.js.map +1 -0
  70. package/dist/hooks/runners/shell.d.ts +71 -0
  71. package/dist/hooks/runners/shell.d.ts.map +1 -0
  72. package/dist/hooks/runners/shell.js +177 -0
  73. package/dist/hooks/runners/shell.js.map +1 -0
  74. package/dist/hooks/runners/webhook.d.ts +66 -0
  75. package/dist/hooks/runners/webhook.d.ts.map +1 -0
  76. package/dist/hooks/runners/webhook.js +163 -0
  77. package/dist/hooks/runners/webhook.js.map +1 -0
  78. package/dist/hooks/types.d.ts +196 -0
  79. package/dist/hooks/types.d.ts.map +1 -0
  80. package/dist/hooks/types.js +12 -0
  81. package/dist/hooks/types.js.map +1 -0
  82. package/dist/index.d.ts +1 -0
  83. package/dist/index.d.ts.map +1 -1
  84. package/dist/index.js +2 -0
  85. package/dist/index.js.map +1 -1
  86. package/dist/runner/__tests__/sdk-adapter.test.js +4 -3
  87. package/dist/runner/__tests__/sdk-adapter.test.js.map +1 -1
  88. package/dist/runner/message-processor.d.ts +5 -1
  89. package/dist/runner/message-processor.d.ts.map +1 -1
  90. package/dist/runner/message-processor.js +238 -18
  91. package/dist/runner/message-processor.js.map +1 -1
  92. package/dist/runner/sdk-adapter.d.ts.map +1 -1
  93. package/dist/runner/sdk-adapter.js +8 -1
  94. package/dist/runner/sdk-adapter.js.map +1 -1
  95. package/dist/runner/types.d.ts +23 -2
  96. package/dist/runner/types.d.ts.map +1 -1
  97. package/dist/scheduler/scheduler.d.ts.map +1 -1
  98. package/dist/scheduler/scheduler.js +9 -0
  99. package/dist/scheduler/scheduler.js.map +1 -1
  100. package/dist/state/schemas/job-metadata.d.ts +4 -4
  101. package/package.json +1 -1
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Discord Hook Runner
3
+ *
4
+ * Posts job notifications to a Discord channel using embeds.
5
+ * Used for team visibility into fleet activity.
6
+ */
7
+ /**
8
+ * Default timeout for Discord API requests in milliseconds
9
+ */
10
+ const DEFAULT_TIMEOUT = 10000;
11
+ /**
12
+ * Maximum output length to include in embed (Discord has a 4096 char limit for embed descriptions)
13
+ */
14
+ const MAX_OUTPUT_LENGTH = 1000;
15
+ /**
16
+ * Embed colors for different event types
17
+ */
18
+ const EMBED_COLORS = {
19
+ completed: 0x22c55e, // green
20
+ failed: 0xef4444, // red
21
+ timeout: 0xf59e0b, // amber
22
+ cancelled: 0x6b7280, // gray
23
+ };
24
+ /**
25
+ * Truncates a string to a maximum length, adding ellipsis if truncated
26
+ */
27
+ function truncateOutput(output, maxLength) {
28
+ if (output.length <= maxLength) {
29
+ return output;
30
+ }
31
+ return output.slice(0, maxLength - 3) + "...";
32
+ }
33
+ /**
34
+ * Formats duration in milliseconds to a human-readable string
35
+ */
36
+ function formatDuration(ms) {
37
+ if (ms < 1000) {
38
+ return `${ms}ms`;
39
+ }
40
+ const seconds = Math.floor(ms / 1000);
41
+ if (seconds < 60) {
42
+ return `${seconds}s`;
43
+ }
44
+ const minutes = Math.floor(seconds / 60);
45
+ const remainingSeconds = seconds % 60;
46
+ if (minutes < 60) {
47
+ return remainingSeconds > 0 ? `${minutes}m ${remainingSeconds}s` : `${minutes}m`;
48
+ }
49
+ const hours = Math.floor(minutes / 60);
50
+ const remainingMinutes = minutes % 60;
51
+ return remainingMinutes > 0 ? `${hours}h ${remainingMinutes}m` : `${hours}h`;
52
+ }
53
+ /**
54
+ * Gets the title emoji and text for the event
55
+ */
56
+ function getEventTitle(event) {
57
+ switch (event) {
58
+ case "completed":
59
+ return "✅ Job Completed";
60
+ case "failed":
61
+ return "❌ Job Failed";
62
+ case "timeout":
63
+ return "⏱️ Job Timed Out";
64
+ case "cancelled":
65
+ return "🚫 Job Cancelled";
66
+ default:
67
+ return "📋 Job Event";
68
+ }
69
+ }
70
+ /**
71
+ * Builds a Discord embed from the hook context
72
+ */
73
+ function buildEmbed(context) {
74
+ const fields = [
75
+ {
76
+ name: "Agent",
77
+ value: context.agent.name || context.agent.id,
78
+ inline: true,
79
+ },
80
+ {
81
+ name: "Job ID",
82
+ value: `\`${context.job.id}\``,
83
+ inline: true,
84
+ },
85
+ {
86
+ name: "Duration",
87
+ value: formatDuration(context.job.durationMs),
88
+ inline: true,
89
+ },
90
+ ];
91
+ // Add schedule name if present
92
+ if (context.job.scheduleName) {
93
+ fields.push({
94
+ name: "Schedule",
95
+ value: context.job.scheduleName,
96
+ inline: true,
97
+ });
98
+ }
99
+ // Add error message if present
100
+ if (context.result.error) {
101
+ fields.push({
102
+ name: "Error",
103
+ value: `\`\`\`\n${truncateOutput(context.result.error, 500)}\n\`\`\``,
104
+ inline: false,
105
+ });
106
+ }
107
+ // Add metadata JSON if present
108
+ if (context.metadata && Object.keys(context.metadata).length > 0) {
109
+ fields.push({
110
+ name: "Metadata",
111
+ value: `\`\`\`json\n${truncateOutput(JSON.stringify(context.metadata, null, 2), MAX_OUTPUT_LENGTH)}\n\`\`\``,
112
+ inline: false,
113
+ });
114
+ }
115
+ // Add output preview if present and meaningful
116
+ const output = context.result.output.trim();
117
+ if (output && output.length > 0) {
118
+ fields.push({
119
+ name: "Output",
120
+ value: `\`\`\`\n${truncateOutput(output, MAX_OUTPUT_LENGTH)}\n\`\`\``,
121
+ inline: false,
122
+ });
123
+ }
124
+ return {
125
+ title: getEventTitle(context.event),
126
+ color: EMBED_COLORS[context.event] ?? EMBED_COLORS.completed,
127
+ fields,
128
+ timestamp: context.job.completedAt,
129
+ footer: {
130
+ text: "herdctl",
131
+ },
132
+ };
133
+ }
134
+ /**
135
+ * DiscordHookRunner posts job notifications to a Discord channel
136
+ *
137
+ * @example
138
+ * ```typescript
139
+ * const runner = new DiscordHookRunner({ logger: console });
140
+ *
141
+ * const result = await runner.execute(
142
+ * {
143
+ * type: 'discord',
144
+ * channel_id: '1234567890',
145
+ * bot_token_env: 'DISCORD_BOT_TOKEN'
146
+ * },
147
+ * hookContext
148
+ * );
149
+ *
150
+ * if (result.success) {
151
+ * console.log('Discord notification sent');
152
+ * } else {
153
+ * console.error('Discord notification failed:', result.error);
154
+ * }
155
+ * ```
156
+ */
157
+ export class DiscordHookRunner {
158
+ logger;
159
+ fetchFn;
160
+ constructor(options = {}) {
161
+ this.logger = options.logger ?? {
162
+ debug: () => { },
163
+ info: () => { },
164
+ warn: () => { },
165
+ error: () => { },
166
+ };
167
+ this.fetchFn = options.fetch ?? globalThis.fetch;
168
+ }
169
+ /**
170
+ * Execute a Discord hook with the given context
171
+ *
172
+ * @param config - Discord hook configuration (accepts input type with optional fields)
173
+ * @param context - Hook context to send in the notification
174
+ * @returns Promise resolving to the hook result
175
+ */
176
+ async execute(config, context) {
177
+ const startTime = Date.now();
178
+ this.logger.debug(`Executing Discord hook for channel: ${config.channel_id}`);
179
+ // Read bot token from environment variable
180
+ const botToken = process.env[config.bot_token_env];
181
+ if (!botToken) {
182
+ const durationMs = Date.now() - startTime;
183
+ const errorMessage = `Discord bot token not found in environment variable: ${config.bot_token_env}`;
184
+ this.logger.error(errorMessage);
185
+ return {
186
+ success: false,
187
+ hookType: "discord",
188
+ durationMs,
189
+ error: errorMessage,
190
+ };
191
+ }
192
+ try {
193
+ // Build the Discord embed
194
+ const embed = buildEmbed(context);
195
+ const payload = {
196
+ embeds: [embed],
197
+ };
198
+ // Discord API endpoint for posting messages
199
+ const url = `https://discord.com/api/v10/channels/${config.channel_id}/messages`;
200
+ // Create abort controller for timeout
201
+ const controller = new AbortController();
202
+ const timeoutId = setTimeout(() => controller.abort(), DEFAULT_TIMEOUT);
203
+ try {
204
+ const response = await this.fetchFn(url, {
205
+ method: "POST",
206
+ headers: {
207
+ "Content-Type": "application/json",
208
+ Authorization: `Bot ${botToken}`,
209
+ },
210
+ body: JSON.stringify(payload),
211
+ signal: controller.signal,
212
+ });
213
+ clearTimeout(timeoutId);
214
+ const durationMs = Date.now() - startTime;
215
+ // Read response body for logging/debugging
216
+ let responseBody;
217
+ try {
218
+ responseBody = await response.text();
219
+ }
220
+ catch {
221
+ // Ignore response body read errors
222
+ }
223
+ // 2xx status codes are success
224
+ if (response.ok) {
225
+ this.logger.info(`Discord hook completed successfully in ${durationMs}ms: channel ${config.channel_id} (${response.status})`);
226
+ return {
227
+ success: true,
228
+ hookType: "discord",
229
+ durationMs,
230
+ output: responseBody,
231
+ };
232
+ }
233
+ else {
234
+ // Parse Discord API error
235
+ let errorDetail = `HTTP ${response.status}: ${response.statusText}`;
236
+ if (responseBody) {
237
+ try {
238
+ const errorJson = JSON.parse(responseBody);
239
+ if (errorJson.message) {
240
+ errorDetail = `Discord API error: ${errorJson.message} (code: ${errorJson.code || response.status})`;
241
+ }
242
+ }
243
+ catch {
244
+ errorDetail += ` - ${responseBody}`;
245
+ }
246
+ }
247
+ this.logger.warn(`Discord hook failed with status ${response.status}: ${errorDetail}`);
248
+ return {
249
+ success: false,
250
+ hookType: "discord",
251
+ durationMs,
252
+ error: errorDetail,
253
+ output: responseBody,
254
+ };
255
+ }
256
+ }
257
+ catch (fetchError) {
258
+ clearTimeout(timeoutId);
259
+ const durationMs = Date.now() - startTime;
260
+ // Handle abort (timeout)
261
+ if (fetchError instanceof Error && fetchError.name === "AbortError") {
262
+ this.logger.error(`Discord hook timed out after ${DEFAULT_TIMEOUT}ms`);
263
+ return {
264
+ success: false,
265
+ hookType: "discord",
266
+ durationMs,
267
+ error: `Discord hook timed out after ${DEFAULT_TIMEOUT}ms`,
268
+ };
269
+ }
270
+ // Handle other fetch errors (network errors, etc.)
271
+ const errorMessage = fetchError instanceof Error ? fetchError.message : String(fetchError);
272
+ this.logger.error(`Discord hook error: ${errorMessage}`);
273
+ return {
274
+ success: false,
275
+ hookType: "discord",
276
+ durationMs,
277
+ error: errorMessage,
278
+ };
279
+ }
280
+ }
281
+ catch (error) {
282
+ const durationMs = Date.now() - startTime;
283
+ const errorMessage = error instanceof Error ? error.message : String(error);
284
+ this.logger.error(`Discord hook error: ${errorMessage}`);
285
+ return {
286
+ success: false,
287
+ hookType: "discord",
288
+ durationMs,
289
+ error: errorMessage,
290
+ };
291
+ }
292
+ }
293
+ }
294
+ //# sourceMappingURL=discord.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discord.js","sourceRoot":"","sources":["../../../src/hooks/runners/discord.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Shell Hook Runner
3
+ *
4
+ * Executes shell commands with HookContext JSON piped to stdin.
5
+ * Used for integrating with custom scripts, logging, and external tooling.
6
+ */
7
+ import type { HookContext, HookResult, ShellHookConfigInput } from "../types.js";
8
+ /**
9
+ * Logger interface for ShellHookRunner
10
+ */
11
+ export interface ShellHookRunnerLogger {
12
+ debug: (message: string) => void;
13
+ info: (message: string) => void;
14
+ warn: (message: string) => void;
15
+ error: (message: string) => void;
16
+ }
17
+ /**
18
+ * Options for ShellHookRunner
19
+ */
20
+ export interface ShellHookRunnerOptions {
21
+ /**
22
+ * Logger for hook execution output
23
+ */
24
+ logger?: ShellHookRunnerLogger;
25
+ /**
26
+ * Working directory for shell commands
27
+ */
28
+ cwd?: string;
29
+ /**
30
+ * Additional environment variables to pass to the shell
31
+ */
32
+ env?: Record<string, string>;
33
+ }
34
+ /**
35
+ * ShellHookRunner executes shell commands with HookContext on stdin
36
+ *
37
+ * @example
38
+ * ```typescript
39
+ * const runner = new ShellHookRunner({ logger: console });
40
+ *
41
+ * const result = await runner.execute(
42
+ * { type: 'shell', command: './scripts/log-job.sh' },
43
+ * hookContext
44
+ * );
45
+ *
46
+ * if (result.success) {
47
+ * console.log('Hook completed:', result.output);
48
+ * } else {
49
+ * console.error('Hook failed:', result.error);
50
+ * }
51
+ * ```
52
+ */
53
+ export declare class ShellHookRunner {
54
+ private logger;
55
+ private cwd?;
56
+ private env?;
57
+ constructor(options?: ShellHookRunnerOptions);
58
+ /**
59
+ * Execute a shell hook with the given context
60
+ *
61
+ * @param config - Shell hook configuration (accepts input type with optional fields)
62
+ * @param context - Hook context to pass to the script
63
+ * @returns Promise resolving to the hook result
64
+ */
65
+ execute(config: ShellHookConfigInput, context: HookContext): Promise<HookResult>;
66
+ /**
67
+ * Run the shell command and capture output
68
+ */
69
+ private runCommand;
70
+ }
71
+ //# sourceMappingURL=shell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../../src/hooks/runners/shell.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAajF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC;;OAEG;IACH,MAAM,CAAC,EAAE,qBAAqB,CAAC;IAE/B;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAwB;IACtC,OAAO,CAAC,GAAG,CAAC,CAAS;IACrB,OAAO,CAAC,GAAG,CAAC,CAAyB;gBAEzB,OAAO,GAAE,sBAA2B;IAWhD;;;;;;OAMG;IACG,OAAO,CAAC,MAAM,EAAE,oBAAoB,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;IA+CtF;;OAEG;IACH,OAAO,CAAC,UAAU;CAyFnB"}
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Shell Hook Runner
3
+ *
4
+ * Executes shell commands with HookContext JSON piped to stdin.
5
+ * Used for integrating with custom scripts, logging, and external tooling.
6
+ */
7
+ import { spawn } from "node:child_process";
8
+ /**
9
+ * Default timeout for shell hooks in milliseconds
10
+ */
11
+ const DEFAULT_TIMEOUT = 30000;
12
+ /**
13
+ * Maximum output buffer size in bytes (1MB)
14
+ * Prevents memory issues with verbose scripts
15
+ */
16
+ const MAX_OUTPUT_SIZE = 1024 * 1024;
17
+ /**
18
+ * ShellHookRunner executes shell commands with HookContext on stdin
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * const runner = new ShellHookRunner({ logger: console });
23
+ *
24
+ * const result = await runner.execute(
25
+ * { type: 'shell', command: './scripts/log-job.sh' },
26
+ * hookContext
27
+ * );
28
+ *
29
+ * if (result.success) {
30
+ * console.log('Hook completed:', result.output);
31
+ * } else {
32
+ * console.error('Hook failed:', result.error);
33
+ * }
34
+ * ```
35
+ */
36
+ export class ShellHookRunner {
37
+ logger;
38
+ cwd;
39
+ env;
40
+ constructor(options = {}) {
41
+ this.logger = options.logger ?? {
42
+ debug: () => { },
43
+ info: () => { },
44
+ warn: () => { },
45
+ error: () => { },
46
+ };
47
+ this.cwd = options.cwd;
48
+ this.env = options.env;
49
+ }
50
+ /**
51
+ * Execute a shell hook with the given context
52
+ *
53
+ * @param config - Shell hook configuration (accepts input type with optional fields)
54
+ * @param context - Hook context to pass to the script
55
+ * @returns Promise resolving to the hook result
56
+ */
57
+ async execute(config, context) {
58
+ const startTime = Date.now();
59
+ const timeout = config.timeout ?? DEFAULT_TIMEOUT;
60
+ const hookName = config.name ?? "shell hook";
61
+ this.logger.debug(`Executing ${hookName}`);
62
+ try {
63
+ const result = await this.runCommand(config.command, context, timeout);
64
+ const durationMs = Date.now() - startTime;
65
+ if (result.exitCode === 0) {
66
+ this.logger.info(`${hookName} completed in ${durationMs}ms`);
67
+ return {
68
+ success: true,
69
+ hookType: "shell",
70
+ durationMs,
71
+ output: result.stdout,
72
+ exitCode: result.exitCode,
73
+ };
74
+ }
75
+ else {
76
+ this.logger.warn(`${hookName} failed with exit code ${result.exitCode}`);
77
+ return {
78
+ success: false,
79
+ hookType: "shell",
80
+ durationMs,
81
+ error: `Exit code ${result.exitCode}: ${result.stderr || "No error output"}`,
82
+ output: result.stdout,
83
+ exitCode: result.exitCode,
84
+ };
85
+ }
86
+ }
87
+ catch (error) {
88
+ const durationMs = Date.now() - startTime;
89
+ const errorMessage = error instanceof Error ? error.message : String(error);
90
+ this.logger.error(`${hookName} error: ${errorMessage}`);
91
+ return {
92
+ success: false,
93
+ hookType: "shell",
94
+ durationMs,
95
+ error: errorMessage,
96
+ };
97
+ }
98
+ }
99
+ /**
100
+ * Run the shell command and capture output
101
+ */
102
+ runCommand(command, context, timeout) {
103
+ return new Promise((resolve, reject) => {
104
+ const contextJson = JSON.stringify(context);
105
+ // Spawn shell process
106
+ const proc = spawn(command, {
107
+ shell: true,
108
+ cwd: this.cwd,
109
+ env: {
110
+ ...process.env,
111
+ ...this.env,
112
+ },
113
+ // Don't inherit stdio - we want to capture output
114
+ stdio: ["pipe", "pipe", "pipe"],
115
+ });
116
+ let stdout = "";
117
+ let stderr = "";
118
+ let killed = false;
119
+ // Set up timeout
120
+ const timeoutHandle = setTimeout(() => {
121
+ killed = true;
122
+ proc.kill("SIGTERM");
123
+ // Force kill after 1 second if SIGTERM doesn't work
124
+ setTimeout(() => {
125
+ if (!proc.killed) {
126
+ proc.kill("SIGKILL");
127
+ }
128
+ }, 1000);
129
+ }, timeout);
130
+ // Capture stdout
131
+ proc.stdout?.on("data", (data) => {
132
+ const chunk = data.toString();
133
+ if (stdout.length + chunk.length <= MAX_OUTPUT_SIZE) {
134
+ stdout += chunk;
135
+ }
136
+ });
137
+ // Capture stderr
138
+ proc.stderr?.on("data", (data) => {
139
+ const chunk = data.toString();
140
+ if (stderr.length + chunk.length <= MAX_OUTPUT_SIZE) {
141
+ stderr += chunk;
142
+ }
143
+ });
144
+ // Handle process exit
145
+ proc.on("close", (code) => {
146
+ clearTimeout(timeoutHandle);
147
+ if (killed) {
148
+ reject(new Error(`Hook timed out after ${timeout}ms`));
149
+ return;
150
+ }
151
+ resolve({
152
+ exitCode: code ?? 1,
153
+ stdout: stdout.trim(),
154
+ stderr: stderr.trim(),
155
+ });
156
+ });
157
+ // Handle spawn errors
158
+ proc.on("error", (error) => {
159
+ clearTimeout(timeoutHandle);
160
+ reject(error);
161
+ });
162
+ // Write context to stdin and close it
163
+ // Handle EPIPE errors that occur if process exits before we finish writing
164
+ if (proc.stdin) {
165
+ proc.stdin.on("error", (err) => {
166
+ // EPIPE is expected if process exits early - ignore it
167
+ if (err.code !== "EPIPE") {
168
+ this.logger.warn(`stdin error: ${err.message}`);
169
+ }
170
+ });
171
+ proc.stdin.write(contextJson);
172
+ proc.stdin.end();
173
+ }
174
+ });
175
+ }
176
+ }
177
+ //# sourceMappingURL=shell.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shell.js","sourceRoot":"","sources":["../../../src/hooks/runners/shell.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Webhook Hook Runner
3
+ *
4
+ * POSTs HookContext JSON to a configured URL.
5
+ * Used for integrating with external services (monitoring, ticketing, dashboards).
6
+ */
7
+ import type { HookContext, HookResult, WebhookHookConfigInput } from "../types.js";
8
+ /**
9
+ * Logger interface for WebhookHookRunner
10
+ */
11
+ export interface WebhookHookRunnerLogger {
12
+ debug: (message: string) => void;
13
+ info: (message: string) => void;
14
+ warn: (message: string) => void;
15
+ error: (message: string) => void;
16
+ }
17
+ /**
18
+ * Options for WebhookHookRunner
19
+ */
20
+ export interface WebhookHookRunnerOptions {
21
+ /**
22
+ * Logger for hook execution output
23
+ */
24
+ logger?: WebhookHookRunnerLogger;
25
+ /**
26
+ * Custom fetch implementation (for testing)
27
+ */
28
+ fetch?: typeof globalThis.fetch;
29
+ }
30
+ /**
31
+ * WebhookHookRunner POSTs HookContext JSON to a URL
32
+ *
33
+ * @example
34
+ * ```typescript
35
+ * const runner = new WebhookHookRunner({ logger: console });
36
+ *
37
+ * const result = await runner.execute(
38
+ * {
39
+ * type: 'webhook',
40
+ * url: 'https://api.example.com/hooks/job-complete',
41
+ * headers: { 'Authorization': 'Bearer ${API_TOKEN}' }
42
+ * },
43
+ * hookContext
44
+ * );
45
+ *
46
+ * if (result.success) {
47
+ * console.log('Webhook delivered successfully');
48
+ * } else {
49
+ * console.error('Webhook failed:', result.error);
50
+ * }
51
+ * ```
52
+ */
53
+ export declare class WebhookHookRunner {
54
+ private logger;
55
+ private fetchFn;
56
+ constructor(options?: WebhookHookRunnerOptions);
57
+ /**
58
+ * Execute a webhook hook with the given context
59
+ *
60
+ * @param config - Webhook hook configuration (accepts input type with optional fields)
61
+ * @param context - Hook context to send in the request body
62
+ * @returns Promise resolving to the hook result
63
+ */
64
+ execute(config: WebhookHookConfigInput, context: HookContext): Promise<HookResult>;
65
+ }
66
+ //# sourceMappingURL=webhook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook.d.ts","sourceRoot":"","sources":["../../../src/hooks/runners/webhook.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAC;AAOnF;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACvC;;OAEG;IACH,MAAM,CAAC,EAAE,uBAAuB,CAAC;IAEjC;;OAEG;IACH,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;CACjC;AAmBD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,MAAM,CAA0B;IACxC,OAAO,CAAC,OAAO,CAA0B;gBAE7B,OAAO,GAAE,wBAA6B;IAUlD;;;;;;OAMG;IACG,OAAO,CAAC,MAAM,EAAE,sBAAsB,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC;CA2GzF"}