@fungi.computer/oyster 0.2.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 (287) hide show
  1. package/README.md +376 -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 +210 -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/pack.d.ts +14 -3
  130. package/dist/pack.js +44 -19
  131. package/dist/page/app-access.d.ts +7 -0
  132. package/dist/page/app-access.js +75 -0
  133. package/dist/page/boot-host.js +57 -0
  134. package/dist/page/capabilities.d.ts +3 -3
  135. package/dist/page/capabilities.js +16 -12
  136. package/dist/page/computer-handles.d.ts +3 -3
  137. package/dist/page/computer-target.d.ts +3 -0
  138. package/dist/page/computer-target.js +9 -0
  139. package/dist/page/mount.d.ts +23 -3
  140. package/dist/page/mount.js +152 -16
  141. package/dist/page-assets.d.ts +22 -0
  142. package/dist/page-assets.js +28 -0
  143. package/dist/page-script.d.ts +3 -0
  144. package/dist/page-script.js +5 -4
  145. package/dist/release.d.ts +13 -6
  146. package/dist/release.js +10 -7
  147. package/dist/root-data.d.ts +16 -6
  148. package/dist/root-data.js +2 -2
  149. package/dist/source/index.d.ts +1 -1
  150. package/dist/source/team-source.d.ts +20 -8
  151. package/dist/source/team-source.js +39 -10
  152. package/dist/source/template-seed.d.ts +2 -2
  153. package/dist/standalone/agent-mail.d.ts +24 -0
  154. package/dist/standalone/agent-mail.js +62 -0
  155. package/dist/standalone/agent-store.d.ts +9 -0
  156. package/dist/standalone/agent-store.js +30 -0
  157. package/dist/standalone/agents.d.ts +68 -9
  158. package/dist/standalone/agents.js +428 -56
  159. package/dist/standalone/app-builds-binding.d.ts +20 -2
  160. package/dist/standalone/app-builds-binding.js +147 -23
  161. package/dist/standalone/app-set.d.ts +5 -2
  162. package/dist/standalone/app-set.js +174 -143
  163. package/dist/standalone/browser.d.ts +11 -0
  164. package/dist/standalone/browser.js +72 -0
  165. package/dist/standalone/builds.d.ts +13 -4
  166. package/dist/standalone/builds.js +28 -44
  167. package/dist/standalone/computer-egress.d.ts +2 -0
  168. package/dist/standalone/computer-egress.js +13 -4
  169. package/dist/standalone/computer-fleet.d.ts +43 -0
  170. package/dist/standalone/computer-fleet.js +200 -0
  171. package/dist/standalone/computer.d.ts +44 -9
  172. package/dist/standalone/computer.js +129 -22
  173. package/dist/standalone/install-apps-cli.js +43 -6
  174. package/dist/standalone/instance.d.ts +2 -2
  175. package/dist/standalone/instance.js +8 -11
  176. package/dist/standalone/machine-link.d.ts +354 -0
  177. package/dist/standalone/machine-link.js +368 -0
  178. package/dist/standalone/media.d.ts +2 -2
  179. package/dist/standalone/media.js +19 -16
  180. package/dist/standalone/preview.d.ts +2 -2
  181. package/dist/standalone/preview.js +37 -10
  182. package/dist/standalone/registry.d.ts +149 -9
  183. package/dist/standalone/registry.js +299 -8
  184. package/dist/standalone/worker.d.ts +19 -5
  185. package/dist/standalone/worker.js +90 -54
  186. package/dist/standalone/workflow-binding.d.ts +18 -22
  187. package/dist/standalone/workflow-binding.js +18 -18
  188. package/dist/standalone/workflow-control.d.ts +4 -0
  189. package/dist/standalone/workflow-control.js +40 -0
  190. package/dist/standalone/workflow-events.d.ts +2 -2
  191. package/dist/standalone/workflow-events.js +9 -10
  192. package/dist/standalone/workflow-git-capture.js +4 -3
  193. package/dist/standalone/workflow-host.d.ts +162 -161
  194. package/dist/standalone/workflow-host.js +101 -21
  195. package/dist/standalone/workflow-node-capture.js +11 -4
  196. package/dist/standalone/workflow-schedules.d.ts +5 -2
  197. package/dist/standalone/workflow-schedules.js +9 -10
  198. package/dist/standalone/workflow-trigger-host.d.ts +65 -5
  199. package/dist/standalone/workflow-trigger-host.js +2 -2
  200. package/dist/standalone/workflow-webhooks.d.ts +22 -0
  201. package/dist/standalone/workflow-webhooks.js +39 -0
  202. package/dist/standalone/workflows.d.ts +140 -43
  203. package/dist/standalone/workflows.js +198 -39
  204. package/dist/storage-frame.d.ts +6 -6
  205. package/dist/testing/capabilities.js +14 -3
  206. package/dist/testing/installation.js +26 -2
  207. package/dist/testing/worker.js +1 -1
  208. package/dist/testing/workers-runtime.d.ts +8 -2
  209. package/dist/testing/workers-runtime.js +20 -2
  210. package/dist/webhook-abuse.d.ts +25 -0
  211. package/dist/webhook-abuse.js +54 -0
  212. package/dist/webhook-custody.d.ts +144 -0
  213. package/dist/webhook-custody.js +222 -0
  214. package/dist/webhook-ingress.d.ts +36 -0
  215. package/dist/webhook-ingress.js +146 -0
  216. package/dist/webhooks.d.ts +111 -0
  217. package/dist/webhooks.js +189 -0
  218. package/dist/workers-git.d.ts +12 -17
  219. package/dist/workers-git.js +60 -52
  220. package/dist/workers.d.ts +224 -13
  221. package/dist/workers.js +351 -51
  222. package/dist/workflow-agent-authority.d.ts +8 -0
  223. package/dist/workflow-agent-authority.js +42 -0
  224. package/dist/workflows.d.ts +66 -0
  225. package/dist/workflows.js +97 -0
  226. package/docs/api/README.md +63 -37
  227. package/docs/api/agents.md +17 -0
  228. package/docs/api/app-storage.md +1 -1
  229. package/docs/api/apps.md +1394 -543
  230. package/docs/api/browser/boot.md +132 -0
  231. package/docs/api/browser.md +1440 -0
  232. package/docs/api/build-contract.md +38 -25
  233. package/docs/api/build.md +263 -84
  234. package/docs/api/cloudflare.md +93 -7
  235. package/docs/api/git.md +3 -13
  236. package/docs/api/host.md +944 -118
  237. package/docs/api/index.md +320 -18
  238. package/docs/api/keys.md +24 -1
  239. package/docs/api/mcp.md +59 -12
  240. package/docs/api/modules.md +33 -40
  241. package/docs/api/pack.md +57 -8
  242. package/docs/api/page/mount.md +92 -4
  243. package/docs/api/workers-git.md +103 -24
  244. package/docs/api/workers.md +1581 -244
  245. package/docs/site/agent-quickstart.mdx +28 -14
  246. package/examples/standalone/worker.ts +3 -1
  247. package/examples/standalone/wrangler.jsonc +2 -0
  248. package/package.json +73 -71
  249. package/dist/installation-consent.d.ts +0 -81
  250. package/dist/installation-consent.js +0 -84
  251. package/dist/shell/app-directory.d.ts +0 -542
  252. package/dist/shell/app-directory.js +0 -196
  253. package/dist/shell/browser-actions.d.ts +0 -7
  254. package/dist/shell/browser-actions.js +0 -56
  255. package/dist/shell/command-host.d.ts +0 -112
  256. package/dist/shell/command-host.js +0 -502
  257. package/dist/shell/commands.d.ts +0 -25
  258. package/dist/shell/commands.js +0 -78
  259. package/dist/shell/index.d.ts +0 -8
  260. package/dist/shell/index.js +0 -8
  261. package/dist/shell/keys.d.ts +0 -41
  262. package/dist/shell/keys.js +0 -134
  263. package/dist/shell/shell-module.d.ts +0 -55
  264. package/dist/shell/shell-module.js +0 -86
  265. package/dist/shell/window-manager.d.ts +0 -128
  266. package/dist/shell/window-manager.js +0 -730
  267. package/dist/shell/workbench-contract.d.ts +0 -68
  268. package/dist/shell/workbench-directory.d.ts +0 -332
  269. package/dist/shell/workbench-directory.js +0 -35
  270. package/dist/shell/workbench-host-types.d.ts +0 -96
  271. package/dist/shell/workbench-host-types.js +0 -1
  272. package/dist/shell/workbench-host.d.ts +0 -34
  273. package/dist/shell/workbench-host.js +0 -352
  274. package/dist/shell/workbench-model.d.ts +0 -194
  275. package/dist/shell/workbench-model.js +0 -53
  276. package/dist/shell/workbench.d.ts +0 -4
  277. package/dist/shell/workbench.js +0 -2
  278. package/docs/api/shell/app-directory.md +0 -599
  279. package/docs/api/shell/command-host.md +0 -224
  280. package/docs/api/shell/commands.md +0 -197
  281. package/docs/api/shell/keys.md +0 -183
  282. package/docs/api/shell/shell-module.md +0 -204
  283. package/docs/api/shell/window-manager.md +0 -267
  284. package/docs/api/shell/workbench-directory.md +0 -119
  285. package/docs/api/shell/workbench.md +0 -205
  286. package/docs/api/shell.md +0 -1915
  287. /package/dist/{shell/workbench-contract.js → page/boot-host.d.ts} +0 -0
