@fungi.computer/oyster 0.2.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (291) hide show
  1. package/README.md +396 -72
  2. package/dist/agents.d.ts +3 -2
  3. package/dist/agents.js +4 -2
  4. package/dist/app-builds.d.ts +81 -8
  5. package/dist/app-builds.js +213 -60
  6. package/dist/app-storage.d.ts +3 -3
  7. package/dist/approval-capability.d.ts +5 -0
  8. package/dist/approval-capability.js +46 -0
  9. package/dist/approval-home.d.ts +51 -0
  10. package/dist/approval-home.js +226 -0
  11. package/dist/apps/catalog.d.ts +335 -0
  12. package/dist/apps/catalog.js +46 -0
  13. package/dist/apps/gate.d.ts +20 -6
  14. package/dist/apps/gate.js +42 -16
  15. package/dist/apps/index.d.ts +3 -1
  16. package/dist/apps/index.js +3 -1
  17. package/dist/apps/installation.d.ts +132 -51
  18. package/dist/apps/installation.js +176 -70
  19. package/dist/apps/permissions.d.ts +247 -0
  20. package/dist/apps/permissions.js +255 -0
  21. package/dist/boot-capability-route.d.ts +15 -0
  22. package/dist/boot-capability-route.js +196 -0
  23. package/dist/boot-capability.d.ts +103 -0
  24. package/dist/boot-capability.js +141 -0
  25. package/dist/boot-construction.d.ts +12 -0
  26. package/dist/boot-construction.js +175 -0
  27. package/dist/boot-gate.d.ts +267 -0
  28. package/dist/boot-gate.js +236 -0
  29. package/dist/boot-host-script.d.ts +2 -0
  30. package/dist/boot-host-script.js +1 -0
  31. package/dist/boot-mount.d.ts +21 -0
  32. package/dist/boot-mount.js +65 -0
  33. package/dist/browser/boot.d.ts +73 -0
  34. package/dist/browser/boot.js +502 -0
  35. package/dist/browser/browser.d.ts +104 -0
  36. package/dist/browser/browser.js +374 -0
  37. package/dist/browser/capability-source.d.ts +76 -0
  38. package/dist/browser/capability-source.js +338 -0
  39. package/dist/browser/cdp-client.d.ts +56 -0
  40. package/dist/browser/cdp-client.js +184 -0
  41. package/dist/browser/errors.d.ts +79 -0
  42. package/dist/browser/errors.js +32 -0
  43. package/dist/browser/index.d.ts +16 -0
  44. package/dist/browser/index.js +14 -0
  45. package/dist/browser/lease-registry.d.ts +61 -0
  46. package/dist/browser/lease-registry.js +101 -0
  47. package/dist/browser/operations.d.ts +225 -0
  48. package/dist/browser/operations.js +137 -0
  49. package/dist/browser/page.d.ts +25 -0
  50. package/dist/browser/page.js +172 -0
  51. package/dist/browser/quick-reads.d.ts +29 -0
  52. package/dist/browser/quick-reads.js +160 -0
  53. package/dist/browser/sessions.d.ts +52 -0
  54. package/dist/browser/sessions.js +118 -0
  55. package/dist/browser/url-policy.d.ts +18 -0
  56. package/dist/browser/url-policy.js +58 -0
  57. package/dist/build/app-imports.d.ts +12 -0
  58. package/dist/build/app-imports.js +105 -0
  59. package/dist/build/build-policy.d.ts +5 -3
  60. package/dist/build/build-policy.js +5 -3
  61. package/dist/build/candidate-builder.d.ts +1 -1
  62. package/dist/build/candidate-cli.mjs +8375 -334
  63. package/dist/build/local-build.d.ts +2 -0
  64. package/dist/build/local-build.js +28 -6
  65. package/dist/build/snapshot-package-store.d.ts +1 -1
  66. package/dist/build/snapshot-package-store.js +7 -2
  67. package/dist/build/workspace-build.d.ts +92 -5
  68. package/dist/build/workspace-build.js +93 -19
  69. package/dist/build.d.ts +1 -1
  70. package/dist/build.js +1 -1
  71. package/dist/catalog-frame.js +1 -1
  72. package/dist/cloudflare.d.ts +13 -3
  73. package/dist/cloudflare.js +102 -4
  74. package/dist/frame-binding-wire-script.js +1 -1
  75. package/dist/frame-binding-wire.js +4 -2
  76. package/dist/git-auth.d.ts +0 -2
  77. package/dist/git-auth.js +0 -2
  78. package/dist/git.d.ts +0 -1
  79. package/dist/git.js +0 -2
  80. package/dist/host.d.ts +39 -13
  81. package/dist/host.js +268 -142
  82. package/dist/index.d.ts +25 -15
  83. package/dist/index.js +39 -16
  84. package/dist/install-release-cli.d.ts +2 -0
  85. package/dist/install-release-cli.js +46 -0
  86. package/dist/installation-client.d.ts +43 -0
  87. package/dist/installation-client.js +178 -0
  88. package/dist/installation-execution.d.ts +11 -0
  89. package/dist/installation-execution.js +184 -0
  90. package/dist/installation-operations.d.ts +1437 -0
  91. package/dist/installation-operations.js +664 -0
  92. package/dist/installation-store-generation.d.ts +3 -0
  93. package/dist/installation-store-generation.js +16 -0
  94. package/dist/instance-id.d.ts +10 -0
  95. package/dist/instance-id.js +10 -0
  96. package/dist/instance-refusal.d.ts +11 -0
  97. package/dist/instance-refusal.js +21 -0
  98. package/dist/internal/delivery.js +4 -2
  99. package/dist/internal/host-gate.js +7 -1
  100. package/dist/internal/registry-installations.js +4 -4
  101. package/dist/keys.d.ts +5 -1
  102. package/dist/keys.js +10 -2
  103. package/dist/machine-link/authority.d.ts +89 -0
  104. package/dist/machine-link/authority.js +37 -0
  105. package/dist/machine-link/client.d.ts +66 -0
  106. package/dist/machine-link/client.js +94 -0
  107. package/dist/machine-link/delivery.d.ts +18 -0
  108. package/dist/machine-link/delivery.js +55 -0
  109. package/dist/machine-link/enrollment.d.ts +111 -0
  110. package/dist/machine-link/enrollment.js +286 -0
  111. package/dist/machine-link/fences.d.ts +37 -0
  112. package/dist/machine-link/fences.js +166 -0
  113. package/dist/machine-link/home.d.ts +20 -0
  114. package/dist/machine-link/home.js +24 -0
  115. package/dist/machine-link/host.d.ts +43 -0
  116. package/dist/machine-link/host.js +189 -0
  117. package/dist/machine-link/index.d.ts +15 -0
  118. package/dist/machine-link/index.js +15 -0
  119. package/dist/machine-link/link.d.ts +48 -0
  120. package/dist/machine-link/link.js +223 -0
  121. package/dist/machine-link/presence.d.ts +10 -0
  122. package/dist/machine-link/presence.js +25 -0
  123. package/dist/machine-link/workers.d.ts +6 -0
  124. package/dist/machine-link/workers.js +6 -0
  125. package/dist/mcp-owner.d.ts +2 -2
  126. package/dist/mcp-owner.js +41 -33
  127. package/dist/mcp.d.ts +15 -3
  128. package/dist/mcp.js +146 -25
  129. package/dist/older-oyster-store-refusal.d.ts +4 -0
  130. package/dist/older-oyster-store-refusal.js +18 -0
  131. package/dist/older-oyster-store.d.ts +21 -0
  132. package/dist/older-oyster-store.js +43 -0
  133. package/dist/pack.d.ts +14 -3
  134. package/dist/pack.js +44 -19
  135. package/dist/page/app-access.d.ts +7 -0
  136. package/dist/page/app-access.js +75 -0
  137. package/dist/page/boot-host.js +57 -0
  138. package/dist/page/capabilities.d.ts +3 -3
  139. package/dist/page/capabilities.js +16 -12
  140. package/dist/page/computer-handles.d.ts +3 -3
  141. package/dist/page/computer-target.d.ts +3 -0
  142. package/dist/page/computer-target.js +9 -0
  143. package/dist/page/mount.d.ts +23 -3
  144. package/dist/page/mount.js +152 -16
  145. package/dist/page-assets.d.ts +22 -0
  146. package/dist/page-assets.js +28 -0
  147. package/dist/page-script.d.ts +3 -0
  148. package/dist/page-script.js +5 -4
  149. package/dist/release.d.ts +13 -6
  150. package/dist/release.js +10 -7
  151. package/dist/root-data.d.ts +16 -6
  152. package/dist/root-data.js +2 -2
  153. package/dist/source/index.d.ts +1 -1
  154. package/dist/source/team-source.d.ts +20 -8
  155. package/dist/source/team-source.js +39 -10
  156. package/dist/source/template-seed.d.ts +2 -2
  157. package/dist/standalone/agent-mail.d.ts +24 -0
  158. package/dist/standalone/agent-mail.js +62 -0
  159. package/dist/standalone/agent-store.d.ts +9 -0
  160. package/dist/standalone/agent-store.js +30 -0
  161. package/dist/standalone/agents.d.ts +68 -9
  162. package/dist/standalone/agents.js +428 -56
  163. package/dist/standalone/app-builds-binding.d.ts +20 -2
  164. package/dist/standalone/app-builds-binding.js +147 -23
  165. package/dist/standalone/app-set.d.ts +5 -2
  166. package/dist/standalone/app-set.js +186 -144
  167. package/dist/standalone/browser.d.ts +11 -0
  168. package/dist/standalone/browser.js +72 -0
  169. package/dist/standalone/builds.d.ts +13 -4
  170. package/dist/standalone/builds.js +28 -44
  171. package/dist/standalone/computer-egress.d.ts +2 -0
  172. package/dist/standalone/computer-egress.js +13 -4
  173. package/dist/standalone/computer-fleet.d.ts +43 -0
  174. package/dist/standalone/computer-fleet.js +200 -0
  175. package/dist/standalone/computer.d.ts +44 -9
  176. package/dist/standalone/computer.js +129 -22
  177. package/dist/standalone/install-apps-cli.js +43 -6
  178. package/dist/standalone/instance.d.ts +2 -2
  179. package/dist/standalone/instance.js +8 -11
  180. package/dist/standalone/machine-link.d.ts +354 -0
  181. package/dist/standalone/machine-link.js +368 -0
  182. package/dist/standalone/media.d.ts +2 -2
  183. package/dist/standalone/media.js +19 -16
  184. package/dist/standalone/preview.d.ts +2 -2
  185. package/dist/standalone/preview.js +37 -10
  186. package/dist/standalone/registry.d.ts +151 -9
  187. package/dist/standalone/registry.js +305 -8
  188. package/dist/standalone/worker.d.ts +19 -5
  189. package/dist/standalone/worker.js +90 -54
  190. package/dist/standalone/workflow-binding.d.ts +18 -22
  191. package/dist/standalone/workflow-binding.js +18 -18
  192. package/dist/standalone/workflow-control.d.ts +4 -0
  193. package/dist/standalone/workflow-control.js +40 -0
  194. package/dist/standalone/workflow-events.d.ts +2 -2
  195. package/dist/standalone/workflow-events.js +9 -10
  196. package/dist/standalone/workflow-git-capture.js +4 -3
  197. package/dist/standalone/workflow-host.d.ts +162 -161
  198. package/dist/standalone/workflow-host.js +101 -21
  199. package/dist/standalone/workflow-node-capture.js +11 -4
  200. package/dist/standalone/workflow-schedules.d.ts +5 -2
  201. package/dist/standalone/workflow-schedules.js +9 -10
  202. package/dist/standalone/workflow-trigger-host.d.ts +65 -5
  203. package/dist/standalone/workflow-trigger-host.js +2 -2
  204. package/dist/standalone/workflow-webhooks.d.ts +22 -0
  205. package/dist/standalone/workflow-webhooks.js +39 -0
  206. package/dist/standalone/workflows.d.ts +140 -43
  207. package/dist/standalone/workflows.js +198 -39
  208. package/dist/storage-frame.d.ts +6 -6
  209. package/dist/testing/capabilities.js +14 -3
  210. package/dist/testing/installation.js +26 -2
  211. package/dist/testing/worker.js +1 -1
  212. package/dist/testing/workers-runtime.d.ts +8 -2
  213. package/dist/testing/workers-runtime.js +20 -2
  214. package/dist/webhook-abuse.d.ts +25 -0
  215. package/dist/webhook-abuse.js +54 -0
  216. package/dist/webhook-custody.d.ts +144 -0
  217. package/dist/webhook-custody.js +222 -0
  218. package/dist/webhook-ingress.d.ts +36 -0
  219. package/dist/webhook-ingress.js +146 -0
  220. package/dist/webhooks.d.ts +111 -0
  221. package/dist/webhooks.js +189 -0
  222. package/dist/workers-git.d.ts +12 -17
  223. package/dist/workers-git.js +64 -52
  224. package/dist/workers.d.ts +226 -13
  225. package/dist/workers.js +363 -51
  226. package/dist/workflow-agent-authority.d.ts +8 -0
  227. package/dist/workflow-agent-authority.js +42 -0
  228. package/dist/workflows.d.ts +66 -0
  229. package/dist/workflows.js +97 -0
  230. package/docs/api/README.md +63 -37
  231. package/docs/api/agents.md +17 -0
  232. package/docs/api/app-storage.md +1 -1
  233. package/docs/api/apps.md +1394 -543
  234. package/docs/api/browser/boot.md +132 -0
  235. package/docs/api/browser.md +1440 -0
  236. package/docs/api/build-contract.md +38 -25
  237. package/docs/api/build.md +263 -84
  238. package/docs/api/cloudflare.md +93 -7
  239. package/docs/api/git.md +3 -13
  240. package/docs/api/host.md +944 -118
  241. package/docs/api/index.md +320 -18
  242. package/docs/api/keys.md +24 -1
  243. package/docs/api/mcp.md +59 -12
  244. package/docs/api/modules.md +33 -40
  245. package/docs/api/pack.md +57 -8
  246. package/docs/api/page/mount.md +92 -4
  247. package/docs/api/workers-git.md +103 -24
  248. package/docs/api/workers.md +1594 -244
  249. package/docs/site/agent-quickstart.mdx +28 -14
  250. package/examples/standalone/worker.ts +3 -1
  251. package/examples/standalone/wrangler.jsonc +2 -0
  252. package/package.json +73 -71
  253. package/dist/installation-consent.d.ts +0 -81
  254. package/dist/installation-consent.js +0 -84
  255. package/dist/shell/app-directory.d.ts +0 -542
  256. package/dist/shell/app-directory.js +0 -196
  257. package/dist/shell/browser-actions.d.ts +0 -7
  258. package/dist/shell/browser-actions.js +0 -56
  259. package/dist/shell/command-host.d.ts +0 -112
  260. package/dist/shell/command-host.js +0 -502
  261. package/dist/shell/commands.d.ts +0 -25
  262. package/dist/shell/commands.js +0 -78
  263. package/dist/shell/index.d.ts +0 -8
  264. package/dist/shell/index.js +0 -8
  265. package/dist/shell/keys.d.ts +0 -41
  266. package/dist/shell/keys.js +0 -134
  267. package/dist/shell/shell-module.d.ts +0 -55
  268. package/dist/shell/shell-module.js +0 -86
  269. package/dist/shell/window-manager.d.ts +0 -128
  270. package/dist/shell/window-manager.js +0 -730
  271. package/dist/shell/workbench-contract.d.ts +0 -68
  272. package/dist/shell/workbench-directory.d.ts +0 -332
  273. package/dist/shell/workbench-directory.js +0 -35
  274. package/dist/shell/workbench-host-types.d.ts +0 -96
  275. package/dist/shell/workbench-host-types.js +0 -1
  276. package/dist/shell/workbench-host.d.ts +0 -34
  277. package/dist/shell/workbench-host.js +0 -352
  278. package/dist/shell/workbench-model.d.ts +0 -194
  279. package/dist/shell/workbench-model.js +0 -53
  280. package/dist/shell/workbench.d.ts +0 -4
  281. package/dist/shell/workbench.js +0 -2
  282. package/docs/api/shell/app-directory.md +0 -599
  283. package/docs/api/shell/command-host.md +0 -224
  284. package/docs/api/shell/commands.md +0 -197
  285. package/docs/api/shell/keys.md +0 -183
  286. package/docs/api/shell/shell-module.md +0 -204
  287. package/docs/api/shell/window-manager.md +0 -267
  288. package/docs/api/shell/workbench-directory.md +0 -119
  289. package/docs/api/shell/workbench.md +0 -205
  290. package/docs/api/shell.md +0 -1915
  291. /package/dist/{shell/workbench-contract.js → page/boot-host.d.ts} +0 -0
