@fungi.computer/oyster 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/README.md +228 -176
  2. package/dist/agent-avatars.d.ts +103 -0
  3. package/dist/agent-avatars.js +66 -0
  4. package/dist/agents.d.ts +12 -2
  5. package/dist/agents.js +39 -2
  6. package/dist/app-builds.d.ts +76 -17
  7. package/dist/app-builds.js +207 -63
  8. package/dist/app-sources.d.ts +7 -22
  9. package/dist/app-sources.js +49 -14
  10. package/dist/apps/gate.d.ts +7 -7
  11. package/dist/apps/gate.js +6 -6
  12. package/dist/apps/installation.d.ts +35 -35
  13. package/dist/apps/installation.js +20 -19
  14. package/dist/build/artifact-writer.d.ts +40 -0
  15. package/dist/build/artifact-writer.js +181 -0
  16. package/dist/build/build-jobs.js +7 -1
  17. package/dist/build/build-policy.d.ts +10 -0
  18. package/dist/build/build-policy.js +10 -0
  19. package/dist/build/build-step.d.ts +12 -1
  20. package/dist/build/build-step.js +9 -1
  21. package/dist/build/candidate-builder.d.ts +68 -0
  22. package/dist/build/candidate-builder.js +91 -0
  23. package/dist/build/candidate-cli.d.ts +1 -0
  24. package/dist/build/candidate-cli.js +119 -0
  25. package/dist/build/candidate-cli.mjs +28220 -0
  26. package/dist/build/content-objects.d.ts +37 -0
  27. package/dist/build/content-objects.js +53 -0
  28. package/dist/build/effect.d.ts +18 -0
  29. package/dist/build/effect.js +52 -12
  30. package/dist/build/git-environment.d.ts +3 -0
  31. package/dist/build/git-environment.js +21 -9
  32. package/dist/build/local-build.d.ts +13 -3
  33. package/dist/build/local-build.js +149 -99
  34. package/dist/build/snapshot-package-store.d.ts +10 -0
  35. package/dist/build/snapshot-package-store.js +15 -0
  36. package/dist/build/snapshot-program-scripts.js +1 -1
  37. package/dist/build/snapshot-programs/snapshot-path.d.ts +2 -0
  38. package/dist/build/snapshot-programs/snapshot-path.js +6 -0
  39. package/dist/build/submission-contract.d.ts +461 -17
  40. package/dist/build/submission-contract.js +136 -26
  41. package/dist/build/workspace-build.d.ts +7 -2
  42. package/dist/build/workspace-build.js +55 -11
  43. package/dist/build-contract.d.ts +3 -0
  44. package/dist/build-contract.js +3 -0
  45. package/dist/build-egress.d.ts +62 -0
  46. package/dist/build-egress.js +148 -0
  47. package/dist/build.d.ts +1 -0
  48. package/dist/build.js +1 -0
  49. package/dist/cloudflare.js +4 -4
  50. package/dist/frame-binding-wire-script.js +1 -1
  51. package/dist/frame-binding-wire.d.ts +1 -1
  52. package/dist/frame-binding-wire.js +1 -1
  53. package/dist/git-journal.js +4 -4
  54. package/dist/index.d.ts +1 -0
  55. package/dist/index.js +1 -0
  56. package/dist/installation-consent.d.ts +3 -1
  57. package/dist/installation-consent.js +2 -0
  58. package/dist/mcp-owner.js +20 -8
  59. package/dist/pack.d.ts +6 -3
  60. package/dist/pack.js +28 -11
  61. package/dist/page/gill-observation.d.ts +4 -0
  62. package/dist/page/gill-observation.js +31 -0
  63. package/dist/page/mount.d.ts +4 -8
  64. package/dist/page/window-launch.d.ts +18 -0
  65. package/dist/page/window-launch.js +11 -0
  66. package/dist/page-script.js +4 -4
  67. package/dist/release.d.ts +11 -0
  68. package/dist/release.js +4 -1
  69. package/dist/shell/app-directory.d.ts +50 -45
  70. package/dist/shell/app-directory.js +19 -18
  71. package/dist/shell/shell-module.d.ts +26 -2
  72. package/dist/shell/shell-module.js +51 -2
  73. package/dist/shell/window-manager.d.ts +5 -1
  74. package/dist/shell/window-manager.js +21 -2
  75. package/dist/shell/workbench-directory.d.ts +332 -0
  76. package/dist/shell/workbench-directory.js +35 -0
  77. package/dist/shell/workbench-host-types.d.ts +1 -1
  78. package/dist/shell/workbench-host.js +5 -0
  79. package/dist/shell/workbench-model.d.ts +3 -1
  80. package/dist/source/index.d.ts +6 -7
  81. package/dist/source/index.js +6 -7
  82. package/dist/source/template-push.d.ts +33 -0
  83. package/dist/source/template-push.js +223 -0
  84. package/dist/source/template-repository.d.ts +2 -0
  85. package/dist/source/template-repository.js +13 -0
  86. package/dist/source/{template-write.d.ts → template-seed.d.ts} +19 -20
  87. package/dist/source/template-seed.js +80 -0
  88. package/dist/standalone/agent-directory.d.ts +4 -0
  89. package/dist/standalone/agent-directory.js +4 -0
  90. package/dist/standalone/agents.d.ts +227 -0
  91. package/dist/standalone/agents.js +834 -0
  92. package/dist/standalone/app-builds-binding.d.ts +36 -0
  93. package/dist/standalone/app-builds-binding.js +119 -0
  94. package/dist/standalone/app-set.d.ts +91 -0
  95. package/dist/standalone/app-set.js +395 -0
  96. package/dist/standalone/app-source.d.ts +41 -0
  97. package/dist/standalone/app-source.js +59 -0
  98. package/dist/standalone/builds.d.ts +18 -0
  99. package/dist/standalone/builds.js +101 -0
  100. package/dist/standalone/computer-egress.d.ts +37 -0
  101. package/dist/standalone/computer-egress.js +111 -0
  102. package/dist/standalone/computer.d.ts +122 -0
  103. package/dist/standalone/computer.js +714 -0
  104. package/dist/standalone/install-apps-cli.d.ts +2 -0
  105. package/dist/standalone/install-apps-cli.js +126 -0
  106. package/dist/standalone/instance.d.ts +35 -0
  107. package/dist/standalone/instance.js +74 -0
  108. package/dist/standalone/media.d.ts +76 -0
  109. package/dist/standalone/media.js +227 -0
  110. package/dist/standalone/preview.d.ts +51 -0
  111. package/dist/standalone/preview.js +167 -0
  112. package/dist/standalone/registry.d.ts +102 -0
  113. package/dist/standalone/registry.js +193 -0
  114. package/dist/standalone/tenancy.d.ts +42 -0
  115. package/dist/standalone/tenancy.js +241 -0
  116. package/dist/standalone/worker.d.ts +55 -0
  117. package/dist/standalone/worker.js +147 -0
  118. package/dist/standalone/workflow-authority-readers.d.ts +16 -0
  119. package/dist/standalone/workflow-authority-readers.js +35 -0
  120. package/dist/standalone/workflow-binding.d.ts +216 -0
  121. package/dist/standalone/workflow-binding.js +217 -0
  122. package/dist/standalone/workflow-events.d.ts +46 -0
  123. package/dist/standalone/workflow-events.js +39 -0
  124. package/dist/standalone/workflow-git-capture.d.ts +7 -0
  125. package/dist/standalone/workflow-git-capture.js +62 -0
  126. package/dist/standalone/workflow-host.d.ts +955 -0
  127. package/dist/standalone/workflow-host.js +778 -0
  128. package/dist/standalone/workflow-node-capture.d.ts +13 -0
  129. package/dist/standalone/workflow-node-capture.js +72 -0
  130. package/dist/standalone/workflow-root-authority.d.ts +27 -0
  131. package/dist/standalone/workflow-root-authority.js +87 -0
  132. package/dist/standalone/workflow-schedules.d.ts +52 -0
  133. package/dist/standalone/workflow-schedules.js +40 -0
  134. package/dist/standalone/workflow-trigger-host.d.ts +1716 -0
  135. package/dist/standalone/workflow-trigger-host.js +52 -0
  136. package/dist/standalone/workflows.d.ts +713 -0
  137. package/dist/standalone/workflows.js +554 -0
  138. package/dist/tenancy/auth0.d.ts +64 -0
  139. package/dist/tenancy/auth0.js +198 -0
  140. package/dist/tenancy/cloudflare/rate-limit.d.ts +8 -0
  141. package/dist/tenancy/cloudflare/rate-limit.js +19 -0
  142. package/dist/tenancy/cloudflare/registry.d.ts +50 -0
  143. package/dist/tenancy/cloudflare/registry.js +301 -0
  144. package/dist/tenancy/cloudflare.d.ts +2 -0
  145. package/dist/tenancy/cloudflare.js +2 -0
  146. package/dist/tenancy/cold-directory.d.ts +13 -0
  147. package/dist/tenancy/cold-directory.js +43 -0
  148. package/dist/tenancy/contracts.d.ts +195 -0
  149. package/dist/tenancy/contracts.js +1 -0
  150. package/dist/tenancy/index.d.ts +19 -0
  151. package/dist/tenancy/index.js +156 -0
  152. package/dist/tenancy/owner-key.d.ts +26 -0
  153. package/dist/tenancy/owner-key.js +63 -0
  154. package/dist/tenancy/oyster.d.ts +4 -0
  155. package/dist/tenancy/oyster.js +25 -0
  156. package/dist/tenancy/registry-record.d.ts +7 -0
  157. package/dist/tenancy/registry-record.js +44 -0
  158. package/dist/tenancy/registry.d.ts +27 -0
  159. package/dist/tenancy/registry.js +138 -0
  160. package/dist/tenancy/resolve.d.ts +7 -0
  161. package/dist/tenancy/resolve.js +64 -0
  162. package/dist/workers-git.js +1 -4
  163. package/dist/workers.d.ts +2 -2
  164. package/dist/workers.js +3 -1
  165. package/docs/api/build-contract.md +829 -32
  166. package/docs/api/build.md +253 -17
  167. package/docs/api/modules.md +40 -32
  168. package/docs/api/pack.md +6 -3
  169. package/docs/api/shell/app-directory.md +267 -0
  170. package/docs/api/shell/shell-module.md +64 -3
  171. package/docs/api/shell/workbench-directory.md +119 -0
  172. package/docs/api/shell/workbench.md +19 -0
  173. package/docs/api/shell.md +127 -0
  174. package/docs/api/tenancy/auth0.md +110 -0
  175. package/docs/api/tenancy/cloudflare.md +221 -0
  176. package/docs/api/tenancy/cold-directory.md +46 -0
  177. package/docs/api/tenancy/owner-key.md +63 -0
  178. package/docs/api/tenancy/registry.md +77 -0
  179. package/docs/api/tenancy/resolve.md +69 -0
  180. package/docs/api/tenancy.md +430 -0
  181. package/docs/api/workers-git.md +140 -21
  182. package/docs/api/workers.md +15 -2
  183. package/docs/site/agent-quickstart.mdx +52 -55
  184. package/examples/standalone/worker.ts +7 -14
  185. package/examples/standalone/wrangler.jsonc +67 -6
  186. package/package.json +78 -25
  187. package/dist/build/r2-artifact-writer.d.ts +0 -31
  188. package/dist/build/r2-artifact-writer.js +0 -179
  189. package/dist/source/template-write.js +0 -344
  190. package/docs/media/architecture.mmd +0 -32
  191. package/docs/media/architecture.png +0 -0
  192. package/docs/media/bonsai-network.png +0 -0
  193. package/docs/media/bonsai-repository.png +0 -0
  194. package/examples/git/worker.ts +0 -39
  195. package/examples/git/wrangler.jsonc +0 -32