@@ -1,38 +1,63 @@
1
1
  /**
2
- * The APPS guest binding on the standalone Bonsai root: start a build job on
2
+ * The APPS guest binding on the standalone Bonsai root: register an App from
3
+ * its repository's committed root manifest, start a build job on
3
4
  * this Oyster's one Computer, read a job's status, and install (or switch) a
4
5
  * Release at an installation id. Every operation re-checks the caller is the
5
6
  * tenant owner; the binding carries no key and no owner secret.
6
7
  */
7
8
  import { z } from "zod";
9
+ import { buildStartFailureReply } from "./builds.js";
8
10
  import * as Schema from "effect/Schema";
9
11
  import { AppInstanceError } from "../index.js";
10
- import { installOrSelect } from "../host.js";
12
+ import { installOrSelect, verifyRelease, } from "../host.js";
13
+ import { repositoryWorkflowSourceSchema } from "@fungi.computer/workflows-wire";
11
14
  import { installationIdSchema } from "../apps/index.js";
12
15
  import { appIdSchema, releaseSchema } from "@fungi.computer/puffball/effect";
16
+ import { gitRepositoryNameSchema } from "@fungi.computer/puffball/git-representation";
13
17
  /** The calling tenant's registry owns its App builds. */
14
18
  const buildRegistry = (env, scope) => env.REGISTRY.getByName(scope.durableName("registry"));
