@agentworkforce/deploy 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bundle.d.ts +22 -0
- package/dist/bundle.d.ts.map +1 -0
- package/dist/bundle.js +132 -0
- package/dist/bundle.js.map +1 -0
- package/dist/bundle.test.d.ts +2 -0
- package/dist/bundle.test.d.ts.map +1 -0
- package/dist/bundle.test.js +92 -0
- package/dist/bundle.test.js.map +1 -0
- package/dist/connect.d.ts +81 -0
- package/dist/connect.d.ts.map +1 -0
- package/dist/connect.js +127 -0
- package/dist/connect.js.map +1 -0
- package/dist/deploy.d.ts +50 -0
- package/dist/deploy.d.ts.map +1 -0
- package/dist/deploy.js +172 -0
- package/dist/deploy.js.map +1 -0
- package/dist/deploy.test.d.ts +2 -0
- package/dist/deploy.test.d.ts.map +1 -0
- package/dist/deploy.test.js +293 -0
- package/dist/deploy.test.js.map +1 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/io.d.ts +22 -0
- package/dist/io.d.ts.map +1 -0
- package/dist/io.js +76 -0
- package/dist/io.js.map +1 -0
- package/dist/login.d.ts +24 -0
- package/dist/login.d.ts.map +1 -0
- package/dist/login.js +27 -0
- package/dist/login.js.map +1 -0
- package/dist/modes/cloud.d.ts +18 -0
- package/dist/modes/cloud.d.ts.map +1 -0
- package/dist/modes/cloud.js +21 -0
- package/dist/modes/cloud.js.map +1 -0
- package/dist/modes/dev.d.ts +12 -0
- package/dist/modes/dev.d.ts.map +1 -0
- package/dist/modes/dev.js +153 -0
- package/dist/modes/dev.js.map +1 -0
- package/dist/modes/sandbox-client.d.ts +63 -0
- package/dist/modes/sandbox-client.d.ts.map +1 -0
- package/dist/modes/sandbox-client.js +177 -0
- package/dist/modes/sandbox-client.js.map +1 -0
- package/dist/modes/sandbox-client.test.d.ts +2 -0
- package/dist/modes/sandbox-client.test.d.ts.map +1 -0
- package/dist/modes/sandbox-client.test.js +177 -0
- package/dist/modes/sandbox-client.test.js.map +1 -0
- package/dist/modes/sandbox.d.ts +50 -0
- package/dist/modes/sandbox.d.ts.map +1 -0
- package/dist/modes/sandbox.js +131 -0
- package/dist/modes/sandbox.js.map +1 -0
- package/dist/modes/sandbox.test.d.ts +2 -0
- package/dist/modes/sandbox.test.d.ts.map +1 -0
- package/dist/modes/sandbox.test.js +95 -0
- package/dist/modes/sandbox.test.js.map +1 -0
- package/dist/preflight.d.ts +14 -0
- package/dist/preflight.d.ts.map +1 -0
- package/dist/preflight.js +78 -0
- package/dist/preflight.js.map +1 -0
- package/dist/types.d.ts +140 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +40 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { mkdtemp, rm, writeFile } from 'node:fs/promises';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import { createProxySandboxClient, SANDBOX_BUNDLE_DIR } from './sandbox-client.js';
|
|
7
|
+
function fakeFetch(handlers) {
|
|
8
|
+
const calls = [];
|
|
9
|
+
let i = 0;
|
|
10
|
+
const impl = (async (input, init) => {
|
|
11
|
+
const url = typeof input === 'string' ? input : input.toString();
|
|
12
|
+
const headers = {};
|
|
13
|
+
if (init?.headers) {
|
|
14
|
+
const entries = init.headers instanceof Headers
|
|
15
|
+
? Array.from(init.headers.entries())
|
|
16
|
+
: Array.isArray(init.headers)
|
|
17
|
+
? init.headers
|
|
18
|
+
: Object.entries(init.headers);
|
|
19
|
+
for (const [k, v] of entries)
|
|
20
|
+
headers[k.toLowerCase()] = String(v);
|
|
21
|
+
}
|
|
22
|
+
const body = init?.body ? JSON.parse(init.body.toString()) : undefined;
|
|
23
|
+
const call = {
|
|
24
|
+
url,
|
|
25
|
+
method: init?.method ?? 'GET',
|
|
26
|
+
headers,
|
|
27
|
+
...(body !== undefined ? { body } : {})
|
|
28
|
+
};
|
|
29
|
+
calls.push(call);
|
|
30
|
+
const handler = handlers[i];
|
|
31
|
+
if (!handler)
|
|
32
|
+
throw new Error(`fakeFetch: no handler at call index ${i}`);
|
|
33
|
+
i += 1;
|
|
34
|
+
return handler(call);
|
|
35
|
+
});
|
|
36
|
+
return { fetch: impl, calls };
|
|
37
|
+
}
|
|
38
|
+
async function fixtureBundle(dir) {
|
|
39
|
+
const runnerPath = path.join(dir, 'runner.mjs');
|
|
40
|
+
const bundlePath = path.join(dir, 'agent.bundle.mjs');
|
|
41
|
+
const personaCopyPath = path.join(dir, 'persona.json');
|
|
42
|
+
const packageJsonPath = path.join(dir, 'package.json');
|
|
43
|
+
await Promise.all([
|
|
44
|
+
writeFile(runnerPath, 'runner', 'utf8'),
|
|
45
|
+
writeFile(bundlePath, 'bundle', 'utf8'),
|
|
46
|
+
writeFile(personaCopyPath, '{"id":"demo"}', 'utf8'),
|
|
47
|
+
writeFile(packageJsonPath, '{}', 'utf8')
|
|
48
|
+
]);
|
|
49
|
+
return { runnerPath, bundlePath, personaCopyPath, packageJsonPath, sizeBytes: 13 };
|
|
50
|
+
}
|
|
51
|
+
test('proxy client mints, uploads, execs, and destroys against cloud sandboxes endpoint', async () => {
|
|
52
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), 'wf-sandbox-'));
|
|
53
|
+
try {
|
|
54
|
+
const bundle = await fixtureBundle(dir);
|
|
55
|
+
const { fetch: impl, calls } = fakeFetch([
|
|
56
|
+
// POST /sandboxes
|
|
57
|
+
() => new Response(JSON.stringify({
|
|
58
|
+
sandboxId: 'sbx_test',
|
|
59
|
+
authMode: 'proxy',
|
|
60
|
+
execUrl: 'https://cloud.example.com/api/v1/workspaces/ws/sandboxes/sbx_test/exec',
|
|
61
|
+
filesUrl: 'https://cloud.example.com/api/v1/workspaces/ws/sandboxes/sbx_test/files'
|
|
62
|
+
}), { status: 201 }),
|
|
63
|
+
// PUT /files
|
|
64
|
+
() => new Response(null, { status: 204 }),
|
|
65
|
+
// POST /exec (npm install)
|
|
66
|
+
() => new Response(JSON.stringify({ exitCode: 0, output: 'added 1 package' }), { status: 200 }),
|
|
67
|
+
// POST /exec (node runner.mjs)
|
|
68
|
+
() => new Response(JSON.stringify({ exitCode: 0, output: 'runner ok' }), { status: 200 }),
|
|
69
|
+
// DELETE /sandboxes/:id
|
|
70
|
+
() => new Response(null, { status: 204 })
|
|
71
|
+
]);
|
|
72
|
+
const client = createProxySandboxClient({
|
|
73
|
+
cloudUrl: 'https://cloud.example.com',
|
|
74
|
+
workspaceId: 'ws',
|
|
75
|
+
workspaceToken: 'tok-secret',
|
|
76
|
+
personaId: 'demo',
|
|
77
|
+
fetchImpl: impl
|
|
78
|
+
});
|
|
79
|
+
const handle = await client.mint({
|
|
80
|
+
label: 'wf-demo',
|
|
81
|
+
env: { WORKFORCE_WORKSPACE_ID: 'ws' }
|
|
82
|
+
});
|
|
83
|
+
assert.equal(handle.mode, 'proxy');
|
|
84
|
+
assert.equal(handle.sandboxId, 'sbx_test');
|
|
85
|
+
assert.equal(handle.id, 'proxy:sbx_test');
|
|
86
|
+
await client.uploadBundle(handle, bundle);
|
|
87
|
+
const runResult = await client.exec(handle, 'node runner.mjs', {
|
|
88
|
+
cwd: SANDBOX_BUNDLE_DIR,
|
|
89
|
+
timeoutSeconds: 60
|
|
90
|
+
});
|
|
91
|
+
assert.equal(runResult.exitCode, 0);
|
|
92
|
+
assert.equal(runResult.output, 'runner ok');
|
|
93
|
+
await client.destroy(handle);
|
|
94
|
+
// Mint request shape.
|
|
95
|
+
assert.equal(calls[0].url, 'https://cloud.example.com/api/v1/workspaces/ws/sandboxes');
|
|
96
|
+
assert.equal(calls[0].method, 'POST');
|
|
97
|
+
assert.equal(calls[0].headers.authorization, 'Bearer tok-secret');
|
|
98
|
+
assert.equal(calls[0].body.purpose, 'workforce-deploy');
|
|
99
|
+
assert.equal(calls[0].body.personaId, 'demo');
|
|
100
|
+
// Upload PUT carries base64 file entries.
|
|
101
|
+
assert.equal(calls[1].method, 'PUT');
|
|
102
|
+
assert.match(calls[1].url, /\/sandboxes\/sbx_test\/files$/);
|
|
103
|
+
const uploadBody = calls[1].body;
|
|
104
|
+
assert.equal(uploadBody.entries.length, 4);
|
|
105
|
+
const runnerEntry = uploadBody.entries.find((e) => e.destination.endsWith('/runner.mjs'));
|
|
106
|
+
assert.ok(runnerEntry);
|
|
107
|
+
assert.equal(Buffer.from(runnerEntry.source, 'base64').toString('utf8'), 'runner');
|
|
108
|
+
// Install exec.
|
|
109
|
+
assert.equal(calls[2].method, 'POST');
|
|
110
|
+
assert.match(calls[2].url, /\/sandboxes\/sbx_test\/exec$/);
|
|
111
|
+
assert.match(calls[2].body.command, /^npm install/);
|
|
112
|
+
// Runner exec.
|
|
113
|
+
assert.equal(calls[3].body.command, 'node runner.mjs');
|
|
114
|
+
// Delete by sandbox id.
|
|
115
|
+
assert.equal(calls[4].method, 'DELETE');
|
|
116
|
+
assert.match(calls[4].url, /\/sandboxes\/sbx_test$/);
|
|
117
|
+
}
|
|
118
|
+
finally {
|
|
119
|
+
await rm(dir, { recursive: true, force: true });
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
test('proxy client surfaces non-2xx mint responses with the cloud status + excerpt', async () => {
|
|
123
|
+
const { fetch: impl } = fakeFetch([
|
|
124
|
+
() => new Response('quota exceeded', { status: 429, statusText: 'Too Many Requests' })
|
|
125
|
+
]);
|
|
126
|
+
const client = createProxySandboxClient({
|
|
127
|
+
cloudUrl: 'https://cloud.example.com',
|
|
128
|
+
workspaceId: 'ws',
|
|
129
|
+
workspaceToken: 'tok',
|
|
130
|
+
personaId: 'demo',
|
|
131
|
+
fetchImpl: impl
|
|
132
|
+
});
|
|
133
|
+
await assert.rejects(() => client.mint({ label: 'wf-demo' }), /sandbox\(proxy\)\.mint: 429 Too Many Requests/);
|
|
134
|
+
});
|
|
135
|
+
test('proxy client tolerates 404 on destroy (already deleted)', async () => {
|
|
136
|
+
const { fetch: impl } = fakeFetch([
|
|
137
|
+
() => new Response('not found', { status: 404, statusText: 'Not Found' })
|
|
138
|
+
]);
|
|
139
|
+
const client = createProxySandboxClient({
|
|
140
|
+
cloudUrl: 'https://cloud.example.com',
|
|
141
|
+
workspaceId: 'ws',
|
|
142
|
+
workspaceToken: 'tok',
|
|
143
|
+
personaId: 'demo',
|
|
144
|
+
fetchImpl: impl
|
|
145
|
+
});
|
|
146
|
+
// Construct a minimal proxy handle by hand (we don't want to mint first).
|
|
147
|
+
await client.destroy({ id: 'proxy:x', sandboxId: 'x', mode: 'proxy' });
|
|
148
|
+
});
|
|
149
|
+
test('proxy client throws when npm install in the sandbox fails', async () => {
|
|
150
|
+
const dir = await mkdtemp(path.join(os.tmpdir(), 'wf-sandbox-'));
|
|
151
|
+
try {
|
|
152
|
+
const bundle = await fixtureBundle(dir);
|
|
153
|
+
const { fetch: impl } = fakeFetch([
|
|
154
|
+
() => new Response(JSON.stringify({
|
|
155
|
+
sandboxId: 'sbx',
|
|
156
|
+
authMode: 'proxy',
|
|
157
|
+
execUrl: 'https://cloud.example.com/api/v1/workspaces/ws/sandboxes/sbx/exec',
|
|
158
|
+
filesUrl: 'https://cloud.example.com/api/v1/workspaces/ws/sandboxes/sbx/files'
|
|
159
|
+
}), { status: 201 }),
|
|
160
|
+
() => new Response(null, { status: 204 }),
|
|
161
|
+
() => new Response(JSON.stringify({ exitCode: 1, output: 'EACCES' }), { status: 200 })
|
|
162
|
+
]);
|
|
163
|
+
const client = createProxySandboxClient({
|
|
164
|
+
cloudUrl: 'https://cloud.example.com',
|
|
165
|
+
workspaceId: 'ws',
|
|
166
|
+
workspaceToken: 'tok',
|
|
167
|
+
personaId: 'demo',
|
|
168
|
+
fetchImpl: impl
|
|
169
|
+
});
|
|
170
|
+
const handle = await client.mint({ label: 'wf' });
|
|
171
|
+
await assert.rejects(() => client.uploadBundle(handle, bundle), /npm install failed \(exit 1\)/);
|
|
172
|
+
}
|
|
173
|
+
finally {
|
|
174
|
+
await rm(dir, { recursive: true, force: true });
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
//# sourceMappingURL=sandbox-client.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox-client.test.js","sourceRoot":"","sources":["../../src/modes/sandbox-client.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { ModeLaunchInput, ModeLauncher } from '../types.js';
|
|
2
|
+
import { type SandboxClient } from './sandbox-client.js';
|
|
3
|
+
/**
|
|
4
|
+
* Daytona-backed sandbox launcher with two auth paths:
|
|
5
|
+
*
|
|
6
|
+
* - **BYO** — `DAYTONA_API_KEY` (or `DAYTONA_JWT_TOKEN` +
|
|
7
|
+
* `DAYTONA_ORGANIZATION_ID`) is present in env. The launcher talks
|
|
8
|
+
* directly to Daytona via `@daytonaio/sdk`. Zero workforce-cloud
|
|
9
|
+
* round-trips; useful in CI or for power users with their own
|
|
10
|
+
* Daytona accounts.
|
|
11
|
+
* - **Workforce-managed** — `DAYTONA_API_KEY` is absent but
|
|
12
|
+
* `WORKFORCE_WORKSPACE_TOKEN` is set (either via `workforce login`
|
|
13
|
+
* or exported manually). The launcher POSTs the cloud sandboxes
|
|
14
|
+
* endpoint to mint a proxy handle and routes all exec/upload
|
|
15
|
+
* traffic through cloud's per-sandbox `/exec` and `/files` URLs.
|
|
16
|
+
* Cloud holds the org Daytona credentials so users never see them.
|
|
17
|
+
*
|
|
18
|
+
* Mode picking is purely env-based today. Pass `--byo-sandbox` on the
|
|
19
|
+
* deploy CLI to force BYO when both are configured (handled in
|
|
20
|
+
* `resolveLauncher`, not here).
|
|
21
|
+
*
|
|
22
|
+
* Streaming: cloud's `/exec` endpoint and Daytona's `executeCommand` are
|
|
23
|
+
* both final-result-only. The runner exits when its envelope stream
|
|
24
|
+
* ends, and the resulting output is forwarded to DeployIO at that
|
|
25
|
+
* point. Live tail support is gated on a future iteration.
|
|
26
|
+
*/
|
|
27
|
+
export declare const sandboxLauncher: ModeLauncher;
|
|
28
|
+
/**
|
|
29
|
+
* Pick the sandbox client implementation based on env. Public so the
|
|
30
|
+
* deploy orchestrator (and tests) can plug in an explicit choice.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveSandboxClient(input: Pick<ModeLaunchInput, 'workspace' | 'persona' | 'env'> & Partial<Pick<ModeLaunchInput, 'io'>>, overrides?: {
|
|
33
|
+
/** Force BYO even when both BYO and workforce-managed are configured. */
|
|
34
|
+
forceByo?: boolean;
|
|
35
|
+
/** Inject a custom client (tests). */
|
|
36
|
+
client?: SandboxClient;
|
|
37
|
+
}): SandboxClient;
|
|
38
|
+
export { SANDBOX_BUNDLE_DIR, createByoSandboxClient, createProxySandboxClient, type SandboxClient, type SandboxHandle } from './sandbox-client.js';
|
|
39
|
+
/**
|
|
40
|
+
* Legacy alias for the env-resolved Daytona credentials surface. Kept so
|
|
41
|
+
* existing imports of `resolveSandboxAuth` continue to compile; new code
|
|
42
|
+
* should use `resolveSandboxClient` instead.
|
|
43
|
+
*/
|
|
44
|
+
export interface SandboxAuth {
|
|
45
|
+
apiKey?: string;
|
|
46
|
+
jwtToken?: string;
|
|
47
|
+
organizationId?: string;
|
|
48
|
+
}
|
|
49
|
+
export declare function resolveSandboxAuth(): SandboxAuth | undefined;
|
|
50
|
+
//# sourceMappingURL=sandbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.d.ts","sourceRoot":"","sources":["../../src/modes/sandbox.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EAEf,YAAY,EACb,MAAM,aAAa,CAAC;AACrB,OAAO,EAIL,KAAK,aAAa,EAEnB,MAAM,qBAAqB,CAAC;AAI7B;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,eAAO,MAAM,eAAe,EAAE,YA2D7B,CAAC;AAEF;;;GAGG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,IAAI,CAAC,eAAe,EAAE,WAAW,GAAG,SAAS,GAAG,KAAK,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,eAAe,EAAE,IAAI,CAAC,CAAC,EACpG,SAAS,GAAE;IACT,yEAAyE;IACzE,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sCAAsC;IACtC,MAAM,CAAC,EAAE,aAAa,CAAC;CACnB,GACL,aAAa,CAkCf;AAGD,OAAO,EACL,kBAAkB,EAClB,sBAAsB,EACtB,wBAAwB,EACxB,KAAK,aAAa,EAClB,KAAK,aAAa,EACnB,MAAM,qBAAqB,CAAC;AAE7B;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,kBAAkB,IAAI,WAAW,GAAG,SAAS,CAU5D"}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { SANDBOX_BUNDLE_DIR, createByoSandboxClient, createProxySandboxClient } from './sandbox-client.js';
|
|
2
|
+
const DEFAULT_CLOUD_URL = 'https://cloud.agentworkforce.com';
|
|
3
|
+
/**
|
|
4
|
+
* Daytona-backed sandbox launcher with two auth paths:
|
|
5
|
+
*
|
|
6
|
+
* - **BYO** — `DAYTONA_API_KEY` (or `DAYTONA_JWT_TOKEN` +
|
|
7
|
+
* `DAYTONA_ORGANIZATION_ID`) is present in env. The launcher talks
|
|
8
|
+
* directly to Daytona via `@daytonaio/sdk`. Zero workforce-cloud
|
|
9
|
+
* round-trips; useful in CI or for power users with their own
|
|
10
|
+
* Daytona accounts.
|
|
11
|
+
* - **Workforce-managed** — `DAYTONA_API_KEY` is absent but
|
|
12
|
+
* `WORKFORCE_WORKSPACE_TOKEN` is set (either via `workforce login`
|
|
13
|
+
* or exported manually). The launcher POSTs the cloud sandboxes
|
|
14
|
+
* endpoint to mint a proxy handle and routes all exec/upload
|
|
15
|
+
* traffic through cloud's per-sandbox `/exec` and `/files` URLs.
|
|
16
|
+
* Cloud holds the org Daytona credentials so users never see them.
|
|
17
|
+
*
|
|
18
|
+
* Mode picking is purely env-based today. Pass `--byo-sandbox` on the
|
|
19
|
+
* deploy CLI to force BYO when both are configured (handled in
|
|
20
|
+
* `resolveLauncher`, not here).
|
|
21
|
+
*
|
|
22
|
+
* Streaming: cloud's `/exec` endpoint and Daytona's `executeCommand` are
|
|
23
|
+
* both final-result-only. The runner exits when its envelope stream
|
|
24
|
+
* ends, and the resulting output is forwarded to DeployIO at that
|
|
25
|
+
* point. Live tail support is gated on a future iteration.
|
|
26
|
+
*/
|
|
27
|
+
export const sandboxLauncher = {
|
|
28
|
+
async launch(input) {
|
|
29
|
+
const client = resolveSandboxClient(input, input.byoSandbox ? { forceByo: true } : {});
|
|
30
|
+
const handle = await client.mint({
|
|
31
|
+
label: `wf-${input.persona.id}`,
|
|
32
|
+
env: {
|
|
33
|
+
...(input.env ?? {}),
|
|
34
|
+
WORKFORCE_WORKSPACE_ID: input.workspace,
|
|
35
|
+
WORKFORCE_PERSONA_ID: input.persona.id
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
try {
|
|
39
|
+
await client.uploadBundle(handle, input.bundle);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
// If upload fails the sandbox is unrecoverable for this deploy.
|
|
43
|
+
// Tear it down so we don't leak Daytona resources or charge for
|
|
44
|
+
// an idle workforce-managed sandbox.
|
|
45
|
+
await client.destroy(handle).catch(() => undefined);
|
|
46
|
+
throw err;
|
|
47
|
+
}
|
|
48
|
+
let stopping = false;
|
|
49
|
+
const stop = async () => {
|
|
50
|
+
if (stopping)
|
|
51
|
+
return;
|
|
52
|
+
stopping = true;
|
|
53
|
+
try {
|
|
54
|
+
await client.destroy(handle);
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
input.io.warn(`sandbox: cleanup failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
const done = (async () => {
|
|
61
|
+
try {
|
|
62
|
+
const result = await client.exec(handle, 'node runner.mjs', {
|
|
63
|
+
cwd: SANDBOX_BUNDLE_DIR
|
|
64
|
+
});
|
|
65
|
+
const output = result.output.trim();
|
|
66
|
+
if (output.length > 0)
|
|
67
|
+
input.io.info(`[sandbox] ${output}`);
|
|
68
|
+
return { code: result.exitCode };
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
if (!stopping) {
|
|
72
|
+
input.io.error(`sandbox: runner exec failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
73
|
+
}
|
|
74
|
+
return { code: 1 };
|
|
75
|
+
}
|
|
76
|
+
})();
|
|
77
|
+
return {
|
|
78
|
+
id: handle.id,
|
|
79
|
+
stop,
|
|
80
|
+
done
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Pick the sandbox client implementation based on env. Public so the
|
|
86
|
+
* deploy orchestrator (and tests) can plug in an explicit choice.
|
|
87
|
+
*/
|
|
88
|
+
export function resolveSandboxClient(input, overrides = {}) {
|
|
89
|
+
if (overrides.client)
|
|
90
|
+
return overrides.client;
|
|
91
|
+
const apiKey = process.env.DAYTONA_API_KEY?.trim();
|
|
92
|
+
const jwtToken = process.env.DAYTONA_JWT_TOKEN?.trim();
|
|
93
|
+
const organizationId = process.env.DAYTONA_ORGANIZATION_ID?.trim();
|
|
94
|
+
const byoAvailable = Boolean(apiKey || jwtToken);
|
|
95
|
+
if (overrides.forceByo || byoAvailable) {
|
|
96
|
+
if (!byoAvailable) {
|
|
97
|
+
throw new Error('sandbox launcher: --byo-sandbox requested but no Daytona credentials are in env. Set DAYTONA_API_KEY (or DAYTONA_JWT_TOKEN + DAYTONA_ORGANIZATION_ID).');
|
|
98
|
+
}
|
|
99
|
+
return createByoSandboxClient({
|
|
100
|
+
...(apiKey ? { apiKey } : {}),
|
|
101
|
+
...(jwtToken ? { jwtToken } : {}),
|
|
102
|
+
...(organizationId ? { organizationId } : {})
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
const workspaceToken = process.env.WORKFORCE_WORKSPACE_TOKEN?.trim();
|
|
106
|
+
if (!workspaceToken) {
|
|
107
|
+
throw new Error('sandbox launcher: no Daytona credentials and no workforce workspace token. Either export DAYTONA_API_KEY, or run `workforce login` (sets WORKFORCE_WORKSPACE_TOKEN) so we can mint a workforce-managed sandbox.');
|
|
108
|
+
}
|
|
109
|
+
const cloudUrl = (process.env.WORKFORCE_CLOUD_URL?.trim() || DEFAULT_CLOUD_URL).replace(/\/$/, '');
|
|
110
|
+
return createProxySandboxClient({
|
|
111
|
+
cloudUrl,
|
|
112
|
+
workspaceId: input.workspace,
|
|
113
|
+
workspaceToken,
|
|
114
|
+
personaId: input.persona.id
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
// Re-exported for tests + power users wanting to compose the client manually.
|
|
118
|
+
export { SANDBOX_BUNDLE_DIR, createByoSandboxClient, createProxySandboxClient } from './sandbox-client.js';
|
|
119
|
+
export function resolveSandboxAuth() {
|
|
120
|
+
const apiKey = process.env.DAYTONA_API_KEY?.trim();
|
|
121
|
+
const jwtToken = process.env.DAYTONA_JWT_TOKEN?.trim();
|
|
122
|
+
const organizationId = process.env.DAYTONA_ORGANIZATION_ID?.trim();
|
|
123
|
+
if (!apiKey && !jwtToken)
|
|
124
|
+
return undefined;
|
|
125
|
+
return {
|
|
126
|
+
...(apiKey ? { apiKey } : {}),
|
|
127
|
+
...(jwtToken ? { jwtToken } : {}),
|
|
128
|
+
...(organizationId ? { organizationId } : {})
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
//# sourceMappingURL=sandbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../src/modes/sandbox.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.test.d.ts","sourceRoot":"","sources":["../../src/modes/sandbox.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { resolveSandboxClient } from './sandbox.js';
|
|
4
|
+
function input() {
|
|
5
|
+
return {
|
|
6
|
+
workspace: 'ws-demo',
|
|
7
|
+
persona: {
|
|
8
|
+
id: 'demo',
|
|
9
|
+
intent: 'documentation',
|
|
10
|
+
tags: ['documentation'],
|
|
11
|
+
description: '',
|
|
12
|
+
skills: [],
|
|
13
|
+
harness: 'claude',
|
|
14
|
+
model: 'm',
|
|
15
|
+
systemPrompt: 's',
|
|
16
|
+
harnessSettings: { reasoning: 'medium', timeoutSeconds: 300 },
|
|
17
|
+
cloud: true,
|
|
18
|
+
onEvent: './agent.ts'
|
|
19
|
+
}
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
function withEnv(overrides, fn) {
|
|
23
|
+
const previous = {};
|
|
24
|
+
for (const key of Object.keys(overrides)) {
|
|
25
|
+
previous[key] = process.env[key];
|
|
26
|
+
if (overrides[key] === undefined)
|
|
27
|
+
delete process.env[key];
|
|
28
|
+
else
|
|
29
|
+
process.env[key] = overrides[key];
|
|
30
|
+
}
|
|
31
|
+
try {
|
|
32
|
+
return fn();
|
|
33
|
+
}
|
|
34
|
+
finally {
|
|
35
|
+
for (const [key, value] of Object.entries(previous)) {
|
|
36
|
+
if (value === undefined)
|
|
37
|
+
delete process.env[key];
|
|
38
|
+
else
|
|
39
|
+
process.env[key] = value;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
test('resolveSandboxClient prefers BYO when DAYTONA_API_KEY is set', () => {
|
|
44
|
+
withEnv({
|
|
45
|
+
DAYTONA_API_KEY: 'sk_byo',
|
|
46
|
+
WORKFORCE_WORKSPACE_TOKEN: 'tok'
|
|
47
|
+
}, () => {
|
|
48
|
+
const client = resolveSandboxClient(input());
|
|
49
|
+
// BYO client carries the Daytona SDK; we infer mode by inspecting
|
|
50
|
+
// a mint-like call would tag the resulting handle. Easier to just
|
|
51
|
+
// verify by structural shape — but the simplest check is that the
|
|
52
|
+
// proxy path was *not* picked (which would have called fetch).
|
|
53
|
+
assert.ok(typeof client.mint === 'function');
|
|
54
|
+
assert.ok(typeof client.exec === 'function');
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
test('resolveSandboxClient falls back to the cloud proxy when only WORKFORCE_WORKSPACE_TOKEN is set', () => {
|
|
58
|
+
withEnv({
|
|
59
|
+
DAYTONA_API_KEY: undefined,
|
|
60
|
+
DAYTONA_JWT_TOKEN: undefined,
|
|
61
|
+
WORKFORCE_WORKSPACE_TOKEN: 'tok-cloud',
|
|
62
|
+
WORKFORCE_CLOUD_URL: 'https://cloud.example.com'
|
|
63
|
+
}, () => {
|
|
64
|
+
const client = resolveSandboxClient(input());
|
|
65
|
+
assert.ok(typeof client.mint === 'function');
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
test('resolveSandboxClient throws when neither path is configured', () => {
|
|
69
|
+
withEnv({
|
|
70
|
+
DAYTONA_API_KEY: undefined,
|
|
71
|
+
DAYTONA_JWT_TOKEN: undefined,
|
|
72
|
+
WORKFORCE_WORKSPACE_TOKEN: undefined
|
|
73
|
+
}, () => {
|
|
74
|
+
assert.throws(() => resolveSandboxClient(input()), /no Daytona credentials and no workforce workspace token/);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
test('resolveSandboxClient honors --byo-sandbox even when both paths are configured', () => {
|
|
78
|
+
withEnv({
|
|
79
|
+
DAYTONA_API_KEY: 'sk_byo',
|
|
80
|
+
WORKFORCE_WORKSPACE_TOKEN: 'tok'
|
|
81
|
+
}, () => {
|
|
82
|
+
const client = resolveSandboxClient(input(), { forceByo: true });
|
|
83
|
+
assert.ok(typeof client.mint === 'function');
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
test('resolveSandboxClient with forceByo and no BYO env throws a clear error', () => {
|
|
87
|
+
withEnv({
|
|
88
|
+
DAYTONA_API_KEY: undefined,
|
|
89
|
+
DAYTONA_JWT_TOKEN: undefined,
|
|
90
|
+
WORKFORCE_WORKSPACE_TOKEN: 'tok'
|
|
91
|
+
}, () => {
|
|
92
|
+
assert.throws(() => resolveSandboxClient(input(), { forceByo: true }), /--byo-sandbox requested but no Daytona credentials/);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
//# sourceMappingURL=sandbox.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sandbox.test.js","sourceRoot":"","sources":["../../src/modes/sandbox.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { DeployPreflight } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Load + parse + validate a persona for the deploy surface. Returns the
|
|
4
|
+
* frozen-shape preflight on success, throws with a field-pointed error
|
|
5
|
+
* on validation failure.
|
|
6
|
+
*
|
|
7
|
+
* Deploy preflight is stricter than the persona-kit parser: the parser
|
|
8
|
+
* accepts any persona, valid or not for deploy; this function enforces
|
|
9
|
+
* the deploy-specific cross-field rules (cloud:true, onEvent present when
|
|
10
|
+
* triggers exist, onEvent file actually on disk, etc.) so the orchestrator
|
|
11
|
+
* never gets a half-valid spec.
|
|
12
|
+
*/
|
|
13
|
+
export declare function preflightPersona(personaPath: string): Promise<DeployPreflight>;
|
|
14
|
+
//# sourceMappingURL=preflight.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight.d.ts","sourceRoot":"","sources":["../src/preflight.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;;;;;;;;;GAUG;AACH,wBAAsB,gBAAgB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC,CAqFpF"}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { readFile, stat } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { lintTriggers, parsePersonaSpec } from '@agentworkforce/persona-kit';
|
|
4
|
+
/**
|
|
5
|
+
* Load + parse + validate a persona for the deploy surface. Returns the
|
|
6
|
+
* frozen-shape preflight on success, throws with a field-pointed error
|
|
7
|
+
* on validation failure.
|
|
8
|
+
*
|
|
9
|
+
* Deploy preflight is stricter than the persona-kit parser: the parser
|
|
10
|
+
* accepts any persona, valid or not for deploy; this function enforces
|
|
11
|
+
* the deploy-specific cross-field rules (cloud:true, onEvent present when
|
|
12
|
+
* triggers exist, onEvent file actually on disk, etc.) so the orchestrator
|
|
13
|
+
* never gets a half-valid spec.
|
|
14
|
+
*/
|
|
15
|
+
export async function preflightPersona(personaPath) {
|
|
16
|
+
const absPath = path.resolve(personaPath);
|
|
17
|
+
const personaDir = path.dirname(absPath);
|
|
18
|
+
const raw = await readFile(absPath, 'utf8').catch((err) => {
|
|
19
|
+
if (err.code === 'ENOENT') {
|
|
20
|
+
throw new Error(`persona JSON not found at ${absPath}`);
|
|
21
|
+
}
|
|
22
|
+
throw err;
|
|
23
|
+
});
|
|
24
|
+
let json;
|
|
25
|
+
try {
|
|
26
|
+
json = JSON.parse(raw);
|
|
27
|
+
}
|
|
28
|
+
catch (err) {
|
|
29
|
+
throw new Error(`persona JSON at ${absPath} is not valid JSON: ${err instanceof Error ? err.message : String(err)}`);
|
|
30
|
+
}
|
|
31
|
+
if (typeof json !== 'object' || json === null) {
|
|
32
|
+
throw new Error(`persona JSON at ${absPath} must be a top-level object`);
|
|
33
|
+
}
|
|
34
|
+
// The persona-kit parser is intent-aware; we pass the intent it declares
|
|
35
|
+
// back to itself so the check is self-consistent (parsePersonaSpec
|
|
36
|
+
// enforces that `intent` matches `expectedIntent` to catch type-collated
|
|
37
|
+
// mistakes in built-in catalogs). For loose deploy use, mirror the
|
|
38
|
+
// declared intent.
|
|
39
|
+
const declaredIntent = json.intent;
|
|
40
|
+
if (typeof declaredIntent !== 'string' || !declaredIntent) {
|
|
41
|
+
throw new Error(`persona JSON at ${absPath} is missing top-level "intent"`);
|
|
42
|
+
}
|
|
43
|
+
const persona = parsePersonaSpec(json, declaredIntent);
|
|
44
|
+
if (persona.cloud !== true) {
|
|
45
|
+
throw new Error(`persona "${persona.id}" is not opted into deploy (set "cloud": true to enable workforce deploy)`);
|
|
46
|
+
}
|
|
47
|
+
const hasIntegrationTriggers = !!persona.integrations &&
|
|
48
|
+
Object.values(persona.integrations).some((cfg) => (cfg.triggers?.length ?? 0) > 0);
|
|
49
|
+
const hasSchedules = (persona.schedules?.length ?? 0) > 0;
|
|
50
|
+
if (!hasIntegrationTriggers && !hasSchedules) {
|
|
51
|
+
throw new Error(`persona "${persona.id}" declares cloud:true but has no triggers (add at least one schedule or integration trigger)`);
|
|
52
|
+
}
|
|
53
|
+
if (!persona.onEvent) {
|
|
54
|
+
throw new Error(`persona "${persona.id}" declares cloud:true but is missing "onEvent" (path to the handler file)`);
|
|
55
|
+
}
|
|
56
|
+
const onEventPath = path.resolve(personaDir, persona.onEvent);
|
|
57
|
+
const onEventStat = await stat(onEventPath).catch((err) => {
|
|
58
|
+
if (err.code === 'ENOENT') {
|
|
59
|
+
throw new Error(`persona "${persona.id}" onEvent file not found at ${onEventPath} (relative to ${personaDir})`);
|
|
60
|
+
}
|
|
61
|
+
throw err;
|
|
62
|
+
});
|
|
63
|
+
if (!onEventStat.isFile()) {
|
|
64
|
+
throw new Error(`onEvent path ${onEventPath} is not a regular file`);
|
|
65
|
+
}
|
|
66
|
+
const triggerLint = lintTriggers(persona);
|
|
67
|
+
const warnings = triggerLint.map((issue) => `${issue.path}: ${issue.message}`);
|
|
68
|
+
return {
|
|
69
|
+
persona,
|
|
70
|
+
personaPath: absPath,
|
|
71
|
+
personaDir,
|
|
72
|
+
onEventPath,
|
|
73
|
+
schedules: (persona.schedules ?? []).map((s) => s.name),
|
|
74
|
+
integrations: persona.integrations ? Object.keys(persona.integrations) : [],
|
|
75
|
+
warnings
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=preflight.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preflight.js","sourceRoot":"","sources":["../src/preflight.ts"],"names":[],"mappings":"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"}
|