@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
@@ -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[]>;