19
+ const repositoryName = Schema.String.check(Schema.makeFilter((name) => gitRepositoryNameSchema.safeParse(name).success));
20
+ const registrationArgs = Schema.decodeUnknownSync(Schema.Tuple([Schema.Struct({ repo: repositoryName })]), { onExcessProperty: "error" });
15
21
  const buildInput = z.lazy(() => z.strictObject({
16
22
  appId: z.string().min(1).max(256),
17
23
  sourceRevision: z.string().min(1).max(256),
24
+ installationId: z.string().min(1).max(256).optional(),
18
25
  }));
19
- const buildStatusInput = z.lazy(() => z.strictObject({
20
- jobId: z.string().min(1).max(256),
21
- }));
26
+ // Workflows wait for their particular job; Settings discovers the latest
27
+ // job for its captured installation's repository after reload.
28
+ const buildStatusArgs = Schema.decodeUnknownSync(Schema.Tuple([
29
+ Schema.Union([
30
+ Schema.Struct({
31
+ jobId: Schema.String.check(Schema.isMinLength(1), Schema.isMaxLength(256)),
32
+ }),
33
+ Schema.Struct({ repo: repositoryName }),
34
+ ]),
35
+ ]), { onExcessProperty: "error" });
22
36
  const selectInput = z.lazy(() => z.strictObject({
23
37
  installationId: z.string().min(1).max(256),
38
+ jobId: z.string().min(1).max(256),
24
39
  release: z.unknown(),
25
40
  }));
