@swarm-agent/sdk 0.1.47

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 (74) hide show
  1. package/APPLICATIONS.md +133 -0
  2. package/HEADLESS_UI.md +97 -0
  3. package/LICENSE +201 -0
  4. package/README.md +473 -0
  5. package/dist/app-results.d.ts +24 -0
  6. package/dist/app-results.js +167 -0
  7. package/dist/apps.d.ts +82 -0
  8. package/dist/apps.js +89 -0
  9. package/dist/auth.d.ts +45 -0
  10. package/dist/auth.js +89 -0
  11. package/dist/automations.d.ts +74 -0
  12. package/dist/automations.js +159 -0
  13. package/dist/client.d.ts +61 -0
  14. package/dist/client.js +103 -0
  15. package/dist/deliverables.d.ts +42 -0
  16. package/dist/deliverables.js +83 -0
  17. package/dist/deploy/dockerfile.d.ts +14 -0
  18. package/dist/deploy/dockerfile.js +14 -0
  19. package/dist/deploy/index.d.ts +67 -0
  20. package/dist/deploy/index.js +226 -0
  21. package/dist/deploy/manifest.d.ts +17 -0
  22. package/dist/deploy/manifest.js +220 -0
  23. package/dist/deploy/providers/gcp-cloud-run.d.ts +9 -0
  24. package/dist/deploy/providers/gcp-cloud-run.js +12 -0
  25. package/dist/deploy/providers/gcp-compute.d.ts +9 -0
  26. package/dist/deploy/providers/gcp-compute.js +12 -0
  27. package/dist/deploy/types.d.ts +211 -0
  28. package/dist/deploy/types.js +4 -0
  29. package/dist/deploy/worker-cloud-deployer.d.ts +33 -0
  30. package/dist/deploy/worker-cloud-deployer.js +14 -0
  31. package/dist/errors.d.ts +36 -0
  32. package/dist/errors.js +68 -0
  33. package/dist/index.d.ts +23 -0
  34. package/dist/index.js +20 -0
  35. package/dist/notifications.d.ts +28 -0
  36. package/dist/notifications.js +65 -0
  37. package/dist/projects.d.ts +147 -0
  38. package/dist/projects.js +513 -0
  39. package/dist/provider-auth.d.ts +160 -0
  40. package/dist/provider-auth.js +54 -0
  41. package/dist/realtime.d.ts +240 -0
  42. package/dist/realtime.js +312 -0
  43. package/dist/sessions.d.ts +60 -0
  44. package/dist/sessions.js +194 -0
  45. package/dist/settings.d.ts +85 -0
  46. package/dist/settings.js +26 -0
  47. package/dist/storage/adapters/memory.d.ts +13 -0
  48. package/dist/storage/adapters/memory.js +35 -0
  49. package/dist/storage/adapters/s3.d.ts +31 -0
  50. package/dist/storage/adapters/s3.js +171 -0
  51. package/dist/storage/client.d.ts +174 -0
  52. package/dist/storage/client.js +121 -0
  53. package/dist/storage/hub.d.ts +30 -0
  54. package/dist/storage/hub.js +372 -0
  55. package/dist/storage/index.d.ts +6 -0
  56. package/dist/storage/index.js +6 -0
  57. package/dist/storage/runner.d.ts +48 -0
  58. package/dist/storage/runner.js +233 -0
  59. package/dist/storage/types.d.ts +198 -0
  60. package/dist/storage/types.js +1 -0
  61. package/dist/system.d.ts +14 -0
  62. package/dist/system.js +52 -0
  63. package/dist/transport.d.ts +17 -0
  64. package/dist/transport.js +243 -0
  65. package/dist/types.d.ts +1137 -0
  66. package/dist/types.js +1 -0
  67. package/dist/usage.d.ts +106 -0
  68. package/dist/usage.js +82 -0
  69. package/dist/workers.d.ts +146 -0
  70. package/dist/workers.js +822 -0
  71. package/dist/workspaces.d.ts +81 -0
  72. package/dist/workspaces.js +58 -0
  73. package/examples/headless-session.ts +85 -0
  74. package/package.json +56 -0
