@fungi.computer/oyster 0.1.0 → 0.3.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 (292) hide show
  1. package/README.md +376 -72
  2. package/dist/agent-avatars.d.ts +103 -0
  3. package/dist/agent-avatars.js +66 -0
  4. package/dist/agents.d.ts +15 -4
  5. package/dist/agents.js +43 -4
  6. package/dist/app-builds.d.ts +81 -8
  7. package/dist/app-builds.js +210 -60
  8. package/dist/app-storage.d.ts +3 -3
  9. package/dist/approval-capability.d.ts +5 -0
  10. package/dist/approval-capability.js +46 -0
  11. package/dist/approval-home.d.ts +51 -0
  12. package/dist/approval-home.js +226 -0
  13. package/dist/apps/catalog.d.ts +335 -0
  14. package/dist/apps/catalog.js +46 -0
  15. package/dist/apps/gate.d.ts +26 -12
  16. package/dist/apps/gate.js +48 -22
  17. package/dist/apps/index.d.ts +3 -1
  18. package/dist/apps/index.js +3 -1
  19. package/dist/apps/installation.d.ts +147 -66
  20. package/dist/apps/installation.js +193 -86
  21. package/dist/apps/permissions.d.ts +247 -0
  22. package/dist/apps/permissions.js +255 -0
  23. package/dist/boot-capability-route.d.ts +15 -0
  24. package/dist/boot-capability-route.js +196 -0
  25. package/dist/boot-capability.d.ts +103 -0
  26. package/dist/boot-capability.js +141 -0
  27. package/dist/boot-construction.d.ts +12 -0
  28. package/dist/boot-construction.js +175 -0
  29. package/dist/boot-gate.d.ts +267 -0
  30. package/dist/boot-gate.js +236 -0
  31. package/dist/boot-host-script.d.ts +2 -0
  32. package/dist/boot-host-script.js +1 -0
  33. package/dist/boot-mount.d.ts +21 -0
  34. package/dist/boot-mount.js +65 -0
  35. package/dist/browser/boot.d.ts +73 -0
  36. package/dist/browser/boot.js +502 -0
  37. package/dist/browser/browser.d.ts +104 -0
  38. package/dist/browser/browser.js +374 -0
  39. package/dist/browser/capability-source.d.ts +76 -0
  40. package/dist/browser/capability-source.js +338 -0
  41. package/dist/browser/cdp-client.d.ts +56 -0
  42. package/dist/browser/cdp-client.js +184 -0
  43. package/dist/browser/errors.d.ts +79 -0
  44. package/dist/browser/errors.js +32 -0
  45. package/dist/browser/index.d.ts +16 -0
  46. package/dist/browser/index.js +14 -0
  47. package/dist/browser/lease-registry.d.ts +61 -0
  48. package/dist/browser/lease-registry.js +101 -0
  49. package/dist/browser/operations.d.ts +225 -0
  50. package/dist/browser/operations.js +137 -0
  51. package/dist/browser/page.d.ts +25 -0
  52. package/dist/browser/page.js +172 -0
  53. package/dist/browser/quick-reads.d.ts +29 -0
  54. package/dist/browser/quick-reads.js +160 -0
  55. package/dist/browser/sessions.d.ts +52 -0
  56. package/dist/browser/sessions.js +118 -0
  57. package/dist/browser/url-policy.d.ts +18 -0
  58. package/dist/browser/url-policy.js +58 -0
  59. package/dist/build/app-imports.d.ts +12 -0
  60. package/dist/build/app-imports.js +105 -0
  61. package/dist/build/build-policy.d.ts +5 -3
  62. package/dist/build/build-policy.js +5 -3
  63. package/dist/build/candidate-builder.d.ts +1 -1
  64. package/dist/build/candidate-cli.mjs +8428 -337
  65. package/dist/build/local-build.d.ts +2 -0
  66. package/dist/build/local-build.js +28 -6
  67. package/dist/build/snapshot-package-store.d.ts +1 -1
  68. package/dist/build/snapshot-package-store.js +7 -2
  69. package/dist/build/workspace-build.d.ts +92 -5
  70. package/dist/build/workspace-build.js +93 -19
  71. package/dist/build-egress.js +4 -4
  72. package/dist/build.d.ts +1 -1
  73. package/dist/build.js +1 -1
  74. package/dist/catalog-frame.js +1 -1
  75. package/dist/cloudflare.d.ts +13 -3
  76. package/dist/cloudflare.js +106 -8
  77. package/dist/frame-binding-wire-script.js +1 -1
  78. package/dist/frame-binding-wire.d.ts +1 -1
  79. package/dist/frame-binding-wire.js +5 -3
  80. package/dist/git-auth.d.ts +0 -2
  81. package/dist/git-auth.js +0 -2
  82. package/dist/git-journal.js +4 -4
  83. package/dist/git.d.ts +0 -1
  84. package/dist/git.js +0 -2
  85. package/dist/host.d.ts +39 -13
  86. package/dist/host.js +268 -142
  87. package/dist/index.d.ts +26 -15
  88. package/dist/index.js +40 -16
  89. package/dist/install-release-cli.d.ts +2 -0
  90. package/dist/install-release-cli.js +46 -0
  91. package/dist/installation-client.d.ts +43 -0
  92. package/dist/installation-client.js +178 -0
  93. package/dist/installation-execution.d.ts +11 -0
  94. package/dist/installation-execution.js +184 -0
  95. package/dist/installation-operations.d.ts +1437 -0
  96. package/dist/installation-operations.js +664 -0
  97. package/dist/installation-store-generation.d.ts +3 -0
  98. package/dist/installation-store-generation.js +16 -0
  99. package/dist/instance-id.d.ts +10 -0
  100. package/dist/instance-id.js +10 -0
  101. package/dist/instance-refusal.d.ts +11 -0
  102. package/dist/instance-refusal.js +21 -0
  103. package/dist/internal/delivery.js +4 -2
  104. package/dist/internal/host-gate.js +7 -1
  105. package/dist/internal/registry-installations.js +4 -4
  106. package/dist/keys.d.ts +5 -1
  107. package/dist/keys.js +10 -2
  108. package/dist/machine-link/authority.d.ts +89 -0
  109. package/dist/machine-link/authority.js +37 -0
  110. package/dist/machine-link/client.d.ts +66 -0
  111. package/dist/machine-link/client.js +94 -0
  112. package/dist/machine-link/delivery.d.ts +18 -0
  113. package/dist/machine-link/delivery.js +55 -0
  114. package/dist/machine-link/enrollment.d.ts +111 -0
  115. package/dist/machine-link/enrollment.js +286 -0
  116. package/dist/machine-link/fences.d.ts +37 -0
  117. package/dist/machine-link/fences.js +166 -0
  118. package/dist/machine-link/home.d.ts +20 -0
  119. package/dist/machine-link/home.js +24 -0
  120. package/dist/machine-link/host.d.ts +43 -0
  121. package/dist/machine-link/host.js +189 -0
  122. package/dist/machine-link/index.d.ts +15 -0
  123. package/dist/machine-link/index.js +15 -0
  124. package/dist/machine-link/link.d.ts +48 -0
  125. package/dist/machine-link/link.js +223 -0
  126. package/dist/machine-link/presence.d.ts +10 -0
  127. package/dist/machine-link/presence.js +25 -0
  128. package/dist/machine-link/workers.d.ts +6 -0
  129. package/dist/machine-link/workers.js +6 -0
  130. package/dist/mcp-owner.d.ts +2 -2
  131. package/dist/mcp-owner.js +41 -33
  132. package/dist/mcp.d.ts +15 -3
  133. package/dist/mcp.js +146 -25
  134. package/dist/pack.d.ts +14 -3
  135. package/dist/pack.js +44 -19
  136. package/dist/page/app-access.d.ts +7 -0
  137. package/dist/page/app-access.js +75 -0
  138. package/dist/page/boot-host.js +57 -0
  139. package/dist/page/capabilities.d.ts +3 -3
  140. package/dist/page/capabilities.js +16 -12
  141. package/dist/page/computer-handles.d.ts +3 -3
  142. package/dist/page/computer-target.d.ts +3 -0
  143. package/dist/page/computer-target.js +9 -0
  144. package/dist/page/mount.d.ts +23 -7
  145. package/dist/page/mount.js +152 -16
  146. package/dist/page-assets.d.ts +22 -0
  147. package/dist/page-assets.js +28 -0
  148. package/dist/page-script.d.ts +3 -0
  149. package/dist/page-script.js +5 -4
  150. package/dist/release.d.ts +13 -6
  151. package/dist/release.js +10 -7
  152. package/dist/root-data.d.ts +16 -6
  153. package/dist/root-data.js +2 -2
  154. package/dist/source/index.d.ts +1 -1
  155. package/dist/source/team-source.d.ts +20 -8
  156. package/dist/source/team-source.js +39 -10
  157. package/dist/source/template-seed.d.ts +2 -2
  158. package/dist/standalone/agent-mail.d.ts +24 -0
  159. package/dist/standalone/agent-mail.js +62 -0
  160. package/dist/standalone/agent-store.d.ts +9 -0
  161. package/dist/standalone/agent-store.js +30 -0
  162. package/dist/standalone/agents.d.ts +78 -12
  163. package/dist/standalone/agents.js +470 -59
  164. package/dist/standalone/app-builds-binding.d.ts +20 -2
  165. package/dist/standalone/app-builds-binding.js +151 -27
  166. package/dist/standalone/app-set.d.ts +5 -2
  167. package/dist/standalone/app-set.js +174 -143
  168. package/dist/standalone/browser.d.ts +11 -0
  169. package/dist/standalone/browser.js +72 -0
  170. package/dist/standalone/builds.d.ts +13 -4
  171. package/dist/standalone/builds.js +28 -44
  172. package/dist/standalone/computer-egress.d.ts +2 -0
  173. package/dist/standalone/computer-egress.js +13 -4
  174. package/dist/standalone/computer-fleet.d.ts +43 -0
  175. package/dist/standalone/computer-fleet.js +200 -0
  176. package/dist/standalone/computer.d.ts +44 -9
  177. package/dist/standalone/computer.js +132 -25
  178. package/dist/standalone/install-apps-cli.js +43 -6
  179. package/dist/standalone/instance.d.ts +2 -2
  180. package/dist/standalone/instance.js +8 -11
  181. package/dist/standalone/machine-link.d.ts +354 -0
  182. package/dist/standalone/machine-link.js +368 -0
  183. package/dist/standalone/media.d.ts +2 -2
  184. package/dist/standalone/media.js +19 -16
  185. package/dist/standalone/preview.d.ts +2 -2
  186. package/dist/standalone/preview.js +39 -12
  187. package/dist/standalone/registry.d.ts +149 -9
  188. package/dist/standalone/registry.js +299 -8
  189. package/dist/standalone/worker.d.ts +19 -5
  190. package/dist/standalone/worker.js +90 -54
  191. package/dist/standalone/workflow-binding.d.ts +28 -32
  192. package/dist/standalone/workflow-binding.js +20 -20
  193. package/dist/standalone/workflow-control.d.ts +4 -0
  194. package/dist/standalone/workflow-control.js +40 -0
  195. package/dist/standalone/workflow-events.d.ts +2 -2
  196. package/dist/standalone/workflow-events.js +9 -10
  197. package/dist/standalone/workflow-git-capture.js +4 -3
  198. package/dist/standalone/workflow-host.d.ts +177 -152
  199. package/dist/standalone/workflow-host.js +137 -30
  200. package/dist/standalone/workflow-node-capture.js +11 -4
  201. package/dist/standalone/workflow-schedules.d.ts +5 -2
  202. package/dist/standalone/workflow-schedules.js +9 -10
  203. package/dist/standalone/workflow-trigger-host.d.ts +88 -6
  204. package/dist/standalone/workflow-trigger-host.js +2 -2
  205. package/dist/standalone/workflow-webhooks.d.ts +22 -0
  206. package/dist/standalone/workflow-webhooks.js +39 -0
  207. package/dist/standalone/workflows.d.ts +203 -50
  208. package/dist/standalone/workflows.js +198 -39
  209. package/dist/storage-frame.d.ts +6 -6
  210. package/dist/testing/capabilities.js +14 -3
  211. package/dist/testing/installation.js +26 -2
  212. package/dist/testing/worker.js +1 -1
  213. package/dist/testing/workers-runtime.d.ts +8 -2
  214. package/dist/testing/workers-runtime.js +20 -2
  215. package/dist/webhook-abuse.d.ts +25 -0
  216. package/dist/webhook-abuse.js +54 -0
  217. package/dist/webhook-custody.d.ts +144 -0
  218. package/dist/webhook-custody.js +222 -0
  219. package/dist/webhook-ingress.d.ts +36 -0
  220. package/dist/webhook-ingress.js +146 -0
  221. package/dist/webhooks.d.ts +111 -0
  222. package/dist/webhooks.js +189 -0
  223. package/dist/workers-git.d.ts +12 -17
  224. package/dist/workers-git.js +60 -55
  225. package/dist/workers.d.ts +224 -13
  226. package/dist/workers.js +351 -51
  227. package/dist/workflow-agent-authority.d.ts +8 -0
  228. package/dist/workflow-agent-authority.js +42 -0
  229. package/dist/workflows.d.ts +66 -0
  230. package/dist/workflows.js +97 -0
  231. package/docs/api/README.md +63 -37
  232. package/docs/api/agents.md +17 -0
  233. package/docs/api/app-storage.md +1 -1
  234. package/docs/api/apps.md +1394 -543
  235. package/docs/api/browser/boot.md +132 -0
  236. package/docs/api/browser.md +1440 -0
  237. package/docs/api/build-contract.md +38 -25
  238. package/docs/api/build.md +263 -84
  239. package/docs/api/cloudflare.md +93 -7
  240. package/docs/api/git.md +3 -13
  241. package/docs/api/host.md +944 -118
  242. package/docs/api/index.md +320 -18
  243. package/docs/api/keys.md +24 -1
  244. package/docs/api/mcp.md +59 -12
  245. package/docs/api/modules.md +33 -40
  246. package/docs/api/pack.md +57 -8
  247. package/docs/api/page/mount.md +92 -4
  248. package/docs/api/workers-git.md +103 -24
  249. package/docs/api/workers.md +1581 -244
  250. package/docs/site/agent-quickstart.mdx +28 -14
  251. package/examples/standalone/worker.ts +3 -1
  252. package/examples/standalone/wrangler.jsonc +2 -0
  253. package/package.json +73 -69
  254. package/dist/installation-consent.d.ts +0 -79
  255. package/dist/installation-consent.js +0 -82
  256. package/dist/shell/app-directory.d.ts +0 -542
  257. package/dist/shell/app-directory.js +0 -199
  258. package/dist/shell/browser-actions.d.ts +0 -7
  259. package/dist/shell/browser-actions.js +0 -56
  260. package/dist/shell/command-host.d.ts +0 -112
  261. package/dist/shell/command-host.js +0 -502
  262. package/dist/shell/commands.d.ts +0 -25
  263. package/dist/shell/commands.js +0 -78
  264. package/dist/shell/index.d.ts +0 -8
  265. package/dist/shell/index.js +0 -8
  266. package/dist/shell/keys.d.ts +0 -41
  267. package/dist/shell/keys.js +0 -134
  268. package/dist/shell/shell-module.d.ts +0 -55
  269. package/dist/shell/shell-module.js +0 -86
  270. package/dist/shell/window-manager.d.ts +0 -124
  271. package/dist/shell/window-manager.js +0 -711
  272. package/dist/shell/workbench-contract.d.ts +0 -68
  273. package/dist/shell/workbench-directory.d.ts +0 -332
  274. package/dist/shell/workbench-directory.js +0 -35
  275. package/dist/shell/workbench-host-types.d.ts +0 -96
  276. package/dist/shell/workbench-host-types.js +0 -1
  277. package/dist/shell/workbench-host.d.ts +0 -34
  278. package/dist/shell/workbench-host.js +0 -347
  279. package/dist/shell/workbench-model.d.ts +0 -192
  280. package/dist/shell/workbench-model.js +0 -53
  281. package/dist/shell/workbench.d.ts +0 -4
  282. package/dist/shell/workbench.js +0 -2
  283. package/docs/api/shell/app-directory.md +0 -599
  284. package/docs/api/shell/command-host.md +0 -224
  285. package/docs/api/shell/commands.md +0 -197
  286. package/docs/api/shell/keys.md +0 -183
  287. package/docs/api/shell/shell-module.md +0 -204
  288. package/docs/api/shell/window-manager.md +0 -267
  289. package/docs/api/shell/workbench-directory.md +0 -119
  290. package/docs/api/shell/workbench.md +0 -205
  291. package/docs/api/shell.md +0 -1915
  292. /package/dist/{shell/workbench-contract.js → page/boot-host.d.ts} +0 -0