26
41
  /** The Instance gate and native guest entrypoint share these argument codecs. */
27
42
  export const appsFrameMethods = {
28
43
  APPS: {
44
+ repository: {
45
+ decodeArgs: registrationArgs,
46
+ decodeResult: Schema.decodeUnknownSync(Schema.Json),
47
+ requiredOperations: () => ["repository"],
48
+ },
49
+ register: {
50
+ decodeArgs: registrationArgs,
51
+ decodeResult: Schema.decodeUnknownSync(Schema.Json),
52
+ requiredOperations: () => ["register"],
53
+ },
29
54
  build: {
30
55
  decodeArgs: (raw) => z.tuple([buildInput]).parse(raw),
31
56
  decodeResult: Schema.decodeUnknownSync(Schema.Json),
32
57
  requiredOperations: () => ["build"],
33
58
  },
34
59
  buildStatus: {
35
- decodeArgs: (raw) => z.tuple([buildStatusInput]).parse(raw),
60
+ decodeArgs: buildStatusArgs,
36
61
  decodeResult: Schema.decodeUnknownSync(Schema.Json),
37
62
  requiredOperations: () => ["buildStatus"],
38
63
  },
@@ -43,7 +68,7 @@ export const appsFrameMethods = {
43
68
  },
44
69
  },
45
70
  };
46
- /** Only a live owner call reaches build, status or select; a key or a
71
+ /** Only a live owner call reaches registration, build, status or select; a key or a
47
72
  * member without the owner role is refused before any registry or host read. */
