@fungi.computer/oyster 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (292) hide show
  1. package/README.md +376 -72
  2. package/dist/agent-avatars.d.ts +103 -0
  3. package/dist/agent-avatars.js +66 -0
  4. package/dist/agents.d.ts +15 -4
  5. package/dist/agents.js +43 -4
  6. package/dist/app-builds.d.ts +81 -8
  7. package/dist/app-builds.js +210 -60
  8. package/dist/app-storage.d.ts +3 -3
  9. package/dist/approval-capability.d.ts +5 -0
  10. package/dist/approval-capability.js +46 -0
  11. package/dist/approval-home.d.ts +51 -0
  12. package/dist/approval-home.js +226 -0
  13. package/dist/apps/catalog.d.ts +335 -0
  14. package/dist/apps/catalog.js +46 -0
  15. package/dist/apps/gate.d.ts +26 -12
  16. package/dist/apps/gate.js +48 -22
  17. package/dist/apps/index.d.ts +3 -1
  18. package/dist/apps/index.js +3 -1
  19. package/dist/apps/installation.d.ts +147 -66
  20. package/dist/apps/installation.js +193 -86
  21. package/dist/apps/permissions.d.ts +247 -0
  22. package/dist/apps/permissions.js +255 -0
  23. package/dist/boot-capability-route.d.ts +15 -0
  24. package/dist/boot-capability-route.js +196 -0
  25. package/dist/boot-capability.d.ts +103 -0
  26. package/dist/boot-capability.js +141 -0
  27. package/dist/boot-construction.d.ts +12 -0
  28. package/dist/boot-construction.js +175 -0
  29. package/dist/boot-gate.d.ts +267 -0
  30. package/dist/boot-gate.js +236 -0
  31. package/dist/boot-host-script.d.ts +2 -0
  32. package/dist/boot-host-script.js +1 -0
  33. package/dist/boot-mount.d.ts +21 -0
  34. package/dist/boot-mount.js +65 -0
  35. package/dist/browser/boot.d.ts +73 -0
  36. package/dist/browser/boot.js +502 -0
  37. package/dist/browser/browser.d.ts +104 -0
  38. package/dist/browser/browser.js +374 -0
  39. package/dist/browser/capability-source.d.ts +76 -0
  40. package/dist/browser/capability-source.js +338 -0
  41. package/dist/browser/cdp-client.d.ts +56 -0
  42. package/dist/browser/cdp-client.js +184 -0
  43. package/dist/browser/errors.d.ts +79 -0
  44. package/dist/browser/errors.js +32 -0
  45. package/dist/browser/index.d.ts +16 -0
  46. package/dist/browser/index.js +14 -0
  47. package/dist/browser/lease-registry.d.ts +61 -0
  48. package/dist/browser/lease-registry.js +101 -0
  49. package/dist/browser/operations.d.ts +225 -0
  50. package/dist/browser/operations.js +137 -0
  51. package/dist/browser/page.d.ts +25 -0
  52. package/dist/browser/page.js +172 -0
  53. package/dist/browser/quick-reads.d.ts +29 -0
  54. package/dist/browser/quick-reads.js +160 -0
  55. package/dist/browser/sessions.d.ts +52 -0
  56. package/dist/browser/sessions.js +118 -0
  57. package/dist/browser/url-policy.d.ts +18 -0
  58. package/dist/browser/url-policy.js +58 -0
  59. package/dist/build/app-imports.d.ts +12 -0
  60. package/dist/build/app-imports.js +105 -0
  61. package/dist/build/build-policy.d.ts +5 -3
  62. package/dist/build/build-policy.js +5 -3
  63. package/dist/build/candidate-builder.d.ts +1 -1
  64. package/dist/build/candidate-cli.mjs +8428 -337
  65. package/dist/build/local-build.d.ts +2 -0
  66. package/dist/build/local-build.js +28 -6
  67. package/dist/build/snapshot-package-store.d.ts +1 -1
  68. package/dist/build/snapshot-package-store.js +7 -2
  69. package/dist/build/workspace-build.d.ts +92 -5
  70. package/dist/build/workspace-build.js +93 -19
  71. package/dist/build-egress.js +4 -4
  72. package/dist/build.d.ts +1 -1
  73. package/dist/build.js +1 -1
  74. package/dist/catalog-frame.js +1 -1
  75. package/dist/cloudflare.d.ts +13 -3
  76. package/dist/cloudflare.js +106 -8
  77. package/dist/frame-binding-wire-script.js +1 -1
  78. package/dist/frame-binding-wire.d.ts +1 -1
  79. package/dist/frame-binding-wire.js +5 -3
  80. package/dist/git-auth.d.ts +0 -2
  81. package/dist/git-auth.js +0 -2
  82. package/dist/git-journal.js +4 -4
  83. package/dist/git.d.ts +0 -1
  84. package/dist/git.js +0 -2
  85. package/dist/host.d.ts +39 -13
  86. package/dist/host.js +268 -142
  87. package/dist/index.d.ts +26 -15
  88. package/dist/index.js +40 -16
  89. package/dist/install-release-cli.d.ts +2 -0
  90. package/dist/install-release-cli.js +46 -0
  91. package/dist/installation-client.d.ts +43 -0
  92. package/dist/installation-client.js +178 -0
  93. package/dist/installation-execution.d.ts +11 -0
  94. package/dist/installation-execution.js +184 -0
  95. package/dist/installation-operations.d.ts +1437 -0
  96. package/dist/installation-operations.js +664 -0
  97. package/dist/installation-store-generation.d.ts +3 -0
  98. package/dist/installation-store-generation.js +16 -0
  99. package/dist/instance-id.d.ts +10 -0
  100. package/dist/instance-id.js +10 -0
  101. package/dist/instance-refusal.d.ts +11 -0
  102. package/dist/instance-refusal.js +21 -0
  103. package/dist/internal/delivery.js +4 -2
  104. package/dist/internal/host-gate.js +7 -1
  105. package/dist/internal/registry-installations.js +4 -4
  106. package/dist/keys.d.ts +5 -1
  107. package/dist/keys.js +10 -2
  108. package/dist/machine-link/authority.d.ts +89 -0
  109. package/dist/machine-link/authority.js +37 -0
  110. package/dist/machine-link/client.d.ts +66 -0
  111. package/dist/machine-link/client.js +94 -0
  112. package/dist/machine-link/delivery.d.ts +18 -0
  113. package/dist/machine-link/delivery.js +55 -0
  114. package/dist/machine-link/enrollment.d.ts +111 -0
  115. package/dist/machine-link/enrollment.js +286 -0
  116. package/dist/machine-link/fences.d.ts +37 -0
  117. package/dist/machine-link/fences.js +166 -0
  118. package/dist/machine-link/home.d.ts +20 -0
  119. package/dist/machine-link/home.js +24 -0
  120. package/dist/machine-link/host.d.ts +43 -0
  121. package/dist/machine-link/host.js +189 -0
  122. package/dist/machine-link/index.d.ts +15 -0
  123. package/dist/machine-link/index.js +15 -0
  124. package/dist/machine-link/link.d.ts +48 -0
  125. package/dist/machine-link/link.js +223 -0
  126. package/dist/machine-link/presence.d.ts +10 -0
  127. package/dist/machine-link/presence.js +25 -0
  128. package/dist/machine-link/workers.d.ts +6 -0
  129. package/dist/machine-link/workers.js +6 -0
  130. package/dist/mcp-owner.d.ts +2 -2
  131. package/dist/mcp-owner.js +41 -33
  132. package/dist/mcp.d.ts +15 -3
  133. package/dist/mcp.js +146 -25
  134. package/dist/pack.d.ts +14 -3
  135. package/dist/pack.js +44 -19
  136. package/dist/page/app-access.d.ts +7 -0
  137. package/dist/page/app-access.js +75 -0
  138. package/dist/page/boot-host.js +57 -0
  139. package/dist/page/capabilities.d.ts +3 -3
  140. package/dist/page/capabilities.js +16 -12
  141. package/dist/page/computer-handles.d.ts +3 -3
  142. package/dist/page/computer-target.d.ts +3 -0
  143. package/dist/page/computer-target.js +9 -0
  144. package/dist/page/mount.d.ts +23 -7
  145. package/dist/page/mount.js +152 -16
  146. package/dist/page-assets.d.ts +22 -0
  147. package/dist/page-assets.js +28 -0
  148. package/dist/page-script.d.ts +3 -0
  149. package/dist/page-script.js +5 -4
  150. package/dist/release.d.ts +13 -6
  151. package/dist/release.js +10 -7
  152. package/dist/root-data.d.ts +16 -6
  153. package/dist/root-data.js +2 -2
  154. package/dist/source/index.d.ts +1 -1
  155. package/dist/source/team-source.d.ts +20 -8
  156. package/dist/source/team-source.js +39 -10
  157. package/dist/source/template-seed.d.ts +2 -2
  158. package/dist/standalone/agent-mail.d.ts +24 -0
  159. package/dist/standalone/agent-mail.js +62 -0
  160. package/dist/standalone/agent-store.d.ts +9 -0
  161. package/dist/standalone/agent-store.js +30 -0
  162. package/dist/standalone/agents.d.ts +78 -12
  163. package/dist/standalone/agents.js +470 -59
  164. package/dist/standalone/app-builds-binding.d.ts +20 -2
  165. package/dist/standalone/app-builds-binding.js +151 -27
  166. package/dist/standalone/app-set.d.ts +5 -2
  167. package/dist/standalone/app-set.js +174 -143
  168. package/dist/standalone/browser.d.ts +11 -0
  169. package/dist/standalone/browser.js +72 -0
  170. package/dist/standalone/builds.d.ts +13 -4
  171. package/dist/standalone/builds.js +28 -44
  172. package/dist/standalone/computer-egress.d.ts +2 -0
  173. package/dist/standalone/computer-egress.js +13 -4
  174. package/dist/standalone/computer-fleet.d.ts +43 -0
  175. package/dist/standalone/computer-fleet.js +200 -0
  176. package/dist/standalone/computer.d.ts +44 -9
  177. package/dist/standalone/computer.js +132 -25
  178. package/dist/standalone/install-apps-cli.js +43 -6
  179. package/dist/standalone/instance.d.ts +2 -2
  180. package/dist/standalone/instance.js +8 -11
  181. package/dist/standalone/machine-link.d.ts +354 -0
  182. package/dist/standalone/machine-link.js +368 -0
  183. package/dist/standalone/media.d.ts +2 -2
  184. package/dist/standalone/media.js +19 -16
  185. package/dist/standalone/preview.d.ts +2 -2
  186. package/dist/standalone/preview.js +39 -12
  187. package/dist/standalone/registry.d.ts +149 -9
  188. package/dist/standalone/registry.js +299 -8
  189. package/dist/standalone/worker.d.ts +19 -5
  190. package/dist/standalone/worker.js +90 -54
  191. package/dist/standalone/workflow-binding.d.ts +28 -32
  192. package/dist/standalone/workflow-binding.js +20 -20
  193. package/dist/standalone/workflow-control.d.ts +4 -0
  194. package/dist/standalone/workflow-control.js +40 -0
  195. package/dist/standalone/workflow-events.d.ts +2 -2
  196. package/dist/standalone/workflow-events.js +9 -10
  197. package/dist/standalone/workflow-git-capture.js +4 -3
  198. package/dist/standalone/workflow-host.d.ts +177 -152
  199. package/dist/standalone/workflow-host.js +137 -30
  200. package/dist/standalone/workflow-node-capture.js +11 -4
  201. package/dist/standalone/workflow-schedules.d.ts +5 -2
  202. package/dist/standalone/workflow-schedules.js +9 -10
  203. package/dist/standalone/workflow-trigger-host.d.ts +88 -6
  204. package/dist/standalone/workflow-trigger-host.js +2 -2
  205. package/dist/standalone/workflow-webhooks.d.ts +22 -0
  206. package/dist/standalone/workflow-webhooks.js +39 -0
  207. package/dist/standalone/workflows.d.ts +203 -50
  208. package/dist/standalone/workflows.js +198 -39
  209. package/dist/storage-frame.d.ts +6 -6
  210. package/dist/testing/capabilities.js +14 -3
  211. package/dist/testing/installation.js +26 -2
  212. package/dist/testing/worker.js +1 -1
  213. package/dist/testing/workers-runtime.d.ts +8 -2
  214. package/dist/testing/workers-runtime.js +20 -2
  215. package/dist/webhook-abuse.d.ts +25 -0
  216. package/dist/webhook-abuse.js +54 -0
  217. package/dist/webhook-custody.d.ts +144 -0
  218. package/dist/webhook-custody.js +222 -0
  219. package/dist/webhook-ingress.d.ts +36 -0
  220. package/dist/webhook-ingress.js +146 -0
  221. package/dist/webhooks.d.ts +111 -0
  222. package/dist/webhooks.js +189 -0
  223. package/dist/workers-git.d.ts +12 -17
  224. package/dist/workers-git.js +60 -55
  225. package/dist/workers.d.ts +224 -13
  226. package/dist/workers.js +351 -51
  227. package/dist/workflow-agent-authority.d.ts +8 -0
  228. package/dist/workflow-agent-authority.js +42 -0
  229. package/dist/workflows.d.ts +66 -0
  230. package/dist/workflows.js +97 -0
  231. package/docs/api/README.md +63 -37
  232. package/docs/api/agents.md +17 -0
  233. package/docs/api/app-storage.md +1 -1
  234. package/docs/api/apps.md +1394 -543
  235. package/docs/api/browser/boot.md +132 -0
  236. package/docs/api/browser.md +1440 -0
  237. package/docs/api/build-contract.md +38 -25
  238. package/docs/api/build.md +263 -84
  239. package/docs/api/cloudflare.md +93 -7
  240. package/docs/api/git.md +3 -13
  241. package/docs/api/host.md +944 -118
  242. package/docs/api/index.md +320 -18
  243. package/docs/api/keys.md +24 -1
  244. package/docs/api/mcp.md +59 -12
  245. package/docs/api/modules.md +33 -40
  246. package/docs/api/pack.md +57 -8
  247. package/docs/api/page/mount.md +92 -4
  248. package/docs/api/workers-git.md +103 -24
  249. package/docs/api/workers.md +1581 -244
  250. package/docs/site/agent-quickstart.mdx +28 -14
  251. package/examples/standalone/worker.ts +3 -1
  252. package/examples/standalone/wrangler.jsonc +2 -0
  253. package/package.json +73 -69
  254. package/dist/installation-consent.d.ts +0 -79
  255. package/dist/installation-consent.js +0 -82
  256. package/dist/shell/app-directory.d.ts +0 -542
  257. package/dist/shell/app-directory.js +0 -199
  258. package/dist/shell/browser-actions.d.ts +0 -7
  259. package/dist/shell/browser-actions.js +0 -56
  260. package/dist/shell/command-host.d.ts +0 -112
  261. package/dist/shell/command-host.js +0 -502
  262. package/dist/shell/commands.d.ts +0 -25
  263. package/dist/shell/commands.js +0 -78
  264. package/dist/shell/index.d.ts +0 -8
  265. package/dist/shell/index.js +0 -8
  266. package/dist/shell/keys.d.ts +0 -41
  267. package/dist/shell/keys.js +0 -134
  268. package/dist/shell/shell-module.d.ts +0 -55
  269. package/dist/shell/shell-module.js +0 -86
  270. package/dist/shell/window-manager.d.ts +0 -124
  271. package/dist/shell/window-manager.js +0 -711
  272. package/dist/shell/workbench-contract.d.ts +0 -68
  273. package/dist/shell/workbench-directory.d.ts +0 -332
  274. package/dist/shell/workbench-directory.js +0 -35
  275. package/dist/shell/workbench-host-types.d.ts +0 -96
  276. package/dist/shell/workbench-host-types.js +0 -1
  277. package/dist/shell/workbench-host.d.ts +0 -34
  278. package/dist/shell/workbench-host.js +0 -347
  279. package/dist/shell/workbench-model.d.ts +0 -192
  280. package/dist/shell/workbench-model.js +0 -53
  281. package/dist/shell/workbench.d.ts +0 -4
  282. package/dist/shell/workbench.js +0 -2
  283. package/docs/api/shell/app-directory.md +0 -599
  284. package/docs/api/shell/command-host.md +0 -224
  285. package/docs/api/shell/commands.md +0 -197
  286. package/docs/api/shell/keys.md +0 -183
  287. package/docs/api/shell/shell-module.md +0 -204
  288. package/docs/api/shell/window-manager.md +0 -267
  289. package/docs/api/shell/workbench-directory.md +0 -119
  290. package/docs/api/shell/workbench.md +0 -205
  291. package/docs/api/shell.md +0 -1915
  292. /package/dist/{shell/workbench-contract.js → page/boot-host.d.ts} +0 -0
