@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,163 @@
1
+ import { type AppOpenInput, type AppRoleChoice } from "@fungi.computer/agar/apps";
2
+ import * as Schema from "effect/Schema";
3
+ import { type AppHost, type AppHostLaunch, type AppHostHandlers } from "@fungi.computer/agar/host";
4
+ import type { WhistleJsonValue } from "@fungi.computer/whistle";
5
+ /** Current server-admitted configuration for one installed App page. */
6
+ export declare const oysterAppConfigSchema: Schema.Struct<{
7
+ readonly workbench: Schema.Boolean;
8
+ /** The home shell Release's own module, imported top-level; null if it ships none. */
9
+ readonly shellModuleUrl: Schema.NullOr<Schema.String>;
10
+ readonly storage: Schema.Boolean;
11
+ /** The Release declares `apps.open`; only an embedding shell can serve it. */
12
+ readonly appsOpen: Schema.Boolean;
13
+ readonly computerId: Schema.NullOr<Schema.String>;
14
+ readonly authorityVersion: Schema.Int;
15
+ readonly commands: Schema.$Array<Schema.Codec<Readonly<{
16
+ id: string;
17
+ title: string;
18
+ category: string;
19
+ description?: string | undefined;
20
+ sigil?: string | undefined;
21
+ projections?: Readonly<{
22
+ bindings?: (Readonly<{
23
+ order?: number | undefined;
24
+ }> & Readonly<{
25
+ values: readonly string[];
26
+ }>) | undefined;
27
+ agent?: (Readonly<{
28
+ order?: number | undefined;
29
+ }> & Readonly<{
30
+ keybind?: string | undefined;
31
+ }>) | undefined;
32
+ help?: Readonly<{
33
+ order
34
+ /** Role and App opens, routed by the embedding shell; the App never names a surface. */
35
+ ? /** Role and App opens, routed by the embedding shell; the App never names a surface. */: number | undefined;
36
+ }> | undefined;
37
+ menu?: Readonly<{
38
+ order?: number | undefined;
39
+ }> | undefined;
40
+ palette?: Readonly<{
41
+ order?: number | undefined;
42
+ }> | undefined;
43
+ slash?: (Readonly<{
44
+ order?: number | undefined;
45
+ }> & Readonly<{
46
+ aliases: readonly string[];
47
+ }>) | undefined;
48
+ }> | undefined;
49
+ }>, Readonly<{
50
+ id: string;
51
+ title: string;
52
+ category: string;
53
+ description?: string | undefined;
54
+ sigil?: string | undefined;
55
+ projections?: Readonly<{
56
+ bindings?: (Readonly<{
57
+ order?: number | undefined;
58
+ }> & Readonly<{
59
+ values: readonly string[];
60
+ }>) | undefined;
61
+ agent?: (Readonly<{
62
+ order?: number | undefined;
63
+ }> & Readonly<{
64
+ keybind?: string | undefined;
65
+ }>) | undefined;
66
+ help?: Readonly<{
67
+ order
68
+ /** Role and App opens, routed by the embedding shell; the App never names a surface. */
69
+ ? /** Role and App opens, routed by the embedding shell; the App never names a surface. */: number | undefined;
70
+ }> | undefined;
71
+ menu?: Readonly<{
72
+ order?: number | undefined;
73
+ }> | undefined;
74
+ palette?: Readonly<{
75
+ order?: number | undefined;
76
+ }> | undefined;
77
+ slash?: (Readonly<{
78
+ order?: number | undefined;
79
+ }> & Readonly<{
80
+ aliases: readonly string[];
81
+ }>) | undefined;
82
+ }> | undefined;
83
+ }>, never, never>>;
84
+ readonly icon: Schema.NullOr<Schema.String>;
85
+ readonly roles: Schema.$Array<Schema.String>;
86
+ readonly installationId: Schema.String;
87
+ readonly appId: Schema.String;
88
+ readonly releaseId: Schema.String;
89
+ readonly uiUrl: Schema.String;
90
+ readonly backendUrl: Schema.String;
91
+ readonly methodsUrl: Schema.String;
92
+ readonly capabilities: Schema.$Array<Schema.Struct<{
93
+ readonly id: Schema.String;
94
+ readonly version: Schema.Number;
95
+ readonly base: Schema.String;
96
+ readonly methods: Schema.$Record<Schema.String, Schema.Union<readonly [Schema.Struct<{
97
+ readonly kind: Schema.Literal<"transport">;
98
+ readonly method: Schema.Literals<readonly ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "ANY"]>;
99
+ readonly path: Schema.String;
100
+ }>, Schema.Struct<{
101
+ readonly kind: Schema.Literals<readonly ["json", "read", "write"]>;
102
+ readonly method: Schema.Literals<readonly ["GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS"]>;
103
+ readonly path: Schema.String;
104
+ }>]>>;
105
+ }>>;
106
+ }>;
107
+ /** Role and App opens, routed by the embedding shell; the App never names a surface. */
108
+ export type OysterAppOpenRouting = Readonly<{
109
+ /** Open the declared intent through the App the Team chose for its role. */
110
+ open(input: AppOpenInput): Promise<void>;
111
+ /** Which App that role's open would reach, or null when none fills it. */
112
+ role(role: string): Promise<AppRoleChoice>;
113
+ }>;
114
+ /** Read the server-admitted configuration this page was served with. */
115
+ export declare function readOysterPageConfig(): OysterAppConfig;
116
+ /** Apply this host's shared page styles and the person's color theme. */
117
+ export declare function applyOysterPageTheme(): "mocha" | "latte";
118
+ /**
119
+ * The home installation's own storage and methods, for the trusted shell the
120
+ * host composes into this document. They reach the same admitted routes an
121
+ * isolated App would, without a frame between the shell and its host.
122
+ */
123
+ export declare function oysterShellHandles(config: OysterAppConfig): {
124
+ storage: Readonly<{
125
+ read(key: string): Promise<import("@fungi.computer/agar").ResolvedAppStorage>;
126
+ write(input: import("@fungi.computer/agar").AppStorageWrite): Promise<{
127
+ revision: number;
128
+ }>;
129
+ reset(input: import("@fungi.computer/agar").AppStorageReset): Promise<{
130
+ revision: number;
131
+ }>;
132
+ watch(key: string): Promise<import("@fungi.computer/agar").AppStorageWatch>;
133
+ }> | null;
134
+ methods: {
135
+ call(method: string, input: string): Promise<WhistleJsonValue>;
136
+ };
137
+ };
138
+ /**
139
+ * Mount one installed App's own page: its sandboxed frame and nothing else.
140
+ * Desktop chrome (menus, palette, status) belongs to the trusted shell.
141
+ */
142
+ export declare function mountOysterPage(): Promise<AppHost>;
143
+ /** The host-admitted App configuration served by Oyster. */
144
+ export type OysterAppConfig = typeof oysterAppConfigSchema.Type;
145
+ /** One isolated App connection, with the slots this host admitted for it. */
146
+ export type OysterAppConnectionOptions = Readonly<{
147
+ config: OysterAppConfig;
148
+ frame: HTMLIFrameElement;
149
+ signal: AbortSignal;
150
+ handlers: AppHostHandlers;
151
+ /** Present only where a shell can route opens; used when the Release declares `apps.open`. */
152
+ appOpen?: OysterAppOpenRouting;
153
+ openRequest?: AppHostLaunch["context"]["value"]["openRequest"];
154
+ surfaceId?: string;
155
+ reservedChords: readonly import("@fungi.computer/agar/host").AppHostReservedChord[];
156
+ theme: string;
157
+ }>;
158
+ /** Connect a child or home App using the same admitted Oyster slot handles. */
159
+ export declare function connectOysterApp(options: OysterAppConnectionOptions): Promise<AppHost>;
160
+ export { oysterStorageHandle } from "./storage.js";
161
+ export { appSandbox } from "../app-sandbox.js";
162
+ /** Resolve only the slots admitted for this installation by its current host. */
163
+ export declare function oysterAppCapabilities(options: Pick<OysterAppConnectionOptions, "config" | "signal" | "appOpen">): Promise<AppHostLaunch["capabilities"]>;
@@ -0,0 +1,390 @@
1
+ import { appOpenInputSchema, appsCall, appsOpen, } from "@fungi.computer/agar/apps";
2
+ import { appApiMethodNameSchema } from "@fungi.computer/puffball/app";
3
+ import { appIdSchema } from "@fungi.computer/puffball/effect";
4
+ import { createBrowserActionHandler } from "../shell/browser-actions.js";
5
+ import { createAppSurfaceCommandHost } from "../shell/command-host.js";
6
+ // App page: mounts one installed App's sandboxed frame and gives it the
7
+ // capabilities this Oyster host provides. Bundled into `shellScript`.
8
+ import { RpcTarget } from "@fungi.computer/capnweb";
9
+ import { createPageLifetime } from "./lifetime.js";
10
+ import * as Schema from "effect/Schema";
11
+ import { AppError } from "@fungi.computer/agar";
12
+ import { appStorage } from "@fungi.computer/agar/storage";
13
+ import { oysterStorageHandle } from "./storage.js";
14
+ import { appBackend, appMethods } from "@fungi.computer/agar/backend";
15
+ import { computerList, computerPorts, computerProcesses, computerReadFile, computerTerminal, computerWriteFile, } from "@fungi.computer/agar/computer";
16
+ import { agentList, agentManage, agentSessionRead, agentSessionWrite, } from "@fungi.computer/agar/agents";
17
+ import { mediaGeneration } from "@fungi.computer/agar/media";
18
+ import { MediaGeneration, mediaGenerationDescriptionSchema, } from "@fungi.computer/agar/media-json";
19
+ import { registeredCapabilityHandle, } from "./capabilities.js";
20
+ import { capabilityDescriptorSchema } from "../capability-descriptor.js";
21
+ import { connectAppHost, } from "@fungi.computer/agar/host";
22
+ import { parseJsonValue } from "@fungi.computer/whistle/wire";
23
+ import { appDeclaredCommandSchema } from "@fungi.computer/puffball/app";
24
+ import { TerminalCapability } from "./terminal.js";
25
+ import { ComputerPortsHandle, ComputerProcessesHandle, } from "./computer-handles.js";
26
+ /** Current server-admitted configuration for one installed App page. */
27
+ export const oysterAppConfigSchema = Schema.Struct({
28
+ workbench: Schema.Boolean,
29
+ /** The home shell Release's own module, imported top-level; null if it ships none. */
30
+ shellModuleUrl: Schema.NullOr(Schema.String),
31
+ storage: Schema.Boolean,
32
+ /** The Release declares `apps.open`; only an embedding shell can serve it. */
33
+ appsOpen: Schema.Boolean,
34
+ computerId: Schema.NullOr(Schema.String),
35
+ authorityVersion: Schema.Int,
36
+ commands: Schema.Array(appDeclaredCommandSchema),
37
+ icon: Schema.NullOr(Schema.String),
38
+ roles: Schema.Array(Schema.String),
39
+ installationId: Schema.String,
40
+ appId: Schema.String,
41
+ releaseId: Schema.String,
42
+ uiUrl: Schema.String,
43
+ backendUrl: Schema.String,
44
+ methodsUrl: Schema.String,
45
+ capabilities: Schema.Array(capabilityDescriptorSchema),
46
+ });
47
+ async function answer(response) {
48
+ if (response.status === 401 || response.status === 403)
49
+ throw new AppError("App permission was denied", {
50
+ code: "CAPABILITY_DENIED",
51
+ retryable: false,
52
+ });
53
+ if (!response.ok)
54
+ throw new AppError("App backend request failed", {
55
+ code: "HOST_FAILURE",
56
+ retryable: response.status >= 500,
57
+ });
58
+ return parseJsonValue(await response.json());
59
+ }
60
+ /** The App's typed methods, reached through this host's method route. */
61
+ class Methods extends RpcTarget {
62
+ #url;
63
+ constructor(url) {
64
+ super();
65
+ this.#url = url;
66
+ }
67
+ async call(method, input) {
68
+ const name = Schema.decodeUnknownSync(Schema.String.check(Schema.isPattern(/^[A-Za-z][A-Za-z0-9_.]{0,79}$/u)))(method);
69
+ const body = Schema.decodeUnknownSync(Schema.String)(input);
70
+ return answer(await fetch(`${this.#url}${name}`, {
71
+ method: "POST",
72
+ headers: { "Content-Type": "application/json" },
73
+ body,
74
+ credentials: "same-origin",
75
+ cache: "no-store",
76
+ redirect: "error",
77
+ }));
78
+ }
79
+ }
80
+ /** A member-only declared deputy; identity and approval are rechecked by the host route. */
81
+ class Calls extends RpcTarget {
82
+ base;
83
+ signal;
84
+ constructor(base, signal) {
85
+ super();
86
+ this.base = base;
87
+ this.signal = signal;
88
+ }
89
+ async call(appId, method, input) {
90
+ const target = Schema.decodeUnknownSync(appIdSchema)(appId);
91
+ const name = Schema.decodeUnknownSync(appApiMethodNameSchema)(method);
92
+ const body = Schema.decodeUnknownSync(Schema.String)(input);
93
+ if (new TextEncoder().encode(body).byteLength > 64 * 1024)
94
+ throw new AppError("App method input is too large", {
95
+ code: "INVALID_ARGUMENT",
96
+ retryable: false,
97
+ });
98
+ Schema.decodeUnknownSync(Schema.fromJsonString(Schema.Json))(body);
99
+ return answer(await fetch(`${this.base}${encodeURIComponent(target)}/${encodeURIComponent(name)}`, {
100
+ method: "POST",
101
+ headers: { "Content-Type": "application/json" },
102
+ body,
103
+ credentials: "same-origin",
104
+ cache: "no-store",
105
+ redirect: "error",
106
+ signal: this.signal,
107
+ }));
108
+ }
109
+ }
110
+ /** A declared `apps.open` reaches the embedding shell's own role routing. */
111
+ class AppOpen extends RpcTarget {
112
+ routing;
113
+ constructor(routing) {
114
+ super();
115
+ this.routing = routing;
116
+ }
117
+ open(value) {
118
+ return this.routing.open(Schema.decodeUnknownSync(appOpenInputSchema, {
119
+ onExcessProperty: "error",
120
+ })(value));
121
+ }
122
+ role(value) {
123
+ const { role } = Schema.decodeUnknownSync(appOpenInputSchema.members[0], {
124
+ onExcessProperty: "error",
125
+ })({ role: value, intent: { kind: "navigate", params: [] } });
126
+ return this.routing.role(role);
127
+ }
128
+ }
129
+ /** The App's backend, reached through this host's admitted backend route. */
130
+ class Backend extends RpcTarget {
131
+ #url;
132
+ constructor(url) {
133
+ super();
134
+ this.#url = url;
135
+ }
136
+ async request(input) {
137
+ const body = Schema.decodeUnknownSync(Schema.String)(input);
138
+ const response = await fetch(this.#url, {
139
+ method: "PUT",
140
+ headers: { "Content-Type": "text/plain" },
141
+ body,
142
+ credentials: "same-origin",
143
+ cache: "no-store",
144
+ redirect: "error",
145
+ });
146
+ return answer(response);
147
+ }
148
+ }
149
+ const denied = () => Promise.reject(new AppError("This Oyster host does not provide that action", {
150
+ code: "CAPABILITY_DENIED",
151
+ retryable: false,
152
+ }));
153
+ function terminalSelection(config) {
154
+ const descriptor = config.capabilities.find((capability) => capability.id === computerTerminal.id &&
155
+ capability.version === computerTerminal.version);
156
+ const method = descriptor?.methods.open;
157
+ return {
158
+ computerId: config.computerId,
159
+ terminalUrl: descriptor !== undefined && method?.kind === "transport"
160
+ ? `${descriptor.base}${method.path}`
161
+ : null,
162
+ };
163
+ }
164
+ /** Read the server-admitted configuration this page was served with. */
165
+ export function readOysterPageConfig() {
166
+ const configElement = document.getElementById("oyster-config");
167
+ if (configElement === null)
168
+ throw new Error("Oyster page config is missing");
169
+ return Schema.decodeUnknownSync(Schema.fromJsonString(oysterAppConfigSchema))(configElement.textContent);
170
+ }
171
+ /** Apply this host's shared page styles and the person's color theme. */
172
+ export function applyOysterPageTheme() {
173
+ const dark = window.matchMedia("(prefers-color-scheme: dark)").matches;
174
+ const theme = dark ? "mocha" : "latte";
175
+ document.documentElement.dataset.theme = theme;
176
+ const style = document.createElement("style");
177
+ style.textContent = OYSTER_SHELL_STYLES;
178
+ document.head.append(style);
179
+ return theme;
180
+ }
181
+ /**
182
+ * The home installation's own storage and methods, for the trusted shell the
183
+ * host composes into this document. They reach the same admitted routes an
184
+ * isolated App would, without a frame between the shell and its host.
185
+ */
186
+ export function oysterShellHandles(config) {
187
+ return {
188
+ storage: config.storage
189
+ ? appStorage.schema.parse(oysterStorageHandle(config.installationId))
190
+ : null,
191
+ methods: appMethods.schema.parse(new Methods(config.methodsUrl)),
192
+ };
193
+ }
194
+ /**
195
+ * Mount one installed App's own page: its sandboxed frame and nothing else.
196
+ * Desktop chrome (menus, palette, status) belongs to the trusted shell.
197
+ */
198
+ export async function mountOysterPage() {
199
+ const frame = document.getElementById("oyster-app");
200
+ if (!(frame instanceof HTMLIFrameElement) || frame.contentWindow === null)
201
+ throw new Error("Oyster App frame is missing");
202
+ const config = readOysterPageConfig();
203
+ const lifetime = createPageLifetime(window);
204
+ const theme = applyOysterPageTheme();
205
+ // The App's commands are still admitted against its Release declaration.
206
+ const commands = createAppSurfaceCommandHost();
207
+ const mount = commands.mount(config.installationId, config.commands);
208
+ lifetime.own(() => {
209
+ commands.dispose();
210
+ });
211
+ return connectOysterApp({
212
+ config,
213
+ frame,
214
+ signal: lifetime.signal,
215
+ reservedChords: [],
216
+ theme,
217
+ handlers: {
218
+ ...mount.handlers,
219
+ reportStatus: () => Promise.resolve(),
220
+ openNavigation: denied,
221
+ reportFocus: () => Promise.resolve(),
222
+ reportAgentSessionSelection: () => Promise.resolve(),
223
+ showToast: () => Promise.resolve(),
224
+ onDisconnect: () => {
225
+ lifetime.dispose();
226
+ return Promise.resolve();
227
+ },
228
+ },
229
+ });
230
+ }
231
+ /** Connect a child or home App using the same admitted Oyster slot handles. */
232
+ export async function connectOysterApp(options) {
233
+ const { config, frame } = options;
234
+ if (frame.contentWindow === null)
235
+ throw new Error("App frame is unavailable");
236
+ const capabilities = await oysterAppCapabilities(options);
237
+ const host = await connectAppHost({
238
+ appWindow: frame.contentWindow,
239
+ expectedAppOrigin: "null",
240
+ hostWindow: window,
241
+ signal: options.signal,
242
+ launch: {
243
+ identity: {
244
+ appId: config.appId,
245
+ releaseId: config.releaseId,
246
+ surfaceId: options.surfaceId ?? config.installationId,
247
+ },
248
+ capabilities,
249
+ context: {
250
+ version: 1,
251
+ value: {
252
+ computerId: config.computerId,
253
+ focus: { editing: false, surface: null },
254
+ openRequest: options.openRequest ?? null,
255
+ visibility: "visible",
256
+ },
257
+ },
258
+ lifecycle: { version: 1, value: "connected" },
259
+ reservedChords: { version: 0, value: options.reservedChords },
260
+ theme: { version: 1, value: options.theme },
261
+ },
262
+ handlers: {
263
+ ...options.handlers,
264
+ requestBrowserAction: createBrowserActionHandler({
265
+ frame,
266
+ hostWindow: window,
267
+ signal: options.signal,
268
+ }),
269
+ },
270
+ });
271
+ if (options.signal.aborted)
272
+ host.dispose();
273
+ else
274
+ options.signal.addEventListener("abort", () => {
275
+ host.dispose();
276
+ }, { once: true });
277
+ return host;
278
+ }
279
+ export { oysterStorageHandle } from "./storage.js";
280
+ export { appSandbox } from "../app-sandbox.js";
281
+ /** Resolve only the slots admitted for this installation by its current host. */
282
+ export async function oysterAppCapabilities(options) {
283
+ const { config } = options;
284
+ const contracts = [
285
+ { contract: computerList },
286
+ {
287
+ contract: computerPorts,
288
+ createHandle: (call) => new ComputerPortsHandle(call),
289
+ },
290
+ {
291
+ contract: computerProcesses,
292
+ createHandle: (call) => new ComputerProcessesHandle(call),
293
+ },
294
+ { contract: computerReadFile },
295
+ { contract: computerWriteFile },
296
+ {
297
+ contract: computerTerminal,
298
+ createHandle: (_call, transport) => {
299
+ const selected = terminalSelection(config);
300
+ if (selected.terminalUrl === null)
301
+ throw new AppError("Computer terminal is unavailable", {
302
+ code: "CAPABILITY_DENIED",
303
+ retryable: false,
304
+ });
305
+ let leaseExpiresAt = 0;
306
+ return new TerminalCapability((input) => transport("open", input), {
307
+ computerId: config.computerId,
308
+ terminalUrl: selected.terminalUrl,
309
+ hostWindow: window,
310
+ mountSignal: options.signal,
311
+ ensureAccess: Object.assign(async (signal) => {
312
+ const response = await fetch(`/apps/${encodeURIComponent(config.installationId)}/`, {
313
+ headers: { Accept: "application/json" },
314
+ credentials: "same-origin",
315
+ cache: "no-store",
316
+ redirect: "error",
317
+ signal,
318
+ });
319
+ const current = Schema.decodeUnknownSync(oysterAppConfigSchema)(await answer(response));
320
+ if (current.installationId !== config.installationId ||
321
+ current.releaseId !== config.releaseId ||
322
+ current.authorityVersion !== config.authorityVersion)
323
+ throw new AppError("App admission changed. Reopen the App.", {
324
+ code: "CAPABILITY_DENIED",
325
+ retryable: false,
326
+ });
327
+ leaseExpiresAt = Date.now() + 60_000;
328
+ return terminalSelection(current);
329
+ }, { leaseExpiresAt: () => leaseExpiresAt }),
330
+ });
331
+ },
332
+ },
333
+ { contract: agentList },
334
+ { contract: agentManage },
335
+ { contract: agentSessionRead },
336
+ { contract: agentSessionWrite },
337
+ {
338
+ contract: mediaGeneration,
339
+ createHandle: async (call) => {
340
+ const description = Schema.decodeUnknownSync(mediaGenerationDescriptionSchema, {
341
+ onExcessProperty: "error",
342
+ })(await call("describe"));
343
+ return new MediaGeneration(call, description.computerId);
344
+ },
345
+ },
346
+ ];
347
+ const unknownCapabilities = [];
348
+ const capabilities = await Promise.all(config.capabilities.flatMap((descriptor) => {
349
+ if (descriptor.id === appsCall.id &&
350
+ descriptor.version === appsCall.version) {
351
+ const base = `/apps/${encodeURIComponent(config.installationId)}/calls/`;
352
+ if (descriptor.base !== base)
353
+ throw new AppError("App call route does not match this installation", {
354
+ code: "PROTOCOL",
355
+ retryable: false,
356
+ });
357
+ return [
358
+ Promise.resolve({
359
+ ...appsCall,
360
+ handle: new Calls(base, options.signal),
361
+ }),
362
+ ];
363
+ }
364
+ const registration = contracts.find(({ contract }) => contract.id === descriptor.id &&
365
+ contract.version === descriptor.version);
366
+ if (registration === undefined) {
367
+ unknownCapabilities.push(`${descriptor.id}@${String(descriptor.version)}`);
368
+ return [];
369
+ }
370
+ return [
371
+ registeredCapabilityHandle(registration, descriptor, config.installationId).then((handle) => ({ ...registration.contract, handle })),
372
+ ];
373
+ }));
374
+ if (unknownCapabilities.length > 0)
375
+ document.body.dataset.oysterCapability = unknownCapabilities.join(", ");
376
+ const resolved = [
377
+ { ...appBackend, handle: new Backend(config.backendUrl) },
378
+ { ...appMethods, handle: new Methods(config.methodsUrl) },
379
+ ...capabilities,
380
+ ...(config.appsOpen && options.appOpen
381
+ ? [{ ...appsOpen, handle: new AppOpen(options.appOpen) }]
382
+ : []),
383
+ ];
384
+ if (config.storage)
385
+ resolved.push({
386
+ ...appStorage,
387
+ handle: oysterStorageHandle(config.installationId),
388
+ });
389
+ return resolved;
390
+ }
@@ -0,0 +1,3 @@
1
+ import { type AppStorageWire } from "@fungi.computer/agar/storage";
2
+ /** The existing Agar storage wire, scoped to an admitted installation and owner. */
3
+ export declare function oysterStorageHandle(installationId: string): AppStorageWire;
@@ -0,0 +1,82 @@
1
+ import { RpcTarget } from "@fungi.computer/capnweb";
2
+ import * as Schema from "effect/Schema";
3
+ import { AppError } from "@fungi.computer/agar";
4
+ import { appStorageKeyNameSchema, appStorageWriteSchema, appStorageResetSchema, appStorageReadResultSchema, appStorageMutationResultSchema, } from "@fungi.computer/agar/storage";
5
+ const NativeTarget = RpcTarget;
6
+ function path(installationId, operation) {
7
+ return `/api/workbench/storage/${encodeURIComponent(installationId)}/${operation}`;
8
+ }
9
+ async function reply(response) {
10
+ if (!response.ok)
11
+ throw new AppError("App storage is unavailable", {
12
+ code: response.status === 401 || response.status === 403
13
+ ? "CAPABILITY_DENIED"
14
+ : "HOST_FAILURE",
15
+ retryable: response.status >= 500,
16
+ });
17
+ return Schema.decodeUnknownSync(Schema.Json)(await response.json());
18
+ }
19
+ class StorageEvents extends NativeTarget {
20
+ url;
21
+ #abort = new AbortController();
22
+ constructor(url) {
23
+ super();
24
+ this.url = url;
25
+ }
26
+ fetch(request) {
27
+ return fetch(this.url, {
28
+ credentials: "same-origin",
29
+ cache: "no-store",
30
+ redirect: "error",
31
+ signal: AbortSignal.any([request.signal, this.#abort.signal]),
32
+ });
33
+ }
34
+ close() {
35
+ this.#abort.abort();
36
+ return Promise.resolve();
37
+ }
38
+ [Symbol.dispose]() {
39
+ this.#abort.abort();
40
+ }
41
+ }
42
+ class Storage extends NativeTarget {
43
+ installationId;
44
+ constructor(installationId) {
45
+ super();
46
+ this.installationId = installationId;
47
+ }
48
+ async read(raw) {
49
+ const key = Schema.decodeUnknownSync(appStorageKeyNameSchema)(raw);
50
+ return Schema.decodeUnknownSync(appStorageReadResultSchema)(await reply(await fetch(`${path(this.installationId, "read")}?${new URLSearchParams({ key })}`, { credentials: "same-origin", cache: "no-store", redirect: "error" })));
51
+ }
52
+ async write(raw) {
53
+ const input = Schema.decodeUnknownSync(appStorageWriteSchema, {
54
+ onExcessProperty: "error",
55
+ })(raw);
56
+ return Schema.decodeUnknownSync(appStorageMutationResultSchema)(await this.mutate("write", input));
57
+ }
58
+ async reset(raw) {
59
+ const input = Schema.decodeUnknownSync(appStorageResetSchema, {
60
+ onExcessProperty: "error",
61
+ })(raw);
62
+ return Schema.decodeUnknownSync(appStorageMutationResultSchema)(await this.mutate("reset", input));
63
+ }
64
+ async mutate(operation, input) {
65
+ return reply(await fetch(path(this.installationId, operation), {
66
+ method: "POST",
67
+ headers: { "Content-Type": "application/json" },
68
+ body: JSON.stringify(input),
69
+ credentials: "same-origin",
70
+ cache: "no-store",
71
+ redirect: "error",
72
+ }));
73
+ }
74
+ openEvents(raw) {
75
+ const key = Schema.decodeUnknownSync(appStorageKeyNameSchema)(raw);
76
+ return Promise.resolve(new StorageEvents(`${path(this.installationId, "events")}?${new URLSearchParams({ key })}`));
77
+ }
78
+ }
79
+ /** The existing Agar storage wire, scoped to an admitted installation and owner. */
80
+ export function oysterStorageHandle(installationId) {
81
+ return new Storage(installationId);
82
+ }
@@ -0,0 +1,5 @@
1
+ import { ComputerTerminalHost, type ComputerTerminalConnect, type ComputerTerminalHostOptions } from "../computer-terminal.js";
2
+ /** Bind the shared terminal protocol to Oyster's admitted transport factory. */
3
+ export declare class TerminalCapability extends ComputerTerminalHost {
4
+ constructor(connect: (input: Parameters<ComputerTerminalConnect>[1]) => WebSocket, options: Omit<ComputerTerminalHostOptions, "connect">);
5
+ }
@@ -0,0 +1,7 @@
1
+ import { ComputerTerminalHost, } from "../computer-terminal.js";
2
+ /** Bind the shared terminal protocol to Oyster's admitted transport factory. */
3
+ export class TerminalCapability extends ComputerTerminalHost {
4
+ constructor(connect, options) {
5
+ super({ ...options, connect: (_url, input) => connect(input) });
6
+ }
7
+ }
@@ -0,0 +1,18 @@
1
+ import type { AppOpenRequest } from "@fungi.computer/agar";
2
+ /**
3
+ * A window's current launch target: the open request and Computer its child
4
+ * App should see. `reconfigure` moves this forward as the window is handed a
5
+ * new file; a later restore (`setVisibility`) must read the latest target
6
+ * here, never the window's first open request.
7
+ */
8
+ export type WindowLaunchTarget = Readonly<{
9
+ openRequest: AppOpenRequest | null;
10
+ computerId: string | null;
11
+ }>;
12
+ export type WindowLaunchTracker = Readonly<{
13
+ current: () => WindowLaunchTarget;
14
+ advance: (next: WindowLaunchTarget) => void;
15
+ }>;
16
+ /** One window's launch history: starts at its first open, moves forward on
17
+ * every `reconfigure`, and never resets on its own. */
18
+ export declare function createWindowLaunchTracker(initial: WindowLaunchTarget): WindowLaunchTracker;