@fungi.computer/agar 0.0.0-stage → 0.0.1

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 (159) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +766 -2
  3. package/dist/agent-message-meta.d.ts +74 -0
  4. package/dist/agent-message-meta.js +63 -0
  5. package/dist/agents.d.ts +170 -0
  6. package/dist/agents.js +218 -0
  7. package/dist/app-build-contract.d.ts +43 -0
  8. package/dist/app-build-contract.js +24 -0
  9. package/dist/apps.d.ts +66 -0
  10. package/dist/apps.js +47 -0
  11. package/dist/backend-declaration.d.ts +6 -0
  12. package/dist/backend-declaration.js +65 -0
  13. package/dist/backend-definition.d.ts +88 -0
  14. package/dist/backend-definition.js +158 -0
  15. package/dist/backend-refusal.d.ts +10 -0
  16. package/dist/backend-refusal.js +10 -0
  17. package/dist/backend.d.ts +30 -0
  18. package/dist/backend.js +28 -0
  19. package/dist/capabilities.d.ts +30 -0
  20. package/dist/capabilities.js +50 -0
  21. package/dist/channels.d.ts +142 -0
  22. package/dist/channels.js +97 -0
  23. package/dist/commands.d.ts +33 -0
  24. package/dist/commands.js +46 -0
  25. package/dist/computer-contracts.d.ts +73 -0
  26. package/dist/computer-contracts.js +57 -0
  27. package/dist/computer.d.ts +294 -0
  28. package/dist/computer.js +319 -0
  29. package/dist/connect.d.ts +11 -0
  30. package/dist/connect.js +211 -0
  31. package/dist/errors.d.ts +34 -0
  32. package/dist/errors.js +106 -0
  33. package/dist/failure.d.ts +2 -0
  34. package/dist/failure.js +9 -0
  35. package/dist/files.d.ts +25 -0
  36. package/dist/files.js +84 -0
  37. package/dist/game-servers.d.ts +530 -0
  38. package/dist/game-servers.js +244 -0
  39. package/dist/gills.d.ts +43 -0
  40. package/dist/gills.js +174 -0
  41. package/dist/git-commit.d.ts +143 -0
  42. package/dist/git-commit.js +251 -0
  43. package/dist/git-rpc.d.ts +310 -0
  44. package/dist/git-rpc.js +166 -0
  45. package/dist/git-steps.d.ts +579 -0
  46. package/dist/git-steps.js +804 -0
  47. package/dist/git-wire.d.ts +33 -0
  48. package/dist/git-wire.js +240 -0
  49. package/dist/git.d.ts +322 -0
  50. package/dist/git.js +98 -0
  51. package/dist/host.d.ts +97 -0
  52. package/dist/host.js +732 -0
  53. package/dist/inbox.d.ts +99 -0
  54. package/dist/inbox.js +184 -0
  55. package/dist/index.d.ts +31 -0
  56. package/dist/index.js +15 -0
  57. package/dist/inference.d.ts +17 -0
  58. package/dist/inference.js +115 -0
  59. package/dist/internal/app-error.d.ts +8 -0
  60. package/dist/internal/app-error.js +36 -0
  61. package/dist/internal/app-session.d.ts +8 -0
  62. package/dist/internal/app-session.js +551 -0
  63. package/dist/internal/back-inputs.d.ts +22 -0
  64. package/dist/internal/back-inputs.js +93 -0
  65. package/dist/internal/browser-bridge.d.ts +30 -0
  66. package/dist/internal/browser-bridge.js +203 -0
  67. package/dist/internal/capabilities.d.ts +13 -0
  68. package/dist/internal/capabilities.js +138 -0
  69. package/dist/internal/commands.d.ts +9 -0
  70. package/dist/internal/commands.js +257 -0
  71. package/dist/internal/disconnect-host.d.ts +7 -0
  72. package/dist/internal/disconnect-host.js +19 -0
  73. package/dist/internal/git-edit-tree.d.ts +6 -0
  74. package/dist/internal/git-edit-tree.js +46 -0
  75. package/dist/internal/memory-fs.d.ts +39 -0
  76. package/dist/internal/memory-fs.js +154 -0
  77. package/dist/internal/protocol.d.ts +116 -0
  78. package/dist/internal/protocol.js +6 -0
  79. package/dist/internal/query-feed.d.ts +23 -0
  80. package/dist/internal/query-feed.js +111 -0
  81. package/dist/internal/result.d.ts +22 -0
  82. package/dist/internal/result.js +61 -0
  83. package/dist/internal/rpc-contract.d.ts +24 -0
  84. package/dist/internal/rpc-contract.js +78 -0
  85. package/dist/internal/schemas.d.ts +307 -0
  86. package/dist/internal/schemas.js +524 -0
  87. package/dist/internal/store.d.ts +8 -0
  88. package/dist/internal/store.js +30 -0
  89. package/dist/internal/terminal-gate.d.ts +17 -0
  90. package/dist/internal/terminal-gate.js +94 -0
  91. package/dist/lifecycle.d.ts +44 -0
  92. package/dist/lifecycle.js +1 -0
  93. package/dist/marketplace.d.ts +159 -0
  94. package/dist/marketplace.js +102 -0
  95. package/dist/media-json.d.ts +181 -0
  96. package/dist/media-json.js +204 -0
  97. package/dist/media-library.d.ts +11 -0
  98. package/dist/media-library.js +15 -0
  99. package/dist/media-request-id.d.ts +7 -0
  100. package/dist/media-request-id.js +16 -0
  101. package/dist/media.d.ts +354 -0
  102. package/dist/media.js +654 -0
  103. package/dist/method-refusal.d.ts +64 -0
  104. package/dist/method-refusal.js +48 -0
  105. package/dist/pending.d.ts +10 -0
  106. package/dist/pending.js +10 -0
  107. package/dist/query.d.ts +76 -0
  108. package/dist/query.js +195 -0
  109. package/dist/react-mount.d.ts +23 -0
  110. package/dist/react-mount.js +108 -0
  111. package/dist/react.d.ts +41 -0
  112. package/dist/react.js +111 -0
  113. package/dist/read-copy.d.ts +103 -0
  114. package/dist/read-copy.js +195 -0
  115. package/dist/roles/files.d.ts +295 -0
  116. package/dist/roles/files.js +184 -0
  117. package/dist/root.d.ts +21 -0
  118. package/dist/root.js +1 -0
  119. package/dist/rpc.d.ts +1 -0
  120. package/dist/rpc.js +1 -0
  121. package/dist/status.d.ts +17 -0
  122. package/dist/status.js +50 -0
  123. package/dist/storage-wire.d.ts +167 -0
  124. package/dist/storage-wire.js +115 -0
  125. package/dist/storage.d.ts +72 -0
  126. package/dist/storage.js +143 -0
  127. package/dist/store.d.ts +11 -0
  128. package/dist/store.js +1 -0
  129. package/dist/test-kit/git.d.ts +31 -0
  130. package/dist/test-kit/git.js +174 -0
  131. package/dist/ui.d.ts +169 -0
  132. package/dist/ui.js +10 -0
  133. package/dist/window.d.ts +41 -0
  134. package/dist/window.js +15 -0
  135. package/dist/world.d.ts +16 -0
  136. package/dist/world.js +17 -0
  137. package/docs/api/README.md +28 -0
  138. package/docs/api/app-build-contract.md +113 -0
  139. package/docs/api/backend-declaration.md +62 -0
  140. package/docs/api/backend-definition.md +215 -0
  141. package/docs/api/backend.md +269 -0
  142. package/docs/api/errors.md +169 -0
  143. package/docs/api/files.md +91 -0
  144. package/docs/api/gills.md +164 -0
  145. package/docs/api/git-commit.md +279 -0
  146. package/docs/api/git-rpc.md +243 -0
  147. package/docs/api/git-steps.md +1010 -0
  148. package/docs/api/git-wire.md +197 -0
  149. package/docs/api/git.md +579 -0
  150. package/docs/api/index.md +2880 -0
  151. package/docs/api/media-json.md +507 -0
  152. package/docs/api/media-request-id.md +32 -0
  153. package/docs/api/modules.md +32 -0
  154. package/docs/api/query.md +253 -0
  155. package/docs/api/react.md +216 -0
  156. package/docs/api/read-copy.md +204 -0
  157. package/docs/api/rpc.md +128 -0
  158. package/docs/api/storage.md +620 -0
  159. package/package.json +197 -3
