@elie-laloum/outpost 1.1.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 (128) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/LICENSE +21 -0
  3. package/README.fr.md +251 -0
  4. package/README.md +226 -0
  5. package/ROADMAP.md +34 -0
  6. package/SECURITY.md +15 -0
  7. package/dist/application/campaign.d.ts +33 -0
  8. package/dist/application/campaign.js +195 -0
  9. package/dist/application/campaign.js.map +1 -0
  10. package/dist/application/execution.d.ts +48 -0
  11. package/dist/application/execution.js +322 -0
  12. package/dist/application/execution.js.map +1 -0
  13. package/dist/application/interactive-brief.d.ts +3 -0
  14. package/dist/application/interactive-brief.js +35 -0
  15. package/dist/application/interactive-brief.js.map +1 -0
  16. package/dist/application/outpost.d.ts +91 -0
  17. package/dist/application/outpost.js +629 -0
  18. package/dist/application/outpost.js.map +1 -0
  19. package/dist/application/remote-workspace.d.ts +11 -0
  20. package/dist/application/remote-workspace.js +264 -0
  21. package/dist/application/remote-workspace.js.map +1 -0
  22. package/dist/application/tasks.d.ts +17 -0
  23. package/dist/application/tasks.js +36 -0
  24. package/dist/application/tasks.js.map +1 -0
  25. package/dist/cli/main.d.ts +2 -0
  26. package/dist/cli/main.js +94 -0
  27. package/dist/cli/main.js.map +1 -0
  28. package/dist/cli/scaffold.d.ts +28 -0
  29. package/dist/cli/scaffold.js +169 -0
  30. package/dist/cli/scaffold.js.map +1 -0
  31. package/dist/cli/starters.d.ts +3 -0
  32. package/dist/cli/starters.js +34 -0
  33. package/dist/cli/starters.js.map +1 -0
  34. package/dist/domain/backlog.d.ts +16 -0
  35. package/dist/domain/backlog.js +23 -0
  36. package/dist/domain/backlog.js.map +1 -0
  37. package/dist/domain/errors.d.ts +11 -0
  38. package/dist/domain/errors.js +37 -0
  39. package/dist/domain/errors.js.map +1 -0
  40. package/dist/domain/ports.d.ts +183 -0
  41. package/dist/domain/ports.js +2 -0
  42. package/dist/domain/ports.js.map +1 -0
  43. package/dist/domain/prompts.d.ts +22 -0
  44. package/dist/domain/prompts.js +45 -0
  45. package/dist/domain/prompts.js.map +1 -0
  46. package/dist/domain/response.d.ts +37 -0
  47. package/dist/domain/response.js +50 -0
  48. package/dist/domain/response.js.map +1 -0
  49. package/dist/domain/workflow.d.ts +68 -0
  50. package/dist/domain/workflow.js +246 -0
  51. package/dist/domain/workflow.js.map +1 -0
  52. package/dist/index.d.ts +27 -0
  53. package/dist/index.js +13 -0
  54. package/dist/index.js.map +1 -0
  55. package/dist/infrastructure/abort.d.ts +1 -0
  56. package/dist/infrastructure/abort.js +16 -0
  57. package/dist/infrastructure/abort.js.map +1 -0
  58. package/dist/infrastructure/conversations.d.ts +30 -0
  59. package/dist/infrastructure/conversations.js +222 -0
  60. package/dist/infrastructure/conversations.js.map +1 -0
  61. package/dist/infrastructure/files.d.ts +5 -0
  62. package/dist/infrastructure/files.js +85 -0
  63. package/dist/infrastructure/files.js.map +1 -0
  64. package/dist/infrastructure/git.d.ts +14 -0
  65. package/dist/infrastructure/git.js +304 -0
  66. package/dist/infrastructure/git.js.map +1 -0
  67. package/dist/infrastructure/journal.d.ts +10 -0
  68. package/dist/infrastructure/journal.js +53 -0
  69. package/dist/infrastructure/journal.js.map +1 -0
  70. package/dist/infrastructure/process.d.ts +6 -0
  71. package/dist/infrastructure/process.js +133 -0
  72. package/dist/infrastructure/process.js.map +1 -0
  73. package/dist/infrastructure/reporter.d.ts +10 -0
  74. package/dist/infrastructure/reporter.js +47 -0
  75. package/dist/infrastructure/reporter.js.map +1 -0
  76. package/dist/infrastructure/settings.d.ts +3 -0
  77. package/dist/infrastructure/settings.js +41 -0
  78. package/dist/infrastructure/settings.js.map +1 -0
  79. package/dist/infrastructure/shutdown.d.ts +1 -0
  80. package/dist/infrastructure/shutdown.js +67 -0
  81. package/dist/infrastructure/shutdown.js.map +1 -0
  82. package/dist/infrastructure/terminal.d.ts +11 -0
  83. package/dist/infrastructure/terminal.js +19 -0
  84. package/dist/infrastructure/terminal.js.map +1 -0
  85. package/dist/infrastructure/transfer.d.ts +3 -0
  86. package/dist/infrastructure/transfer.js +29 -0
  87. package/dist/infrastructure/transfer.js.map +1 -0
  88. package/dist/providers/agents.d.ts +17 -0
  89. package/dist/providers/agents.js +204 -0
  90. package/dist/providers/agents.js.map +1 -0
  91. package/dist/providers/backlogs.d.ts +9 -0
  92. package/dist/providers/backlogs.js +82 -0
  93. package/dist/providers/backlogs.js.map +1 -0
  94. package/dist/providers/cloud-files.d.ts +4 -0
  95. package/dist/providers/cloud-files.js +66 -0
  96. package/dist/providers/cloud-files.js.map +1 -0
  97. package/dist/providers/container.d.ts +21 -0
  98. package/dist/providers/container.js +310 -0
  99. package/dist/providers/container.js.map +1 -0
  100. package/dist/providers/daytona.d.ts +10 -0
  101. package/dist/providers/daytona.js +153 -0
  102. package/dist/providers/daytona.js.map +1 -0
  103. package/dist/providers/docker.d.ts +3 -0
  104. package/dist/providers/docker.js +3 -0
  105. package/dist/providers/docker.js.map +1 -0
  106. package/dist/providers/factories.d.ts +9 -0
  107. package/dist/providers/factories.js +12 -0
  108. package/dist/providers/factories.js.map +1 -0
  109. package/dist/providers/local.d.ts +4 -0
  110. package/dist/providers/local.js +64 -0
  111. package/dist/providers/local.js.map +1 -0
  112. package/dist/providers/podman.d.ts +3 -0
  113. package/dist/providers/podman.js +3 -0
  114. package/dist/providers/podman.js.map +1 -0
  115. package/dist/providers/vercel.d.ts +9 -0
  116. package/dist/providers/vercel.js +158 -0
  117. package/dist/providers/vercel.js.map +1 -0
  118. package/dist/providers/versions.d.ts +4 -0
  119. package/dist/providers/versions.js +5 -0
  120. package/dist/providers/versions.js.map +1 -0
  121. package/docs/api.md +147 -0
  122. package/docs/architecture.md +21 -0
  123. package/docs/migration-1.1.fr.md +44 -0
  124. package/docs/migration-1.1.md +38 -0
  125. package/docs/operations.md +101 -0
  126. package/docs/providers.md +119 -0
  127. package/docs/workflows.md +101 -0
  128. package/package.json +95 -0