@@ -0,0 +1,247 @@
1
+ import * as z from "zod";
2
+ import type { AppPermissionRequest } from "@fungi.computer/agar";
3
+ import { type AppDeclaration, type AppCapabilityId } from "@fungi.computer/puffball/app";
4
+ import { type PermissionCatalogEntry } from "./catalog.js";
5
+ import type { SigilName } from "@fungi.computer/sigils";
6
+ import { type AppAuthority, type DeclaredOperations, type GrantCommand, type GrantChange, type ResourceRef } from "./installation.js";
7
+ /** A host-provided resource identity and its display label. */
8
+ export type ResourceOption = {
9
+ kind: string;
10
+ id: string;
11
+ label: string;
12
+ };
13
+ /** Includes newly declared operations and capabilities the owner has narrowed. */
14
+ export declare function pendingCapabilities(authority: Pick<AppAuthority, "approvedGrants">, declaration: Pick<AppDeclaration, "capabilities">, declaredOperations: DeclaredOperations): AppDeclaration["capabilities"];
15
+ /** How an App's runtime permission request relates to the owner's stored grants. */
16
+ export type GrantRequestDecision = Readonly<{
17
+ kind: "covered";
18
+ }> | Readonly<{
19
+ kind: "customize";
20
+ }> | Readonly<{
21
+ kind: "refused";
22
+ code: "not_declared" | "stale_authority" | "window_scope_unavailable";
23
+ }> | Readonly<{
24
+ kind: "ask";
25
+ adds: readonly GrantChange[];
26
+ command: Extract<GrantCommand, {
27
+ kind: "change-grants";
28
+ }>;
29
+ }>;
30
+ /** Bound the real SDK request; an Allow never silently widens selected resources. */
31
+ export declare function grantRequestFor(authority: AppAuthority, facts: Readonly<{
32
+ declaration: Pick<AppDeclaration, "capabilities">;
33
+ declaredOperations: DeclaredOperations;
34
+ }>, request: AppPermissionRequest, window: Readonly<{
35
+ computerId: string | null;
36
+ }>): GrantRequestDecision;
37
+ /**
38
+ * A draft contains approvals, never the broader declared-operation projection.
39
+ * @inline
40
+ */
41
+ export type PermissionGrant = Readonly<{
42
+ operations: readonly string[];
43
+ resources: "tenant-scope" | readonly ResourceRef[];
44
+ }>;
45
+ /**
46
+ * Capability approvals being edited; null removes the capability's grant.
47
+ * @inlineType PermissionGrant
48
+ */
49
+ export type PermissionDraft = ReadonlyMap<AppCapabilityId, PermissionGrant | null>;
50
+ /** One switch, scope, resource or operation change applied to a draft. */
51
+ export type PermissionEdit = Readonly<{
52
+ kind: "switch" | "all";
53
+ capability: AppCapabilityId;
54
+ on: boolean;
55
+ }> | Readonly<{
56
+ kind: "resource";
57
+ capability: AppCapabilityId;
58
+ resource: ResourceRef;
59
+ on: boolean;
60
+ }> | Readonly<{
61
+ kind: "operation";
62
+ capability: AppCapabilityId;
63
+ operation: string;
64
+ on: boolean;
65
+ }>;
66
+ /** The saved operation ceiling is the starting point, including empty operation rows. */
67
+ export declare function draftOf(authority: AppAuthority): PermissionDraft;
68
+ /** An edit changes one capability; unrelated saved operations and scopes are retained. */
69
+ export declare function editPermissions(draft: PermissionDraft, edit: PermissionEdit, declared: DeclaredOperations): PermissionDraft;
70
+ /** Only touched capability rows cross the save boundary. */
71
+ export declare function planGrantChange(baseline: AppAuthority, draft: PermissionDraft): readonly GrantChange[];
72
+ /** A conflict preserves the person's edits while taking fresh untouched capabilities. */
73
+ export declare function rebaseDraft(draft: PermissionDraft, baseline: AppAuthority, current: AppAuthority): PermissionDraft;
74
+ /** Serializable host facts; the browser derives presentation, never authority. */
75
+ export declare const appPermissionsWireSchema: z.ZodObject<{
76
+ authority: z.ZodObject<{
77
+ authorityVersion: z.ZodLazy<z.ZodNumber>;
78
+ declaredOperationsDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
79
+ approvedGrants: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
80
+ capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"approvals" | "agent.list" | "agent.manage" | "agent.rename" | "agent.avatar" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
81
+ capabilityApproved: z.ZodLiteral<true>;
82
+ operations: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
83
+ resources: z.ZodUnion<readonly [z.ZodLiteral<"tenant-scope">, z.ZodReadonly<z.ZodArray<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
84
+ kind: z.ZodString;
85
+ id: z.ZodString;
86
+ }, z.core.$strict>>>>>]>;
87
+ }, z.core.$strict>>>>>;
88
+ approval: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
89
+ by: import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
90
+ kind: import("zod/mini").ZodMiniLiteral<"member">;
91
+ memberId: import("zod/mini").ZodMiniString<string>;
92
+ }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
93
+ kind: import("zod/mini").ZodMiniLiteral<"agent">;
94
+ agentId: import("zod/mini").ZodMiniString<string>;
95
+ }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
96
+ kind: import("zod/mini").ZodMiniLiteral<"team-key">;
97
+ keyId: import("zod/mini").ZodMiniString<string>;
98
+ }, z.core.$strip>], "kind">;
99
+ at: z.ZodNumber;
100
+ authorityVersion: z.ZodLazy<z.ZodNumber>;
101
+ }, z.core.$strict>>>>;
102
+ }, z.core.$strict>;
103
+ declaredOperations: z.ZodLazy<z.ZodObject<{
104
+ artifactDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
105
+ digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
106
+ anonymousMethods: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
107
+ name: z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>;
108
+ digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
109
+ }, z.core.$strict>>>>;
110
+ capabilities: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
111
+ capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"approvals" | "agent.list" | "agent.manage" | "agent.rename" | "agent.avatar" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
112
+ operations: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
113
+ }, z.core.$strict>>>>;
114
+ }, z.core.$strict>>;
115
+ }, z.core.$strict>;
116
+ /** Host-supplied authority and declared operations used to derive permission UI. */
117
+ export type AppPermissionsWire = z.output<typeof appPermissionsWireSchema>;
118
+ export type PermissionCellState = "on" | "off" | "via-all";
119
+ /**
120
+ * Catalog copy and pending status shared by a group's scoped and switch columns.
121
+ * @inline
122
+ */
123
+ export type PermissionColumn = Readonly<{
124
+ capability: AppCapabilityId;
125
+ label: string;
126
+ caption: string;
127
+ description: string;
128
+ sigil: SigilName;
129
+ warning: string | null;
130
+ pending: boolean;
131
+ }>;
132
+ /**
133
+ * Catalog-derived permission groups, resource cells and operation switches.
134
+ * @inlineType PermissionColumn
135
+ */
136
+ export type PermissionScreen = Readonly<{
137
+ canEdit: boolean;
138
+ pending: readonly AppCapabilityId[];
139
+ groups: readonly Readonly<{
140
+ id: PermissionCatalogEntry["group"];
141
+ scope: "computer" | "agent" | null;
142
+ columns: readonly PermissionColumn[];
143
+ rows: readonly Readonly<{
144
+ resource: ResourceRef | "all";
145
+ label: string;
146
+ cells: readonly Readonly<{
147
+ capability: AppCapabilityId;
148
+ state: PermissionCellState;
149
+ }>[];
150
+ }>[];
151
+ switches: readonly (PermissionColumn & Readonly<{
152
+ on: boolean;
153
+ }>)[];
154
+ operations: readonly Readonly<{
155
+ capability: "apps.call";
156
+ operation: string;
157
+ on: boolean;
158
+ }>[];
159
+ }>[];
160
+ }>;
161
+ /** Every declared permission is visible, including removable saved resources no longer listed by the host. */
162
+ export declare function permissionScreen(input: AppPermissionsWire & Readonly<{
163
+ resources: readonly ResourceOption[];
164
+ canEdit: boolean;
165
+ }>): PermissionScreen;
166
+ /** Owner-direct permission page and JSON projection. Copy stays in the catalog. */
167
+ export declare const permissionPinsSchema: z.ZodObject<{
168
+ storeGeneration: z.ZodString;
169
+ authorityVersion: z.ZodNumber;
170
+ artifactDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
171
+ }, z.core.$strict>;
172
+ /** Generation, authority version and artifact digest fencing a permission edit. */
173
+ export type PermissionPins = z.output<typeof permissionPinsSchema>;
174
+ /** Permission edit command coupled to the version pins read by the owner. */
175
+ export declare const permissionSaveSchema: z.ZodObject<{
176
+ storeGeneration: z.ZodString;
177
+ authorityVersion: z.ZodNumber;
178
+ artifactDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
179
+ command: z.ZodDiscriminatedUnion<[z.ZodObject<{
180
+ kind: z.ZodLiteral<"install">;
181
+ }, z.core.$strict>, z.ZodObject<{
182
+ kind: z.ZodLiteral<"change-grants">;
183
+ changes: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
184
+ capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"approvals" | "agent.list" | "agent.manage" | "agent.rename" | "agent.avatar" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
185
+ grant: z.ZodNullable<z.ZodReadonly<z.ZodObject<{
186
+ operations: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
187
+ resources: z.ZodUnion<readonly [z.ZodLiteral<"tenant-scope">, z.ZodReadonly<z.ZodArray<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
188
+ kind: z.ZodString;
189
+ id: z.ZodString;
190
+ }, z.core.$strict>>>>>]>;
191
+ }, z.core.$strict>>>;
192
+ }, z.core.$strict>>>>;
193
+ }, z.core.$strict>, z.ZodObject<{
194
+ kind: z.ZodLiteral<"select-release">;
195
+ }, z.core.$strict>, z.ZodObject<{
196
+ kind: z.ZodLiteral<"delete">;
197
+ }, z.core.$strict>], "kind">;
198
+ }, z.core.$strict>;
199
+ /** Owner permission-page identity, artifact and current permission facts. */
200
+ export declare const appPermissionPageSchema: z.ZodObject<{
201
+ storeGeneration: z.ZodString;
202
+ installationId: z.ZodString;
203
+ appId: z.ZodString;
204
+ appName: z.ZodString;
205
+ artifactDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
206
+ permissions: z.ZodObject<{
207
+ authority: z.ZodObject<{
208
+ authorityVersion: z.ZodLazy<z.ZodNumber>;
209
+ declaredOperationsDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
210
+ approvedGrants: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
211
+ capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"approvals" | "agent.list" | "agent.manage" | "agent.rename" | "agent.avatar" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
212
+ capabilityApproved: z.ZodLiteral<true>;
213
+ operations: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
214
+ resources: z.ZodUnion<readonly [z.ZodLiteral<"tenant-scope">, z.ZodReadonly<z.ZodArray<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
215
+ kind: z.ZodString;
216
+ id: z.ZodString;
217
+ }, z.core.$strict>>>>>]>;
218
+ }, z.core.$strict>>>>>;
219
+ approval: z.ZodNullable<z.ZodLazy<z.ZodReadonly<z.ZodObject<{
220
+ by: import("zod/mini").ZodMiniDiscriminatedUnion<[import("zod/mini").ZodMiniObject<{
221
+ kind: import("zod/mini").ZodMiniLiteral<"member">;
222
+ memberId: import("zod/mini").ZodMiniString<string>;
223
+ }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
224
+ kind: import("zod/mini").ZodMiniLiteral<"agent">;
225
+ agentId: import("zod/mini").ZodMiniString<string>;
226
+ }, z.core.$strip>, import("zod/mini").ZodMiniObject<{
227
+ kind: import("zod/mini").ZodMiniLiteral<"team-key">;
228
+ keyId: import("zod/mini").ZodMiniString<string>;
229
+ }, z.core.$strip>], "kind">;
230
+ at: z.ZodNumber;
231
+ authorityVersion: z.ZodLazy<z.ZodNumber>;
232
+ }, z.core.$strict>>>>;
233
+ }, z.core.$strict>;
234
+ declaredOperations: z.ZodLazy<z.ZodObject<{
235
+ artifactDigest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
236
+ digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
237
+ anonymousMethods: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
238
+ name: z.ZodPipe<z.ZodUnknown, z.ZodTransform<string, unknown>>;
239
+ digest: z.ZodPipe<z.ZodUnknown, z.ZodTransform<import("@fungi.computer/puffball").Sha256Digest, unknown>>;
240
+ }, z.core.$strict>>>>;
241
+ capabilities: z.ZodReadonly<z.ZodArray<z.ZodReadonly<z.ZodObject<{
242
+ capability: z.ZodPipe<z.ZodUnknown, z.ZodTransform<"approvals" | "agent.list" | "agent.manage" | "agent.rename" | "agent.avatar" | "agent.toolPolicy" | "agent.read" | "agent.send" | "computer.list" | "computer.readFile" | "computer.writeFile" | "computer.execute" | "llm.generation" | "media.generation" | "games:servers" | "git.repository" | "apps.open" | "apps.call" | "app.storage" | "app.events.emit" | "team.workbenchHost" | "marketplace.browse" | "marketplace.purchase" | "workflow.run" | "workflow.publish" | "workflow.arm" | "world" | "channels.read" | "channels.personal.manage", unknown>>;
243
+ operations: z.ZodLazy<z.ZodReadonly<z.ZodArray<z.ZodString>>>;
244
+ }, z.core.$strict>>>>;
245
+ }, z.core.$strict>>;
246
+ }, z.core.$strict>;
247
+ }, z.core.$strict>;
@@ -0,0 +1,255 @@
1
+ import * as z from "zod";
2
+ import { permissionCatalog } from "./catalog.js";
3
+ import { sha256DigestSchema } from "@fungi.computer/puffball/effect";
4
+ import { appAuthoritySchema, declaredOperationsSchema, ownerCodec, grantCommandSchema, } from "./installation.js";
5
+ /** Includes newly declared operations and capabilities the owner has narrowed. */
6
+ export function pendingCapabilities(authority, declaration, declaredOperations) {
7
+ return declaration.capabilities.filter((capability) => {
8
+ if (permissionCatalog[capability].consent === "affordance")
9
+ return false;
10
+ const grant = authority.approvedGrants.find((row) => row.capability === capability);
11
+ return (grant === undefined ||
12
+ (grant.resources !== "tenant-scope" && grant.resources.length === 0) ||
13
+ declaredOperations.capabilities
14
+ .find((row) => row.capability === capability)
15
+ ?.operations.some((operation) => !grant.operations.includes(operation)) === true);
16
+ });
17
+ }
18
+ /** Bound the real SDK request; an Allow never silently widens selected resources. */
19
+ export function grantRequestFor(authority, facts, request, window) {
20
+ if (authority.declaredOperationsDigest !== facts.declaredOperations.digest)
21
+ return { kind: "refused", code: "stale_authority" };
22
+ const requested = [
23
+ ...new Set([...(request.agents ?? []), ...(request.computers ?? [])]),
24
+ ];
25
+ if (requested.some((capability) => !facts.declaration.capabilities.includes(capability)))
26
+ return { kind: "refused", code: "not_declared" };
27
+ const adds = [];
28
+ for (const capability of requested) {
29
+ const existing = authority.approvedGrants.find((row) => row.capability === capability);
30
+ const operations = facts.declaredOperations.capabilities.find((row) => row.capability === capability)?.operations ?? [];
31
+ if (existing !== undefined &&
32
+ existing.resources !== "tenant-scope" &&
33
+ existing.resources.length > 0) {
34
+ // approvedGrantSchema admits only capabilityApproved: true.
35
+ // A replay can use that approval, but cannot extend its finite scope.
36
+ if (permissionCatalog[capability].scope === "computer" &&
37
+ window.computerId !== null &&
38
+ existing.resources.some((resource) => resource.kind === "computer" && resource.id === window.computerId) &&
39
+ operations.every((operation) => existing.operations.includes(operation)))
40
+ continue;
41
+ return { kind: "customize" };
42
+ }
43
+ if (existing?.resources === "tenant-scope" &&
44
+ operations.every((operation) => existing.operations.includes(operation)))
45
+ continue;
46
+ let resources = "tenant-scope";
47
+ if (permissionCatalog[capability].scope === "computer") {
48
+ // Only the embedding host supplies this fact, never the App's request.
49
+ const computerId = window.computerId;
50
+ if (computerId == null)
51
+ return { kind: "refused", code: "window_scope_unavailable" };
52
+ resources = [{ kind: "computer", id: computerId }];
53
+ }
54
+ adds.push({ capability, grant: { operations, resources } });
55
+ }
56
+ if (adds.length === 0)
57
+ return { kind: "covered" };
58
+ return {
59
+ kind: "ask",
60
+ adds,
61
+ command: { kind: "change-grants", changes: adds },
62
+ };
63
+ }
64
+ /** The saved operation ceiling is the starting point, including empty operation rows. */
65
+ export function draftOf(authority) {
66
+ return new Map(authority.approvedGrants.map(({ capability, operations, resources }) => [
67
+ capability,
68
+ { operations, resources },
69
+ ]));
70
+ }
71
+ function sameGrant(a, b) {
72
+ if (a == null || b == null)
73
+ return a == null && b == null;
74
+ const sameValues = (left, right) => left.length === right.length &&
75
+ left.every((value) => right.includes(value));
76
+ if (!sameValues(a.operations, b.operations))
77
+ return false;
78
+ if (a.resources === "tenant-scope" || b.resources === "tenant-scope")
79
+ return a.resources === b.resources;
80
+ return (a.resources.length === b.resources.length &&
81
+ a.resources.every((resource) => b.resources !== "tenant-scope" &&
82
+ b.resources.some((other) => resource.kind === other.kind && resource.id === other.id)));
83
+ }
84
+ /** An edit changes one capability; unrelated saved operations and scopes are retained. */
85
+ export function editPermissions(draft, edit, declared) {
86
+ const row = declared.capabilities.find(({ capability }) => capability === edit.capability);
87
+ const policy = permissionCatalog[edit.capability];
88
+ if (row === undefined || policy.consent === "affordance")
89
+ return draft;
90
+ const next = new Map(draft);
91
+ const existing = draft.get(edit.capability);
92
+ const enabled = existing ?? {
93
+ operations: row.operations,
94
+ resources: "tenant-scope",
95
+ };
96
+ switch (edit.kind) {
97
+ case "switch":
98
+ next.set(edit.capability, edit.on ? enabled : null);
99
+ break;
100
+ case "all":
101
+ if (policy.scope === null)
102
+ return draft;
103
+ next.set(edit.capability, edit.on ? { ...enabled, resources: "tenant-scope" } : null);
104
+ break;
105
+ case "resource": {
106
+ if (policy.scope !== edit.resource.kind ||
107
+ existing?.resources === "tenant-scope")
108
+ return draft;
109
+ const resources = existing?.resources ?? [];
110
+ const kept = resources.filter((resource) => resource.kind !== edit.resource.kind ||
111
+ resource.id !== edit.resource.id);
112
+ const changed = edit.on ? [...kept, edit.resource] : kept;
113
+ next.set(edit.capability, changed.length === 0 ? null : { ...enabled, resources: changed });
114
+ break;
115
+ }
116
+ case "operation": {
117
+ if (edit.capability !== "apps.call" ||
118
+ !row.operations.includes(edit.operation))
119
+ return draft;
120
+ const kept = (existing?.operations ?? []).filter((operation) => operation !== edit.operation);
121
+ const operations = edit.on ? [...kept, edit.operation] : kept;
122
+ next.set(edit.capability, operations.length === 0 ? null : { ...enabled, operations });
123
+ break;
124
+ }
125
+ }
126
+ return next;
127
+ }
128
+ /** Only touched capability rows cross the save boundary. */
129
+ export function planGrantChange(baseline, draft) {
130
+ const saved = draftOf(baseline);
131
+ const capabilities = new Set([...saved.keys(), ...draft.keys()]);
132
+ return [...capabilities].flatMap((capability) => sameGrant(saved.get(capability), draft.get(capability))
133
+ ? []
134
+ : [{ capability, grant: draft.get(capability) ?? null }]);
135
+ }
136
+ /** A conflict preserves the person's edits while taking fresh untouched capabilities. */
137
+ export function rebaseDraft(draft, baseline, current) {
138
+ const rebased = new Map(draftOf(current));
139
+ for (const change of planGrantChange(baseline, draft))
140
+ rebased.set(change.capability, change.grant);
141
+ return rebased;
142
+ }
143
+ /** Serializable host facts; the browser derives presentation, never authority. */
144
+ export const appPermissionsWireSchema = z.strictObject({
145
+ authority: appAuthoritySchema,
146
+ declaredOperations: declaredOperationsSchema,
147
+ });
148
+ /** Every declared permission is visible, including removable saved resources no longer listed by the host. */
149
+ export function permissionScreen(input) {
150
+ const pending = pendingCapabilities(input.authority, {
151
+ capabilities: input.declaredOperations.capabilities.map((row) => row.capability),
152
+ }, input.declaredOperations);
153
+ const draft = draftOf(input.authority);
154
+ const grouped = new Map();
155
+ for (const { capability } of input.declaredOperations.capabilities) {
156
+ const group = permissionCatalog[capability].group;
157
+ grouped.set(group, [...(grouped.get(group) ?? []), capability]);
158
+ }
159
+ const column = (capability) => {
160
+ const { label, caption, description, sigil, warning } = permissionCatalog[capability];
161
+ return {
162
+ capability,
163
+ label,
164
+ caption,
165
+ description,
166
+ sigil,
167
+ warning,
168
+ pending: pending.includes(capability),
169
+ };
170
+ };
171
+ return {
172
+ canEdit: input.canEdit,
173
+ pending,
174
+ groups: [...grouped].map(([id, capabilities]) => {
175
+ const scoped = capabilities.filter((capability) => permissionCatalog[capability].scope !== null);
176
+ const scope = scoped.length === 0
177
+ ? null
178
+ : permissionCatalog[scoped[0] ?? "apps.open"].scope;
179
+ const resources = new Map(input.resources
180
+ .filter((resource) => resource.kind === scope)
181
+ .map((resource) => [resource.id, resource]));
182
+ for (const capability of scoped) {
183
+ const grant = draft.get(capability);
184
+ if (grant == null || grant.resources === "tenant-scope")
185
+ continue;
186
+ for (const resource of grant.resources) {
187
+ if (resource.kind === scope && !resources.has(resource.id))
188
+ resources.set(resource.id, { ...resource, label: resource.id });
189
+ }
190
+ }
191
+ const row = (resource, label) => ({
192
+ resource,
193
+ label,
194
+ cells: scoped.map((capability) => {
195
+ const grant = draft.get(capability);
196
+ const state = grant == null
197
+ ? "off"
198
+ : grant.resources === "tenant-scope"
199
+ ? resource === "all"
200
+ ? "on"
201
+ : "via-all"
202
+ : resource !== "all" &&
203
+ grant.resources.some((ref) => ref.kind === resource.kind && ref.id === resource.id)
204
+ ? "on"
205
+ : "off";
206
+ return { capability, state };
207
+ }),
208
+ });
209
+ return {
210
+ id,
211
+ scope,
212
+ columns: scoped.map(column),
213
+ rows: scope === null
214
+ ? []
215
+ : [
216
+ row("all", scope === "computer" ? "All Computers" : "All Agents"),
217
+ ...[...resources.values()].map((resource) => row(resource, resource.label)),
218
+ ],
219
+ switches: capabilities
220
+ .filter((capability) => permissionCatalog[capability].scope === null)
221
+ .map((capability) => ({
222
+ ...column(capability),
223
+ on: permissionCatalog[capability].consent === "affordance" ||
224
+ draft.get(capability) != null,
225
+ })),
226
+ operations: capabilities.includes("apps.call")
227
+ ? (input.declaredOperations.capabilities.find((capability) => capability.capability === "apps.call")?.operations ?? []).map((operation) => ({
228
+ capability: "apps.call",
229
+ operation,
230
+ on: draft.get("apps.call")?.operations.includes(operation) === true,
231
+ }))
232
+ : [],
233
+ };
234
+ }),
235
+ };
236
+ }
237
+ /** Owner-direct permission page and JSON projection. Copy stays in the catalog. */
238
+ export const permissionPinsSchema = z.strictObject({
239
+ storeGeneration: z.string().min(1),
240
+ authorityVersion: z.number().int().positive(),
241
+ artifactDigest: ownerCodec(sha256DigestSchema),
242
+ });
243
+ /** Permission edit command coupled to the version pins read by the owner. */
244
+ export const permissionSaveSchema = permissionPinsSchema.extend({
245
+ command: grantCommandSchema,
246
+ });
247
+ /** Owner permission-page identity, artifact and current permission facts. */
248
+ export const appPermissionPageSchema = z.strictObject({
249
+ storeGeneration: permissionPinsSchema.shape.storeGeneration,
250
+ installationId: z.string(),
251
+ appId: z.string(),
252
+ appName: z.string(),
253
+ artifactDigest: ownerCodec(sha256DigestSchema),
254
+ permissions: appPermissionsWireSchema,
255
+ });
@@ -0,0 +1,15 @@
1
+ import { type BootCapabilityStore } from "./boot-capability.js";
2
+ /** The artifact bucket read the route needs; an R2 bucket is one. */
3
+ export type BootAssetBucket = Readonly<{
4
+ get(key: string): Promise<Readonly<{
5
+ size: number;
6
+ body: ReadableStream<Uint8Array>;
7
+ }> | null>;
8
+ }>;
9
+ export type BootCapabilityRouteOptions = Readonly<{
10
+ configuredOrigin: string;
11
+ bucket: BootAssetBucket;
12
+ capabilities: BootCapabilityStore;
13
+ }>;
14
+ /** Worker-only HTTPS endpoint for a single digest-authorized boot lease. */
15
+ export declare function serveBootCapability(request: Request, options: BootCapabilityRouteOptions): Promise<Response | null>;