48
73
  function callerOwner(frame) {
49
74
  const subject = frame.facts.subject;
@@ -61,36 +86,129 @@ export async function dispatchAppsBuildsBinding(env, scope, frame, props, method
61
86
  frame.signal.throwIfAborted();
62
87
  if (props.binding !== "APPS")
63
88
  throw new AppInstanceError("revoked");
89
+ if (method === "repository") {
90
+ const subject = frame.facts.subject;
91
+ if (frame.facts.selection.owner.kind !== "installation")
92
+ throw new AppInstanceError("revoked");
93
+ if (subject.kind === "call")
94
+ callerOwner(frame);
95
+ else if (subject.name !== "onGitPush")
96
+ throw new AppInstanceError("revoked");
97
+ const [input] = registrationArgs(args);
98
+ const installationId = frame.facts.selection.owner.id;
99
+ const source = await buildRegistry(env, scope).repositoryBuildSource(installationId, input.repo);
100
+ if (source === null)
101
+ return null;
102
+ const host = await backgroundHost();
103
+ if (host === null)
104
+ throw new AppInstanceError("revoked");
105
+ const installation = await host.installations.get(installationId);
106
+ if (installation?.status !== "enabled" ||
107
+ installation.instanceId !== frame.facts.instanceId ||
108
+ installation.authority.authorityVersion !==
109
+ frame.facts.selection.authorityVersion ||
110
+ installation.release.appId !== frame.facts.selection.appId ||
111
+ installation.release.releaseId !== frame.facts.selection.releaseId)
112
+ throw new AppInstanceError("revoked");
113
+ const verified = await verifyRelease(host.artifacts, installation.release, undefined, false);
114
+ frame.signal.throwIfAborted();
115
+ // invocationAuthorityOf pins executable backend bytes, not the App descriptor.
116
+ if (verified.backend?.digest !== frame.facts.artifactDigest)
117
+ throw new AppInstanceError("revoked");
118
+ return Schema.decodeUnknownSync(Schema.Json)(Schema.decodeUnknownSync(repositoryWorkflowSourceSchema)({
119
+ appId: source.appId,
120
+ installationId,
121
+ callerAppId: verified.release.appId,
122
+ callerSourceRevision: verified.release.artifact.provenance.sourceRevision,
123
+ }));
124
+ }
64
125
  const principal = callerOwner(frame);
65
126
  const requestedBy = principal.actor.kind === "member" ? principal.actor.memberId : "owner";
127
+ if (method === "register") {
128
+ const [input] = registrationArgs(args);
129
+ let result;
130
+ try {
131
+ result = await buildRegistry(env, scope).registerRepositoryApp({
132
+ memberId: requestedBy,
133
+ installationId: frame.facts.selection.owner.id,
134
+ repository: input.repo,
135
+ });
136
+ }
137
+ catch {
138
+ frame.signal.throwIfAborted();
139
+ return { status: 503, body: { error: "App registration unavailable" } };
140
+ }
141
+ frame.signal.throwIfAborted();
142
+ if (result.kind === "registered")
143
+ return {
144
+ status: 200,
145
+ body: { appId: result.appId, sourceRevision: result.sourceRevision },
146
+ };
147
+ switch (result.kind) {
148
+ case "unauthorized":
149
+ return { status: 403, body: { error: "Owner only" } };
150
+ case "invalid_app":
151
+ return {
152
+ status: 400,
153
+ body: { error: "Repository has no valid root App manifest" },
154
+ };
155
+ case "conflict":
156
+ return {
157
+ status: 409,
158
+ body: {
159
+ error: "App identity is already registered to another source",
160
+ },
161
+ };
162
+ }
163
+ }
66
164
  if (method === "build") {
67
165
  const [input] = z.tuple([buildInput]).parse(args);
68
166
  const appId = Schema.decodeUnknownSync(appIdSchema)(input.appId);
69
167
  const registry = buildRegistry(env, scope);
70
- let build;
168
+ const context = frame.facts.subject.kind === "call"
169
+ ? frame.facts.subject.context
170
+ : undefined;
171
+ const workflowRequestId = context?.workflow === undefined ? undefined : context.idempotencyKey;
172
+ if (context?.workflow !== undefined && workflowRequestId === undefined)
173
+ throw new AppInstanceError("revoked");
174
+ const request = {
175
+ appId,
176
+ sourceRevision: input.sourceRevision,
177
+ requestedBy,
178
+ };
179
+ if (input.installationId !== undefined && workflowRequestId === undefined)
180
+ throw new AppInstanceError("revoked");
181
+ if (workflowRequestId !== undefined) {
182
+ request.workflow = {
183
+ requestId: workflowRequestId,
184
+ callerInstallationId: frame.facts.selection.owner.id,
185
+ };
186
+ if (input.installationId !== undefined)
187
+ request.workflow.installationId = input.installationId;
188
+ }
189
+ let result;
71
190
  try {
72
- build = await registry.startBuild({
73
- appId,
74
- sourceRevision: input.sourceRevision,
75
- requestedBy,
76
- });
191
+ result = await registry.startBuild(request);
77
192
  }
78
193
  catch {
79
- return Schema.decodeUnknownSync(Schema.Json)({
80
- status: 409,
81
- body: { error: "App has no build source" },
82
- });
194
+ return Schema.decodeUnknownSync(Schema.Json)(buildStartFailureReply("unavailable"));
83
195
  }
84
196
  frame.signal.throwIfAborted();
85
- return Schema.decodeUnknownSync(Schema.Json)({ status: 202, body: build });
197
+ return Schema.decodeUnknownSync(Schema.Json)(result.kind === "started"
198
+ ? { status: 202, body: result.build }
199
+ : buildStartFailureReply(result.reason));
86
200
  }
87
201
  if (method === "buildStatus") {
88
- const [input] = z.tuple([buildStatusInput]).parse(args);
89
- const build = await buildRegistry(env, scope).readBuild(input.jobId);
202
+ const [input] = buildStatusArgs(args);
203
+ const registry = buildRegistry(env, scope);
204
+ const build = "repo" in input
205
+ ? await registry.readRepositoryBuild(frame.facts.selection.owner.id, input.repo)
206
+ : await registry.readBuild(input.jobId);
90
207
  frame.signal.throwIfAborted();
208
+ const missingJob = build === null && "jobId" in input;
91
209
  return Schema.decodeUnknownSync(Schema.Json)({
92
- status: build === null ? 404 : 200,
93
- body: build ?? { error: "Not found" },
210
+ status: missingJob ? 404 : 200,
211
+ body: missingJob ? { error: "Not found" } : build,
94
212
  });
95
213
  }
96
214
  if (method === "select") {
@@ -108,10 +226,16 @@ export async function dispatchAppsBuildsBinding(env, scope, frame, props, method
108
226
  body: { error: "Invalid Release" },
109
227
  });
110
228
  }
229
+ if (frame.facts.subject.kind === "call" &&
230
+ frame.facts.subject.context.workflow !== undefined) {
231
+ const result = await buildRegistry(env, scope).installWorkflowBuild(input.jobId, installationId, release, requestedBy, frame.facts.selection.owner.id);
232
+ frame.signal.throwIfAborted();
233
+ return Schema.decodeUnknownSync(Schema.Json)(result);
234
+ }
111
235
  const host = await backgroundHost();
112
236
  if (host === null)
113
237
  throw new AppInstanceError("revoked");
114
- const response = await installOrSelect(host, installationId, release, principal);
238
+ const response = await installOrSelect(host, installationId, release, principal, "install-or-select", "app");
115
239
  frame.signal.throwIfAborted();
116
240
  return Schema.decodeUnknownSync(Schema.Json)(await responseResult(response));
117
241
  }
