@fungi.computer/oyster 0.6.0 → 0.8.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/README.md +133 -78
- package/dist/agent-archive-projection.d.ts +8 -0
- package/dist/agent-archive-projection.js +49 -0
- package/dist/agent-schedules.d.ts +61 -0
- package/dist/agent-schedules.js +19 -0
- package/dist/agents.d.ts +35 -14
- package/dist/agents.js +93 -144
- package/dist/app-builds.d.ts +7 -2
- package/dist/app-builds.js +19 -2
- package/dist/approval-capability.d.ts +1 -1
- package/dist/approval-capability.js +11 -16
- package/dist/approval-home.d.ts +2 -1
- package/dist/approval-home.js +5 -3
- package/dist/apps/catalog.js +1 -1
- package/dist/apps/gate.d.ts +4 -7
- package/dist/apps/gate.js +14 -29
- package/dist/apps/index.d.ts +1 -1
- package/dist/apps/installation.d.ts +4 -42
- package/dist/apps/installation.js +7 -75
- package/dist/apps/operations.js +0 -10
- package/dist/apps/permissions.d.ts +18 -8
- package/dist/apps/permissions.js +7 -1
- package/dist/auth.d.ts +1 -24
- package/dist/auth.js +9 -39
- package/dist/authorization.d.ts +307 -0
- package/dist/authorization.js +542 -0
- package/dist/boot-host-script.js +1 -1
- package/dist/build/build-jobs.d.ts +2 -2
- package/dist/build/candidate-builder.d.ts +2 -0
- package/dist/build/candidate-builder.js +5 -1
- package/dist/build/candidate-cli.js +3 -0
- package/dist/build/candidate-cli.mjs +70 -22
- package/dist/build/job-log.d.ts +23 -0
- package/dist/build/job-log.js +88 -0
- package/dist/build/local-build.d.ts +9 -1
- package/dist/build/local-build.js +11 -9
- package/dist/cloudflare.d.ts +4 -1
- package/dist/cloudflare.js +1 -1
- package/dist/files.js +9 -8
- package/dist/git-admission.d.ts +3 -3
- package/dist/git-admission.js +4 -6
- package/dist/git-door.d.ts +8 -7
- package/dist/git-door.js +18 -17
- package/dist/git.d.ts +1 -1
- package/dist/host.d.ts +33 -40
- package/dist/host.js +156 -275
- package/dist/installation-execution.js +14 -5
- package/dist/installation-operations.d.ts +4 -180
- package/dist/installation-operations.js +1 -5
- package/dist/installation-store-generation.d.ts +4 -1
- package/dist/installation-store-generation.js +59 -6
- package/dist/internal/delivery.js +0 -1
- package/dist/internal/host-gate.d.ts +3 -2
- package/dist/internal/host-gate.js +5 -18
- package/dist/internal/invocation-timing.d.ts +16 -0
- package/dist/internal/invocation-timing.js +23 -0
- package/dist/internal/registry-installations.js +1 -0
- package/dist/invocation.d.ts +15 -14
- package/dist/invocation.js +58 -26
- package/dist/keys.d.ts +2 -19
- package/dist/keys.js +1 -37
- package/dist/mcp.d.ts +15 -27
- package/dist/mcp.js +105 -155
- package/dist/page/agent-browser.d.ts +15 -0
- package/dist/page/agent-browser.js +162 -0
- package/dist/page/app-permissions-port.d.ts +3 -0
- package/dist/page/app-permissions-port.js +43 -0
- package/dist/page/app-permissions.d.ts +11 -0
- package/dist/page/app-permissions.js +296 -0
- package/dist/page/isolated-page-theme.d.ts +2 -0
- package/dist/page/isolated-page-theme.js +11 -0
- package/dist/page/mount.d.ts +2 -13
- package/dist/page/mount.js +7 -93
- package/dist/page-script.d.ts +0 -3
- package/dist/page-script.js +3 -4
- package/dist/standalone/agent-archive-owner.d.ts +42 -0
- package/dist/standalone/agent-archive-owner.js +116 -0
- package/dist/standalone/agent-archive-schedules.d.ts +6 -0
- package/dist/standalone/agent-archive-schedules.js +76 -0
- package/dist/standalone/agent-archive.d.ts +31 -0
- package/dist/standalone/agent-archive.js +67 -0
- package/dist/standalone/agent-computers.d.ts +7 -6
- package/dist/standalone/agent-computers.js +4 -7
- package/dist/standalone/agent-mail.d.ts +2 -2
- package/dist/standalone/agents.d.ts +186 -20
- package/dist/standalone/agents.js +251 -30
- package/dist/standalone/app-builds-binding.js +1 -1
- package/dist/standalone/app-set.js +2 -54
- package/dist/standalone/app-source.d.ts +3 -4
- package/dist/standalone/app-source.js +12 -9
- package/dist/standalone/builds.d.ts +2 -14
- package/dist/standalone/builds.js +15 -13
- package/dist/standalone/computer-fleet.d.ts +4 -4
- package/dist/standalone/computer-fleet.js +13 -42
- package/dist/standalone/computer.d.ts +4 -3
- package/dist/standalone/computer.js +52 -53
- package/dist/standalone/dashboard-approval.d.ts +10 -0
- package/dist/standalone/dashboard-approval.js +66 -0
- package/dist/standalone/machine-link.d.ts +4 -221
- package/dist/standalone/machine-link.js +21 -15
- package/dist/standalone/media.d.ts +1 -0
- package/dist/standalone/media.js +20 -14
- package/dist/standalone/owner-routes.d.ts +16 -0
- package/dist/standalone/owner-routes.js +21 -0
- package/dist/standalone/permission-resources.d.ts +5 -0
- package/dist/standalone/permission-resources.js +31 -0
- package/dist/standalone/registry.d.ts +7 -0
- package/dist/standalone/registry.js +3 -0
- package/dist/standalone/tenancy.d.ts +0 -3
- package/dist/standalone/tenancy.js +2 -5
- package/dist/standalone/worker-routes.d.ts +19 -0
- package/dist/standalone/worker-routes.js +9 -0
- package/dist/standalone/worker.d.ts +1 -1
- package/dist/standalone/worker.js +27 -35
- package/dist/standalone/workflow-binding.d.ts +10 -3
- package/dist/standalone/workflow-binding.js +22 -5
- package/dist/standalone/workflow-git-capture.js +2 -1
- package/dist/standalone/workflow-host.d.ts +8 -103
- package/dist/standalone/workflow-host.js +1 -1
- package/dist/standalone/workflow-node-capture.js +2 -2
- package/dist/standalone/workflow-root-authority.d.ts +1 -1
- package/dist/standalone/workflow-root-authority.js +1 -1
- package/dist/standalone/workflow-schedules.d.ts +31 -4
- package/dist/standalone/workflow-schedules.js +18 -5
- package/dist/standalone/workflow-webhooks.d.ts +4 -18
- package/dist/standalone/workflow-webhooks.js +5 -5
- package/dist/standalone/workflows.d.ts +53 -27
- package/dist/standalone/workflows.js +9 -3
- package/dist/storage-frame.d.ts +6 -6
- package/dist/testing/capabilities.d.ts +7 -6
- package/dist/testing/capabilities.js +3 -6
- package/dist/testing/installation.d.ts +0 -1
- package/dist/testing/installation.js +2 -5
- package/dist/workers-git.d.ts +12 -4
- package/dist/workers-git.js +38 -35
- package/dist/workers.d.ts +9 -1
- package/dist/workers.js +44 -8
- package/dist/workflows.d.ts +4 -0
- package/dist/workflows.js +2 -0
- package/docs/api/README.md +7 -0
- package/docs/api/agent-schedules.md +176 -0
- package/docs/api/agents.md +34 -13
- package/docs/api/app-storage.md +1 -1
- package/docs/api/apps.md +323 -225
- package/docs/api/auth.md +0 -55
- package/docs/api/authorization.md +1300 -0
- package/docs/api/build.md +42 -38
- package/docs/api/cloudflare.md +3 -3
- package/docs/api/git.md +20 -11
- package/docs/api/host.md +64 -192
- package/docs/api/index.md +1 -1
- package/docs/api/invocation.md +14 -14
- package/docs/api/keys.md +1 -98
- package/docs/api/mcp.md +43 -40
- package/docs/api/modules.md +2 -0
- package/docs/api/page/mount.md +16 -19
- package/docs/api/workers-git.md +46 -12
- package/docs/api/workers.md +111 -222
- package/package.json +41 -22
- package/dist/page/computer-target.d.ts +0 -3
- package/dist/page/computer-target.js +0 -9
- package/dist/standalone/channel-session-door.d.ts +0 -4
- package/dist/standalone/channel-session-door.js +0 -72
package/dist/workers-git.js
CHANGED
|
@@ -13,7 +13,6 @@ import { APP_INVOCATION_CEILING_MS, invocationFacts, invocationCallerContext, }
|
|
|
13
13
|
import { AppInstanceError, selectionOf } from "./index.js";
|
|
14
14
|
import { ownerOrKeyAuth } from "./auth.js";
|
|
15
15
|
import { causeClass } from "./cause-class.js";
|
|
16
|
-
import { Hono } from "hono";
|
|
17
16
|
import { HTTPException } from "hono/http-exception";
|
|
18
17
|
import * as Schema from "effect/Schema";
|
|
19
18
|
import { defineIdFamily } from "@fungi.computer/cairn";
|
|
@@ -26,7 +25,8 @@ import { agentCapabilities, agentApprovalRoutes, agentMcpServerRoutes, } from ".
|
|
|
26
25
|
import { createArtifactsRestNamespace, } from "@fungi.computer/burrow";
|
|
27
26
|
import { attemptWebhook } from "./webhook-delivery.js";
|
|
28
27
|
import { createRecipientDeliveries, } from "./event-recipients.js";
|
|
29
|
-
import { createOyster,
|
|
28
|
+
import { createOyster, } from "./host.js";
|
|
29
|
+
import { oysterPrincipalIsOwner, owner as ownerRoute, routes as routeTable, } from "./authorization.js";
|
|
30
30
|
import { OysterInstance, oysterBindingEntrypoint, oysterBindings, oysterWorkerHost, r2FileSource, r2ArtifactStore, serveOysterBootCapability, } from "./workers.js";
|
|
31
31
|
import { registryInstallations } from "./internal/registry-installations.js";
|
|
32
32
|
import { refuseOlderOysterStore } from "./older-oyster-store-refusal.js";
|
|
@@ -763,36 +763,29 @@ const subscribeSchema = Schema.Struct({
|
|
|
763
763
|
secret: Schema.optional(Schema.String.check(Schema.isMinLength(16))),
|
|
764
764
|
});
|
|
765
765
|
const keyNamePattern = /^[a-z0-9][a-z0-9-]{0,39}$/u;
|
|
766
|
-
/** `invocation.ts:486` uses `team-key:visitor` for anonymous readers; a key can never claim that name. */
|
|
767
|
-
const reservedKeyName = "visitor";
|
|
768
766
|
const keysWire = keyWire(oysterKeyVocabulary);
|
|
769
767
|
/** Owner routes for keys and webhooks; `createOyster` mounts them owner-only. */
|
|
770
768
|
export function gitAdminRoutes(env, scope) {
|
|
771
|
-
const routes =
|
|
769
|
+
const routes = routeTable();
|
|
772
770
|
const keys = () => env.KEYS.getByName(scope.durableName("keys"));
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
const listed = await keys().list(owner.actor.memberId);
|
|
771
|
+
// Key and webhook custody is the owner's own, never through an App.
|
|
772
|
+
const owner = ownerRoute("direct");
|
|
773
|
+
routes.get("/api/keys", owner, async (_context, { principal }) => {
|
|
774
|
+
const listed = await keys().list(principal.actor.memberId);
|
|
778
775
|
if (listed.kind === "error")
|
|
779
776
|
return Response.json({ error: listed.error.code }, { status: 500 });
|
|
780
777
|
return Response.json({ keys: listed.value.map(keysWire.toSummary) });
|
|
781
778
|
});
|
|
782
|
-
routes.post("/api/keys", async (context) => {
|
|
779
|
+
routes.post("/api/keys", owner, async (context, { principal }) => {
|
|
783
780
|
const body = keysWire.issue.safeParse(await context.req.json());
|
|
784
781
|
if (!body.success)
|
|
785
782
|
return Response.json({ error: "Invalid key" }, { status: 400 });
|
|
786
783
|
// Named identities and rate policy belong to this host, not the wire grammar.
|
|
787
784
|
if (!keyNamePattern.test(body.data.name) ||
|
|
788
|
-
body.data.name === reservedKeyName ||
|
|
789
785
|
body.data.keyId !== undefined ||
|
|
790
786
|
body.data.rateLimit !== undefined)
|
|
791
787
|
return Response.json({ error: "Invalid key name" }, { status: 400 });
|
|
792
|
-
const
|
|
793
|
-
if (!oysterPrincipalIsOwner(owner))
|
|
794
|
-
return Response.json({ error: "Owner only" }, { status: 403 });
|
|
795
|
-
const issued = await keys().issue(owner.actor.memberId, {
|
|
788
|
+
const issued = await keys().issue(principal.actor.memberId, {
|
|
796
789
|
name: body.data.name,
|
|
797
790
|
grants: body.data.grants,
|
|
798
791
|
expiresAt: body.data.expiresAt,
|
|
@@ -804,19 +797,16 @@ export function gitAdminRoutes(env, scope) {
|
|
|
804
797
|
key: keysWire.toSummary(issued.value.record),
|
|
805
798
|
}, { status: 201 });
|
|
806
799
|
});
|
|
807
|
-
routes.post("/api/keys/revoke", async (context) => {
|
|
800
|
+
routes.post("/api/keys/revoke", owner, async (context, { principal }) => {
|
|
808
801
|
const body = keysWire.revoke.safeParse(await context.req.json());
|
|
809
802
|
if (!body.success)
|
|
810
803
|
return Response.json({ error: "Invalid request" }, { status: 400 });
|
|
811
|
-
const
|
|
812
|
-
if (!oysterPrincipalIsOwner(owner))
|
|
813
|
-
return Response.json({ error: "Owner only" }, { status: 403 });
|
|
814
|
-
const revoked = await keys().revoke(owner.actor.memberId, body.data.requestId, body.data.keyId);
|
|
804
|
+
const revoked = await keys().revoke(principal.actor.memberId, body.data.requestId, body.data.keyId);
|
|
815
805
|
if (revoked.kind === "error")
|
|
816
806
|
return Response.json({ error: revoked.error.code }, { status: revoked.error.code === "denied" ? 404 : 400 });
|
|
817
807
|
return Response.json({ key: keysWire.toSummary(revoked.value) });
|
|
818
808
|
});
|
|
819
|
-
routes.post("/api/webhooks", async (context) => {
|
|
809
|
+
routes.post("/api/webhooks", owner, async (context) => {
|
|
820
810
|
const body = Schema.decodeUnknownOption(subscribeSchema)(await context.req.json());
|
|
821
811
|
if (body._tag === "None")
|
|
822
812
|
return Response.json({ error: "Invalid subscription" }, { status: 400 });
|
|
@@ -825,9 +815,9 @@ export function gitAdminRoutes(env, scope) {
|
|
|
825
815
|
types: body.value.types ?? [],
|
|
826
816
|
}), { status: 201 });
|
|
827
817
|
});
|
|
828
|
-
routes.get("/api/webhooks", async () => Response.json(await env.WEBHOOKS.getByName(scope.durableName("webhooks")).subscriptions()));
|
|
829
|
-
routes.get("/api/webhooks/:id/deliveries", async (context) => Response.json(await env.WEBHOOKS.getByName(scope.durableName("webhooks")).deliveries(context.req.param("id"))));
|
|
830
|
-
routes.delete("/api/webhooks/:id", async (context) => (await env.WEBHOOKS.getByName(scope.durableName("webhooks")).unsubscribe(context.req.param("id")))
|
|
818
|
+
routes.get("/api/webhooks", owner, async () => Response.json(await env.WEBHOOKS.getByName(scope.durableName("webhooks")).subscriptions()));
|
|
819
|
+
routes.get("/api/webhooks/:id/deliveries", owner, async (context) => Response.json(await env.WEBHOOKS.getByName(scope.durableName("webhooks")).deliveries(context.req.param("id"))));
|
|
820
|
+
routes.delete("/api/webhooks/:id", owner, async (context) => (await env.WEBHOOKS.getByName(scope.durableName("webhooks")).unsubscribe(context.req.param("id")))
|
|
831
821
|
? new Response(null, { status: 204 })
|
|
832
822
|
: Response.json({ error: "Not found" }, { status: 404 }));
|
|
833
823
|
return routes;
|
|
@@ -1136,8 +1126,8 @@ export async function oysterGitWorkerHost(env, options, selected, request) {
|
|
|
1136
1126
|
const base = oysterWorkerHost(env, auth, policyOptions);
|
|
1137
1127
|
const capabilities = [
|
|
1138
1128
|
...(base.capabilities ?? []),
|
|
1139
|
-
...(agents === undefined ? [] : agentCapabilities(agents
|
|
1140
|
-
...(options.capabilities?.(env, workspace
|
|
1129
|
+
...(agents === undefined ? [] : agentCapabilities(agents)),
|
|
1130
|
+
...(options.capabilities?.(env, workspace) ?? []),
|
|
1141
1131
|
];
|
|
1142
1132
|
let gitOptions = { scope };
|
|
1143
1133
|
if (options.workflowGitPass !== undefined)
|
|
@@ -1145,14 +1135,7 @@ export async function oysterGitWorkerHost(env, options, selected, request) {
|
|
|
1145
1135
|
if (options.buildGitPass !== undefined)
|
|
1146
1136
|
gitOptions = { ...gitOptions, buildGitPass: options.buildGitPass };
|
|
1147
1137
|
const git = oysterWorkerGit(env, gitOptions);
|
|
1148
|
-
const ownerRoutes =
|
|
1149
|
-
const hostOwnerRoutes = options.ownerRoutes?.(env, scope);
|
|
1150
|
-
if (hostOwnerRoutes !== undefined)
|
|
1151
|
-
ownerRoutes.route("/", hostOwnerRoutes);
|
|
1152
|
-
if (agents !== undefined) {
|
|
1153
|
-
ownerRoutes.route("/", agentApprovalRoutes(agents));
|
|
1154
|
-
ownerRoutes.route("/", agentMcpServerRoutes(agents));
|
|
1155
|
-
}
|
|
1138
|
+
const ownerRoutes = oysterGitOwnerRoutes(env, scope, options.ownerRoutes?.(env, scope), agents);
|
|
1156
1139
|
let host = {
|
|
1157
1140
|
...base,
|
|
1158
1141
|
capabilities,
|
|
@@ -1168,8 +1151,28 @@ export async function oysterGitWorkerHost(env, options, selected, request) {
|
|
|
1168
1151
|
host = { ...host, computerControl: options.computerControl(env, scope) };
|
|
1169
1152
|
if (options.homeInstallationId !== undefined)
|
|
1170
1153
|
host = { ...host, homeInstallationId: options.homeInstallationId(env) };
|
|
1154
|
+
if (options.permissionResources !== undefined)
|
|
1155
|
+
host = {
|
|
1156
|
+
...host,
|
|
1157
|
+
permissionResources: options.permissionResources(env, scope),
|
|
1158
|
+
};
|
|
1171
1159
|
return host;
|
|
1172
1160
|
}
|
|
1161
|
+
/**
|
|
1162
|
+
* A Git host's whole owner table: keys and webhooks, the root's own owner
|
|
1163
|
+
* routes, and Agent approval and MCP server custody. The host and the
|
|
1164
|
+
* authorization law both compose it here.
|
|
1165
|
+
*/
|
|
1166
|
+
export function oysterGitOwnerRoutes(env, scope, hostOwnerRoutes, agents) {
|
|
1167
|
+
const ownerRoutes = gitAdminRoutes(env, scope);
|
|
1168
|
+
if (hostOwnerRoutes !== undefined)
|
|
1169
|
+
ownerRoutes.include(hostOwnerRoutes);
|
|
1170
|
+
if (agents !== undefined) {
|
|
1171
|
+
ownerRoutes.include(agentApprovalRoutes(agents));
|
|
1172
|
+
ownerRoutes.include(agentMcpServerRoutes(agents));
|
|
1173
|
+
}
|
|
1174
|
+
return ownerRoutes;
|
|
1175
|
+
}
|
|
1173
1176
|
/**
|
|
1174
1177
|
* Authenticate against the pinned tenant. A request admitted at the Worker's
|
|
1175
1178
|
* top reuses that one admission; any other entry resolves its own.
|
package/dist/workers.d.ts
CHANGED
|
@@ -34,6 +34,11 @@ export { r2ArtifactStore, r2FileSource, ownerKeyAuth };
|
|
|
34
34
|
export type OysterBindingResult = Awaited<ReturnType<GitBinding[keyof GitBinding]>> | Schema.Json | undefined;
|
|
35
35
|
/** Verified backend custody is captured in the frame, never in a current-context field. */
|
|
36
36
|
export type OysterInvocationHost = BackgroundFrameState & Readonly<{
|
|
37
|
+
/** This frame's guest binding packets and the wall time they waited. */
|
|
38
|
+
bindingWaits: {
|
|
39
|
+
count: number;
|
|
40
|
+
ms: number;
|
|
41
|
+
};
|
|
37
42
|
artifact: Backend;
|
|
38
43
|
declaration: AppDeclaration | null;
|
|
39
44
|
/** The verified declared method; opaque backend and lifecycle frames have none. */
|
|
@@ -124,10 +129,10 @@ export declare class OysterRegistry<Env extends OysterWorkerEnv = OysterWorkerEn
|
|
|
124
129
|
readonly kind: "policy";
|
|
125
130
|
} | null;
|
|
126
131
|
readonly access: "write" | "external";
|
|
132
|
+
readonly state: "pending" | "expired" | "denied" | "applied" | "requested" | "approved" | "claimed" | "outcome_unknown";
|
|
127
133
|
readonly reason: "pending" | "expired" | "not-found" | "not-eligible" | "already-answered" | "stale-revision" | "declined" | "fenced" | "not-granted" | "read-only" | "in-flight" | "outcome-unknown" | "identity-conflict" | null;
|
|
128
134
|
readonly updatedAt: number;
|
|
129
135
|
readonly module: string;
|
|
130
|
-
readonly state: "pending" | "expired" | "denied" | "applied" | "requested" | "approved" | "claimed" | "outcome_unknown";
|
|
131
136
|
readonly recordId: string;
|
|
132
137
|
readonly authorityFence: string;
|
|
133
138
|
readonly requester: {
|
|
@@ -222,6 +227,8 @@ export declare class OysterRegistry<Env extends OysterWorkerEnv = OysterWorkerEn
|
|
|
222
227
|
get(installationId: string): Installation | null;
|
|
223
228
|
/** Durable store identity, regenerated only when the store itself is replaced. */
|
|
224
229
|
generation(): string;
|
|
230
|
+
/** Permanent audit fact for the owner Home's empty installation notice. */
|
|
231
|
+
installationResetAt(): number | null;
|
|
225
232
|
/** Native RPC returns a closed result; callers never classify a transported Error. */
|
|
226
233
|
compareAndPut(installation: Installation, expectedAuthorityVersion: number, expectedGeneration: string, tenantId?: TenantId): Promise<InstallationCommit>;
|
|
227
234
|
private writeInstallation;
|
|
@@ -387,6 +394,7 @@ export declare class OysterInstance<Env extends OysterWorkerEnv = OysterWorkerEn
|
|
|
387
394
|
/** Resolve each guest packet against its immutable frame before any host effect. */
|
|
388
395
|
bindingCall(raw: FrameBindingProps, method: string, input: readonly unknown[]): Promise<FrameBindingReply<OysterBindingResult>>;
|
|
389
396
|
private executeBindingCall;
|
|
397
|
+
private dispatchBindingCall;
|
|
390
398
|
/** Last provider-accepted ref recorded by this installation's journal. */
|
|
391
399
|
gitTip(installationId: string, repository: string, ref: string, tenantId?: TenantId): Promise<string | null>;
|
|
392
400
|
/** Join accepted fact identity and Carrier delivery in one local transaction. */
|
package/dist/workers.js
CHANGED
|
@@ -38,6 +38,7 @@ import { AppInstanceError, } from "./index.js";
|
|
|
38
38
|
import { createCloudflareAppInstance, r2ArtifactStore, createCloudflareInvocationGate, edgeVerifiedObjectCache, decodeFrameBindingProps, captureFrameBindingReply, frameBindingEntrypoint, backgroundFrameMethods, } from "./cloudflare.js";
|
|
39
39
|
import { invocationFactsSchema, assertBackgroundBinding, admitBackgroundFrame, } from "./invocation.js";
|
|
40
40
|
import { deliverBackground, deliverGitPush } from "./internal/delivery.js";
|
|
41
|
+
import { reportSlowInvocation } from "./internal/invocation-timing.js";
|
|
41
42
|
import { releaseCache } from "./internal/host-gate.js";
|
|
42
43
|
import { createOyster, } from "./host.js";
|
|
43
44
|
import { createGitPushJournal } from "./git-journal.js";
|
|
@@ -66,7 +67,7 @@ const approvalHomePinRow = Schema.Struct({
|
|
|
66
67
|
});
|
|
67
68
|
/** The installation registry: one SQLite-backed Durable Object per Oyster. */
|
|
68
69
|
export class OysterRegistry extends DurableObject {
|
|
69
|
-
#
|
|
70
|
+
#installationStore;
|
|
70
71
|
/** Decided once, before this version writes anything, and never revised. */
|
|
71
72
|
#installationsFromOlderOyster;
|
|
72
73
|
#approval;
|
|
@@ -161,7 +162,7 @@ export class OysterRegistry extends DurableObject {
|
|
|
161
162
|
this.#installationsFromOlderOyster = installationsFromOlderOyster(ctx.storage.sql);
|
|
162
163
|
ctx.storage.sql.exec("CREATE TABLE IF NOT EXISTS oyster_approval_home (id INTEGER PRIMARY KEY CHECK (id = 1), tenant_id TEXT NOT NULL, origin TEXT NOT NULL) STRICT");
|
|
163
164
|
ctx.storage.sql.exec("CREATE TABLE IF NOT EXISTS installations (installation_id TEXT PRIMARY KEY, record TEXT NOT NULL) STRICT");
|
|
164
|
-
this.#
|
|
165
|
+
this.#installationStore = createInstallationStoreGeneration(ctx.storage);
|
|
165
166
|
ctx.storage.sql.exec("CREATE TABLE IF NOT EXISTS boot_capabilities (id TEXT PRIMARY KEY, token_digest TEXT NOT NULL, expires_at INTEGER NOT NULL, record TEXT NOT NULL) STRICT");
|
|
166
167
|
ensureAppSourceTables(ctx.storage.sql);
|
|
167
168
|
this.#installationOperations = createInstallationOperations({
|
|
@@ -376,7 +377,11 @@ export class OysterRegistry extends DurableObject {
|
|
|
376
377
|
}
|
|
377
378
|
/** Durable store identity, regenerated only when the store itself is replaced. */
|
|
378
379
|
generation() {
|
|
379
|
-
return this.#generation();
|
|
380
|
+
return this.#installationStore.generation();
|
|
381
|
+
}
|
|
382
|
+
/** Permanent audit fact for the owner Home's empty installation notice. */
|
|
383
|
+
installationResetAt() {
|
|
384
|
+
return this.#installationStore.resetAt();
|
|
380
385
|
}
|
|
381
386
|
/** Native RPC returns a closed result; callers never classify a transported Error. */
|
|
382
387
|
async compareAndPut(installation, expectedAuthorityVersion, expectedGeneration, tenantId = defaultTenant) {
|
|
@@ -762,9 +767,19 @@ export class OysterInstance extends DurableObject {
|
|
|
762
767
|
const frame = this.frames.active(props.frameId);
|
|
763
768
|
if (props.instanceId !== frame.facts.instanceId)
|
|
764
769
|
throw new AppInstanceError("revoked");
|
|
770
|
+
const started = Date.now();
|
|
771
|
+
try {
|
|
772
|
+
return await this.dispatchBindingCall(frame, props, method, input);
|
|
773
|
+
}
|
|
774
|
+
finally {
|
|
775
|
+
frame.host.bindingWaits.count += 1;
|
|
776
|
+
frame.host.bindingWaits.ms += Date.now() - started;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
async dispatchBindingCall(frame, props, method, input) {
|
|
765
780
|
assertBackgroundBinding(frame, props.binding);
|
|
766
781
|
// A guest packet is its own entry: exactly one registry read re-admits it.
|
|
767
|
-
await this.assertCurrent(frame);
|
|
782
|
+
const current = await this.assertCurrent(frame);
|
|
768
783
|
const row = this.bindings[props.binding];
|
|
769
784
|
const descriptor = row?.methods[method];
|
|
770
785
|
// Operations declared by the verified Release; absent bindings grant nothing.
|
|
@@ -784,10 +799,14 @@ export class OysterInstance extends DurableObject {
|
|
|
784
799
|
throw new AppInstanceError("binding_unavailable");
|
|
785
800
|
}
|
|
786
801
|
const args = descriptor.decodeArgs(input);
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
.every((operation) => granted.includes(operation)))
|
|
802
|
+
const required = descriptor.requiredOperations(args);
|
|
803
|
+
if (!required.every((operation) => granted.includes(operation)))
|
|
790
804
|
throw new AppInstanceError("binding_not_granted");
|
|
805
|
+
if (descriptor.requestedResource !== undefined) {
|
|
806
|
+
const selected = approvedBindingGrants(current, frame.host.declaration ?? emptyAppDeclaration, descriptor.requestedResource(args)).find((grant) => grant.binding === props.binding)?.operations ?? [];
|
|
807
|
+
if (!required.every((operation) => selected.includes(operation)))
|
|
808
|
+
throw new AppInstanceError("binding_not_granted");
|
|
809
|
+
}
|
|
791
810
|
const result = await row.dispatch(this.#bindingContext, frame, props, method, args);
|
|
792
811
|
if (this.frames.active(props.frameId) !== frame)
|
|
793
812
|
throw new AppInstanceError("revoked");
|
|
@@ -848,8 +867,10 @@ export class OysterInstance extends DurableObject {
|
|
|
848
867
|
.find((currentGrant) => currentGrant.binding === grant.binding)
|
|
849
868
|
?.operations.includes(operation) !== true)))
|
|
850
869
|
throw new AppInstanceError("revoked");
|
|
870
|
+
return current;
|
|
851
871
|
}
|
|
852
872
|
async withFrame(raw, limits, work, tenantId = defaultTenant, methodName) {
|
|
873
|
+
const entered = Date.now();
|
|
853
874
|
this.requireTenant(tenantId);
|
|
854
875
|
const facts = Schema.decodeUnknownSync(invocationFactsSchema, {
|
|
855
876
|
onExcessProperty: "error",
|
|
@@ -860,6 +881,7 @@ export class OysterInstance extends DurableObject {
|
|
|
860
881
|
throw new AppInstanceError("instance_identity_mismatch");
|
|
861
882
|
const release = this.release(facts.selection.releaseId);
|
|
862
883
|
const resolved = await this.backends(release);
|
|
884
|
+
const verified = Date.now();
|
|
863
885
|
if (resolved?.digest !== facts.artifactDigest)
|
|
864
886
|
throw new AppInstanceError("invalid_invocation_facts");
|
|
865
887
|
if (facts.subject.kind === "call" &&
|
|
@@ -895,6 +917,7 @@ export class OysterInstance extends DurableObject {
|
|
|
895
917
|
};
|
|
896
918
|
}
|
|
897
919
|
let host = {
|
|
920
|
+
bindingWaits: { count: 0, ms: 0 },
|
|
898
921
|
artifact: { release, ...resolved },
|
|
899
922
|
declaration: resolved.declaration,
|
|
900
923
|
origin: "unchecked",
|
|
@@ -904,7 +927,20 @@ export class OysterInstance extends DurableObject {
|
|
|
904
927
|
// Facts carry the authority admitted at the request's top. The Instance
|
|
905
928
|
// checks them against the owner state the host applied to it, never by
|
|
906
929
|
// calling back up to the registry.
|
|
907
|
-
|
|
930
|
+
let admitted = verified;
|
|
931
|
+
try {
|
|
932
|
+
return await this.frames.run(scoped, host, (frame) => {
|
|
933
|
+
admitted = Date.now();
|
|
934
|
+
return work(this.runtimeFor(limits), frame);
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
finally {
|
|
938
|
+
reportSlowInvocation(methodName ?? facts.subject.kind, host, {
|
|
939
|
+
entered,
|
|
940
|
+
verified,
|
|
941
|
+
admitted,
|
|
942
|
+
});
|
|
943
|
+
}
|
|
908
944
|
}
|
|
909
945
|
release(releaseId) {
|
|
910
946
|
const row = this.ctx.storage.sql
|
package/dist/workflows.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export declare const agentWorkflowOperationSchema: z.ZodEnum<{
|
|
|
10
10
|
catalog: "catalog";
|
|
11
11
|
armSchedule: "armSchedule";
|
|
12
12
|
disarmSchedule: "disarmSchedule";
|
|
13
|
+
pauseSchedule: "pauseSchedule";
|
|
14
|
+
resumeSchedule: "resumeSchedule";
|
|
13
15
|
schedules: "schedules";
|
|
14
16
|
armEventTrigger: "armEventTrigger";
|
|
15
17
|
disarmEventTrigger: "disarmEventTrigger";
|
|
@@ -26,6 +28,8 @@ export declare const agentAppWorkflowRequestSchema: z.ZodObject<{
|
|
|
26
28
|
catalog: "catalog";
|
|
27
29
|
armSchedule: "armSchedule";
|
|
28
30
|
disarmSchedule: "disarmSchedule";
|
|
31
|
+
pauseSchedule: "pauseSchedule";
|
|
32
|
+
resumeSchedule: "resumeSchedule";
|
|
29
33
|
schedules: "schedules";
|
|
30
34
|
armEventTrigger: "armEventTrigger";
|
|
31
35
|
disarmEventTrigger: "disarmEventTrigger";
|
package/dist/workflows.js
CHANGED
package/docs/api/README.md
CHANGED
|
@@ -36,6 +36,13 @@
|
|
|
36
36
|
| `@fungi.computer/oyster/git` | `EventSink`, `createGitDoor`, `signStandardWebhook` | The EVENTS binding contract, the git smart-HTTP door and Standard Webhooks signing. `GitBinding` comes from `@fungi.computer/agar/git`. |
|
|
37
37
|
| `@fungi.computer/oyster/workers-git` | `oysterGitRoot`, `createOysterGitWorker`, `ownerOrKeyTenancy`, `oysterWorkerGit`, `gitAdminRoutes` | One Git root whose `hostFor` serves HTTP, MCP and Instances, or `host.git` and key/webhook routes for your own host. |
|
|
38
38
|
|
|
39
|
+
Standalone Oyster owners can `POST /agents/:agentId/archive` and
|
|
40
|
+
`POST /agents/:agentId/unarchive`. `GET /agents` lists active Agents;
|
|
41
|
+
`GET /agents?archived=true` lists only archived Agents. Archive preserves
|
|
42
|
+
existing Sessions and reads but refuses new Shiitake work with
|
|
43
|
+
`contract/archived`. It pauses Almanac and Loop schedules; restore resumes only
|
|
44
|
+
schedules paused by archive. The generated Agent API is in `docs/api/agents.md`.
|
|
45
|
+
|
|
39
46
|
The host owns admission: it decides who may apply owner state and which
|
|
40
47
|
selection a request carries. Oyster owns what happens to one Instance once the
|
|
41
48
|
host has that authority: owner-state replay and conflict rules, Release
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
<!-- Generated by Botanical API docs (TypeDoc + typedoc-plugin-markdown). Do not edit. -->
|
|
2
|
+
|
|
3
|
+
[**@fungi.computer/oyster**](README.md)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
[@fungi.computer/oyster](modules.md) / agent-schedules
|
|
8
|
+
|
|
9
|
+
# agent-schedules
|
|
10
|
+
|
|
11
|
+
## Type Aliases
|
|
12
|
+
|
|
13
|
+
### AppAgentScheduleListInput
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
type AppAgentScheduleListInput = z.input<
|
|
17
|
+
typeof appAgentScheduleListInputSchema
|
|
18
|
+
>;
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
A single bounded native read, not an all-Agent inventory grant.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
### AgentScheduleTarget
|
|
26
|
+
|
|
27
|
+
```ts
|
|
28
|
+
type AgentScheduleTarget = z.output<typeof agentScheduleTargetSchema>;
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Identity to admit before acquiring the corresponding Agent owner.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
### AgentSchedulePage
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
type AgentSchedulePage = typeof agentSchedulePageSchema.Type;
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
One Agent's page, with no directory fan-out or availability policy.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
### AgentScheduleControlReceipt
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
type AgentScheduleControlReceipt =
|
|
49
|
+
typeof agentScheduleControlReceiptSchema.Type;
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Content-free acknowledgement of the native owner's completed transition.
|
|
53
|
+
|
|
54
|
+
## Variables
|
|
55
|
+
|
|
56
|
+
### appAgentScheduleListInputSchema
|
|
57
|
+
|
|
58
|
+
```ts
|
|
59
|
+
const appAgentScheduleListInputSchema: ZodObject<
|
|
60
|
+
{
|
|
61
|
+
agentId: ZodString;
|
|
62
|
+
after: ZodOptional<
|
|
63
|
+
ZodObject<
|
|
64
|
+
{
|
|
65
|
+
agentId: ZodString;
|
|
66
|
+
kind: ZodUnion<readonly [ZodLiteral<"almanac">, ZodLiteral<"loop">]>;
|
|
67
|
+
after: ZodOptional<ZodString>;
|
|
68
|
+
},
|
|
69
|
+
$strict
|
|
70
|
+
>
|
|
71
|
+
>;
|
|
72
|
+
limit: ZodDefault<ZodNumber>;
|
|
73
|
+
},
|
|
74
|
+
$strict
|
|
75
|
+
>;
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
The App selects one Agent; its host must admit that target before opening it.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
### agentScheduleBindingArgs
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
const agentScheduleBindingArgs: object;
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Both hosts decode the ordinary AGENTS packet with the native owner's grammar.
|
|
89
|
+
|
|
90
|
+
#### Type Declaration
|
|
91
|
+
|
|
92
|
+
| Name | Type | Description |
|
|
93
|
+
| ----------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
|
|
94
|
+
| <a id="property-schedules"></a> `schedules` | `ZodTuple`\<\[`ZodObject`\<\{ `agentId`: `ZodString`; `after`: `ZodOptional`\<`ZodObject`\<\{ `agentId`: `ZodString`; `kind`: `ZodUnion`\<readonly \[`ZodLiteral`\<...\>, `ZodLiteral`\<...\>\]\>; `after`: `ZodOptional`\<`ZodString`\>; \}, `$strict`\>\>; `limit`: `ZodDefault`\<`ZodNumber`\>; \}, `$strict`\>\], `null`\> | One bounded content-bearing read, admitted independently of manage. |
|
|
95
|
+
| <a id="property-pauseschedule"></a> `pauseSchedule` | `ZodTuple`\<\[`ZodDiscriminatedUnion`\<\[`ZodObject`\<\{ `kind`: `ZodLiteral`\<`"almanac"`\>; `agentId`: `ZodString`; `scheduleId`: `ZodString` & `ZodType`\<`string`, `string`, `$ZodTypeInternals`\<`string`, `string`\>\>; \}, `$strict`\>, `ZodObject`\<\{ `kind`: `ZodLiteral`\<`"loop"`\>; `agentId`: `ZodString`; `sessionId`: `ZodString` & `ZodType`\<`string`, `string`, `$ZodTypeInternals`\<`string`, `string`\>\>; `loopId`: `ZodString` & `ZodType`\<`string`, `string`, `$ZodTypeInternals`\<`string`, `string`\>\>; \}, `$strict`\>\], `"kind"`\>\], `null`\> | Pause the exact listed schedule, retaining future resume and accepted work. |
|
|
96
|
+
| <a id="property-resumeschedule"></a> `resumeSchedule` | `ZodTuple`\<\[`ZodDiscriminatedUnion`\<\[`ZodObject`\<\{ `kind`: `ZodLiteral`\<`"almanac"`\>; `agentId`: `ZodString`; `scheduleId`: `ZodString` & `ZodType`\<`string`, `string`, `$ZodTypeInternals`\<`string`, `string`\>\>; \}, `$strict`\>, `ZodObject`\<\{ `kind`: `ZodLiteral`\<`"loop"`\>; `agentId`: `ZodString`; `sessionId`: `ZodString` & `ZodType`\<`string`, `string`, `$ZodTypeInternals`\<`string`, `string`\>\>; `loopId`: `ZodString` & `ZodType`\<`string`, `string`, `$ZodTypeInternals`\<`string`, `string`\>\>; \}, `$strict`\>\], `"kind"`\>\], `null`\> | Resume the exact listed schedule through its native owner. |
|
|
97
|
+
| <a id="property-deleteschedule"></a> `deleteSchedule` | `ZodTuple`\<\[`ZodDiscriminatedUnion`\<\[`ZodObject`\<\{ `kind`: `ZodLiteral`\<`"almanac"`\>; `agentId`: `ZodString`; `scheduleId`: `ZodString` & `ZodType`\<`string`, `string`, `$ZodTypeInternals`\<`string`, `string`\>\>; \}, `$strict`\>, `ZodObject`\<\{ `kind`: `ZodLiteral`\<`"loop"`\>; `agentId`: `ZodString`; `sessionId`: `ZodString` & `ZodType`\<`string`, `string`, `$ZodTypeInternals`\<`string`, `string`\>\>; `loopId`: `ZodString` & `ZodType`\<`string`, `string`, `$ZodTypeInternals`\<`string`, `string`\>\>; \}, `$strict`\>\], `"kind"`\>\], `null`\> | Cancel future occurrences of the exact identity without erasing history. |
|
|
98
|
+
|
|
99
|
+
---
|
|
100
|
+
|
|
101
|
+
### agentSchedulePageSchema
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const agentSchedulePageSchema: Schema.Struct<{
|
|
105
|
+
items: Schema.$Array<Schema.Union<readonly [Schema.Struct<{
|
|
106
|
+
agentId: Schema.String;
|
|
107
|
+
kind: Schema.Literal<"almanac">;
|
|
108
|
+
schedule: Schema.Struct<{
|
|
109
|
+
id: Schema.String;
|
|
110
|
+
sessionId: Schema.String;
|
|
111
|
+
prompt: Schema.String;
|
|
112
|
+
cron: Schema.NullOr<...>;
|
|
113
|
+
nextDueAt: Schema.Int;
|
|
114
|
+
state: Schema.Literals<...>;
|
|
115
|
+
lastCommandId: Schema.NullOr<...>;
|
|
116
|
+
lastError: Schema.NullOr<...>;
|
|
117
|
+
attempt: Schema.Int;
|
|
118
|
+
}>;
|
|
119
|
+
}>, Schema.Struct<{
|
|
120
|
+
agentId: Schema.String;
|
|
121
|
+
kind: Schema.Literal<"loop">;
|
|
122
|
+
schedule: Schema.Struct<{
|
|
123
|
+
sessionId: Schema.String;
|
|
124
|
+
loopId: Schema.String;
|
|
125
|
+
origin: Schema.Literals<...>;
|
|
126
|
+
expiresAt: Schema.NullOr<...>;
|
|
127
|
+
prompt: Schema.String;
|
|
128
|
+
mode: Schema.Literals<...>;
|
|
129
|
+
cron: Schema.NullOr<...>;
|
|
130
|
+
state: Schema.Literals<...>;
|
|
131
|
+
commandId: Schema.String;
|
|
132
|
+
reason: Schema.NullOr<...>;
|
|
133
|
+
nextDueAt: Schema.NullOr<...>;
|
|
134
|
+
lastError: Schema.NullOr<...>;
|
|
135
|
+
consecutiveFailures: Schema.Int;
|
|
136
|
+
}>;
|
|
137
|
+
}>]>>;
|
|
138
|
+
next: Schema.NullOr<Schema.Struct<{
|
|
139
|
+
agentId: Schema.String;
|
|
140
|
+
kind: Schema.Literals<readonly ["almanac", "loop"]>;
|
|
141
|
+
after: Schema.optionalKey<Schema.String>;
|
|
142
|
+
}>>;
|
|
143
|
+
}>;
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
A bounded content-bearing page; owner failures reject rather than look empty.
|
|
147
|
+
|
|
148
|
+
---
|
|
149
|
+
|
|
150
|
+
### agentScheduleControlReceiptSchema
|
|
151
|
+
|
|
152
|
+
```ts
|
|
153
|
+
const agentScheduleControlReceiptSchema: Schema.Union<
|
|
154
|
+
readonly [
|
|
155
|
+
Schema.Struct<{
|
|
156
|
+
agentId: Schema.String;
|
|
157
|
+
kind: Schema.Literal<"almanac">;
|
|
158
|
+
scheduleId: Schema.String;
|
|
159
|
+
state: Schema.Literals<
|
|
160
|
+
readonly ["active", "paused", "cancelled", "finished"]
|
|
161
|
+
>;
|
|
162
|
+
}>,
|
|
163
|
+
Schema.Struct<{
|
|
164
|
+
agentId: Schema.String;
|
|
165
|
+
kind: Schema.Literal<"loop">;
|
|
166
|
+
sessionId: Schema.String;
|
|
167
|
+
loopId: Schema.String;
|
|
168
|
+
state: Schema.Literals<
|
|
169
|
+
readonly ["active", "paused", "finished", "failed", "cancelled"]
|
|
170
|
+
>;
|
|
171
|
+
}>,
|
|
172
|
+
]
|
|
173
|
+
>;
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
Manage-only result: exact target and native state, never prompt or history.
|
package/docs/api/agents.md
CHANGED
|
@@ -167,6 +167,26 @@ type OysterAgents = Readonly<{
|
|
|
167
167
|
)[];
|
|
168
168
|
}>[]
|
|
169
169
|
>;
|
|
170
|
+
setArchived: Promise<
|
|
171
|
+
| Readonly<{
|
|
172
|
+
archived: boolean;
|
|
173
|
+
revision: number;
|
|
174
|
+
}>
|
|
175
|
+
| Readonly<{
|
|
176
|
+
error:
|
|
177
|
+
| "not_found"
|
|
178
|
+
| "not_granted"
|
|
179
|
+
| "self"
|
|
180
|
+
| "not_creator"
|
|
181
|
+
| "running"
|
|
182
|
+
| "pending"
|
|
183
|
+
| "unreadable"
|
|
184
|
+
| "archived";
|
|
185
|
+
message?: string;
|
|
186
|
+
archived?: boolean;
|
|
187
|
+
revision?: number;
|
|
188
|
+
}>
|
|
189
|
+
>;
|
|
170
190
|
create: Promise<
|
|
171
191
|
Readonly<{
|
|
172
192
|
agentId: string;
|
|
@@ -301,7 +321,12 @@ type OysterAgents = Readonly<{
|
|
|
301
321
|
}>;
|
|
302
322
|
```
|
|
303
323
|
|
|
304
|
-
Where an Oyster's agents live and run.
|
|
324
|
+
Where an Oyster's agents live and run. Archive is non-destructive: `list()`
|
|
325
|
+
hides archived agents, and `list({ archived: true })` shows only archives.
|
|
326
|
+
Archived agents keep existing reads, replays and settlements, but refuse new
|
|
327
|
+
Sessions, prompts and steers with `contract/archived`. Archive refuses non-idle
|
|
328
|
+
Session work or unsettled delegations; it pauses Almanac and Loop schedules and
|
|
329
|
+
restores only archive-paused schedules on unarchive.
|
|
305
330
|
|
|
306
331
|
---
|
|
307
332
|
|
|
@@ -358,20 +383,16 @@ optional bearer.
|
|
|
358
383
|
### agentCapabilities()
|
|
359
384
|
|
|
360
385
|
```ts
|
|
361
|
-
function agentCapabilities(
|
|
362
|
-
agents,
|
|
363
|
-
liveKey,
|
|
364
|
-
): readonly Readonly<object & object>[];
|
|
386
|
+
function agentCapabilities(agents): readonly Readonly<object & object>[];
|
|
365
387
|
```
|
|
366
388
|
|
|
367
389
|
Agent adapters admitted against each App's declared capabilities.
|
|
368
390
|
|
|
369
391
|
#### Parameters
|
|
370
392
|
|
|
371
|
-
| Parameter | Type
|
|
372
|
-
| --------- |
|
|
373
|
-
| `agents` | [`OysterAgents`](#oysteragents)
|
|
374
|
-
| `liveKey` | (`keyId`) => `Promise`\< \| `Readonly`\<\{ `keyId`: `string`; `owner`: `string`; `grantVersion`: `number`; `grants`: readonly `Readonly`\<\{ `capability`: [`OysterKeyCapability`](keys.md#oysterkeycapability); `targets`: `GrantTargets`; \}\>[]; \}\> \| `null`\> |
|
|
393
|
+
| Parameter | Type |
|
|
394
|
+
| --------- | ------------------------------- |
|
|
395
|
+
| `agents` | [`OysterAgents`](#oysteragents) |
|
|
375
396
|
|
|
376
397
|
#### Returns
|
|
377
398
|
|
|
@@ -382,7 +403,7 @@ readonly `Readonly`\<`object` & `object`\>[]
|
|
|
382
403
|
### agentApprovalRoutes()
|
|
383
404
|
|
|
384
405
|
```ts
|
|
385
|
-
function agentApprovalRoutes(agents):
|
|
406
|
+
function agentApprovalRoutes(agents): Routes<OysterEnv>;
|
|
386
407
|
```
|
|
387
408
|
|
|
388
409
|
Host-owned direct approval under the admitted owner; never an App capability.
|
|
@@ -395,14 +416,14 @@ Host-owned direct approval under the admitted owner; never an App capability.
|
|
|
395
416
|
|
|
396
417
|
#### Returns
|
|
397
418
|
|
|
398
|
-
`
|
|
419
|
+
[`Routes`](authorization.md#routes)\<[`OysterEnv`](host.md#oysterenv)\>
|
|
399
420
|
|
|
400
421
|
---
|
|
401
422
|
|
|
402
423
|
### agentMcpServerRoutes()
|
|
403
424
|
|
|
404
425
|
```ts
|
|
405
|
-
function agentMcpServerRoutes(agents):
|
|
426
|
+
function agentMcpServerRoutes(agents): Routes<OysterEnv>;
|
|
406
427
|
```
|
|
407
428
|
|
|
408
429
|
Host-owned Agent MCP server custody for the owner directly; never an App
|
|
@@ -416,4 +437,4 @@ capability. Bearer tokens go in and never come back out.
|
|
|
416
437
|
|
|
417
438
|
#### Returns
|
|
418
439
|
|
|
419
|
-
`
|
|
440
|
+
[`Routes`](authorization.md#routes)\<[`OysterEnv`](host.md#oysterenv)\>
|
package/docs/api/app-storage.md
CHANGED
|
@@ -131,7 +131,7 @@ Whether `writer` may mutate `scope`; anything else is `owner_required`.
|
|
|
131
131
|
| Parameter | Type |
|
|
132
132
|
| --------- | --------------------------------------- |
|
|
133
133
|
| `writer` | [`AppStorageWriter`](#appstoragewriter) |
|
|
134
|
-
| `scope` | `"
|
|
134
|
+
| `scope` | `"team"` \| `"member"` |
|
|
135
135
|
|
|
136
136
|
#### Returns
|
|
137
137
|
|