@@ -7,17 +7,34 @@ import type { StandaloneComputerEnv } from "./computer.js";
7
7
  /** The Instance gate and native guest entrypoint share these argument codecs. */
8
8
  export declare const appsFrameMethods: {
9
9
  APPS: {
10
+ repository: {
11
+ decodeArgs: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => readonly [{
12
+ readonly repo: string;
13
+ }];
14
+ decodeResult: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => Schema.Json;
15
+ requiredOperations: () => string[];
16
+ };
17
+ register: {
18
+ decodeArgs: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => readonly [{
19
+ readonly repo: string;
20
+ }];
21
+ decodeResult: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => Schema.Json;
22
+ requiredOperations: () => string[];
23
+ };
10
24
  build: {
11
25
  decodeArgs: (raw: readonly unknown[]) => [{
12
26
  appId: string;
13
27
  sourceRevision: string;
28
+ installationId?: string | undefined;
14
29
  }];
15
30
  decodeResult: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => Schema.Json;
16
31
  requiredOperations: () => string[];
17
32
  };
18
33
  buildStatus: {
19
- decodeArgs: (raw: readonly unknown[]) => [{
20
- jobId: string;
34
+ decodeArgs: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => readonly [{
35
+ readonly jobId: string;
36
+ } | {
37
+ readonly repo: string;
21
38
  }];
22
39
  decodeResult: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => Schema.Json;
23
40
  requiredOperations: () => string[];
@@ -25,6 +42,7 @@ export declare const appsFrameMethods: {
25
42
  select: {
26
43
  decodeArgs: (raw: readonly unknown[]) => [{
27
44
  installationId: string;
45
+ jobId: string;
28
46
  release: unknown;
29
47
  }];
30
48
  decodeResult: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => Schema.Json;
@@ -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"));
15
- const buildInput = z.strictObject({
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" });
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),
18
- });
19
- const buildStatusInput = z.strictObject({
20
- jobId: z.string().min(1).max(256),
21
- });
22
- const selectInput = z.strictObject({
24
+ installationId: z.string().min(1).max(256).optional(),
25
+ }));
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" });
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[]>;