@@ -1,14 +1,15 @@
1
1
  import * as Schema from "effect/Schema";
2
2
  import { type PackOptions } from "../pack.js";
3
- /** One starter App: where its source lives and how the Computer builds it. */
3
+ /** One starter App's identity and source; its manifest owns the build recipe. */
4
4
  export type StarterApp = Readonly<{
5
+ /** Selecting this configured dashboard approves its declared shell authority only. */
6
+ dashboard?: true;
5
7
  installationId: string;
6
8
  appId: string;
7
9
  /** The App's directory in a Botanical checkout; its recipe is rooted there. */
8
10
  directory: string;
9
11
  /** Its own public source repository's name, the App at that repository's root. */
10
12
  repository: string;
11
- recipe: PackOptions["recipe"];
12
13
  }>;
13
14
  export declare const standaloneAppSet: readonly StarterApp[];
14
15
  /** Where the starter Apps' sources come from. */
@@ -87,5 +88,7 @@ export declare function installStandaloneAppSet(options: Readonly<{
87
88
  recipe: PackOptions["recipe"];
88
89
  }>) => Promise<Response>;
89
90
  pollMs?: number;
91
+ /** The idle wait between build status reads; the real timer by default. */
92
+ idle?: (ms: number, signal: AbortSignal) => Promise<void>;
90
93
  waitMs?: number;
91
94
  }>): Promise<readonly InstalledStarterApp[]>;