@fungi.computer/oyster 0.0.0-stage → 0.1.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.
- package/LICENSE +21 -0
- package/README.md +1134 -2
- package/dist/agents.d.ts +114 -0
- package/dist/agents.js +322 -0
- package/dist/app-builds.d.ts +210 -0
- package/dist/app-builds.js +499 -0
- package/dist/app-sandbox.d.ts +2 -0
- package/dist/app-sandbox.js +2 -0
- package/dist/app-sources.d.ts +31 -0
- package/dist/app-sources.js +370 -0
- package/dist/app-storage.d.ts +141 -0
- package/dist/app-storage.js +281 -0
- package/dist/apps/gate.d.ts +105 -0
- package/dist/apps/gate.js +273 -0
- package/dist/apps/index.d.ts +5 -0
- package/dist/apps/index.js +5 -0
- package/dist/apps/installation.d.ts +248 -0
- package/dist/apps/installation.js +307 -0
- package/dist/apps/operations.d.ts +8 -0
- package/dist/apps/operations.js +98 -0
- package/dist/apps/tools.d.ts +33 -0
- package/dist/apps/tools.js +17 -0
- package/dist/auth.d.ts +11 -0
- package/dist/auth.js +93 -0
- package/dist/backend-request.d.ts +3 -0
- package/dist/backend-request.js +53 -0
- package/dist/build/artifact-writer.d.ts +40 -0
- package/dist/build/artifact-writer.js +181 -0
- package/dist/build/build-jobs.d.ts +128 -0
- package/dist/build/build-jobs.js +203 -0
- package/dist/build/build-policy.d.ts +10 -0
- package/dist/build/build-policy.js +10 -0
- package/dist/build/build-step.d.ts +37 -0
- package/dist/build/build-step.js +28 -0
- package/dist/build/bundled-html.d.ts +7 -0
- package/dist/build/bundled-html.js +64 -0
- package/dist/build/candidate-builder.d.ts +68 -0
- package/dist/build/candidate-builder.js +91 -0
- package/dist/build/candidate-cli.d.ts +1 -0
- package/dist/build/candidate-cli.js +119 -0
- package/dist/build/candidate-cli.mjs +28170 -0
- package/dist/build/content-objects.d.ts +37 -0
- package/dist/build/content-objects.js +53 -0
- package/dist/build/definition-emission.d.ts +34 -0
- package/dist/build/definition-emission.js +201 -0
- package/dist/build/effect.d.ts +249 -0
- package/dist/build/effect.js +436 -0
- package/dist/build/git-environment.d.ts +9 -0
- package/dist/build/git-environment.js +60 -0
- package/dist/build/html-recipe.d.ts +20 -0
- package/dist/build/html-recipe.js +51 -0
- package/dist/build/local-build.d.ts +67 -0
- package/dist/build/local-build.js +1128 -0
- package/dist/build/snapshot-package-store.d.ts +12 -0
- package/dist/build/snapshot-package-store.js +36 -0
- package/dist/build/snapshot-program-scripts.d.ts +6 -0
- package/dist/build/snapshot-program-scripts.js +2 -0
- package/dist/build/snapshot-programs/snapshot-path.d.ts +2 -0
- package/dist/build/snapshot-programs/snapshot-path.js +6 -0
- package/dist/build/submission-contract.d.ts +828 -0
- package/dist/build/submission-contract.js +180 -0
- package/dist/build/workspace-build.d.ts +55 -0
- package/dist/build/workspace-build.js +200 -0
- package/dist/build-contract.d.ts +7 -0
- package/dist/build-contract.js +7 -0
- package/dist/build-egress.d.ts +62 -0
- package/dist/build-egress.js +148 -0
- package/dist/build-jobs.d.ts +2 -0
- package/dist/build-jobs.js +2 -0
- package/dist/build.d.ts +12 -0
- package/dist/build.js +14 -0
- package/dist/capability-descriptor.d.ts +46 -0
- package/dist/capability-descriptor.js +51 -0
- package/dist/catalog-frame.d.ts +39 -0
- package/dist/catalog-frame.js +72 -0
- package/dist/cause-class.d.ts +19 -0
- package/dist/cause-class.js +54 -0
- package/dist/cloudflare.d.ts +123 -0
- package/dist/cloudflare.js +391 -0
- package/dist/computer-terminal.d.ts +38 -0
- package/dist/computer-terminal.js +410 -0
- package/dist/computer.d.ts +60 -0
- package/dist/computer.js +33 -0
- package/dist/event-recipients.d.ts +57 -0
- package/dist/event-recipients.js +144 -0
- package/dist/facet-invocation.d.ts +4 -0
- package/dist/facet-invocation.js +45 -0
- package/dist/files.d.ts +42 -0
- package/dist/files.js +123 -0
- package/dist/frame-binding-wire-script.d.ts +2 -0
- package/dist/frame-binding-wire-script.js +1 -0
- package/dist/frame-binding-wire.d.ts +28 -0
- package/dist/frame-binding-wire.js +54 -0
- package/dist/git-admission.d.ts +52 -0
- package/dist/git-admission.js +188 -0
- package/dist/git-auth.d.ts +11 -0
- package/dist/git-auth.js +27 -0
- package/dist/git-door.d.ts +35 -0
- package/dist/git-door.js +108 -0
- package/dist/git-journal.d.ts +31 -0
- package/dist/git-journal.js +188 -0
- package/dist/git.d.ts +31 -0
- package/dist/git.js +64 -0
- package/dist/guest-policy.d.ts +9 -0
- package/dist/guest-policy.js +13 -0
- package/dist/host.d.ts +244 -0
- package/dist/host.js +1043 -0
- package/dist/index.d.ts +166 -0
- package/dist/index.js +320 -0
- package/dist/installation-consent.d.ts +79 -0
- package/dist/installation-consent.js +82 -0
- package/dist/internal/background-origins.d.ts +3 -0
- package/dist/internal/background-origins.js +8 -0
- package/dist/internal/delivery.d.ts +12 -0
- package/dist/internal/delivery.js +167 -0
- package/dist/internal/host-gate.d.ts +14 -0
- package/dist/internal/host-gate.js +62 -0
- package/dist/internal/registry-installations.d.ts +6 -0
- package/dist/internal/registry-installations.js +12 -0
- package/dist/invocation.d.ts +251 -0
- package/dist/invocation.js +377 -0
- package/dist/keys.d.ts +48 -0
- package/dist/keys.js +52 -0
- package/dist/mcp-owner.d.ts +27 -0
- package/dist/mcp-owner.js +155 -0
- package/dist/mcp.d.ts +89 -0
- package/dist/mcp.js +429 -0
- package/dist/media.d.ts +23 -0
- package/dist/media.js +12 -0
- package/dist/pack.d.ts +79 -0
- package/dist/pack.js +151 -0
- package/dist/page/capabilities.d.ts +23 -0
- package/dist/page/capabilities.js +256 -0
- package/dist/page/computer-handles.d.ts +79 -0
- package/dist/page/computer-handles.js +44 -0
- package/dist/page/gill-observation.d.ts +4 -0
- package/dist/page/gill-observation.js +31 -0
- package/dist/page/lifetime.d.ts +6 -0
- package/dist/page/lifetime.js +19 -0
- package/dist/page/mount.d.ts +163 -0
- package/dist/page/mount.js +390 -0
- package/dist/page/storage.d.ts +3 -0
- package/dist/page/storage.js +82 -0
- package/dist/page/terminal.d.ts +5 -0
- package/dist/page/terminal.js +7 -0
- package/dist/page/window-launch.d.ts +18 -0
- package/dist/page/window-launch.js +11 -0
- package/dist/page-script.d.ts +14 -0
- package/dist/page-script.js +5 -0
- package/dist/r2-files.d.ts +3 -0
- package/dist/r2-files.js +79 -0
- package/dist/release.d.ts +83 -0
- package/dist/release.js +167 -0
- package/dist/root-data.d.ts +86 -0
- package/dist/root-data.js +69 -0
- package/dist/shell/app-directory.d.ts +542 -0
- package/dist/shell/app-directory.js +199 -0
- package/dist/shell/browser-actions.d.ts +7 -0
- package/dist/shell/browser-actions.js +56 -0
- package/dist/shell/command-host.d.ts +112 -0
- package/dist/shell/command-host.js +502 -0
- package/dist/shell/commands.d.ts +25 -0
- package/dist/shell/commands.js +78 -0
- package/dist/shell/index.d.ts +8 -0
- package/dist/shell/index.js +8 -0
- package/dist/shell/keys.d.ts +41 -0
- package/dist/shell/keys.js +134 -0
- package/dist/shell/shell-module.d.ts +55 -0
- package/dist/shell/shell-module.js +86 -0
- package/dist/shell/window-manager.d.ts +124 -0
- package/dist/shell/window-manager.js +711 -0
- package/dist/shell/workbench-contract.d.ts +68 -0
- package/dist/shell/workbench-contract.js +1 -0
- package/dist/shell/workbench-directory.d.ts +332 -0
- package/dist/shell/workbench-directory.js +35 -0
- package/dist/shell/workbench-host-types.d.ts +96 -0
- package/dist/shell/workbench-host-types.js +1 -0
- package/dist/shell/workbench-host.d.ts +34 -0
- package/dist/shell/workbench-host.js +347 -0
- package/dist/shell/workbench-model.d.ts +192 -0
- package/dist/shell/workbench-model.js +53 -0
- package/dist/shell/workbench.d.ts +4 -0
- package/dist/shell/workbench.js +2 -0
- package/dist/source/fork.d.ts +27 -0
- package/dist/source/fork.js +46 -0
- package/dist/source/index.d.ts +10 -0
- package/dist/source/index.js +10 -0
- package/dist/source/seed-receipt.d.ts +53 -0
- package/dist/source/seed-receipt.js +18 -0
- package/dist/source/team-source.d.ts +32 -0
- package/dist/source/team-source.js +42 -0
- package/dist/source/template-push.d.ts +33 -0
- package/dist/source/template-push.js +223 -0
- package/dist/source/template-repository.d.ts +4 -0
- package/dist/source/template-repository.js +21 -0
- package/dist/source/template-seed.d.ts +68 -0
- package/dist/source/template-seed.js +80 -0
- package/dist/standalone/agent-directory.d.ts +4 -0
- package/dist/standalone/agent-directory.js +4 -0
- package/dist/standalone/agents.d.ts +220 -0
- package/dist/standalone/agents.js +795 -0
- package/dist/standalone/app-builds-binding.d.ts +36 -0
- package/dist/standalone/app-builds-binding.js +119 -0
- package/dist/standalone/app-set.d.ts +91 -0
- package/dist/standalone/app-set.js +395 -0
- package/dist/standalone/app-source.d.ts +41 -0
- package/dist/standalone/app-source.js +59 -0
- package/dist/standalone/builds.d.ts +18 -0
- package/dist/standalone/builds.js +101 -0
- package/dist/standalone/computer-egress.d.ts +37 -0
- package/dist/standalone/computer-egress.js +111 -0
- package/dist/standalone/computer.d.ts +122 -0
- package/dist/standalone/computer.js +714 -0
- package/dist/standalone/install-apps-cli.d.ts +2 -0
- package/dist/standalone/install-apps-cli.js +126 -0
- package/dist/standalone/instance.d.ts +35 -0
- package/dist/standalone/instance.js +74 -0
- package/dist/standalone/media.d.ts +76 -0
- package/dist/standalone/media.js +227 -0
- package/dist/standalone/preview.d.ts +51 -0
- package/dist/standalone/preview.js +167 -0
- package/dist/standalone/registry.d.ts +102 -0
- package/dist/standalone/registry.js +193 -0
- package/dist/standalone/tenancy.d.ts +42 -0
- package/dist/standalone/tenancy.js +241 -0
- package/dist/standalone/worker.d.ts +55 -0
- package/dist/standalone/worker.js +147 -0
- package/dist/standalone/workflow-authority-readers.d.ts +16 -0
- package/dist/standalone/workflow-authority-readers.js +35 -0
- package/dist/standalone/workflow-binding.d.ts +216 -0
- package/dist/standalone/workflow-binding.js +217 -0
- package/dist/standalone/workflow-events.d.ts +46 -0
- package/dist/standalone/workflow-events.js +39 -0
- package/dist/standalone/workflow-git-capture.d.ts +7 -0
- package/dist/standalone/workflow-git-capture.js +62 -0
- package/dist/standalone/workflow-host.d.ts +931 -0
- package/dist/standalone/workflow-host.js +751 -0
- package/dist/standalone/workflow-node-capture.d.ts +13 -0
- package/dist/standalone/workflow-node-capture.js +72 -0
- package/dist/standalone/workflow-root-authority.d.ts +27 -0
- package/dist/standalone/workflow-root-authority.js +87 -0
- package/dist/standalone/workflow-schedules.d.ts +52 -0
- package/dist/standalone/workflow-schedules.js +40 -0
- package/dist/standalone/workflow-trigger-host.d.ts +1694 -0
- package/dist/standalone/workflow-trigger-host.js +52 -0
- package/dist/standalone/workflows.d.ts +657 -0
- package/dist/standalone/workflows.js +554 -0
- package/dist/storage-frame.d.ts +64 -0
- package/dist/storage-frame.js +28 -0
- package/dist/tenancy/auth0.d.ts +64 -0
- package/dist/tenancy/auth0.js +198 -0
- package/dist/tenancy/cloudflare/rate-limit.d.ts +8 -0
- package/dist/tenancy/cloudflare/rate-limit.js +19 -0
- package/dist/tenancy/cloudflare/registry.d.ts +50 -0
- package/dist/tenancy/cloudflare/registry.js +301 -0
- package/dist/tenancy/cloudflare.d.ts +2 -0
- package/dist/tenancy/cloudflare.js +2 -0
- package/dist/tenancy/cold-directory.d.ts +13 -0
- package/dist/tenancy/cold-directory.js +43 -0
- package/dist/tenancy/contracts.d.ts +195 -0
- package/dist/tenancy/contracts.js +1 -0
- package/dist/tenancy/index.d.ts +19 -0
- package/dist/tenancy/index.js +156 -0
- package/dist/tenancy/owner-key.d.ts +26 -0
- package/dist/tenancy/owner-key.js +63 -0
- package/dist/tenancy/oyster.d.ts +4 -0
- package/dist/tenancy/oyster.js +25 -0
- package/dist/tenancy/registry-record.d.ts +7 -0
- package/dist/tenancy/registry-record.js +44 -0
- package/dist/tenancy/registry.d.ts +27 -0
- package/dist/tenancy/registry.js +138 -0
- package/dist/tenancy/resolve.d.ts +7 -0
- package/dist/tenancy/resolve.js +64 -0
- package/dist/tenant.d.ts +81 -0
- package/dist/tenant.js +71 -0
- package/dist/testing/capabilities.d.ts +29 -0
- package/dist/testing/capabilities.js +130 -0
- package/dist/testing/catalog.d.ts +3 -0
- package/dist/testing/catalog.js +53 -0
- package/dist/testing/index.d.ts +10 -0
- package/dist/testing/index.js +10 -0
- package/dist/testing/installation.d.ts +11 -0
- package/dist/testing/installation.js +25 -0
- package/dist/testing/native-worker.d.ts +21 -0
- package/dist/testing/native-worker.js +106 -0
- package/dist/testing/worker.d.ts +18 -0
- package/dist/testing/worker.js +67 -0
- package/dist/testing/workers-runtime.d.ts +24 -0
- package/dist/testing/workers-runtime.js +33 -0
- package/dist/webhook-delivery.d.ts +14 -0
- package/dist/webhook-delivery.js +17 -0
- package/dist/workers-git.d.ts +285 -0
- package/dist/workers-git.js +1174 -0
- package/dist/workers.d.ts +352 -0
- package/dist/workers.js +868 -0
- package/docs/api/README.md +82 -0
- package/docs/api/agents.md +332 -0
- package/docs/api/app-storage.md +209 -0
- package/docs/api/apps.md +1375 -0
- package/docs/api/auth.md +63 -0
- package/docs/api/build-contract.md +1304 -0
- package/docs/api/build.md +1712 -0
- package/docs/api/cloudflare.md +421 -0
- package/docs/api/computer.md +203 -0
- package/docs/api/files.md +117 -0
- package/docs/api/git.md +470 -0
- package/docs/api/host.md +1328 -0
- package/docs/api/index.md +430 -0
- package/docs/api/invocation.md +738 -0
- package/docs/api/keys.md +175 -0
- package/docs/api/mcp.md +301 -0
- package/docs/api/media.md +40 -0
- package/docs/api/modules.md +50 -0
- package/docs/api/pack.md +141 -0
- package/docs/api/page/mount.md +298 -0
- package/docs/api/root-data.md +111 -0
- package/docs/api/shell/app-directory.md +599 -0
- package/docs/api/shell/command-host.md +224 -0
- package/docs/api/shell/commands.md +197 -0
- package/docs/api/shell/keys.md +183 -0
- package/docs/api/shell/shell-module.md +204 -0
- package/docs/api/shell/window-manager.md +267 -0
- package/docs/api/shell/workbench-directory.md +119 -0
- package/docs/api/shell/workbench.md +205 -0
- package/docs/api/shell.md +1915 -0
- package/docs/api/tenancy/auth0.md +110 -0
- package/docs/api/tenancy/cloudflare.md +221 -0
- package/docs/api/tenancy/cold-directory.md +46 -0
- package/docs/api/tenancy/owner-key.md +63 -0
- package/docs/api/tenancy/registry.md +77 -0
- package/docs/api/tenancy/resolve.md +69 -0
- package/docs/api/tenancy.md +430 -0
- package/docs/api/tenant.md +194 -0
- package/docs/api/workers-git.md +1646 -0
- package/docs/api/workers.md +1691 -0
- package/docs/site/agent-quickstart.mdx +346 -0
- package/examples/standalone/worker.ts +7 -0
- package/examples/standalone/wrangler.jsonc +82 -0
- package/package.json +300 -3
|
@@ -0,0 +1,554 @@
|
|
|
1
|
+
import { createCodemodeSandbox } from "@fungi.computer/mycelium/workers";
|
|
2
|
+
import { DurableObject } from "cloudflare:workers";
|
|
3
|
+
import * as S from "effect/Schema";
|
|
4
|
+
import { GraphWorkflow, } from "@fungi.computer/braid/cloudflare";
|
|
5
|
+
import {} from "@fungi.computer/braid";
|
|
6
|
+
import { standaloneTenancy } from "./tenancy.js";
|
|
7
|
+
import { createStandaloneWorkflowGitAccess, createStandaloneWorkflowRootAuthority, } from "./workflow-root-authority.js";
|
|
8
|
+
import { createStandaloneWorkflowHost } from "./workflow-host.js";
|
|
9
|
+
import { createStandaloneWorkflowSchedules, } from "./workflow-schedules.js";
|
|
10
|
+
import { createStandaloneWorkflowEvents, } from "./workflow-events.js";
|
|
11
|
+
import { createStandaloneWorkflowTriggerHost, standaloneTriggerErrors, } from "./workflow-trigger-host.js";
|
|
12
|
+
import { createWorkflowPublishedDefinitionPort, readPublishedWorkflow, } from "@fungi.computer/workflows-wire";
|
|
13
|
+
import { defaultTenant, tenantScope } from "../tenant.js";
|
|
14
|
+
import { AppInstanceError } from "../index.js";
|
|
15
|
+
import { workflowGitPassPrefix } from "../git.js";
|
|
16
|
+
import { createWorkflowGitPasses, createWorkflowGitPassStore, workflowGitPassWriter, workflowRunReport, wireRunInitiator, } from "@fungi.computer/braid/runtime";
|
|
17
|
+
import { canonicalJson } from "@fungi.computer/braid";
|
|
18
|
+
import { runKey, reviewKey, workflowGitPassRequestSchema, } from "./workflow-binding.js";
|
|
19
|
+
import { agentDirectoryForScope } from "./agent-directory.js";
|
|
20
|
+
/** SQLite and the native Workflow binding belong to this standalone host; its root supplies `hostFor`. */
|
|
21
|
+
export class StandaloneWorkflowRunsBase extends DurableObject {
|
|
22
|
+
composed;
|
|
23
|
+
/** Schedule time and its native alarm instant; production is the wall clock. */
|
|
24
|
+
scheduleClock = {
|
|
25
|
+
now: () => Date.now(),
|
|
26
|
+
alarmAt: (due) => due,
|
|
27
|
+
};
|
|
28
|
+
owner;
|
|
29
|
+
constructor(ctx, env) {
|
|
30
|
+
super(ctx, env);
|
|
31
|
+
// This object is named by its Workflows library installation; the alarm
|
|
32
|
+
// and App events have no library frame, so the first admitted trigger
|
|
33
|
+
// control records that name.
|
|
34
|
+
ctx.storage.sql
|
|
35
|
+
.exec(`CREATE TABLE IF NOT EXISTS standalone_workflow_library (
|
|
36
|
+
singleton INTEGER PRIMARY KEY CHECK (singleton = 1), installation_id TEXT NOT NULL
|
|
37
|
+
) STRICT`);
|
|
38
|
+
this.composed = ctx.blockConcurrencyWhile(async () => {
|
|
39
|
+
const shared = await standaloneTenancy(env);
|
|
40
|
+
const host = this.hostFor(tenantScope(defaultTenant, env.OYSTER_ORIGIN));
|
|
41
|
+
const agentToolPolicy = async (agentId) => (await host.appToolPolicy?.({ kind: "agent", agentId })) ?? null;
|
|
42
|
+
// A key's App access is its own grants (Ear Tag), read through
|
|
43
|
+
// `host.keys.live`, never through `appToolPolicy`.
|
|
44
|
+
const keyLive = async (keyId) => (await host.keys?.live(keyId)) ?? null;
|
|
45
|
+
// The one owner reaches every Agent; the report needs one that exists.
|
|
46
|
+
const admitDelivery = (_memberId, delivery) => agentDirectoryForScope(env, tenantScope(defaultTenant, env.OYSTER_ORIGIN)).has(delivery.agentId);
|
|
47
|
+
const owner = createStandaloneWorkflowHost(ctx.storage, host, {
|
|
48
|
+
authority(libraryInstallationId) {
|
|
49
|
+
return createStandaloneWorkflowRootAuthority({
|
|
50
|
+
shared,
|
|
51
|
+
host,
|
|
52
|
+
libraryInstallationId,
|
|
53
|
+
catalogHost: owner,
|
|
54
|
+
agentToolPolicy,
|
|
55
|
+
keyLive,
|
|
56
|
+
});
|
|
57
|
+
},
|
|
58
|
+
admitDelivery,
|
|
59
|
+
});
|
|
60
|
+
const triggersFor = (libraryId) => {
|
|
61
|
+
const authority = createStandaloneWorkflowRootAuthority({
|
|
62
|
+
shared,
|
|
63
|
+
host,
|
|
64
|
+
libraryInstallationId: libraryId,
|
|
65
|
+
catalogHost: owner,
|
|
66
|
+
agentToolPolicy,
|
|
67
|
+
keyLive,
|
|
68
|
+
});
|
|
69
|
+
const admitTrigger = async (memberId, installationId, computerId) => {
|
|
70
|
+
await authority.member(memberId);
|
|
71
|
+
if (installationId !== libraryId ||
|
|
72
|
+
!(await authority.memberComputer(memberId, computerId)))
|
|
73
|
+
throw standaloneTriggerErrors.denied();
|
|
74
|
+
return owner.triggerAuthority(installationId);
|
|
75
|
+
};
|
|
76
|
+
const triggers = createStandaloneWorkflowTriggerHost({
|
|
77
|
+
authority,
|
|
78
|
+
admitDelivery,
|
|
79
|
+
runs: {
|
|
80
|
+
sql: ctx.storage.sql,
|
|
81
|
+
transactionSync: (body) => ctx.storage.transactionSync(body),
|
|
82
|
+
teamId: () => libraryId,
|
|
83
|
+
},
|
|
84
|
+
triggers: {
|
|
85
|
+
published: createWorkflowPublishedDefinitionPort((git) => ({
|
|
86
|
+
published: (workflowId, at) => readPublishedWorkflow(git, workflowId, at),
|
|
87
|
+
})),
|
|
88
|
+
admit: async (memberId, installationId, computerId) => (await admitTrigger(memberId, installationId, computerId)).pin,
|
|
89
|
+
async source(memberId, installationId, computerId) {
|
|
90
|
+
const { installation } = await admitTrigger(memberId, installationId, computerId);
|
|
91
|
+
return (await host.git.git(installation)).binding({
|
|
92
|
+
kind: "member",
|
|
93
|
+
memberId,
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
// Standalone has no Connector-attachment store (Hub's own
|
|
97
|
+
// mechanism for Agent arming); an Agent's owner-approved tool
|
|
98
|
+
// policy governs dispatch, not arming here. See W-1/B-4(b).
|
|
99
|
+
readAgentAccess: () => Promise.resolve(null),
|
|
100
|
+
// The member's current Workflows Git policy; mints no pass itself.
|
|
101
|
+
admitGitAccess: async (memberId, repository, scope) => {
|
|
102
|
+
if (!(await gitAccess(libraryId)(memberId, repository, scope)))
|
|
103
|
+
throw standaloneTriggerErrors.denied();
|
|
104
|
+
},
|
|
105
|
+
launch: (run) => this.launch(libraryId, run),
|
|
106
|
+
},
|
|
107
|
+
recordCaller: (runId, memberId, computerId) => {
|
|
108
|
+
owner.recordTriggerCaller(runId, memberId, computerId);
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
const controls = {
|
|
112
|
+
sql: ctx.storage.sql,
|
|
113
|
+
triggers: triggers.triggers,
|
|
114
|
+
teamId: () => libraryId,
|
|
115
|
+
commit: (body) => Promise.resolve(ctx.storage.transactionSync(body)),
|
|
116
|
+
async authorize(memberId, installationId) {
|
|
117
|
+
await authority.member(memberId);
|
|
118
|
+
if (installationId !== libraryId)
|
|
119
|
+
throw standaloneTriggerErrors.denied();
|
|
120
|
+
},
|
|
121
|
+
admitInvocation: async (facts, operation) => {
|
|
122
|
+
const admitted = await owner.admitInvocation(facts, operation);
|
|
123
|
+
if (admitted.libraryId !== libraryId)
|
|
124
|
+
throw new AppInstanceError("revoked");
|
|
125
|
+
return admitted;
|
|
126
|
+
},
|
|
127
|
+
};
|
|
128
|
+
return {
|
|
129
|
+
schedules: createStandaloneWorkflowSchedules({
|
|
130
|
+
...controls,
|
|
131
|
+
now: () => this.scheduleClock.now(),
|
|
132
|
+
wake: (due) => due === null
|
|
133
|
+
? ctx.storage.deleteAlarm()
|
|
134
|
+
: ctx.storage.setAlarm(this.scheduleClock.alarmAt(due)),
|
|
135
|
+
reportFailure: ({ source, cause }) => {
|
|
136
|
+
console.error("Standalone Workflow schedule failed", source, cause);
|
|
137
|
+
},
|
|
138
|
+
}),
|
|
139
|
+
events: createStandaloneWorkflowEvents(controls),
|
|
140
|
+
};
|
|
141
|
+
};
|
|
142
|
+
let library = null;
|
|
143
|
+
const libraryTriggers = (libraryId) => {
|
|
144
|
+
this.nameLibrary(libraryId);
|
|
145
|
+
return (library ??= triggersFor(libraryId));
|
|
146
|
+
};
|
|
147
|
+
const computerId = host.computerId;
|
|
148
|
+
// Passes live with the run owner that records the Git steps they serve.
|
|
149
|
+
const passStore = createWorkflowGitPassStore({
|
|
150
|
+
sql: ctx.storage.sql,
|
|
151
|
+
transactionSync: (body) => ctx.storage.transactionSync(body),
|
|
152
|
+
ownerId: () => this.libraryId(),
|
|
153
|
+
computerId: () => computerId,
|
|
154
|
+
mintPassId: () => Array.from(crypto.getRandomValues(new Uint8Array(32)), (byte) => byte.toString(16).padStart(2, "0")).join(""),
|
|
155
|
+
remote: (_passId, repository) => {
|
|
156
|
+
const libraryId = this.libraryId();
|
|
157
|
+
if (repository.kind !== "installation" || libraryId === null)
|
|
158
|
+
throw new AppInstanceError("revoked");
|
|
159
|
+
// The tenant's ordinary smart-HTTP door; the pass never enters the
|
|
160
|
+
// URL and travels only as the bearer header.
|
|
161
|
+
return new URL(`/git/${repository.installationId}/${repository.repository}.git`, env.OYSTER_ORIGIN).href;
|
|
162
|
+
},
|
|
163
|
+
denied: () => new AppInstanceError("revoked"),
|
|
164
|
+
});
|
|
165
|
+
const gitAccess = (libraryId) => createStandaloneWorkflowGitAccess({
|
|
166
|
+
shared,
|
|
167
|
+
host,
|
|
168
|
+
libraryInstallationId: libraryId,
|
|
169
|
+
catalogHost: owner,
|
|
170
|
+
});
|
|
171
|
+
const gitPasses = (libraryId) => {
|
|
172
|
+
const access = gitAccess(libraryId);
|
|
173
|
+
return createWorkflowGitPasses({
|
|
174
|
+
denied: () => new AppInstanceError("revoked"),
|
|
175
|
+
admitNode: (context, target) => {
|
|
176
|
+
const node = owner.gitNode(context.idempotencyKey);
|
|
177
|
+
return node?.teamId === libraryId &&
|
|
178
|
+
node.installationId === target.installationId &&
|
|
179
|
+
node.method === target.method
|
|
180
|
+
? node
|
|
181
|
+
: null;
|
|
182
|
+
},
|
|
183
|
+
async admitMemberGitAccess(memberId, repository, scope) {
|
|
184
|
+
if (!(await access(memberId, repository, scope)))
|
|
185
|
+
throw new AppInstanceError("revoked");
|
|
186
|
+
},
|
|
187
|
+
open: (_computer, grant) => {
|
|
188
|
+
const pass = passStore.openWorkflowPass(grant);
|
|
189
|
+
return Promise.resolve({
|
|
190
|
+
...pass,
|
|
191
|
+
bearer: `${workflowGitPassPrefix}${libraryId}.${pass.passId}`,
|
|
192
|
+
});
|
|
193
|
+
},
|
|
194
|
+
revoke: (_computer, input) => {
|
|
195
|
+
passStore.revokeWorkflowRunGitPasses(input);
|
|
196
|
+
return Promise.resolve();
|
|
197
|
+
},
|
|
198
|
+
// Revocation runs in this object when the run ends; nothing is queued.
|
|
199
|
+
pending: () => [],
|
|
200
|
+
acknowledge: () => undefined,
|
|
201
|
+
});
|
|
202
|
+
};
|
|
203
|
+
return { owner, libraryTriggers, passStore, gitAccess, gitPasses };
|
|
204
|
+
});
|
|
205
|
+
this.owner = this.composed.then(({ owner }) => owner);
|
|
206
|
+
}
|
|
207
|
+
/** Record the library this object serves; another name is a revocation. */
|
|
208
|
+
nameLibrary(libraryId) {
|
|
209
|
+
const named = this.libraryId();
|
|
210
|
+
if (named !== null && named !== libraryId)
|
|
211
|
+
throw new AppInstanceError("revoked");
|
|
212
|
+
if (named === null)
|
|
213
|
+
this.ctx.storage.sql.exec("INSERT INTO standalone_workflow_library(singleton,installation_id) VALUES(1,?)", libraryId);
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Mint (or renew) the Git pass for the Git step a node frame is executing.
|
|
217
|
+
* Null when this library dispatched no such step; a step that does not match
|
|
218
|
+
* the frame's attested Workflow, member and Computer is a revocation.
|
|
219
|
+
*/
|
|
220
|
+
async openWorkflowGitPass(raw) {
|
|
221
|
+
const request = workflowGitPassRequestSchema.parse(raw);
|
|
222
|
+
const { owner, gitPasses } = await this.composed;
|
|
223
|
+
const libraryId = this.libraryId();
|
|
224
|
+
const node = owner.gitNode(request.idempotencyKey);
|
|
225
|
+
if (libraryId === null || node === null)
|
|
226
|
+
return null;
|
|
227
|
+
if (node.teamId !== libraryId ||
|
|
228
|
+
node.installationId !== request.installationId ||
|
|
229
|
+
node.memberId !== request.memberId ||
|
|
230
|
+
node.computerId !== request.computerId ||
|
|
231
|
+
node.context.workflowId !== request.workflow.workflowId ||
|
|
232
|
+
node.context.runId !== request.workflow.runId ||
|
|
233
|
+
node.context.nodeId !== request.workflow.nodeId ||
|
|
234
|
+
canonicalJson(node.context.armedBy) !==
|
|
235
|
+
canonicalJson(request.workflow.armedBy))
|
|
236
|
+
throw new AppInstanceError("revoked");
|
|
237
|
+
return gitPasses(libraryId).openWorkflowPass(node.context, {
|
|
238
|
+
installationId: node.installationId,
|
|
239
|
+
method: node.method,
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
/** The tenant Git door's per-request admission of a presented pass. */
|
|
243
|
+
async admitWorkflowGitPass(passId, repository, scope) {
|
|
244
|
+
const { owner, passStore, gitAccess } = await this.composed;
|
|
245
|
+
const libraryId = this.libraryId();
|
|
246
|
+
const grant = passStore.admit({ passId, repository, scope });
|
|
247
|
+
if (libraryId === null ||
|
|
248
|
+
grant === null ||
|
|
249
|
+
owner.store.outcome(grant.runId) !== "active" ||
|
|
250
|
+
!(await gitAccess(libraryId)(grant.memberId, repository, scope)))
|
|
251
|
+
return null;
|
|
252
|
+
// The live root admission above holds only for the canonical owner.
|
|
253
|
+
return { ...workflowGitPassWriter(grant), role: "owner" };
|
|
254
|
+
}
|
|
255
|
+
/** A finished run's passes and recorded Git steps end with it. */
|
|
256
|
+
async endRunGit(runId) {
|
|
257
|
+
const { owner, passStore } = await this.composed;
|
|
258
|
+
const run = owner.store.read(runId);
|
|
259
|
+
if (run !== null)
|
|
260
|
+
passStore.revokeWorkflowRunGitPasses({ teamId: run.teamId, runId });
|
|
261
|
+
owner.forgetGitNodes(runId);
|
|
262
|
+
}
|
|
263
|
+
libraryId() {
|
|
264
|
+
const row = this.ctx.storage.sql
|
|
265
|
+
.exec("SELECT installation_id FROM standalone_workflow_library")
|
|
266
|
+
.toArray()[0];
|
|
267
|
+
return row === undefined
|
|
268
|
+
? null
|
|
269
|
+
: S.decodeUnknownSync(S.Struct({ installation_id: S.String }))(row)
|
|
270
|
+
.installation_id;
|
|
271
|
+
}
|
|
272
|
+
/** Trigger controls open the library named by the admitted frame. */
|
|
273
|
+
async library(facts, operation) {
|
|
274
|
+
const { owner, libraryTriggers } = await this.composed;
|
|
275
|
+
const { libraryId } = await owner.admitInvocation(facts, operation);
|
|
276
|
+
return libraryTriggers(libraryId);
|
|
277
|
+
}
|
|
278
|
+
/** Idempotently ensure a recorded run has its engine instance. */
|
|
279
|
+
async launch(installationId, run) {
|
|
280
|
+
try {
|
|
281
|
+
await this.env.GRAPH_WORKFLOWS.create({
|
|
282
|
+
id: run.runId,
|
|
283
|
+
params: {
|
|
284
|
+
kind: "run",
|
|
285
|
+
teamId: installationId,
|
|
286
|
+
runId: run.runId,
|
|
287
|
+
planDigest: run.planDigest,
|
|
288
|
+
},
|
|
289
|
+
});
|
|
290
|
+
}
|
|
291
|
+
catch (cause) {
|
|
292
|
+
// The durable run survives a lost create reply. Confirm its owned engine
|
|
293
|
+
// instance exists; unrelated create failures remain failures.
|
|
294
|
+
try {
|
|
295
|
+
await (await this.env.GRAPH_WORKFLOWS.get(run.runId)).status();
|
|
296
|
+
}
|
|
297
|
+
catch {
|
|
298
|
+
throw cause;
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
async armSchedule(facts, input) {
|
|
303
|
+
return (await this.library(facts, "armSchedule")).schedules.arm(facts, input);
|
|
304
|
+
}
|
|
305
|
+
async disarmSchedule(facts, input) {
|
|
306
|
+
return (await this.library(facts, "disarmSchedule")).schedules.disarm(facts, input);
|
|
307
|
+
}
|
|
308
|
+
async schedules(facts) {
|
|
309
|
+
return (await this.library(facts, "schedules")).schedules.list(facts);
|
|
310
|
+
}
|
|
311
|
+
async armEventTrigger(facts, input) {
|
|
312
|
+
return (await this.library(facts, "armEventTrigger")).events.arm(facts, input);
|
|
313
|
+
}
|
|
314
|
+
async disarmEventTrigger(facts, input) {
|
|
315
|
+
return (await this.library(facts, "disarmEventTrigger")).events.disarm(facts, input);
|
|
316
|
+
}
|
|
317
|
+
async eventTriggers(facts) {
|
|
318
|
+
return (await this.library(facts, "eventTriggers")).events.list(facts);
|
|
319
|
+
}
|
|
320
|
+
/** Up to 50 runs of this library, newest first; this host has no per-member rule. */
|
|
321
|
+
async runs(facts, input) {
|
|
322
|
+
const owner = await this.owner;
|
|
323
|
+
const { libraryId } = await owner.admitInvocation(facts, "runs");
|
|
324
|
+
const filter = input.workflowId === undefined
|
|
325
|
+
? { installationId: libraryId }
|
|
326
|
+
: { installationId: libraryId, workflowId: input.workflowId };
|
|
327
|
+
return {
|
|
328
|
+
runs: owner.store.list(filter).map((run) => {
|
|
329
|
+
const row = {
|
|
330
|
+
runId: run.runId,
|
|
331
|
+
workflowId: run.publication?.workflowId ?? run.trigger?.workflowId,
|
|
332
|
+
commit: run.publication?.commit ?? run.trigger?.commit,
|
|
333
|
+
source: run.source,
|
|
334
|
+
initiatedBy: wireRunInitiator(run.initiatedBy),
|
|
335
|
+
startedAt: run.startedAt,
|
|
336
|
+
};
|
|
337
|
+
return run.trigger === undefined
|
|
338
|
+
? row
|
|
339
|
+
: { ...row, triggerId: run.trigger.triggerId };
|
|
340
|
+
}),
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
/** Native alarm delivery: fire every due schedule of this library. */
|
|
344
|
+
async alarm() {
|
|
345
|
+
const { libraryTriggers } = await this.composed;
|
|
346
|
+
const libraryId = this.libraryId();
|
|
347
|
+
if (libraryId === null)
|
|
348
|
+
return;
|
|
349
|
+
await libraryTriggers(libraryId).schedules.alarm();
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* The emitting App's Instance delivers each accepted event here. The
|
|
353
|
+
* emitter's live Release must declare the event and its payload schema
|
|
354
|
+
* must accept it before any armed trigger of this library fires.
|
|
355
|
+
*/
|
|
356
|
+
async deliverEvent(fact) {
|
|
357
|
+
const { owner, libraryTriggers } = await this.composed;
|
|
358
|
+
const libraryId = this.libraryId();
|
|
359
|
+
if (libraryId === null)
|
|
360
|
+
return "accepted";
|
|
361
|
+
const admitted = await owner.admitEventFact(fact);
|
|
362
|
+
return libraryTriggers(libraryId).events.deliver(admitted);
|
|
363
|
+
}
|
|
364
|
+
async catalog(facts, input) {
|
|
365
|
+
const owner = await this.owner;
|
|
366
|
+
return owner.catalog(facts, input);
|
|
367
|
+
}
|
|
368
|
+
async start(facts, input) {
|
|
369
|
+
const owner = await this.owner;
|
|
370
|
+
const result = await owner.prepare(facts, input);
|
|
371
|
+
const installationId = facts.selection.owner.id;
|
|
372
|
+
if (!("kind" in result) ||
|
|
373
|
+
(result.kind !== "started" && result.kind !== "replay"))
|
|
374
|
+
return result;
|
|
375
|
+
if (owner.store.outcome(result.runId) !== "active")
|
|
376
|
+
return result;
|
|
377
|
+
this.nameLibrary(installationId);
|
|
378
|
+
await this.launch(installationId, result);
|
|
379
|
+
return result;
|
|
380
|
+
}
|
|
381
|
+
async loadRun(installationId, runId) {
|
|
382
|
+
const owner = await this.owner;
|
|
383
|
+
return owner.loadRun(installationId, runId);
|
|
384
|
+
}
|
|
385
|
+
async beforeNode(event) {
|
|
386
|
+
const owner = await this.owner;
|
|
387
|
+
return owner.beforeNode(event);
|
|
388
|
+
}
|
|
389
|
+
async dispatch(call) {
|
|
390
|
+
const owner = await this.owner;
|
|
391
|
+
return owner.dispatch(call);
|
|
392
|
+
}
|
|
393
|
+
async recordEvent(event) {
|
|
394
|
+
const owner = await this.owner;
|
|
395
|
+
owner.store.recordEvent(event);
|
|
396
|
+
}
|
|
397
|
+
async openReview(review) {
|
|
398
|
+
const owner = await this.owner;
|
|
399
|
+
return owner.store.openReview(review);
|
|
400
|
+
}
|
|
401
|
+
async answerReview(facts, raw) {
|
|
402
|
+
const owner = await this.owner;
|
|
403
|
+
const input = S.decodeUnknownSync(reviewKey)(raw, {
|
|
404
|
+
onExcessProperty: "error",
|
|
405
|
+
});
|
|
406
|
+
const { libraryId, context } = await (await this.owner).admitInvocation(facts, "answerReview");
|
|
407
|
+
const run = owner.store.read(input.runId);
|
|
408
|
+
if (run?.teamId !== libraryId || context.actor.kind !== "member")
|
|
409
|
+
return { result: "denied" };
|
|
410
|
+
const result = owner.store.answerReview(input, input.answer, {
|
|
411
|
+
kind: "member",
|
|
412
|
+
actorId: context.actor.memberId,
|
|
413
|
+
isOwner: context.role === "owner",
|
|
414
|
+
});
|
|
415
|
+
if (result === "denied" || result === "invalid")
|
|
416
|
+
return { result };
|
|
417
|
+
for (const delivery of owner.store.pendingReviewDeliveries(input.runId)) {
|
|
418
|
+
const instance = await this.env.GRAPH_WORKFLOWS.get(delivery.instanceId);
|
|
419
|
+
await owner.admitInvocation(facts, "answerReview");
|
|
420
|
+
if (owner.store.outcome(input.runId) !== "active")
|
|
421
|
+
break;
|
|
422
|
+
await instance.sendEvent({
|
|
423
|
+
type: delivery.eventType,
|
|
424
|
+
payload: delivery.answer,
|
|
425
|
+
});
|
|
426
|
+
owner.store.markReviewDelivered(delivery);
|
|
427
|
+
}
|
|
428
|
+
return { result };
|
|
429
|
+
}
|
|
430
|
+
/** Record the engine's ending, then report it to the run's declared delivery. */
|
|
431
|
+
async terminal(runId, ending) {
|
|
432
|
+
const owner = await this.owner;
|
|
433
|
+
owner.store.markTerminal(runId, "terminal");
|
|
434
|
+
await this.endRunGit(runId);
|
|
435
|
+
await this.report(runId, ending);
|
|
436
|
+
}
|
|
437
|
+
/**
|
|
438
|
+
* One idempotent follow-up into the run's declared delivery Session, however
|
|
439
|
+
* the run started, through the same Session send that the AGENTS binding
|
|
440
|
+
* uses. Delivery never changes the run's recorded outcome.
|
|
441
|
+
*/
|
|
442
|
+
async report(runId, ending) {
|
|
443
|
+
const owner = await this.owner;
|
|
444
|
+
const run = owner.store.read(runId);
|
|
445
|
+
const delivery = run?.delivery;
|
|
446
|
+
if (run === null || delivery === undefined)
|
|
447
|
+
return;
|
|
448
|
+
try {
|
|
449
|
+
await this.env.AGENTS.getByName(delivery.agentId).sendFromApp(run.teamId, delivery.sessionId, {
|
|
450
|
+
requestId: `workflow-run-report:${runId}`,
|
|
451
|
+
text: workflowRunReport(run.plan.definition.title, runId, ending),
|
|
452
|
+
delivery: "followUp",
|
|
453
|
+
});
|
|
454
|
+
}
|
|
455
|
+
catch (cause) {
|
|
456
|
+
console.error("Workflow run report was not delivered", runId, cause);
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
async status(facts, raw) {
|
|
460
|
+
const owner = await this.owner;
|
|
461
|
+
const { runId } = S.decodeUnknownSync(runKey)(raw, {
|
|
462
|
+
onExcessProperty: "error",
|
|
463
|
+
});
|
|
464
|
+
const { libraryId: installationId } = await (await this.owner).admitInvocation(facts, "graphStatus");
|
|
465
|
+
const run = owner.store.read(runId);
|
|
466
|
+
if (run?.teamId !== installationId)
|
|
467
|
+
return { error: "not_found" };
|
|
468
|
+
const outcome = owner.store.outcome(runId);
|
|
469
|
+
let status;
|
|
470
|
+
try {
|
|
471
|
+
status = await (await this.env.GRAPH_WORKFLOWS.get(runId)).status();
|
|
472
|
+
}
|
|
473
|
+
catch (cause) {
|
|
474
|
+
// The recorded run is visible before its engine instance is: while
|
|
475
|
+
// the run is still active, a failed instance lookup is that honest
|
|
476
|
+
// wait, not a fault. A settled run's lookup failure stays a failure.
|
|
477
|
+
if (outcome !== "active")
|
|
478
|
+
throw cause;
|
|
479
|
+
status = { status: "queued" };
|
|
480
|
+
}
|
|
481
|
+
return {
|
|
482
|
+
runId,
|
|
483
|
+
planDigest: run.plan.planDigest,
|
|
484
|
+
title: run.plan.definition.title,
|
|
485
|
+
outcome,
|
|
486
|
+
events: owner.store.events(runId),
|
|
487
|
+
reviews: owner.store.reviews(runId),
|
|
488
|
+
status: outcome === "cancelled" ? "terminated" : status.status,
|
|
489
|
+
output: outcome === "cancelled" ? null : (status.output ?? null),
|
|
490
|
+
error: status.error ?? null,
|
|
491
|
+
};
|
|
492
|
+
}
|
|
493
|
+
async cancel(facts, raw) {
|
|
494
|
+
const owner = await this.owner;
|
|
495
|
+
const { runId } = S.decodeUnknownSync(runKey)(raw, {
|
|
496
|
+
onExcessProperty: "error",
|
|
497
|
+
});
|
|
498
|
+
const { libraryId: installationId } = await (await this.owner).admitInvocation(facts, "cancel");
|
|
499
|
+
const run = owner.store.read(runId);
|
|
500
|
+
if (run?.teamId !== installationId)
|
|
501
|
+
return { kind: "refused", reason: "denied" };
|
|
502
|
+
if (owner.store.outcome(runId) !== "active")
|
|
503
|
+
return { kind: "terminal" };
|
|
504
|
+
const instance = await this.env.GRAPH_WORKFLOWS.get(runId);
|
|
505
|
+
try {
|
|
506
|
+
await instance.terminate();
|
|
507
|
+
}
|
|
508
|
+
catch (cause) {
|
|
509
|
+
const status = await instance.status();
|
|
510
|
+
if (status.status !== "terminated" &&
|
|
511
|
+
status.status !== "complete" &&
|
|
512
|
+
status.status !== "errored")
|
|
513
|
+
throw cause;
|
|
514
|
+
owner.store.markTerminal(runId, status.status === "terminated" ? "cancelled" : "terminal");
|
|
515
|
+
await this.endRunGit(runId);
|
|
516
|
+
if (status.status === "terminated")
|
|
517
|
+
await this.report(runId, { kind: "cancelled" });
|
|
518
|
+
return {
|
|
519
|
+
kind: status.status === "terminated" ? "cancelled" : "terminal",
|
|
520
|
+
};
|
|
521
|
+
}
|
|
522
|
+
owner.store.markTerminal(runId, "cancelled");
|
|
523
|
+
await this.endRunGit(runId);
|
|
524
|
+
await this.report(runId, { kind: "cancelled" });
|
|
525
|
+
return { kind: "cancelled" };
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
/** The SAME extracted interpreter as Hub, with this host's owned ports. */
|
|
529
|
+
export class StandaloneGraphWorkflow extends GraphWorkflow {
|
|
530
|
+
codeExecution() {
|
|
531
|
+
const localCpuUnenforced = "WORKFLOW_CODE_LOCAL_DEV" in this.env &&
|
|
532
|
+
this.env.WORKFLOW_CODE_LOCAL_DEV === "true";
|
|
533
|
+
return {
|
|
534
|
+
sandbox: createCodemodeSandbox(this.env.LOADER, "workflow-code", {
|
|
535
|
+
localDevUnenforcedLimits: localCpuUnenforced ? ["cpu"] : [],
|
|
536
|
+
}),
|
|
537
|
+
// Workflow data transforms have a host-owned 30-second execution budget.
|
|
538
|
+
timeoutMs: 30_000,
|
|
539
|
+
};
|
|
540
|
+
}
|
|
541
|
+
dispatcher(params) {
|
|
542
|
+
const runs = this.env.WORKFLOW_RUNS.getByName(params.teamId);
|
|
543
|
+
return {
|
|
544
|
+
loadRun: (installationId, runId) => runs.loadRun(installationId, runId),
|
|
545
|
+
beforeNode: (event) => runs.beforeNode(event),
|
|
546
|
+
dispatch: (call) => runs.dispatch(call),
|
|
547
|
+
recordEvent: (event) => runs.recordEvent(event),
|
|
548
|
+
openReview: (review) => runs.openReview(review),
|
|
549
|
+
};
|
|
550
|
+
}
|
|
551
|
+
terminalTriggerRun(params, ending) {
|
|
552
|
+
return this.env.WORKFLOW_RUNS.getByName(params.teamId).terminal(params.runId, ending);
|
|
553
|
+
}
|
|
554
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
/** The storage codecs and operation checks used by both sides of the native frame. */
|
|
3
|
+
export declare const storageFrameMethods: {
|
|
4
|
+
APP_STORAGE: {
|
|
5
|
+
read: {
|
|
6
|
+
decodeArgs: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => readonly [string];
|
|
7
|
+
decodeResult: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => {
|
|
8
|
+
readonly kind: "accepted";
|
|
9
|
+
readonly value: {
|
|
10
|
+
readonly value: Schema.Json;
|
|
11
|
+
readonly source: "team" | "member" | "none";
|
|
12
|
+
readonly team: {
|
|
13
|
+
readonly value: Schema.Json;
|
|
14
|
+
readonly revision: number;
|
|
15
|
+
} | null;
|
|
16
|
+
readonly member: {
|
|
17
|
+
readonly value: Schema.Json;
|
|
18
|
+
readonly revision: number;
|
|
19
|
+
} | null;
|
|
20
|
+
readonly canWriteTeam: boolean;
|
|
21
|
+
};
|
|
22
|
+
} | {
|
|
23
|
+
readonly kind: "rejected";
|
|
24
|
+
readonly code: "unavailable" | "invalid" | "undeclared_key" | "scope_not_declared" | "owner_required" | "too_large" | "quota_exceeded" | "conflict";
|
|
25
|
+
};
|
|
26
|
+
requiredOperations: () => string[];
|
|
27
|
+
};
|
|
28
|
+
write: {
|
|
29
|
+
decodeArgs: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => readonly [{
|
|
30
|
+
readonly value: Schema.Json;
|
|
31
|
+
readonly key: string;
|
|
32
|
+
readonly scope: "team" | "member";
|
|
33
|
+
readonly basedOn: number | null;
|
|
34
|
+
}];
|
|
35
|
+
decodeResult: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => {
|
|
36
|
+
readonly kind: "accepted";
|
|
37
|
+
readonly value: {
|
|
38
|
+
readonly revision: number;
|
|
39
|
+
};
|
|
40
|
+
} | {
|
|
41
|
+
readonly kind: "rejected";
|
|
42
|
+
readonly code: "unavailable" | "invalid" | "undeclared_key" | "scope_not_declared" | "owner_required" | "too_large" | "quota_exceeded" | "conflict";
|
|
43
|
+
};
|
|
44
|
+
requiredOperations: () => string[];
|
|
45
|
+
};
|
|
46
|
+
reset: {
|
|
47
|
+
decodeArgs: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => readonly [{
|
|
48
|
+
readonly key: string;
|
|
49
|
+
readonly scope: "team" | "member";
|
|
50
|
+
readonly basedOn: number | null;
|
|
51
|
+
}];
|
|
52
|
+
decodeResult: (input: unknown, options?: import("effect/SchemaAST").ParseOptions) => {
|
|
53
|
+
readonly kind: "accepted";
|
|
54
|
+
readonly value: {
|
|
55
|
+
readonly revision: number;
|
|
56
|
+
};
|
|
57
|
+
} | {
|
|
58
|
+
readonly kind: "rejected";
|
|
59
|
+
readonly code: "unavailable" | "invalid" | "undeclared_key" | "scope_not_declared" | "owner_required" | "too_large" | "quota_exceeded" | "conflict";
|
|
60
|
+
};
|
|
61
|
+
requiredOperations: () => string[];
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import * as Schema from "effect/Schema";
|
|
2
|
+
import { appStorageKeyNameSchema, appStorageWriteSchema, appStorageResetSchema, appStorageReadResultSchema, appStorageMutationResultSchema, } from "@fungi.computer/agar/storage";
|
|
3
|
+
/** The storage codecs and operation checks used by both sides of the native frame. */
|
|
4
|
+
export const storageFrameMethods = {
|
|
5
|
+
APP_STORAGE: {
|
|
6
|
+
read: {
|
|
7
|
+
decodeArgs: Schema.decodeUnknownSync(Schema.Tuple([appStorageKeyNameSchema]), { onExcessProperty: "error" }),
|
|
8
|
+
decodeResult: Schema.decodeUnknownSync(appStorageReadResultSchema, {
|
|
9
|
+
onExcessProperty: "error",
|
|
10
|
+
}),
|
|
11
|
+
requiredOperations: () => ["read"],
|
|
12
|
+
},
|
|
13
|
+
write: {
|
|
14
|
+
decodeArgs: Schema.decodeUnknownSync(Schema.Tuple([appStorageWriteSchema]), { onExcessProperty: "error" }),
|
|
15
|
+
decodeResult: Schema.decodeUnknownSync(appStorageMutationResultSchema, {
|
|
16
|
+
onExcessProperty: "error",
|
|
17
|
+
}),
|
|
18
|
+
requiredOperations: () => ["write"],
|
|
19
|
+
},
|
|
20
|
+
reset: {
|
|
21
|
+
decodeArgs: Schema.decodeUnknownSync(Schema.Tuple([appStorageResetSchema]), { onExcessProperty: "error" }),
|
|
22
|
+
decodeResult: Schema.decodeUnknownSync(appStorageMutationResultSchema, {
|
|
23
|
+
onExcessProperty: "error",
|
|
24
|
+
}),
|
|
25
|
+
requiredOperations: () => ["reset"],
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
};
|