@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,513 @@
1
+ import { SwarmApiError, SwarmTimeoutError, } from './errors.js';
2
+ export class SwarmProjectsNamespace {
3
+ transport;
4
+ constructor(transport) {
5
+ this.transport = transport;
6
+ }
7
+ // ==========================================================================
8
+ // Project CRUD Operations
9
+ // ==========================================================================
10
+ /**
11
+ * Lists projects across the active account.
12
+ */
13
+ async list(params = {}, options) {
14
+ const q = new URLSearchParams();
15
+ if (typeof params.limit === 'number' && params.limit > 0) {
16
+ q.set('limit', String(params.limit));
17
+ }
18
+ const queryStr = q.toString() ? `?${q.toString()}` : '';
19
+ const res = await this.transport.request(`/v3/projects${queryStr}`, { method: 'GET', ...options });
20
+ if (Array.isArray(res.data)) {
21
+ return res.data;
22
+ }
23
+ if (res.data && typeof res.data === 'object' && 'projects' in res.data && Array.isArray(res.data.projects)) {
24
+ return res.data.projects;
25
+ }
26
+ return [];
27
+ }
28
+ /**
29
+ * Creates a new project in the active account.
30
+ */
31
+ async create(params, options) {
32
+ const res = await this.transport.request('/v3/projects', {
33
+ method: 'POST',
34
+ body: params,
35
+ ...options,
36
+ });
37
+ const data = res.data;
38
+ if (data && typeof data === 'object' && 'project' in data && data.project) {
39
+ return data.project;
40
+ }
41
+ if (data && typeof data === 'object' && 'id' in data) {
42
+ return data;
43
+ }
44
+ throw new SwarmApiError('Malformed response: missing project record', { status: res.status, details: data });
45
+ }
46
+ /**
47
+ * Retrieves a single project by ID.
48
+ */
49
+ async get(projectId, options) {
50
+ const id = encodeURIComponent(projectId.trim());
51
+ const res = await this.transport.request(`/v3/projects/${id}`, { method: 'GET', ...options });
52
+ const data = res.data;
53
+ if (data && typeof data === 'object' && 'project' in data && data.project) {
54
+ return data.project;
55
+ }
56
+ if (data && typeof data === 'object' && 'id' in data) {
57
+ return data;
58
+ }
59
+ throw new SwarmApiError('Malformed response: missing project record', { status: res.status, details: data });
60
+ }
61
+ /**
62
+ * Updates an existing project's metadata, context, or bound workspaces.
63
+ */
64
+ async update(projectId, params, options) {
65
+ const id = encodeURIComponent(projectId.trim());
66
+ const res = await this.transport.request(`/v3/projects/${id}`, {
67
+ method: 'PATCH',
68
+ body: params,
69
+ ...options,
70
+ });
71
+ const data = res.data;
72
+ if (data && typeof data === 'object' && 'project' in data && data.project) {
73
+ return data.project;
74
+ }
75
+ if (data && typeof data === 'object' && 'id' in data) {
76
+ return data;
77
+ }
78
+ throw new SwarmApiError('Malformed response: missing project record', { status: res.status, details: data });
79
+ }
80
+ /**
81
+ * Deletes a project by ID.
82
+ */
83
+ async delete(projectId, options) {
84
+ const id = encodeURIComponent(projectId.trim());
85
+ const res = await this.transport.request(`/v3/projects/${id}`, { method: 'DELETE', ...options });
86
+ return res.data ?? { status: 'deleted', id: projectId.trim() };
87
+ }
88
+ /**
89
+ * Synthesizes Markdown project context from project name and linked workspaces.
90
+ */
91
+ async synthesizeContext(params, options) {
92
+ const res = await this.transport.request('/v3/projects/synthesize-context', {
93
+ method: 'POST',
94
+ body: params,
95
+ ...options,
96
+ });
97
+ return res.data?.project_context ?? '';
98
+ }
99
+ /**
100
+ * Clears orchestrator context for a project, archiving old session and provisioning replacement.
101
+ */
102
+ async clearContext(projectId, options) {
103
+ const id = encodeURIComponent(projectId.trim());
104
+ const res = await this.transport.request(`/v3/projects/${id}/orchestrator:clear-context`, { method: 'POST', ...options });
105
+ return res.data ?? { status: 'cleared' };
106
+ }
107
+ // ==========================================================================
108
+ // Project Media Sub-resource
109
+ // ==========================================================================
110
+ /**
111
+ * Lists media items attached to a project.
112
+ */
113
+ async listMedia(projectId, options) {
114
+ const id = encodeURIComponent(projectId.trim());
115
+ const res = await this.transport.request(`/v3/projects/${id}/media`, { method: 'GET', ...options });
116
+ if (Array.isArray(res.data)) {
117
+ return res.data;
118
+ }
119
+ if (res.data && typeof res.data === 'object' && 'media' in res.data && Array.isArray(res.data.media)) {
120
+ return res.data.media;
121
+ }
122
+ return [];
123
+ }
124
+ /**
125
+ * Uploads or attaches a media item to a project.
126
+ */
127
+ async uploadMedia(projectId, media, options) {
128
+ const id = encodeURIComponent(projectId.trim());
129
+ const res = await this.transport.request(`/v3/projects/${id}/media`, {
130
+ method: 'POST',
131
+ body: media,
132
+ ...options,
133
+ });
134
+ const data = res.data;
135
+ if (data && typeof data === 'object' && 'media' in data && data.media) {
136
+ return data.media;
137
+ }
138
+ if (data && typeof data === 'object' && 'id' in data) {
139
+ return data;
140
+ }
141
+ throw new SwarmApiError('Malformed response: missing media record', { status: res.status, details: data });
142
+ }
143
+ /**
144
+ * Removes an attached media item from a project.
145
+ */
146
+ async deleteMedia(projectId, mediaId, options) {
147
+ const pId = encodeURIComponent(projectId.trim());
148
+ const mId = encodeURIComponent(mediaId.trim());
149
+ const res = await this.transport.request(`/v3/projects/${pId}/media/${mId}`, { method: 'DELETE', ...options });
150
+ return res.data ?? { removed: true, media_id: mediaId.trim(), uploaded_media: [] };
151
+ }
152
+ // ==========================================================================
153
+ // Project Tasks CRUD & Previews
154
+ // ==========================================================================
155
+ /**
156
+ * Lists tasks associated with a project.
157
+ */
158
+ async listTasks(projectId, options, view = 'active') {
159
+ const id = encodeURIComponent(projectId.trim());
160
+ const res = await this.transport.request(`/v3/projects/${id}/tasks${view === 'archived' ? '?view=archived' : ''}`, { method: 'GET', ...options });
161
+ if (Array.isArray(res.data)) {
162
+ return res.data;
163
+ }
164
+ if (res.data && typeof res.data === 'object' && 'tasks' in res.data && Array.isArray(res.data.tasks)) {
165
+ return res.data.tasks;
166
+ }
167
+ return [];
168
+ }
169
+ /**
170
+ * Creates a new autonomous task inside a project.
171
+ */
172
+ async createTask(projectId, params, options) {
173
+ const id = encodeURIComponent(projectId.trim());
174
+ const res = await this.transport.request(`/v3/projects/${id}/tasks`, {
175
+ method: 'POST',
176
+ body: params,
177
+ ...options,
178
+ });
179
+ const data = res.data;
180
+ if (data && typeof data === 'object' && 'task' in data && data.task) {
181
+ return {
182
+ task: data.task,
183
+ model_preview: data.model_preview,
184
+ };
185
+ }
186
+ if (data && typeof data === 'object' && 'id' in data) {
187
+ return {
188
+ task: data,
189
+ };
190
+ }
191
+ throw new SwarmApiError('Malformed response: missing task record', { status: res.status, details: data });
192
+ }
193
+ /**
194
+ * Retrieves a single task by ID within a project, including model preview.
195
+ */
196
+ async getTask(projectId, taskId, options) {
197
+ const pId = encodeURIComponent(projectId.trim());
198
+ const tId = encodeURIComponent(taskId.trim());
199
+ const res = await this.transport.request(`/v3/projects/${pId}/tasks/${tId}`, { method: 'GET', ...options });
200
+ const data = res.data;
201
+ if (data && typeof data === 'object' && 'task' in data && data.task) {
202
+ return {
203
+ task: data.task,
204
+ model_preview: data.model_preview,
205
+ };
206
+ }
207
+ if (data && typeof data === 'object' && 'id' in data) {
208
+ return {
209
+ task: data,
210
+ };
211
+ }
212
+ throw new SwarmApiError('Malformed response: missing task record', { status: res.status, details: data });
213
+ }
214
+ /**
215
+ * Updates an existing pending or queued task in a project.
216
+ */
217
+ async updateTask(projectId, taskId, params, options) {
218
+ const pId = encodeURIComponent(projectId.trim());
219
+ const tId = encodeURIComponent(taskId.trim());
220
+ const res = await this.transport.request(`/v3/projects/${pId}/tasks/${tId}`, {
221
+ method: 'PATCH',
222
+ body: params,
223
+ ...options,
224
+ });
225
+ const data = res.data;
226
+ if (data && typeof data === 'object' && 'task' in data && data.task) {
227
+ return data.task;
228
+ }
229
+ if (data && typeof data === 'object' && 'id' in data) {
230
+ return data;
231
+ }
232
+ throw new SwarmApiError('Malformed response: missing task record', { status: res.status, details: data });
233
+ }
234
+ /** Archives a task only at the supplied revision. */
235
+ async archiveTask(projectId, taskId, revision, options) {
236
+ const path = `/v3/projects/${encodeURIComponent(projectId.trim())}/tasks/${encodeURIComponent(taskId.trim())}/archive`;
237
+ const res = await this.transport.request(path, { method: 'POST', body: { revision }, ...options });
238
+ if (!res.data?.task)
239
+ throw new SwarmApiError('Malformed response: missing archived task', { status: res.status, details: res.data });
240
+ return res.data.task;
241
+ }
242
+ /** Deletes only an archived, unlaunched task at the supplied revision. */
243
+ async deleteTask(projectId, taskId, revision, options) {
244
+ const pId = encodeURIComponent(projectId.trim());
245
+ const tId = encodeURIComponent(taskId.trim());
246
+ const res = await this.transport.request(`/v3/projects/${pId}/tasks/${tId}?revision=${encodeURIComponent(String(revision))}`, { method: 'DELETE', ...options });
247
+ return res.data ?? { status: 'deleted', task_id: taskId.trim() };
248
+ }
249
+ /**
250
+ * Previews how a task will be routed, planned, and modeled before creating it.
251
+ */
252
+ async previewTask(projectId, params, options) {
253
+ const id = encodeURIComponent(projectId.trim());
254
+ const res = await this.transport.request(`/v3/projects/${id}/tasks:preview`, {
255
+ method: 'POST',
256
+ body: params,
257
+ ...options,
258
+ });
259
+ return res.data;
260
+ }
261
+ /**
262
+ * Retrieves the authoritative model preview for an existing task.
263
+ */
264
+ async getTaskModelPreview(projectId, taskId, options) {
265
+ const pId = encodeURIComponent(projectId.trim());
266
+ const tId = encodeURIComponent(taskId.trim());
267
+ const res = await this.transport.request(`/v3/projects/${pId}/tasks/${tId}/model-preview`, { method: 'GET', ...options });
268
+ return res.data;
269
+ }
270
+ // ==========================================================================
271
+ // Task Plan Lifecycle: Approval, Rejection, Reopening, Refinement, Completion
272
+ // ==========================================================================
273
+ /**
274
+ * Approves a task session with optional exact revision guards.
275
+ * If the task is bound to a structured plan, exact session_id, plan_id, and definition_revision
276
+ * guards are enforced by the backend to prevent stale approvals.
277
+ */
278
+ async approveTask(projectId, taskId, guards, options) {
279
+ const pId = encodeURIComponent(projectId.trim());
280
+ const tId = encodeURIComponent(taskId.trim());
281
+ const res = await this.transport.request(`/v3/projects/${pId}/tasks/${tId}/approve`, {
282
+ method: 'POST',
283
+ body: guards ?? {},
284
+ ...options,
285
+ });
286
+ const data = res.data;
287
+ if (data && typeof data === 'object' && 'task' in data && data.task) {
288
+ return {
289
+ status: data.status ?? 'approved',
290
+ task: data.task,
291
+ };
292
+ }
293
+ throw new SwarmApiError('Malformed response: missing task in approve response', {
294
+ status: res.status,
295
+ details: data,
296
+ });
297
+ }
298
+ /**
299
+ * Convenient alias for approveTask.
300
+ */
301
+ async acceptTask(projectId, taskId, guards, options) {
302
+ return this.approveTask(projectId, taskId, guards, options);
303
+ }
304
+ /**
305
+ * Rejects a task and marks its bound plan as rejected.
306
+ */
307
+ async rejectTask(projectId, taskId, guards, options) {
308
+ const pId = encodeURIComponent(projectId.trim());
309
+ const tId = encodeURIComponent(taskId.trim());
310
+ const res = await this.transport.request(`/v3/projects/${pId}/tasks/${tId}/reject`, { method: 'POST', body: guards ?? {}, ...options });
311
+ const data = res.data;
312
+ if (data && typeof data === 'object' && 'task' in data && data.task) {
313
+ return {
314
+ status: data.status ?? 'rejected',
315
+ task: data.task,
316
+ };
317
+ }
318
+ throw new SwarmApiError('Malformed response: missing task in reject response', {
319
+ status: res.status,
320
+ details: data,
321
+ });
322
+ }
323
+ /**
324
+ * Reopens a completed or needs_review task with optional feedback instructions.
325
+ */
326
+ async reopenTask(projectId, taskId, params, options) {
327
+ const pId = encodeURIComponent(projectId.trim());
328
+ const tId = encodeURIComponent(taskId.trim());
329
+ const res = await this.transport.request(`/v3/projects/${pId}/tasks/${tId}/reopen`, {
330
+ method: 'POST',
331
+ body: params ?? {},
332
+ ...options,
333
+ });
334
+ const data = res.data;
335
+ if (data && typeof data === 'object' && 'task' in data && data.task) {
336
+ return {
337
+ status: data.status ?? 'reopened',
338
+ task: data.task,
339
+ };
340
+ }
341
+ throw new SwarmApiError('Malformed response: missing task in reopen response', {
342
+ status: res.status,
343
+ details: data,
344
+ });
345
+ }
346
+ /**
347
+ * Marks a task as accepted and completed by the user.
348
+ */
349
+ async completeTask(projectId, taskId, options) {
350
+ const pId = encodeURIComponent(projectId.trim());
351
+ const tId = encodeURIComponent(taskId.trim());
352
+ const res = await this.transport.request(`/v3/projects/${pId}/tasks/${tId}/complete`, { method: 'POST', ...options });
353
+ const data = res.data;
354
+ if (data && typeof data === 'object' && 'task' in data && data.task) {
355
+ return {
356
+ status: data.status ?? 'completed',
357
+ task: data.task,
358
+ };
359
+ }
360
+ throw new SwarmApiError('Malformed response: missing task in complete response', {
361
+ status: res.status,
362
+ details: data,
363
+ });
364
+ }
365
+ /**
366
+ * Refines a task plan based on user feedback directives or error recovery strategy.
367
+ */
368
+ async refineTask(projectId, taskId, params, options) {
369
+ const pId = encodeURIComponent(projectId.trim());
370
+ const tId = encodeURIComponent(taskId.trim());
371
+ const res = await this.transport.request(`/v3/projects/${pId}/tasks/${tId}/refine`, {
372
+ method: 'POST',
373
+ body: params,
374
+ ...options,
375
+ });
376
+ const data = res.data;
377
+ if (data && typeof data === 'object' && 'task' in data && data.task) {
378
+ return {
379
+ status: data.status ?? 'refined',
380
+ task: data.task,
381
+ };
382
+ }
383
+ throw new SwarmApiError('Malformed response: missing task in refine response', {
384
+ status: res.status,
385
+ details: data,
386
+ });
387
+ }
388
+ // ==========================================================================
389
+ // Task Integration & Task Program Execution
390
+ // ==========================================================================
391
+ /**
392
+ * Integrates task commits into the parent workspace repository.
393
+ */
394
+ async integrateTask(projectId, taskId, options) {
395
+ const pId = encodeURIComponent(projectId.trim());
396
+ const tId = encodeURIComponent(taskId.trim());
397
+ const res = await this.transport.request(`/v3/projects/${pId}/tasks/${tId}/integrate`, { method: 'POST', ...options });
398
+ return res.data;
399
+ }
400
+ /**
401
+ * Deploys a task program for staged multi-agent execution.
402
+ */
403
+ async deployTaskProgram(projectId, taskId, options) {
404
+ const pId = encodeURIComponent(projectId.trim());
405
+ const tId = encodeURIComponent(taskId.trim());
406
+ const res = await this.transport.request(`/v3/projects/${pId}/tasks/${tId}/program:deploy`, { method: 'POST', ...options });
407
+ return res.data;
408
+ }
409
+ /**
410
+ * Redeploys a failed or rejected job within a deployed task program.
411
+ */
412
+ async redeployTaskProgramJob(projectId, taskId, params, options) {
413
+ const pId = encodeURIComponent(projectId.trim());
414
+ const tId = encodeURIComponent(taskId.trim());
415
+ const res = await this.transport.request(`/v3/projects/${pId}/tasks/${tId}/program:redeploy-job`, {
416
+ method: 'POST',
417
+ body: params,
418
+ ...options,
419
+ });
420
+ return res.data;
421
+ }
422
+ /**
423
+ * Inspects the durable TaskProgramRecord for a deployed task program.
424
+ */
425
+ async getTaskProgram(projectId, taskId, options) {
426
+ const pId = encodeURIComponent(projectId.trim());
427
+ const tId = encodeURIComponent(taskId.trim());
428
+ const res = await this.transport.request(`/v3/projects/${pId}/tasks/${tId}/program`, { method: 'GET', ...options });
429
+ return res.data;
430
+ }
431
+ // ==========================================================================
432
+ // Sync Stream, Event Replay, and Polling Helpers
433
+ // ==========================================================================
434
+ /**
435
+ * Streams outbox events after an opaque endpoint cursor via HTTP POST /v3/sync/stream.
436
+ * Cursors remain strictly opaque strings.
437
+ */
438
+ async syncStream(params, options) {
439
+ const res = await this.transport.request('/v3/sync/stream', {
440
+ method: 'POST',
441
+ body: params,
442
+ ...options,
443
+ });
444
+ return res.data;
445
+ }
446
+ /**
447
+ * Replays events starting after an opaque endpoint cursor.
448
+ */
449
+ async replayEvents(cursor, params = {}, options) {
450
+ return this.syncStream({
451
+ ...params,
452
+ endpoint_cursor: cursor,
453
+ }, options);
454
+ }
455
+ /**
456
+ * Polls a task until a predicate condition is satisfied, or times out/aborts.
457
+ */
458
+ async waitForTask(projectId, taskId, predicate, options = {}) {
459
+ const timeoutMs = options.timeoutMs ?? 60_000;
460
+ const pollIntervalMs = options.pollIntervalMs ?? 500;
461
+ const deadline = Date.now() + timeoutMs;
462
+ while (Date.now() < deadline) {
463
+ if (options.signal?.aborted) {
464
+ throw new SwarmApiError('Request aborted by caller', { status: 0 });
465
+ }
466
+ const { task } = await this.getTask(projectId, taskId, {
467
+ signal: options.signal,
468
+ timeoutMs: options.timeoutMs,
469
+ });
470
+ if (predicate(task)) {
471
+ return task;
472
+ }
473
+ await new Promise((resolve, reject) => {
474
+ const timer = setTimeout(resolve, pollIntervalMs);
475
+ if (options.signal) {
476
+ options.signal.addEventListener('abort', () => {
477
+ clearTimeout(timer);
478
+ reject(new SwarmApiError('Request aborted by caller', { status: 0 }));
479
+ }, { once: true });
480
+ }
481
+ });
482
+ }
483
+ throw new SwarmTimeoutError(`Task did not satisfy condition within ${timeoutMs}ms`, timeoutMs);
484
+ }
485
+ /**
486
+ * Async generator yielding sync stream events starting after an opaque cursor,
487
+ * respecting cancellation via AbortSignal.
488
+ */
489
+ async *streamEvents(initialCursor, params = {}, options = {}) {
490
+ let cursor = initialCursor;
491
+ const pollIntervalMs = options.pollIntervalMs ?? 500;
492
+ while (!options.signal?.aborted) {
493
+ const res = await this.syncStream({ ...params, endpoint_cursor: cursor }, { signal: options.signal, timeoutMs: options.timeoutMs });
494
+ cursor = res.endpoint_cursor;
495
+ for (const event of res.events || []) {
496
+ yield event;
497
+ }
498
+ if (!res.has_more) {
499
+ if (options.signal?.aborted)
500
+ break;
501
+ await new Promise((resolve) => {
502
+ const timer = setTimeout(resolve, pollIntervalMs);
503
+ if (options.signal) {
504
+ options.signal.addEventListener('abort', () => {
505
+ clearTimeout(timer);
506
+ resolve();
507
+ }, { once: true });
508
+ }
509
+ });
510
+ }
511
+ }
512
+ }
513
+ }
@@ -0,0 +1,160 @@
1
+ import type { SwarmTransport } from './transport.js';
2
+ export interface CredentialInput {
3
+ provider: string;
4
+ type: string;
5
+ id?: string;
6
+ label?: string;
7
+ tags?: string[];
8
+ api_key?: string;
9
+ access_token?: string;
10
+ refresh_token?: string;
11
+ expires_at?: number;
12
+ account_id?: string;
13
+ active?: boolean;
14
+ }
15
+ export interface CredentialConnection {
16
+ connected: boolean;
17
+ method?: string;
18
+ message?: string;
19
+ verified_at?: number;
20
+ }
21
+ /** Redacted server status: never includes credential material. */
22
+ export interface CredentialStatus {
23
+ id: string;
24
+ provider: string;
25
+ active: boolean;
26
+ auth_type: string;
27
+ label?: string;
28
+ tags?: string[];
29
+ updated_at: number;
30
+ created_at: number;
31
+ expires_at?: number;
32
+ last4?: string;
33
+ has_refresh_token?: boolean;
34
+ has_account_id?: boolean;
35
+ storage_mode: string;
36
+ connection?: CredentialConnection;
37
+ auto_defaults?: {
38
+ applied: boolean;
39
+ error?: string;
40
+ provider?: string;
41
+ model?: string;
42
+ thinking?: string;
43
+ global_model?: boolean;
44
+ agents?: string[];
45
+ subagents?: string[];
46
+ utility_provider?: string;
47
+ utility_model?: string;
48
+ utility_thinking?: string;
49
+ };
50
+ }
51
+ export interface CredentialList {
52
+ provider?: string;
53
+ query?: string;
54
+ total: number;
55
+ records: CredentialStatus[];
56
+ providers?: string[];
57
+ }
58
+ export interface CodexLogin {
59
+ session_id: string;
60
+ provider: string;
61
+ method: 'browser' | 'manual' | 'device';
62
+ label?: string;
63
+ active: boolean;
64
+ auth_url?: string;
65
+ verification_url?: string;
66
+ user_code?: string;
67
+ expires_at?: number;
68
+ status: string;
69
+ error?: string;
70
+ credential?: CredentialStatus;
71
+ }
72
+ export declare class SwarmCredentialsNamespace {
73
+ private readonly transport;
74
+ constructor(transport: SwarmTransport);
75
+ list(options?: {
76
+ provider?: string;
77
+ query?: string;
78
+ limit?: number;
79
+ }): Promise<CredentialList>;
80
+ save(input: CredentialInput): Promise<CredentialStatus>;
81
+ activate(provider: string, id: string): Promise<CredentialStatus>;
82
+ verify(provider: string, id: string): Promise<{
83
+ provider: string;
84
+ id: string;
85
+ connection: CredentialConnection;
86
+ }>;
87
+ delete(provider: string, id: string): Promise<{
88
+ ok: boolean;
89
+ deleted: boolean;
90
+ provider: string;
91
+ id: string;
92
+ cleanup: Record<string, unknown>;
93
+ }>;
94
+ }
95
+ export declare class SwarmCodexAuthNamespace {
96
+ private readonly transport;
97
+ constructor(transport: SwarmTransport);
98
+ start(input: {
99
+ method: 'browser' | 'manual' | 'device';
100
+ label?: string;
101
+ active?: boolean;
102
+ }): Promise<CodexLogin>;
103
+ status(session_id: string): Promise<CodexLogin>;
104
+ complete(session_id: string, callback_input: string): Promise<CodexLogin>;
105
+ }
106
+ export interface OnboardingStatus {
107
+ ok: boolean;
108
+ needs_onboarding: boolean;
109
+ identity: {
110
+ bootstrapped: boolean;
111
+ user_id?: string;
112
+ account_scope_id?: string;
113
+ username?: string;
114
+ team_id?: string;
115
+ team_display_name?: string;
116
+ team_default?: boolean;
117
+ membership_role?: string;
118
+ };
119
+ heuristics: {
120
+ missing_swarm_name: boolean;
121
+ credential_count: number;
122
+ agent_count: number;
123
+ saved_workspace_count: number;
124
+ vault_configured: boolean;
125
+ };
126
+ config: {
127
+ swarm_name: string;
128
+ desktop_onboarding_complete: boolean;
129
+ mode: string;
130
+ port: number;
131
+ desktop_port: number;
132
+ advertise_port: number;
133
+ peer_transport_port: number;
134
+ [key: string]: unknown;
135
+ };
136
+ workspace_guidance?: Record<string, unknown>;
137
+ session?: {
138
+ expires_at?: string;
139
+ };
140
+ tailscale: Record<string, unknown>;
141
+ }
142
+ export interface OnboardingUpdate {
143
+ username?: string;
144
+ swarm_name?: string;
145
+ desktop_onboarding_complete?: boolean;
146
+ mode?: string;
147
+ port?: number;
148
+ advertise_host?: string;
149
+ advertise_port?: number;
150
+ tailscale_url?: string;
151
+ peer_transport_port?: number;
152
+ }
153
+ export declare class SwarmOnboardingNamespace {
154
+ private readonly transport;
155
+ constructor(transport: SwarmTransport);
156
+ get(): Promise<OnboardingStatus>;
157
+ update(body: OnboardingUpdate): Promise<OnboardingStatus>;
158
+ /** First credential only. Use auth.credentials.save for subsequent credentials. */
159
+ credential(body: Omit<CredentialInput, 'id'>): Promise<CredentialStatus>;
160
+ }