@fungi.computer/oyster 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1134 -2
  3. package/dist/agents.d.ts +114 -0
  4. package/dist/agents.js +322 -0
  5. package/dist/app-builds.d.ts +210 -0
  6. package/dist/app-builds.js +499 -0
  7. package/dist/app-sandbox.d.ts +2 -0
  8. package/dist/app-sandbox.js +2 -0
  9. package/dist/app-sources.d.ts +31 -0
  10. package/dist/app-sources.js +370 -0
  11. package/dist/app-storage.d.ts +141 -0
  12. package/dist/app-storage.js +281 -0
  13. package/dist/apps/gate.d.ts +105 -0
  14. package/dist/apps/gate.js +273 -0
  15. package/dist/apps/index.d.ts +5 -0
  16. package/dist/apps/index.js +5 -0
  17. package/dist/apps/installation.d.ts +248 -0
  18. package/dist/apps/installation.js +307 -0
  19. package/dist/apps/operations.d.ts +8 -0
  20. package/dist/apps/operations.js +98 -0
  21. package/dist/apps/tools.d.ts +33 -0
  22. package/dist/apps/tools.js +17 -0
  23. package/dist/auth.d.ts +11 -0
  24. package/dist/auth.js +93 -0
  25. package/dist/backend-request.d.ts +3 -0
  26. package/dist/backend-request.js +53 -0
  27. package/dist/build/artifact-writer.d.ts +40 -0
  28. package/dist/build/artifact-writer.js +181 -0
  29. package/dist/build/build-jobs.d.ts +128 -0
  30. package/dist/build/build-jobs.js +203 -0
  31. package/dist/build/build-policy.d.ts +10 -0
  32. package/dist/build/build-policy.js +10 -0
  33. package/dist/build/build-step.d.ts +37 -0
  34. package/dist/build/build-step.js +28 -0
  35. package/dist/build/bundled-html.d.ts +7 -0
  36. package/dist/build/bundled-html.js +64 -0
  37. package/dist/build/candidate-builder.d.ts +68 -0
  38. package/dist/build/candidate-builder.js +91 -0
  39. package/dist/build/candidate-cli.d.ts +1 -0
  40. package/dist/build/candidate-cli.js +119 -0
  41. package/dist/build/candidate-cli.mjs +28170 -0
  42. package/dist/build/content-objects.d.ts +37 -0
  43. package/dist/build/content-objects.js +53 -0
  44. package/dist/build/definition-emission.d.ts +34 -0
  45. package/dist/build/definition-emission.js +201 -0
  46. package/dist/build/effect.d.ts +249 -0
  47. package/dist/build/effect.js +436 -0
  48. package/dist/build/git-environment.d.ts +9 -0
  49. package/dist/build/git-environment.js +60 -0
  50. package/dist/build/html-recipe.d.ts +20 -0
  51. package/dist/build/html-recipe.js +51 -0
  52. package/dist/build/local-build.d.ts +67 -0
  53. package/dist/build/local-build.js +1128 -0
  54. package/dist/build/snapshot-package-store.d.ts +12 -0
  55. package/dist/build/snapshot-package-store.js +36 -0
  56. package/dist/build/snapshot-program-scripts.d.ts +6 -0
  57. package/dist/build/snapshot-program-scripts.js +2 -0
  58. package/dist/build/snapshot-programs/snapshot-path.d.ts +2 -0
  59. package/dist/build/snapshot-programs/snapshot-path.js +6 -0
  60. package/dist/build/submission-contract.d.ts +828 -0
  61. package/dist/build/submission-contract.js +180 -0
  62. package/dist/build/workspace-build.d.ts +55 -0
  63. package/dist/build/workspace-build.js +200 -0
  64. package/dist/build-contract.d.ts +7 -0
  65. package/dist/build-contract.js +7 -0
  66. package/dist/build-egress.d.ts +62 -0
  67. package/dist/build-egress.js +148 -0
  68. package/dist/build-jobs.d.ts +2 -0
  69. package/dist/build-jobs.js +2 -0
  70. package/dist/build.d.ts +12 -0
  71. package/dist/build.js +14 -0
  72. package/dist/capability-descriptor.d.ts +46 -0
  73. package/dist/capability-descriptor.js +51 -0
  74. package/dist/catalog-frame.d.ts +39 -0
  75. package/dist/catalog-frame.js +72 -0
  76. package/dist/cause-class.d.ts +19 -0
  77. package/dist/cause-class.js +54 -0
  78. package/dist/cloudflare.d.ts +123 -0
  79. package/dist/cloudflare.js +391 -0
  80. package/dist/computer-terminal.d.ts +38 -0
  81. package/dist/computer-terminal.js +410 -0
  82. package/dist/computer.d.ts +60 -0
  83. package/dist/computer.js +33 -0
  84. package/dist/event-recipients.d.ts +57 -0
  85. package/dist/event-recipients.js +144 -0
  86. package/dist/facet-invocation.d.ts +4 -0
  87. package/dist/facet-invocation.js +45 -0
  88. package/dist/files.d.ts +42 -0
  89. package/dist/files.js +123 -0
  90. package/dist/frame-binding-wire-script.d.ts +2 -0
  91. package/dist/frame-binding-wire-script.js +1 -0
  92. package/dist/frame-binding-wire.d.ts +28 -0
  93. package/dist/frame-binding-wire.js +54 -0
  94. package/dist/git-admission.d.ts +52 -0
  95. package/dist/git-admission.js +188 -0
  96. package/dist/git-auth.d.ts +11 -0
  97. package/dist/git-auth.js +27 -0
  98. package/dist/git-door.d.ts +35 -0
  99. package/dist/git-door.js +108 -0
  100. package/dist/git-journal.d.ts +31 -0
  101. package/dist/git-journal.js +188 -0
  102. package/dist/git.d.ts +31 -0
  103. package/dist/git.js +64 -0
  104. package/dist/guest-policy.d.ts +9 -0
  105. package/dist/guest-policy.js +13 -0
  106. package/dist/host.d.ts +244 -0
  107. package/dist/host.js +1043 -0
  108. package/dist/index.d.ts +166 -0
  109. package/dist/index.js +320 -0
  110. package/dist/installation-consent.d.ts +79 -0
  111. package/dist/installation-consent.js +82 -0
  112. package/dist/internal/background-origins.d.ts +3 -0
  113. package/dist/internal/background-origins.js +8 -0
  114. package/dist/internal/delivery.d.ts +12 -0
  115. package/dist/internal/delivery.js +167 -0
  116. package/dist/internal/host-gate.d.ts +14 -0
  117. package/dist/internal/host-gate.js +62 -0
  118. package/dist/internal/registry-installations.d.ts +6 -0
  119. package/dist/internal/registry-installations.js +12 -0
  120. package/dist/invocation.d.ts +251 -0
  121. package/dist/invocation.js +377 -0
  122. package/dist/keys.d.ts +48 -0
  123. package/dist/keys.js +52 -0
  124. package/dist/mcp-owner.d.ts +27 -0
  125. package/dist/mcp-owner.js +155 -0
  126. package/dist/mcp.d.ts +89 -0
  127. package/dist/mcp.js +429 -0
  128. package/dist/media.d.ts +23 -0
  129. package/dist/media.js +12 -0
  130. package/dist/pack.d.ts +79 -0
  131. package/dist/pack.js +151 -0
  132. package/dist/page/capabilities.d.ts +23 -0
  133. package/dist/page/capabilities.js +256 -0
  134. package/dist/page/computer-handles.d.ts +79 -0
  135. package/dist/page/computer-handles.js +44 -0
  136. package/dist/page/gill-observation.d.ts +4 -0
  137. package/dist/page/gill-observation.js +31 -0
  138. package/dist/page/lifetime.d.ts +6 -0
  139. package/dist/page/lifetime.js +19 -0
  140. package/dist/page/mount.d.ts +163 -0
  141. package/dist/page/mount.js +390 -0
  142. package/dist/page/storage.d.ts +3 -0
  143. package/dist/page/storage.js +82 -0
  144. package/dist/page/terminal.d.ts +5 -0
  145. package/dist/page/terminal.js +7 -0
  146. package/dist/page/window-launch.d.ts +18 -0
  147. package/dist/page/window-launch.js +11 -0
  148. package/dist/page-script.d.ts +14 -0
  149. package/dist/page-script.js +5 -0
  150. package/dist/r2-files.d.ts +3 -0
  151. package/dist/r2-files.js +79 -0
  152. package/dist/release.d.ts +83 -0
  153. package/dist/release.js +167 -0
  154. package/dist/root-data.d.ts +86 -0
  155. package/dist/root-data.js +69 -0
  156. package/dist/shell/app-directory.d.ts +542 -0
  157. package/dist/shell/app-directory.js +199 -0
  158. package/dist/shell/browser-actions.d.ts +7 -0
  159. package/dist/shell/browser-actions.js +56 -0
  160. package/dist/shell/command-host.d.ts +112 -0
  161. package/dist/shell/command-host.js +502 -0
  162. package/dist/shell/commands.d.ts +25 -0
  163. package/dist/shell/commands.js +78 -0
  164. package/dist/shell/index.d.ts +8 -0
  165. package/dist/shell/index.js +8 -0
  166. package/dist/shell/keys.d.ts +41 -0
  167. package/dist/shell/keys.js +134 -0
  168. package/dist/shell/shell-module.d.ts +55 -0
  169. package/dist/shell/shell-module.js +86 -0
  170. package/dist/shell/window-manager.d.ts +124 -0
  171. package/dist/shell/window-manager.js +711 -0
  172. package/dist/shell/workbench-contract.d.ts +68 -0
  173. package/dist/shell/workbench-contract.js +1 -0
  174. package/dist/shell/workbench-directory.d.ts +332 -0
  175. package/dist/shell/workbench-directory.js +35 -0
  176. package/dist/shell/workbench-host-types.d.ts +96 -0
  177. package/dist/shell/workbench-host-types.js +1 -0
  178. package/dist/shell/workbench-host.d.ts +34 -0
  179. package/dist/shell/workbench-host.js +347 -0
  180. package/dist/shell/workbench-model.d.ts +192 -0
  181. package/dist/shell/workbench-model.js +53 -0
  182. package/dist/shell/workbench.d.ts +4 -0
  183. package/dist/shell/workbench.js +2 -0
  184. package/dist/source/fork.d.ts +27 -0
  185. package/dist/source/fork.js +46 -0
  186. package/dist/source/index.d.ts +10 -0
  187. package/dist/source/index.js +10 -0
  188. package/dist/source/seed-receipt.d.ts +53 -0
  189. package/dist/source/seed-receipt.js +18 -0
  190. package/dist/source/team-source.d.ts +32 -0
  191. package/dist/source/team-source.js +42 -0
  192. package/dist/source/template-push.d.ts +33 -0
  193. package/dist/source/template-push.js +223 -0
  194. package/dist/source/template-repository.d.ts +4 -0
  195. package/dist/source/template-repository.js +21 -0
  196. package/dist/source/template-seed.d.ts +68 -0
  197. package/dist/source/template-seed.js +80 -0
  198. package/dist/standalone/agent-directory.d.ts +4 -0
  199. package/dist/standalone/agent-directory.js +4 -0
  200. package/dist/standalone/agents.d.ts +220 -0
  201. package/dist/standalone/agents.js +795 -0
  202. package/dist/standalone/app-builds-binding.d.ts +36 -0
  203. package/dist/standalone/app-builds-binding.js +119 -0
  204. package/dist/standalone/app-set.d.ts +91 -0
  205. package/dist/standalone/app-set.js +395 -0
  206. package/dist/standalone/app-source.d.ts +41 -0
  207. package/dist/standalone/app-source.js +59 -0
  208. package/dist/standalone/builds.d.ts +18 -0
  209. package/dist/standalone/builds.js +101 -0
  210. package/dist/standalone/computer-egress.d.ts +37 -0
  211. package/dist/standalone/computer-egress.js +111 -0
  212. package/dist/standalone/computer.d.ts +122 -0
  213. package/dist/standalone/computer.js +714 -0
  214. package/dist/standalone/install-apps-cli.d.ts +2 -0
  215. package/dist/standalone/install-apps-cli.js +126 -0
  216. package/dist/standalone/instance.d.ts +35 -0
  217. package/dist/standalone/instance.js +74 -0
  218. package/dist/standalone/media.d.ts +76 -0
  219. package/dist/standalone/media.js +227 -0
  220. package/dist/standalone/preview.d.ts +51 -0
  221. package/dist/standalone/preview.js +167 -0
  222. package/dist/standalone/registry.d.ts +102 -0
  223. package/dist/standalone/registry.js +193 -0
  224. package/dist/standalone/tenancy.d.ts +42 -0
  225. package/dist/standalone/tenancy.js +241 -0
  226. package/dist/standalone/worker.d.ts +55 -0
  227. package/dist/standalone/worker.js +147 -0
  228. package/dist/standalone/workflow-authority-readers.d.ts +16 -0
  229. package/dist/standalone/workflow-authority-readers.js +35 -0
  230. package/dist/standalone/workflow-binding.d.ts +216 -0
  231. package/dist/standalone/workflow-binding.js +217 -0
  232. package/dist/standalone/workflow-events.d.ts +46 -0
  233. package/dist/standalone/workflow-events.js +39 -0
  234. package/dist/standalone/workflow-git-capture.d.ts +7 -0
  235. package/dist/standalone/workflow-git-capture.js +62 -0
  236. package/dist/standalone/workflow-host.d.ts +931 -0
  237. package/dist/standalone/workflow-host.js +751 -0
  238. package/dist/standalone/workflow-node-capture.d.ts +13 -0
  239. package/dist/standalone/workflow-node-capture.js +72 -0
  240. package/dist/standalone/workflow-root-authority.d.ts +27 -0
  241. package/dist/standalone/workflow-root-authority.js +87 -0
  242. package/dist/standalone/workflow-schedules.d.ts +52 -0
  243. package/dist/standalone/workflow-schedules.js +40 -0
  244. package/dist/standalone/workflow-trigger-host.d.ts +1694 -0
  245. package/dist/standalone/workflow-trigger-host.js +52 -0
  246. package/dist/standalone/workflows.d.ts +657 -0
  247. package/dist/standalone/workflows.js +554 -0
  248. package/dist/storage-frame.d.ts +64 -0
  249. package/dist/storage-frame.js +28 -0
  250. package/dist/tenancy/auth0.d.ts +64 -0
  251. package/dist/tenancy/auth0.js +198 -0
  252. package/dist/tenancy/cloudflare/rate-limit.d.ts +8 -0
  253. package/dist/tenancy/cloudflare/rate-limit.js +19 -0
  254. package/dist/tenancy/cloudflare/registry.d.ts +50 -0
  255. package/dist/tenancy/cloudflare/registry.js +301 -0
  256. package/dist/tenancy/cloudflare.d.ts +2 -0
  257. package/dist/tenancy/cloudflare.js +2 -0
  258. package/dist/tenancy/cold-directory.d.ts +13 -0
  259. package/dist/tenancy/cold-directory.js +43 -0
  260. package/dist/tenancy/contracts.d.ts +195 -0
  261. package/dist/tenancy/contracts.js +1 -0
  262. package/dist/tenancy/index.d.ts +19 -0
  263. package/dist/tenancy/index.js +156 -0
  264. package/dist/tenancy/owner-key.d.ts +26 -0
  265. package/dist/tenancy/owner-key.js +63 -0
  266. package/dist/tenancy/oyster.d.ts +4 -0
  267. package/dist/tenancy/oyster.js +25 -0
  268. package/dist/tenancy/registry-record.d.ts +7 -0
  269. package/dist/tenancy/registry-record.js +44 -0
  270. package/dist/tenancy/registry.d.ts +27 -0
  271. package/dist/tenancy/registry.js +138 -0
  272. package/dist/tenancy/resolve.d.ts +7 -0
  273. package/dist/tenancy/resolve.js +64 -0
  274. package/dist/tenant.d.ts +81 -0
  275. package/dist/tenant.js +71 -0
  276. package/dist/testing/capabilities.d.ts +29 -0
  277. package/dist/testing/capabilities.js +130 -0
  278. package/dist/testing/catalog.d.ts +3 -0
  279. package/dist/testing/catalog.js +53 -0
  280. package/dist/testing/index.d.ts +10 -0
  281. package/dist/testing/index.js +10 -0
  282. package/dist/testing/installation.d.ts +11 -0
  283. package/dist/testing/installation.js +25 -0
  284. package/dist/testing/native-worker.d.ts +21 -0
  285. package/dist/testing/native-worker.js +106 -0
  286. package/dist/testing/worker.d.ts +18 -0
  287. package/dist/testing/worker.js +67 -0
  288. package/dist/testing/workers-runtime.d.ts +24 -0
  289. package/dist/testing/workers-runtime.js +33 -0
  290. package/dist/webhook-delivery.d.ts +14 -0
  291. package/dist/webhook-delivery.js +17 -0
  292. package/dist/workers-git.d.ts +285 -0
  293. package/dist/workers-git.js +1174 -0
  294. package/dist/workers.d.ts +352 -0
  295. package/dist/workers.js +868 -0
  296. package/docs/api/README.md +82 -0
  297. package/docs/api/agents.md +332 -0
  298. package/docs/api/app-storage.md +209 -0
  299. package/docs/api/apps.md +1375 -0
  300. package/docs/api/auth.md +63 -0
  301. package/docs/api/build-contract.md +1304 -0
  302. package/docs/api/build.md +1712 -0
  303. package/docs/api/cloudflare.md +421 -0
  304. package/docs/api/computer.md +203 -0
  305. package/docs/api/files.md +117 -0
  306. package/docs/api/git.md +470 -0
  307. package/docs/api/host.md +1328 -0
  308. package/docs/api/index.md +430 -0
  309. package/docs/api/invocation.md +738 -0
  310. package/docs/api/keys.md +175 -0
  311. package/docs/api/mcp.md +301 -0
  312. package/docs/api/media.md +40 -0
  313. package/docs/api/modules.md +50 -0
  314. package/docs/api/pack.md +141 -0
  315. package/docs/api/page/mount.md +298 -0
  316. package/docs/api/root-data.md +111 -0
  317. package/docs/api/shell/app-directory.md +599 -0
  318. package/docs/api/shell/command-host.md +224 -0
  319. package/docs/api/shell/commands.md +197 -0
  320. package/docs/api/shell/keys.md +183 -0
  321. package/docs/api/shell/shell-module.md +204 -0
  322. package/docs/api/shell/window-manager.md +267 -0
  323. package/docs/api/shell/workbench-directory.md +119 -0
  324. package/docs/api/shell/workbench.md +205 -0
  325. package/docs/api/shell.md +1915 -0
  326. package/docs/api/tenancy/auth0.md +110 -0
  327. package/docs/api/tenancy/cloudflare.md +221 -0
  328. package/docs/api/tenancy/cold-directory.md +46 -0
  329. package/docs/api/tenancy/owner-key.md +63 -0
  330. package/docs/api/tenancy/registry.md +77 -0
  331. package/docs/api/tenancy/resolve.md +69 -0
  332. package/docs/api/tenancy.md +430 -0
  333. package/docs/api/tenant.md +194 -0
  334. package/docs/api/workers-git.md +1646 -0
  335. package/docs/api/workers.md +1691 -0
  336. package/docs/site/agent-quickstart.mdx +346 -0
  337. package/examples/standalone/worker.ts +7 -0
  338. package/examples/standalone/wrangler.jsonc +82 -0
  339. package/package.json +300 -3
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,126 @@
1
+ #!/usr/bin/env node
2
+ // `oyster install-apps`: seed, build on the Oyster's own Computer, and install
3
+ // the starter Apps (Tourtois, Bonsai, Shed, Inkcap, Trellis, Prints and
4
+ // Grove). Each App comes from its own public repository by default, or from a
5
+ // Botanical checkout with `--from <directory>`.
6
+ //
7
+ // OYSTER_URL=https://… OYSTER_OWNER_KEY=… oyster install-apps
8
+ // [--repositories <base URL>] [--ref <branch or tag>]
9
+ // [--from <checkout directory>] [--concurrency 1-3] [--timings <file>]
10
+ import { execFileSync } from "node:child_process";
11
+ import { mkdtemp, rm, writeFile } from "node:fs/promises";
12
+ import { tmpdir } from "node:os";
13
+ import { join, resolve } from "node:path";
14
+ import process from "node:process";
15
+ import { parseArgs } from "node:util";
16
+ import { defaultStarterBuildConcurrency, installStandaloneAppSet, } from "./app-set.js";
17
+ /** The starter Apps' public source repositories. */
18
+ const defaultRepositories = "https://github.com/fungi-computer";
19
+ const usage = "Usage: oyster install-apps [--repositories <base URL>] [--ref <ref>] [--from <checkout>] [--concurrency 1-3] [--timings <file>]";
20
+ function seconds(milliseconds) {
21
+ return `${(milliseconds / 1000).toFixed(1)}s`;
22
+ }
23
+ function timingTable(results) {
24
+ const rows = results.map(({ installationId, timings }) => [
25
+ installationId,
26
+ seconds(timings.fetch),
27
+ seconds(timings.publish),
28
+ seconds(timings.queue),
29
+ seconds(timings.build),
30
+ timings.computer === null ? "-" : seconds(timings.computer.clone),
31
+ timings.computer === null ? "-" : seconds(timings.computer.install),
32
+ timings.computer === null ? "-" : seconds(timings.computer.build),
33
+ timings.computer === null ? "-" : seconds(timings.computer.upload),
34
+ seconds(timings.install),
35
+ ]);
36
+ const header = [
37
+ "App",
38
+ "fetch",
39
+ "seed",
40
+ "queue",
41
+ "build",
42
+ "clone",
43
+ "deps",
44
+ "compile",
45
+ "upload",
46
+ "install",
47
+ ];
48
+ return [header, ...rows].map((row) => row.join("\t")).join("\n");
49
+ }
50
+ async function installApps(args) {
51
+ const { values } = parseArgs({
52
+ args: [...args],
53
+ options: {
54
+ repositories: { type: "string" },
55
+ ref: { type: "string" },
56
+ from: { type: "string" },
57
+ concurrency: { type: "string" },
58
+ timings: { type: "string" },
59
+ },
60
+ strict: true,
61
+ });
62
+ const url = process.env.OYSTER_URL;
63
+ const key = process.env.OYSTER_OWNER_KEY;
64
+ if (!url || !key)
65
+ throw new Error("Set OYSTER_URL and OYSTER_OWNER_KEY");
66
+ if (values.from !== undefined && values.repositories !== undefined)
67
+ throw new Error("Choose either --from or --repositories");
68
+ const concurrency = values.concurrency === undefined
69
+ ? defaultStarterBuildConcurrency
70
+ : Number(values.concurrency);
71
+ const scratch = await mkdtemp(join(tmpdir(), "oyster-install-apps-"));
72
+ try {
73
+ let source;
74
+ if (values.from === undefined)
75
+ source = {
76
+ kind: "repositories",
77
+ base: (values.repositories ?? defaultRepositories).replace(/\/+$/u, ""),
78
+ ref: values.ref ?? "main",
79
+ scratch,
80
+ };
81
+ else {
82
+ const directory = resolve(values.from);
83
+ const revision = execFileSync("git", ["rev-parse", "HEAD"], {
84
+ cwd: directory,
85
+ encoding: "utf8",
86
+ }).trim();
87
+ source = { kind: "checkout", directory, revision: `git:${revision}` };
88
+ }
89
+ const started = performance.now();
90
+ const results = await installStandaloneAppSet({
91
+ source,
92
+ url,
93
+ key,
94
+ concurrency,
95
+ report: (message) => {
96
+ process.stdout.write(`${message}\n`);
97
+ },
98
+ });
99
+ const elapsed = performance.now() - started;
100
+ process.stdout.write(`\n${timingTable(results)}\n`);
101
+ process.stdout.write(`\nInstalled ${String(results.length)} Apps in ${seconds(elapsed)}. Open ${url}/ to use Tourtois and the installed Apps.\n`);
102
+ if (values.timings !== undefined)
103
+ await writeFile(values.timings, JSON.stringify({
104
+ concurrency,
105
+ elapsedMs: elapsed,
106
+ apps: results.map(({ installationId, jobId, timings }) => ({
107
+ installationId,
108
+ jobId,
109
+ timings,
110
+ })),
111
+ }, null, 2) + "\n");
112
+ }
113
+ finally {
114
+ await rm(scratch, { recursive: true, force: true });
115
+ }
116
+ }
117
+ const [command, ...rest] = process.argv.slice(2);
118
+ if (command !== "install-apps") {
119
+ process.stderr.write(`${usage}\n`);
120
+ process.exitCode = 2;
121
+ }
122
+ else
123
+ await installApps(rest).catch((cause) => {
124
+ process.stderr.write(`${cause instanceof Error ? cause.message : String(cause)}\n`);
125
+ process.exitCode = 1;
126
+ });
@@ -0,0 +1,35 @@
1
+ import { type OysterBindingTable } from "../workers.js";
2
+ import { OysterGitInstance, OysterWebhooks, type HostRecipientEvent, type OysterGitWorkerEnv } from "../workers-git.js";
3
+ import { type StandaloneAgentsEnv } from "./agents.js";
4
+ import { type StandaloneComputerEnv } from "./computer.js";
5
+ import { type OysterMediaEnv } from "./media.js";
6
+ import { type AppSourceBindingEnv } from "./app-source.js";
7
+ import { type WorkflowBindingEnv, type WorkflowEventEnv, type WorkflowGitPassEnv } from "./workflow-binding.js";
8
+ export type StandaloneInstanceEnv = OysterGitWorkerEnv & WorkflowBindingEnv & WorkflowEventEnv & WorkflowGitPassEnv & StandaloneComputerEnv & StandaloneAgentsEnv & OysterMediaEnv & AppSourceBindingEnv;
9
+ /** Git and Events plus the declared Computer, Media, Workflow, Agent and App
10
+ * source bindings. */
11
+ export declare const standaloneBindings: OysterBindingTable<StandaloneInstanceEnv>;
12
+ declare const OysterBinding_base: abstract new (ctx: ExecutionContext, env: StandaloneInstanceEnv) => CloudflareWorkersModule.WorkerEntrypoint<StandaloneInstanceEnv, Readonly<{
13
+ instanceId: string;
14
+ binding: import("@fungi.computer/puffball/app").AppBackendBindingName;
15
+ frameId: string;
16
+ }>>;
17
+ /** The standalone root's one guest binding entrypoint, over `standaloneBindings`. */
18
+ export declare class OysterBinding extends OysterBinding_base {
19
+ }
20
+ /** The standalone Instance serves `standaloneBindings`; its root names `hostFor`. */
21
+ export declare abstract class StandaloneInstance<Env extends StandaloneInstanceEnv = StandaloneInstanceEnv> extends OysterGitInstance<Env> {
22
+ protected readonly bindings: OysterBindingTable<Env>;
23
+ }
24
+ /**
25
+ * The tenant's event delivery owner, whose host recipients are Workflows
26
+ * libraries. A library that is down keeps its own row pending and retried, or
27
+ * failed after the last retry; the emitting App's write has already returned.
28
+ */
29
+ export declare class StandaloneEventDelivery extends OysterWebhooks<WorkflowEventEnv> {
30
+ protected deliverToRecipient(delivery: Readonly<{
31
+ recipient: string;
32
+ event: HostRecipientEvent;
33
+ }>): Promise<void>;
34
+ }
35
+ export {};
@@ -0,0 +1,74 @@
1
+ import { AppInstanceError } from "../index.js";
2
+ import { oysterBindingEntrypoint, } from "../workers.js";
3
+ import { OysterGitInstance, OysterWebhooks, eventsBindingFor, gitBindings, } from "../workers-git.js";
4
+ import { agentFrameMethods, dispatchAgentBinding, } from "./agents.js";
5
+ import { computerFrameMethods, computerInvocation, standaloneWorkspace, } from "./computer.js";
6
+ import { dispatchMediaBinding, mediaFrameMethods, } from "./media.js";
7
+ import { appSourceFrameMethods, dispatchAppSourceBinding, } from "./app-source.js";
8
+ import { workflowFrameMethods, dispatchWorkflowBinding, deliverWorkflowEvent, openWorkflowGitPass, workflowEventRecipients, } from "./workflow-binding.js";
9
+ import { appsFrameMethods, dispatchAppsBuildsBinding, } from "./app-builds-binding.js";
10
+ /** Git and Events plus the declared Computer, Media, Workflow, Agent and App
11
+ * source bindings. */
12
+ export const standaloneBindings = {
13
+ ...gitBindings,
14
+ /** Catalog and fork are source operations; build, status and select
15
+ * run on this Oyster's Computer and installations. */
16
+ APPS: {
17
+ methods: { ...appSourceFrameMethods.APPS, ...appsFrameMethods.APPS },
18
+ dispatch: (context, frame, props, method, args) => Object.hasOwn(appSourceFrameMethods.APPS, method)
19
+ ? dispatchAppSourceBinding(context.env, context.scope(), frame, method, args)
20
+ : dispatchAppsBuildsBinding(context.env, context.scope(), frame, props, method, args, context.backgroundHost),
21
+ },
22
+ COMPUTER: {
23
+ methods: computerFrameMethods.COMPUTER,
24
+ async dispatch(context, frame, _props, method, args) {
25
+ if (method !== "workflowGitPass")
26
+ return computerInvocation(context.env, frame, method, args);
27
+ // A published Workflow Git step's pass, minted by the library that runs it.
28
+ const host = await context.backgroundHost();
29
+ if (host === null)
30
+ throw new AppInstanceError("revoked");
31
+ return openWorkflowGitPass(context.env, host.installations, frame, args);
32
+ },
33
+ },
34
+ MEDIA: {
35
+ methods: mediaFrameMethods.MEDIA,
36
+ dispatch: (context, frame, props, method, args) => dispatchMediaBinding(context.env, frame, props, method, args, standaloneWorkspace(context.env)),
37
+ },
38
+ WORKFLOWS: {
39
+ methods: workflowFrameMethods.WORKFLOWS,
40
+ dispatch: (context, frame, props, method, args) => dispatchWorkflowBinding(context.env, frame, props, method, args),
41
+ },
42
+ INBOX: {
43
+ methods: agentFrameMethods.INBOX,
44
+ dispatch: (context, frame, props, method, args) => dispatchAgentBinding(context.env, context.scope(), frame, props, method, args),
45
+ },
46
+ AGENTS: {
47
+ methods: agentFrameMethods.AGENTS,
48
+ dispatch: (context, frame, props, method, args) => dispatchAgentBinding(context.env, context.scope(), frame, props, method, args),
49
+ },
50
+ /** The emit commits to the delivery owner; Workflows libraries receive it afterwards. */
51
+ EVENTS: eventsBindingFor(async (context) => {
52
+ const host = await context.backgroundHost();
53
+ if (host === null)
54
+ throw new AppInstanceError("revoked");
55
+ return workflowEventRecipients(host.installations);
56
+ }),
57
+ };
58
+ /** The standalone root's one guest binding entrypoint, over `standaloneBindings`. */
59
+ export class OysterBinding extends oysterBindingEntrypoint(standaloneBindings) {
60
+ }
61
+ /** The standalone Instance serves `standaloneBindings`; its root names `hostFor`. */
62
+ export class StandaloneInstance extends OysterGitInstance {
63
+ bindings = standaloneBindings;
64
+ }
65
+ /**
66
+ * The tenant's event delivery owner, whose host recipients are Workflows
67
+ * libraries. A library that is down keeps its own row pending and retried, or
68
+ * failed after the last retry; the emitting App's write has already returned.
69
+ */
70
+ export class StandaloneEventDelivery extends OysterWebhooks {
71
+ deliverToRecipient(delivery) {
72
+ return deliverWorkflowEvent(this.env, delivery.recipient, delivery.event);
73
+ }
74
+ }
@@ -0,0 +1,76 @@
1
+ import type { FrameBindingProps } from "../cloudflare.js";
2
+ import type { InvocationFrame } from "../invocation.js";
3
+ import type { OysterBindingResult } from "../workers.js";
4
+ import * as Schema from "effect/Schema";
5
+ import { type MediaServiceHost } from "@fungi.computer/darkroom/server";
6
+ import { type MediaAiPort, type MediaImagePort } from "@fungi.computer/darkroom/cloudflare";
7
+ import { type OysterCapability } from "../host.js";
8
+ import type { FileSource } from "../files.js";
9
+ /** Bindings for Media generation into the standalone Oyster workspace. */
10
+ export type OysterMediaEnv = Readonly<{
11
+ /** Workers AI provider, admitted by this Worker. */
12
+ AI: MediaAiPort;
13
+ /** Darkroom's durable operation namespace. */
14
+ MEDIA_OPERATION: MediaServiceHost["operations"];
15
+ /** Native image decoding and bounded reference fitting. */
16
+ IMAGES?: MediaImagePort;
17
+ /** The AI Gateway third-party models (GPT Image 2, Seedance, Veo) route
18
+ * through. The background retry owner already reads this same binding
19
+ * name for its own provider, so one var wires both doors. */
20
+ AI_GATEWAY_ID?: string;
21
+ }>;
22
+ /** Media capability using Darkroom execution and the existing workspace FileSource. */
23
+ export declare function workersMedia(env: OysterMediaEnv, workspace: Readonly<{
24
+ computerId: string;
25
+ files: FileSource;
26
+ }>): readonly OysterCapability[];
27
+ /** The Instance gate and native guest entrypoint share these argument codecs. */
28
+ export declare const mediaFrameMethods: {
29
+ MEDIA: {
30
+ [k: string]: {
31
+ decodeArgs: (raw: readonly unknown[]) => [Record<string, never> | {
32
+ kind: "image";
33
+ requestId: string;
34
+ libraryPath: string;
35
+ settings: {
36
+ width: number;
37
+ height: number;
38
+ model: string;
39
+ prompt: string;
40
+ resolution?: "480p" | "720p" | "768p" | "1080p" | "4k" | undefined;
41
+ aspectRatio?: "16:9" | "4:3" | "1:1" | "3:4" | "9:16" | "21:9" | "9:21" | undefined;
42
+ references?: {
43
+ path: string;
44
+ role?: "first-frame" | "last-frame" | "reference" | undefined;
45
+ }[] | undefined;
46
+ generateAudio?: boolean | undefined;
47
+ steps?: number | undefined;
48
+ };
49
+ outputFormat?: "png" | "jpeg" | "webp" | undefined;
50
+ } | {
51
+ kind: "video";
52
+ requestId: string;
53
+ libraryPath: string;
54
+ settings: {
55
+ model: "bytedance/seedance-2.0" | "google/veo-3.1" | "bytedance/seedance-2.0-fast" | "bytedance/seedance-2.0-mini" | "google/veo-3.1-fast" | "minimax/h3-max";
56
+ prompt: string;
57
+ resolution?: "480p" | "720p" | "768p" | "1080p" | "4k" | undefined;
58
+ aspectRatio?: "16:9" | "4:3" | "1:1" | "3:4" | "9:16" | "21:9" | "9:21" | undefined;
59
+ durationSeconds?: number | undefined;
60
+ generateAudio?: boolean | undefined;
61
+ references?: {
62
+ path: string;
63
+ role: "first-frame" | "last-frame" | "reference";
64
+ }[] | undefined;
65
+ };
66
+ }];
67
+ decodeResult: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => Schema.Json;
68
+ requiredOperations: () => string[];
69
+ };
70
+ };
71
+ };
72
+ /** Called only after the Instance resolves the captured frame and current grants. */
73
+ export declare function dispatchMediaBinding(env: OysterMediaEnv, frame: InvocationFrame, props: FrameBindingProps, method: string, args: readonly unknown[], workspace: Readonly<{
74
+ computerId: string;
75
+ files: FileSource;
76
+ }>): Promise<OysterBindingResult>;
@@ -0,0 +1,227 @@
1
+ import { z } from "zod";
2
+ import { MAX_REFERENCE_BYTES, MediaSettingsError, } from "@fungi.computer/darkroom";
3
+ import { AppInstanceError } from "../index.js";
4
+ import { readMediaFailure } from "@fungi.computer/darkroom/browser";
5
+ import { appMediaGenerationResultSchema } from "@fungi.computer/darkroom/app-media-contracts";
6
+ import { mediaSlot } from "../media.js";
7
+ import { Hono } from "hono";
8
+ import * as Schema from "effect/Schema";
9
+ import { pendingSchema } from "@fungi.computer/agar/backend-definition";
10
+ import { mediaGenerationDescriptionSchema, mediaGenerationJsonRequestSchema, mediaGenerationReferenceSchema, } from "@fungi.computer/agar/media-json";
11
+ import { createMediaService, mediaPendingSchema, mediaResultSchema, mediaBindingCallSchema, mediaBindingRequest, parseMediaBindingCall, readMediaBindingReply, } from "@fungi.computer/darkroom/server";
12
+ import { createWorkersAiMediaProvider, createImagesReferenceFitter, } from "@fungi.computer/darkroom/cloudflare";
13
+ import { oysterPrincipalId, } from "../host.js";
14
+ import { normalizeFilePath } from "../files.js";
15
+ /** Media capability using Darkroom execution and the existing workspace FileSource. */
16
+ export function workersMedia(env, workspace) {
17
+ const { computerId } = workspace;
18
+ const routes = new Hono();
19
+ const service = (principal) => standaloneMediaService(env, oysterPrincipalId(principal), workspace);
20
+ routes.get("/describe", async (context) => {
21
+ const response = await service(context.env.principal).request("http://media/models");
22
+ return context.json(Schema.decodeUnknownSync(mediaGenerationDescriptionSchema)({
23
+ computerId,
24
+ canGenerate: true,
25
+ models: await response.json(),
26
+ }));
27
+ });
28
+ routes.post("/generate", async (context) => {
29
+ const input = Schema.decodeUnknownOption(Schema.fromJsonString(mediaGenerationJsonRequestSchema), { onExcessProperty: "error" })(await context.req.text());
30
+ if (input._tag === "None")
31
+ return context.json(invalidRequest());
32
+ const path = normalizeFilePath(input.value.destination.path);
33
+ if (path === null || path === "/")
34
+ return context.json(invalidRequest());
35
+ const references = input.value.settings.references?.map((reference) => ({
36
+ ...reference,
37
+ computerId,
38
+ path: normalizeFilePath(reference.path),
39
+ }));
40
+ if (references?.some((reference) => reference.path === null || reference.path === "/"))
41
+ return context.json(invalidRequest());
42
+ const response = await service(context.env.principal).request("http://media/generate", {
43
+ method: "POST",
44
+ signal: context.req.raw.signal,
45
+ headers: {
46
+ "Content-Type": "application/json",
47
+ "X-Request-Id": input.value.requestId,
48
+ },
49
+ body: JSON.stringify({
50
+ path,
51
+ settings: { ...input.value.settings, references },
52
+ }),
53
+ });
54
+ if (!response.ok) {
55
+ const failure = await readMediaFailure(response);
56
+ return context.json({
57
+ kind: "failed",
58
+ failure: failure === null
59
+ ? {
60
+ message: "Invalid media service response",
61
+ code: "PROTOCOL",
62
+ retryable: false,
63
+ }
64
+ : {
65
+ message: failure.error,
66
+ code: failure.code,
67
+ stage: failure.stage,
68
+ retryable: failure.retryable,
69
+ },
70
+ });
71
+ }
72
+ if (response.status === 202) {
73
+ const pending = mediaPendingSchema.parse(await response.json());
74
+ return context.json(pendingSchema.parse({
75
+ kind: "pending",
76
+ retryAfterMs: pending.retryAfterSeconds * 1_000,
77
+ }));
78
+ }
79
+ const { path: destination, ...result } = mediaResultSchema.parse(await response.json());
80
+ return context.json({
81
+ kind: "succeeded",
82
+ result: {
83
+ ...result,
84
+ destination: { computerId, path: destination },
85
+ },
86
+ });
87
+ });
88
+ routes.post("/cancel-attempt", async (context) => {
89
+ const reference = Schema.decodeUnknownOption(Schema.fromJsonString(mediaGenerationReferenceSchema), { onExcessProperty: "error" })(await context.req.text());
90
+ if (reference._tag === "None" || reference.value.computerId !== computerId)
91
+ return context.json({ error: "Invalid workspace media reference" }, 400);
92
+ // The page aborts its active requests. Durable generation remains restorable.
93
+ return context.json(null);
94
+ });
95
+ return [
96
+ {
97
+ ...mediaSlot,
98
+ permission: "media.generation",
99
+ routes,
100
+ },
101
+ ];
102
+ }
103
+ function invalidRequest() {
104
+ return {
105
+ kind: "failed",
106
+ failure: {
107
+ message: "Invalid workspace media request",
108
+ stage: "settings",
109
+ code: "INVALID_ARGUMENT",
110
+ retryable: false,
111
+ },
112
+ };
113
+ }
114
+ function workspacePath(path) {
115
+ const normalized = normalizeFilePath(path);
116
+ if (normalized === null || normalized === "/")
117
+ throw new Error("Media destination must be an absolute workspace file path");
118
+ return normalized;
119
+ }
120
+ /** Both the HTTP capability and guest binding construct the existing Darkroom service. */
121
+ function standaloneMediaService(env, actorId, workspace, owner = "owner", libraryPath) {
122
+ const { computerId, files } = workspace;
123
+ const fit = env.IMAGES === undefined
124
+ ? undefined
125
+ : createImagesReferenceFitter(env.IMAGES);
126
+ const destination = {
127
+ authorize: async (path) => {
128
+ workspacePath(path);
129
+ if (libraryPath !== undefined)
130
+ await files.mkdir(workspacePath(libraryPath));
131
+ },
132
+ write: (path, bytes) => files.write(workspacePath(path), bytes),
133
+ };
134
+ const admittedDestination = fit === undefined
135
+ ? destination
136
+ : {
137
+ ...destination,
138
+ readReference: async (reference) => {
139
+ if (reference.computerId !== computerId)
140
+ throw new MediaSettingsError("reference Computer is not selected");
141
+ const bytes = await files.read(workspacePath(reference.path));
142
+ if (bytes === null ||
143
+ bytes.byteLength === 0 ||
144
+ bytes.byteLength > MAX_REFERENCE_BYTES)
145
+ throw new MediaSettingsError("reference image is unavailable or exceeds the byte limit");
146
+ return {
147
+ ...(await fit(bytes)),
148
+ filename: reference.path.split("/").at(-1) ?? "reference",
149
+ };
150
+ },
151
+ };
152
+ return createMediaService({
153
+ scope: { actorId, namespace: "oyster", owner, destinationId: computerId },
154
+ operations: env.MEDIA_OPERATION,
155
+ provider: createWorkersAiMediaProvider(env.AI, env.AI_GATEWAY_ID === undefined
156
+ ? undefined
157
+ : { gateway: { id: env.AI_GATEWAY_ID } }),
158
+ metering: "unmetered",
159
+ destination: admittedDestination,
160
+ });
161
+ }
162
+ /** The Instance gate and native guest entrypoint share these argument codecs. */
163
+ export const mediaFrameMethods = {
164
+ MEDIA: Object.fromEntries(["models", "generate"].map((method) => [
165
+ method,
166
+ {
167
+ decodeArgs: (raw) => z
168
+ .tuple([
169
+ mediaBindingCallSchema.options[method === "models" ? 0 : 1].shape
170
+ .input,
171
+ ])
172
+ .parse(raw),
173
+ decodeResult: Schema.decodeUnknownSync(Schema.Json),
174
+ requiredOperations: () => [method],
175
+ },
176
+ ])),
177
+ };
178
+ /** Called only after the Instance resolves the captured frame and current grants. */
179
+ export async function dispatchMediaBinding(env, frame, props, method, args, workspace) {
180
+ frame.signal.throwIfAborted();
181
+ if (props.binding !== "MEDIA" ||
182
+ frame.facts.subject.kind !== "call" ||
183
+ frame.facts.selection.owner.kind !== "installation")
184
+ throw new AppInstanceError("revoked");
185
+ const caller = frame.facts.subject.context;
186
+ if (caller.computerId !== workspace.computerId ||
187
+ caller.actor.kind === "team-key")
188
+ throw new AppInstanceError("revoked");
189
+ const parsed = parseMediaBindingCall(Schema.decodeUnknownSync(Schema.Json)({
190
+ operation: method,
191
+ input: args[0],
192
+ }));
193
+ if (parsed.kind === "refused")
194
+ return Schema.decodeUnknownSync(Schema.Json)(parsed.result);
195
+ const actorId = caller.actor.kind === "member"
196
+ ? caller.actor.memberId
197
+ : caller.actor.agentId;
198
+ const input = parsed.call;
199
+ const service = standaloneMediaService(env, actorId, workspace, frame.facts.selection.owner.id, input.operation === "generate" ? input.input.libraryPath : undefined);
200
+ let response;
201
+ if (input.operation === "models")
202
+ response = await service.request("/models");
203
+ else {
204
+ const body = mediaBindingRequest(input.input, workspace.computerId);
205
+ const generated = await service.request("/generate", {
206
+ method: "POST",
207
+ signal: frame.signal,
208
+ headers: {
209
+ "Content-Type": "application/json",
210
+ "X-Request-Id": input.input.requestId,
211
+ },
212
+ body: JSON.stringify(body),
213
+ });
214
+ if (generated.ok && generated.status !== 202) {
215
+ const result = mediaResultSchema.parse(await generated.json());
216
+ const { path, ...saved } = result;
217
+ response = Response.json(appMediaGenerationResultSchema.parse({
218
+ ...saved,
219
+ destination: { computerId: workspace.computerId, path },
220
+ }));
221
+ }
222
+ else
223
+ response = generated;
224
+ }
225
+ frame.signal.throwIfAborted();
226
+ return Schema.decodeUnknownSync(Schema.Json)(await readMediaBindingReply(input, workspace.computerId, response));
227
+ }
@@ -0,0 +1,51 @@
1
+ import * as Schema from "effect/Schema";
2
+ import { ComputerPortPreview } from "@fungi.computer/computer/preview";
3
+ export declare const previewSelectorSchema: Schema.Struct<{
4
+ readonly ownerId: Schema.NonEmptyString;
5
+ readonly installationId: Schema.NonEmptyString;
6
+ readonly selection: Schema.Struct<{
7
+ readonly instanceId: Schema.Codec<import("../index.js").InstanceId, string, never, never>;
8
+ readonly owner: Schema.Struct<{
9
+ readonly kind: Schema.Literals<readonly ["installation", "deployment"]>;
10
+ readonly id: Schema.NonEmptyString;
11
+ }>;
12
+ readonly appId: Schema.refine<import("@fungi.computer/puffball").AppId, Schema.String>;
13
+ readonly releaseId: Schema.refine<import("@fungi.computer/puffball").ReleaseId, Schema.String>;
14
+ readonly authorityVersion: Schema.Number;
15
+ }>;
16
+ readonly artifactDigest: Schema.refine<import("@fungi.computer/puffball").Sha256Digest, Schema.String>;
17
+ }>;
18
+ export type PreviewSelector = Schema.Schema.Type<typeof previewSelectorSchema>;
19
+ export type PreviewOrigins = Readonly<{
20
+ owner: string;
21
+ preview: string;
22
+ }>;
23
+ export type StandalonePreviewEnv = Readonly<{
24
+ OYSTER_ORIGIN?: string;
25
+ OYSTER_PREVIEW_ORIGIN?: string;
26
+ }>;
27
+ export declare function previewOrigins(env: StandalonePreviewEnv): PreviewOrigins | null;
28
+ /**
29
+ * The native Computer's preview port. `current` re-proves the selector's
30
+ * owner and Installation against live authority before every issue and
31
+ * every forwarded request.
32
+ */
33
+ export type PreviewNative = Readonly<{
34
+ current: (selector: PreviewSelector) => Promise<void>;
35
+ accept: (selector: PreviewSelector) => void;
36
+ list: (accept: () => void) => Promise<{
37
+ ports: number[];
38
+ }>;
39
+ forward: (port: number, request: Request, accept: () => void) => Promise<Response>;
40
+ }>;
41
+ export declare class PreviewRefused extends Error {
42
+ }
43
+ export declare function createStandalonePreview(storage: ConstructorParameters<typeof ComputerPortPreview>[0], computerId: string, origin: string, native: PreviewNative): {
44
+ issue(selector: PreviewSelector, port: number): Promise<{
45
+ previewUrl: string;
46
+ expiresAt: number;
47
+ }>;
48
+ fetch(signature: string, port: number, request: Request): Promise<Response>;
49
+ };
50
+ export declare function passivePreviewResponse(response: Response): Promise<Response>;
51
+ export declare function standalonePreviewRequest(request: Request, env: StandalonePreviewEnv, computerId: string, forward: (signature: string, port: number, request: Request) => Promise<Response>): Promise<Response | null>;