@@ -0,0 +1,294 @@
1
+ import * as Schema from "effect/Schema";
2
+ import type { CapabilityContract, CapabilityDirectory } from "./capabilities.js";
3
+ import { type AppFileRead, type AppFileWrite } from "./files.js";
4
+ export declare const computerListingSchema: Schema.Struct<{
5
+ readonly path: Schema.String;
6
+ readonly entries: Schema.$Array<Schema.Struct<{
7
+ readonly name: Schema.String;
8
+ readonly type: Schema.Literals<readonly ["file", "directory", "symlink"]>;
9
+ readonly size: Schema.Number;
10
+ readonly modifiedAt: Schema.Number;
11
+ }>>;
12
+ readonly nextOffset: Schema.NullOr<Schema.Number>;
13
+ }>;
14
+ export type ComputerListing = Schema.Schema.Type<typeof computerListingSchema>;
15
+ export declare const computerList: CapabilityContract<{
16
+ list(input: {
17
+ path: string;
18
+ limit: number;
19
+ offset: number;
20
+ }): Promise<ComputerListing>;
21
+ }>;
22
+ export declare const computerRuntimeStateSchema: Schema.Union<readonly [Schema.Struct<{
23
+ readonly state: Schema.Literals<readonly ["running", "sleeping", "starting"]>;
24
+ }>, Schema.Struct<{
25
+ readonly state: Schema.Literal<"queued">;
26
+ readonly position: Schema.Number;
27
+ }>]>;
28
+ export type ComputerRuntimeState = Schema.Schema.Type<typeof computerRuntimeStateSchema>;
29
+ export declare const computerInternetAccessSchema: Schema.Struct<{
30
+ readonly enabled: Schema.Boolean;
31
+ readonly effective: Schema.Boolean;
32
+ readonly blockedBy: Schema.NullOr<Schema.Literals<readonly ["team", "global"]>>;
33
+ }>;
34
+ export type ComputerInternetAccess = Schema.Schema.Type<typeof computerInternetAccessSchema>;
35
+ export declare const computerInstrumentSnapshotSchema: Schema.Struct<{
36
+ readonly computerId: Schema.NonEmptyString;
37
+ readonly name: Schema.NonEmptyString;
38
+ readonly runtime: Schema.Union<readonly [Schema.Struct<{
39
+ readonly state: Schema.Literals<readonly ["running", "sleeping", "starting"]>;
40
+ }>, Schema.Struct<{
41
+ readonly state: Schema.Literal<"queued">;
42
+ readonly position: Schema.Number;
43
+ }>]>;
44
+ readonly backends: Schema.$Array<Schema.Struct<{
45
+ readonly id: Schema.NonEmptyString;
46
+ readonly kind: Schema.Literals<readonly ["platform-container", "on-box-vm", "local"]>;
47
+ readonly status: Schema.Literals<readonly ["ready", "queued", "online", "offline"]>;
48
+ readonly queuePosition: Schema.NullOr<Schema.Number>;
49
+ readonly hostId: Schema.NullOr<Schema.String>;
50
+ readonly hostLabel: Schema.NullOr<Schema.String>;
51
+ readonly folderLabel: Schema.NullOr<Schema.String>;
52
+ readonly detachable: Schema.Boolean;
53
+ }>>;
54
+ readonly internet: Schema.Struct<{
55
+ readonly enabled: Schema.Boolean;
56
+ readonly effective: Schema.Boolean;
57
+ readonly blockedBy: Schema.NullOr<Schema.Literals<readonly ["team", "global"]>>;
58
+ }>;
59
+ }>;
60
+ export type ComputerInstrumentSnapshot = Schema.Schema.Type<typeof computerInstrumentSnapshotSchema>;
61
+ export declare const computerInstrumentRead: CapabilityContract<{
62
+ read(): Promise<ComputerInstrumentSnapshot>;
63
+ }>;
64
+ export declare const computerInstrumentControl: CapabilityContract<{
65
+ start(): Promise<ComputerRuntimeState>;
66
+ setInternetAccess(enabled: boolean): Promise<ComputerInternetAccess>;
67
+ detachLocal(backendId: string): Promise<{
68
+ detached: boolean;
69
+ }>;
70
+ }>;
71
+ export declare function readComputerInstrument(capabilities: CapabilityDirectory): Promise<ComputerInstrumentSnapshot>;
72
+ export declare function startInstrumentComputer(capabilities: CapabilityDirectory): Promise<ComputerRuntimeState>;
73
+ export declare function setInstrumentInternetAccess(capabilities: CapabilityDirectory, enabled: boolean): Promise<ComputerInternetAccess>;
74
+ export declare function detachInstrumentLocalBackend(capabilities: CapabilityDirectory, backendId: string): Promise<{
75
+ detached: boolean;
76
+ }>;
77
+ export declare const computerPortsSchema: Schema.Struct<{
78
+ readonly ports: Schema.$Array<Schema.Struct<{
79
+ readonly port: Schema.Number;
80
+ readonly previewUrl: Schema.NonEmptyString;
81
+ /** Host-selected display mode; this metadata does not grant preview access. */
82
+ readonly openMode: Schema.Literals<readonly ["inline", "external-only"]>;
83
+ readonly expiresAt: Schema.Number;
84
+ }>>;
85
+ }>;
86
+ export type ComputerPorts = Schema.Schema.Type<typeof computerPortsSchema>;
87
+ export declare const computerPortsResultSchema: Schema.Union<readonly [Schema.Struct<{
88
+ readonly ports: Schema.$Array<Schema.Struct<{
89
+ readonly port: Schema.Number;
90
+ readonly previewUrl: Schema.NonEmptyString;
91
+ /** Host-selected display mode; this metadata does not grant preview access. */
92
+ readonly openMode: Schema.Literals<readonly ["inline", "external-only"]>;
93
+ readonly expiresAt: Schema.Number;
94
+ }>>;
95
+ }>, Schema.Struct<{
96
+ readonly error: Schema.Literal<"port_previews_not_configured">;
97
+ }>]>;
98
+ export type ComputerPortsResult = Schema.Schema.Type<typeof computerPortsResultSchema>;
99
+ export type ComputerPortExposure = Readonly<{
100
+ port: number;
101
+ exposed: boolean;
102
+ }>;
103
+ export type ComputerPortRemoval = Readonly<{
104
+ port: number;
105
+ removed: boolean;
106
+ }>;
107
+ export declare const computerPortExposureSchema: Schema.Struct<{
108
+ readonly port: Schema.Number;
109
+ readonly exposed: Schema.Boolean;
110
+ }>;
111
+ export declare const computerPortRemovalSchema: Schema.Struct<{
112
+ readonly port: Schema.Number;
113
+ readonly removed: Schema.Boolean;
114
+ }>;
115
+ /** The selected Computer's admitted preview URLs and port mutations. */
116
+ export declare const computerPorts: CapabilityContract<{
117
+ list(): Promise<ComputerPortsResult>;
118
+ expose(port: number): Promise<ComputerPortExposure>;
119
+ unexpose(port: number): Promise<ComputerPortRemoval>;
120
+ }>;
121
+ /** Decode exposed ports at the SDK boundary. */
122
+ export declare function listComputerPorts(capabilities: CapabilityDirectory): Promise<ComputerPortsResult>;
123
+ /** Expose one port on the selected Computer under its App admission. */
124
+ export declare function exposeComputerPort(capabilities: CapabilityDirectory, port: number): Promise<ComputerPortExposure>;
125
+ /** Remove one exposed port from the selected Computer. */
126
+ export declare function unexposeComputerPort(capabilities: CapabilityDirectory, port: number): Promise<ComputerPortRemoval>;
127
+ /**
128
+ * `synced`: the exact observation that recorded this exit also confirmed
129
+ * computerd's post-command pull landed. `pending`: that observation saw
130
+ * the pull fail, or gave up waiting for it. `unknown`: this exit was
131
+ * recorded with no pull evidence at all.
132
+ */
133
+ export declare const computerProcessSyncSchema: Schema.Literals<readonly ["synced", "pending", "unknown"]>;
134
+ /** A process owned by the selected Computer's durable process inventory. */
135
+ export declare const computerProcessSchema: Schema.Struct<{
136
+ readonly port: Schema.NullOr<Schema.Number>;
137
+ readonly id: Schema.NonEmptyString;
138
+ readonly command: Schema.NonEmptyString;
139
+ readonly cwd: Schema.NullOr<Schema.String>;
140
+ readonly startedAt: Schema.Number;
141
+ readonly state: Schema.Literals<readonly ["running", "exited", "uncertain"]>;
142
+ readonly exitCode: Schema.NullOr<Schema.Number>;
143
+ readonly sync: Schema.Literals<readonly ["synced", "pending", "unknown"]>;
144
+ readonly endedAt: Schema.NullOr<Schema.Number>;
145
+ }>;
146
+ export declare const computerProcessesSchema: Schema.Struct<{
147
+ readonly processes: Schema.$Array<Schema.Struct<{
148
+ readonly port: Schema.NullOr<Schema.Number>;
149
+ readonly id: Schema.NonEmptyString;
150
+ readonly command: Schema.NonEmptyString;
151
+ readonly cwd: Schema.NullOr<Schema.String>;
152
+ readonly startedAt: Schema.Number;
153
+ readonly state: Schema.Literals<readonly ["running", "exited", "uncertain"]>;
154
+ readonly exitCode: Schema.NullOr<Schema.Number>;
155
+ readonly sync: Schema.Literals<readonly ["synced", "pending", "unknown"]>;
156
+ readonly endedAt: Schema.NullOr<Schema.Number>;
157
+ }>>;
158
+ }>;
159
+ export declare const computerProcessKillSchema: Schema.Struct<{
160
+ readonly process: Schema.Struct<{
161
+ readonly port: Schema.NullOr<Schema.Number>;
162
+ readonly id: Schema.NonEmptyString;
163
+ readonly command: Schema.NonEmptyString;
164
+ readonly cwd: Schema.NullOr<Schema.String>;
165
+ readonly startedAt: Schema.Number;
166
+ readonly state: Schema.Literals<readonly ["running", "exited", "uncertain"]>;
167
+ readonly exitCode: Schema.NullOr<Schema.Number>;
168
+ readonly sync: Schema.Literals<readonly ["synced", "pending", "unknown"]>;
169
+ readonly endedAt: Schema.NullOr<Schema.Number>;
170
+ }>;
171
+ readonly signalled: Schema.Boolean;
172
+ }>;
173
+ export type ComputerProcess = Schema.Schema.Type<typeof computerProcessSchema>;
174
+ export type ComputerProcessSync = Schema.Schema.Type<typeof computerProcessSyncSchema>;
175
+ export type ComputerProcesses = Schema.Schema.Type<typeof computerProcessesSchema>;
176
+ /** Stable UI request identity is distinct from the host-only native scope. */
177
+ export declare const computerProcessStartSchema: Schema.Struct<{
178
+ readonly requestId: Schema.NonEmptyString;
179
+ readonly command: Schema.NonEmptyString;
180
+ readonly cwd: Schema.optionalKey<Schema.String>;
181
+ readonly port: Schema.optionalKey<Schema.Number>;
182
+ }>;
183
+ export type ComputerProcessStart = Schema.Schema.Type<typeof computerProcessStartSchema>;
184
+ /** Read the authoritative process inventory from the selected Computer. */
185
+ export declare const computerProcesses: CapabilityContract<{
186
+ start(input: ComputerProcessStart): Promise<ComputerProcess>;
187
+ list(): Promise<ComputerProcesses>;
188
+ kill(id: string): Promise<Schema.Schema.Type<typeof computerProcessKillSchema>>;
189
+ }>;
190
+ /** Decode the Computer owner's process inventory at the App boundary. */
191
+ export declare function listComputerProcesses(capabilities: CapabilityDirectory): Promise<ComputerProcesses>;
192
+ /** Stop one process owned by the selected Computer. */
193
+ export declare function killComputerProcess(capabilities: CapabilityDirectory, id: string): Promise<{
194
+ readonly process: {
195
+ readonly port: number | null;
196
+ readonly id: string;
197
+ readonly command: string;
198
+ readonly cwd: string | null;
199
+ readonly startedAt: number;
200
+ readonly state: "running" | "exited" | "uncertain";
201
+ readonly exitCode: number | null;
202
+ readonly sync: "unknown" | "pending" | "synced";
203
+ readonly endedAt: number | null;
204
+ };
205
+ readonly signalled: boolean;
206
+ }>;
207
+ export declare const computerReadFile: CapabilityContract<{
208
+ open(input: {
209
+ path: string;
210
+ }): Promise<AppFileRead>;
211
+ }>;
212
+ /** The caller receives native file bytes; HTTP details stay in the SDK adapter. */
213
+ export declare function readComputerFile(capabilities: CapabilityDirectory, input: {
214
+ path: string;
215
+ }, options: {
216
+ signal?: AbortSignal;
217
+ }): Promise<File>;
218
+ /** Decode listing data at the SDK boundary, before the App consumes it. */
219
+ export declare function listComputerFiles(capabilities: CapabilityDirectory, input: {
220
+ path: string;
221
+ limit: number;
222
+ offset: number;
223
+ }): Promise<ComputerListing>;
224
+ export declare const computerWriteFile: CapabilityContract<{
225
+ open(input: {
226
+ path: string;
227
+ }): Promise<AppFileWrite>;
228
+ mkdir(input: {
229
+ path: string;
230
+ }): Promise<void>;
231
+ replace(input: ComputerFileReplacementInput): Promise<ComputerFileReplacementOutcome>;
232
+ }>;
233
+ export type ComputerFileReplacementInput = Readonly<{
234
+ path: string;
235
+ expectedContent: string;
236
+ content: string;
237
+ }>;
238
+ declare const computerFileReplacementOutcomeSchema: Schema.Union<readonly [Schema.Struct<{
239
+ readonly kind: Schema.Literal<"replaced">;
240
+ readonly path: Schema.NonEmptyString;
241
+ readonly bytes: Schema.Number;
242
+ }>, Schema.Struct<{
243
+ readonly kind: Schema.Literal<"conflict">;
244
+ }>]>;
245
+ export type ComputerFileReplacementOutcome = Schema.Schema.Type<typeof computerFileReplacementOutcomeSchema>;
246
+ export declare function replaceComputerFileIfUnchanged(capabilities: CapabilityDirectory, input: ComputerFileReplacementInput, options: {
247
+ signal?: AbortSignal;
248
+ }): Promise<Readonly<{
249
+ path: string;
250
+ bytes: number;
251
+ }>>;
252
+ export type ComputerTerminalSize = Readonly<{
253
+ cols: number;
254
+ rows: number;
255
+ }>;
256
+ /** Display facts supplied by the admitted Computer, separate from shell bytes. */
257
+ export declare const computerTerminalInformationSchema: Schema.Struct<{
258
+ readonly computerName: Schema.NonEmptyString;
259
+ readonly teamName: Schema.NonEmptyString;
260
+ readonly modelDoor: Schema.NonEmptyString;
261
+ readonly uptimeSeconds: Schema.Number;
262
+ readonly version: Schema.NonEmptyString;
263
+ }>;
264
+ export type ComputerTerminalInformation = Schema.Schema.Type<typeof computerTerminalInformationSchema>;
265
+ /** The host keeps the PTY socket and exposes only its two flow-controlled streams. */
266
+ export type AppComputerTerminal = Disposable & {
267
+ information(): Promise<ComputerTerminalInformation>;
268
+ output(): Promise<ReadableStream<Uint8Array>>;
269
+ input(): Promise<WritableStream<Uint8Array>>;
270
+ resize(size: ComputerTerminalSize): Promise<void>;
271
+ close(): Promise<void>;
272
+ };
273
+ export type ComputerTerminal = Readonly<{
274
+ information: ComputerTerminalInformation;
275
+ output: ReadableStream<Uint8Array>;
276
+ input: WritableStream<Uint8Array>;
277
+ resize(size: ComputerTerminalSize): Promise<void>;
278
+ close(): Promise<void>;
279
+ }>;
280
+ export declare const computerTerminal: CapabilityContract<{
281
+ open(size: ComputerTerminalSize): Promise<AppComputerTerminal>;
282
+ }>;
283
+ /** Open one host-owned terminal and bind its lifetime to the mounted App. */
284
+ export declare function openComputerTerminal(capabilities: CapabilityDirectory, size: ComputerTerminalSize, options?: {
285
+ signal?: AbortSignal;
286
+ }): Promise<ComputerTerminal>;
287
+ /** Native file stream crosses RPC; neither File subclass nor an editable URL crosses. */
288
+ export declare function writeComputerFile(capabilities: CapabilityDirectory, input: {
289
+ path: string;
290
+ content: Blob;
291
+ }, options: {
292
+ signal?: AbortSignal;
293
+ }): Promise<void>;
294
+ export {};
@@ -0,0 +1,319 @@
1
+ import { defineCapability } from "./capabilities.js";
2
+ import { rpcDataSchema, rpcHandleSchema, rpcMethod, rpcVoid, } from "./internal/rpc-contract.js";
3
+ import * as z from "zod";
4
+ import * as Schema from "effect/Schema";
5
+ import { readAppFile, writeAppFile, } from "./files.js";
6
+ import { reportCatchFailure } from "./failure.js";
7
+ import { AppError } from "./errors.js";
8
+ export const computerListingSchema = Schema.Struct({
9
+ path: Schema.String,
10
+ entries: Schema.Array(Schema.Struct({
11
+ name: Schema.String,
12
+ type: Schema.Literals(["file", "directory", "symlink"]),
13
+ size: Schema.Number,
14
+ modifiedAt: Schema.Number,
15
+ })),
16
+ nextOffset: Schema.NullOr(Schema.Number),
17
+ });
18
+ export const computerList = defineCapability("computer.list", 1, rpcHandleSchema({
19
+ list: rpcMethod(rpcDataSchema(z
20
+ .unknown()
21
+ .transform((value) => Schema.decodeUnknownSync(computerListingSchema)(value)))),
22
+ }));
23
+ export const computerRuntimeStateSchema = Schema.Union([
24
+ Schema.Struct({
25
+ state: Schema.Literals(["running", "sleeping", "starting"]),
26
+ }),
27
+ Schema.Struct({
28
+ state: Schema.Literal("queued"),
29
+ position: Schema.Number.pipe(Schema.check(Schema.isInt()), Schema.check(Schema.isGreaterThan(0))),
30
+ }),
31
+ ]);
32
+ export const computerInternetAccessSchema = Schema.Struct({
33
+ enabled: Schema.Boolean,
34
+ effective: Schema.Boolean,
35
+ blockedBy: Schema.NullOr(Schema.Literals(["team", "global"])),
36
+ });
37
+ export const computerInstrumentSnapshotSchema = Schema.Struct({
38
+ computerId: Schema.NonEmptyString,
39
+ name: Schema.NonEmptyString,
40
+ runtime: computerRuntimeStateSchema,
41
+ backends: Schema.Array(Schema.Struct({
42
+ id: Schema.NonEmptyString,
43
+ kind: Schema.Literals(["platform-container", "on-box-vm", "local"]),
44
+ status: Schema.Literals(["ready", "queued", "online", "offline"]),
45
+ queuePosition: Schema.NullOr(Schema.Number.pipe(Schema.check(Schema.isInt()), Schema.check(Schema.isGreaterThan(0)))),
46
+ hostId: Schema.NullOr(Schema.String),
47
+ hostLabel: Schema.NullOr(Schema.String),
48
+ folderLabel: Schema.NullOr(Schema.String),
49
+ detachable: Schema.Boolean,
50
+ })),
51
+ internet: computerInternetAccessSchema,
52
+ });
53
+ export const computerInstrumentRead = defineCapability("computer.instrument.read", 1, rpcHandleSchema({
54
+ read: rpcMethod(rpcDataSchema(z
55
+ .unknown()
56
+ .transform((value) => Schema.decodeUnknownSync(computerInstrumentSnapshotSchema)(value)))),
57
+ }));
58
+ export const computerInstrumentControl = defineCapability("computer.instrument.control", 1, rpcHandleSchema({
59
+ start: rpcMethod(rpcDataSchema(z
60
+ .unknown()
61
+ .transform((value) => Schema.decodeUnknownSync(computerRuntimeStateSchema)(value)))),
62
+ setInternetAccess: rpcMethod(rpcDataSchema(z
63
+ .unknown()
64
+ .transform((value) => Schema.decodeUnknownSync(computerInternetAccessSchema)(value)))),
65
+ detachLocal: rpcMethod(rpcDataSchema(z
66
+ .unknown()
67
+ .transform((value) => Schema.decodeUnknownSync(Schema.Struct({ detached: Schema.Boolean }))(value)))),
68
+ }));
69
+ export async function readComputerInstrument(capabilities) {
70
+ return Schema.decodeUnknownSync(computerInstrumentSnapshotSchema)(await capabilities.require(computerInstrumentRead).read());
71
+ }
72
+ export async function startInstrumentComputer(capabilities) {
73
+ return Schema.decodeUnknownSync(computerRuntimeStateSchema)(await capabilities.require(computerInstrumentControl).start());
74
+ }
75
+ export async function setInstrumentInternetAccess(capabilities, enabled) {
76
+ return Schema.decodeUnknownSync(computerInternetAccessSchema)(await capabilities
77
+ .require(computerInstrumentControl)
78
+ .setInternetAccess(enabled));
79
+ }
80
+ export async function detachInstrumentLocalBackend(capabilities, backendId) {
81
+ return Schema.decodeUnknownSync(Schema.Struct({ detached: Schema.Boolean }))(await capabilities
82
+ .require(computerInstrumentControl)
83
+ .detachLocal(backendId));
84
+ }
85
+ export const computerPortsSchema = Schema.Struct({
86
+ ports: Schema.Array(Schema.Struct({
87
+ port: Schema.Number.pipe(Schema.check(Schema.isInt()), Schema.check(Schema.isBetween({ minimum: 1, maximum: 65_535 }))),
88
+ previewUrl: Schema.NonEmptyString,
89
+ /** Host-selected display mode; this metadata does not grant preview access. */
90
+ openMode: Schema.Literals(["inline", "external-only"]),
91
+ expiresAt: Schema.Number.pipe(Schema.check(Schema.isInt()), Schema.check(Schema.isGreaterThan(0))),
92
+ })).pipe(Schema.check(Schema.isMaxLength(64))),
93
+ });
94
+ export const computerPortsResultSchema = Schema.Union([
95
+ computerPortsSchema,
96
+ Schema.Struct({ error: Schema.Literal("port_previews_not_configured") }),
97
+ ]);
98
+ export const computerPortExposureSchema = Schema.Struct({
99
+ port: Schema.Number.annotate({
100
+ message: "Use a port from 1 to 65535.",
101
+ }).check(Schema.isInt({ message: "Use a port from 1 to 65535." }), Schema.isBetween({ minimum: 1, maximum: 65_535 }, { message: "Use a port from 1 to 65535." })),
102
+ exposed: Schema.Boolean,
103
+ });
104
+ export const computerPortRemovalSchema = Schema.Struct({
105
+ port: Schema.Number.pipe(Schema.check(Schema.isInt()), Schema.check(Schema.isBetween({ minimum: 1, maximum: 65_535 }))),
106
+ removed: Schema.Boolean,
107
+ });
108
+ /** The selected Computer's admitted preview URLs and port mutations. */
109
+ export const computerPorts = defineCapability("computer.ports", 2, rpcHandleSchema({
110
+ list: rpcMethod(rpcDataSchema(z
111
+ .unknown()
112
+ .transform((value) => Schema.decodeUnknownSync(computerPortsResultSchema)(value)))),
113
+ expose: rpcMethod(rpcDataSchema(z
114
+ .unknown()
115
+ .transform((value) => Schema.decodeUnknownSync(computerPortExposureSchema)(value)))),
116
+ unexpose: rpcMethod(rpcDataSchema(z
117
+ .unknown()
118
+ .transform((value) => Schema.decodeUnknownSync(computerPortRemovalSchema)(value)))),
119
+ }));
120
+ /** Decode exposed ports at the SDK boundary. */
121
+ export async function listComputerPorts(capabilities) {
122
+ const result = Schema.decodeUnknownSync(computerPortsResultSchema)(await capabilities.require(computerPorts).list());
123
+ if ("error" in result)
124
+ return result;
125
+ for (const { previewUrl, expiresAt } of result.ports) {
126
+ const url = new URL(previewUrl);
127
+ if (url.protocol !== "https:" ||
128
+ url.username ||
129
+ url.password ||
130
+ expiresAt <= Date.now())
131
+ throw new Error("Computer preview URL is invalid");
132
+ }
133
+ return result;
134
+ }
135
+ /** Expose one port on the selected Computer under its App admission. */
136
+ export async function exposeComputerPort(capabilities, port) {
137
+ return Schema.decodeUnknownSync(computerPortExposureSchema)(await capabilities.require(computerPorts).expose(port));
138
+ }
139
+ /** Remove one exposed port from the selected Computer. */
140
+ export async function unexposeComputerPort(capabilities, port) {
141
+ return Schema.decodeUnknownSync(computerPortRemovalSchema)(await capabilities.require(computerPorts).unexpose(port));
142
+ }
143
+ /**
144
+ * `synced`: the exact observation that recorded this exit also confirmed
145
+ * computerd's post-command pull landed. `pending`: that observation saw
146
+ * the pull fail, or gave up waiting for it. `unknown`: this exit was
147
+ * recorded with no pull evidence at all.
148
+ */
149
+ export const computerProcessSyncSchema = Schema.Literals([
150
+ "synced",
151
+ "pending",
152
+ "unknown",
153
+ ]);
154
+ /** A process owned by the selected Computer's durable process inventory. */
155
+ export const computerProcessSchema = Schema.Struct({
156
+ port: Schema.NullOr(computerPortExposureSchema.fields.port),
157
+ id: Schema.NonEmptyString,
158
+ command: Schema.NonEmptyString,
159
+ cwd: Schema.NullOr(Schema.String),
160
+ startedAt: Schema.Number.pipe(Schema.check(Schema.isInt()), Schema.check(Schema.isGreaterThanOrEqualTo(0))),
161
+ state: Schema.Literals(["running", "exited", "uncertain"]),
162
+ exitCode: Schema.NullOr(Schema.Number.pipe(Schema.check(Schema.isInt()))),
163
+ sync: computerProcessSyncSchema,
164
+ endedAt: Schema.NullOr(Schema.Number.pipe(Schema.check(Schema.isInt()), Schema.check(Schema.isGreaterThanOrEqualTo(0)))),
165
+ });
166
+ export const computerProcessesSchema = Schema.Struct({
167
+ processes: Schema.Array(computerProcessSchema),
168
+ });
169
+ export const computerProcessKillSchema = Schema.Struct({
170
+ process: computerProcessSchema,
171
+ signalled: Schema.Boolean,
172
+ });
173
+ /** Stable UI request identity is distinct from the host-only native scope. */
174
+ export const computerProcessStartSchema = Schema.Struct({
175
+ requestId: Schema.NonEmptyString.pipe(Schema.check(Schema.isMaxLength(256))),
176
+ command: Schema.NonEmptyString.pipe(Schema.check(Schema.isMaxLength(16 * 1024))),
177
+ cwd: Schema.optionalKey(Schema.String),
178
+ port: Schema.optionalKey(computerPortExposureSchema.fields.port),
179
+ });
180
+ /** Read the authoritative process inventory from the selected Computer. */
181
+ export const computerProcesses = defineCapability("computer.processes", 1, rpcHandleSchema({
182
+ start: rpcMethod(rpcDataSchema(z
183
+ .unknown()
184
+ .transform((value) => Schema.decodeUnknownSync(computerProcessSchema)(value)))),
185
+ list: rpcMethod(rpcDataSchema(z
186
+ .unknown()
187
+ .transform((value) => Schema.decodeUnknownSync(computerProcessesSchema)(value)))),
188
+ kill: rpcMethod(rpcDataSchema(z
189
+ .unknown()
190
+ .transform((value) => Schema.decodeUnknownSync(computerProcessKillSchema)(value)))),
191
+ }));
192
+ /** Decode the Computer owner's process inventory at the App boundary. */
193
+ export async function listComputerProcesses(capabilities) {
194
+ return Schema.decodeUnknownSync(computerProcessesSchema)(await capabilities.require(computerProcesses).list());
195
+ }
196
+ /** Stop one process owned by the selected Computer. */
197
+ export async function killComputerProcess(capabilities, id) {
198
+ return Schema.decodeUnknownSync(computerProcessKillSchema)(await capabilities.require(computerProcesses).kill(id));
199
+ }
200
+ export const computerReadFile = defineCapability("computer.readFile", 1, rpcHandleSchema({
201
+ open: rpcMethod(rpcHandleSchema({
202
+ response: rpcMethod(z.instanceof(Response)),
203
+ close: rpcVoid,
204
+ })),
205
+ }));
206
+ /** The caller receives native file bytes; HTTP details stay in the SDK adapter. */
207
+ export async function readComputerFile(capabilities, input, options) {
208
+ return await readAppFile(await capabilities.require(computerReadFile).open(input), { ...options, name: input.path.split("/").at(-1) ?? "file" });
209
+ }
210
+ /** Decode listing data at the SDK boundary, before the App consumes it. */
211
+ export async function listComputerFiles(capabilities, input) {
212
+ return Schema.decodeUnknownSync(computerListingSchema)(await capabilities.require(computerList).list(input));
213
+ }
214
+ export const computerWriteFile = defineCapability("computer.writeFile", 3, rpcHandleSchema({
215
+ open: rpcMethod(rpcHandleSchema({ write: rpcVoid, close: rpcVoid })),
216
+ mkdir: rpcVoid,
217
+ replace: rpcMethod(rpcDataSchema(z
218
+ .unknown()
219
+ .transform((value) => Schema.decodeUnknownSync(computerFileReplacementOutcomeSchema)(value)))),
220
+ }));
221
+ const computerFileReplacementOutcomeSchema = Schema.Union([
222
+ Schema.Struct({
223
+ kind: Schema.Literal("replaced"),
224
+ path: Schema.NonEmptyString,
225
+ bytes: Schema.Number.pipe(Schema.check(Schema.isInt()), Schema.check(Schema.isGreaterThanOrEqualTo(0))),
226
+ }),
227
+ Schema.Struct({ kind: Schema.Literal("conflict") }),
228
+ ]);
229
+ export async function replaceComputerFileIfUnchanged(capabilities, input, options) {
230
+ options.signal?.throwIfAborted();
231
+ const result = await capabilities.require(computerWriteFile).replace(input);
232
+ if (result.kind === "conflict")
233
+ throw new AppError("Computer file changed since it was opened", {
234
+ code: "CONFLICT",
235
+ retryable: false,
236
+ });
237
+ return { path: result.path, bytes: result.bytes };
238
+ }
239
+ /** Display facts supplied by the admitted Computer, separate from shell bytes. */
240
+ export const computerTerminalInformationSchema = Schema.Struct({
241
+ computerName: Schema.NonEmptyString.pipe(Schema.check(Schema.isMaxLength(256))),
242
+ teamName: Schema.NonEmptyString.pipe(Schema.check(Schema.isMaxLength(256))),
243
+ modelDoor: Schema.NonEmptyString.pipe(Schema.check(Schema.isMaxLength(256))),
244
+ uptimeSeconds: Schema.Number.pipe(Schema.check(Schema.isInt()), Schema.check(Schema.isGreaterThanOrEqualTo(0))),
245
+ version: Schema.NonEmptyString.pipe(Schema.check(Schema.isMaxLength(64))),
246
+ });
247
+ export const computerTerminal = defineCapability("computer.terminal", 2, rpcHandleSchema({
248
+ open: rpcMethod(rpcHandleSchema({
249
+ information: rpcMethod(rpcDataSchema(z
250
+ .unknown()
251
+ .transform((value) => Schema.decodeUnknownSync(computerTerminalInformationSchema)(value)))),
252
+ output: rpcMethod(z.instanceof(ReadableStream).transform((stream) => stream.pipeThrough(new TransformStream({
253
+ transform(chunk, controller) {
254
+ controller.enqueue(z.instanceof(Uint8Array).parse(chunk));
255
+ },
256
+ })))),
257
+ input: rpcMethod(z.instanceof(WritableStream)),
258
+ resize: rpcVoid,
259
+ close: rpcVoid,
260
+ })),
261
+ }));
262
+ /** Open one host-owned terminal and bind its lifetime to the mounted App. */
263
+ export async function openComputerTerminal(capabilities, size, options = {}) {
264
+ options.signal?.throwIfAborted();
265
+ const terminal = await capabilities.require(computerTerminal).open(size);
266
+ let closing;
267
+ const close = () => {
268
+ if (closing !== undefined)
269
+ return closing;
270
+ options.signal?.removeEventListener("abort", abort);
271
+ closing = Promise.resolve().then(async () => {
272
+ try {
273
+ await terminal.close();
274
+ }
275
+ finally {
276
+ terminal[Symbol.dispose]();
277
+ }
278
+ });
279
+ return closing;
280
+ };
281
+ const abort = () => {
282
+ void close().catch((cause) => {
283
+ reportCatchFailure("computer.terminal.abort-close", cause);
284
+ });
285
+ };
286
+ options.signal?.addEventListener("abort", abort, { once: true });
287
+ try {
288
+ const [output, input, information] = await Promise.all([
289
+ terminal.output(),
290
+ terminal.input(),
291
+ terminal.information(),
292
+ ]);
293
+ options.signal?.throwIfAborted();
294
+ const outputStream = output;
295
+ const inputStream = input;
296
+ return {
297
+ information: Schema.decodeUnknownSync(computerTerminalInformationSchema)(information),
298
+ output: outputStream,
299
+ input: inputStream,
300
+ resize: async (nextSize) => {
301
+ options.signal?.throwIfAborted();
302
+ if (closing !== undefined)
303
+ throw new Error("Computer terminal is closed");
304
+ await terminal.resize(nextSize);
305
+ },
306
+ close,
307
+ };
308
+ }
309
+ catch (error) {
310
+ await close().catch((cause) => {
311
+ reportCatchFailure("computer.terminal.open-cleanup", cause);
312
+ });
313
+ throw error;
314
+ }
315
+ }
316
+ /** Native file stream crosses RPC; neither File subclass nor an editable URL crosses. */
317
+ export async function writeComputerFile(capabilities, input, options) {
318
+ await writeAppFile(await capabilities.require(computerWriteFile).open({ path: input.path }), input.content, options);
319
+ }
@@ -0,0 +1,11 @@
1
+ import type { AppRoot } from "./root.js";
2
+ /** Options for connecting this iframe page to its authenticated host. */
3
+ export type ConnectAppOptions = {
4
+ /** The origin the host handshake message must come from; the connection
5
+ * is refused when it comes from anywhere else. */
6
+ readonly expectedHostOrigin: string;
7
+ /** Cancels a pending connection attempt. */
8
+ readonly signal?: AbortSignal;
9
+ };
10
+ /** Connects this iframe page to its authenticated host. */
11
+ export declare function connectApp(options: ConnectAppOptions): Promise<AppRoot>;