package/dist/release.d.ts CHANGED
@@ -9,6 +9,17 @@ export type ArtifactStore = Readonly<{
9
9
  /** Store bytes under `artifactRef`; the caller has verified the digest. */
10
10
  put: (artifactRef: ArtifactRef, bytes: Uint8Array) => Promise<void>;
11
11
  }>;
12
+ /** What a store knows of one object without reading it. */
13
+ export type ArtifactHead = Readonly<{
14
+ byteLength: number;
15
+ /** The digest the store verified when it took the bytes, if it did. */
16
+ digest: Sha256Digest | null;
17
+ }>;
18
+ /** A store that can describe an object without reading its bytes. */
19
+ export type ArtifactHeads = Readonly<{
20
+ /** Describe the object at `artifactRef`, or `null` when absent. */
21
+ head: (artifactRef: ArtifactRef) => Promise<ArtifactHead | null>;
22
+ }>;
12
23
  /** Why a Release could not be read; the host maps it to an HTTP refusal. */
13
24
  export declare class ReleaseError extends Error {
14
25
  readonly code: "artifact_missing" | "digest_mismatch" | "invalid_release" | "asset_missing";
package/dist/release.js CHANGED
@@ -79,8 +79,11 @@ readAssets = true) {
79
79
  catch (cause) {
80
80
  throw new ReleaseError("invalid_release", "Invalid assets", { cause });
81
81
  }
82
+ // One asset at a time: a Release's assets together can exceed an
83
+ // isolate's memory, each alone is bounded by its policy.
82
84
  if (readAssets)
83
- await Promise.all(assets.assets.map((asset) => readVerified(store, asset.artifactRef, asset.digest)));
85
+ for (const asset of assets.assets)
86
+ await readVerified(store, asset.artifactRef, asset.digest);
84
87
  ui = { kind: "assets", build: assets };
85
88
  }