@@ -0,0 +1,822 @@
1
+ import { SwarmValidationError } from './errors.js';
2
+ /**
3
+ * SwarmWorkersNamespace manages durable, account-owned workers, their revisions,
4
+ * attached automations, and portable import/export definitions over canonical /v3/workers APIs.
5
+ *
6
+ * Distinct from legacy SwarmAutomationsNamespace which targets /v3/automations/v2.
7
+ */
8
+ export class SwarmWorkersNamespace {
9
+ transport;
10
+ constructor(transport) {
11
+ this.transport = transport;
12
+ }
13
+ /**
14
+ * Creates a new durable worker in idle state.
15
+ * Requires nonblank name and idempotency_key; instructions may be empty.
16
+ * Server assigns stable identity and initial revision 1.
17
+ */
18
+ async create(params) {
19
+ if (!params || typeof params !== 'object') {
20
+ throw new SwarmValidationError('Worker creation parameters are required');
21
+ }
22
+ if (!params.name || typeof params.name !== 'string' || params.name.trim() === '') {
23
+ throw new SwarmValidationError('Worker name is required and cannot be blank');
24
+ }
25
+ if (params.instructions !== undefined && typeof params.instructions !== 'string') {
26
+ throw new SwarmValidationError('Worker instructions must be a string');
27
+ }
28
+ if ('id' in params || 'local_bindings' in params) {
29
+ throw new SwarmValidationError('Worker identity and local bindings are server-owned');
30
+ }
31
+ if (!params.idempotency_key || typeof params.idempotency_key !== 'string' || params.idempotency_key.trim() === '') {
32
+ throw new SwarmValidationError('Worker idempotency_key is required and cannot be blank');
33
+ }
34
+ const body = {
35
+ name: params.name.trim(),
36
+ instructions: params.instructions,
37
+ idempotency_key: params.idempotency_key.trim(),
38
+ };
39
+ if (params.description !== undefined)
40
+ body.description = params.description;
41
+ if (params.requested_capabilities !== undefined)
42
+ body.requested_capabilities = params.requested_capabilities;
43
+ if (params.workspace_requirements !== undefined)
44
+ body.workspace_requirements = params.workspace_requirements;
45
+ if (params.automations !== undefined)
46
+ body.automations = params.automations;
47
+ if (params.metadata !== undefined)
48
+ body.metadata = params.metadata;
49
+ const res = await this.transport.request('/v3/workers', {
50
+ method: 'POST',
51
+ headers: {
52
+ 'Idempotency-Key': params.idempotency_key.trim(),
53
+ },
54
+ body,
55
+ });
56
+ if (!res.data ||
57
+ typeof res.data !== 'object' ||
58
+ !res.data.worker ||
59
+ typeof res.data.worker !== 'object' ||
60
+ typeof res.data.worker.id !== 'string' ||
61
+ res.data.worker.id === '') {
62
+ throw new SwarmValidationError('Malformed response envelope: expected worker record');
63
+ }
64
+ return res.data.worker;
65
+ }
66
+ /**
67
+ * Retrieves a durable worker by its server ID or attached automation ID.
68
+ */
69
+ async get(id) {
70
+ if (!id || typeof id !== 'string' || id.trim() === '') {
71
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
72
+ }
73
+ try {
74
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(id.trim())}`, { method: 'GET' });
75
+ if (!res.data ||
76
+ typeof res.data !== 'object' ||
77
+ !res.data.worker ||
78
+ typeof res.data.worker !== 'object' ||
79
+ typeof res.data.worker.id !== 'string' ||
80
+ res.data.worker.id === '') {
81
+ throw new SwarmValidationError('Malformed response envelope: expected worker record');
82
+ }
83
+ return res.data.worker;
84
+ }
85
+ catch (err) {
86
+ if (err?.status === 404) {
87
+ return null;
88
+ }
89
+ throw err;
90
+ }
91
+ }
92
+ /**
93
+ * Lists durable workers with pagination, lifecycle filters, and cursor support.
94
+ */
95
+ async list(params) {
96
+ const q = new URLSearchParams();
97
+ if (params?.limit !== undefined) {
98
+ if (!Number.isSafeInteger(params.limit) || params.limit < 1 || params.limit > 100) {
99
+ throw new SwarmValidationError('limit must be an integer between 1 and 100');
100
+ }
101
+ q.set('limit', params.limit.toString());
102
+ }
103
+ if (params?.cursor !== undefined) {
104
+ if (typeof params.cursor !== 'string' || params.cursor.length > 1024) {
105
+ throw new SwarmValidationError('cursor must be a valid string <= 1024 characters');
106
+ }
107
+ if (params.cursor.trim() !== '') {
108
+ q.set('cursor', params.cursor.trim());
109
+ }
110
+ }
111
+ if (params?.lifecycle_state) {
112
+ q.set('lifecycle_state', params.lifecycle_state);
113
+ }
114
+ if (params?.include_deleted !== undefined) {
115
+ q.set('include_deleted', params.include_deleted ? 'true' : 'false');
116
+ }
117
+ const queryStr = q.toString();
118
+ const endpoint = queryStr ? `/v3/workers?${queryStr}` : '/v3/workers';
119
+ const res = await this.transport.request(endpoint, {
120
+ method: 'GET',
121
+ });
122
+ if (!res.data || typeof res.data !== 'object' || !Array.isArray(res.data.workers)) {
123
+ throw new SwarmValidationError('Malformed response envelope: expected workers array');
124
+ }
125
+ if (res.data.next_cursor !== undefined && typeof res.data.next_cursor !== 'string')
126
+ throw new SwarmValidationError('Malformed response cursor');
127
+ return {
128
+ workers: res.data.workers,
129
+ next_cursor: typeof res.data.next_cursor === 'string' && res.data.next_cursor.length > 0 ? res.data.next_cursor : undefined,
130
+ };
131
+ }
132
+ /**
133
+ * Updates a worker's definition with an explicit expected revision for optimistic concurrency.
134
+ * Body carries expected_revision only (no query params, no local_bindings).
135
+ */
136
+ async update(id, expectedRevision, params) {
137
+ if (!id || typeof id !== 'string' || id.trim() === '') {
138
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
139
+ }
140
+ if (!Number.isSafeInteger(expectedRevision) || expectedRevision < 1) {
141
+ throw new SwarmValidationError('Explicit numeric expectedRevision >= 1 is required');
142
+ }
143
+ if (!params || typeof params !== 'object') {
144
+ throw new SwarmValidationError('Update parameters are required');
145
+ }
146
+ if ('local_bindings' in params)
147
+ throw new SwarmValidationError('Local bindings require approved activation');
148
+ const body = {
149
+ expected_revision: expectedRevision,
150
+ };
151
+ if (params.name !== undefined)
152
+ body.name = params.name;
153
+ if (params.description !== undefined)
154
+ body.description = params.description;
155
+ if (params.instructions !== undefined)
156
+ body.instructions = params.instructions;
157
+ if (params.requested_capabilities !== undefined)
158
+ body.requested_capabilities = params.requested_capabilities;
159
+ if (params.workspace_requirements !== undefined)
160
+ body.workspace_requirements = params.workspace_requirements;
161
+ if (params.automations !== undefined)
162
+ body.automations = params.automations;
163
+ if (params.metadata !== undefined)
164
+ body.metadata = params.metadata;
165
+ if (params.change_summary !== undefined)
166
+ body.change_summary = params.change_summary;
167
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(id.trim())}`, {
168
+ method: 'PUT',
169
+ body,
170
+ });
171
+ if (!res.data ||
172
+ typeof res.data !== 'object' ||
173
+ !res.data.worker ||
174
+ typeof res.data.worker !== 'object' ||
175
+ typeof res.data.worker.id !== 'string' ||
176
+ res.data.worker.id === '') {
177
+ throw new SwarmValidationError('Malformed response envelope: expected worker record');
178
+ }
179
+ return res.data.worker;
180
+ }
181
+ /**
182
+ * Validates a portable worker definition document without persisting it.
183
+ * Sends raw PortableWorkerDefinition body and expects { valid: true, worker: doc }.
184
+ */
185
+ async validate(definition) {
186
+ let payload;
187
+ if (typeof definition === 'string') {
188
+ try {
189
+ payload = JSON.parse(definition);
190
+ }
191
+ catch (err) {
192
+ throw new SwarmValidationError(`Invalid JSON in portable worker definition: ${err.message}`);
193
+ }
194
+ }
195
+ else {
196
+ payload = definition;
197
+ }
198
+ if (!payload || typeof payload !== 'object') {
199
+ throw new SwarmValidationError('Portable worker definition must be a valid object');
200
+ }
201
+ const res = await this.transport.request('/v3/workers/validate', {
202
+ method: 'POST',
203
+ body: payload,
204
+ });
205
+ if (!res.data ||
206
+ typeof res.data !== 'object' ||
207
+ typeof res.data.valid !== 'boolean' ||
208
+ !res.data.worker ||
209
+ typeof res.data.worker !== 'object') {
210
+ throw new SwarmValidationError('Malformed response envelope: expected valid boolean and worker definition');
211
+ }
212
+ return {
213
+ valid: res.data.valid,
214
+ worker: res.data.worker,
215
+ };
216
+ }
217
+ /**
218
+ * Exports a complete portable worker definition.
219
+ * Returns { worker: doc }.
220
+ */
221
+ async export(id) {
222
+ if (!id || typeof id !== 'string' || id.trim() === '') {
223
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
224
+ }
225
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(id.trim())}/export`, { method: 'GET' });
226
+ if (!res.data || typeof res.data !== 'object' || !res.data.worker || typeof res.data.worker !== 'object') {
227
+ throw new SwarmValidationError('Malformed response envelope: expected worker export document');
228
+ }
229
+ return {
230
+ worker: res.data.worker,
231
+ };
232
+ }
233
+ /**
234
+ * Imports a portable worker definition.
235
+ * Sends raw document body.
236
+ * - If mode is 'new' (default when targetWorkerId omitted): requires idempotencyKey option, queries ?mode=new&idempotency_key=...
237
+ * - If mode is 'update' (or targetWorkerId provided): requires targetWorkerId and expectedRevision, queries ?mode=update&worker_id=...&expected_revision=...
238
+ */
239
+ async import(definition, options) {
240
+ let payload;
241
+ if (typeof definition === 'string') {
242
+ try {
243
+ payload = JSON.parse(definition);
244
+ }
245
+ catch (err) {
246
+ throw new SwarmValidationError(`Invalid JSON in portable worker definition: ${err.message}`);
247
+ }
248
+ }
249
+ else {
250
+ payload = definition;
251
+ }
252
+ if (!payload || typeof payload !== 'object') {
253
+ throw new SwarmValidationError('Portable worker definition must be a valid object');
254
+ }
255
+ const mode = options?.mode ?? (options?.targetWorkerId ? 'update' : 'new');
256
+ const q = new URLSearchParams();
257
+ q.set('mode', mode);
258
+ const headers = {};
259
+ if (mode === 'update') {
260
+ if (!options?.targetWorkerId || typeof options.targetWorkerId !== 'string' || options.targetWorkerId.trim() === '') {
261
+ throw new SwarmValidationError('targetWorkerId is required when importing in update mode');
262
+ }
263
+ if (typeof options.expectedRevision !== 'number' || !Number.isSafeInteger(options.expectedRevision) || options.expectedRevision < 1) {
264
+ throw new SwarmValidationError('Explicit numeric expectedRevision >= 1 is required when importing into an existing target worker');
265
+ }
266
+ q.set('worker_id', options.targetWorkerId.trim());
267
+ q.set('expected_revision', options.expectedRevision.toString());
268
+ }
269
+ else if (mode === 'new') {
270
+ if (!options?.idempotencyKey || typeof options.idempotencyKey !== 'string' || options.idempotencyKey.trim() === '') {
271
+ throw new SwarmValidationError('idempotencyKey is required when importing a new worker');
272
+ }
273
+ q.set('idempotency_key', options.idempotencyKey.trim());
274
+ headers['Idempotency-Key'] = options.idempotencyKey.trim();
275
+ }
276
+ else {
277
+ throw new SwarmValidationError("mode must be either 'new' or 'update'");
278
+ }
279
+ const res = await this.transport.request(`/v3/workers/import?${q.toString()}`, {
280
+ method: 'POST',
281
+ headers,
282
+ body: payload,
283
+ });
284
+ if (!res.data ||
285
+ typeof res.data !== 'object' ||
286
+ !res.data.worker ||
287
+ typeof res.data.worker !== 'object' ||
288
+ typeof res.data.worker.id !== 'string' ||
289
+ res.data.worker.id === '') {
290
+ throw new SwarmValidationError('Malformed response envelope: expected worker record');
291
+ }
292
+ return res.data.worker;
293
+ }
294
+ /**
295
+ * Attaches an automation definition to the worker.
296
+ * Body carries { expected_worker_revision, automation }, no query param.
297
+ */
298
+ async attachAutomation(params) {
299
+ if (!params || typeof params !== 'object') {
300
+ throw new SwarmValidationError('Attachment parameters are required');
301
+ }
302
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
303
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
304
+ }
305
+ if (!Number.isSafeInteger(params.expected_worker_revision) || params.expected_worker_revision < 1) {
306
+ throw new SwarmValidationError('Explicit numeric expected_worker_revision >= 1 is required');
307
+ }
308
+ if (!params.automation || typeof params.automation !== 'object') {
309
+ throw new SwarmValidationError('Automation definition is required');
310
+ }
311
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/automations`, {
312
+ method: 'POST',
313
+ body: {
314
+ expected_worker_revision: params.expected_worker_revision,
315
+ automation: params.automation,
316
+ },
317
+ });
318
+ if (!res.data ||
319
+ typeof res.data !== 'object' ||
320
+ !res.data.worker ||
321
+ typeof res.data.worker !== 'object' ||
322
+ typeof res.data.worker.id !== 'string' ||
323
+ res.data.worker.id === '') {
324
+ throw new SwarmValidationError('Malformed response envelope: expected worker record');
325
+ }
326
+ return res.data.worker;
327
+ }
328
+ /**
329
+ * Updates an existing attached automation definition on the worker.
330
+ * Body carries { expected_worker_revision, automation }, no query param.
331
+ */
332
+ async updateAutomation(params) {
333
+ if (!params || typeof params !== 'object') {
334
+ throw new SwarmValidationError('Update automation parameters are required');
335
+ }
336
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
337
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
338
+ }
339
+ if (!params.automation_id || typeof params.automation_id !== 'string' || params.automation_id.trim() === '') {
340
+ throw new SwarmValidationError('Automation ID is required and cannot be blank');
341
+ }
342
+ if (!Number.isSafeInteger(params.expected_worker_revision) || params.expected_worker_revision < 1) {
343
+ throw new SwarmValidationError('Explicit numeric expected_worker_revision >= 1 is required');
344
+ }
345
+ if (!params.automation || typeof params.automation !== 'object') {
346
+ throw new SwarmValidationError('Automation definition is required');
347
+ }
348
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/automations/${encodeURIComponent(params.automation_id.trim())}`, {
349
+ method: 'PUT',
350
+ body: {
351
+ expected_worker_revision: params.expected_worker_revision,
352
+ automation: params.automation,
353
+ },
354
+ });
355
+ if (!res.data ||
356
+ typeof res.data !== 'object' ||
357
+ !res.data.worker ||
358
+ typeof res.data.worker !== 'object' ||
359
+ typeof res.data.worker.id !== 'string' ||
360
+ res.data.worker.id === '') {
361
+ throw new SwarmValidationError('Malformed response envelope: expected worker record');
362
+ }
363
+ return res.data.worker;
364
+ }
365
+ /**
366
+ * Detaches/removes an automation definition from the worker.
367
+ */
368
+ async removeAutomation(params) {
369
+ if (!params || typeof params !== 'object') {
370
+ throw new SwarmValidationError('Remove automation parameters are required');
371
+ }
372
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
373
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
374
+ }
375
+ if (!params.automation_id || typeof params.automation_id !== 'string' || params.automation_id.trim() === '') {
376
+ throw new SwarmValidationError('Automation ID is required and cannot be blank');
377
+ }
378
+ if (!Number.isSafeInteger(params.expected_worker_revision) || params.expected_worker_revision < 1) {
379
+ throw new SwarmValidationError('Explicit numeric expected_worker_revision >= 1 is required');
380
+ }
381
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/automations/${encodeURIComponent(params.automation_id.trim())}?expected_worker_revision=${params.expected_worker_revision}`, {
382
+ method: 'DELETE',
383
+ });
384
+ if (!res.data ||
385
+ typeof res.data !== 'object' ||
386
+ !res.data.worker ||
387
+ typeof res.data.worker !== 'object' ||
388
+ typeof res.data.worker.id !== 'string' ||
389
+ res.data.worker.id === '') {
390
+ throw new SwarmValidationError('Malformed response envelope: expected worker record');
391
+ }
392
+ return res.data.worker;
393
+ }
394
+ /**
395
+ * Activates a stored worker with approved local workspace bindings.
396
+ * Transitions worker from idle/paused to active state.
397
+ */
398
+ async activate(params) {
399
+ if (!params || typeof params !== 'object') {
400
+ throw new SwarmValidationError('Activate worker parameters are required');
401
+ }
402
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
403
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
404
+ }
405
+ if (!Number.isSafeInteger(params.expected_revision) || params.expected_revision < 1) {
406
+ throw new SwarmValidationError('Explicit numeric expected_revision >= 1 is required');
407
+ }
408
+ if (!params.local_bindings || typeof params.local_bindings !== 'object') {
409
+ throw new SwarmValidationError('Approved local_bindings map is required');
410
+ }
411
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/activate`, {
412
+ method: 'POST',
413
+ body: {
414
+ expected_revision: params.expected_revision,
415
+ local_bindings: params.local_bindings,
416
+ ...(params.activate === undefined ? {} : { activate: params.activate }),
417
+ },
418
+ });
419
+ if (!res.data || typeof res.data !== 'object' || !res.data.worker) {
420
+ throw new SwarmValidationError('Malformed response envelope: expected worker record');
421
+ }
422
+ return res.data.worker;
423
+ }
424
+ /**
425
+ * Local deployment alias for activate: validates and activates with approved bindings.
426
+ */
427
+ async deploy(params) {
428
+ return this.activate(params);
429
+ }
430
+ /**
431
+ * Pauses an active worker, closing admission and invalidating queued work.
432
+ */
433
+ async pause(params) {
434
+ if (!params || typeof params !== 'object') {
435
+ throw new SwarmValidationError('Pause worker parameters are required');
436
+ }
437
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
438
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
439
+ }
440
+ if (!Number.isSafeInteger(params.expected_revision) || params.expected_revision < 1) {
441
+ throw new SwarmValidationError('Explicit numeric expected_revision >= 1 is required');
442
+ }
443
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/pause`, {
444
+ method: 'POST',
445
+ body: { expected_revision: params.expected_revision },
446
+ });
447
+ if (!res.data || typeof res.data !== 'object' || !res.data.worker) {
448
+ throw new SwarmValidationError('Malformed response envelope: expected worker record');
449
+ }
450
+ return res.data.worker;
451
+ }
452
+ /**
453
+ * Resumes a paused worker without replaying cancelled work.
454
+ */
455
+ async resume(params) {
456
+ if (!params || typeof params !== 'object') {
457
+ throw new SwarmValidationError('Resume worker parameters are required');
458
+ }
459
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
460
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
461
+ }
462
+ if (!Number.isSafeInteger(params.expected_revision) || params.expected_revision < 1) {
463
+ throw new SwarmValidationError('Explicit numeric expected_revision >= 1 is required');
464
+ }
465
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/resume`, {
466
+ method: 'POST',
467
+ body: { expected_revision: params.expected_revision },
468
+ });
469
+ if (!res.data || typeof res.data !== 'object' || !res.data.worker) {
470
+ throw new SwarmValidationError('Malformed response envelope: expected worker record');
471
+ }
472
+ return res.data.worker;
473
+ }
474
+ /**
475
+ * Archives a worker, stopping future work and disabling automations.
476
+ * Rejects if there are active running executions.
477
+ */
478
+ async archive(params) {
479
+ if (!params || typeof params !== 'object') {
480
+ throw new SwarmValidationError('Archive worker parameters are required');
481
+ }
482
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
483
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
484
+ }
485
+ if (!Number.isSafeInteger(params.expected_revision) || params.expected_revision < 1) {
486
+ throw new SwarmValidationError('Explicit numeric expected_revision >= 1 is required');
487
+ }
488
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/archive`, {
489
+ method: 'POST',
490
+ body: { expected_revision: params.expected_revision },
491
+ });
492
+ if (!res.data || typeof res.data !== 'object' || !res.data.worker) {
493
+ throw new SwarmValidationError('Malformed response envelope: expected worker record');
494
+ }
495
+ return res.data.worker;
496
+ }
497
+ /**
498
+ * Deletes a worker with safe stop barrier enforcement (tombstone).
499
+ * Rejects if there are active running executions.
500
+ */
501
+ async delete(params) {
502
+ if (!params || typeof params !== 'object') {
503
+ throw new SwarmValidationError('Delete worker parameters are required');
504
+ }
505
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
506
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
507
+ }
508
+ if (!Number.isSafeInteger(params.expected_revision) || params.expected_revision < 1) {
509
+ throw new SwarmValidationError('Explicit numeric expected_revision >= 1 is required');
510
+ }
511
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}?expected_revision=${params.expected_revision}`, { method: 'DELETE' });
512
+ if (!res.data || typeof res.data !== 'object' || !res.data.ok) {
513
+ throw new SwarmValidationError('Malformed response envelope: expected { ok: true, deleted: true }');
514
+ }
515
+ return { ok: true, deleted: true };
516
+ }
517
+ /**
518
+ * Enables a specific attached automation on the worker.
519
+ */
520
+ async enableAutomation(params) {
521
+ if (!params || typeof params !== 'object') {
522
+ throw new SwarmValidationError('Enable automation parameters are required');
523
+ }
524
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
525
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
526
+ }
527
+ if (!params.automation_id || typeof params.automation_id !== 'string' || params.automation_id.trim() === '') {
528
+ throw new SwarmValidationError('Automation ID is required and cannot be blank');
529
+ }
530
+ if (!Number.isSafeInteger(params.expected_worker_revision) || params.expected_worker_revision < 1) {
531
+ throw new SwarmValidationError('Explicit numeric expected_worker_revision >= 1 is required');
532
+ }
533
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/automations/${encodeURIComponent(params.automation_id.trim())}/enable`, {
534
+ method: 'POST',
535
+ body: { expected_worker_revision: params.expected_worker_revision },
536
+ });
537
+ if (!res.data || typeof res.data !== 'object' || !res.data.worker) {
538
+ throw new SwarmValidationError('Malformed response envelope: expected worker record');
539
+ }
540
+ return res.data.worker;
541
+ }
542
+ /**
543
+ * Disables a specific attached automation on the worker without stopping other jobs.
544
+ */
545
+ async disableAutomation(params) {
546
+ if (!params || typeof params !== 'object') {
547
+ throw new SwarmValidationError('Disable automation parameters are required');
548
+ }
549
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
550
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
551
+ }
552
+ if (!params.automation_id || typeof params.automation_id !== 'string' || params.automation_id.trim() === '') {
553
+ throw new SwarmValidationError('Automation ID is required and cannot be blank');
554
+ }
555
+ if (!Number.isSafeInteger(params.expected_worker_revision) || params.expected_worker_revision < 1) {
556
+ throw new SwarmValidationError('Explicit numeric expected_worker_revision >= 1 is required');
557
+ }
558
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/automations/${encodeURIComponent(params.automation_id.trim())}/disable`, {
559
+ method: 'POST',
560
+ body: { expected_worker_revision: params.expected_worker_revision },
561
+ });
562
+ if (!res.data || typeof res.data !== 'object' || !res.data.worker) {
563
+ throw new SwarmValidationError('Malformed response envelope: expected worker record');
564
+ }
565
+ return res.data.worker;
566
+ }
567
+ /**
568
+ * Dispatches a direct execution request to the worker without creating a persistent automation.
569
+ */
570
+ async directRequest(params) {
571
+ if (!params || typeof params !== 'object') {
572
+ throw new SwarmValidationError('Direct request parameters are required');
573
+ }
574
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
575
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
576
+ }
577
+ const hasPrompt = typeof params.prompt === 'string' && params.prompt.trim() !== '';
578
+ const hasInput = params.input && typeof params.input === 'object' && Object.keys(params.input).length > 0;
579
+ if (!hasPrompt && !hasInput) {
580
+ throw new SwarmValidationError('Prompt or input is required for direct request');
581
+ }
582
+ const headers = {};
583
+ if (params.idempotency_key && typeof params.idempotency_key === 'string' && params.idempotency_key.trim() !== '') {
584
+ headers['Idempotency-Key'] = params.idempotency_key.trim();
585
+ }
586
+ const body = {};
587
+ if (hasPrompt)
588
+ body.prompt = params.prompt.trim();
589
+ if (params.input)
590
+ body.input = params.input;
591
+ if (params.idempotency_key)
592
+ body.idempotency_key = params.idempotency_key.trim();
593
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/direct`, {
594
+ method: 'POST',
595
+ headers,
596
+ body,
597
+ });
598
+ if (!res.data || typeof res.data !== 'object' || !res.data.run) {
599
+ throw new SwarmValidationError('Malformed response envelope: expected worker run record');
600
+ }
601
+ return res.data.run;
602
+ }
603
+ /**
604
+ * Dispatches an explicitly labelled test run. Does not enable schedules.
605
+ */
606
+ async testRun(params) {
607
+ if (!params || typeof params !== 'object') {
608
+ throw new SwarmValidationError('Test run parameters are required');
609
+ }
610
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
611
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
612
+ }
613
+ const headers = {};
614
+ if (params.idempotency_key && typeof params.idempotency_key === 'string' && params.idempotency_key.trim() !== '') {
615
+ headers['Idempotency-Key'] = params.idempotency_key.trim();
616
+ }
617
+ const body = {};
618
+ if (params.automation_id && typeof params.automation_id === 'string' && params.automation_id.trim() !== '') {
619
+ body.automation_id = params.automation_id.trim();
620
+ }
621
+ if (params.prompt && typeof params.prompt === 'string' && params.prompt.trim() !== '') {
622
+ body.prompt = params.prompt.trim();
623
+ }
624
+ if (params.input && typeof params.input === 'object') {
625
+ body.input = params.input;
626
+ }
627
+ if (params.idempotency_key)
628
+ body.idempotency_key = params.idempotency_key.trim();
629
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/test`, {
630
+ method: 'POST',
631
+ headers,
632
+ body,
633
+ });
634
+ if (!res.data || typeof res.data !== 'object' || !res.data.run) {
635
+ throw new SwarmValidationError('Malformed response envelope: expected worker run record');
636
+ }
637
+ return res.data.run;
638
+ }
639
+ /**
640
+ * Dispatches an authenticated external trigger to the worker or specific automation.
641
+ */
642
+ async trigger(params) {
643
+ if (!params || typeof params !== 'object') {
644
+ throw new SwarmValidationError('Trigger parameters are required');
645
+ }
646
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
647
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
648
+ }
649
+ const headers = {};
650
+ if (params.idempotency_key && typeof params.idempotency_key === 'string' && params.idempotency_key.trim() !== '') {
651
+ headers['Idempotency-Key'] = params.idempotency_key.trim();
652
+ }
653
+ const body = {};
654
+ if (params.automation_id && typeof params.automation_id === 'string' && params.automation_id.trim() !== '') {
655
+ body.automation_id = params.automation_id.trim();
656
+ }
657
+ if (params.payload && typeof params.payload === 'object') {
658
+ body.payload = params.payload;
659
+ }
660
+ if (params.idempotency_key)
661
+ body.idempotency_key = params.idempotency_key.trim();
662
+ const url = params.automation_id
663
+ ? `/v3/workers/${encodeURIComponent(params.worker_id.trim())}/automations/${encodeURIComponent(params.automation_id.trim())}/trigger`
664
+ : `/v3/workers/${encodeURIComponent(params.worker_id.trim())}/trigger`;
665
+ const res = await this.transport.request(url, {
666
+ method: 'POST',
667
+ headers,
668
+ body,
669
+ });
670
+ if (!res.data || typeof res.data !== 'object' || !res.data.run) {
671
+ throw new SwarmValidationError('Malformed response envelope: expected worker run record');
672
+ }
673
+ return res.data.run;
674
+ }
675
+ /**
676
+ * Mints an authenticated scoped trigger token for this worker.
677
+ */
678
+ async mintTriggerToken(params) {
679
+ if (!params || typeof params !== 'object') {
680
+ throw new SwarmValidationError('Mint trigger token parameters are required');
681
+ }
682
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
683
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
684
+ }
685
+ const body = {};
686
+ if (params.name)
687
+ body.name = params.name.trim();
688
+ if (params.save_to_secrets !== undefined)
689
+ body.save_to_secrets = params.save_to_secrets;
690
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/token`, {
691
+ method: 'POST',
692
+ body,
693
+ });
694
+ if (!res.data || typeof res.data !== 'object' || typeof res.data.token !== 'string' || res.data.token === '') {
695
+ throw new SwarmValidationError('Malformed response envelope: expected trigger token result');
696
+ }
697
+ return res.data;
698
+ }
699
+ /**
700
+ * Lists historical and active execution runs for a worker with pagination.
701
+ */
702
+ async listRuns(params) {
703
+ if (!params || typeof params !== 'object') {
704
+ throw new SwarmValidationError('List runs parameters are required');
705
+ }
706
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
707
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
708
+ }
709
+ const q = new URLSearchParams();
710
+ if (params.limit !== undefined)
711
+ q.set('limit', String(params.limit));
712
+ if (params.cursor !== undefined && params.cursor.trim() !== '')
713
+ q.set('cursor', params.cursor.trim());
714
+ const qs = q.toString() ? `?${q.toString()}` : '';
715
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/runs${qs}`, { method: 'GET' });
716
+ if (!res.data || typeof res.data !== 'object' || !Array.isArray(res.data.runs)) {
717
+ throw new SwarmValidationError('Malformed response envelope: expected { runs: WorkerRunRecord[] }');
718
+ }
719
+ return {
720
+ runs: res.data.runs,
721
+ next_cursor: res.data.next_cursor,
722
+ };
723
+ }
724
+ /**
725
+ * Retrieves a single worker execution run by ID.
726
+ */
727
+ async getRun(params) {
728
+ if (!params || typeof params !== 'object') {
729
+ throw new SwarmValidationError('Get run parameters are required');
730
+ }
731
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
732
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
733
+ }
734
+ if (!params.run_id || typeof params.run_id !== 'string' || params.run_id.trim() === '') {
735
+ throw new SwarmValidationError('Run ID is required and cannot be blank');
736
+ }
737
+ try {
738
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/runs/${encodeURIComponent(params.run_id.trim())}`, { method: 'GET' });
739
+ if (!res.data || typeof res.data !== 'object' || !res.data.run) {
740
+ throw new SwarmValidationError('Malformed response envelope: expected { run: WorkerRunRecord }');
741
+ }
742
+ return res.data.run;
743
+ }
744
+ catch (err) {
745
+ if (err?.status === 404 || err?.statusCode === 404) {
746
+ return null;
747
+ }
748
+ throw err;
749
+ }
750
+ }
751
+ /**
752
+ * Cancels an active or admitted execution run.
753
+ */
754
+ async cancelRun(params) {
755
+ if (!params || typeof params !== 'object') {
756
+ throw new SwarmValidationError('Cancel run parameters are required');
757
+ }
758
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
759
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
760
+ }
761
+ if (!params.run_id || typeof params.run_id !== 'string' || params.run_id.trim() === '') {
762
+ throw new SwarmValidationError('Run ID is required and cannot be blank');
763
+ }
764
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/runs/${encodeURIComponent(params.run_id.trim())}/cancel`, { method: 'POST' });
765
+ if (!res.data || typeof res.data !== 'object' || !res.data.run) {
766
+ throw new SwarmValidationError('Malformed response envelope: expected { run: WorkerRunRecord }');
767
+ }
768
+ return res.data.run;
769
+ }
770
+ /**
771
+ * Retrieves revision history snapshots for a worker.
772
+ */
773
+ async getHistory(params) {
774
+ if (!params || typeof params !== 'object') {
775
+ throw new SwarmValidationError('History parameters are required');
776
+ }
777
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
778
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
779
+ }
780
+ const q = new URLSearchParams();
781
+ if (params.limit !== undefined)
782
+ q.set('limit', String(params.limit));
783
+ if (params.cursor !== undefined && params.cursor.trim() !== '')
784
+ q.set('cursor', params.cursor.trim());
785
+ const qs = q.toString() ? `?${q.toString()}` : '';
786
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/history${qs}`, { method: 'GET' });
787
+ if (!res.data || typeof res.data !== 'object' || !Array.isArray(res.data.revisions)) {
788
+ throw new SwarmValidationError('Malformed response envelope: expected { revisions: WorkerRevisionRecord[] }');
789
+ }
790
+ return {
791
+ history: res.data.revisions,
792
+ next_cursor: res.data.next_cursor,
793
+ };
794
+ }
795
+ /**
796
+ * Retrieves a specific pinned revision snapshot of a worker.
797
+ */
798
+ async getRevision(params) {
799
+ if (!params || typeof params !== 'object') {
800
+ throw new SwarmValidationError('Revision parameters are required');
801
+ }
802
+ if (!params.worker_id || typeof params.worker_id !== 'string' || params.worker_id.trim() === '') {
803
+ throw new SwarmValidationError('Worker ID is required and cannot be blank');
804
+ }
805
+ if (!Number.isSafeInteger(params.revision) || params.revision < 1) {
806
+ throw new SwarmValidationError('Explicit numeric revision >= 1 is required');
807
+ }
808
+ try {
809
+ const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/revisions/${params.revision}`, { method: 'GET' });
810
+ if (!res.data || typeof res.data !== 'object' || !res.data.revision) {
811
+ throw new SwarmValidationError('Malformed response envelope: expected { revision: WorkerRevisionRecord }');
812
+ }
813
+ return res.data.revision;
814
+ }
815
+ catch (err) {
816
+ if (err?.status === 404 || err?.statusCode === 404) {
817
+ return null;
818
+ }
819
+ throw err;
820
+ }
821
+ }
822
+ }