@@ -0,0 +1,153 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { posix } from "node:path";
3
+ import { OutpostError } from "../domain/errors.js";
4
+ import { quote } from "../infrastructure/process.js";
5
+ import { interruptible } from "../infrastructure/abort.js";
6
+ import { registerCleanup } from "../infrastructure/shutdown.js";
7
+ import { downloadTree, manifestScript, uploadTree } from "./cloud-files.js";
8
+ import { transfer } from "../infrastructure/transfer.js";
9
+ export function daytona(options = {}, connect = async (config) => new (await import("@daytona/sdk")).Daytona(config)) {
10
+ return {
11
+ name: "daytona",
12
+ placement: "remote",
13
+ variables: { ...options.variables },
14
+ async acquire(context) {
15
+ context.signal?.throwIfAborted();
16
+ const client = await connect(options.connection);
17
+ const sandbox = await client.create(options.create ?? {});
18
+ const home = (await sandbox.getUserHomeDir()) ?? "/home/daytona";
19
+ const root = options.root ?? posix.join(home, "outpost");
20
+ let closed = false, releasing;
21
+ let unregister = () => { };
22
+ const release = () => (releasing ??= client
23
+ .delete(sandbox)
24
+ .then(() => {
25
+ closed = true;
26
+ unregister();
27
+ })
28
+ .catch((error) => {
29
+ releasing = undefined;
30
+ throw error;
31
+ }));
32
+ unregister = registerCleanup(release);
33
+ try {
34
+ await sandbox.fs.createFolder(root, "755");
35
+ }
36
+ catch (cause) {
37
+ await release();
38
+ throw cause;
39
+ }
40
+ return {
41
+ root,
42
+ home,
43
+ async invoke(command) {
44
+ if (closed)
45
+ throw new OutpostError("provider", "Cloud sandbox is closed");
46
+ if (command.interactive)
47
+ throw new OutpostError("provider", "Interactive terminals require a mounted or local provider");
48
+ const signal = command.signal
49
+ ? AbortSignal.any([
50
+ command.signal,
51
+ AbortSignal.timeout(command.deadlineMs ?? 600_000),
52
+ ])
53
+ : AbortSignal.timeout(command.deadlineMs ?? 600_000);
54
+ signal.throwIfAborted();
55
+ const id = `outpost-${randomUUID()}`;
56
+ const input = `/tmp/${id}.stdin`;
57
+ const pid = `/tmp/${id}.pid`;
58
+ if (command.stdin !== undefined)
59
+ await sandbox.fs.uploadFile(Buffer.from(command.stdin), input);
60
+ const variables = { ...context.variables, ...command.variables };
61
+ const program = [
62
+ ...(command.elevated ? ["sudo", "-n", "--"] : []),
63
+ command.executable,
64
+ ...(command.arguments ?? []),
65
+ ]
66
+ .map(quote)
67
+ .join(" ");
68
+ const script = `cd ${quote(command.directory ?? root)} && exec env ${Object.entries(variables)
69
+ .map(([key, value]) => quote(`${key}=${value}`))
70
+ .join(" ")} setsid sh -c ${quote(`echo $$ > ${quote(pid)}; test ! -f ${quote(pid + ".cancel")} || exit 130; exec ${program}${command.stdin === undefined ? "" : ` < ${quote(input)}`}`)}`;
71
+ const output = { stdout: "", stderr: "" };
72
+ let cancellation;
73
+ const cancel = () => {
74
+ cancellation ??= sandbox.process.executeCommand(`touch ${quote(pid + ".cancel")}; if [ -f ${quote(pid)} ]; then kill -KILL -$(cat ${quote(pid)}) 2>/dev/null || true; fi`);
75
+ void cancellation.catch(() => undefined);
76
+ };
77
+ await sandbox.process.createSession(id);
78
+ try {
79
+ signal.addEventListener("abort", cancel, { once: true });
80
+ if (signal.aborted)
81
+ cancel();
82
+ signal.throwIfAborted();
83
+ const response = await interruptible(sandbox.process.executeSessionCommand(id, {
84
+ command: script,
85
+ async: true,
86
+ }), signal);
87
+ if (!response.cmdId)
88
+ throw new OutpostError("provider", "Cloud provider returned no command identifier");
89
+ const consume = (channel) => (chunk) => {
90
+ output[channel] = (output[channel] + chunk).slice(-(command.retain ?? options.retain ?? 65_536));
91
+ command.observe?.(channel, chunk);
92
+ };
93
+ await interruptible(sandbox.process.getSessionCommandLogs(id, response.cmdId, consume("stdout"), consume("stderr")), signal);
94
+ if (cancellation)
95
+ await cancellation;
96
+ signal.throwIfAborted();
97
+ const result = await sandbox.process.getSessionCommand(id, response.cmdId);
98
+ if (result.exitCode === undefined)
99
+ throw new OutpostError("provider", "Cloud command ended without an exit status");
100
+ return { status: result.exitCode, ...output };
101
+ }
102
+ catch (cause) {
103
+ cancel();
104
+ try {
105
+ await interruptible(cancellation, AbortSignal.timeout(15_000));
106
+ }
107
+ catch (cleanup) {
108
+ throw new AggregateError([cause, cleanup], "Cloud cancellation could not be confirmed");
109
+ }
110
+ throw cause;
111
+ }
112
+ finally {
113
+ signal.removeEventListener("abort", cancel);
114
+ await sandbox.process.deleteSession(id);
115
+ await sandbox.process
116
+ .executeCommand(`rm -f ${quote(input)} ${quote(pid)}`)
117
+ .catch(() => undefined);
118
+ }
119
+ },
120
+ async upload(source, destination, options = {}) {
121
+ return transfer(options, async (signal) => {
122
+ await uploadTree(source, destination, async (path, content) => {
123
+ await sandbox.fs.createFolder(posix.dirname(path), "755");
124
+ await sandbox.fs.uploadFile(content, path);
125
+ }, async (target, path) => {
126
+ const result = await sandbox.process.executeCommand(`mkdir -p ${quote(posix.dirname(path))} && ln -s -- ${quote(target)} ${quote(path)}`);
127
+ if (result.exitCode !== 0)
128
+ throw new OutpostError("provider", "Symlink upload failed");
129
+ }, async (path, directory, mode) => {
130
+ if (directory)
131
+ await sandbox.fs.createFolder(path, mode.toString(8));
132
+ else {
133
+ const result = await sandbox.process.executeCommand(`chmod ${mode.toString(8)} ${quote(path)}`);
134
+ if (result.exitCode !== 0)
135
+ throw new OutpostError("provider", "Transfer permissions could not be set");
136
+ }
137
+ }, signal);
138
+ });
139
+ },
140
+ async download(source, destination, options = {}) {
141
+ return transfer(options, async (signal) => {
142
+ const listing = await sandbox.process.executeCommand(`node -e ${quote(manifestScript)} ${quote(source)}`);
143
+ if (listing.exitCode !== 0)
144
+ throw new OutpostError("provider", "Remote transfer source is unavailable");
145
+ await downloadTree(source, destination, listing.result, (path) => sandbox.fs.downloadFile(path), signal);
146
+ });
147
+ },
148
+ release,
149
+ };
150
+ },
151
+ };
152
+ }
153
+ //# sourceMappingURL=daytona.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daytona.js","sourceRoot":"","sources":["../../src/providers/daytona.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { posix } from \"node:path\";\nimport type {\n Daytona,\n DaytonaConfig,\n CreateSandboxFromImageParams,\n CreateSandboxFromSnapshotParams,\n} from \"@daytona/sdk\";\nimport type { SandboxProvider, Variables } from \"../domain/ports.ts\";\nimport { OutpostError } from \"../domain/errors.ts\";\nimport { quote } from \"../infrastructure/process.ts\";\nimport { interruptible } from \"../infrastructure/abort.ts\";\nimport { registerCleanup } from \"../infrastructure/shutdown.ts\";\nimport { downloadTree, manifestScript, uploadTree } from \"./cloud-files.ts\";\nimport { transfer } from \"../infrastructure/transfer.ts\";\n\nexport interface DaytonaOptions {\n readonly connection?: DaytonaConfig;\n readonly create?:\n CreateSandboxFromImageParams | CreateSandboxFromSnapshotParams;\n readonly variables?: Variables;\n readonly root?: string;\n readonly retain?: number;\n}\n\nexport function daytona(\n options: DaytonaOptions = {},\n connect: (\n config?: DaytonaConfig,\n ) => Promise<Pick<Daytona, \"create\" | \"delete\">> = async (config) =>\n new (await import(\"@daytona/sdk\")).Daytona(config),\n): SandboxProvider {\n return {\n name: \"daytona\",\n placement: \"remote\",\n variables: { ...options.variables },\n async acquire(context) {\n context.signal?.throwIfAborted();\n const client = await connect(options.connection);\n const sandbox = await client.create(options.create ?? {});\n const home = (await sandbox.getUserHomeDir()) ?? \"/home/daytona\";\n const root = options.root ?? posix.join(home, \"outpost\");\n let closed = false,\n releasing: Promise<void> | undefined;\n let unregister = () => {};\n const release = () =>\n (releasing ??= client\n .delete(sandbox)\n .then(() => {\n closed = true;\n unregister();\n })\n .catch((error) => {\n releasing = undefined;\n throw error;\n }));\n unregister = registerCleanup(release);\n try {\n await sandbox.fs.createFolder(root, \"755\");\n } catch (cause) {\n await release();\n throw cause;\n }\n return {\n root,\n home,\n async invoke(command) {\n if (closed)\n throw new OutpostError(\"provider\", \"Cloud sandbox is closed\");\n if (command.interactive)\n throw new OutpostError(\n \"provider\",\n \"Interactive terminals require a mounted or local provider\",\n );\n const signal = command.signal\n ? AbortSignal.any([\n command.signal,\n AbortSignal.timeout(command.deadlineMs ?? 600_000),\n ])\n : AbortSignal.timeout(command.deadlineMs ?? 600_000);\n signal.throwIfAborted();\n const id = `outpost-${randomUUID()}`;\n const input = `/tmp/${id}.stdin`;\n const pid = `/tmp/${id}.pid`;\n if (command.stdin !== undefined)\n await sandbox.fs.uploadFile(Buffer.from(command.stdin), input);\n const variables = { ...context.variables, ...command.variables };\n const program = [\n ...(command.elevated ? [\"sudo\", \"-n\", \"--\"] : []),\n command.executable,\n ...(command.arguments ?? []),\n ]\n .map(quote)\n .join(\" \");\n const script = `cd ${quote(command.directory ?? root)} && exec env ${Object.entries(\n variables,\n )\n .map(([key, value]) => quote(`${key}=${value}`))\n .join(\n \" \",\n )} setsid sh -c ${quote(`echo $$ > ${quote(pid)}; test ! -f ${quote(pid + \".cancel\")} || exit 130; exec ${program}${command.stdin === undefined ? \"\" : ` < ${quote(input)}`}`)}`;\n const output = { stdout: \"\", stderr: \"\" };\n let cancellation: Promise<unknown> | undefined;\n const cancel = () => {\n cancellation ??= sandbox.process.executeCommand(\n `touch ${quote(pid + \".cancel\")}; if [ -f ${quote(pid)} ]; then kill -KILL -$(cat ${quote(pid)}) 2>/dev/null || true; fi`,\n );\n void cancellation.catch(() => undefined);\n };\n await sandbox.process.createSession(id);\n try {\n signal.addEventListener(\"abort\", cancel, { once: true });\n if (signal.aborted) cancel();\n signal.throwIfAborted();\n const response = await interruptible(\n sandbox.process.executeSessionCommand(id, {\n command: script,\n async: true,\n }),\n signal,\n );\n if (!response.cmdId)\n throw new OutpostError(\n \"provider\",\n \"Cloud provider returned no command identifier\",\n );\n const consume =\n (channel: \"stdout\" | \"stderr\") => (chunk: string) => {\n output[channel] = (output[channel] + chunk).slice(\n -(command.retain ?? options.retain ?? 65_536),\n );\n command.observe?.(channel, chunk);\n };\n await interruptible(\n sandbox.process.getSessionCommandLogs(\n id,\n response.cmdId,\n consume(\"stdout\"),\n consume(\"stderr\"),\n ),\n signal,\n );\n if (cancellation) await cancellation;\n signal.throwIfAborted();\n const result = await sandbox.process.getSessionCommand(\n id,\n response.cmdId,\n );\n if (result.exitCode === undefined)\n throw new OutpostError(\n \"provider\",\n \"Cloud command ended without an exit status\",\n );\n return { status: result.exitCode, ...output };\n } catch (cause) {\n cancel();\n try {\n await interruptible(cancellation!, AbortSignal.timeout(15_000));\n } catch (cleanup) {\n throw new AggregateError(\n [cause, cleanup],\n \"Cloud cancellation could not be confirmed\",\n );\n }\n throw cause;\n } finally {\n signal.removeEventListener(\"abort\", cancel);\n await sandbox.process.deleteSession(id);\n await sandbox.process\n .executeCommand(`rm -f ${quote(input)} ${quote(pid)}`)\n .catch(() => undefined);\n }\n },\n async upload(source, destination, options = {}) {\n return transfer(options, async (signal) => {\n await uploadTree(\n source,\n destination,\n async (path, content) => {\n await sandbox.fs.createFolder(posix.dirname(path), \"755\");\n await sandbox.fs.uploadFile(content, path);\n },\n async (target, path) => {\n const result = await sandbox.process.executeCommand(\n `mkdir -p ${quote(posix.dirname(path))} && ln -s -- ${quote(target)} ${quote(path)}`,\n );\n if (result.exitCode !== 0)\n throw new OutpostError(\"provider\", \"Symlink upload failed\");\n },\n async (path, directory, mode) => {\n if (directory)\n await sandbox.fs.createFolder(path, mode.toString(8));\n else {\n const result = await sandbox.process.executeCommand(\n `chmod ${mode.toString(8)} ${quote(path)}`,\n );\n if (result.exitCode !== 0)\n throw new OutpostError(\n \"provider\",\n \"Transfer permissions could not be set\",\n );\n }\n },\n signal,\n );\n });\n },\n async download(source, destination, options = {}) {\n return transfer(options, async (signal) => {\n const listing = await sandbox.process.executeCommand(\n `node -e ${quote(manifestScript)} ${quote(source)}`,\n );\n if (listing.exitCode !== 0)\n throw new OutpostError(\n \"provider\",\n \"Remote transfer source is unavailable\",\n );\n await downloadTree(\n source,\n destination,\n listing.result,\n (path) => sandbox.fs.downloadFile(path),\n signal,\n );\n });\n },\n release,\n };\n },\n };\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { ContainerOptions } from "./container.ts";
2
+ export type { ContainerOptions } from "./container.ts";
3
+ export declare const docker: (options?: ContainerOptions) => import("../index.ts").SandboxProvider;
@@ -0,0 +1,3 @@
1
+ import { containerProvider } from "./container.js";
2
+ export const docker = (options = {}) => containerProvider("docker", options);
3
+ //# sourceMappingURL=docker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"docker.js","sourceRoot":"","sources":["../../src/providers/docker.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGnD,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,UAA4B,EAAE,EAAE,EAAE,CACvD,iBAAiB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC","sourcesContent":["import { containerProvider } from \"./container.ts\";\nimport type { ContainerOptions } from \"./container.ts\";\nexport type { ContainerOptions } from \"./container.ts\";\nexport const docker = (options: ContainerOptions = {}) =>\n containerProvider(\"docker\", options);\n"]}
@@ -0,0 +1,9 @@
1
+ import type { SandboxContext, SandboxLease, SandboxProvider, Variables } from "../domain/ports.ts";
2
+ interface ProviderDefinition {
3
+ readonly name: string;
4
+ readonly variables?: Variables;
5
+ acquire(context: SandboxContext): Promise<SandboxLease>;
6
+ }
7
+ export declare const mountedProvider: (definition: ProviderDefinition) => SandboxProvider;
8
+ export declare const remoteProvider: (definition: ProviderDefinition) => SandboxProvider;
9
+ export {};
@@ -0,0 +1,12 @@
1
+ import { invariant } from "../domain/errors.js";
2
+ function provider(placement, definition) {
3
+ invariant(definition.name.trim(), "A provider needs a name");
4
+ return Object.freeze({
5
+ ...definition,
6
+ placement,
7
+ variables: Object.freeze({ ...definition.variables }),
8
+ });
9
+ }
10
+ export const mountedProvider = (definition) => provider("mounted", definition);
11
+ export const remoteProvider = (definition) => provider("remote", definition);
12
+ //# sourceMappingURL=factories.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"factories.js","sourceRoot":"","sources":["../../src/providers/factories.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAC;AAQhD,SAAS,QAAQ,CACf,SAA+B,EAC/B,UAA8B;IAE9B,SAAS,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,yBAAyB,CAAC,CAAC;IAC7D,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,GAAG,UAAU;QACb,SAAS;QACT,SAAS,EAAE,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,UAAU,CAAC,SAAS,EAAE,CAAC;KACtD,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,UAA8B,EACb,EAAE,CAAC,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC;AACtD,MAAM,CAAC,MAAM,cAAc,GAAG,CAC5B,UAA8B,EACb,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC","sourcesContent":["import type {\n SandboxContext,\n SandboxLease,\n SandboxProvider,\n Variables,\n} from \"../domain/ports.ts\";\nimport { invariant } from \"../domain/errors.ts\";\n\ninterface ProviderDefinition {\n readonly name: string;\n readonly variables?: Variables;\n acquire(context: SandboxContext): Promise<SandboxLease>;\n}\n\nfunction provider(\n placement: \"mounted\" | \"remote\",\n definition: ProviderDefinition,\n): SandboxProvider {\n invariant(definition.name.trim(), \"A provider needs a name\");\n return Object.freeze({\n ...definition,\n placement,\n variables: Object.freeze({ ...definition.variables }),\n });\n}\n\nexport const mountedProvider = (\n definition: ProviderDefinition,\n): SandboxProvider => provider(\"mounted\", definition);\nexport const remoteProvider = (\n definition: ProviderDefinition,\n): SandboxProvider => provider(\"remote\", definition);\n"]}
@@ -0,0 +1,4 @@
1
+ import type { SandboxProvider, Variables } from "../domain/ports.ts";
2
+ export declare function local(options?: {
3
+ variables?: Variables;
4
+ }): SandboxProvider;
@@ -0,0 +1,64 @@
1
+ import { cp, mkdir } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { dirname, resolve } from "node:path";
4
+ import { executeProcess } from "../infrastructure/process.js";
5
+ import { OutpostError } from "../domain/errors.js";
6
+ export function local(options = {}) {
7
+ return {
8
+ name: "local",
9
+ placement: "host",
10
+ variables: { ...options.variables },
11
+ async acquire(context) {
12
+ context.signal?.throwIfAborted();
13
+ const stop = new AbortController();
14
+ const active = new Set();
15
+ let disposed = false;
16
+ const copy = async (source, destination, options = {}) => {
17
+ options.signal?.throwIfAborted();
18
+ if (disposed)
19
+ throw new OutpostError("provider", "Local sandbox is closed");
20
+ if (resolve(source) === resolve(destination))
21
+ return;
22
+ await mkdir(dirname(destination), { recursive: true });
23
+ await cp(source, destination, {
24
+ recursive: true,
25
+ force: true,
26
+ filter: () => {
27
+ options.signal?.throwIfAborted();
28
+ return true;
29
+ },
30
+ });
31
+ };
32
+ return {
33
+ root: context.directory,
34
+ home: homedir(),
35
+ invoke(command) {
36
+ if (disposed)
37
+ return Promise.reject(new OutpostError("provider", "Local sandbox is closed"));
38
+ const signal = command.signal
39
+ ? AbortSignal.any([command.signal, stop.signal])
40
+ : stop.signal;
41
+ const pending = executeProcess({
42
+ ...command,
43
+ directory: command.directory ?? context.directory,
44
+ variables: { ...context.variables, ...command.variables },
45
+ signal,
46
+ });
47
+ active.add(pending);
48
+ void pending.then(() => active.delete(pending), () => active.delete(pending));
49
+ return pending;
50
+ },
51
+ upload: copy,
52
+ download: copy,
53
+ async release() {
54
+ if (disposed)
55
+ return;
56
+ disposed = true;
57
+ stop.abort(new OutpostError("aborted", "Sandbox disposed"));
58
+ await Promise.allSettled(active);
59
+ },
60
+ };
61
+ },
62
+ };
63
+ }
64
+ //# sourceMappingURL=local.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local.js","sourceRoot":"","sources":["../../src/providers/local.ts"],"names":[],"mappings":"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","sourcesContent":["import { cp, mkdir } from \"node:fs/promises\";\nimport { homedir } from \"node:os\";\nimport { dirname, resolve } from \"node:path\";\nimport { executeProcess } from \"../infrastructure/process.ts\";\nimport { OutpostError } from \"../domain/errors.ts\";\nimport type {\n Command,\n SandboxProvider,\n Variables,\n TransferOptions,\n} from \"../domain/ports.ts\";\n\nexport function local(\n options: { variables?: Variables } = {},\n): SandboxProvider {\n return {\n name: \"local\",\n placement: \"host\",\n variables: { ...options.variables },\n async acquire(context) {\n context.signal?.throwIfAborted();\n const stop = new AbortController();\n const active = new Set<Promise<unknown>>();\n let disposed = false;\n const copy = async (\n source: string,\n destination: string,\n options: TransferOptions = {},\n ) => {\n options.signal?.throwIfAborted();\n if (disposed)\n throw new OutpostError(\"provider\", \"Local sandbox is closed\");\n if (resolve(source) === resolve(destination)) return;\n await mkdir(dirname(destination), { recursive: true });\n await cp(source, destination, {\n recursive: true,\n force: true,\n filter: () => {\n options.signal?.throwIfAborted();\n return true;\n },\n });\n };\n return {\n root: context.directory,\n home: homedir(),\n invoke(command: Command) {\n if (disposed)\n return Promise.reject(\n new OutpostError(\"provider\", \"Local sandbox is closed\"),\n );\n const signal = command.signal\n ? AbortSignal.any([command.signal, stop.signal])\n : stop.signal;\n const pending = executeProcess({\n ...command,\n directory: command.directory ?? context.directory,\n variables: { ...context.variables, ...command.variables },\n signal,\n });\n active.add(pending);\n void pending.then(\n () => active.delete(pending),\n () => active.delete(pending),\n );\n return pending;\n },\n upload: copy,\n download: copy,\n async release() {\n if (disposed) return;\n disposed = true;\n stop.abort(new OutpostError(\"aborted\", \"Sandbox disposed\"));\n await Promise.allSettled(active);\n },\n };\n },\n };\n}\n"]}
@@ -0,0 +1,3 @@
1
+ import type { ContainerOptions } from "./container.ts";
2
+ export type { ContainerOptions } from "./container.ts";
3
+ export declare const podman: (options?: ContainerOptions) => import("../index.ts").SandboxProvider;
@@ -0,0 +1,3 @@
1
+ import { containerProvider } from "./container.js";
2
+ export const podman = (options = {}) => containerProvider("podman", options);
3
+ //# sourceMappingURL=podman.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"podman.js","sourceRoot":"","sources":["../../src/providers/podman.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAGnD,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,UAA4B,EAAE,EAAE,EAAE,CACvD,iBAAiB,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC","sourcesContent":["import { containerProvider } from \"./container.ts\";\nimport type { ContainerOptions } from \"./container.ts\";\nexport type { ContainerOptions } from \"./container.ts\";\nexport const podman = (options: ContainerOptions = {}) =>\n containerProvider(\"podman\", options);\n"]}
@@ -0,0 +1,9 @@
1
+ import type { Sandbox } from "@vercel/sandbox";
2
+ import type { SandboxProvider, Variables } from "../domain/ports.ts";
3
+ export interface VercelOptions {
4
+ readonly create?: NonNullable<Parameters<typeof Sandbox.create>[0]>;
5
+ readonly variables?: Variables;
6
+ readonly root?: string;
7
+ readonly retain?: number;
8
+ }
9
+ export declare function vercel(options?: VercelOptions, connect?: (config: VercelOptions["create"]) => Promise<Sandbox>): SandboxProvider;
@@ -0,0 +1,158 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { posix } from "node:path";
3
+ import { OutpostError } from "../domain/errors.js";
4
+ import { quote } from "../infrastructure/process.js";
5
+ import { registerCleanup } from "../infrastructure/shutdown.js";
6
+ import { downloadTree, manifestScript, uploadTree } from "./cloud-files.js";
7
+ import { transfer } from "../infrastructure/transfer.js";
8
+ export function vercel(options = {}, connect = async (config) => (await import("@vercel/sandbox")).Sandbox.create(config)) {
9
+ return {
10
+ name: "vercel",
11
+ placement: "remote",
12
+ variables: { ...options.variables },
13
+ async acquire(context) {
14
+ context.signal?.throwIfAborted();
15
+ const sandbox = await connect({
16
+ ...options.create,
17
+ env: { ...options.create?.env, ...context.variables },
18
+ });
19
+ const root = options.root ?? "/vercel/sandbox/outpost";
20
+ let closed = false;
21
+ let releasing;
22
+ let unregister = () => { };
23
+ const release = () => (releasing ??= sandbox
24
+ .stop()
25
+ .then(() => {
26
+ closed = true;
27
+ unregister();
28
+ })
29
+ .catch((error) => {
30
+ releasing = undefined;
31
+ throw error;
32
+ }));
33
+ unregister = registerCleanup(release);
34
+ let home;
35
+ try {
36
+ await sandbox.mkDir(root);
37
+ home = (await (await sandbox.runCommand("printenv", ["HOME"])).stdout()).trim();
38
+ if (!home.startsWith("/"))
39
+ throw new OutpostError("provider", "Cloud sandbox returned an invalid home directory");
40
+ }
41
+ catch (cause) {
42
+ await release();
43
+ throw cause;
44
+ }
45
+ return {
46
+ root,
47
+ home,
48
+ async invoke(command) {
49
+ if (closed)
50
+ throw new OutpostError("provider", "Cloud sandbox is closed");
51
+ if (command.interactive)
52
+ throw new OutpostError("provider", "Interactive terminals require a mounted or local provider");
53
+ const signal = command.signal
54
+ ? AbortSignal.any([
55
+ command.signal,
56
+ AbortSignal.timeout(command.deadlineMs ?? 600_000),
57
+ ])
58
+ : AbortSignal.timeout(command.deadlineMs ?? 600_000);
59
+ signal.throwIfAborted();
60
+ const inputPath = `/tmp/outpost-${randomUUID()}.stdin`;
61
+ if (command.stdin !== undefined)
62
+ await sandbox.writeFiles([
63
+ { path: inputPath, content: Buffer.from(command.stdin) },
64
+ ]);
65
+ const output = { stdout: "", stderr: "" };
66
+ const cmd = command.stdin === undefined ? command.executable : "sh";
67
+ const args = command.stdin === undefined
68
+ ? [...(command.arguments ?? [])]
69
+ : [
70
+ "-c",
71
+ `exec ${[command.executable, ...(command.arguments ?? [])].map(quote).join(" ")} < ${quote(inputPath)}`,
72
+ ];
73
+ try {
74
+ const running = await sandbox.runCommand({
75
+ cmd,
76
+ args,
77
+ cwd: command.directory ?? root,
78
+ env: { ...command.variables },
79
+ sudo: command.elevated ?? false,
80
+ detached: true,
81
+ signal,
82
+ timeoutMs: command.deadlineMs ?? 600_000,
83
+ });
84
+ try {
85
+ for await (const log of running.logs({ signal })) {
86
+ const channel = log.stream;
87
+ if (channel !== "stdout" && channel !== "stderr")
88
+ continue;
89
+ output[channel] = (output[channel] + log.data).slice(-(command.retain ?? options.retain ?? 65_536));
90
+ command.observe?.(channel, log.data);
91
+ }
92
+ const result = await running.wait({ signal });
93
+ return { status: result.exitCode, ...output };
94
+ }
95
+ catch (cause) {
96
+ await running.kill("SIGKILL", {
97
+ abortSignal: AbortSignal.timeout(15_000),
98
+ });
99
+ throw cause;
100
+ }
101
+ }
102
+ finally {
103
+ if (command.stdin !== undefined)
104
+ await sandbox
105
+ .runCommand("rm", ["-f", inputPath])
106
+ .catch(() => undefined);
107
+ }
108
+ },
109
+ async upload(source, destination, options = {}) {
110
+ return transfer(options, async (signal) => {
111
+ await uploadTree(source, destination, (path, content) => sandbox.writeFiles([{ path, content }]), async (target, path) => {
112
+ await sandbox.mkDir(posix.dirname(path));
113
+ const result = await sandbox.runCommand("ln", [
114
+ "-s",
115
+ "--",
116
+ target,
117
+ path,
118
+ ]);
119
+ if (result.exitCode !== 0)
120
+ throw new OutpostError("provider", "Symlink upload failed");
121
+ }, async (path, directory, mode) => {
122
+ if (directory)
123
+ await sandbox.mkDir(path);
124
+ const result = await sandbox.runCommand("chmod", [
125
+ mode.toString(8),
126
+ path,
127
+ ]);
128
+ if (result.exitCode !== 0)
129
+ throw new OutpostError("provider", "Transfer permissions could not be set");
130
+ }, signal);
131
+ });
132
+ },
133
+ async download(source, destination, options = {}) {
134
+ return transfer(options, async (signal) => {
135
+ const listing = await sandbox.runCommand("node", [
136
+ "-e",
137
+ manifestScript,
138
+ source,
139
+ ]);
140
+ if (listing.exitCode !== 0)
141
+ throw new OutpostError("provider", "Remote transfer source is unavailable");
142
+ await downloadTree(source, destination, await listing.stdout(), async (path) => {
143
+ const stream = await sandbox.readFile({ path });
144
+ if (!stream)
145
+ throw new OutpostError("provider", `Remote file is missing: ${path}`);
146
+ const chunks = [];
147
+ for await (const chunk of stream)
148
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
149
+ return Buffer.concat(chunks);
150
+ }, signal);
151
+ });
152
+ },
153
+ release,
154
+ };
155
+ },
156
+ };
157
+ }
158
+ //# sourceMappingURL=vercel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vercel.js","sourceRoot":"","sources":["../../src/providers/vercel.ts"],"names":[],"mappings":"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","sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { posix } from \"node:path\";\nimport type { Sandbox } from \"@vercel/sandbox\";\nimport type { SandboxProvider, Variables } from \"../domain/ports.ts\";\nimport { OutpostError } from \"../domain/errors.ts\";\nimport { quote } from \"../infrastructure/process.ts\";\nimport { registerCleanup } from \"../infrastructure/shutdown.ts\";\nimport { downloadTree, manifestScript, uploadTree } from \"./cloud-files.ts\";\nimport { transfer } from \"../infrastructure/transfer.ts\";\n\nexport interface VercelOptions {\n readonly create?: NonNullable<Parameters<typeof Sandbox.create>[0]>;\n readonly variables?: Variables;\n readonly root?: string;\n readonly retain?: number;\n}\n\nexport function vercel(\n options: VercelOptions = {},\n connect: (config: VercelOptions[\"create\"]) => Promise<Sandbox> = async (\n config,\n ) => (await import(\"@vercel/sandbox\")).Sandbox.create(config),\n): SandboxProvider {\n return {\n name: \"vercel\",\n placement: \"remote\",\n variables: { ...options.variables },\n async acquire(context) {\n context.signal?.throwIfAborted();\n const sandbox = await connect({\n ...options.create,\n env: { ...options.create?.env, ...context.variables },\n });\n const root = options.root ?? \"/vercel/sandbox/outpost\";\n let closed = false;\n let releasing: Promise<void> | undefined;\n let unregister = () => {};\n const release = () =>\n (releasing ??= sandbox\n .stop()\n .then(() => {\n closed = true;\n unregister();\n })\n .catch((error) => {\n releasing = undefined;\n throw error;\n }));\n unregister = registerCleanup(release);\n let home: string;\n try {\n await sandbox.mkDir(root);\n home = (\n await (await sandbox.runCommand(\"printenv\", [\"HOME\"])).stdout()\n ).trim();\n if (!home.startsWith(\"/\"))\n throw new OutpostError(\n \"provider\",\n \"Cloud sandbox returned an invalid home directory\",\n );\n } catch (cause) {\n await release();\n throw cause;\n }\n return {\n root,\n home,\n async invoke(command) {\n if (closed)\n throw new OutpostError(\"provider\", \"Cloud sandbox is closed\");\n if (command.interactive)\n throw new OutpostError(\n \"provider\",\n \"Interactive terminals require a mounted or local provider\",\n );\n const signal = command.signal\n ? AbortSignal.any([\n command.signal,\n AbortSignal.timeout(command.deadlineMs ?? 600_000),\n ])\n : AbortSignal.timeout(command.deadlineMs ?? 600_000);\n signal.throwIfAborted();\n const inputPath = `/tmp/outpost-${randomUUID()}.stdin`;\n if (command.stdin !== undefined)\n await sandbox.writeFiles([\n { path: inputPath, content: Buffer.from(command.stdin) },\n ]);\n const output = { stdout: \"\", stderr: \"\" };\n const cmd = command.stdin === undefined ? command.executable : \"sh\";\n const args =\n command.stdin === undefined\n ? [...(command.arguments ?? [])]\n : [\n \"-c\",\n `exec ${[command.executable, ...(command.arguments ?? [])].map(quote).join(\" \")} < ${quote(inputPath)}`,\n ];\n try {\n const running = await sandbox.runCommand({\n cmd,\n args,\n cwd: command.directory ?? root,\n env: { ...command.variables },\n sudo: command.elevated ?? false,\n detached: true,\n signal,\n timeoutMs: command.deadlineMs ?? 600_000,\n });\n try {\n for await (const log of running.logs({ signal })) {\n const channel = log.stream;\n if (channel !== \"stdout\" && channel !== \"stderr\") continue;\n output[channel] = (output[channel] + log.data).slice(\n -(command.retain ?? options.retain ?? 65_536),\n );\n command.observe?.(channel, log.data);\n }\n const result = await running.wait({ signal });\n return { status: result.exitCode, ...output };\n } catch (cause) {\n await running.kill(\"SIGKILL\", {\n abortSignal: AbortSignal.timeout(15_000),\n });\n throw cause;\n }\n } finally {\n if (command.stdin !== undefined)\n await sandbox\n .runCommand(\"rm\", [\"-f\", inputPath])\n .catch(() => undefined);\n }\n },\n async upload(source, destination, options = {}) {\n return transfer(options, async (signal) => {\n await uploadTree(\n source,\n destination,\n (path, content) => sandbox.writeFiles([{ path, content }]),\n async (target, path) => {\n await sandbox.mkDir(posix.dirname(path));\n const result = await sandbox.runCommand(\"ln\", [\n \"-s\",\n \"--\",\n target,\n path,\n ]);\n if (result.exitCode !== 0)\n throw new OutpostError(\"provider\", \"Symlink upload failed\");\n },\n async (path, directory, mode) => {\n if (directory) await sandbox.mkDir(path);\n const result = await sandbox.runCommand(\"chmod\", [\n mode.toString(8),\n path,\n ]);\n if (result.exitCode !== 0)\n throw new OutpostError(\n \"provider\",\n \"Transfer permissions could not be set\",\n );\n },\n signal,\n );\n });\n },\n async download(source, destination, options = {}) {\n return transfer(options, async (signal) => {\n const listing = await sandbox.runCommand(\"node\", [\n \"-e\",\n manifestScript,\n source,\n ]);\n if (listing.exitCode !== 0)\n throw new OutpostError(\n \"provider\",\n \"Remote transfer source is unavailable\",\n );\n await downloadTree(\n source,\n destination,\n await listing.stdout(),\n async (path) => {\n const stream = await sandbox.readFile({ path });\n if (!stream)\n throw new OutpostError(\n \"provider\",\n `Remote file is missing: ${path}`,\n );\n const chunks: Buffer[] = [];\n for await (const chunk of stream)\n chunks.push(\n Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk),\n );\n return Buffer.concat(chunks);\n },\n signal,\n );\n });\n },\n release,\n };\n },\n };\n}\n"]}
@@ -0,0 +1,4 @@
1
+ export declare const agentVersions: Readonly<{
2
+ codex: "0.156.1";
3
+ claude: "2.1.280";
4
+ }>;
@@ -0,0 +1,5 @@
1
+ export const agentVersions = Object.freeze({
2
+ codex: "0.156.1",
3
+ claude: "2.1.280",
4
+ });
5
+ //# sourceMappingURL=versions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"versions.js","sourceRoot":"","sources":["../../src/providers/versions.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;IACzC,KAAK,EAAE,SAAS;IAChB,MAAM,EAAE,SAAS;CAClB,CAAC,CAAC","sourcesContent":["export const agentVersions = Object.freeze({\n codex: \"0.156.1\",\n claude: \"2.1.280\",\n});\n"]}