86
89
  else
@@ -2,23 +2,23 @@ import * as Schema from "effect/Schema";
2
2
  import { appDeclaredGillSchema } from "@fungi.computer/gills";
3
3
  import * as z from "zod";
4
4
  /** An App address selects a host default or a specific installation. */
5
- export declare const appAddressSchema: z.ZodUnion<readonly [z.ZodObject<{
5
+ export declare const appAddressSchema: z.ZodLazy<z.ZodUnion<readonly [z.ZodObject<{
6
6
  kind: z.ZodLiteral<"default">;
7
7
  appId: z.ZodString;
8
8
  }, z.core.$strict>, z.ZodObject<{
9
9
  kind: z.ZodLiteral<"installation">;
10
10
  installationId: z.ZodString;
11
- }, z.core.$strict>]>;
11
+ }, z.core.$strict>]>>;
12
12
  /** Host-reported progress of applying a revised App authority version. */
13
- export declare const appAuthorityEnforcementSchema: z.ZodObject<{
13
+ export declare const appAuthorityEnforcementSchema: z.ZodLazy<z.ZodObject<{
14
14
  requestId: z.ZodString;
15
- address: z.ZodUnion<readonly [z.ZodObject<{
15
+ address: z.ZodLazy<z.ZodUnion<readonly [z.ZodObject<{
16
16
  kind: z.ZodLiteral<"default">;
17
17
  appId: z.ZodString;
18
18
  }, z.core.$strict>, z.ZodObject<{
19
19
  kind: z.ZodLiteral<"installation">;
20
20
  installationId: z.ZodString;
21
- }, z.core.$strict>]>;
21
+ }, z.core.$strict>]>>;
22
22
  authorityVersion: z.ZodNumber;
23
23
  state: z.ZodEnum<{
24
24
  unaffected: "unaffected";
@@ -27,7 +27,7 @@ export declare const appAuthorityEnforcementSchema: z.ZodObject<{
27
27
  expired: "expired";
28
28
  }>;
29
29
  outstanding: z.ZodNumber;
30
- }, z.core.$strict>;
30
+ }, z.core.$strict>>;
31
31
  /** Decoded address of a default App or an installation. */
32
32
  export type AppAddress = z.output<typeof appAddressSchema>;
33
33
  /** Stable identity of one App address across directory and settings views. */
@@ -43,13 +43,13 @@ export type AppDirectoryGill = {
43
43
  };
44
44
  /** Reusable App metadata supplied by an embedding host; it conveys no permissions. */
45
45
  export declare const appDirectoryEntrySchema: z.ZodObject<{
46
- address: z.ZodUnion<readonly [z.ZodObject<{
46
+ address: z.ZodLazy<z.ZodUnion<readonly [z.ZodObject<{
47
47
  kind: z.ZodLiteral<"default">;
48
48
  appId: z.ZodString;
49
49
  }, z.core.$strict>, z.ZodObject<{
50
50
  kind: z.ZodLiteral<"installation">;
51
51
  installationId: z.ZodString;
52
- }, z.core.$strict>]>;
52
+ }, z.core.$strict>]>>;
53
53
  installationId: z.ZodNullable<z.ZodString>;
54
54
  surfaceId: z.ZodString;
55
55
  appId: z.ZodString;
@@ -57,15 +57,15 @@ export declare const appDirectoryEntrySchema: z.ZodObject<{
57
57
  icon: z.ZodOptional<z.ZodNullable<z.ZodString>>;
58
58
  releaseId: z.ZodNullable<z.ZodString>;
59
59
  authorityVersion: z.ZodNumber;
60
- enforcement: z.ZodNullable<z.ZodObject<{
60
+ enforcement: z.ZodNullable<z.ZodLazy<z.ZodObject<{
61
61
  requestId: z.ZodString;
62
- address: z.ZodUnion<readonly [z.ZodObject<{
62
+ address: z.ZodLazy<z.ZodUnion<readonly [z.ZodObject<{
63
63
  kind: z.ZodLiteral<"default">;
64
64
  appId: z.ZodString;
65
65
  }, z.core.$strict>, z.ZodObject<{
66
66
  kind: z.ZodLiteral<"installation">;
67
67
  installationId: z.ZodString;
68
- }, z.core.$strict>]>;
68
+ }, z.core.$strict>]>>;
69
69
  authorityVersion: z.ZodNumber;
70
70
  state: z.ZodEnum<{
71
71
  unaffected: "unaffected";
@@ -74,7 +74,7 @@ export declare const appDirectoryEntrySchema: z.ZodObject<{
74
74
  expired: "expired";
75
75
  }>;
76
76
  outstanding: z.ZodNumber;
77
- }, z.core.$strict>>;
77
+ }, z.core.$strict>>>;
78
78
  handlers: z.ZodArray<z.ZodLiteral<"file.open">>;
79
79
  roles: z.ZodArray<z.ZodString>;
80
80
  declaredCapabilities: z.ZodArray<z.ZodString>;
@@ -132,14 +132,8 @@ export declare const appRoleSelectionSchema: z.ZodObject<{
132
132
  surfaceId: z.ZodNullable<z.ZodString>;
133
133
  chosen: z.ZodBoolean;
134
134
  }, z.core.$strict>;
135
- declare const appComputerOperationSchema: z.ZodEnum<{
136
- "computer.list": "computer.list";
137
- "computer.readFile": "computer.readFile";
138
- "computer.writeFile": "computer.writeFile";
139
- "computer.execute": "computer.execute";
140
- }>;
141
- export type AppComputerOperation = z.output<typeof appComputerOperationSchema>;
142
- export declare const appComputerPermissionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
135
+ /** App Computer permissions limited to selected Computers or the Team's Computers. */
136
+ export declare const appComputerPermissionSchema: z.ZodDiscriminatedUnion<[z.ZodLazy<z.ZodObject<{
143
137
  kind: z.ZodLiteral<"selected-computers">;
144
138
  computers: z.ZodArray<z.ZodObject<{
145
139
  computerId: z.ZodString;
@@ -150,7 +144,7 @@ export declare const appComputerPermissionSchema: z.ZodDiscriminatedUnion<[z.Zod
150
144
  "computer.execute": "computer.execute";
151
145
  }>>;
152
146
  }, z.core.$strict>>;
153
- }, z.core.$strict>, z.ZodObject<{
147
+ }, z.core.$strict>>, z.ZodLazy<z.ZodObject<{
154
148
  kind: z.ZodLiteral<"all-team-computers">;
155
149
  operations: z.ZodArray<z.ZodEnum<{
156
150
  "computer.list": "computer.list";
@@ -158,8 +152,14 @@ export declare const appComputerPermissionSchema: z.ZodDiscriminatedUnion<[z.Zod
158
152
  "computer.writeFile": "computer.writeFile";
159
153
  "computer.execute": "computer.execute";
160
154
  }>>;
161
- }, z.core.$strict>], "kind">;
155
+ }, z.core.$strict>>], "kind">;
156
+ /** One operation an App may request for a Computer. */
157
+ export type AppComputerOperation = Extract<z.output<typeof appComputerPermissionSchema>, {
158
+ kind: "all-team-computers";
159
+ }>["operations"][number];
160
+ /** Decoded Computer permission scope attached to an App directory entry. */
162
161
  export type AppComputerPermission = z.output<typeof appComputerPermissionSchema>;
162
+ /** Agent directory and session operations an App may request from its host. */
163
163
  export declare const appAgentPermissionSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
164
164
  kind: z.ZodLiteral<"all-team-agents">;
165
165
  directoryOperations: z.ZodArray<z.ZodEnum<{
@@ -184,23 +184,28 @@ export declare const appAgentPermissionSchema: z.ZodDiscriminatedUnion<[z.ZodObj
184
184
  }>>;
185
185
  }, z.core.$strict>>;
186
186
  }, z.core.$strict>], "kind">;
187
+ /** Decoded Agent permission scope attached to an App directory entry. */
187
188
  export type AppAgentPermission = z.output<typeof appAgentPermissionSchema>;
189
+ /** Whether an App may use language-model and media generation services. */
188
190
  export declare const appGenerationPermissionsSchema: z.ZodObject<{
189
191
  llm: z.ZodBoolean;
190
192
  media: z.ZodBoolean;
191
193
  }, z.core.$strict>;
194
+ /** Decoded generation permissions attached to an App directory entry. */
192
195
  export type AppGenerationPermissions = z.output<typeof appGenerationPermissionsSchema>;
196
+ /** Whether an App may browse, buy, or install free marketplace entries. */
193
197
  export declare const appMarketplacePermissionsSchema: z.ZodObject<{
194
198
  browse: z.ZodBoolean;
195
199
  purchase: z.ZodBoolean;
196
200
  installFree: z.ZodBoolean;
197
201
  }, z.core.$strict>;
202
+ /** Decoded marketplace permissions attached to an App directory entry. */
198
203
  export type AppMarketplacePermissions = z.output<typeof appMarketplacePermissionsSchema>;
199
204
  /**
200
205
  * A host's Team App directory with its permission projection, parsed strictly
201
206
  * by every consumer: an unknown field is a contract change both sides make.
202
207
  */
203
- export declare const appDirectoryResponseSchema: z.ZodObject<{
208
+ export declare const appDirectoryResponseSchema: z.ZodLazy<z.ZodObject<{
204
209
  actorIsTeamOwner: z.ZodBoolean;
205
210
  needsUpdate: z.ZodOptional<z.ZodArray<z.ZodObject<{
206
211
  installationId: z.ZodNullable<z.ZodString>;
@@ -208,13 +213,13 @@ export declare const appDirectoryResponseSchema: z.ZodObject<{
208
213
  displayName: z.ZodString;
209
214
  }, z.core.$strict>>>;
210
215
  apps: z.ZodArray<z.ZodObject<{
211
- address: z.ZodUnion<readonly [z.ZodObject<{
216
+ address: z.ZodLazy<z.ZodUnion<readonly [z.ZodObject<{
212
217
  kind: z.ZodLiteral<"default">;
213
218
  appId: z.ZodString;
214
219
  }, z.core.$strict>, z.ZodObject<{
215
220
  kind: z.ZodLiteral<"installation">;
216
221
  installationId: z.ZodString;
217
- }, z.core.$strict>]>;
222
+ }, z.core.$strict>]>>;
218
223
  installationId: z.ZodNullable<z.ZodString>;
219
224
  surfaceId: z.ZodString;
220
225
  appId: z.ZodString;
@@ -222,15 +227,15 @@ export declare const appDirectoryResponseSchema: z.ZodObject<{
222
227
  icon: z.ZodOptional<z.ZodNullable<z.ZodString>>;
223
228
  releaseId: z.ZodNullable<z.ZodString>;
224
229
  authorityVersion: z.ZodNumber;
225
- enforcement: z.ZodNullable<z.ZodObject<{
230
+ enforcement: z.ZodNullable<z.ZodLazy<z.ZodObject<{
226
231
  requestId: z.ZodString;
227
- address: z.ZodUnion<readonly [z.ZodObject<{
232
+ address: z.ZodLazy<z.ZodUnion<readonly [z.ZodObject<{
228
233
  kind: z.ZodLiteral<"default">;
229
234
  appId: z.ZodString;
230
235
  }, z.core.$strict>, z.ZodObject<{
231
236
  kind: z.ZodLiteral<"installation">;
232
237
  installationId: z.ZodString;
233
- }, z.core.$strict>]>;
238
+ }, z.core.$strict>]>>;
234
239
  authorityVersion: z.ZodNumber;
235
240
  state: z.ZodEnum<{
236
241
  unaffected: "unaffected";
@@ -239,7 +244,7 @@ export declare const appDirectoryResponseSchema: z.ZodObject<{
239
244
  expired: "expired";
240
245
  }>;
241
246
  outstanding: z.ZodNumber;
242
- }, z.core.$strict>>;
247
+ }, z.core.$strict>>>;
243
248
  handlers: z.ZodArray<z.ZodLiteral<"file.open">>;
244
249
  roles: z.ZodArray<z.ZodString>;
245
250
  declaredCapabilities: z.ZodArray<z.ZodString>;
@@ -298,7 +303,7 @@ export declare const appDirectoryResponseSchema: z.ZodObject<{
298
303
  operation: z.ZodString;
299
304
  resourceId: z.ZodString;
300
305
  }, z.core.$strict>>;
301
- computerPermission: z.ZodOptional<z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodObject<{
306
+ computerPermission: z.ZodOptional<z.ZodNullable<z.ZodDiscriminatedUnion<[z.ZodLazy<z.ZodObject<{
302
307
  kind: z.ZodLiteral<"selected-computers">;
303
308
  computers: z.ZodArray<z.ZodObject<{
304
309
  computerId: z.ZodString;
@@ -309,7 +314,7 @@ export declare const appDirectoryResponseSchema: z.ZodObject<{
309
314
  "computer.execute": "computer.execute";
310
315
  }>>;
311
316
  }, z.core.$strict>>;
312
- }, z.core.$strict>, z.ZodObject<{
317
+ }, z.core.$strict>>, z.ZodLazy<z.ZodObject<{
313
318
  kind: z.ZodLiteral<"all-team-computers">;
314
319
  operations: z.ZodArray<z.ZodEnum<{
315
320
  "computer.list": "computer.list";
@@ -317,7 +322,7 @@ export declare const appDirectoryResponseSchema: z.ZodObject<{
317
322
  "computer.writeFile": "computer.writeFile";
318
323
  "computer.execute": "computer.execute";
319
324
  }>>;
320
- }, z.core.$strict>], "kind">>>;
325
+ }, z.core.$strict>>], "kind">>>;
321
326
  generationPermissions: z.ZodObject<{
322
327
  llm: z.ZodBoolean;
323
328
  media: z.ZodBoolean;
@@ -356,7 +361,8 @@ export declare const appDirectoryResponseSchema: z.ZodObject<{
356
361
  surfaceId: z.ZodNullable<z.ZodString>;
357
362
  chosen: z.ZodBoolean;
358
363
  }, z.core.$strict>>;
359
- }, z.core.$strict>;
364
+ }, z.core.$strict>>;
365
+ /** The host-resolved Team App directory and its permission projections. */
360
366
  export type AppDirectory = z.output<typeof appDirectoryResponseSchema>;
361
367
  /** Read-only catalog metadata for one App, without host-specific role policy. */
362
368
  export declare const appCatalogEntrySchema: z.ZodObject<{
@@ -366,7 +372,7 @@ export declare const appCatalogEntrySchema: z.ZodObject<{
366
372
  gills: z.ZodArray<z.ZodObject<{
367
373
  id: z.ZodString;
368
374
  title: z.ZodString;
369
- params: z.ZodOptional<z.ZodArray<z.ZodObject<{
375
+ params: z.ZodOptional<z.ZodLazy<z.ZodArray<z.ZodObject<{
370
376
  key: z.ZodString;
371
377
  label: z.ZodString;
372
378
  kind: z.ZodEnum<{
@@ -400,7 +406,7 @@ export declare const appCatalogEntrySchema: z.ZodObject<{
400
406
  kind: "computer" | "repository" | "branch";
401
407
  required: boolean;
402
408
  options?: string | undefined;
403
- }[]>>>;
409
+ }[]>>>>;
404
410
  desktop: z.ZodOptional<z.ZodObject<{
405
411
  sizes: z.ZodArray<z.ZodEnum<{
406
412
  S: "S";
@@ -411,7 +417,7 @@ export declare const appCatalogEntrySchema: z.ZodObject<{
411
417
  }, z.core.$strict>>;
412
418
  }, z.core.$strict>;
413
419
  /** Read-only desktop metadata; identities are surface addresses, never launch authority. */
414
- export declare const appCatalogResponseSchema: z.ZodObject<{
420
+ export declare const appCatalogResponseSchema: z.ZodLazy<z.ZodObject<{
415
421
  apps: z.ZodArray<z.ZodObject<{
416
422
  appId: z.ZodString;
417
423
  surfaceId: z.ZodString;
@@ -419,7 +425,7 @@ export declare const appCatalogResponseSchema: z.ZodObject<{
419
425
  gills: z.ZodArray<z.ZodObject<{
420
426
  id: z.ZodString;
421
427
  title: z.ZodString;
422
- params: z.ZodOptional<z.ZodArray<z.ZodObject<{
428
+ params: z.ZodOptional<z.ZodLazy<z.ZodArray<z.ZodObject<{
423
429
  key: z.ZodString;
424
430
  label: z.ZodString;
425
431
  kind: z.ZodEnum<{
@@ -453,7 +459,7 @@ export declare const appCatalogResponseSchema: z.ZodObject<{
453
459
  kind: "computer" | "repository" | "branch";
454
460
  required: boolean;
455
461
  options?: string | undefined;
456
- }[]>>>;
462
+ }[]>>>>;
457
463
  desktop: z.ZodOptional<z.ZodObject<{
458
464
  sizes: z.ZodArray<z.ZodEnum<{
459
465
  S: "S";
@@ -469,11 +475,11 @@ export declare const appCatalogResponseSchema: z.ZodObject<{
469
475
  chosen: z.ZodBoolean;
470
476
  }, z.core.$strict>>;
471
477
  }, z.core.$strict>;
472
- }, z.core.$strict>;
478
+ }, z.core.$strict>>;
473
479
  /** Parsed metadata returned by the read-only APPS.catalog binding. */
474
480
  export type AppCatalog = z.output<typeof appCatalogResponseSchema>;
475
481
  /** Complete APPS.catalog reply, including broker admission failures. */
476
- export declare const appCatalogBrokerResultSchema: z.ZodUnion<readonly [z.ZodObject<{
482
+ export declare const appCatalogBrokerResultSchema: z.ZodLazy<z.ZodUnion<readonly [z.ZodLazy<z.ZodObject<{
477
483
  apps: z.ZodArray<z.ZodObject<{
478
484
  appId: z.ZodString;
479
485
  surfaceId: z.ZodString;
@@ -481,7 +487,7 @@ export declare const appCatalogBrokerResultSchema: z.ZodUnion<readonly [z.ZodObj
481
487
  gills: z.ZodArray<z.ZodObject<{
482
488
  id: z.ZodString;
483
489
  title: z.ZodString;
484
- params: z.ZodOptional<z.ZodArray<z.ZodObject<{
490
+ params: z.ZodOptional<z.ZodLazy<z.ZodArray<z.ZodObject<{
485
491
  key: z.ZodString;
486
492
  label: z.ZodString;
487
493
  kind: z.ZodEnum<{
@@ -515,7 +521,7 @@ export declare const appCatalogBrokerResultSchema: z.ZodUnion<readonly [z.ZodObj
515
521
  kind: "computer" | "repository" | "branch";
516
522
  required: boolean;
517
523
  options?: string | undefined;
518
- }[]>>>;
524
+ }[]>>>>;
519
525
  desktop: z.ZodOptional<z.ZodObject<{
520
526
  sizes: z.ZodArray<z.ZodEnum<{
521
527
  S: "S";
@@ -531,7 +537,6 @@ export declare const appCatalogBrokerResultSchema: z.ZodUnion<readonly [z.ZodObj
531
537
  chosen: z.ZodBoolean;
532
538
  }, z.core.$strict>>;
533
539
  }, z.core.$strict>;
534
- }, z.core.$strict>, z.ZodObject<{
540
+ }, z.core.$strict>>, z.ZodObject<{
535
541
  error: z.ZodString;
536
- }, z.core.$strict>]>;
537
- export {};
542
+ }, z.core.$strict>]>>;
@@ -3,7 +3,7 @@ import { appDeclaredCommandSchema, appCallsSchema, } from "@fungi.computer/puffb
3
3
  import { appDeclaredGillSchema, appGillParamsSchema, } from "@fungi.computer/gills";
4
4
  import * as z from "zod";
5
5
  /** An App address selects a host default or a specific installation. */
6
- export const appAddressSchema = z.union([
6
+ export const appAddressSchema = z.lazy(() => z.union([
7
7
  z.strictObject({
8
8
  kind: z.literal("default"),
9
9
  appId: z.string().min(1),
@@ -12,15 +12,15 @@ export const appAddressSchema = z.union([
12
12
  kind: z.literal("installation"),
13
13
  installationId: z.string().min(1),
14
14
  }),
15
- ]);
15
+ ]));
16
16
  /** Host-reported progress of applying a revised App authority version. */
17
- export const appAuthorityEnforcementSchema = z.strictObject({
17
+ export const appAuthorityEnforcementSchema = z.lazy(() => z.strictObject({
18
18
  requestId: z.string().min(1),
19
19
  address: appAddressSchema,
20
20
  authorityVersion: z.number().int().positive(),
21
21
  state: z.enum(["unaffected", "pending", "applied", "expired"]),
22
22
  outstanding: z.number().int().nonnegative(),
23
- });
23
+ }));
24
24
  /** Stable identity of one App address across directory and settings views. */
25
25
  export const addressKey = (address) => address.kind === "default"
26
26
  ? `default:${address.appId}`
@@ -69,17 +69,18 @@ const appComputerOperationSchema = z.enum([
69
69
  "computer.writeFile",
70
70
  "computer.execute",
71
71
  ]);
72
- const selectedComputerPermissionSchema = z.strictObject({
72
+ const selectedComputerPermissionSchema = z.lazy(() => z.strictObject({
73
73
  kind: z.literal("selected-computers"),
74
74
  computers: z.array(z.strictObject({
75
75
  computerId: z.string().min(1),
76
76
  operations: z.array(appComputerOperationSchema),
77
77
  })),
78
- });
79
- const allTeamComputersPermissionSchema = z.strictObject({
78
+ }));
79
+ const allTeamComputersPermissionSchema = z.lazy(() => z.strictObject({
80
80
  kind: z.literal("all-team-computers"),
81
81
  operations: z.array(appComputerOperationSchema),
82
- });
82
+ }));
83
+ /** App Computer permissions limited to selected Computers or the Team's Computers. */
83
84
  export const appComputerPermissionSchema = z.discriminatedUnion("kind", [
84
85
  selectedComputerPermissionSchema,
85
86
  allTeamComputersPermissionSchema,
@@ -90,6 +91,7 @@ const agentSessionOperationSchema = z.enum([
90
91
  "agent.send",
91
92
  "agent.manage",
92
93
  ]);
94
+ /** Agent directory and session operations an App may request from its host. */
93
95
  export const appAgentPermissionSchema = z.discriminatedUnion("kind", [
94
96
  z.strictObject({
95
97
  kind: z.literal("all-team-agents"),
@@ -105,10 +107,12 @@ export const appAgentPermissionSchema = z.discriminatedUnion("kind", [
105
107
  })),
106
108
  }),
107
109
  ]);
110
+ /** Whether an App may use language-model and media generation services. */
108
111
  export const appGenerationPermissionsSchema = z.strictObject({
109
112
  llm: z.boolean(),
110
113
  media: z.boolean(),
111
114
  });
115
+ /** Whether an App may browse, buy, or install free marketplace entries. */
112
116
  export const appMarketplacePermissionsSchema = z.strictObject({
113
117
  browse: z.boolean(),
114
118
  purchase: z.boolean(),
@@ -118,7 +122,7 @@ export const appMarketplacePermissionsSchema = z.strictObject({
118
122
  * A host's Team App directory with its permission projection, parsed strictly
119
123
  * by every consumer: an unknown field is a contract change both sides make.
120
124
  */
121
- export const appDirectoryResponseSchema = z.strictObject({
125
+ export const appDirectoryResponseSchema = z.lazy(() => z.strictObject({
122
126
  actorIsTeamOwner: z.boolean(),
123
127
  needsUpdate: z
124
128
  .array(z.strictObject({
@@ -146,9 +150,9 @@ export const appDirectoryResponseSchema = z.strictObject({
146
150
  })),
147
151
  /** The Team's effective App per role, owned and resolved by the host. */
148
152
  roles: z.record(z.string().min(1), appRoleSelectionSchema),
149
- });
153
+ }));
150
154
  /** Desktop metadata is a method result, distinct from the full Release Gill declaration. */
151
- const catalogGillParamsSchema = z
155
+ const catalogGillParamsSchema = z.lazy(() => z
152
156
  .array(z.strictObject({
153
157
  key: z.string().max(64),
154
158
  label: z.string().max(256),
@@ -158,7 +162,7 @@ const catalogGillParamsSchema = z
158
162
  }))
159
163
  .max(4)
160
164
  // The wire shape is representable; Gill owns its domain refinements.
161
- .refine(Schema.is(appGillParamsSchema), "Invalid Gill placement parameters");
165
+ .refine(Schema.is(appGillParamsSchema), "Invalid Gill placement parameters"));
162
166
  const catalogGillSchema = z.strictObject({
163
167
  id: z.string().trim().min(1).max(256),
164
168
  title: z.string().trim().min(1).max(256),
@@ -182,14 +186,11 @@ export const appCatalogEntrySchema = appDirectoryEntrySchema
182
186
  })
183
187
  .extend({ gills: z.array(catalogGillSchema).max(16) });
184
188
  /** Read-only desktop metadata; identities are surface addresses, never launch authority. */
185
- export const appCatalogResponseSchema = z.strictObject({
189
+ export const appCatalogResponseSchema = z.lazy(() => z.strictObject({
186
190
  apps: z.array(appCatalogEntrySchema).max(50),
187
191
  roles: z.strictObject({
188
192
  inbox: appRoleSelectionSchema.optional(),
189
193
  }),
190
- });
194
+ }));
191
195
  /** Complete APPS.catalog reply, including broker admission failures. */
192
- export const appCatalogBrokerResultSchema = z.union([
193
- appCatalogResponseSchema,
194
- z.strictObject({ error: z.string() }),
195
- ]);
196
+ export const appCatalogBrokerResultSchema = z.lazy(() => z.union([appCatalogResponseSchema, z.strictObject({ error: z.string() })]));
@@ -1,6 +1,7 @@
1
1
  import type { AppStorage } from "@fungi.computer/agar/storage";
2
2
  import type { WhistleJsonValue } from "@fungi.computer/whistle";
3
3
  import type { TeamWorkbenchHostHandle } from "./workbench-contract.js";
4
+ import type { WorkbenchHostControls } from "./workbench-host-types.js";
4
5
  /**
5
6
  * What a host hands the shell a Team picked. The host composes that shell into
6
7
  * its own top-level document, so it runs with the host's escalated
@@ -20,12 +21,35 @@ export type ShellMountInput = Readonly<{
20
21
  * function that removes it again. The shell loads its own code and styles.
21
22
  */
22
23
  export type MountShell = (root: HTMLElement, input: ShellMountInput) => Promise<() => void>;
24
+ /**
25
+ * Settings a shell renders for a host that has none of its own, such as a
26
+ * standalone Oyster: the shell draws them into `root`, and the host hands
27
+ * `controls` to its workbench so Apps and the dashboard can open them.
28
+ */
29
+ export type ShellPlatformControls = Readonly<{
30
+ controls: WorkbenchHostControls;
31
+ /** A child App suggested desktop Settings for one of its surfaces. */
32
+ suggestDesktopSettings(surfaceId: string): void;
33
+ /** Remove the rendered Settings. */
34
+ dispose(): void;
35
+ }>;
36
+ /** Render the shell's own Settings into `root` for the host at `teamId`. */
37
+ export type MountPlatformControls = (root: HTMLElement, input: Readonly<{
38
+ teamId: string;
39
+ }>) => Promise<ShellPlatformControls>;
40
+ /** What a host gets from a picked shell Release's module. */
41
+ export type ShellModule = Readonly<{
42
+ mountShell: MountShell;
43
+ /** Absent when the shell renders no Settings of its own. */
44
+ mountPlatformControls: MountPlatformControls | null;
45
+ }>;
23
46
  /** The picked shell's module could not be loaded or does not fit the contract. */
24
47
  export declare class ShellModuleError extends Error {
25
48
  readonly name = "ShellModuleError";
26
49
  }
27
50
  /**
28
51
  * Import the picked shell Release's module from the host's own origin and
29
- * check that it exports `mountShell`. The host never bundles a shell.
52
+ * check that it exports `mountShell`, and `mountPlatformControls` when it
53
+ * offers its own Settings. The host never bundles a shell.
30
54
  */
31
- export declare function importShellModule(moduleUrl: URL, hostOrigin: string): Promise<MountShell>;
55
+ export declare function importShellModule(moduleUrl: URL, hostOrigin: string): Promise<ShellModule>;
@@ -1,4 +1,5 @@
1
1
  import * as z from "zod";
2
+ const unsubscribe = () => z.function({ input: [], output: z.void() });
2
3
  /** The module namespace a shell Release must export; built on first use,
3
4
  * since only a browser has `HTMLElement`. */
4
5
  const shellModuleSchema = () => z.object({
@@ -7,6 +8,50 @@ const shellModuleSchema = () => z.object({
7
8
  input: [z.instanceof(HTMLElement), z.unknown()],
8
9
  output: z.promise(z.function({ input: [], output: z.void() })),
9
10
  }),
11
+ mountPlatformControls: z
12
+ .function({
13
+ input: [
14
+ z.instanceof(HTMLElement),
15
+ z.object({ teamId: z.string() }).readonly(),
16
+ ],
17
+ output: z.promise(z.object({
18
+ controls: z.object({
19
+ sections: z.array(z.string()).readonly().optional(),
20
+ // The host passes the workbench's own values; the shell
21
+ // parses what it reads.
22
+ parseSettings: z.function({
23
+ input: [z.unknown()],
24
+ output: z.json(),
25
+ }),
26
+ openSettings: z.function({
27
+ input: [z.unknown(), z.object({ restoreFocus: z.boolean() })],
28
+ output: z.void(),
29
+ }),
30
+ subscribeSettingsClosed: z.function({
31
+ input: [unsubscribe()],
32
+ output: unsubscribe(),
33
+ }),
34
+ subscribeChanges: z.function({
35
+ input: [unsubscribe()],
36
+ output: unsubscribe(),
37
+ }),
38
+ attachDesktopSettings: z.function({
39
+ input: [z.unknown()],
40
+ output: unsubscribe(),
41
+ }),
42
+ requestAppAccess: z.function({
43
+ input: [z.unknown(), z.unknown()],
44
+ output: z.promise(z.enum(["granted", "declined", "customize"])),
45
+ }),
46
+ }),
47
+ suggestDesktopSettings: z.function({
48
+ input: [z.string()],
49
+ output: z.void(),
50
+ }),
51
+ dispose: unsubscribe(),
52
+ })),
53
+ })
54
+ .optional(),
10
55
  });
11
56
  /** The picked shell's module could not be loaded or does not fit the contract. */
12
57
  export class ShellModuleError extends Error {
@@ -14,7 +59,8 @@ export class ShellModuleError extends Error {
14
59
  }
15
60
  /**
16
61
  * Import the picked shell Release's module from the host's own origin and
17
- * check that it exports `mountShell`. The host never bundles a shell.
62
+ * check that it exports `mountShell`, and `mountPlatformControls` when it
63
+ * offers its own Settings. The host never bundles a shell.
18
64
  */
19
65
  export async function importShellModule(moduleUrl, hostOrigin) {
20
66
  if (moduleUrl.origin !== hostOrigin || moduleUrl.hash !== "")
@@ -33,5 +79,8 @@ export async function importShellModule(moduleUrl, hostOrigin) {
33
79
  throw new ShellModuleError("The picked shell does not export mountShell", {
34
80
  cause: decoded.error,
35
81
  });
36
- return decoded.data.mountShell;
82
+ return {
83
+ mountShell: decoded.data.mountShell,
84
+ mountPlatformControls: decoded.data.mountPlatformControls ?? null,
85
+ };
37
86
  }
@@ -1,4 +1,4 @@
1
- import { type AppNavigationState, type AppStatusAction, type AppStatusItem } from "@fungi.computer/agar";
1
+ import { type AppNavigationActivation, type AppNavigationState, type AppStatusAction, type AppStatusItem } from "@fungi.computer/agar";
2
2
  /** Minimum identity required to own a window across mount generations. */
3
3
  export type WindowLaunch = Readonly<{
4
4
  windowId: string;
@@ -15,6 +15,8 @@ export type WindowHost<Launch extends WindowLaunch> = Readonly<{
15
15
  requestClose?: () => boolean | Promise<boolean>;
16
16
  /** Ask the mounted App to go back in its own history; `true` when it did. */
17
17
  requestBack?: () => boolean | Promise<boolean>;
18
+ /** Deliver the person's use of a crumb or header command; `true` when the App acted. */
19
+ activateNavigation?: (activation: AppNavigationActivation) => boolean | Promise<boolean>;
18
20
  /** Deliver the person's use of a status item; `true` when the App acted. */
19
21
  activateStatus?: (action: AppStatusAction) => boolean | Promise<boolean>;
20
22
  /** Release the current mount and its host resources. */
@@ -79,6 +81,8 @@ export type WindowManager<Launch extends WindowLaunch, Container> = Readonly<{
79
81
  replace: (windowId: string, launch: Launch) => Promise<void>;
80
82
  /** Ask a ready window's App to go back; `false` when it cannot. */
81
83
  back: (windowId: string) => Promise<boolean>;
84
+ /** Deliver a crumb or header command to a ready window's App; `false` when it cannot. */
85
+ activateNavigation: (windowId: string, activation: AppNavigationActivation) => Promise<boolean>;
82
86
  /** Deliver a status item action to a ready window's App; `false` when it cannot. */
83
87
  activateStatus: (windowId: string, action: AppStatusAction) => Promise<boolean>;
84
88
  /** Register the current window generation's host-owned picker. */
@@ -1,5 +1,5 @@
1
1
  import * as Redacted from "effect/Redacted";
2
- import { AppError, statusActionAllowed, } from "@fungi.computer/agar";
2
+ import { AppError, navigationActivationAllowed, statusActionAllowed, } from "@fungi.computer/agar";
3
3
  /**
4
4
  * Shared window lifetime owner for browser and terminal shells.
5
5
  *
@@ -18,7 +18,14 @@ function sameStatusItems(current, next) {
18
18
  function sameNavigation(current, next) {
19
19
  if (current === null || next === null)
20
20
  return current === next;
21
- return current.canGoBack === next.canGoBack && current.title === next.title;
21
+ return (current.canGoBack === next.canGoBack &&
22
+ current.title === next.title &&
23
+ JSON.stringify([
24
+ current.crumbs,
25
+ current.primary,
26
+ current.menu,
27
+ current.status,
28
+ ]) === JSON.stringify([next.crumbs, next.primary, next.menu, next.status]));
22
29
  }
23
30
  /** Whether any projected App window is still visible in the workspace. */
24
31
  export function hasVisibleWindows(projection) {
@@ -626,6 +633,17 @@ export function createWindowManager(options) {
626
633
  const requestBack = record.host?.requestBack;
627
634
  return requestBack ? await requestBack() : false;
628
635
  };
636
+ const activateNavigation = async (windowId, activation) => {
637
+ const record = records.get(windowId);
638
+ if (!record || !isActive(record) || record.status !== "ready")
639
+ return false;
640
+ // Only a crumb or enabled command the App currently publishes.
641
+ if (record.navigation === null ||
642
+ !navigationActivationAllowed(record.navigation, activation))
643
+ return false;
644
+ const deliver = record.host?.activateNavigation;
645
+ return deliver ? await deliver(activation) : false;
646
+ };
629
647
  const activateStatus = async (windowId, action) => {
630
648
  const record = records.get(windowId);
631
649
  if (!record || !isActive(record) || record.status !== "ready")
@@ -697,6 +715,7 @@ export function createWindowManager(options) {
697
715
  close,
698
716
  reconfigure,
699
717
  update,
718
+ activateNavigation,
700
719
  activateStatus,
701
720
  registerComputerChoice,
702
721
  replace,