@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.
- package/README.md +396 -72
- package/dist/agents.d.ts +3 -2
- package/dist/agents.js +4 -2
- package/dist/app-builds.d.ts +81 -8
- package/dist/app-builds.js +213 -60
- package/dist/app-storage.d.ts +3 -3
- package/dist/approval-capability.d.ts +5 -0
- package/dist/approval-capability.js +46 -0
- package/dist/approval-home.d.ts +51 -0
- package/dist/approval-home.js +226 -0
- package/dist/apps/catalog.d.ts +335 -0
- package/dist/apps/catalog.js +46 -0
- package/dist/apps/gate.d.ts +20 -6
- package/dist/apps/gate.js +42 -16
- package/dist/apps/index.d.ts +3 -1
- package/dist/apps/index.js +3 -1
- package/dist/apps/installation.d.ts +132 -51
- package/dist/apps/installation.js +176 -70
- package/dist/apps/permissions.d.ts +247 -0
- package/dist/apps/permissions.js +255 -0
- package/dist/boot-capability-route.d.ts +15 -0
- package/dist/boot-capability-route.js +196 -0
- package/dist/boot-capability.d.ts +103 -0
- package/dist/boot-capability.js +141 -0
- package/dist/boot-construction.d.ts +12 -0
- package/dist/boot-construction.js +175 -0
- package/dist/boot-gate.d.ts +267 -0
- package/dist/boot-gate.js +236 -0
- package/dist/boot-host-script.d.ts +2 -0
- package/dist/boot-host-script.js +1 -0
- package/dist/boot-mount.d.ts +21 -0
- package/dist/boot-mount.js +65 -0
- package/dist/browser/boot.d.ts +73 -0
- package/dist/browser/boot.js +502 -0
- package/dist/browser/browser.d.ts +104 -0
- package/dist/browser/browser.js +374 -0
- package/dist/browser/capability-source.d.ts +76 -0
- package/dist/browser/capability-source.js +338 -0
- package/dist/browser/cdp-client.d.ts +56 -0
- package/dist/browser/cdp-client.js +184 -0
- package/dist/browser/errors.d.ts +79 -0
- package/dist/browser/errors.js +32 -0
- package/dist/browser/index.d.ts +16 -0
- package/dist/browser/index.js +14 -0
- package/dist/browser/lease-registry.d.ts +61 -0
- package/dist/browser/lease-registry.js +101 -0
- package/dist/browser/operations.d.ts +225 -0
- package/dist/browser/operations.js +137 -0
- package/dist/browser/page.d.ts +25 -0
- package/dist/browser/page.js +172 -0
- package/dist/browser/quick-reads.d.ts +29 -0
- package/dist/browser/quick-reads.js +160 -0
- package/dist/browser/sessions.d.ts +52 -0
- package/dist/browser/sessions.js +118 -0
- package/dist/browser/url-policy.d.ts +18 -0
- package/dist/browser/url-policy.js +58 -0
- package/dist/build/app-imports.d.ts +12 -0
- package/dist/build/app-imports.js +105 -0
- package/dist/build/build-policy.d.ts +5 -3
- package/dist/build/build-policy.js +5 -3
- package/dist/build/candidate-builder.d.ts +1 -1
- package/dist/build/candidate-cli.mjs +8375 -334
- package/dist/build/local-build.d.ts +2 -0
- package/dist/build/local-build.js +28 -6
- package/dist/build/snapshot-package-store.d.ts +1 -1
- package/dist/build/snapshot-package-store.js +7 -2
- package/dist/build/workspace-build.d.ts +92 -5
- package/dist/build/workspace-build.js +93 -19
- package/dist/build.d.ts +1 -1
- package/dist/build.js +1 -1
- package/dist/catalog-frame.js +1 -1
- package/dist/cloudflare.d.ts +13 -3
- package/dist/cloudflare.js +102 -4
- package/dist/frame-binding-wire-script.js +1 -1
- package/dist/frame-binding-wire.js +4 -2
- package/dist/git-auth.d.ts +0 -2
- package/dist/git-auth.js +0 -2
- package/dist/git.d.ts +0 -1
- package/dist/git.js +0 -2
- package/dist/host.d.ts +39 -13
- package/dist/host.js +268 -142
- package/dist/index.d.ts +25 -15
- package/dist/index.js +39 -16
- package/dist/install-release-cli.d.ts +2 -0
- package/dist/install-release-cli.js +46 -0
- package/dist/installation-client.d.ts +43 -0
- package/dist/installation-client.js +178 -0
- package/dist/installation-execution.d.ts +11 -0
- package/dist/installation-execution.js +184 -0
- package/dist/installation-operations.d.ts +1437 -0
- package/dist/installation-operations.js +664 -0
- package/dist/installation-store-generation.d.ts +3 -0
- package/dist/installation-store-generation.js +16 -0
- package/dist/instance-id.d.ts +10 -0
- package/dist/instance-id.js +10 -0
- package/dist/instance-refusal.d.ts +11 -0
- package/dist/instance-refusal.js +21 -0
- package/dist/internal/delivery.js +4 -2
- package/dist/internal/host-gate.js +7 -1
- package/dist/internal/registry-installations.js +4 -4
- package/dist/keys.d.ts +5 -1
- package/dist/keys.js +10 -2
- package/dist/machine-link/authority.d.ts +89 -0
- package/dist/machine-link/authority.js +37 -0
- package/dist/machine-link/client.d.ts +66 -0
- package/dist/machine-link/client.js +94 -0
- package/dist/machine-link/delivery.d.ts +18 -0
- package/dist/machine-link/delivery.js +55 -0
- package/dist/machine-link/enrollment.d.ts +111 -0
- package/dist/machine-link/enrollment.js +286 -0
- package/dist/machine-link/fences.d.ts +37 -0
- package/dist/machine-link/fences.js +166 -0
- package/dist/machine-link/home.d.ts +20 -0
- package/dist/machine-link/home.js +24 -0
- package/dist/machine-link/host.d.ts +43 -0
- package/dist/machine-link/host.js +189 -0
- package/dist/machine-link/index.d.ts +15 -0
- package/dist/machine-link/index.js +15 -0
- package/dist/machine-link/link.d.ts +48 -0
- package/dist/machine-link/link.js +223 -0
- package/dist/machine-link/presence.d.ts +10 -0
- package/dist/machine-link/presence.js +25 -0
- package/dist/machine-link/workers.d.ts +6 -0
- package/dist/machine-link/workers.js +6 -0
- package/dist/mcp-owner.d.ts +2 -2
- package/dist/mcp-owner.js +41 -33
- package/dist/mcp.d.ts +15 -3
- package/dist/mcp.js +146 -25
- package/dist/older-oyster-store-refusal.d.ts +4 -0
- package/dist/older-oyster-store-refusal.js +18 -0
- package/dist/older-oyster-store.d.ts +21 -0
- package/dist/older-oyster-store.js +43 -0
- package/dist/pack.d.ts +14 -3
- package/dist/pack.js +44 -19
- package/dist/page/app-access.d.ts +7 -0
- package/dist/page/app-access.js +75 -0
- package/dist/page/boot-host.js +57 -0
- package/dist/page/capabilities.d.ts +3 -3
- package/dist/page/capabilities.js +16 -12
- package/dist/page/computer-handles.d.ts +3 -3
- package/dist/page/computer-target.d.ts +3 -0
- package/dist/page/computer-target.js +9 -0
- package/dist/page/mount.d.ts +23 -3
- package/dist/page/mount.js +152 -16
- package/dist/page-assets.d.ts +22 -0
- package/dist/page-assets.js +28 -0
- package/dist/page-script.d.ts +3 -0
- package/dist/page-script.js +5 -4
- package/dist/release.d.ts +13 -6
- package/dist/release.js +10 -7
- package/dist/root-data.d.ts +16 -6
- package/dist/root-data.js +2 -2
- package/dist/source/index.d.ts +1 -1
- package/dist/source/team-source.d.ts +20 -8
- package/dist/source/team-source.js +39 -10
- package/dist/source/template-seed.d.ts +2 -2
- package/dist/standalone/agent-mail.d.ts +24 -0
- package/dist/standalone/agent-mail.js +62 -0
- package/dist/standalone/agent-store.d.ts +9 -0
- package/dist/standalone/agent-store.js +30 -0
- package/dist/standalone/agents.d.ts +68 -9
- package/dist/standalone/agents.js +428 -56
- package/dist/standalone/app-builds-binding.d.ts +20 -2
- package/dist/standalone/app-builds-binding.js +147 -23
- package/dist/standalone/app-set.d.ts +5 -2
- package/dist/standalone/app-set.js +186 -144
- package/dist/standalone/browser.d.ts +11 -0
- package/dist/standalone/browser.js +72 -0
- package/dist/standalone/builds.d.ts +13 -4
- package/dist/standalone/builds.js +28 -44
- package/dist/standalone/computer-egress.d.ts +2 -0
- package/dist/standalone/computer-egress.js +13 -4
- package/dist/standalone/computer-fleet.d.ts +43 -0
- package/dist/standalone/computer-fleet.js +200 -0
- package/dist/standalone/computer.d.ts +44 -9
- package/dist/standalone/computer.js +129 -22
- package/dist/standalone/install-apps-cli.js +43 -6
- package/dist/standalone/instance.d.ts +2 -2
- package/dist/standalone/instance.js +8 -11
- package/dist/standalone/machine-link.d.ts +354 -0
- package/dist/standalone/machine-link.js +368 -0
- package/dist/standalone/media.d.ts +2 -2
- package/dist/standalone/media.js +19 -16
- package/dist/standalone/preview.d.ts +2 -2
- package/dist/standalone/preview.js +37 -10
- package/dist/standalone/registry.d.ts +151 -9
- package/dist/standalone/registry.js +305 -8
- package/dist/standalone/worker.d.ts +19 -5
- package/dist/standalone/worker.js +90 -54
- package/dist/standalone/workflow-binding.d.ts +18 -22
- package/dist/standalone/workflow-binding.js +18 -18
- package/dist/standalone/workflow-control.d.ts +4 -0
- package/dist/standalone/workflow-control.js +40 -0
- package/dist/standalone/workflow-events.d.ts +2 -2
- package/dist/standalone/workflow-events.js +9 -10
- package/dist/standalone/workflow-git-capture.js +4 -3
- package/dist/standalone/workflow-host.d.ts +162 -161
- package/dist/standalone/workflow-host.js +101 -21
- package/dist/standalone/workflow-node-capture.js +11 -4
- package/dist/standalone/workflow-schedules.d.ts +5 -2
- package/dist/standalone/workflow-schedules.js +9 -10
- package/dist/standalone/workflow-trigger-host.d.ts +65 -5
- package/dist/standalone/workflow-trigger-host.js +2 -2
- package/dist/standalone/workflow-webhooks.d.ts +22 -0
- package/dist/standalone/workflow-webhooks.js +39 -0
- package/dist/standalone/workflows.d.ts +140 -43
- package/dist/standalone/workflows.js +198 -39
- package/dist/storage-frame.d.ts +6 -6
- package/dist/testing/capabilities.js +14 -3
- package/dist/testing/installation.js +26 -2
- package/dist/testing/worker.js +1 -1
- package/dist/testing/workers-runtime.d.ts +8 -2
- package/dist/testing/workers-runtime.js +20 -2
- package/dist/webhook-abuse.d.ts +25 -0
- package/dist/webhook-abuse.js +54 -0
- package/dist/webhook-custody.d.ts +144 -0
- package/dist/webhook-custody.js +222 -0
- package/dist/webhook-ingress.d.ts +36 -0
- package/dist/webhook-ingress.js +146 -0
- package/dist/webhooks.d.ts +111 -0
- package/dist/webhooks.js +189 -0
- package/dist/workers-git.d.ts +12 -17
- package/dist/workers-git.js +64 -52
- package/dist/workers.d.ts +226 -13
- package/dist/workers.js +363 -51
- package/dist/workflow-agent-authority.d.ts +8 -0
- package/dist/workflow-agent-authority.js +42 -0
- package/dist/workflows.d.ts +66 -0
- package/dist/workflows.js +97 -0
- package/docs/api/README.md +63 -37
- package/docs/api/agents.md +17 -0
- package/docs/api/app-storage.md +1 -1
- package/docs/api/apps.md +1394 -543
- package/docs/api/browser/boot.md +132 -0
- package/docs/api/browser.md +1440 -0
- package/docs/api/build-contract.md +38 -25
- package/docs/api/build.md +263 -84
- package/docs/api/cloudflare.md +93 -7
- package/docs/api/git.md +3 -13
- package/docs/api/host.md +944 -118
- package/docs/api/index.md +320 -18
- package/docs/api/keys.md +24 -1
- package/docs/api/mcp.md +59 -12
- package/docs/api/modules.md +33 -40
- package/docs/api/pack.md +57 -8
- package/docs/api/page/mount.md +92 -4
- package/docs/api/workers-git.md +103 -24
- package/docs/api/workers.md +1594 -244
- package/docs/site/agent-quickstart.mdx +28 -14
- package/examples/standalone/worker.ts +3 -1
- package/examples/standalone/wrangler.jsonc +2 -0
- package/package.json +73 -71
- package/dist/installation-consent.d.ts +0 -81
- package/dist/installation-consent.js +0 -84
- package/dist/shell/app-directory.d.ts +0 -542
- package/dist/shell/app-directory.js +0 -196
- package/dist/shell/browser-actions.d.ts +0 -7
- package/dist/shell/browser-actions.js +0 -56
- package/dist/shell/command-host.d.ts +0 -112
- package/dist/shell/command-host.js +0 -502
- package/dist/shell/commands.d.ts +0 -25
- package/dist/shell/commands.js +0 -78
- package/dist/shell/index.d.ts +0 -8
- package/dist/shell/index.js +0 -8
- package/dist/shell/keys.d.ts +0 -41
- package/dist/shell/keys.js +0 -134
- package/dist/shell/shell-module.d.ts +0 -55
- package/dist/shell/shell-module.js +0 -86
- package/dist/shell/window-manager.d.ts +0 -128
- package/dist/shell/window-manager.js +0 -730
- package/dist/shell/workbench-contract.d.ts +0 -68
- package/dist/shell/workbench-directory.d.ts +0 -332
- package/dist/shell/workbench-directory.js +0 -35
- package/dist/shell/workbench-host-types.d.ts +0 -96
- package/dist/shell/workbench-host-types.js +0 -1
- package/dist/shell/workbench-host.d.ts +0 -34
- package/dist/shell/workbench-host.js +0 -352
- package/dist/shell/workbench-model.d.ts +0 -194
- package/dist/shell/workbench-model.js +0 -53
- package/dist/shell/workbench.d.ts +0 -4
- package/dist/shell/workbench.js +0 -2
- package/docs/api/shell/app-directory.md +0 -599
- package/docs/api/shell/command-host.md +0 -224
- package/docs/api/shell/commands.md +0 -197
- package/docs/api/shell/keys.md +0 -183
- package/docs/api/shell/shell-module.md +0 -204
- package/docs/api/shell/window-manager.md +0 -267
- package/docs/api/shell/workbench-directory.md +0 -119
- package/docs/api/shell/workbench.md +0 -205
- package/docs/api/shell.md +0 -1915
- /package/dist/{shell/workbench-contract.js → page/boot-host.d.ts} +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
+
import { attachedBackendId, hostedBackingSchema, } from "@fungi.computer/computer/backing";
|
|
2
3
|
import { appMethodRefusalStatus, appMethodRefusedReplySchema, } from "@fungi.computer/agar/backend";
|
|
3
|
-
import { workflowGitPassResultSchema, } from "@fungi.computer/agar/computer-contracts";
|
|
4
4
|
import * as Schema from "effect/Schema";
|
|
5
5
|
import { computerPortsSchema, } from "@fungi.computer/agar/computer";
|
|
6
6
|
import { verifyRelease } from "../host.js";
|
|
@@ -9,15 +9,18 @@ import { createStandalonePreview, previewOrigins, previewSelectorSchema, Preview
|
|
|
9
9
|
import { standaloneTenancy } from "./tenancy.js";
|
|
10
10
|
import { Base64 } from "effect/encoding";
|
|
11
11
|
import * as z from "zod";
|
|
12
|
-
import { ComputerPortConflictError, computerByteReadReplySchema, computerProcessSchema, installationProcessScope, processStartInputSchema, processStartToolInputSchema, computerCapabilities, computerToolResultSchema, readOutputSchema, } from "@fungi.computer/computer
|
|
13
|
-
import { ComputerDO as NativeComputerDO,
|
|
14
|
-
import {
|
|
12
|
+
import { ComputerPortConflictError, computerByteReadReplySchema, computerProcessSchema, installationProcessScope, processStartInputSchema, processStartToolInputSchema, computerCapabilities, computerToolResultSchema, readOutputSchema, } from "@fungi.computer/computer-contract";
|
|
13
|
+
import { ComputerDO as NativeComputerDO, ComputerOperationConflictError, } from "@fungi.computer/computer";
|
|
14
|
+
import { ComputerFileConflict, computerExecutionRequestSchema, computerValueSchema, computerPortInputSchema, listInputSchema, listOutputSchema, readBytesInputSchema, writeInputSchema, replaceInputSchema, writeOutputSchema, mkdirOutputSchema, computerPortsOutputSchema, computerPortOutputSchema, computerPortRemovalOutputSchema, processListOutputSchema, processKillOutputSchema, computerOperationResultSchema, mintComputerRequestId, processIdInputSchema, } from "@fungi.computer/computer-contract";
|
|
15
|
+
import { workflowGitExecutionEnvironment, workflowGitPassGrantSchema, } from "@fungi.computer/braid/runtime";
|
|
16
|
+
import { checkComputerGrant, computerActionSchema, computerGrantSchema, createFleetBacking, FleetGrantRefused, FleetLifecycle, } from "@fungi.computer/computer/fleet";
|
|
15
17
|
import { AppInstanceError, selectionOf } from "../index.js";
|
|
16
18
|
import {} from "../cloudflare.js";
|
|
17
19
|
import { computerSlots } from "../computer.js";
|
|
18
20
|
import { oysterPrincipalId, oysterPrincipalIsOwner, } from "../host.js";
|
|
19
21
|
import { keyAllowsComputerUse } from "../keys.js";
|
|
20
|
-
import { oysterAppBuildTimeoutMs } from "../app-builds.js";
|
|
22
|
+
import { oysterAppBuildTimeoutMs, } from "../app-builds.js";
|
|
23
|
+
import { workflowGitStepGrant, } from "./workflow-binding.js";
|
|
21
24
|
const missingFile = z.lazy(() => z.object({ code: z.literal("ENOENT") }));
|
|
22
25
|
const workspaceId = computerGrantSchema.shape.computerId;
|
|
23
26
|
const command = computerExecutionRequestSchema({ maximumTimeMs: 45_000 }).omit({
|
|
@@ -109,11 +112,14 @@ const previewRefusal = appMethodRefusedReplySchema.parse({
|
|
|
109
112
|
code: "forbidden",
|
|
110
113
|
message: "Port previews belong to the current owner of an enabled installation.",
|
|
111
114
|
});
|
|
115
|
+
/** The non-secret context a native command carries for its admitted Git step. */
|
|
116
|
+
const workflowGitExecutionContextSchema = z.lazy(() => z.strictObject({ workflowGit: workflowGitPassGrantSchema }));
|
|
112
117
|
/** Durable workspace and existing backings, with fleet checks at native acceptance. */
|
|
113
118
|
export class ComputerDO extends NativeComputerDO {
|
|
114
119
|
previewBindings;
|
|
115
120
|
#backends;
|
|
116
121
|
#preview;
|
|
122
|
+
#lifecycle;
|
|
117
123
|
constructor(state, previewBindings) {
|
|
118
124
|
// The Computer's HTTP(S) egress goes only through the gateway the
|
|
119
125
|
// standalone Worker exports beside this object.
|
|
@@ -123,6 +129,50 @@ export class ComputerDO extends NativeComputerDO {
|
|
|
123
129
|
});
|
|
124
130
|
this.previewBindings = previewBindings;
|
|
125
131
|
}
|
|
132
|
+
#fleetLifecycle() {
|
|
133
|
+
if (this.#lifecycle !== undefined)
|
|
134
|
+
return this.#lifecycle;
|
|
135
|
+
this.#lifecycle = new FleetLifecycle({
|
|
136
|
+
storage: this.state.storage,
|
|
137
|
+
alarm: this.state,
|
|
138
|
+
computerId: this.#id(),
|
|
139
|
+
runtimeWatchMs: undefined,
|
|
140
|
+
backend: {
|
|
141
|
+
state: this.state,
|
|
142
|
+
onBoxVmHost: (hostId) => this.onBoxVmHost(hostId),
|
|
143
|
+
hostedContainerHost: (backing) => this.hostedContainerHost(backing),
|
|
144
|
+
readyWorkspace: () => this.readyWorkspace(),
|
|
145
|
+
workspace: () => this.workspace(),
|
|
146
|
+
syncRecycledWorkspace: async (backing) => {
|
|
147
|
+
const workspace = await this.readyWorkspace();
|
|
148
|
+
const id = attachedBackendId(backing);
|
|
149
|
+
await workspace.push(id);
|
|
150
|
+
await workspace.pull(id);
|
|
151
|
+
},
|
|
152
|
+
attachedBackends: () => this.attachedBackends(),
|
|
153
|
+
describeBackends: () => this.describeBackends(),
|
|
154
|
+
requireHostedRoute: () => this.requireHostedRoute(),
|
|
155
|
+
containerRunning: (backing) => this.containerRunning(backing),
|
|
156
|
+
// Standalone boots use the native host directly, not Hub's admission queue.
|
|
157
|
+
vmQueuePosition: () => Promise.resolve(null),
|
|
158
|
+
},
|
|
159
|
+
});
|
|
160
|
+
return this.#lifecycle;
|
|
161
|
+
}
|
|
162
|
+
/** Install the fleet's creation projection before exposing its new identity. */
|
|
163
|
+
initializeFleetBackings(backings) {
|
|
164
|
+
const owner = createFleetBacking(this.state.storage);
|
|
165
|
+
owner.ensure();
|
|
166
|
+
this.#backends = owner.computerCreated(this.#id(), z.array(hostedBackingSchema).parse(backings)).backends;
|
|
167
|
+
}
|
|
168
|
+
/** An admitted fleet control starts exactly this Computer's hosted backend. */
|
|
169
|
+
async startHostedComputer(authority) {
|
|
170
|
+
this.#accept(authority, "start");
|
|
171
|
+
return this.#fleetLifecycle().startHostedComputer(async (_backing, run) => {
|
|
172
|
+
this.#accept(authority, "start");
|
|
173
|
+
await run();
|
|
174
|
+
});
|
|
175
|
+
}
|
|
126
176
|
#previewGrant(ownerId) {
|
|
127
177
|
return {
|
|
128
178
|
computerId: this.#id(),
|
|
@@ -173,6 +223,12 @@ export class ComputerDO extends NativeComputerDO {
|
|
|
173
223
|
});
|
|
174
224
|
return this.#preview;
|
|
175
225
|
}
|
|
226
|
+
/** A read-only preflight over the maintained hosted-route selector. */
|
|
227
|
+
buildBackend() {
|
|
228
|
+
return this.hostedRoute() === undefined
|
|
229
|
+
? { kind: "no_backend" }
|
|
230
|
+
: { kind: "hosted" };
|
|
231
|
+
}
|
|
176
232
|
/**
|
|
177
233
|
* Run one App build job's fixed command, under the build budget. The
|
|
178
234
|
* registry that minted the job re-admits it for this Computer first.
|
|
@@ -186,7 +242,7 @@ export class ComputerDO extends NativeComputerDO {
|
|
|
186
242
|
cwd: "/workspace",
|
|
187
243
|
timeoutMs: input.timeoutMs,
|
|
188
244
|
requestId: mintComputerRequestId(),
|
|
189
|
-
}, () => undefined, "
|
|
245
|
+
}, () => undefined, "hosted", { maximumTimeMs: oysterAppBuildTimeoutMs });
|
|
190
246
|
const output = z
|
|
191
247
|
.object({ exitCode: z.number().nullable(), stderr: z.string() })
|
|
192
248
|
.safeParse(result.output);
|
|
@@ -231,6 +287,36 @@ export class ComputerDO extends NativeComputerDO {
|
|
|
231
287
|
#id() {
|
|
232
288
|
return workspaceId.parse(this.state.id.name);
|
|
233
289
|
}
|
|
290
|
+
/**
|
|
291
|
+
* The host side of native execution (Computer ABI 0edb0e4a): the grant's
|
|
292
|
+
* library run owner issues one credential for the invocation and the
|
|
293
|
+
* Computer hands it only to that command's Git environment.
|
|
294
|
+
*/
|
|
295
|
+
executionHooks() {
|
|
296
|
+
const issuer = (context) => {
|
|
297
|
+
const grant = workflowGitExecutionContextSchema.parse(context).workflowGit;
|
|
298
|
+
return {
|
|
299
|
+
grant,
|
|
300
|
+
runs: this.previewBindings.WORKFLOW_RUNS.getByName(grant.teamId),
|
|
301
|
+
};
|
|
302
|
+
};
|
|
303
|
+
return {
|
|
304
|
+
async open(invocation, context) {
|
|
305
|
+
const { grant, runs } = issuer(context);
|
|
306
|
+
return {
|
|
307
|
+
env: workflowGitExecutionEnvironment(await runs.issueWorkflowGit(invocation.id, grant)),
|
|
308
|
+
};
|
|
309
|
+
},
|
|
310
|
+
async renew(invocation, context) {
|
|
311
|
+
const { grant, runs } = issuer(context);
|
|
312
|
+
await runs.renewWorkflowGit(invocation.id, grant);
|
|
313
|
+
},
|
|
314
|
+
async close(invocation, context) {
|
|
315
|
+
const { grant, runs } = issuer(context);
|
|
316
|
+
await runs.closeWorkflowGit(invocation.id, grant);
|
|
317
|
+
},
|
|
318
|
+
};
|
|
319
|
+
}
|
|
234
320
|
attachedBackends() {
|
|
235
321
|
if (this.#backends !== undefined)
|
|
236
322
|
return this.#backends;
|
|
@@ -268,7 +354,12 @@ export class ComputerDO extends NativeComputerDO {
|
|
|
268
354
|
return output.parse(await this.callAfterAcceptance(tool, input, accept));
|
|
269
355
|
}
|
|
270
356
|
/** JSON operations keep the Computer's maintained parsers and execution engine. */
|
|
271
|
-
async value(authority, action, input) {
|
|
357
|
+
async value(authority, action, input, executionContext) {
|
|
358
|
+
// Only an exact public grant rides along, and only on a native command.
|
|
359
|
+
if (executionContext !== undefined &&
|
|
360
|
+
((action !== "exec" && action !== "processStart") ||
|
|
361
|
+
!workflowGitExecutionContextSchema.safeParse(executionContext).success))
|
|
362
|
+
throw new AppInstanceError("binding_unavailable");
|
|
272
363
|
const accept = () => {
|
|
273
364
|
this.#accept(authority, action);
|
|
274
365
|
};
|
|
@@ -283,7 +374,7 @@ export class ComputerDO extends NativeComputerDO {
|
|
|
283
374
|
return this.listProcessesAfterAcceptance(accept);
|
|
284
375
|
case "processStart":
|
|
285
376
|
try {
|
|
286
|
-
return await this.startProcessAfterAcceptance(input, accept);
|
|
377
|
+
return await this.startProcessAfterAcceptance(input, accept, executionContext);
|
|
287
378
|
}
|
|
288
379
|
catch (cause) {
|
|
289
380
|
if (cause instanceof ComputerOperationConflictError ||
|
|
@@ -294,7 +385,7 @@ export class ComputerDO extends NativeComputerDO {
|
|
|
294
385
|
case "processKill":
|
|
295
386
|
return this.killProcessAfterAcceptance(processIdInputSchema.parse(input), accept);
|
|
296
387
|
case "exec":
|
|
297
|
-
return this.executeOperationAfterAcceptance({ ...command.parse(input), requestId: mintComputerRequestId() }, accept, "bash", { maximumTimeMs: 45_000 });
|
|
388
|
+
return this.executeOperationAfterAcceptance({ ...command.parse(input), requestId: mintComputerRequestId() }, accept, "bash", { maximumTimeMs: 45_000 }, undefined, executionContext);
|
|
298
389
|
case "files.list":
|
|
299
390
|
return listOutputSchema.parse(await this.callAfterAcceptance("list", input, accept));
|
|
300
391
|
case "files.readBytes": {
|
|
@@ -406,8 +497,8 @@ export class ComputerDO extends NativeComputerDO {
|
|
|
406
497
|
* omit it, since a team-key principal then simply never reaches the
|
|
407
498
|
* Computer, rather than reading `env.KEYS` directly and skipping the check.
|
|
408
499
|
*/
|
|
409
|
-
export function standaloneWorkspace(env, keysLive) {
|
|
410
|
-
const computerId = workspaceId.parse(
|
|
500
|
+
export function standaloneWorkspace(env, keysLive, selectedComputerId = env.OYSTER_COMPUTER_ID) {
|
|
501
|
+
const computerId = workspaceId.parse(selectedComputerId);
|
|
411
502
|
const computer = () => env.COMPUTER.getByName(computerId);
|
|
412
503
|
const authority = () => grant(computerId, "oyster-workspace");
|
|
413
504
|
return {
|
|
@@ -524,11 +615,6 @@ export function standaloneComputerCapabilities(env, workspace, keysLive) {
|
|
|
524
615
|
/** Closed COMPUTER binding codecs, joined into the standalone Instance. */
|
|
525
616
|
export const computerFrameMethods = {
|
|
526
617
|
COMPUTER: {
|
|
527
|
-
workflowGitPass: {
|
|
528
|
-
decodeArgs: (args) => z.tuple([empty]).parse(args),
|
|
529
|
-
decodeResult: (value) => workflowGitPassResultSchema.parse(value),
|
|
530
|
-
requiredOperations: () => ["workflowGitPass"],
|
|
531
|
-
},
|
|
532
618
|
list: {
|
|
533
619
|
decodeArgs: (args) => z.tuple([listInputSchema]).parse(args),
|
|
534
620
|
decodeResult: (value) => listOutputSchema.parse(value),
|
|
@@ -592,13 +678,13 @@ export const computerFrameMethods = {
|
|
|
592
678
|
/** Owner-only preview tickets carry the verified frame's Installation selection. */
|
|
593
679
|
async function computerPreviewInvocation(env, frame, args) {
|
|
594
680
|
const subject = frame.facts.subject;
|
|
595
|
-
const computerId = workspaceId.parse(env.OYSTER_COMPUTER_ID);
|
|
596
681
|
const owner = frame.facts.selection.owner;
|
|
597
682
|
if (subject.kind !== "call" ||
|
|
598
683
|
subject.context.actor.kind !== "member" ||
|
|
599
684
|
subject.context.role !== "owner" ||
|
|
600
685
|
owner.kind !== "installation")
|
|
601
686
|
throw new AppInstanceError("revoked");
|
|
687
|
+
const computerId = workspaceId.parse(subject.context.computerId);
|
|
602
688
|
// The admitted owner's member ID; the Computer owner proves it is still
|
|
603
689
|
// the live canonical owner before issuing any ticket.
|
|
604
690
|
const ownerId = subject.context.actor.memberId;
|
|
@@ -623,12 +709,27 @@ async function computerPreviewInvocation(env, frame, args) {
|
|
|
623
709
|
throw new AppInstanceError("revoked");
|
|
624
710
|
return preview;
|
|
625
711
|
}
|
|
626
|
-
/**
|
|
627
|
-
|
|
712
|
+
/** Re-admit the Computer captured by this invocation, never the current UI selection. */
|
|
713
|
+
async function frameComputerId(env, scope, frame) {
|
|
714
|
+
frame.signal.throwIfAborted();
|
|
715
|
+
const subject = frame.facts.subject;
|
|
716
|
+
if (subject.kind !== "call" || subject.context.computerId === null)
|
|
717
|
+
throw new AppInstanceError("revoked");
|
|
718
|
+
const computerId = workspaceId.parse(subject.context.computerId);
|
|
719
|
+
if (!(await env.REGISTRY.getByName(scope.durableName("registry")).ownsComputer(computerId)))
|
|
720
|
+
throw new AppInstanceError("revoked");
|
|
628
721
|
frame.signal.throwIfAborted();
|
|
722
|
+
return computerId;
|
|
723
|
+
}
|
|
724
|
+
/** Media and Computer bindings capture the same inventory-admitted workspace. */
|
|
725
|
+
export async function standaloneFrameWorkspace(env, scope, frame) {
|
|
726
|
+
return standaloneWorkspace(env, undefined, await frameComputerId(env, scope, frame));
|
|
727
|
+
}
|
|
728
|
+
/** Dispatch one admitted COMPUTER operation under its captured frame. */
|
|
729
|
+
export async function computerInvocation(env, scope, frame, method, args) {
|
|
730
|
+
const computerId = await frameComputerId(env, scope, frame);
|
|
629
731
|
const subject = frame.facts.subject;
|
|
630
|
-
|
|
631
|
-
if (subject.kind !== "call" || subject.context.computerId !== computerId)
|
|
732
|
+
if (subject.kind !== "call")
|
|
632
733
|
throw new AppInstanceError("revoked");
|
|
633
734
|
const actor = subject.context.actor;
|
|
634
735
|
if (method === "preview")
|
|
@@ -703,6 +804,10 @@ export function computerInvocation(env, frame, method, args) {
|
|
|
703
804
|
default:
|
|
704
805
|
throw new AppInstanceError("revoked");
|
|
705
806
|
}
|
|
807
|
+
// A Workflow Git step's native commands carry only its public grant.
|
|
808
|
+
const grant = action === "exec" || action === "processStart"
|
|
809
|
+
? await workflowGitStepGrant(env, env.REGISTRY.getByName(scope.durableName("registry")), frame)
|
|
810
|
+
: null;
|
|
706
811
|
const native = env.COMPUTER.getByName(computerId);
|
|
707
812
|
frame.signal.throwIfAborted();
|
|
708
813
|
return native.value({
|
|
@@ -710,5 +815,7 @@ export function computerInvocation(env, frame, method, args) {
|
|
|
710
815
|
actions: new Set([action]),
|
|
711
816
|
expiresAt: Math.min(frame.facts.deadlineAt, Date.now() + 60_000),
|
|
712
817
|
provenance: { actor: `${actor.kind}:${actorId}` },
|
|
713
|
-
}, action, input
|
|
818
|
+
}, action, input, grant === null
|
|
819
|
+
? undefined
|
|
820
|
+
: computerValueSchema.parse(JSON.parse(JSON.stringify({ workflowGit: grant }))));
|
|
714
821
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// `oyster install-apps`: seed, build on the Oyster's own Computer, and install
|
|
3
|
-
// the starter Apps (Tourtois, Bonsai, Shed, Inkcap, Trellis, Prints
|
|
4
|
-
// Grove). Each
|
|
5
|
-
// Botanical checkout with `--from <directory>`.
|
|
3
|
+
// the seven starter Apps (Tourtois, Bonsai, Shed, Inkcap, Trellis, Prints,
|
|
4
|
+
// and Grove). Each comes from its own public repository by default,
|
|
5
|
+
// or from a Botanical checkout with `--from <directory>`.
|
|
6
6
|
//
|
|
7
7
|
// OYSTER_URL=https://… OYSTER_OWNER_KEY=… oyster install-apps
|
|
8
8
|
// [--repositories <base URL>] [--ref <branch or tag>]
|
|
@@ -13,10 +13,39 @@ import { tmpdir } from "node:os";
|
|
|
13
13
|
import { join, resolve } from "node:path";
|
|
14
14
|
import process from "node:process";
|
|
15
15
|
import { parseArgs } from "node:util";
|
|
16
|
+
import { installReleaseCommand, installReleaseUsage, } from "../install-release-cli.js";
|
|
16
17
|
import { defaultStarterBuildConcurrency, installStandaloneAppSet, } from "./app-set.js";
|
|
17
18
|
/** The starter Apps' public source repositories. */
|
|
18
19
|
const defaultRepositories = "https://github.com/fungi-computer";
|
|
19
20
|
const usage = "Usage: oyster install-apps [--repositories <base URL>] [--ref <ref>] [--from <checkout>] [--concurrency 1-3] [--timings <file>]";
|
|
21
|
+
const urlSource = "OYSTER_URL is the address of your deployed Oyster Worker, such as https://oyster.<your-subdomain>.workers.dev (http://127.0.0.1:8787 for a local one). You set it when you deploy.";
|
|
22
|
+
const keySource = "OYSTER_OWNER_KEY is the owner key you chose for that Oyster: export OYSTER_OWNER_KEY=$(openssl rand -hex 24), then store it with `wrangler secret put OYSTER_OWNER_KEY`.";
|
|
23
|
+
const helpText = `${usage}
|
|
24
|
+
|
|
25
|
+
Builds the seven starter Apps on your Oyster's own Computer and installs them.
|
|
26
|
+
Starter builds need a deployed Oyster host; this command does not create one.
|
|
27
|
+
Deploy first (see the Oyster README), then set:
|
|
28
|
+
|
|
29
|
+
${urlSource}
|
|
30
|
+
${keySource}
|
|
31
|
+
|
|
32
|
+
Options:
|
|
33
|
+
--repositories <base URL> fetch each App from <base URL> instead of the public repositories
|
|
34
|
+
--ref <ref> branch or tag to build (default main)
|
|
35
|
+
--from <checkout> install from a Botanical checkout directory
|
|
36
|
+
--concurrency 1-3 Apps to build at once
|
|
37
|
+
--timings <file> write the build timings as JSON
|
|
38
|
+
-h, --help show this help
|
|
39
|
+
`;
|
|
40
|
+
function missingVariableMessage(url, key) {
|
|
41
|
+
const lines = [];
|
|
42
|
+
if (!url)
|
|
43
|
+
lines.push(`OYSTER_URL is not set. ${urlSource}`);
|
|
44
|
+
if (!key)
|
|
45
|
+
lines.push(`OYSTER_OWNER_KEY is not set. ${keySource}`);
|
|
46
|
+
lines.push("Run oyster install-apps --help for details.");
|
|
47
|
+
return lines.join("\n");
|
|
48
|
+
}
|
|
20
49
|
function seconds(milliseconds) {
|
|
21
50
|
return `${(milliseconds / 1000).toFixed(1)}s`;
|
|
22
51
|
}
|
|
@@ -56,13 +85,18 @@ async function installApps(args) {
|
|
|
56
85
|
from: { type: "string" },
|
|
57
86
|
concurrency: { type: "string" },
|
|
58
87
|
timings: { type: "string" },
|
|
88
|
+
help: { type: "boolean", short: "h" },
|
|
59
89
|
},
|
|
60
90
|
strict: true,
|
|
61
91
|
});
|
|
92
|
+
if (values.help === true) {
|
|
93
|
+
process.stdout.write(helpText);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
62
96
|
const url = process.env.OYSTER_URL;
|
|
63
97
|
const key = process.env.OYSTER_OWNER_KEY;
|
|
64
98
|
if (!url || !key)
|
|
65
|
-
throw new Error(
|
|
99
|
+
throw new Error(missingVariableMessage(url, key));
|
|
66
100
|
if (values.from !== undefined && values.repositories !== undefined)
|
|
67
101
|
throw new Error("Choose either --from or --repositories");
|
|
68
102
|
const concurrency = values.concurrency === undefined
|
|
@@ -115,12 +149,15 @@ async function installApps(args) {
|
|
|
115
149
|
}
|
|
116
150
|
}
|
|
117
151
|
const [command, ...rest] = process.argv.slice(2);
|
|
118
|
-
if (command
|
|
152
|
+
if (command === "--help" || command === "-h") {
|
|
153
|
+
process.stdout.write(usage + "\n" + installReleaseUsage + "\n");
|
|
154
|
+
}
|
|
155
|
+
else if (command !== "install-apps" && command !== "install") {
|
|
119
156
|
process.stderr.write(`${usage}\n`);
|
|
120
157
|
process.exitCode = 2;
|
|
121
158
|
}
|
|
122
159
|
else
|
|
123
|
-
await installApps(rest).catch((cause) => {
|
|
160
|
+
await (command === "install" ? installReleaseCommand(rest) : installApps(rest)).catch((cause) => {
|
|
124
161
|
process.stderr.write(`${cause instanceof Error ? cause.message : String(cause)}\n`);
|
|
125
162
|
process.exitCode = 1;
|
|
126
163
|
});
|
|
@@ -4,8 +4,8 @@ import { type StandaloneAgentsEnv } from "./agents.js";
|
|
|
4
4
|
import { type StandaloneComputerEnv } from "./computer.js";
|
|
5
5
|
import { type OysterMediaEnv } from "./media.js";
|
|
6
6
|
import { type AppSourceBindingEnv } from "./app-source.js";
|
|
7
|
-
import { type WorkflowBindingEnv, type WorkflowEventEnv
|
|
8
|
-
export type StandaloneInstanceEnv = OysterGitWorkerEnv & WorkflowBindingEnv & WorkflowEventEnv &
|
|
7
|
+
import { type WorkflowBindingEnv, type WorkflowEventEnv } from "./workflow-binding.js";
|
|
8
|
+
export type StandaloneInstanceEnv = OysterGitWorkerEnv & WorkflowBindingEnv & WorkflowEventEnv & StandaloneComputerEnv & StandaloneAgentsEnv & OysterMediaEnv & AppSourceBindingEnv;
|
|
9
9
|
/** Git and Events plus the declared Computer, Media, Workflow, Agent and App
|
|
10
10
|
* source bindings. */
|
|
11
11
|
export declare const standaloneBindings: OysterBindingTable<StandaloneInstanceEnv>;
|
|
@@ -2,10 +2,10 @@ import { AppInstanceError } from "../index.js";
|
|
|
2
2
|
import { oysterBindingEntrypoint, } from "../workers.js";
|
|
3
3
|
import { OysterGitInstance, OysterWebhooks, eventsBindingFor, gitBindings, } from "../workers-git.js";
|
|
4
4
|
import { agentFrameMethods, dispatchAgentBinding, } from "./agents.js";
|
|
5
|
-
import { computerFrameMethods, computerInvocation,
|
|
5
|
+
import { computerFrameMethods, computerInvocation, standaloneFrameWorkspace, } from "./computer.js";
|
|
6
6
|
import { dispatchMediaBinding, mediaFrameMethods, } from "./media.js";
|
|
7
7
|
import { appSourceFrameMethods, dispatchAppSourceBinding, } from "./app-source.js";
|
|
8
|
-
import { workflowFrameMethods, dispatchWorkflowBinding, deliverWorkflowEvent,
|
|
8
|
+
import { workflowFrameMethods, dispatchWorkflowBinding, deliverWorkflowEvent, workflowEventRecipients, } from "./workflow-binding.js";
|
|
9
9
|
import { appsFrameMethods, dispatchAppsBuildsBinding, } from "./app-builds-binding.js";
|
|
10
10
|
/** Git and Events plus the declared Computer, Media, Workflow, Agent and App
|
|
11
11
|
* source bindings. */
|
|
@@ -21,19 +21,16 @@ export const standaloneBindings = {
|
|
|
21
21
|
},
|
|
22
22
|
COMPUTER: {
|
|
23
23
|
methods: computerFrameMethods.COMPUTER,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
return computerInvocation(context.env, frame, method, args);
|
|
27
|
-
// A published Workflow Git step's pass, minted by the library that runs it.
|
|
28
|
-
const host = await context.backgroundHost();
|
|
29
|
-
if (host === null)
|
|
30
|
-
throw new AppInstanceError("revoked");
|
|
31
|
-
return openWorkflowGitPass(context.env, host.installations, frame, args);
|
|
24
|
+
dispatch(context, frame, _props, method, args) {
|
|
25
|
+
return computerInvocation(context.env, context.scope(), frame, method, args);
|
|
32
26
|
},
|
|
33
27
|
},
|
|
34
28
|
MEDIA: {
|
|
35
29
|
methods: mediaFrameMethods.MEDIA,
|
|
36
|
-
dispatch
|
|
30
|
+
async dispatch(context, frame, props, method, args) {
|
|
31
|
+
const workspace = await standaloneFrameWorkspace(context.env, context.scope(), frame);
|
|
32
|
+
return dispatchMediaBinding(context.env, frame, props, method, args, workspace);
|
|
33
|
+
},
|
|
37
34
|
},
|
|
38
35
|
WORKFLOWS: {
|
|
39
36
|
methods: workflowFrameMethods.WORKFLOWS,
|