@@ -4,7 +4,8 @@ import * as Result from "effect/Result";
4
4
  import { appCapabilityIdSchema, appApiMethodNameSchema, } from "@fungi.computer/puffball/app";
5
5
  import { hostActorSchema } from "@fungi.computer/puffball/app-method-runtime";
6
6
  import { appIdSchema, releaseSchema, sha256DigestSchema, } from "@fungi.computer/puffball/effect";
7
- import { instanceIdSchema } from "../index.js";
7
+ import { instanceIdSchema } from "../instance-id.js";
8
+ import { permissionCatalog } from "./catalog.js";
8
9
  /** Reuse the owning Effect codec at a JSON/storage boundary. */
9
10
  export function ownerCodec(schema) {
10
11
  const decode = Schema.decodeUnknownResult(schema, {
@@ -22,7 +23,7 @@ export function ownerCodec(schema) {
22
23
  /** Installation names cannot contain the tenant separator. */
23
24
  export const installationIdSchema = z.lazy(() => z.string().regex(/^[a-z](?:[a-z0-9]|-(?!-)){0,62}$/u));
24
25
  /** A resource identity minted and resolved by the host, never by this module. */
25
- const resourceRefSchema = z.lazy(() => z
26
+ export const resourceRefSchema = z.lazy(() => z
26
27
  .strictObject({
27
28
  kind: z.string().min(1),
28
29
  id: z.string().min(1),
@@ -38,10 +39,10 @@ const operationsSchema = z.lazy(() => z
38
39
  * no new consent; a new capability does. Release selection intersects stored
39
40
  * operations instead of adding approvals. Each Worker call is still restricted
40
41
  * to that method's declared requires, never the App's complete capability set.
41
- * Only an approved install or set-grants command mints capabilityApproved.
42
+ * Only an approved install or change-grants command mints capabilityApproved.
42
43
  * Empty operation rows retain that consent; removing the capability revokes it.
43
44
  * route:app.methods rows record approval detail, not a method allowlist: narrowing
44
- * them in set-grants does not restrict methods using an approved capability.
45
+ * them in change-grants does not restrict methods using an approved capability.
45
46
  * Exact operation rows are enforced for capability routes and backend bindings.
46
47
  */
47
48
  export const approvedGrantSchema = z
@@ -60,18 +61,23 @@ const approvedGrantsSchema = z.lazy(() => z
60
61
  .array(approvedGrantSchema)
61
62
  .refine((grants) => new Set(grants.map((grant) => grant.capability)).size === grants.length, "Capabilities must be unique")
62
63
  .readonly());
63
- /** Shorthand is accepted only on a command and expanded at approval time. */
64
- const grantRequestSchema = z.union([
65
- z.literal("none"),
66
- z.literal("declared"),
67
- z
68
- .array(approvedGrantSchema
64
+ /** A bounded owner edit. Unnamed approvals are not part of the command. */
65
+ export const grantChangeSchema = z
66
+ .strictObject({
67
+ capability: ownerCodec(appCapabilityIdSchema),
68
+ grant: approvedGrantSchema
69
69
  .unwrap()
70
- .omit({ capabilityApproved: true })
71
- .readonly())
72
- .refine((grants) => new Set(grants.map((grant) => grant.capability)).size === grants.length, "Capabilities must be unique")
73
- .readonly(),
74
- ]);
70
+ .omit({ capabilityApproved: true, capability: true })
71
+ .readonly()
72
+ .nullable(),
73
+ })
74
+ .readonly();
75
+ const grantChangesSchema = z
76
+ .array(grantChangeSchema)
77
+ .min(1)
78
+ .refine((changes) => new Set(changes.map((change) => change.capability)).size ===
79
+ changes.length, "Capabilities must be unique")
80
+ .readonly();
75
81
  const versionSchema = z.lazy(() => z.number().int().positive());
76
82
  /** An owner's approval of a fixed operation snapshot. */
77
83
  const approvalSchema = z.lazy(() => z
@@ -81,6 +87,109 @@ const approvalSchema = z.lazy(() => z
81
87
  authorityVersion: versionSchema,
82
88
  })
83
89
  .readonly());
90
+ /** The complete grant state. Hosts own storage and compare-and-set commits. */
91
+ export const appAuthoritySchema = z.strictObject({
92
+ authorityVersion: versionSchema,
93
+ declaredOperationsDigest: ownerCodec(sha256DigestSchema),
94
+ approvedGrants: approvedGrantsSchema,
95
+ approval: approvalSchema.nullable(),
96
+ });
97
+ export const grantCommandSchema = z.discriminatedUnion("kind", [
98
+ z.strictObject({ kind: z.literal("install") }),
99
+ z.strictObject({
100
+ kind: z.literal("change-grants"),
101
+ changes: grantChangesSchema,
102
+ }),
103
+ z.strictObject({ kind: z.literal("select-release") }),
104
+ z.strictObject({ kind: z.literal("delete") }),
105
+ ]);
106
+ /** One host-independent approval policy; selection only intersects existing grants. */
107
+ export function applyGrantCommand(current, rawCommand, context) {
108
+ const refuse = (code) => Result.fail({ kind: "refused", code });
109
+ const parsed = grantCommandSchema.safeParse(rawCommand);
110
+ if (!parsed.success)
111
+ return refuse("invalid_command");
112
+ const command = parsed.data;
113
+ if ((current === null && command.kind !== "install") ||
114
+ (current !== null && command.kind === "install"))
115
+ return refuse("invalid_command");
116
+ if ((context.expectedVersion ?? 0) !== (current?.authorityVersion ?? 0) ||
117
+ (current !== null &&
118
+ command.kind !== "select-release" &&
119
+ current.declaredOperationsDigest !== context.declaredOperations.digest))
120
+ return refuse("stale_authority");
121
+ if (context.principal.role === null ||
122
+ context.principal.actor.kind === "visitor" ||
123
+ (command.kind === "change-grants" && context.principal.role !== "owner"))
124
+ return refuse("not_owner");
125
+ const declared = (capability) => context.declaredOperations.capabilities.find((row) => row.capability === capability)?.operations ?? [];
126
+ const version = (current?.authorityVersion ?? 0) + 1;
127
+ let grants = current?.approvedGrants ?? [];
128
+ let approval = current?.approval ?? null;
129
+ switch (command.kind) {
130
+ case "install":
131
+ grants =
132
+ context.principal.role === "owner"
133
+ ? context.declaration.capabilities
134
+ .filter((capability) => permissionCatalog[capability].consent === "install")
135
+ .map((capability) => ({
136
+ capability,
137
+ capabilityApproved: true,
138
+ operations: declared(capability),
139
+ resources: "tenant-scope",
140
+ }))
141
+ : [];
142
+ break;
143
+ case "change-grants": {
144
+ for (const { capability, grant } of command.changes) {
145
+ if (!context.declaration.capabilities.includes(capability) ||
146
+ grant?.operations.some((operation) => !declared(capability).includes(operation)))
147
+ return refuse("not_declared");
148
+ const scope = permissionCatalog[capability].scope;
149
+ if (grant !== null &&
150
+ grant.resources !== "tenant-scope" &&
151
+ (scope === null ||
152
+ grant.resources.some((resource) => resource.kind !== scope)))
153
+ return refuse("invalid_command");
154
+ }
155
+ const changed = new Map(command.changes.map((change) => [change.capability, change.grant]));
156
+ grants = [
157
+ ...grants.filter((grant) => !changed.has(grant.capability)),
158
+ ...command.changes.flatMap(({ capability, grant }) => grant === null ||
159
+ (grant.resources !== "tenant-scope" && grant.resources.length === 0)
160
+ ? []
161
+ : [{ capability, ...grant, capabilityApproved: true }]),
162
+ ];
163
+ break;
164
+ }
165
+ case "select-release":
166
+ grants = grants
167
+ .filter((grant) => context.declaration.capabilities.includes(grant.capability))
168
+ .map((grant) => ({
169
+ ...grant,
170
+ operations: grant.operations.filter((operation) => declared(grant.capability).includes(operation)),
171
+ }));
172
+ break;
173
+ case "delete":
174
+ grants = [];
175
+ break;
176
+ }
177
+ if (grants.length === 0)
178
+ approval = null;
179
+ else if (command.kind === "install" || command.kind === "change-grants") {
180
+ approval = {
181
+ by: context.principal.actor,
182
+ at: context.now,
183
+ authorityVersion: version,
184
+ };
185
+ }
186
+ return Result.succeed({
187
+ authorityVersion: version,
188
+ declaredOperationsDigest: context.declaredOperations.digest,
189
+ approvedGrants: grants,
190
+ approval,
191
+ });
192
+ }
84
193
  const anonymousMethodsSchema = z
85
194
  .array(z
86
195
  .strictObject({
@@ -115,12 +224,9 @@ export const installationSchema = z
115
224
  appId: ownerCodec(appIdSchema),
116
225
  release: ownerCodec(releaseSchema),
117
226
  releasePin: z.enum(["pinned", "floating"]),
118
- authorityVersion: versionSchema,
227
+ authority: appAuthoritySchema,
119
228
  status: z.enum(["enabled", "disabled", "deleted"]),
120
229
  visibility: z.enum(["private", "public"]),
121
- declaredOperationsDigest: ownerCodec(sha256DigestSchema),
122
- approvedGrants: approvedGrantsSchema,
123
- approval: approvalSchema.nullable(),
124
230
  approvedAnonymousMethods: anonymousMethodsSchema,
125
231
  anonymousApproval: approvalSchema.nullable(),
126
232
  })
@@ -132,7 +238,7 @@ export const installationSchema = z
132
238
  : installation.status !== "deleted" &&
133
239
  installation.approvedAnonymousMethods.length > 0 &&
134
240
  approval.by.kind === "member" &&
135
- approval.authorityVersion <= installation.authorityVersion;
241
+ approval.authorityVersion <= installation.authority.authorityVersion;
136
242
  }, "Anonymous authority requires a retained human approval receipt");
137
243
  const releaseFields = {
138
244
  release: ownerCodec(releaseSchema),
@@ -143,7 +249,6 @@ export const installationCommandSchema = z.lazy(() => z.discriminatedUnion("kind
143
249
  z.strictObject({
144
250
  kind: z.literal("install"),
145
251
  ...releaseFields,
146
- grants: grantRequestSchema,
147
252
  }),
148
253
  z.strictObject({ kind: z.literal("select-release"), ...releaseFields }),
149
254
  z.strictObject({
@@ -155,8 +260,8 @@ export const installationCommandSchema = z.lazy(() => z.discriminatedUnion("kind
155
260
  visibility: installationSchema.shape.visibility,
156
261
  }),
157
262
  z.strictObject({
158
- kind: z.literal("set-grants"),
159
- grants: grantRequestSchema,
263
+ kind: z.literal("change-grants"),
264
+ changes: grantChangesSchema,
160
265
  }),
161
266
  z.strictObject({
162
267
  kind: z.literal("approve-anonymous"),
@@ -191,12 +296,10 @@ export function applyInstallationCommand(current, rawCommand, context) {
191
296
  return refuse("stale_authority");
192
297
  }
193
298
  else if (command.kind === "install" ||
194
- context.expectedVersion !== current.authorityVersion) {
299
+ context.expectedVersion !== current.authority.authorityVersion) {
195
300
  return refuse("stale_authority");
196
301
  }
197
- if ((command.kind === "set-grants" ||
198
- (command.kind === "install" && command.grants !== "none")) &&
199
- context.role !== "owner")
302
+ if (command.kind === "change-grants" && context.role !== "owner")
200
303
  return refuse("not_owner");
201
304
  const anonymousConsent = context.by.kind === "member" &&
202
305
  context.anonymousConsent?.memberId === context.by.memberId;
@@ -216,14 +319,38 @@ export function applyInstallationCommand(current, rawCommand, context) {
216
319
  release.artifact.artifactDigest ||
217
320
  (current !== null &&
218
321
  command.kind !== "select-release" &&
219
- context.declaredOperations.digest !== current.declaredOperationsDigest))
322
+ context.declaredOperations.digest !==
323
+ current.authority.declaredOperationsDigest))
220
324
  return refuse("stale_authority");
221
- const declared = (capability) => context.declaration.capabilities.includes(capability)
222
- ? (context.declaredOperations.capabilities.find((row) => row.capability === capability)?.operations ?? [])
223
- : [];
224
- const version = (current?.authorityVersion ?? 0) + 1;
225
- let grants = current?.approvedGrants ?? [];
226
- let approval = current?.approval ?? null;
325
+ const version = (current?.authority.authorityVersion ?? 0) + 1;
326
+ const grantCommand = command.kind === "install" || command.kind === "select-release"
327
+ ? { kind: command.kind }
328
+ : command.kind === "change-grants"
329
+ ? command
330
+ : command.kind === "set-status" && command.status === "deleted"
331
+ ? { kind: "delete" }
332
+ : null;
333
+ const authority = grantCommand === null
334
+ ? current === null
335
+ ? Result.fail({
336
+ kind: "refused",
337
+ code: "invalid_command",
338
+ })
339
+ : Result.succeed({
340
+ authorityVersion: version,
341
+ declaredOperationsDigest: current.authority.declaredOperationsDigest,
342
+ approvedGrants: current.authority.approvedGrants,
343
+ approval: current.authority.approval,
344
+ })
345
+ : applyGrantCommand(current?.authority ?? null, grantCommand, {
346
+ principal: { actor: context.by, role: context.role },
347
+ expectedVersion: context.expectedVersion,
348
+ declaration: context.declaration,
349
+ declaredOperations: context.declaredOperations,
350
+ now: context.now,
351
+ });
352
+ if (Result.isFailure(authority))
353
+ return refuse(authority.failure.code);
227
354
  let anonymousMethods = current?.approvedAnonymousMethods ?? [];
228
355
  let anonymousApproval = current?.anonymousApproval ?? null;
229
356
  if (command.kind === "approve-anonymous") {
@@ -240,44 +367,12 @@ export function applyInstallationCommand(current, rawCommand, context) {
240
367
  authorityVersion: version,
241
368
  };
242
369
  }
243
- if (command.kind === "install" || command.kind === "set-grants") {
244
- grants =
245
- command.grants === "none"
246
- ? []
247
- : command.grants === "declared"
248
- ? context.declaredOperations.capabilities
249
- .filter((row) => context.declaration.capabilities.includes(row.capability))
250
- .map((row) => ({
251
- ...row,
252
- capabilityApproved: true,
253
- resources: "tenant-scope",
254
- }))
255
- : command.grants.map((grant) => ({
256
- ...grant,
257
- capabilityApproved: true,
258
- }));
259
- if (grants.some((grant) => !context.declaration.capabilities.includes(grant.capability) ||
260
- grant.operations.some((operation) => !declared(grant.capability).includes(operation))))
261
- return refuse("not_declared");
262
- approval =
263
- command.grants === "none"
264
- ? null
265
- : { by: context.by, at: context.now, authorityVersion: version };
266
- }
267
370
  if (command.kind === "select-release") {
268
371
  anonymousMethods = anonymousMethods.filter((method) => context.declaredOperations.anonymousMethods.some((declared) => declared.name === method.name && declared.digest === method.digest));
269
372
  if (anonymousMethods.length === 0)
270
373
  anonymousApproval = null;
271
- grants = grants
272
- .map((grant) => ({
273
- ...grant,
274
- operations: grant.operations.filter((operation) => declared(grant.capability).includes(operation)),
275
- }))
276
- .filter((grant) => context.declaration.capabilities.includes(grant.capability));
277
374
  }
278
375
  if (command.kind === "set-status" && command.status === "deleted") {
279
- grants = [];
280
- approval = null;
281
376
  anonymousMethods = [];
282
377
  anonymousApproval = null;
283
378
  }
@@ -289,16 +384,13 @@ export function applyInstallationCommand(current, rawCommand, context) {
289
384
  releasePin: command.kind === "install" || command.kind === "select-release"
290
385
  ? command.releasePin
291
386
  : current?.releasePin,
292
- authorityVersion: version,
293
387
  status: command.kind === "set-status"
294
388
  ? command.status
295
389
  : (current?.status ?? "enabled"),
296
390
  visibility: command.kind === "set-visibility"
297
391
  ? command.visibility
298
392
  : (current?.visibility ?? "private"),
299
- declaredOperationsDigest: context.declaredOperations.digest,
300
- approvedGrants: grants,
301
- approval,
393
+ authority: authority.success,
302
394
  approvedAnonymousMethods: anonymousMethods,
303
395
  anonymousApproval,
304
396
  });
@@ -306,3 +398,17 @@ export function applyInstallationCommand(current, rawCommand, context) {
306
398
  ? Result.succeed({ next: next.data, authorityChanged: true })
307
399
  : refuse("invalid_command");
308
400
  }
401
+ /** Only the committed installation may activate this exact owner selection. */
402
+ export function isCommittedInstallation(current, state, release) {
403
+ return (current !== null &&
404
+ state.owner.kind === "installation" &&
405
+ current.installationId === state.owner.id &&
406
+ current.instanceId === state.instanceId &&
407
+ current.appId === state.appId &&
408
+ current.authority.authorityVersion === state.authorityVersion &&
409
+ current.status === state.status &&
410
+ current.release.releaseId === state.releaseId &&
411
+ release.releaseId === state.releaseId &&
412
+ release.appId === state.appId &&
413
+ current.release.artifact.artifactDigest === release.artifact.artifactDigest);
414
+ }
@@ -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>;