@frockbot/kernel-contracts 0.3.1 → 0.3.2
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/package.json +4 -2
- package/src/applets.test.ts +299 -0
- package/src/applets.ts +902 -0
- package/src/authoring.test.ts +47 -0
- package/src/authoring.ts +57 -21
- package/src/contributions.ts +102 -0
- package/src/iframe-ui.test.ts +238 -37
- package/src/iframe-ui.ts +430 -89
- package/src/index.ts +2 -0
- package/src/isolate-context-catalog.generated.ts +3 -2
- package/src/isolate.ts +98 -0
- package/src/types.ts +10 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// Generated by scripts/generate-isolate-context-catalog.ts. Do not edit.
|
|
2
2
|
export const BOT_ISOLATE_CONTEXT_DTS_V1 =
|
|
3
|
-
"/**\n * The common exact `ctx` passed to a Bot-authored Package's tool and hook.\n * The model-facing declarations are generated from these interfaces, and the\n * wrapper's implementation is compile- and test-checked against the same\n * keys.\n */\ninterface BotPackageContextV1 {\n readonly tool?: string;\n readonly event?: BotIsolateHookEventNameV1;\n readonly botId: string;\n readonly sessionId: string;\n readonly runId: string;\n readonly turnId: string;\n readonly generationId: string;\n readonly packageId: string;\n readonly deadlineMs: number;\n readonly bindings: string[];\n readonly capabilities: {\n list(): Promise<IsolateCapabilityListOutcomeV1>;\n };\n readonly model: {\n invoke(request: NormalizedModelRequest): Promise<BotPackageModelOutcomeV1>;\n };\n readonly tools: {\n /** Runs through the trusted registry's active-Composition and deny guards. */\n invoke(request: IsolateToolRequestV1): Promise<IsolateToolOutcomeV1>;\n };\n readonly memory: {\n read(request: IsolateMemoryReadRequestV1): Promise<IsolateMemoryOutcomeV1>;\n write(request: IsolateMemoryWriteRequestV1): Promise<IsolateMemoryOutcomeV1>;\n forget(request: IsolateMemoryWriteRequestV1): Promise<IsolateMemoryOutcomeV1>;\n };\n readonly workspace: {\n read(path: IsolateWorkspacePathV1): Promise<IsolateWorkspaceOutcomeV1>;\n list(request: IsolateWorkspaceListRequestV1): Promise<IsolateWorkspaceOutcomeV1>;\n stat(path: IsolateWorkspacePathV1): Promise<IsolateWorkspaceOutcomeV1>;\n write(request: IsolateWorkspaceWriteRequestV1): Promise<IsolateWorkspaceOutcomeV1>;\n delete(request: IsolateWorkspaceDeleteRequestV1): Promise<IsolateWorkspaceOutcomeV1>;\n };\n connection(connectionId: string): Promise<IsolateConnectionOutcomeV1>;\n notify(request: IsolateNotificationRequestV1): Promise<IsolateNotificationOutcomeV1>;\n schedule(request: IsolateScheduleRequestV1): Promise<IsolateScheduleOutcomeV1>;\n}\n\ninterface BotPackageExecutionContextV1 extends BotPackageContextV1 {\n readonly tool: string;\n readonly event?: never;\n}\n\ninterface BotPackageHookContextV1 extends BotPackageContextV1 {\n readonly tool?: never;\n readonly event: BotIsolateHookEventNameV1;\n}";
|
|
3
|
+
"/**\n * The common exact `ctx` passed to a Bot-authored Package's tool and hook.\n * The model-facing declarations are generated from these interfaces, and the\n * wrapper's implementation is compile- and test-checked against the same\n * keys.\n */\ninterface BotPackageContextV1 {\n readonly tool?: string;\n readonly event?: BotIsolateHookEventNameV1;\n readonly botId: string;\n readonly sessionId: string;\n readonly runId: string;\n readonly turnId: string;\n readonly generationId: string;\n readonly packageId: string;\n readonly deadlineMs: number;\n readonly bindings: string[];\n readonly capabilities: {\n list(): Promise<IsolateCapabilityListOutcomeV1>;\n };\n readonly model: {\n invoke(request: NormalizedModelRequest): Promise<BotPackageModelOutcomeV1>;\n };\n readonly tools: {\n /** Runs through the trusted registry's active-Composition and deny guards. */\n invoke(request: IsolateToolRequestV1): Promise<IsolateToolOutcomeV1>;\n };\n readonly memory: {\n read(request: IsolateMemoryReadRequestV1): Promise<IsolateMemoryOutcomeV1>;\n write(request: IsolateMemoryWriteRequestV1): Promise<IsolateMemoryOutcomeV1>;\n forget(request: IsolateMemoryWriteRequestV1): Promise<IsolateMemoryOutcomeV1>;\n };\n readonly workspace: {\n read(path: IsolateWorkspacePathV1): Promise<IsolateWorkspaceOutcomeV1>;\n list(request: IsolateWorkspaceListRequestV1): Promise<IsolateWorkspaceOutcomeV1>;\n stat(path: IsolateWorkspacePathV1): Promise<IsolateWorkspaceOutcomeV1>;\n write(request: IsolateWorkspaceWriteRequestV1): Promise<IsolateWorkspaceOutcomeV1>;\n delete(request: IsolateWorkspaceDeleteRequestV1): Promise<IsolateWorkspaceOutcomeV1>;\n };\n /**\n * The User's Applets (ADR 0022). Account-wide: every Bot of this User sees\n * every Applet. `publish` is a durable effect — it reads the built Applet\n * from the Applets Package's durable root, verifies its manifest against the\n * bytes, writes immutable artifacts, records the generation, mounts it, and\n * proposes a new Composition generation for this Bot.\n */\n readonly applets: {\n list(): Promise<IsolateAppletsOutcomeV1>;\n create(input: {\n displayName: string;\n }): Promise<IsolateAppletsOutcomeV1>;\n publish(input: {\n appletId: string;\n }): Promise<IsolateAppletsOutcomeV1>;\n revert(input: {\n appletId: string;\n generationId: string;\n }): Promise<IsolateAppletsOutcomeV1>;\n delete(input: {\n appletId: string;\n }): Promise<IsolateAppletsOutcomeV1>;\n focus(input: {\n appletId: string | null;\n }): Promise<IsolateAppletsOutcomeV1>;\n generations(input: {\n appletId: string;\n }): Promise<IsolateAppletsOutcomeV1>;\n };\n connection(connectionId: string): Promise<IsolateConnectionOutcomeV1>;\n notify(request: IsolateNotificationRequestV1): Promise<IsolateNotificationOutcomeV1>;\n schedule(request: IsolateScheduleRequestV1): Promise<IsolateScheduleOutcomeV1>;\n}\n\ninterface BotPackageExecutionContextV1 extends BotPackageContextV1 {\n readonly tool: string;\n readonly event?: never;\n}\n\ninterface BotPackageHookContextV1 extends BotPackageContextV1 {\n readonly tool?: never;\n readonly event: BotIsolateHookEventNameV1;\n}";
|
|
4
4
|
export const BOT_ISOLATE_CONTEXT_KEYS_V1 = [
|
|
5
5
|
"tool",
|
|
6
6
|
"event",
|
|
@@ -17,9 +17,10 @@ export const BOT_ISOLATE_CONTEXT_KEYS_V1 = [
|
|
|
17
17
|
"tools",
|
|
18
18
|
"memory",
|
|
19
19
|
"workspace",
|
|
20
|
+
"applets",
|
|
20
21
|
"connection",
|
|
21
22
|
"notify",
|
|
22
23
|
"schedule",
|
|
23
24
|
] as const;
|
|
24
25
|
export const BOT_ISOLATE_CONTEXT_SUMMARY_V1 =
|
|
25
|
-
"Package execute and hook ctx share: readonly tool?: string; readonly event?: BotIsolateHookEventNameV1; readonly botId: string; readonly sessionId: string; readonly runId: string; readonly turnId: string; readonly generationId: string; readonly packageId: string; readonly deadlineMs: number; readonly bindings: string[]; readonly capabilities: { list(): Promise<IsolateCapabilityListOutcomeV1>; }; readonly model: { invoke(request: NormalizedModelRequest): Promise<BotPackageModelOutcomeV1>; }; readonly tools: { /** Runs through the trusted registry's active-Composition and deny guards. */ invoke(request: IsolateToolRequestV1): Promise<IsolateToolOutcomeV1>; }; readonly memory: { read(request: IsolateMemoryReadRequestV1): Promise<IsolateMemoryOutcomeV1>; write(request: IsolateMemoryWriteRequestV1): Promise<IsolateMemoryOutcomeV1>; forget(request: IsolateMemoryWriteRequestV1): Promise<IsolateMemoryOutcomeV1>; }; readonly workspace: { read(path: IsolateWorkspacePathV1): Promise<IsolateWorkspaceOutcomeV1>; list(request: IsolateWorkspaceListRequestV1): Promise<IsolateWorkspaceOutcomeV1>; stat(path: IsolateWorkspacePathV1): Promise<IsolateWorkspaceOutcomeV1>; write(request: IsolateWorkspaceWriteRequestV1): Promise<IsolateWorkspaceOutcomeV1>; delete(request: IsolateWorkspaceDeleteRequestV1): Promise<IsolateWorkspaceOutcomeV1>; }; connection(connectionId: string): Promise<IsolateConnectionOutcomeV1>; notify(request: IsolateNotificationRequestV1): Promise<IsolateNotificationOutcomeV1>; schedule(request: IsolateScheduleRequestV1): Promise<IsolateScheduleOutcomeV1>;";
|
|
26
|
+
"Package execute and hook ctx share: readonly tool?: string; readonly event?: BotIsolateHookEventNameV1; readonly botId: string; readonly sessionId: string; readonly runId: string; readonly turnId: string; readonly generationId: string; readonly packageId: string; readonly deadlineMs: number; readonly bindings: string[]; readonly capabilities: { list(): Promise<IsolateCapabilityListOutcomeV1>; }; readonly model: { invoke(request: NormalizedModelRequest): Promise<BotPackageModelOutcomeV1>; }; readonly tools: { /** Runs through the trusted registry's active-Composition and deny guards. */ invoke(request: IsolateToolRequestV1): Promise<IsolateToolOutcomeV1>; }; readonly memory: { read(request: IsolateMemoryReadRequestV1): Promise<IsolateMemoryOutcomeV1>; write(request: IsolateMemoryWriteRequestV1): Promise<IsolateMemoryOutcomeV1>; forget(request: IsolateMemoryWriteRequestV1): Promise<IsolateMemoryOutcomeV1>; }; readonly workspace: { read(path: IsolateWorkspacePathV1): Promise<IsolateWorkspaceOutcomeV1>; list(request: IsolateWorkspaceListRequestV1): Promise<IsolateWorkspaceOutcomeV1>; stat(path: IsolateWorkspacePathV1): Promise<IsolateWorkspaceOutcomeV1>; write(request: IsolateWorkspaceWriteRequestV1): Promise<IsolateWorkspaceOutcomeV1>; delete(request: IsolateWorkspaceDeleteRequestV1): Promise<IsolateWorkspaceOutcomeV1>; }; /** * The User's Applets (ADR 0022). Account-wide: every Bot of this User sees * every Applet. `publish` is a durable effect — it reads the built Applet * from the Applets Package's durable root, verifies its manifest against the * bytes, writes immutable artifacts, records the generation, mounts it, and * proposes a new Composition generation for this Bot. */ readonly applets: { list(): Promise<IsolateAppletsOutcomeV1>; create(input: { displayName: string; }): Promise<IsolateAppletsOutcomeV1>; publish(input: { appletId: string; }): Promise<IsolateAppletsOutcomeV1>; revert(input: { appletId: string; generationId: string; }): Promise<IsolateAppletsOutcomeV1>; delete(input: { appletId: string; }): Promise<IsolateAppletsOutcomeV1>; focus(input: { appletId: string | null; }): Promise<IsolateAppletsOutcomeV1>; generations(input: { appletId: string; }): Promise<IsolateAppletsOutcomeV1>; }; connection(connectionId: string): Promise<IsolateConnectionOutcomeV1>; notify(request: IsolateNotificationRequestV1): Promise<IsolateNotificationOutcomeV1>; schedule(request: IsolateScheduleRequestV1): Promise<IsolateScheduleOutcomeV1>;";
|
package/src/isolate.ts
CHANGED
|
@@ -230,6 +230,25 @@ export interface IsolateNotificationRequestV1 {
|
|
|
230
230
|
export type IsolateNotificationOutcomeV1 =
|
|
231
231
|
{ status: "recorded" } | IsolateCapabilityFailureV1;
|
|
232
232
|
|
|
233
|
+
/**
|
|
234
|
+
* The Applet capability a Bot isolate calls (ADR 0022, plan §3).
|
|
235
|
+
*
|
|
236
|
+
* One tagged request rather than seven methods on the stub: the operations
|
|
237
|
+
* share a scope, an authority, and an outcome shape, and the wrapper narrows
|
|
238
|
+
* them back into the seven-verb `ctx.applets` a Bot author writes against.
|
|
239
|
+
*/
|
|
240
|
+
export type IsolateAppletsRequestV1 =
|
|
241
|
+
| { op: "list" }
|
|
242
|
+
| { op: "create"; displayName: string }
|
|
243
|
+
| { op: "publish"; appletId: string }
|
|
244
|
+
| { op: "revert"; appletId: string; generationId: string }
|
|
245
|
+
| { op: "delete"; appletId: string }
|
|
246
|
+
| { op: "focus"; appletId: string | null }
|
|
247
|
+
| { op: "generations"; appletId: string };
|
|
248
|
+
|
|
249
|
+
export type IsolateAppletsOutcomeV1 =
|
|
250
|
+
{ status: "available"; value: unknown } | IsolateCapabilityFailureV1;
|
|
251
|
+
|
|
233
252
|
/** A durable Routine operation attributed to one Package call. */
|
|
234
253
|
export interface IsolateScheduleRequestV1 {
|
|
235
254
|
callId: string;
|
|
@@ -303,6 +322,7 @@ export interface BotCapabilitiesStub {
|
|
|
303
322
|
schedule(
|
|
304
323
|
request: IsolateScheduleRequestV1,
|
|
305
324
|
): Promise<IsolateScheduleOutcomeV1>;
|
|
325
|
+
applets(request: IsolateAppletsRequestV1): Promise<IsolateAppletsOutcomeV1>;
|
|
306
326
|
}
|
|
307
327
|
|
|
308
328
|
/** The model outcome Bot-authored `package.js` receives after wrapper narrowing. */
|
|
@@ -363,6 +383,25 @@ export interface BotPackageContextV1 {
|
|
|
363
383
|
request: IsolateWorkspaceDeleteRequestV1,
|
|
364
384
|
): Promise<IsolateWorkspaceOutcomeV1>;
|
|
365
385
|
};
|
|
386
|
+
/**
|
|
387
|
+
* The User's Applets (ADR 0022). Account-wide: every Bot of this User sees
|
|
388
|
+
* every Applet. `publish` is a durable effect — it reads the built Applet
|
|
389
|
+
* from the Applets Package's durable root, verifies its manifest against the
|
|
390
|
+
* bytes, writes immutable artifacts, records the generation, mounts it, and
|
|
391
|
+
* proposes a new Composition generation for this Bot.
|
|
392
|
+
*/
|
|
393
|
+
readonly applets: {
|
|
394
|
+
list(): Promise<IsolateAppletsOutcomeV1>;
|
|
395
|
+
create(input: { displayName: string }): Promise<IsolateAppletsOutcomeV1>;
|
|
396
|
+
publish(input: { appletId: string }): Promise<IsolateAppletsOutcomeV1>;
|
|
397
|
+
revert(input: {
|
|
398
|
+
appletId: string;
|
|
399
|
+
generationId: string;
|
|
400
|
+
}): Promise<IsolateAppletsOutcomeV1>;
|
|
401
|
+
delete(input: { appletId: string }): Promise<IsolateAppletsOutcomeV1>;
|
|
402
|
+
focus(input: { appletId: string | null }): Promise<IsolateAppletsOutcomeV1>;
|
|
403
|
+
generations(input: { appletId: string }): Promise<IsolateAppletsOutcomeV1>;
|
|
404
|
+
};
|
|
366
405
|
connection(connectionId: string): Promise<IsolateConnectionOutcomeV1>;
|
|
367
406
|
notify(
|
|
368
407
|
request: IsolateNotificationRequestV1,
|
|
@@ -999,6 +1038,65 @@ export function decodeIsolateScheduleRequestV1(
|
|
|
999
1038
|
};
|
|
1000
1039
|
}
|
|
1001
1040
|
|
|
1041
|
+
const APPLET_CAPABILITY_ID = /^[a-z0-9][a-z0-9-]{0,63}\.[a-z0-9-]{1,64}$/;
|
|
1042
|
+
|
|
1043
|
+
export function decodeIsolateAppletsRequestV1(
|
|
1044
|
+
input: unknown,
|
|
1045
|
+
label = "isolate Applets request",
|
|
1046
|
+
): IsolateAppletsRequestV1 {
|
|
1047
|
+
const value = record(input, label);
|
|
1048
|
+
const appletId = (): string => {
|
|
1049
|
+
const id = boundedString(value.appletId, `${label}.appletId`, 129);
|
|
1050
|
+
if (!APPLET_CAPABILITY_ID.test(id)) {
|
|
1051
|
+
throw new Error(`${label}.appletId is invalid`);
|
|
1052
|
+
}
|
|
1053
|
+
return id;
|
|
1054
|
+
};
|
|
1055
|
+
switch (value.op) {
|
|
1056
|
+
case "list":
|
|
1057
|
+
exactKeys(value, ["op"], label);
|
|
1058
|
+
return { op: "list" };
|
|
1059
|
+
case "create":
|
|
1060
|
+
exactKeys(value, ["op", "displayName"], label);
|
|
1061
|
+
return {
|
|
1062
|
+
op: "create",
|
|
1063
|
+
displayName: boundedString(
|
|
1064
|
+
value.displayName,
|
|
1065
|
+
`${label}.displayName`,
|
|
1066
|
+
128,
|
|
1067
|
+
),
|
|
1068
|
+
};
|
|
1069
|
+
case "publish":
|
|
1070
|
+
exactKeys(value, ["op", "appletId"], label);
|
|
1071
|
+
return { op: "publish", appletId: appletId() };
|
|
1072
|
+
case "revert":
|
|
1073
|
+
exactKeys(value, ["op", "appletId", "generationId"], label);
|
|
1074
|
+
return {
|
|
1075
|
+
op: "revert",
|
|
1076
|
+
appletId: appletId(),
|
|
1077
|
+
generationId: boundedString(
|
|
1078
|
+
value.generationId,
|
|
1079
|
+
`${label}.generationId`,
|
|
1080
|
+
128,
|
|
1081
|
+
),
|
|
1082
|
+
};
|
|
1083
|
+
case "delete":
|
|
1084
|
+
exactKeys(value, ["op", "appletId"], label);
|
|
1085
|
+
return { op: "delete", appletId: appletId() };
|
|
1086
|
+
case "focus":
|
|
1087
|
+
exactKeys(value, ["op", "appletId"], label);
|
|
1088
|
+
return {
|
|
1089
|
+
op: "focus",
|
|
1090
|
+
appletId: value.appletId === null ? null : appletId(),
|
|
1091
|
+
};
|
|
1092
|
+
case "generations":
|
|
1093
|
+
exactKeys(value, ["op", "appletId"], label);
|
|
1094
|
+
return { op: "generations", appletId: appletId() };
|
|
1095
|
+
default:
|
|
1096
|
+
throw new Error(`${label}.op is invalid`);
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1002
1100
|
const MEMORY_SCOPES = ["bot", "user", "project"] as const;
|
|
1003
1101
|
const MEMORY_TIERS = ["profile", "log", "note"] as const;
|
|
1004
1102
|
|
package/src/types.ts
CHANGED
|
@@ -611,7 +611,10 @@ export interface SessionEventMap {
|
|
|
611
611
|
*
|
|
612
612
|
* `reason` is why the sync ran: `open` before the Turn's first Computer tool
|
|
613
613
|
* call, `signal` when the on-Computer watcher reported a change mid-Turn,
|
|
614
|
-
* `turn-end` after a Turn that used the Computer
|
|
614
|
+
* `turn-end` after a Turn that used the Computer, and `publish` for the one
|
|
615
|
+
* sanctioned reconciliation outside that policy — a single declared root
|
|
616
|
+
* pulled and pushed so an Applet publish can read the artifact `applet
|
|
617
|
+
* build` left on the Computer (ADR 0022 decision 7).
|
|
615
618
|
*/
|
|
616
619
|
/**
|
|
617
620
|
* A background process on the Computer changed hands: it was launched,
|
|
@@ -640,7 +643,7 @@ export interface SessionEventMap {
|
|
|
640
643
|
};
|
|
641
644
|
"computer/sync": {
|
|
642
645
|
turn: number;
|
|
643
|
-
reason: "open" | "signal" | "turn-end";
|
|
646
|
+
reason: "open" | "signal" | "turn-end" | "publish";
|
|
644
647
|
status: "ok" | "unavailable" | "refused" | "skipped";
|
|
645
648
|
detail: string;
|
|
646
649
|
pulled: number;
|
|
@@ -1875,7 +1878,11 @@ export function decodeSessionEvent(input: unknown): SessionEvent {
|
|
|
1875
1878
|
"session event",
|
|
1876
1879
|
);
|
|
1877
1880
|
turn();
|
|
1878
|
-
if (
|
|
1881
|
+
if (
|
|
1882
|
+
!["open", "signal", "turn-end", "publish"].includes(
|
|
1883
|
+
event.reason as string,
|
|
1884
|
+
)
|
|
1885
|
+
) {
|
|
1879
1886
|
throw new Error("session event.reason is invalid");
|
|
1880
1887
|
}
|
|
1881
1888
|
if (
|