@fungi.computer/computer 0.1.0 → 0.2.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 (39) hide show
  1. package/README.md +38 -10
  2. package/dist/computer-backends.d.ts +0 -1
  3. package/dist/computer-backends.js +0 -3
  4. package/dist/exec-output.d.ts +13 -0
  5. package/dist/exec-output.js +24 -0
  6. package/dist/execution-lifecycle.d.ts +35 -0
  7. package/dist/execution-lifecycle.js +78 -0
  8. package/dist/files-patch.d.ts +12 -4
  9. package/dist/files-patch.js +8 -14
  10. package/dist/files.d.ts +65 -15
  11. package/dist/files.js +152 -31
  12. package/dist/fleet/index.d.ts +1 -1
  13. package/dist/fleet/index.js +1 -1
  14. package/dist/fleet/inventory-wire.d.ts +6 -2
  15. package/dist/fleet/inventory-wire.js +7 -2
  16. package/dist/fleet/lifecycle.d.ts +7 -1
  17. package/dist/fleet/lifecycle.js +22 -0
  18. package/dist/fleet/wire.d.ts +12 -12
  19. package/dist/fleet/wire.js +1 -1
  20. package/dist/index.d.ts +33 -15
  21. package/dist/index.js +422 -105
  22. package/dist/internet-access.d.ts +4 -0
  23. package/dist/internet-access.js +14 -0
  24. package/dist/local-backend-replay.d.ts +10 -0
  25. package/dist/local-backend-replay.js +43 -0
  26. package/dist/local-backend.d.ts +2 -1
  27. package/dist/local-backend.js +4 -4
  28. package/dist/on-box-vm.d.ts +11 -0
  29. package/dist/on-box-vm.js +36 -13
  30. package/dist/operation-record.d.ts +1 -1
  31. package/dist/operation-record.js +1 -1
  32. package/dist/process-inventory.d.ts +3 -1
  33. package/dist/process-inventory.js +2 -2
  34. package/dist/team-candidate-builder.mjs +8375 -334
  35. package/package.json +17 -24
  36. package/dist/light-shell.d.ts +0 -44
  37. package/dist/light-shell.js +0 -376
  38. package/dist/operation-contract.d.ts +0 -456
  39. package/dist/operation-contract.js +0 -450
package/dist/files.js CHANGED
@@ -1,4 +1,8 @@
1
- import { replaceOutputSchema, } from "./operation-contract.js";
1
+ import { WorkspaceFileStore } from "@fungi.computer/cloudflare-computer/tools";
2
+ import { posix } from "node:path";
3
+ import { SearchVisibility } from "@fungi.computer/knapsack/files-search";
4
+ import { imageReadResult, imageSniffBytes, imageTooLargeMessage, maximumImageBytes, sniffImageMimeType, } from "@fungi.computer/knapsack/files-read";
5
+ import { replaceOutputSchema, } from "@fungi.computer/computer-contract";
2
6
  const utf8 = new TextEncoder();
