@vendoai/apps 0.4.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 (203) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +8 -0
  3. package/dist/adapter-conformance.d.ts +48 -0
  4. package/dist/adapter-conformance.d.ts.map +1 -0
  5. package/dist/adapter-conformance.js +196 -0
  6. package/dist/adapter-conformance.js.map +1 -0
  7. package/dist/agent-tools.d.ts +10 -0
  8. package/dist/agent-tools.d.ts.map +1 -0
  9. package/dist/agent-tools.js +252 -0
  10. package/dist/agent-tools.js.map +1 -0
  11. package/dist/app-data.d.ts +23 -0
  12. package/dist/app-data.d.ts.map +1 -0
  13. package/dist/app-data.js +129 -0
  14. package/dist/app-data.js.map +1 -0
  15. package/dist/app-token.d.ts +24 -0
  16. package/dist/app-token.d.ts.map +1 -0
  17. package/dist/app-token.js +61 -0
  18. package/dist/app-token.js.map +1 -0
  19. package/dist/audit.d.ts +11 -0
  20. package/dist/audit.d.ts.map +1 -0
  21. package/dist/audit.js +19 -0
  22. package/dist/audit.js.map +1 -0
  23. package/dist/automation-plan.d.ts +43 -0
  24. package/dist/automation-plan.d.ts.map +1 -0
  25. package/dist/automation-plan.js +212 -0
  26. package/dist/automation-plan.js.map +1 -0
  27. package/dist/bench/client.d.ts +43 -0
  28. package/dist/bench/client.d.ts.map +1 -0
  29. package/dist/bench/client.js +129 -0
  30. package/dist/bench/client.js.map +1 -0
  31. package/dist/bench/fixtures.d.ts +42 -0
  32. package/dist/bench/fixtures.d.ts.map +1 -0
  33. package/dist/bench/fixtures.js +146 -0
  34. package/dist/bench/fixtures.js.map +1 -0
  35. package/dist/bench/judge.d.ts +9 -0
  36. package/dist/bench/judge.d.ts.map +1 -0
  37. package/dist/bench/judge.js +71 -0
  38. package/dist/bench/judge.js.map +1 -0
  39. package/dist/bench/metrics.d.ts +32 -0
  40. package/dist/bench/metrics.d.ts.map +1 -0
  41. package/dist/bench/metrics.js +172 -0
  42. package/dist/bench/metrics.js.map +1 -0
  43. package/dist/bench/prompts.d.ts +17 -0
  44. package/dist/bench/prompts.d.ts.map +1 -0
  45. package/dist/bench/prompts.js +100 -0
  46. package/dist/bench/prompts.js.map +1 -0
  47. package/dist/bench/report.d.ts +43 -0
  48. package/dist/bench/report.d.ts.map +1 -0
  49. package/dist/bench/report.js +74 -0
  50. package/dist/bench/report.js.map +1 -0
  51. package/dist/bench/runner.d.ts +15 -0
  52. package/dist/bench/runner.d.ts.map +1 -0
  53. package/dist/bench/runner.js +26 -0
  54. package/dist/bench/runner.js.map +1 -0
  55. package/dist/bench/toolfork.d.ts +18 -0
  56. package/dist/bench/toolfork.d.ts.map +1 -0
  57. package/dist/bench/toolfork.js +125 -0
  58. package/dist/bench/toolfork.js.map +1 -0
  59. package/dist/box-agent.d.ts +78 -0
  60. package/dist/box-agent.d.ts.map +1 -0
  61. package/dist/box-agent.js +137 -0
  62. package/dist/box-agent.js.map +1 -0
  63. package/dist/box-env.d.ts +26 -0
  64. package/dist/box-env.d.ts.map +1 -0
  65. package/dist/box-env.js +52 -0
  66. package/dist/box-env.js.map +1 -0
  67. package/dist/call.d.ts +23 -0
  68. package/dist/call.d.ts.map +1 -0
  69. package/dist/call.js +45 -0
  70. package/dist/call.js.map +1 -0
  71. package/dist/cloud.d.ts +4917 -0
  72. package/dist/cloud.d.ts.map +1 -0
  73. package/dist/cloud.js +16 -0
  74. package/dist/cloud.js.map +1 -0
  75. package/dist/e2b/index.d.ts +30 -0
  76. package/dist/e2b/index.d.ts.map +1 -0
  77. package/dist/e2b/index.js +273 -0
  78. package/dist/e2b/index.js.map +1 -0
  79. package/dist/egress-approval.d.ts +73 -0
  80. package/dist/egress-approval.d.ts.map +1 -0
  81. package/dist/egress-approval.js +74 -0
  82. package/dist/egress-approval.js.map +1 -0
  83. package/dist/engine.d.ts +188 -0
  84. package/dist/engine.d.ts.map +1 -0
  85. package/dist/engine.js +1507 -0
  86. package/dist/engine.js.map +1 -0
  87. package/dist/fn.d.ts +22 -0
  88. package/dist/fn.d.ts.map +1 -0
  89. package/dist/fn.js +108 -0
  90. package/dist/fn.js.map +1 -0
  91. package/dist/history.d.ts +21 -0
  92. package/dist/history.d.ts.map +1 -0
  93. package/dist/history.js +158 -0
  94. package/dist/history.js.map +1 -0
  95. package/dist/inclient.d.ts +48 -0
  96. package/dist/inclient.d.ts.map +1 -0
  97. package/dist/inclient.js +68 -0
  98. package/dist/inclient.js.map +1 -0
  99. package/dist/index.d.ts +24 -0
  100. package/dist/index.d.ts.map +1 -0
  101. package/dist/index.js +25 -0
  102. package/dist/index.js.map +1 -0
  103. package/dist/interchange.d.ts +17 -0
  104. package/dist/interchange.d.ts.map +1 -0
  105. package/dist/interchange.js +133 -0
  106. package/dist/interchange.js.map +1 -0
  107. package/dist/machine-lifecycle.d.ts +102 -0
  108. package/dist/machine-lifecycle.d.ts.map +1 -0
  109. package/dist/machine-lifecycle.js +360 -0
  110. package/dist/machine-lifecycle.js.map +1 -0
  111. package/dist/manifest.d.ts +42 -0
  112. package/dist/manifest.d.ts.map +1 -0
  113. package/dist/manifest.js +53 -0
  114. package/dist/manifest.js.map +1 -0
  115. package/dist/open.d.ts +45 -0
  116. package/dist/open.d.ts.map +1 -0
  117. package/dist/open.js +245 -0
  118. package/dist/open.js.map +1 -0
  119. package/dist/parked-action.d.ts +51 -0
  120. package/dist/parked-action.d.ts.map +1 -0
  121. package/dist/parked-action.js +29 -0
  122. package/dist/parked-action.js.map +1 -0
  123. package/dist/persistence.d.ts +41 -0
  124. package/dist/persistence.d.ts.map +1 -0
  125. package/dist/persistence.js +86 -0
  126. package/dist/persistence.js.map +1 -0
  127. package/dist/pins.d.ts +231 -0
  128. package/dist/pins.d.ts.map +1 -0
  129. package/dist/pins.js +213 -0
  130. package/dist/pins.js.map +1 -0
  131. package/dist/pipeline.d.ts +142 -0
  132. package/dist/pipeline.d.ts.map +1 -0
  133. package/dist/pipeline.js +1014 -0
  134. package/dist/pipeline.js.map +1 -0
  135. package/dist/prewired-schema.d.ts +16 -0
  136. package/dist/prewired-schema.d.ts.map +1 -0
  137. package/dist/prewired-schema.js +48 -0
  138. package/dist/prewired-schema.js.map +1 -0
  139. package/dist/redaction.d.ts +13 -0
  140. package/dist/redaction.d.ts.map +1 -0
  141. package/dist/redaction.js +67 -0
  142. package/dist/redaction.js.map +1 -0
  143. package/dist/runtime.d.ts +463 -0
  144. package/dist/runtime.d.ts.map +1 -0
  145. package/dist/runtime.js +1715 -0
  146. package/dist/runtime.js.map +1 -0
  147. package/dist/sandbox.d.ts +90 -0
  148. package/dist/sandbox.d.ts.map +1 -0
  149. package/dist/sandbox.js +2 -0
  150. package/dist/sandbox.js.map +1 -0
  151. package/dist/schedules.d.ts +89 -0
  152. package/dist/schedules.d.ts.map +1 -0
  153. package/dist/schedules.js +334 -0
  154. package/dist/schedules.js.map +1 -0
  155. package/dist/secret-exposure.d.ts +55 -0
  156. package/dist/secret-exposure.d.ts.map +1 -0
  157. package/dist/secret-exposure.js +53 -0
  158. package/dist/secret-exposure.js.map +1 -0
  159. package/dist/ship-diff.d.ts +47 -0
  160. package/dist/ship-diff.d.ts.map +1 -0
  161. package/dist/ship-diff.js +39 -0
  162. package/dist/ship-diff.js.map +1 -0
  163. package/dist/testing/fake-box.d.ts +67 -0
  164. package/dist/testing/fake-box.d.ts.map +1 -0
  165. package/dist/testing/fake-box.js +166 -0
  166. package/dist/testing/fake-box.js.map +1 -0
  167. package/dist/testing/fake-sandbox-v2.d.ts +59 -0
  168. package/dist/testing/fake-sandbox-v2.d.ts.map +1 -0
  169. package/dist/testing/fake-sandbox-v2.js +121 -0
  170. package/dist/testing/fake-sandbox-v2.js.map +1 -0
  171. package/dist/testing/fake-sandbox.d.ts +94 -0
  172. package/dist/testing/fake-sandbox.d.ts.map +1 -0
  173. package/dist/testing/fake-sandbox.js +239 -0
  174. package/dist/testing/fake-sandbox.js.map +1 -0
  175. package/dist/testing/guard-fixture.d.ts +19 -0
  176. package/dist/testing/guard-fixture.d.ts.map +1 -0
  177. package/dist/testing/guard-fixture.js +134 -0
  178. package/dist/testing/guard-fixture.js.map +1 -0
  179. package/dist/testing/index.d.ts +8 -0
  180. package/dist/testing/index.d.ts.map +1 -0
  181. package/dist/testing/index.js +8 -0
  182. package/dist/testing/index.js.map +1 -0
  183. package/dist/testing/memory-store.d.ts +5 -0
  184. package/dist/testing/memory-store.d.ts.map +1 -0
  185. package/dist/testing/memory-store.js +4 -0
  186. package/dist/testing/memory-store.js.map +1 -0
  187. package/dist/testing/scripted-model.d.ts +32 -0
  188. package/dist/testing/scripted-model.d.ts.map +1 -0
  189. package/dist/testing/scripted-model.js +112 -0
  190. package/dist/testing/scripted-model.js.map +1 -0
  191. package/dist/testing/seed-app-row.d.ts +4 -0
  192. package/dist/testing/seed-app-row.d.ts.map +1 -0
  193. package/dist/testing/seed-app-row.js +7 -0
  194. package/dist/testing/seed-app-row.js.map +1 -0
  195. package/dist/unified-diff.d.ts +13 -0
  196. package/dist/unified-diff.d.ts.map +1 -0
  197. package/dist/unified-diff.js +127 -0
  198. package/dist/unified-diff.js.map +1 -0
  199. package/dist/version-hash.d.ts +9 -0
  200. package/dist/version-hash.d.ts.map +1 -0
  201. package/dist/version-hash.js +12 -0
  202. package/dist/version-hash.js.map +1 -0
  203. package/package.json +84 -0
