@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.
Files changed (65) hide show
  1. package/dist/bundle.d.ts +22 -0
  2. package/dist/bundle.d.ts.map +1 -0
  3. package/dist/bundle.js +132 -0
  4. package/dist/bundle.js.map +1 -0
  5. package/dist/bundle.test.d.ts +2 -0
  6. package/dist/bundle.test.d.ts.map +1 -0
  7. package/dist/bundle.test.js +92 -0
  8. package/dist/bundle.test.js.map +1 -0
  9. package/dist/connect.d.ts +81 -0
  10. package/dist/connect.d.ts.map +1 -0
  11. package/dist/connect.js +127 -0
  12. package/dist/connect.js.map +1 -0
  13. package/dist/deploy.d.ts +50 -0
  14. package/dist/deploy.d.ts.map +1 -0
  15. package/dist/deploy.js +172 -0
  16. package/dist/deploy.js.map +1 -0
  17. package/dist/deploy.test.d.ts +2 -0
  18. package/dist/deploy.test.d.ts.map +1 -0
  19. package/dist/deploy.test.js +293 -0
  20. package/dist/deploy.test.js.map +1 -0
  21. package/dist/index.d.ts +11 -0
  22. package/dist/index.d.ts.map +1 -0
  23. package/dist/index.js +10 -0
  24. package/dist/index.js.map +1 -0
  25. package/dist/io.d.ts +22 -0
  26. package/dist/io.d.ts.map +1 -0
  27. package/dist/io.js +76 -0
  28. package/dist/io.js.map +1 -0
  29. package/dist/login.d.ts +24 -0
  30. package/dist/login.d.ts.map +1 -0
  31. package/dist/login.js +27 -0
  32. package/dist/login.js.map +1 -0
  33. package/dist/modes/cloud.d.ts +18 -0
  34. package/dist/modes/cloud.d.ts.map +1 -0
  35. package/dist/modes/cloud.js +21 -0
  36. package/dist/modes/cloud.js.map +1 -0
  37. package/dist/modes/dev.d.ts +12 -0
  38. package/dist/modes/dev.d.ts.map +1 -0
  39. package/dist/modes/dev.js +153 -0
  40. package/dist/modes/dev.js.map +1 -0
  41. package/dist/modes/sandbox-client.d.ts +63 -0
  42. package/dist/modes/sandbox-client.d.ts.map +1 -0
  43. package/dist/modes/sandbox-client.js +177 -0
  44. package/dist/modes/sandbox-client.js.map +1 -0
  45. package/dist/modes/sandbox-client.test.d.ts +2 -0
  46. package/dist/modes/sandbox-client.test.d.ts.map +1 -0
  47. package/dist/modes/sandbox-client.test.js +177 -0
  48. package/dist/modes/sandbox-client.test.js.map +1 -0
  49. package/dist/modes/sandbox.d.ts +50 -0
  50. package/dist/modes/sandbox.d.ts.map +1 -0
  51. package/dist/modes/sandbox.js +131 -0
  52. package/dist/modes/sandbox.js.map +1 -0
  53. package/dist/modes/sandbox.test.d.ts +2 -0
  54. package/dist/modes/sandbox.test.d.ts.map +1 -0
  55. package/dist/modes/sandbox.test.js +95 -0
  56. package/dist/modes/sandbox.test.js.map +1 -0
  57. package/dist/preflight.d.ts +14 -0
  58. package/dist/preflight.d.ts.map +1 -0
  59. package/dist/preflight.js +78 -0
  60. package/dist/preflight.js.map +1 -0
  61. package/dist/types.d.ts +140 -0
  62. package/dist/types.d.ts.map +1 -0
  63. package/dist/types.js +2 -0
  64. package/dist/types.js.map +1 -0
  65. 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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=sandbox.test.d.ts.map
@@ -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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"}