3
7
  function entryType(entry) {
4
8
  if (entry.isSymbolicLink)
@@ -52,7 +56,7 @@ export function readBoundedWorkspaceText(provider, path, maximumBytes) {
52
56
  }
53
57
  /** Adapt native Workspace.fs at the one real file boundary. */
54
58
  export function createWorkspaceFilesPort(workspace, owner) {
55
- return Object.freeze({
59
+ const port = {
56
60
  async read(input) {
57
61
  const stat = await workspace.fs.stat(input.path);
58
62
  if (!stat.isFile)
@@ -69,10 +73,22 @@ export function createWorkspaceFilesPort(workspace, owner) {
69
73
  truncated: false,
70
74
  };
71
75
  }
72
- const pageBytes = await readBytes(workspace, input.path, input.offset, Math.min(input.limit, stat.size - input.offset));
73
- if (pageBytes.byteLength === 0) {
76
+ // The first read covers the sniff window whatever the caller's limit.
77
+ const windowBytes = await readBytes(workspace, input.path, input.offset, Math.min(input.offset === 0
78
+ ? Math.max(input.limit, imageSniffBytes)
79
+ : input.limit, stat.size - input.offset));
80
+ if (windowBytes.byteLength === 0) {
74
81
  throw new Error(`Files path changed during read: ${input.path}`);
75
82
  }
83
+ const mimeType = input.offset === 0 ? sniffImageMimeType(windowBytes) : undefined;
84
+ if (mimeType !== undefined) {
85
+ if (stat.size > maximumImageBytes)
86
+ throw new Error(imageTooLargeMessage(input.path, stat.size, maximumImageBytes));
87
+ return imageReadResult(input.path, mimeType, windowBytes.byteLength === stat.size
88
+ ? windowBytes
89
+ : await readBytes(workspace, input.path, 0, stat.size));
90
+ }
91
+ const pageBytes = windowBytes.subarray(0, input.limit);
76
92
  const page = decodeUtf8Page(pageBytes, input.path, input.offset + pageBytes.byteLength < stat.size);
77
93
  const nextOffset = input.offset + page.byteLength;
78
94
  return {
@@ -83,54 +99,159 @@ export function createWorkspaceFilesPort(workspace, owner) {
83
99
  truncated: nextOffset < stat.size,
84
100
  };
85
101
  },
86
- async list(input) {
87
- const rows = await workspace.fs.readdir(input.path, {
88
- limit: input.limit + 1,
89
- });
90
- const entries = rows.slice(0, input.limit).map((entry) => {
91
- const path = childPath(input.path, entry.name);
92
- return {
93
- path,
94
- name: entry.name,
95
- type: entryType(entry),
96
- size: entry.size,
97
- modifiedAt: entry.mtime,
98
- };
99
- });
102
+ async list(input, context) {
103
+ const output = await searchWorkspaceDirectory(workspace, { ...input, offset: 0 }, context?.signal);
100
104
  return {
101
105
  path: input.path,
102
- entries,
103
- truncated: rows.length > input.limit,
106
+ ...output,
107
+ results: output.results.map((entry) => ({
108
+ path: entry.path,
109
+ type: entryType(entry),
110
+ })),
104
111
  };
105
112
  },
106
- async glob(input) {
107
- const rows = await workspace.fs.find(input.path, input.pattern, {
108
- limit: input.limit + 1,
109
- });
113
+ async glob(input, context) {
114
+ const output = await visibleSearch(workspace, workspacePath(input.path), input.limit, (options) => workspace.fs.find(workspacePath(input.path), input.pattern, options), (entry) => entry.type === "dir", context?.signal);
110
115
  return {
111
116
  path: input.path,
112
- matches: rows.slice(0, input.limit).map((entry) => entry.path),
113
- truncated: rows.length > input.limit,
117
+ ...output,
118
+ results: output.results.map((row) => ({
119
+ path: row.path,
120
+ type: row.type === "dir" ? "directory" : "file",
121
+ })),
114
122
  };
115
123
  },
116
- async grep(input) {
117
- const rows = await workspace.fs.grep(input.pattern, input.path, {
124
+ async grep(input, context) {
125
+ const options = {
118
126
  regex: input.regex,
119
127
  ignoreCase: input.ignoreCase,
120
128
  limit: input.limit + 1,
121
- });
129
+ };
130
+ if (input.include !== undefined)
131
+ options.include = input.include;
132
+ const output = await visibleSearch(workspace, workspacePath(input.path), input.limit, (page) => workspace.fs.grep(input.pattern, workspacePath(input.path), {
133
+ ...options,
134
+ ...page,
135
+ }), () => false, context?.signal);
122
136
  return {
123
137
  path: input.path,
124
- matches: rows.slice(0, input.limit).map((row) => ({
138
+ ...output,
139
+ results: output.results.map((row) => ({
125
140
  path: row.path,
126
141
  line: row.line,
127
142
  text: row.text,
128
143
  })),
129
- truncated: rows.length > input.limit,
130
144
  };
131
145
  },
132
146
  async replace(input) {
133
147
  return replaceOutputSchema.parse(await owner.replaceFileIfUnchanged(input));
134
148
  },
149
+ };
150
+ return Object.freeze({
151
+ ...port,
152
+ // The Computer REST contract keeps its own path and content searches for
153
+ // Apps and Hub routes; its matches/boolean results are not Agent results.
154
+ rest: Object.freeze({
155
+ list: (input) => listWorkspaceFiles(workspace, input),
156
+ async glob(input) {
157
+ const output = await port.glob(input);
158
+ return {
159
+ path: input.path,
160
+ matches: output.results.map((entry) => entry.path),
161
+ truncated: output.truncated !== null,
162
+ };
163
+ },
164
+ async grep(input) {
165
+ const output = await port.grep(input);
166
+ return {
167
+ path: input.path,
168
+ matches: output.results,
169
+ truncated: output.truncated !== null,
170
+ };
171
+ },
172
+ }),
173
+ });
174
+ }
175
+ function searchWorkspaceDirectory(workspace, input, signal) {
176
+ const path = workspacePath(input.path);
177
+ return visibleSearch(workspace, path, input.limit, async (options) => (await workspace.fs.readdir(path, options)).map((entry) => ({
178
+ ...entry,
179
+ path: childPath(path, entry.name),
180
+ })), (entry) => entry.isDirectory, signal, input.offset);
181
+ }
182
+ /** Shared REST listing: offsets count visible entries, never ignored candidates. */
183
+ export async function listWorkspaceFiles(workspace, input) {
184
+ const output = await searchWorkspaceDirectory(workspace, input);
185
+ // The existing list wire has no scan-reason field. Do not disguise an
186
+ // exhausted scan as an empty finished page or a fabricated next offset.
187
+ if (output.truncated === "scan")
188
+ throw new Error("Files listing reached the search scan bound; narrow path");
189
+ return {
190
+ path: input.path,
191
+ entries: output.results.map((entry) => ({
192
+ name: entry.name,
193
+ size: entry.size,
194
+ modifiedAt: entry.mtime,
195
+ type: entryType(entry),
196
+ })),
197
+ nextOffset: output.truncated === null ? null : input.offset + output.results.length,
198
+ };
199
+ }
200
+ /** Computer wire paths are absolute within its Workspace, even for relative Files inputs. */
201
+ function workspacePath(path) {
202
+ if (path === ".")
203
+ return "/";
204
+ return path.startsWith("/") ? path : `/${path}`;
205
+ }
206
+ /** Storage adapter only; shared Files policy owns visibility and grammar. */
207
+ function workspaceSearchVisibility(workspace) {
208
+ const store = new WorkspaceFileStore(workspace);
209
+ let bytes = 0;
210
+ return new SearchVisibility(async (directory) => {
211
+ const path = posix.join("/", directory, ".gitignore");
212
+ const stat = await store.stat(path);
213
+ if (stat !== null) {
214
+ // Match Local's bounded text reads; never silently omit unreadable rules.
215
+ if (stat.size > 128 * 1_024 || bytes + stat.size > 64 * 1_024 * 1_024)
216
+ throw new Error(`Files ignore rules exceed the search byte bound: ${path}`);
217
+ bytes += stat.size;
218
+ return decodeUtf8(await readBytes(workspace, path, 0, stat.size), path);
219
+ }
220
+ return undefined;
135
221
  });
136
222
  }
223
+ function searchRelativePath(path) {
224
+ return posix.relative("/", posix.resolve("/", path));
225
+ }
226
+ /** Page the SDK's traversal; filtering must not spend the visible-result limit. */
227
+ async function visibleSearch(workspace, root, limit, page, isDirectory, signal, visibleOffset = 0) {
228
+ const rules = workspaceSearchVisibility(workspace);
229
+ const results = [];
230
+ signal?.throwIfAborted();
231
+ const metadata = await workspace.fs.stat(root);
232
+ if (!(await rules.visible(searchRelativePath(root), metadata.isDirectory)))
233
+ return { results, truncated: null };
234
+ const maximumCandidates = 50_000;
235
+ let offset = 0;
236
+ while (offset < maximumCandidates) {
237
+ signal?.throwIfAborted();
238
+ const count = Math.min(offset === 0 ? limit + 1 : Math.max(128, limit + 1), maximumCandidates - offset);
239
+ const rows = await page(offset === 0 ? { limit: count } : { limit: count, offset });
240
+ for (const row of rows) {
241
+ signal?.throwIfAborted();
242
+ if (!(await rules.visible(searchRelativePath(row.path), isDirectory(row))))
243
+ continue;
244
+ if (visibleOffset > 0) {
245
+ visibleOffset--;
246
+ continue;
247
+ }
248
+ if (results.length === limit)
249
+ return { results, truncated: "limit" };
250
+ results.push(row);
251
+ }
252
+ if (rows.length < count)
253
+ return { results, truncated: null };
254
+ offset += rows.length;
255
+ }
256
+ return { results, truncated: "scan" };
257
+ }
@@ -5,7 +5,7 @@ export { computerActionSchema, computerProvenanceSchema, computerGrantSchema, co
5
5
  export { ComputerRuntimeUsage } from "./runtime-usage.js";
6
6
  export { computerUsageIntervalSchema, type ComputerUsageInterval, } from "./wire.js";
7
7
  export { createFleetInventory } from "./inventory.js";
8
- export { ComputerInventoryError, type FleetActor, type FleetComputer, } from "./inventory-wire.js";
8
+ export { ComputerInventoryError, computerCreateRequestSchema, computerPageSchema, type ComputerCreateRequest, type ComputerPage, type FleetActor, type FleetComputer, } from "./inventory-wire.js";
9
9
  export { createFleetSlots } from "./slots.js";
10
10
  export { FleetLifecycle, FleetGrantRefused, type FleetLifecyclePorts, type FleetLifecycleFact, } from "./lifecycle.js";
11
11
  export { createFleetComputers } from "./computers.js";
@@ -5,7 +5,7 @@ export { computerActionSchema, computerProvenanceSchema, computerGrantSchema, co
5
5
  export { ComputerRuntimeUsage } from "./runtime-usage.js";
6
6
  export { computerUsageIntervalSchema, } from "./wire.js";
7
7
  export { createFleetInventory } from "./inventory.js";
8
- export { ComputerInventoryError, } from "./inventory-wire.js";
8
+ export { ComputerInventoryError, computerCreateRequestSchema, computerPageSchema, } from "./inventory-wire.js";
9
9
  export { createFleetSlots } from "./slots.js";
10
10
  export { FleetLifecycle, FleetGrantRefused, } from "./lifecycle.js";
11
11
  export { createFleetComputers } from "./computers.js";
@@ -12,15 +12,19 @@ export type FleetComputer = Readonly<{
12
12
  updatedAt: number;
13
13
  }>;
14
14
  /** A durable create receipt binds the complete request to its actor. */
15
+ export declare const computerCreateRequestSchema: z.ZodObject<{
16
+ name: z.ZodOptional<z.ZodString>;
17
+ requestId: z.ZodString;
18
+ }, z.core.$strict>;
15
19
  export type ComputerCreateRequest = Readonly<{
16
20
  name?: string | undefined;
17
21
  requestId: string;
18
22
  }>;
19
23
  /** Inventory pages retain stable ordering and a bounded response. */
20
- export declare const computerPageSchema: z.ZodLazy<z.ZodObject<{
24
+ export declare const computerPageSchema: z.ZodObject<{
21
25
  limit: z.ZodDefault<z.ZodNumber>;
22
26
  offset: z.ZodDefault<z.ZodNumber>;
23
- }, z.core.$strict>>;
27
+ }, z.core.$strict>;
24
28
  export type ComputerPage = z.input<typeof computerPageSchema>;
25
29
  /** Inventory failures, independent of a host's public error mapping. */
26
30
  export declare class ComputerInventoryError extends Error {
@@ -1,9 +1,14 @@
1
1
  import { z } from "zod";
2
+ /** A durable create receipt binds the complete request to its actor. */
3
+ export const computerCreateRequestSchema = z.strictObject({
4
+ name: z.string().min(1).max(256).optional(),
5
+ requestId: z.string().min(1).max(256),
6
+ });
2
7
  /** Inventory pages retain stable ordering and a bounded response. */
3
- export const computerPageSchema = z.lazy(() => z.strictObject({
8
+ export const computerPageSchema = z.strictObject({
4
9
  limit: z.number().int().min(1).max(100).default(100),
5
10
  offset: z.number().int().nonnegative().default(0),
6
- }));
11
+ });
7
12
  /** Inventory failures, independent of a host's public error mapping. */
8
13
  export class ComputerInventoryError extends Error {
9
14
  code;
@@ -53,10 +53,16 @@ export declare class FleetLifecycle {
53
53
  readonly usage: ComputerRuntimeUsage;
54
54
  constructor(ports: FleetLifecyclePorts);
55
55
  get recycleRuntimeId(): string | undefined;
56
+ /** A successful stop cannot race an admitted boot or in-flight operation. */
57
+ get hasPendingOperations(): boolean;
56
58
  takeFacts(): FleetLifecycleFact[];
57
59
  private diagnostic;
58
60
  /** Keep pending starts visible while the host obtains admission and capacity. */
59
- beginHostedStart(): () => void;
61
+ private beginHostedStart;
62
+ /** Start the selected hosted backend under the host's admission and slot policy. */
63
+ startHostedComputer(admitted: (backing: HostedBacking, run: () => Promise<void>) => Promise<void>): Promise<{
64
+ state: "running";
65
+ }>;
60
66
  /** Read liveness without waking a sleeping backend. Queue state wins over booting. */
61
67
  readComputerState(): Promise<{
62
68
  state: "queued";
@@ -40,6 +40,12 @@ export class FleetLifecycle {
40
40
  get recycleRuntimeId() {
41
41
  return this.#recycleRuntimeId;
42
42
  }
43
+ /** A successful stop cannot race an admitted boot or in-flight operation. */
44
+ get hasPendingOperations() {
45
+ return (this.#hostedOperations > 0 ||
46
+ this.#startingHosted > 0 ||
47
+ this.#recycling !== undefined);
48
+ }
43
49
  takeFacts() {
44
50
  const facts = this.#facts;
45
51
  this.#facts = [];
@@ -55,6 +61,22 @@ export class FleetLifecycle {
55
61
  this.#startingHosted--;
56
62
  };
57
63
  }
64
+ /** Start the selected hosted backend under the host's admission and slot policy. */
65
+ async startHostedComputer(admitted) {
66
+ const hosted = this.ports.backend.requireHostedRoute();
67
+ const finish = this.beginHostedStart();
68
+ try {
69
+ await admitted(hosted.backing, async () => {
70
+ await this.ports.backend.workspace().push(hosted.id);
71
+ });
72
+ if (!(await this.ports.backend.containerRunning(hosted.backing)))
73
+ throw new Error("Hosted Computer disconnected while starting");
74
+ return { state: "running" };
75
+ }
76
+ finally {
77
+ finish();
78
+ }
79
+ }
58
80
  /** Read liveness without waking a sleeping backend. Queue state wins over booting. */
59
81
  async readComputerState() {
60
82
  const backends = await this.readAttachedBackends();
@@ -5,6 +5,12 @@ export declare const computerActionSchema: z.ZodEnum<{
5
5
  exec: "exec";
6
6
  start: "start";
7
7
  delete: "delete";
8
+ mkdir: "mkdir";
9
+ backing: "backing";
10
+ bash: "bash";
11
+ exposePort: "exposePort";
12
+ listPorts: "listPorts";
13
+ unexposePort: "unexposePort";
8
14
  "files.read": "files.read";
9
15
  "files.readBytes": "files.readBytes";
10
16
  "files.write": "files.write";
@@ -14,12 +20,6 @@ export declare const computerActionSchema: z.ZodEnum<{
14
20
  "files.grep": "files.grep";
15
21
  "files.edit": "files.edit";
16
22
  "files.patch": "files.patch";
17
- mkdir: "mkdir";
18
- bash: "bash";
19
- backing: "backing";
20
- exposePort: "exposePort";
21
- listPorts: "listPorts";
22
- unexposePort: "unexposePort";
23
23
  terminal: "terminal";
24
24
  stop: "stop";
25
25
  processStart: "processStart";
@@ -40,6 +40,12 @@ export declare const computerGrantSchema: z.ZodObject<{
40
40
  exec: "exec";
41
41
  start: "start";
42
42
  delete: "delete";
43
+ mkdir: "mkdir";
44
+ backing: "backing";
45
+ bash: "bash";
46
+ exposePort: "exposePort";
47
+ listPorts: "listPorts";
48
+ unexposePort: "unexposePort";
43
49
  "files.read": "files.read";
44
50
  "files.readBytes": "files.readBytes";
45
51
  "files.write": "files.write";
@@ -49,12 +55,6 @@ export declare const computerGrantSchema: z.ZodObject<{
49
55
  "files.grep": "files.grep";
50
56
  "files.edit": "files.edit";
51
57
  "files.patch": "files.patch";
52
- mkdir: "mkdir";
53
- bash: "bash";
54
- backing: "backing";
55
- exposePort: "exposePort";
56
- listPorts: "listPorts";
57
- unexposePort: "unexposePort";
58
58
  terminal: "terminal";
59
59
  stop: "stop";
60
60
  processStart: "processStart";
@@ -1,5 +1,5 @@
1
1
  import { z } from "zod";
2
- import { computerOperationSchema, computerValueSchema, pathSchema, } from "../operation-contract.js";
2
+ import { computerOperationSchema, computerValueSchema, pathSchema, } from "@fungi.computer/computer-contract";
3
3
  import { attachedBackendId, hostedBackingSchema, localBackendSchema, } from "../computer-backends.js";
4
4
  /** Operations the host may admit on one Computer. */
5
5
  export const computerActionSchema = z.enum([
package/dist/index.d.ts CHANGED
@@ -1,10 +1,11 @@
1
+ export { createLocalBackendReplayStore } from "./local-backend-replay.js";
1
2
  import { Workspace, WorkspaceProxy, WorkspaceServiceProxy, type WorkspaceStubHost } from "@fungi.computer/cloudflare-computer";
2
3
  import { type WorkerShellBackendOptions } from "@fungi.computer/cloudflare-computer/backends/worker-shell";
3
4
  import { type IWorkspaceContainerAPI } from "@fungi.computer/cloudflare-computer/backends/container";
4
5
  import { DurableObject } from "cloudflare:workers";
5
6
  import type { FilesPort } from "@fungi.computer/knapsack";
6
7
  import { z } from "zod";
7
- import { type ComputerExecutionBudget, type ComputerExecRequest, type ComputerOperationResult, type ComputerFileReadInput, type ComputerFileByteReadInput, type ComputerFileReplacement, type ComputerFileReplacementResult, type ComputerValue, writeInputSchema, writeOutputSchema, type ComputerProcess } from "./operation-contract.js";
8
+ import { type ComputerExecutionBudget, type ComputerExecutionHostHooks, type ComputerExecRequest, type ComputerOperationResult, type ComputerFileReadInput, type ComputerFileByteReadInput, type ComputerFileReplacement, type ComputerFileReplacementResult, type ComputerValue, writeInputSchema, writeOutputSchema, type ComputerProcess } from "@fungi.computer/computer-contract";
8
9
  import { createWorkspaceFilesPort } from "./files.js";
9
10
  import { OnBoxVmContainerHost, type OnBoxVmEnv, type OnBoxVmPlacement } from "./on-box-vm.js";
10
11
  import { type AttachedBackend, type AttachedBackendView, type BackendNeed, type BackendRoute, type ContainerRuntimeStart, type HostedBacking } from "./computer-backends.js";
@@ -89,7 +90,7 @@ declare class ContainerComputer extends ContainerComputerBase {
89
90
  * The hosted backend that terminals, processes and ports use: the first in
90
91
  * the default order, or none when only local machines are attached.
91
92
  */
92
- protected hostedRoute(): Readonly<{
93
+ protected hostedRoute(backend?: string): Readonly<{
93
94
  id: string;
94
95
  backing: HostedBacking;
95
96
  }> | undefined;
@@ -114,9 +115,8 @@ declare class ContainerComputer extends ContainerComputerBase {
114
115
  protected workspace(): Workspace;
115
116
  /**
116
117
  * The current Workspace once its mount index is ready and its guest mount
117
- * root exists. Every backend mounts `/workspace`, so a host write there
118
- * (such as a Workflow step's one-shot Git credential file) must not depend
119
- * on a guest having booted first.
118
+ * root exists. Every backend mounts `/workspace`, so an ordinary host file
119
+ * write there must not depend on a guest having booted first.
120
120
  */
121
121
  protected readyWorkspace(): Promise<Workspace>;
122
122
  /** `getWorkspace(stub)` reaches the current generation through this door. */
@@ -132,6 +132,16 @@ declare class ContainerComputer extends ContainerComputerBase {
132
132
  /** One upstream Cloudflare Workspace that advertises and runs its capabilities. */
133
133
  export declare class ComputerDO extends ContainerComputer {
134
134
  #private;
135
+ constructor(ctx: DurableObjectState, env: ComputerEnv);
136
+ /** Host-admitted settings write; egress reads the current durable value. */
137
+ internetAccess(enabled?: boolean): boolean;
138
+ /** Ordinary Computers have no credential host; resource hosts override it. */
139
+ protected executionHooks(): ComputerExecutionHostHooks | undefined;
140
+ /**
141
+ * Admission observes the actual native subscriber, never App completion,
142
+ * output silence, an accepted signal or this isolate's warm state.
143
+ */
144
+ executionIsLive(invocationId: string): Promise<boolean>;
135
145
  /** Persist the bounded set of ports admitted for preview on this Computer. */
136
146
  exposePort(input: {
137
147
  port: number;
@@ -201,17 +211,25 @@ export declare class ComputerDO extends ContainerComputer {
201
211
  protected applyPatchAfterAcceptance(input: {
202
212
  patch: string;
203
213
  }, accept: () => void): Promise<{
204
- status: "completed" | "failed" | "cancelled";
214
+ status: "failed" | "completed" | "cancelled";
205
215
  exitCode: number;
206
216
  stdout: string;
207
217
  stderr: string;
208
- truncated: boolean;
218
+ truncated: false | {
219
+ stream: "stdout" | "stderr";
220
+ keptBytes: number;
221
+ totalBytes: number;
222
+ }[];
209
223
  } | {
210
- status: "completed" | "failed" | "cancelled";
224
+ status: "failed" | "completed" | "cancelled";
211
225
  exitCode: number;
212
226
  stdout: string;
213
227
  stderr: string;
214
- truncated: boolean;
228
+ truncated: false | {
229
+ stream: "stdout" | "stderr";
230
+ keptBytes: number;
231
+ totalBytes: number;
232
+ }[];
215
233
  error: {
216
234
  kind: "mismatch";
217
235
  };
@@ -220,14 +238,15 @@ export declare class ComputerDO extends ContainerComputer {
220
238
  protected writeTextAfterAcceptance(input: z.output<typeof writeInputSchema>, accept: () => void): Promise<z.output<typeof writeOutputSchema>>;
221
239
  call(capabilityId: ComputerValue, input: ComputerValue): Promise<ComputerValue>;
222
240
  /** Resource hosts may accept authority once the Workspace is ready to dispatch. */
223
- protected callAfterAcceptance(capabilityId: ComputerValue, input: ComputerValue, accept: () => void): Promise<ComputerValue>;
241
+ protected callAfterAcceptance(capabilityId: ComputerValue, input: ComputerValue, accept: () => void, executionContext?: ComputerValue): Promise<ComputerValue>;
224
242
  /**
225
243
  * Execute a host request once, after the host accepts current authority.
226
244
  * `exec` runs on the Workspace's built-in Worker shell unless it names an
227
245
  * attached backend; `bash` always runs on an attached backend, the named one
228
- * or the first available in the default order.
246
+ * or the first available in the default order. Host-only `hosted` execution
247
+ * excludes local backends, including an explicitly named local backend.
229
248
  */
230
- protected executeOperationAfterAcceptance(input: ComputerExecRequest, accept: () => void, kind: "exec" | "bash", budget?: ComputerExecutionBudget, signal?: AbortSignal): Promise<ComputerOperationResult>;
249
+ protected executeOperationAfterAcceptance(input: ComputerExecRequest, accept: () => void, kind: "exec" | "bash" | "hosted", budget?: ComputerExecutionBudget, signal?: AbortSignal, executionContext?: ComputerValue): Promise<ComputerOperationResult>;
231
250
  /**
232
251
  * Run one command on a routed backend. Owners admit and meter hosted
233
252
  * backends here; a member's own machine is neither reserved nor metered.
@@ -238,7 +257,7 @@ export declare class ComputerDO extends ContainerComputer {
238
257
  /** Start one long-running container process with a durable identity. */
239
258
  startProcess(input: ComputerValue): Promise<ComputerProcess>;
240
259
  /** The host accepts authority when the running slot is reserved. */
241
- protected startProcessAfterAcceptance(input: ComputerValue, accept: () => void): Promise<ComputerProcess>;
260
+ protected startProcessAfterAcceptance(input: ComputerValue, accept: () => void, executionContext?: ComputerValue): Promise<ComputerProcess>;
242
261
  /** List this Computer's processes, reconciling live ones with computerd. */
243
262
  listProcesses(): Promise<{
244
263
  processes: ComputerProcess[];
@@ -270,13 +289,12 @@ export declare class ComputerDO extends ContainerComputer {
270
289
  protected replaceFileIfUnchangedAfterAcceptance(input: ComputerFileReplacement, accept: () => void): Promise<ComputerFileReplacementResult>;
271
290
  }
272
291
  export { WorkspaceProxy, WorkspaceServiceProxy };
273
- export { OnBoxVmContainerHost, onBoxVmPlacement, onBoxVmIngress, type OnBoxVmEnv, type OnBoxVmState, } from "./on-box-vm.js";
292
+ export { OnBoxVmContainerHost, OnBoxVmTimeoutError, onBoxVmPlacement, onBoxVmIngress, type OnBoxVmEnv, type OnBoxVmOperation, type OnBoxVmState, } from "./on-box-vm.js";
274
293
  export { computerContainerSleepAfterMs } from "./container-policy.js";
275
294
  export * from "./computer-backends.js";
276
295
  export { LocalBackendOfflineError, localBackendAudience, localBackendDialPath, verifyLocalBackendDial, } from "./local-backend.js";
277
296
  /** Keep each native Workspace lease inside the operation that uses it. */
278
297
  export declare function createComputerFilesPort(computer: ComputerRpc): FilesPort;
279
298
  export { createWorkspaceFilesPort, type WorkspaceFilesOwner } from "./files.js";
280
- export * from "./operation-contract.js";
281
299
  export { ComputerOperationConflictError, ComputerOperationLimitError, ComputerRequestInvalidError, } from "./operation-record.js";
282
300
  export type { ContainerComputer };