@@ -0,0 +1,166 @@
1
+ import { BOX_CONTROL_PORT } from "../box-agent.js";
2
+ /**
3
+ * execution-v2 Wave 3 test substrate — a fake sandbox that models a REAL v2
4
+ * box faithfully: two listeners (the app's $PORT and the harness control port
5
+ * 8811), an injectable in-box agent, a `vendo.json` manifest, POST /fn/<name>
6
+ * handlers the agent installs, env re-injection, and snapshot/resume
7
+ * persistence. It exists so graduation, editApp, schedule ticks, and the
8
+ * prompt-injection floor can be exercised without live e2b — the shared
9
+ * single-listener fakeSandbox stays untouched.
10
+ */
11
+ const encoder = new TextEncoder();
12
+ const decoder = new TextDecoder();
13
+ const snapshots = new Map();
14
+ let nextId = 1;
15
+ let nextSnap = 1;
16
+ class FakeBoxMachine {
17
+ state;
18
+ allowedDomains;
19
+ agent;
20
+ id = `box-${nextId++}`;
21
+ destroyed = false;
22
+ stopped = false;
23
+ /** Task results by id (control-port task store). */
24
+ tasks = new Map();
25
+ constructor(state, allowedDomains, agent) {
26
+ this.state = state;
27
+ this.allowedDomains = allowedDomains;
28
+ this.agent = agent;
29
+ }
30
+ appPort() {
31
+ const port = Number(this.state.env.PORT ?? 8080);
32
+ return Number.isInteger(port) && port > 0 ? port : 8080;
33
+ }
34
+ async request(req) {
35
+ if (this.destroyed || this.stopped)
36
+ throw new Error(`box ${this.id} is not running`);
37
+ const bodyText = req.body === undefined ? "" : typeof req.body === "string" ? req.body : decoder.decode(req.body);
38
+ const port = req.port ?? this.appPort();
39
+ const json = (status, value) => ({
40
+ status,
41
+ headers: { "content-type": "application/json" },
42
+ body: encoder.encode(JSON.stringify(value)),
43
+ });
44
+ if (port === BOX_CONTROL_PORT)
45
+ return this.control(req.method, req.path, bodyText, json);
46
+ if (port === this.appPort())
47
+ return this.app(req.method, req.path, bodyText, json);
48
+ throw new Error(`box ${this.id} has no listener on port ${port}`);
49
+ }
50
+ async control(method, path, bodyText, json) {
51
+ const route = `${method} ${path}`;
52
+ if (route === "GET /agent/health")
53
+ return json(200, { ok: true, harness: "fake-box/1", app: { running: true } });
54
+ if (route === "POST /agent/env") {
55
+ const env = JSON.parse(bodyText).env;
56
+ // Model the real harness (box/harness.mjs): the boundary env file is
57
+ // REPLACED and the app restarts with exactly the injected set — a
58
+ // revoked secret is gone, never merged over.
59
+ this.state.env = { ...env };
60
+ return json(200, { ok: true });
61
+ }
62
+ if (route === "POST /agent/restart-app")
63
+ return json(200, { ok: true });
64
+ if (route === "POST /agent/task") {
65
+ const payload = JSON.parse(bodyText);
66
+ const taskId = `boxtask_${this.id}_${this.tasks.size}`;
67
+ this.tasks.set(taskId, { status: "running" });
68
+ const result = await this.agent({ prompt: payload.prompt, context: payload.context, env: this.state.env, box: this.state });
69
+ this.tasks.set(taskId, { status: "done", result });
70
+ return json(202, { taskId });
71
+ }
72
+ if (method === "GET" && path.startsWith("/agent/task/")) {
73
+ const entry = this.tasks.get(path.slice("/agent/task/".length));
74
+ if (entry === undefined)
75
+ return json(404, { error: "unknown task" });
76
+ return json(200, { status: entry.status, ...(entry.result === undefined ? {} : { result: entry.result }), log: "" });
77
+ }
78
+ return json(404, { error: `unknown control route: ${route}` });
79
+ }
80
+ app(method, path, bodyText, json) {
81
+ if (method === "GET" && path === "/vendo.json") {
82
+ if (this.state.manifest.schedules === undefined && this.state.manifest.egress === undefined) {
83
+ return json(404, { error: "no manifest" });
84
+ }
85
+ return json(200, this.state.manifest);
86
+ }
87
+ // Wave 4 (layer 3) — agent-installed served pages win over the default
88
+ // ok-stub, so tests can prove a real web app is served beside /fn.
89
+ const page = this.state.pages.get(path);
90
+ if (method === "GET" && page !== undefined) {
91
+ return {
92
+ status: 200,
93
+ headers: { "content-type": "text/html; charset=utf-8" },
94
+ body: encoder.encode(page),
95
+ };
96
+ }
97
+ const fnMatch = /^\/fn\/([A-Za-z_][A-Za-z0-9_-]*)$/.exec(path);
98
+ if (method === "POST" && fnMatch?.[1] !== undefined) {
99
+ const handler = this.state.fns.get(fnMatch[1]);
100
+ if (handler === undefined)
101
+ return json(404, { error: { code: "not-found", message: `no fn ${fnMatch[1]}` } });
102
+ const args = (() => { try {
103
+ return JSON.parse(bodyText).args;
104
+ }
105
+ catch {
106
+ return undefined;
107
+ } })();
108
+ try {
109
+ const result = handler(args, this.state.env);
110
+ return json(200, { result });
111
+ }
112
+ catch (error) {
113
+ return json(500, { error: { code: "machine", message: error instanceof Error ? error.message : "fn failed" } });
114
+ }
115
+ }
116
+ return json(200, { ok: true });
117
+ }
118
+ async url(port) {
119
+ if (this.destroyed || this.stopped)
120
+ throw new Error(`box ${this.id} is not running`);
121
+ return `https://${port ?? this.appPort()}-${this.id}.fake-box.test`;
122
+ }
123
+ async snapshot() {
124
+ if (this.destroyed || this.stopped)
125
+ throw new Error(`box ${this.id} is not running`);
126
+ const ref = `fakebox:snap_${nextSnap++}`;
127
+ snapshots.set(ref, {
128
+ env: { ...this.state.env },
129
+ manifest: structuredClone(this.state.manifest),
130
+ fns: new Map(this.state.fns),
131
+ pages: new Map(this.state.pages),
132
+ ...(this.allowedDomains === undefined ? {} : { allowedDomains: [...this.allowedDomains] }),
133
+ });
134
+ return ref;
135
+ }
136
+ async stop() { this.stopped = true; }
137
+ async destroy() { this.destroyed = true; this.stopped = true; }
138
+ }
139
+ export const fakeBoxSandbox = (options = {}) => {
140
+ const machines = [];
141
+ // Default agent: a no-op that reports success but changes nothing.
142
+ const agent = options.agent ?? (() => ({ ok: true, summary: "noop", filesChanged: [], testsRun: 0 }));
143
+ const make = (state, allowedDomains) => {
144
+ const machine = new FakeBoxMachine(state, allowedDomains, agent);
145
+ machines.push(machine);
146
+ return machine;
147
+ };
148
+ return {
149
+ machines,
150
+ async create(spec) {
151
+ return make({ env: { ...spec.env }, manifest: {}, fns: new Map(), pages: new Map() }, spec.allowedDomains);
152
+ },
153
+ async resume(snapshotRef, policy) {
154
+ const snap = snapshots.get(snapshotRef);
155
+ if (snap === undefined)
156
+ throw new Error(`unknown fake-box snapshot: ${snapshotRef}`);
157
+ return make({ env: { ...snap.env }, manifest: structuredClone(snap.manifest), fns: new Map(snap.fns), pages: new Map(snap.pages) }, policy === undefined ? snap.allowedDomains : policy.allowedDomains);
158
+ },
159
+ async destroy(snapshotRef) {
160
+ if (!snapshotRef.startsWith("fakebox:"))
161
+ throw new Error(`not a fake-box ref: ${snapshotRef}`);
162
+ snapshots.delete(snapshotRef);
163
+ },
164
+ };
165
+ };
166
+ //# sourceMappingURL=fake-box.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-box.js","sourceRoot":"","sources":["../../src/testing/fake-box.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,59 @@
1
+ import type { SandboxAdapter, SandboxMachine } from "../sandbox.js";
2
+ interface FakeSnapshotV2 {
3
+ env: Readonly<Record<string, string>>;
4
+ /** The create-time egress allowlist the snapshot carries (like real refs). */
5
+ allowedDomains?: readonly string[];
6
+ template?: string;
7
+ state: ReadonlyMap<string, string>;
8
+ }
9
+ /**
10
+ * Execution-v2 fake machine. Its only observable box state is a key-value map
11
+ * mutated over HTTP (`POST /state/<key>` writes the body, `GET /state/<key>`
12
+ * reads it back), so lifecycle tests can prove a snapshot/resume cycle
13
+ * preserves what ran inside the box.
14
+ */
15
+ export declare class FakeMachineV2 implements SandboxMachine {
16
+ readonly id: string;
17
+ readonly allowedDomains: readonly string[] | undefined;
18
+ readonly template: string | undefined;
19
+ private readonly saveSnapshot;
20
+ stopped: boolean;
21
+ /** True after the live-machine destroy() (distinct from a snapshot-preserving stop). */
22
+ destroyedSelf: boolean;
23
+ /** True after the PROVIDER reaped the machine out from under us (TTL, sweep). */
24
+ reaped: boolean;
25
+ readonly env: Readonly<Record<string, string>>;
26
+ readonly state: Map<string, string>;
27
+ constructor(id: string, env: Record<string, string>, allowedDomains: readonly string[] | undefined, template: string | undefined, state: ReadonlyMap<string, string>, saveSnapshot: (machine: FakeMachineV2) => string);
28
+ request(req: {
29
+ method: string;
30
+ path: string;
31
+ headers?: Record<string, string>;
32
+ body?: Uint8Array | string;
33
+ }): Promise<{
34
+ status: number;
35
+ headers: Record<string, string>;
36
+ body: Uint8Array;
37
+ }>;
38
+ url(port?: number): Promise<string>;
39
+ snapshot(): Promise<string>;
40
+ stop(): Promise<void>;
41
+ /** Live-machine destroy: gone for good; previously taken snapshot refs stay valid. */
42
+ destroy(): Promise<void>;
43
+ /** Simulate the PROVIDER killing the machine (TTL expiry, idle sweep). */
44
+ reap(): void;
45
+ }
46
+ export interface FakeSandboxV2 extends SandboxAdapter {
47
+ /** Every machine this adapter ever booted, in boot order. */
48
+ readonly machines: FakeMachineV2[];
49
+ /** Live provider-side snapshots (destroy removes its ref from here). */
50
+ readonly snapshots: Map<string, FakeSnapshotV2>;
51
+ /** Refs passed to destroy, in call order. */
52
+ readonly destroyed: string[];
53
+ creates: number;
54
+ resumes: number;
55
+ }
56
+ /** In-process SandboxAdapter with inspectable machines, snapshots, and destroys. */
57
+ export declare const fakeSandboxV2: () => FakeSandboxV2;
58
+ export {};
59
+ //# sourceMappingURL=fake-sandbox-v2.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-sandbox-v2.d.ts","sourceRoot":"","sources":["../../src/testing/fake-sandbox-v2.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAcpE,UAAU,cAAc;IACtB,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACtC,8EAA8E;IAC9E,cAAc,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAED;;;;;GAKG;AACH,qBAAa,aAAc,YAAW,cAAc;IAUhD,QAAQ,CAAC,EAAE,EAAE,MAAM;IAEnB,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS;IACtD,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS;IAErC,OAAO,CAAC,QAAQ,CAAC,YAAY;IAd/B,OAAO,UAAS;IAChB,wFAAwF;IACxF,aAAa,UAAS;IACtB,iFAAiF;IACjF,MAAM,UAAS;IACf,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC/C,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAGzB,EAAE,EAAE,MAAM,EACnB,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClB,cAAc,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,EAC7C,QAAQ,EAAE,MAAM,GAAG,SAAS,EACrC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EACjB,YAAY,EAAE,CAAC,OAAO,EAAE,aAAa,KAAK,MAAM;IAM7D,OAAO,CAAC,GAAG,EAAE;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QACjC,IAAI,CAAC,EAAE,UAAU,GAAG,MAAM,CAAC;KAC5B,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC;IAoB5E,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAKnC,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAI3B,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B,sFAAsF;IAChF,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAK9B,0EAA0E;IAC1E,IAAI,IAAI,IAAI;CAGb;AAED,MAAM,WAAW,aAAc,SAAQ,cAAc;IACnD,6DAA6D;IAC7D,QAAQ,CAAC,QAAQ,EAAE,aAAa,EAAE,CAAC;IACnC,wEAAwE;IACxE,QAAQ,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAChD,6CAA6C;IAC7C,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,oFAAoF;AACpF,eAAO,MAAM,aAAa,QAAO,aA4DhC,CAAC"}
@@ -0,0 +1,121 @@
1
+ import { VendoError } from "@vendoai/core";
2
+ const textEncoder = new TextEncoder();
3
+ const textDecoder = new TextDecoder();
4
+ const respond = (status, body) => ({
5
+ status,
6
+ headers: { "content-type": "text/plain; charset=utf-8" },
7
+ body: textEncoder.encode(body),
8
+ });
9
+ /**
10
+ * Execution-v2 fake machine. Its only observable box state is a key-value map
11
+ * mutated over HTTP (`POST /state/<key>` writes the body, `GET /state/<key>`
12
+ * reads it back), so lifecycle tests can prove a snapshot/resume cycle
13
+ * preserves what ran inside the box.
14
+ */
15
+ export class FakeMachineV2 {
16
+ id;
17
+ allowedDomains;
18
+ template;
19
+ saveSnapshot;
20
+ stopped = false;
21
+ /** True after the live-machine destroy() (distinct from a snapshot-preserving stop). */
22
+ destroyedSelf = false;
23
+ /** True after the PROVIDER reaped the machine out from under us (TTL, sweep). */
24
+ reaped = false;
25
+ env;
26
+ state;
27
+ constructor(id, env, allowedDomains, template, state, saveSnapshot) {
28
+ this.id = id;
29
+ this.allowedDomains = allowedDomains;
30
+ this.template = template;
31
+ this.saveSnapshot = saveSnapshot;
32
+ this.env = Object.freeze({ ...env });
33
+ this.state = new Map(state);
34
+ }
35
+ async request(req) {
36
+ // The seam's dead-machine signal (sandbox.ts): provider state gone under a
37
+ // live handle throws VendoError not-found, never an app-level status.
38
+ if (this.reaped)
39
+ throw new VendoError("not-found", `fake v2 machine ${this.id} was reaped by the provider`);
40
+ if (this.stopped)
41
+ throw new Error(`fake v2 machine ${this.id} is stopped`);
42
+ const key = /^\/state\/([A-Za-z0-9_-]+)$/.exec(req.path)?.[1];
43
+ if (key !== undefined) {
44
+ if (req.method.toUpperCase() === "POST") {
45
+ this.state.set(key, typeof req.body === "string" ? req.body : textDecoder.decode(req.body ?? new Uint8Array()));
46
+ return respond(204, "");
47
+ }
48
+ const value = this.state.get(key);
49
+ return value === undefined ? respond(404, "") : respond(200, value);
50
+ }
51
+ return respond(200, "ok");
52
+ }
53
+ async url(port) {
54
+ const target = port ?? Number(this.env.PORT ?? 8080);
55
+ return `https://${target}-${this.id}.fake-v2.test`;
56
+ }
57
+ async snapshot() {
58
+ return this.saveSnapshot(this);
59
+ }
60
+ async stop() {
61
+ this.stopped = true;
62
+ }
63
+ /** Live-machine destroy: gone for good; previously taken snapshot refs stay valid. */
64
+ async destroy() {
65
+ this.stopped = true;
66
+ this.destroyedSelf = true;
67
+ }
68
+ /** Simulate the PROVIDER killing the machine (TTL expiry, idle sweep). */
69
+ reap() {
70
+ this.reaped = true;
71
+ }
72
+ }
73
+ /** In-process SandboxAdapter with inspectable machines, snapshots, and destroys. */
74
+ export const fakeSandboxV2 = () => {
75
+ const machines = [];
76
+ const snapshots = new Map();
77
+ const destroyed = [];
78
+ let nextMachine = 1;
79
+ let nextSnapshot = 1;
80
+ const saveSnapshot = (machine) => {
81
+ const ref = `fake-v2:snap_${nextSnapshot++}`;
82
+ snapshots.set(ref, Object.freeze({
83
+ env: machine.env,
84
+ ...(machine.allowedDomains === undefined ? {} : { allowedDomains: Object.freeze([...machine.allowedDomains]) }),
85
+ ...(machine.template === undefined ? {} : { template: machine.template }),
86
+ state: new Map(machine.state),
87
+ }));
88
+ return ref;
89
+ };
90
+ const boot = (env, allowedDomains, template, state) => {
91
+ const machine = new FakeMachineV2(`fake-machine-${nextMachine++}`, env, allowedDomains === undefined ? undefined : Object.freeze([...allowedDomains]), template, state, saveSnapshot);
92
+ machines.push(machine);
93
+ return machine;
94
+ };
95
+ const adapter = {
96
+ machines,
97
+ snapshots,
98
+ destroyed,
99
+ creates: 0,
100
+ resumes: 0,
101
+ async create(spec) {
102
+ adapter.creates += 1;
103
+ return boot(spec.env, spec.allowedDomains, spec.template, new Map());
104
+ },
105
+ async resume(snapshotRef, policy) {
106
+ adapter.resumes += 1;
107
+ const snapshot = snapshots.get(snapshotRef);
108
+ if (snapshot === undefined)
109
+ throw new Error(`unknown fake v2 snapshot: ${snapshotRef}`);
110
+ // Lane E — a passed policy replaces the snapshot-time allowlist (seam rule).
111
+ const allowedDomains = policy === undefined ? snapshot.allowedDomains : policy.allowedDomains;
112
+ return boot({ ...snapshot.env }, allowedDomains, snapshot.template, snapshot.state);
113
+ },
114
+ async destroy(snapshotRef) {
115
+ destroyed.push(snapshotRef);
116
+ snapshots.delete(snapshotRef);
117
+ },
118
+ };
119
+ return adapter;
120
+ };
121
+ //# sourceMappingURL=fake-sandbox-v2.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-sandbox-v2.js","sourceRoot":"","sources":["../../src/testing/fake-sandbox-v2.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,94 @@
1
+ import type { SandboxAdapter, SandboxMachine } from "../sandbox.js";
2
+ export interface MachineRequest {
3
+ method: string;
4
+ path: string;
5
+ port?: number;
6
+ headers?: Record<string, string>;
7
+ body?: Uint8Array | string;
8
+ }
9
+ export interface MachineResponse {
10
+ status: number;
11
+ headers: Record<string, string>;
12
+ body: Uint8Array | string;
13
+ }
14
+ /** The box's boundary as the fake's in-process app handler sees it. */
15
+ export interface MachineAppContext {
16
+ env: Readonly<Record<string, string>>;
17
+ allowedDomains: readonly string[] | undefined;
18
+ port: number;
19
+ }
20
+ export type MachineApp = (request: MachineRequest, ctx: MachineAppContext) => MachineResponse | Promise<MachineResponse>;
21
+ export interface FakeExecResult {
22
+ code: number;
23
+ stdout: string;
24
+ stderr: string;
25
+ }
26
+ export interface FakeExecCall {
27
+ cmd: string;
28
+ opts?: {
29
+ cwd?: string;
30
+ timeoutMs?: number;
31
+ };
32
+ }
33
+ /** The v2 create spec (the seam's SandboxAdapter.create parameter, kept local
34
+ for the fake's internal signatures). */
35
+ export interface FakeCreateSpec {
36
+ template?: string;
37
+ env: Record<string, string>;
38
+ allowedDomains?: string[];
39
+ }
40
+ /** Test machine with deterministic I/O and inspectable state. */
41
+ export declare class FakeSandboxMachine implements SandboxMachine {
42
+ readonly id: string;
43
+ readonly allowedDomains: readonly string[] | undefined;
44
+ readonly template: string | undefined;
45
+ private readonly saveSnapshot;
46
+ readonly requests: MachineRequest[];
47
+ readonly commands: FakeExecCall[];
48
+ readonly execResults: FakeExecResult[];
49
+ readonly fileContents: Map<string, Uint8Array>;
50
+ readonly env: Record<string, string>;
51
+ readonly port: number;
52
+ /** v2 sleep flag; also true once destroyed. Writable for test scripting. */
53
+ stopped: boolean;
54
+ /** v2 gone-for-good flag. */
55
+ destroyed: boolean;
56
+ app: MachineApp | undefined;
57
+ constructor(id: string, env: Record<string, string>, allowedDomains: readonly string[] | undefined, template: string | undefined, files: ReadonlyMap<string, Uint8Array>, app: MachineApp | undefined, saveSnapshot: (machine: FakeSandboxMachine) => string);
58
+ private appContext;
59
+ private ensureRunning;
60
+ readonly files: {
61
+ read: (path: string) => Promise<Uint8Array>;
62
+ write: (path: string, bytes: Uint8Array | string) => Promise<void>;
63
+ list: (dir: string) => Promise<string[]>;
64
+ };
65
+ request(request: MachineRequest): Promise<{
66
+ status: number;
67
+ headers: Record<string, string>;
68
+ body: Uint8Array;
69
+ }>;
70
+ exec(cmd: string, opts?: {
71
+ cwd?: string;
72
+ timeoutMs?: number;
73
+ }): Promise<FakeExecResult>;
74
+ programExec(...results: FakeExecResult[]): void;
75
+ setApp(app: MachineApp): void;
76
+ snapshot(): Promise<string>;
77
+ screenshot(): Promise<Uint8Array>;
78
+ url(port?: number): Promise<string>;
79
+ stop(): Promise<void>;
80
+ destroy(): Promise<void>;
81
+ }
82
+ export interface FakeSandboxAdapter extends SandboxAdapter {
83
+ readonly machines: Map<string, FakeSandboxMachine>;
84
+ create(spec: FakeCreateSpec): Promise<FakeSandboxMachine>;
85
+ resume(snapshotRef: string, policy?: {
86
+ allowedDomains: string[] | undefined;
87
+ }): Promise<FakeSandboxMachine>;
88
+ setApp(app: MachineApp): void;
89
+ }
90
+ /** Create an in-process sandbox adapter whose requests dispatch to a machine app handler. */
91
+ export declare const fakeSandbox: (options?: {
92
+ app?: MachineApp;
93
+ }) => FakeSandboxAdapter;
94
+ //# sourceMappingURL=fake-sandbox.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fake-sandbox.d.ts","sourceRoot":"","sources":["../../src/testing/fake-sandbox.ts"],"names":[],"mappings":"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"}