@swarm-agent/sdk 0.1.50 → 0.1.52

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.
package/README.md CHANGED
@@ -21,8 +21,8 @@ Requires Node 22 or newer (ESM). The package is public on npm:
21
21
  npm install @swarm-agent/sdk
22
22
  </copy>
23
23
 
24
- You need a running Swarm on Linux x86_64. Install one with
25
- `curl -fsSL https://swarmagent.dev/install | sh -s -- --yes`.
24
+ You need a running Swarm. Install the Swarm box (Ubuntu 24.04 x86_64) with
25
+ `curl -fsSL https://swarmagent.dev/install | sudo bash`.
26
26
 
27
27
  ## Connect to your Swarm
28
28
 
@@ -58,10 +58,14 @@ example, not source tests or node_modules. `prepack` builds locally; there are n
58
58
  install/prepare hooks. TypeScript/tsx are build/test tools, not runtime dependencies.
59
59
  CommonJS `require` and non-Node runtimes are not validated by this packaging step.
60
60
 
61
- For the headless container, use the matching `@swarm-agent/cli` package and explicitly
62
- export a scoped token through `swarm-headless setup -- sdk-token`. Connect to
63
- `http://127.0.0.1:7783`; **do not** use Desktop bootstrap or a privileged socket.
64
- The headless listener allows session operations only, not the complete API below.
61
+ On the Swarm box, `http://127.0.0.1:7783` is the scoped-token listener. The AI
62
+ key the installer wrote to `~/.config/swarm/ai-key` (a new one:
63
+ `sudo bash /var/lib/swarm-headless/src/containers/headless/app/install.sh connect-ai`)
64
+ works only through its MCP, `http://127.0.0.1:7783/mcp`, with any MCP client;
65
+ it reaches no SDK route. For the session routes there, use a client key (a full
66
+ AI key's `swarm_create_client_key` mints one); **do not** use Desktop bootstrap
67
+ or a privileged socket. A client key reaches session operations only, not the
68
+ complete API below.
65
69
  The packaged `examples/headless-session.ts` imports `@swarm-agent/sdk` and can be copied
66
70
  into your consumer and run with an explicitly installed `tsx` runner. Protect its
67
71
  `SWARM_SDK_TOKEN_FILE` (0600); the example asks before each tool approval and uses
@@ -451,13 +455,28 @@ for (const ws of workspaces) {
451
455
 
452
456
  Manage multi-workspace projects, autonomous tasks, route previews, plan review lifecycles, and opaque event sync streams:
453
457
 
458
+ A project groups registered workspaces: the existing folders or repositories the
459
+ work lives in (`client.workspaces.add({ path, context_only: true,
460
+ require_existing_content: true, make_current: false })`), not an empty
461
+ repository created for it. Creating it makes Swarm write the project's
462
+ `project.md` (the orchestrator's context) from the workspaces' AGENTS.md, README
463
+ and file tree; `context_generation.status` moves from `pending`/`running` to
464
+ `ready` or `failed` (`retryContext(id, attempt)`). Open orchestrator
465
+ conversations once it is `ready`. Workspace and `project_context` edits through
466
+ `update` are refused until then.
467
+
454
468
  ```typescript
455
- // Create a new project aggregating workspaces
456
- const project = await client.projects.create({
469
+ // Create a new project aggregating the person's existing workspaces
470
+ let project = await client.projects.create({
457
471
  name: 'Mobile Core Redesign',
458
472
  description: 'Refactor mobile navigation and auth screens',
459
473
  workspaces: [{ path: '/workspaces/mobile-app', role: 'primary_code' }],
460
474
  });
475
+ // Re-read until project.md is generated (or follow realtime project updates)
476
+ project = await client.projects.get(project.id);
477
+ if (project.context_generation?.status === 'failed') {
478
+ project = await client.projects.retryContext(project.id, project.context_generation.attempt);
479
+ }
461
480
 
462
481
  // Create an autonomous task with agent routing
463
482
  const { task, model_preview } = await client.projects.createTask(project.id, {
package/dist/auth.d.ts CHANGED
@@ -25,10 +25,11 @@ export declare class SwarmAuthNamespace {
25
25
  /**
26
26
  * Creates an AI key for Swarm Control (`/mcp` on the scoped-token gateway).
27
27
  * `read` keys see and call only read tools; `write` keys may also start and
28
- * steer sessions; neither may approve tool calls or manage anything. `full`
28
+ * steer sessions and start the person's ChatGPT sign-in (they finish it in
29
+ * their own browser); neither may approve tool calls or manage anything. `full`
29
30
  * keys are for an AI the owner trusts to run the box: they also approve
30
- * tool calls and manage models, workers, limits, custom agents, client app
31
- * keys and ChatGPT sign-in. Every level reaches only `/mcp`. Lifetime
31
+ * tool calls and manage models, workers, limits, custom agents and client app
32
+ * keys. Every level reaches only `/mcp`. Lifetime
32
33
  * defaults to 30 days (at most 365). Owner only.
33
34
  */
34
35
  createAIKey(params: {
package/dist/auth.js CHANGED
@@ -57,10 +57,11 @@ export class SwarmAuthNamespace {
57
57
  /**
58
58
  * Creates an AI key for Swarm Control (`/mcp` on the scoped-token gateway).
59
59
  * `read` keys see and call only read tools; `write` keys may also start and
60
- * steer sessions; neither may approve tool calls or manage anything. `full`
60
+ * steer sessions and start the person's ChatGPT sign-in (they finish it in
61
+ * their own browser); neither may approve tool calls or manage anything. `full`
61
62
  * keys are for an AI the owner trusts to run the box: they also approve
62
- * tool calls and manage models, workers, limits, custom agents, client app
63
- * keys and ChatGPT sign-in. Every level reaches only `/mcp`. Lifetime
63
+ * tool calls and manage models, workers, limits, custom agents and client app
64
+ * keys. Every level reaches only `/mcp`. Lifetime
64
65
  * defaults to 30 days (at most 365). Owner only.
65
66
  */
66
67
  async createAIKey(params) {
package/dist/box.d.ts CHANGED
@@ -10,6 +10,26 @@ export interface BoxSummary {
10
10
  machine: {
11
11
  name?: string;
12
12
  uptime_ms: number;
13
+ version?: string;
14
+ commit?: string;
15
+ /** The installer's update state (install.sh update), when it has one. */
16
+ update?: {
17
+ auto?: 'on' | 'off';
18
+ channel?: string;
19
+ /** current, waiting, waiting_review, blocked, building, waiting_idle, installed, rolled_back or failed. */
20
+ state?: string;
21
+ reason?: string;
22
+ running?: string;
23
+ candidate?: string;
24
+ at?: number;
25
+ };
26
+ };
27
+ /** What a restart of Swarm would interrupt now, across the machine. */
28
+ busy: {
29
+ busy: boolean;
30
+ sessions: number;
31
+ worker_runs: number;
32
+ environment_builds: number;
13
33
  };
14
34
  sandbox: {
15
35
  mode: string;
@@ -1,5 +1,5 @@
1
1
  import type { SwarmTransport } from './transport.js';
2
- import type { ApproveProjectTaskResult, ClearProjectContextResult, CompleteProjectTaskResult, CreateProjectParams, CreateProjectTaskParams, CreateProjectTaskResult, DeleteProjectMediaResult, DeleteProjectResult, DeleteProjectTaskResult, DeployProjectTaskProgramResult, GetProjectTaskProgramResult, GetProjectTaskResult, IntegrateProjectTaskOptions, IntegrateProjectTaskResult, IntegrateProjectTaskSelection, ListProjectsParams, PreviewProjectTaskParams, ProjectRecord, ProjectTaskApprovalGuards, ProjectTaskMediaRef, ProjectTaskModelPreviewResult, ProjectTaskPreviewResult, ProjectTaskRecord, RedeployProjectTaskJobResult, RefineProjectTaskParams, RefineProjectTaskResult, RejectProjectTaskResult, ReopenProjectTaskResult, RequestOptions, SessionRecord, SyncStreamParams, SyncStreamResult, SynthesizeProjectContextParams, UpdateProjectParams, UpdateProjectTaskParams } from './types.js';
2
+ import type { ApproveProjectTaskResult, ClearProjectContextResult, CompleteProjectTaskResult, CreateProjectParams, CreateProjectTaskParams, CreateProjectTaskResult, DeleteProjectMediaResult, DeleteProjectResult, DeleteProjectTaskResult, DeployProjectTaskProgramResult, GetProjectTaskProgramResult, GetProjectTaskResult, IntegrateProjectTaskOptions, IntegrateProjectTaskResult, IntegrateProjectTaskSelection, ListProjectsParams, PreviewProjectTaskParams, ProjectRecord, ProjectTaskApprovalGuards, ProjectTaskMediaRef, ProjectTaskModelPreviewResult, ProjectTaskPreviewResult, ProjectTaskRecord, RedeployProjectTaskJobResult, RefineProjectTaskParams, RefineProjectTaskResult, RejectProjectTaskResult, ReopenProjectTaskResult, RequestOptions, SessionRecord, SyncStreamParams, SyncStreamResult, UpdateProjectParams, UpdateProjectTaskParams } from './types.js';
3
3
  export declare class SwarmProjectsNamespace {
4
4
  private readonly transport;
5
5
  constructor(transport: SwarmTransport);
@@ -65,10 +65,6 @@ export declare class SwarmProjectsNamespace {
65
65
  * Deletes a project by ID.
66
66
  */
67
67
  delete(projectId: string, options?: RequestOptions): Promise<DeleteProjectResult>;
68
- /**
69
- * Synthesizes Markdown project context from project name and linked workspaces.
70
- */
71
- synthesizeContext(params: SynthesizeProjectContextParams, options?: RequestOptions): Promise<string>;
72
68
  /**
73
69
  * Clears orchestrator context for a project, archiving old session and provisioning replacement.
74
70
  */
package/dist/projects.js CHANGED
@@ -178,17 +178,6 @@ export class SwarmProjectsNamespace {
178
178
  const res = await this.transport.request(`/v3/projects/${id}`, { method: 'DELETE', ...options });
179
179
  return res.data ?? { status: 'deleted', id: projectId.trim() };
180
180
  }
181
- /**
182
- * Synthesizes Markdown project context from project name and linked workspaces.
183
- */
184
- async synthesizeContext(params, options) {
185
- const res = await this.transport.request('/v3/projects/synthesize-context', {
186
- method: 'POST',
187
- body: params,
188
- ...options,
189
- });
190
- return res.data?.project_context ?? '';
191
- }
192
181
  /**
193
182
  * Clears orchestrator context for a project, archiving old session and provisioning replacement.
194
183
  */
package/dist/types.d.ts CHANGED
@@ -500,10 +500,6 @@ export interface UpdateProjectParams {
500
500
  export interface ListProjectsParams {
501
501
  limit?: number;
502
502
  }
503
- export interface SynthesizeProjectContextParams {
504
- name: string;
505
- workspaces: string[];
506
- }
507
503
  export interface DeleteProjectResult {
508
504
  status: string;
509
505
  id: string;
@@ -982,10 +978,18 @@ export interface WorkerAutomationDefinition {
982
978
  plan_document: SessionPlanDocument;
983
979
  input_requirements?: WorkerInputRequirement[] | null;
984
980
  deliverable_requirements?: WorkerDeliverableRequirement[] | null;
981
+ /** Registered workspace this automation's runs work in; absent means the worker's primary binding. */
982
+ workspace_id?: string | null;
985
983
  revision: number;
986
984
  created_at: number;
987
985
  updated_at: number;
988
986
  }
987
+ /**
988
+ * Code-owned system agent that runs a worker's jobs. Absent means `swarm`.
989
+ * `swarm` executes jobs as accepted plans; `coder`, `designer` and `finder`
990
+ * run their compiled agent in an auto session.
991
+ */
992
+ export type WorkerRole = 'swarm' | 'coder' | 'designer' | 'finder';
989
993
  export interface WorkerAutomationInput {
990
994
  name: string;
991
995
  description?: string;
@@ -1001,10 +1005,13 @@ export interface WorkerAutomationInput {
1001
1005
  plan_document: SessionPlanDocument;
1002
1006
  input_requirements?: WorkerInputRequirement[];
1003
1007
  deliverable_requirements?: WorkerDeliverableRequirement[];
1008
+ /** Registered workspace this automation's runs work in. Required for schedules of a worker with no primary binding. */
1009
+ workspace_id?: string;
1004
1010
  }
1005
1011
  export interface WorkerRecord {
1006
1012
  id: string;
1007
1013
  account_scope_id: string;
1014
+ role?: WorkerRole | null;
1008
1015
  name: string;
1009
1016
  description?: string | null;
1010
1017
  instructions: string;
@@ -1038,6 +1045,12 @@ export interface WorkerRunRecord {
1038
1045
  automation_id?: string;
1039
1046
  automation_revision?: number;
1040
1047
  occurrence_id?: string;
1048
+ /** Workspace pinned at admission. */
1049
+ workspace_id?: string;
1050
+ /** `worker_job` when the request or automation named the workspace, `worker_binding` when it came from the primary binding. */
1051
+ workspace_source?: 'worker_job' | 'worker_binding' | string;
1052
+ /** Worker role pinned at admission; absent means `swarm`. */
1053
+ role?: WorkerRole | string;
1041
1054
  session_id?: string;
1042
1055
  request_source: 'direct' | 'schedule' | 'trigger' | 'test_run' | 'orchestrator' | string;
1043
1056
  input?: Record<string, unknown>;
@@ -1081,6 +1094,7 @@ export interface PortableWorkerDefinition {
1081
1094
  provenance?: PortableWorkerProvenance | null;
1082
1095
  }
1083
1096
  export interface CreateWorkerParams {
1097
+ role?: WorkerRole;
1084
1098
  name: string;
1085
1099
  description?: string;
1086
1100
  instructions?: string;
@@ -1091,6 +1105,7 @@ export interface CreateWorkerParams {
1091
1105
  idempotency_key: string;
1092
1106
  }
1093
1107
  export interface UpdateWorkerParams {
1108
+ role?: WorkerRole;
1094
1109
  name?: string;
1095
1110
  description?: string;
1096
1111
  instructions?: string;
@@ -1174,6 +1189,10 @@ export interface DirectWorkerRequestParams {
1174
1189
  prompt?: string;
1175
1190
  input?: Record<string, unknown>;
1176
1191
  idempotency_key?: string;
1192
+ /** Workspace this job works in (registered workspace ID). Required when the worker has no primary binding. */
1193
+ workspace_id?: string;
1194
+ /** Alternative to workspace_id: the exact root path of a registered workspace. */
1195
+ workspace_path?: string;
1177
1196
  }
1178
1197
  export interface TestWorkerRunParams {
1179
1198
  worker_id: string;
@@ -1181,6 +1200,10 @@ export interface TestWorkerRunParams {
1181
1200
  prompt?: string;
1182
1201
  input?: Record<string, unknown>;
1183
1202
  idempotency_key?: string;
1203
+ /** Workspace this job works in (registered workspace ID). */
1204
+ workspace_id?: string;
1205
+ /** Alternative to workspace_id: the exact root path of a registered workspace. */
1206
+ workspace_path?: string;
1184
1207
  }
1185
1208
  export interface TriggerWorkerParams {
1186
1209
  worker_id: string;
package/dist/workers.d.ts CHANGED
@@ -25,6 +25,12 @@ export declare class SwarmWorkersNamespace {
25
25
  * Lists durable workers with pagination, lifecycle filters, and cursor support.
26
26
  */
27
27
  list(params?: ListWorkersParams): Promise<ListWorkersResult>;
28
+ /**
29
+ * Creates and activates the box's missing premade workers (Coder, Designer,
30
+ * Finder) and returns all three. Existing presets are returned unchanged.
31
+ * Presets are box-level: every job names its workspace.
32
+ */
33
+ ensurePresets(): Promise<WorkerRecord[]>;
28
34
  /**
29
35
  * Updates a worker's definition with an explicit expected revision for optimistic concurrency.
30
36
  * Body carries expected_revision only (no query params, no local_bindings).
package/dist/workers.js CHANGED
@@ -39,6 +39,8 @@ export class SwarmWorkersNamespace {
39
39
  instructions: params.instructions,
40
40
  idempotency_key: params.idempotency_key.trim(),
41
41
  };
42
+ if (params.role !== undefined)
43
+ body.role = params.role;
42
44
  if (params.description !== undefined)
43
45
  body.description = params.description;
44
46
  if (params.requested_capabilities !== undefined)
@@ -132,6 +134,21 @@ export class SwarmWorkersNamespace {
132
134
  next_cursor: typeof res.data.next_cursor === 'string' && res.data.next_cursor.length > 0 ? res.data.next_cursor : undefined,
133
135
  };
134
136
  }
137
+ /**
138
+ * Creates and activates the box's missing premade workers (Coder, Designer,
139
+ * Finder) and returns all three. Existing presets are returned unchanged.
140
+ * Presets are box-level: every job names its workspace.
141
+ */
142
+ async ensurePresets() {
143
+ const res = await this.transport.request('/v3/workers:ensure-presets', {
144
+ method: 'POST',
145
+ body: {},
146
+ });
147
+ if (!res.data || typeof res.data !== 'object' || !Array.isArray(res.data.workers)) {
148
+ throw new SwarmValidationError('Malformed response envelope: expected workers array');
149
+ }
150
+ return res.data.workers;
151
+ }
135
152
  /**
136
153
  * Updates a worker's definition with an explicit expected revision for optimistic concurrency.
137
154
  * Body carries expected_revision only (no query params, no local_bindings).
@@ -151,6 +168,8 @@ export class SwarmWorkersNamespace {
151
168
  const body = {
152
169
  expected_revision: expectedRevision,
153
170
  };
171
+ if (params.role !== undefined)
172
+ body.role = params.role;
154
173
  if (params.name !== undefined)
155
174
  body.name = params.name;
156
175
  if (params.description !== undefined)
@@ -593,6 +612,10 @@ export class SwarmWorkersNamespace {
593
612
  body.input = params.input;
594
613
  if (params.idempotency_key)
595
614
  body.idempotency_key = params.idempotency_key.trim();
615
+ if (params.workspace_id && params.workspace_id.trim() !== '')
616
+ body.workspace_id = params.workspace_id.trim();
617
+ if (params.workspace_path && params.workspace_path.trim() !== '')
618
+ body.workspace_path = params.workspace_path.trim();
596
619
  const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/direct`, {
597
620
  method: 'POST',
598
621
  headers,
@@ -629,6 +652,10 @@ export class SwarmWorkersNamespace {
629
652
  }
630
653
  if (params.idempotency_key)
631
654
  body.idempotency_key = params.idempotency_key.trim();
655
+ if (params.workspace_id && params.workspace_id.trim() !== '')
656
+ body.workspace_id = params.workspace_id.trim();
657
+ if (params.workspace_path && params.workspace_path.trim() !== '')
658
+ body.workspace_path = params.workspace_path.trim();
632
659
  const res = await this.transport.request(`/v3/workers/${encodeURIComponent(params.worker_id.trim())}/test`, {
633
660
  method: 'POST',
634
661
  headers,
@@ -15,12 +15,21 @@ export declare class SwarmWorkspacesNamespace {
15
15
  name: string;
16
16
  make_current?: boolean;
17
17
  }): Promise<WorkspaceResolution>;
18
+ /**
19
+ * Registers an existing folder. A Git repository by default; with
20
+ * `context_only` any readable folder (a project source, never selected as the
21
+ * coding workspace), and with `require_existing_content` as well the daemon
22
+ * refuses empty folders, system/Swarm storage directories and folders inside
23
+ * an already registered workspace (for folders the person named).
24
+ */
18
25
  add(body: {
19
26
  path: string;
20
27
  name?: string;
21
28
  theme_id?: string;
22
29
  make_current?: boolean;
23
30
  confirm_committed_only?: boolean;
31
+ context_only?: boolean;
32
+ require_existing_content?: boolean;
24
33
  }): Promise<WorkspaceResolution>;
25
34
  inspectRepository(path: string): Promise<WorkspaceRepository>;
26
35
  setupRepository(path: string, expected_resolved_path: string): Promise<WorkspaceRepository>;
@@ -23,6 +23,13 @@ export class SwarmWorkspacesNamespace {
23
23
  await this.setupRepository(path, path);
24
24
  return this.add({ path, name: body.name, make_current: body.make_current ?? false });
25
25
  }
26
+ /**
27
+ * Registers an existing folder. A Git repository by default; with
28
+ * `context_only` any readable folder (a project source, never selected as the
29
+ * coding workspace), and with `require_existing_content` as well the daemon
30
+ * refuses empty folders, system/Swarm storage directories and folders inside
31
+ * an already registered workspace (for folders the person named).
32
+ */
26
33
  async add(body) {
27
34
  return (await this.transport.request('/v1/workspace/add', { method: 'POST', body })).data.workspace;
28
35
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swarm-agent/sdk",
3
- "version": "0.1.50",
3
+ "version": "0.1.52",
4
4
  "description": "Official TypeScript SDK for Swarm local AI coding workspace",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",