@swarm-agent/sdk 0.1.47 → 0.1.49
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/HEADLESS_UI.md +2 -0
- package/README.md +270 -7
- package/WORKER_CONTROL.md +77 -0
- package/dist/auth.d.ts +26 -0
- package/dist/auth.js +81 -0
- package/dist/browser.d.ts +94 -0
- package/dist/browser.js +408 -0
- package/dist/chat.d.ts +134 -0
- package/dist/chat.js +307 -0
- package/dist/client.d.ts +6 -0
- package/dist/client.js +8 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/permission-ui.d.ts +50 -0
- package/dist/permission-ui.js +167 -0
- package/dist/permissions.d.ts +126 -0
- package/dist/permissions.js +131 -0
- package/dist/projects.d.ts +36 -1
- package/dist/projects.js +96 -1
- package/dist/provider-auth.d.ts +38 -0
- package/dist/provider-auth.js +87 -0
- package/dist/sessions.d.ts +2 -0
- package/dist/sessions.js +34 -7
- package/dist/settings.d.ts +29 -1
- package/dist/settings.js +69 -0
- package/dist/types.d.ts +13 -0
- package/dist/websocket.d.ts +60 -0
- package/dist/websocket.js +207 -0
- package/dist/worker-control.d.ts +133 -0
- package/dist/worker-control.js +93 -0
- package/dist/workers.d.ts +2 -0
- package/dist/workers.js +3 -0
- package/examples/headless-worker-control.ts +28 -0
- package/package.json +8 -1
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { SwarmValidationError } from './errors.js';
|
|
2
|
+
const id = (value) => {
|
|
3
|
+
if (typeof value !== 'string' || !/^[a-zA-Z0-9_.-]{3,128}$/.test(value))
|
|
4
|
+
throw new SwarmValidationError('Invalid worker control identity');
|
|
5
|
+
return encodeURIComponent(value);
|
|
6
|
+
};
|
|
7
|
+
const revision = (value, zero = false) => {
|
|
8
|
+
if (!Number.isSafeInteger(value) || value < (zero ? 0 : 1))
|
|
9
|
+
throw new SwarmValidationError('Exact revision is required');
|
|
10
|
+
};
|
|
11
|
+
const key = (value) => {
|
|
12
|
+
if (typeof value !== 'string' || !value.trim() || value !== value.trim() || value.length > 256 || /[/\\\r\n\0]/.test(value))
|
|
13
|
+
throw new SwarmValidationError('Stable idempotency key is required');
|
|
14
|
+
};
|
|
15
|
+
/** Durable configuration/queued intent only. No SSH, cloud credentials or remote executor. */
|
|
16
|
+
export class SwarmWorkerControlNamespace {
|
|
17
|
+
transport;
|
|
18
|
+
constructor(transport) {
|
|
19
|
+
this.transport = transport;
|
|
20
|
+
}
|
|
21
|
+
path(worker, tail) { return `/v3/workers/${id(worker)}/${tail}`; }
|
|
22
|
+
async call(path, method, field, body, array = false) {
|
|
23
|
+
const result = await this.transport.request(path, { method, ...(body === undefined ? {} : { body }) });
|
|
24
|
+
const value = result.data?.[field];
|
|
25
|
+
if (array ? !Array.isArray(value) : !value || typeof value !== 'object' || Array.isArray(value))
|
|
26
|
+
throw new SwarmValidationError(`Malformed worker control envelope: ${field}`);
|
|
27
|
+
return value;
|
|
28
|
+
}
|
|
29
|
+
registerSSHTarget(worker, request) {
|
|
30
|
+
key(request.idempotency_key);
|
|
31
|
+
return this.call(this.path(worker, 'ssh-targets'), 'POST', 'target', request);
|
|
32
|
+
}
|
|
33
|
+
registerGCPTarget(worker, request) {
|
|
34
|
+
key(request.idempotency_key);
|
|
35
|
+
return this.call(this.path(worker, 'gcp-targets'), 'POST', 'target', request);
|
|
36
|
+
}
|
|
37
|
+
resolveTarget(worker, target) {
|
|
38
|
+
if (!['ssh', 'gcp'].includes(target.kind) || !Number.isInteger(target.capacity) || target.capacity < 1 || target.capacity > 100)
|
|
39
|
+
throw new SwarmValidationError('Invalid target capability');
|
|
40
|
+
return this.call(this.path(worker, 'target-reference'), 'POST', 'target', target);
|
|
41
|
+
}
|
|
42
|
+
getContext(worker, atRevision) {
|
|
43
|
+
if (atRevision !== undefined)
|
|
44
|
+
revision(atRevision);
|
|
45
|
+
return this.call(this.path(worker, `context${atRevision === undefined ? '' : `?revision=${atRevision}`}`), 'GET', 'context');
|
|
46
|
+
}
|
|
47
|
+
updateContext(worker, request) {
|
|
48
|
+
revision(request.expected_revision, true);
|
|
49
|
+
if (!request.provenance.trim())
|
|
50
|
+
throw new SwarmValidationError('Context provenance is required');
|
|
51
|
+
return this.call(this.path(worker, 'context'), 'PUT', 'context', request);
|
|
52
|
+
}
|
|
53
|
+
proposeDeployment(worker, request) {
|
|
54
|
+
revision(request.worker_revision);
|
|
55
|
+
revision(request.context_revision, true);
|
|
56
|
+
key(request.idempotency_key);
|
|
57
|
+
if (!['persistent', 'on_demand'].includes(request.lifecycle))
|
|
58
|
+
throw new SwarmValidationError('Explicit lifecycle is required');
|
|
59
|
+
return this.call(this.path(worker, 'deployments'), 'POST', 'deployment', request);
|
|
60
|
+
}
|
|
61
|
+
listDeployments(worker) { return this.call(this.path(worker, 'deployments'), 'GET', 'deployments', undefined, true); }
|
|
62
|
+
getDeployment(worker, deployment) { return this.call(this.path(worker, `deployments/${id(deployment)}`), 'GET', 'deployment'); }
|
|
63
|
+
/** Explicit user approval of the exact digest; does not start a runtime. */
|
|
64
|
+
approveDeployment(worker, deployment, expectedRevision, approvalDigest) {
|
|
65
|
+
revision(expectedRevision);
|
|
66
|
+
if (!approvalDigest.trim())
|
|
67
|
+
throw new SwarmValidationError('Approval digest required');
|
|
68
|
+
return this.call(this.path(worker, `deployments/${id(deployment)}/approve`), 'POST', 'deployment', { expected_revision: expectedRevision, approval_digest: approvalDigest });
|
|
69
|
+
}
|
|
70
|
+
queueJob(worker, deployment, request) {
|
|
71
|
+
revision(request.worker_revision);
|
|
72
|
+
revision(request.deployment_revision);
|
|
73
|
+
revision(request.context_revision, true);
|
|
74
|
+
key(request.idempotency_key);
|
|
75
|
+
return this.call(this.path(worker, `deployments/${id(deployment)}/jobs`), 'POST', 'run', request);
|
|
76
|
+
}
|
|
77
|
+
/** Start rejects with service unavailable. Stop is durable pending intent, not acknowledgement. */
|
|
78
|
+
command(worker, deployment, request) {
|
|
79
|
+
revision(request.expected_revision);
|
|
80
|
+
revision(request.generation);
|
|
81
|
+
key(request.idempotency_key);
|
|
82
|
+
return this.call(this.path(worker, `deployments/${id(deployment)}/commands`), 'POST', 'command', request);
|
|
83
|
+
}
|
|
84
|
+
commands(worker, deployment) { return this.call(this.path(worker, `deployments/${id(deployment)}/commands`), 'GET', 'commands', undefined, true); }
|
|
85
|
+
acknowledgeCommand(worker, deployment, commandId, ack) {
|
|
86
|
+
revision(ack.generation);
|
|
87
|
+
if (!['acknowledged', 'rejected'].includes(ack.status))
|
|
88
|
+
throw new SwarmValidationError('Invalid command status');
|
|
89
|
+
if (!ack.evidence_digest || ack.evidence_digest.length !== 64)
|
|
90
|
+
throw new SwarmValidationError('Invalid evidence digest');
|
|
91
|
+
return this.call(this.path(worker, `deployments/${id(deployment)}/commands/${id(commandId)}/ack`), 'POST', 'command', ack);
|
|
92
|
+
}
|
|
93
|
+
}
|
package/dist/workers.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SwarmTransport } from './transport.js';
|
|
2
|
+
import { SwarmWorkerControlNamespace } from './worker-control.js';
|
|
2
3
|
import type { WorkerRecord, WorkerRevisionRecord, WorkerRunRecord, PortableWorkerDefinition, CreateWorkerParams, UpdateWorkerParams, ListWorkersParams, ListWorkersResult, AttachWorkerAutomationParams, UpdateWorkerAutomationParams, RemoveWorkerAutomationParams, WorkerValidateResult, WorkerExportResult, ImportWorkerOptions, ActivateWorkerParams, PauseWorkerParams, ResumeWorkerParams, ArchiveWorkerParams, DeleteWorkerParams, SetWorkerAutomationEnabledParams, DirectWorkerRequestParams, TestWorkerRunParams, TriggerWorkerParams, MintWorkerTriggerTokenParams, MintWorkerTriggerTokenResult, ListWorkerRunsParams, ListWorkerRunsResult, GetWorkerRunParams, CancelWorkerRunParams } from './types.js';
|
|
3
4
|
/**
|
|
4
5
|
* SwarmWorkersNamespace manages durable, account-owned workers, their revisions,
|
|
@@ -7,6 +8,7 @@ import type { WorkerRecord, WorkerRevisionRecord, WorkerRunRecord, PortableWorke
|
|
|
7
8
|
* Distinct from legacy SwarmAutomationsNamespace which targets /v3/automations/v2.
|
|
8
9
|
*/
|
|
9
10
|
export declare class SwarmWorkersNamespace {
|
|
11
|
+
readonly control: SwarmWorkerControlNamespace;
|
|
10
12
|
private transport;
|
|
11
13
|
constructor(transport: SwarmTransport);
|
|
12
14
|
/**
|
package/dist/workers.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SwarmWorkerControlNamespace } from './worker-control.js';
|
|
1
2
|
import { SwarmValidationError } from './errors.js';
|
|
2
3
|
/**
|
|
3
4
|
* SwarmWorkersNamespace manages durable, account-owned workers, their revisions,
|
|
@@ -6,9 +7,11 @@ import { SwarmValidationError } from './errors.js';
|
|
|
6
7
|
* Distinct from legacy SwarmAutomationsNamespace which targets /v3/automations/v2.
|
|
7
8
|
*/
|
|
8
9
|
export class SwarmWorkersNamespace {
|
|
10
|
+
control;
|
|
9
11
|
transport;
|
|
10
12
|
constructor(transport) {
|
|
11
13
|
this.transport = transport;
|
|
14
|
+
this.control = new SwarmWorkerControlNamespace(transport);
|
|
12
15
|
}
|
|
13
16
|
/**
|
|
14
17
|
* Creates a new durable worker in idle state.
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import type { SwarmClient, WorkerSSHRegistration } from '../src/index.js';
|
|
2
|
+
|
|
3
|
+
/** Configuration only. Supply an already authenticated private SDK client and
|
|
4
|
+
* an existing worker. No browser, SSH command, provider key or cloud helper. */
|
|
5
|
+
export async function proposeHeadlessPlacements(
|
|
6
|
+
client: SwarmClient,
|
|
7
|
+
workerId: string,
|
|
8
|
+
targets: WorkerSSHRegistration[],
|
|
9
|
+
) {
|
|
10
|
+
if (targets.length < 1 || targets.length > 10) throw new Error('Supply 1–10 explicit SSH targets');
|
|
11
|
+
const worker = await client.workers.get(workerId);
|
|
12
|
+
if (!worker) throw new Error('Worker not found');
|
|
13
|
+
const context = await client.workers.control.getContext(worker.id);
|
|
14
|
+
const proposals = [];
|
|
15
|
+
for (const registration of targets) {
|
|
16
|
+
const target = await client.workers.control.registerSSHTarget(worker.id, registration);
|
|
17
|
+
proposals.push(await client.workers.control.proposeDeployment(worker.id, {
|
|
18
|
+
worker_revision: worker.revision,
|
|
19
|
+
context_revision: context.revision,
|
|
20
|
+
target,
|
|
21
|
+
lifecycle: 'on_demand',
|
|
22
|
+
idempotency_key: `placement-${registration.idempotency_key}`,
|
|
23
|
+
}));
|
|
24
|
+
}
|
|
25
|
+
// Present exact revisions/digests to the authorized human. Do not automatically
|
|
26
|
+
// approve them or report online: every observed_state is currently unavailable.
|
|
27
|
+
return proposals;
|
|
28
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@swarm-agent/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.49",
|
|
4
4
|
"description": "Official TypeScript SDK for Swarm local AI coding workspace",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -9,11 +9,17 @@
|
|
|
9
9
|
".": {
|
|
10
10
|
"types": "./dist/index.d.ts",
|
|
11
11
|
"import": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./browser": {
|
|
14
|
+
"types": "./dist/browser.d.ts",
|
|
15
|
+
"import": "./dist/browser.js"
|
|
12
16
|
}
|
|
13
17
|
},
|
|
14
18
|
"files": [
|
|
15
19
|
"dist",
|
|
16
20
|
"examples/headless-session.ts",
|
|
21
|
+
"examples/headless-worker-control.ts",
|
|
22
|
+
"WORKER_CONTROL.md",
|
|
17
23
|
"README.md",
|
|
18
24
|
"APPLICATIONS.md",
|
|
19
25
|
"HEADLESS_UI.md",
|
|
@@ -40,6 +46,7 @@
|
|
|
40
46
|
},
|
|
41
47
|
"devDependencies": {
|
|
42
48
|
"@types/node": "22.19.15",
|
|
49
|
+
"@types/ws": "^8.18.2",
|
|
43
50
|
"tsx": "4.21.0",
|
|
44
51
|
"typescript": "5.9.3"
|
|
45
52
|
},
|