@agentorg/cli 0.0.4 → 0.0.6
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 +18 -102
- package/dist/node_modules/@agentorg/hub/dist/src/hub-actor.d.ts +2 -7
- package/dist/node_modules/@agentorg/hub/dist/src/hub-actor.js +4 -111
- package/dist/node_modules/@agentorg/hub/dist/src/index.d.ts +1 -3
- package/dist/node_modules/@agentorg/hub/dist/src/index.js +1 -3
- package/dist/node_modules/@agentorg/hub/dist/src/router.d.ts +6 -57
- package/dist/node_modules/@agentorg/hub/dist/src/router.js +38 -413
- package/dist/node_modules/@agentorg/hub/dist/src/state.d.ts +20 -298
- package/dist/node_modules/@agentorg/hub/dist/src/state.js +73 -456
- package/dist/node_modules/@agentorg/hub/dist/src/validate.d.ts +1 -3
- package/dist/node_modules/@agentorg/hub/dist/src/validate.js +3 -15
- package/dist/node_modules/@agentorg/hub/package.json +0 -3
- package/dist/node_modules/@agentorg/interfaces/dist/src/agent-provider.d.ts +132 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/agent-provider.js +105 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/agent-settings.d.ts +42 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/agent-settings.js +53 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/chat.d.ts +15 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/chat.js +14 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/hub.d.ts +16 -267
- package/dist/node_modules/@agentorg/interfaces/dist/src/hub.js +17 -145
- package/dist/node_modules/@agentorg/interfaces/dist/src/index.d.ts +6 -8
- package/dist/node_modules/@agentorg/interfaces/dist/src/index.js +6 -8
- package/dist/node_modules/@agentorg/interfaces/dist/src/kv.d.ts +2 -2
- package/dist/node_modules/@agentorg/interfaces/dist/src/kv.js +2 -2
- package/dist/node_modules/@agentorg/interfaces/dist/src/manager.d.ts +272 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/manager.js +185 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/mcp-provider.d.ts +88 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/mcp-provider.js +78 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/tools.d.ts +39 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/tools.js +43 -0
- package/dist/node_modules/@agentorg/manager/dist/src/index.d.ts +1 -0
- package/dist/node_modules/@agentorg/manager/dist/src/index.js +1 -0
- package/dist/node_modules/@agentorg/manager/dist/src/manager.d.ts +21 -0
- package/dist/node_modules/@agentorg/manager/dist/src/manager.js +528 -0
- package/dist/node_modules/@agentorg/manager/dist/src/skills.d.ts +25 -0
- package/dist/node_modules/@agentorg/manager/dist/src/skills.js +145 -0
- package/dist/node_modules/@agentorg/manager/package.json +30 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/connection.d.ts +33 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/connection.js +290 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/index.d.ts +1 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/index.js +1 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/kinds.d.ts +50 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/kinds.js +69 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/provider.d.ts +22 -0
- package/dist/node_modules/@agentorg/mcp/dist/src/provider.js +167 -0
- package/dist/node_modules/@agentorg/mcp/package.json +31 -0
- package/dist/node_modules/@agentorg/sdk/dist/src/cli.js +3 -23
- package/dist/node_modules/@agentorg/sdk/dist/src/client.d.ts +4 -25
- package/dist/node_modules/@agentorg/sdk/dist/src/client.js +5 -55
- package/dist/node_modules/@agentorg/sdk/dist/src/errors.d.ts +1 -1
- package/dist/node_modules/@agentorg/sdk/dist/src/errors.js +3 -3
- package/dist/node_modules/@agentorg/sdk/dist/src/index.d.ts +2 -2
- package/dist/node_modules/@agentorg/sdk/dist/src/index.js +1 -1
- package/dist/node_modules/@agentorg/sdk/dist/src/interface.d.ts +6 -34
- package/dist/node_modules/@agentorg/sdk/dist/src/interface.js +3 -24
- package/dist/node_modules/@agentorg/sdk/dist/src/module-host.d.ts +8 -17
- package/dist/node_modules/@agentorg/sdk/dist/src/module-host.js +15 -87
- package/dist/node_modules/@agentorg/sdk/dist/src/module.d.ts +10 -76
- package/dist/node_modules/@agentorg/sdk/dist/src/module.js +3 -23
- package/dist/node_modules/@agentorg/sdk/dist/src/person-commands.js +0 -5
- package/dist/node_modules/@agentorg/sdk/dist/src/runtime.d.ts +3 -27
- package/dist/node_modules/@agentorg/sdk/dist/src/runtime.js +5 -100
- package/dist/node_modules/@agentorg/sdk/dist/src/testing.d.ts +7 -8
- package/dist/node_modules/@agentorg/sdk/dist/src/testing.js +12 -24
- package/dist/node_modules/@agentorg/sdk/package.json +4 -37
- package/dist/node_modules/@agentorg/shell/dist/app.css +3435 -739
- package/dist/node_modules/@agentorg/shell/dist/app.js +204 -202
- package/dist/node_modules/@agentorg/shell/package.json +18 -10
- package/dist/node_modules/@agentorg/wire/dist/src/frames.d.ts +2 -3
- package/dist/node_modules/@agentorg/wire/dist/src/frames.js +2 -3
- package/dist/node_modules/@agentorg/wire/dist/src/ops.d.ts +5 -34
- package/dist/node_modules/@agentorg/wire/dist/src/ops.js +2 -17
- package/dist/node_modules/assistant/dist/src/agent.d.ts +62 -0
- package/dist/node_modules/assistant/dist/src/agent.js +226 -0
- package/dist/node_modules/assistant/dist/src/engine.d.ts +23 -0
- package/dist/node_modules/assistant/dist/src/engine.js +88 -0
- package/dist/node_modules/assistant/dist/src/history.d.ts +97 -0
- package/dist/node_modules/assistant/dist/src/history.js +235 -0
- package/dist/node_modules/assistant/dist/src/local-store.d.ts +3 -0
- package/dist/node_modules/assistant/dist/src/local-store.js +58 -0
- package/dist/node_modules/assistant/dist/src/provider.d.ts +21 -0
- package/dist/node_modules/assistant/dist/src/provider.js +231 -0
- package/dist/node_modules/assistant/dist/src/settings.d.ts +17 -0
- package/dist/node_modules/assistant/dist/src/settings.js +43 -0
- package/dist/node_modules/assistant/dist/src/tools.d.ts +74 -0
- package/dist/node_modules/assistant/dist/src/tools.js +123 -0
- package/dist/node_modules/assistant/package.json +29 -0
- package/dist/node_modules/chatgpt/dist/src/account.d.ts +52 -0
- package/dist/node_modules/chatgpt/dist/src/account.js +270 -0
- package/dist/node_modules/chatgpt/dist/src/encoding.d.ts +7 -0
- package/dist/node_modules/chatgpt/dist/src/encoding.js +20 -0
- package/dist/node_modules/chatgpt/dist/src/file-store.d.ts +9 -0
- package/dist/node_modules/chatgpt/dist/src/file-store.js +68 -0
- package/dist/node_modules/chatgpt/dist/src/index.d.ts +1 -0
- package/dist/node_modules/chatgpt/dist/src/index.js +1 -0
- package/dist/node_modules/chatgpt/dist/src/jwt.d.ts +15 -0
- package/dist/node_modules/chatgpt/dist/src/jwt.js +37 -0
- package/dist/node_modules/chatgpt/dist/src/oauth.d.ts +43 -0
- package/dist/node_modules/chatgpt/dist/src/oauth.js +104 -0
- package/dist/node_modules/chatgpt/dist/src/program.d.ts +23 -0
- package/dist/node_modules/chatgpt/dist/src/program.js +41 -0
- package/dist/node_modules/chatgpt/dist/src/responses.d.ts +54 -0
- package/dist/node_modules/chatgpt/dist/src/responses.js +300 -0
- package/dist/node_modules/chatgpt/dist/src/serve.d.ts +65 -0
- package/dist/node_modules/chatgpt/dist/src/serve.js +46 -0
- package/dist/node_modules/chatgpt/package.json +33 -0
- package/dist/src/api.d.ts +5 -34
- package/dist/src/api.js +6 -68
- package/dist/src/cli.js +3 -7
- package/dist/src/gateway.d.ts +6 -7
- package/dist/src/gateway.js +39 -285
- package/dist/src/index.d.ts +4 -5
- package/dist/src/index.js +3 -4
- package/dist/src/notes.d.ts +11 -0
- package/dist/src/notes.js +64 -0
- package/dist/src/oauth.d.ts +16 -0
- package/dist/src/oauth.js +46 -0
- package/dist/src/programs.d.ts +29 -0
- package/dist/src/programs.js +171 -0
- package/package.json +3 -11
- package/dist/bundled/index.json +0 -6
- package/dist/bundled/sha256-01d69bc3888c2a53963f4413d47de909d129ad27c78e9af6d830bb50c3478419.agentorg +0 -0
- package/dist/bundled/sha256-84165e3be5c904fc971d983dab31102e07cca725d8629a6fd7d118fa3a0a88b8.agentorg +0 -0
- package/dist/bundled/sha256-ade9132b3f34b4c39db92adeadc7e540dc745e4a81b5b54f5d45bf9ec92bca75.agentorg +0 -0
- package/dist/bundled/sha256-f4330f5987f37d8cf3aeb44d2f831b573641a87186daa2f811f0c35ba04804f0.agentorg +0 -0
- package/dist/node_modules/@agentorg/hub/dist/src/build.d.ts +0 -17
- package/dist/node_modules/@agentorg/hub/dist/src/build.js +0 -120
- package/dist/node_modules/@agentorg/hub/dist/src/logs.d.ts +0 -33
- package/dist/node_modules/@agentorg/hub/dist/src/logs.js +0 -162
- package/dist/node_modules/@agentorg/hub/dist/src/net.d.ts +0 -41
- package/dist/node_modules/@agentorg/hub/dist/src/net.js +0 -265
- package/dist/node_modules/@agentorg/hub/dist/src/processes.d.ts +0 -78
- package/dist/node_modules/@agentorg/hub/dist/src/processes.js +0 -485
- package/dist/node_modules/@agentorg/hub/dist/src/storage.d.ts +0 -38
- package/dist/node_modules/@agentorg/hub/dist/src/storage.js +0 -194
- package/dist/node_modules/@agentorg/interfaces/dist/src/http-egress.d.ts +0 -6
- package/dist/node_modules/@agentorg/interfaces/dist/src/http-egress.js +0 -7
- package/dist/node_modules/@agentorg/interfaces/dist/src/installer.d.ts +0 -191
- package/dist/node_modules/@agentorg/interfaces/dist/src/installer.js +0 -136
- package/dist/node_modules/@agentorg/interfaces/dist/src/layout.d.ts +0 -47
- package/dist/node_modules/@agentorg/interfaces/dist/src/layout.js +0 -52
- package/dist/node_modules/@agentorg/interfaces/dist/src/rules.d.ts +0 -35
- package/dist/node_modules/@agentorg/interfaces/dist/src/rules.js +0 -37
- package/dist/node_modules/@agentorg/interfaces/dist/src/storage-admin.d.ts +0 -23
- package/dist/node_modules/@agentorg/interfaces/dist/src/storage-admin.js +0 -31
- package/dist/node_modules/@agentorg/interfaces/dist/src/ui-shell.d.ts +0 -14
- package/dist/node_modules/@agentorg/interfaces/dist/src/ui-shell.js +0 -26
- package/dist/node_modules/@agentorg/interfaces/dist/src/ui-view.d.ts +0 -27
- package/dist/node_modules/@agentorg/interfaces/dist/src/ui-view.js +0 -26
- package/dist/node_modules/@agentorg/kit/dist/src/chat.d.ts +0 -37
- package/dist/node_modules/@agentorg/kit/dist/src/chat.js +0 -131
- package/dist/node_modules/@agentorg/kit/dist/src/components.d.ts +0 -94
- package/dist/node_modules/@agentorg/kit/dist/src/components.js +0 -66
- package/dist/node_modules/@agentorg/kit/dist/src/icons.d.ts +0 -17
- package/dist/node_modules/@agentorg/kit/dist/src/icons.js +0 -30
- package/dist/node_modules/@agentorg/kit/dist/src/index.d.ts +0 -6
- package/dist/node_modules/@agentorg/kit/dist/src/index.js +0 -10
- package/dist/node_modules/@agentorg/kit/dist/src/markdown.d.ts +0 -9
- package/dist/node_modules/@agentorg/kit/dist/src/markdown.js +0 -14
- package/dist/node_modules/@agentorg/kit/dist/src/resizable.d.ts +0 -5
- package/dist/node_modules/@agentorg/kit/dist/src/resizable.js +0 -8
- package/dist/node_modules/@agentorg/kit/dist/src/styles.d.ts +0 -11
- package/dist/node_modules/@agentorg/kit/dist/src/styles.js +0 -166
- package/dist/node_modules/@agentorg/kit/package.json +0 -44
- package/dist/node_modules/@agentorg/sdk/dist/frame/runtime.js +0 -753
- package/dist/node_modules/@agentorg/sdk/dist/host/runner.js +0 -21963
- package/dist/node_modules/@agentorg/sdk/dist/src/build.d.ts +0 -2
- package/dist/node_modules/@agentorg/sdk/dist/src/build.js +0 -2
- package/dist/node_modules/@agentorg/sdk/dist/src/client-http.d.ts +0 -24
- package/dist/node_modules/@agentorg/sdk/dist/src/client-http.js +0 -247
- package/dist/node_modules/@agentorg/sdk/dist/src/describe.d.ts +0 -13
- package/dist/node_modules/@agentorg/sdk/dist/src/describe.js +0 -16
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-base.d.ts +0 -8
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-base.js +0 -64
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-entry.d.ts +0 -1
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-entry.js +0 -35
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-host.d.ts +0 -57
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-host.js +0 -293
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-protocol.d.ts +0 -124
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-protocol.js +0 -16
- package/dist/node_modules/@agentorg/sdk/dist/src/frame.d.ts +0 -25
- package/dist/node_modules/@agentorg/sdk/dist/src/frame.js +0 -248
- package/dist/node_modules/@agentorg/sdk/dist/src/host-main.d.ts +0 -1
- package/dist/node_modules/@agentorg/sdk/dist/src/host-main.js +0 -60
- package/dist/node_modules/@agentorg/sdk/dist/src/host.d.ts +0 -25
- package/dist/node_modules/@agentorg/sdk/dist/src/host.js +0 -92
- package/dist/node_modules/@agentorg/sdk/dist/src/manifest-api.d.ts +0 -2
- package/dist/node_modules/@agentorg/sdk/dist/src/manifest-api.js +0 -2
- package/dist/node_modules/@agentorg/sdk/dist/src/manifest.d.ts +0 -56
- package/dist/node_modules/@agentorg/sdk/dist/src/manifest.js +0 -165
- package/dist/node_modules/@agentorg/sdk/dist/src/package.d.ts +0 -60
- package/dist/node_modules/@agentorg/sdk/dist/src/package.js +0 -538
- package/dist/node_modules/@agentorg/sdk/dist/src/tar.d.ts +0 -7
- package/dist/node_modules/@agentorg/sdk/dist/src/tar.js +0 -71
- package/dist/node_modules/@agentorg/shell/dist/agent-bindings.js +0 -59
- package/dist/node_modules/@agentorg/shell/src/agent-bindings.ts +0 -107
- package/dist/src/frames.d.ts +0 -23
- package/dist/src/frames.js +0 -78
- package/dist/src/layout.d.ts +0 -44
- package/dist/src/layout.js +0 -90
- package/dist/src/model.d.ts +0 -51
- package/dist/src/model.js +0 -230
- package/dist/src/rules.d.ts +0 -71
- package/dist/src/rules.js +0 -157
- package/dist/src/transfer.d.ts +0 -30
- package/dist/src/transfer.js +0 -110
|
@@ -1,248 +0,0 @@
|
|
|
1
|
-
import { errorBodyOf, errorFromBody, OutcomeUnknown, Refused } from "./errors.js";
|
|
2
|
-
import { isShellInterface } from "./frame-protocol.js";
|
|
3
|
-
import { isFrameInterface, isModuleDefinition, } from "./module.js";
|
|
4
|
-
import { createRuntime } from "./runtime.js";
|
|
5
|
-
/**
|
|
6
|
-
* Run a view module in a frame, on the same runtime as a host module, so a view behaves as it does
|
|
7
|
-
* in tests. Every slot of `ui.shell@1` is served by the shell and always bound; every other slot is
|
|
8
|
-
* served over the port while the shell says it is bound. The shell drives `ui.view@1`: `mount`,
|
|
9
|
-
* `resize` and `unmount` reach the view's handle. Only `ui.view@1` is served among its exports.
|
|
10
|
-
*/
|
|
11
|
-
export function runFrame(options) {
|
|
12
|
-
const { port } = options;
|
|
13
|
-
const send = (message) => port.postMessage(message);
|
|
14
|
-
let nextId = 0;
|
|
15
|
-
const pending = new Map();
|
|
16
|
-
const request = (message, target) => new Promise((resolve, reject) => {
|
|
17
|
-
const id = ++nextId;
|
|
18
|
-
pending.set(id, { resolve, reject, target });
|
|
19
|
-
send({ ...message, id });
|
|
20
|
-
});
|
|
21
|
-
/** The view's runtime, once its start has finished. */
|
|
22
|
-
let runtime;
|
|
23
|
-
let definition;
|
|
24
|
-
let loading = false;
|
|
25
|
-
let mounted;
|
|
26
|
-
const bindings = new Map();
|
|
27
|
-
/**
|
|
28
|
-
* Until the view has started, which slots are bound: from load's snapshot, then from any notice
|
|
29
|
-
* meanwhile, while its bundle imports and while start runs.
|
|
30
|
-
*/
|
|
31
|
-
let early = new Map();
|
|
32
|
-
/** Slot events the view listens to, each with its live subscription's id, if any. */
|
|
33
|
-
const listened = new Map();
|
|
34
|
-
const subscriptions = new Map();
|
|
35
|
-
const log = {
|
|
36
|
-
info: (message, fields) => send({ op: "log", level: "info", message, ...(fields ? { fields } : {}) }),
|
|
37
|
-
warn: (message, fields) => send({ op: "log", level: "warn", message, ...(fields ? { fields } : {}) }),
|
|
38
|
-
error: (message, fields) => send({ op: "log", level: "error", message, ...(fields ? { fields } : {}) }),
|
|
39
|
-
};
|
|
40
|
-
const subscribe = (slot, event) => {
|
|
41
|
-
const events = listened.get(slot) ?? new Map();
|
|
42
|
-
listened.set(slot, events);
|
|
43
|
-
if (!events.has(event))
|
|
44
|
-
events.set(event, undefined);
|
|
45
|
-
if (!bindings.has(slot) || events.get(event) !== undefined)
|
|
46
|
-
return;
|
|
47
|
-
const sub = ++nextId;
|
|
48
|
-
subscriptions.set(sub, { slot, event });
|
|
49
|
-
events.set(event, sub);
|
|
50
|
-
send({ op: "subscribe", sub, slot, event });
|
|
51
|
-
};
|
|
52
|
-
/** Stop a slot's live subscriptions; the interest stays for when it is usable again. */
|
|
53
|
-
const stopAll = (slot, tell) => {
|
|
54
|
-
const events = listened.get(slot);
|
|
55
|
-
for (const [event, sub] of events ?? []) {
|
|
56
|
-
if (sub === undefined)
|
|
57
|
-
continue;
|
|
58
|
-
subscriptions.delete(sub);
|
|
59
|
-
events?.set(event, undefined);
|
|
60
|
-
if (tell)
|
|
61
|
-
send({ op: "unsubscribe", sub });
|
|
62
|
-
}
|
|
63
|
-
};
|
|
64
|
-
const resubscribe = (slot) => {
|
|
65
|
-
stopAll(slot, true);
|
|
66
|
-
for (const event of listened.get(slot)?.keys() ?? [])
|
|
67
|
-
subscribe(slot, event);
|
|
68
|
-
};
|
|
69
|
-
const bind = (slot) => {
|
|
70
|
-
if (!runtime)
|
|
71
|
-
return;
|
|
72
|
-
bindings.set(slot, runtime.bind(slot, {
|
|
73
|
-
call: (method, input) => request({ op: "call", slot, method, input }, slot),
|
|
74
|
-
open: async () => {
|
|
75
|
-
throw new Refused("unimplemented", `${slot}: a view's stream slots aren't served yet.`);
|
|
76
|
-
},
|
|
77
|
-
fetch: async () => {
|
|
78
|
-
throw new Refused("unimplemented", `${slot}: a view's http slots aren't served yet.`);
|
|
79
|
-
},
|
|
80
|
-
}));
|
|
81
|
-
resubscribe(slot);
|
|
82
|
-
};
|
|
83
|
-
const onSlot = (slot, bound) => {
|
|
84
|
-
if (early)
|
|
85
|
-
return void early.set(slot, bound);
|
|
86
|
-
const iface = definition && Object.hasOwn(definition.slots, slot) ? definition.slots[slot] : undefined;
|
|
87
|
-
// ui.shell@1 is the shell's, always bound; the shell never names it.
|
|
88
|
-
if (!runtime || !iface || isShellInterface(iface))
|
|
89
|
-
return;
|
|
90
|
-
if (!bound) {
|
|
91
|
-
bindings.delete(slot);
|
|
92
|
-
stopAll(slot, true);
|
|
93
|
-
return runtime.unbind(slot);
|
|
94
|
-
}
|
|
95
|
-
if (bindings.has(slot)) {
|
|
96
|
-
// Its provider came back: what was missed is read again in onBind, and events resume.
|
|
97
|
-
resubscribe(slot);
|
|
98
|
-
return runtime.usable(slot);
|
|
99
|
-
}
|
|
100
|
-
bind(slot);
|
|
101
|
-
};
|
|
102
|
-
const viewExport = () => {
|
|
103
|
-
for (const [name, iface] of Object.entries(definition?.exports ?? {}))
|
|
104
|
-
if (isFrameInterface(iface))
|
|
105
|
-
return name;
|
|
106
|
-
throw new Refused("unimplemented", "This module exports no ui.view@1.");
|
|
107
|
-
};
|
|
108
|
-
const answer = async (id, run) => {
|
|
109
|
-
try {
|
|
110
|
-
send({ op: "reply", id, result: (await run()) ?? {} });
|
|
111
|
-
}
|
|
112
|
-
catch (error) {
|
|
113
|
-
send({ op: "reply", id, error: errorBodyOf(error) });
|
|
114
|
-
}
|
|
115
|
-
};
|
|
116
|
-
const handle = (message) => {
|
|
117
|
-
switch (message.op) {
|
|
118
|
-
case "load":
|
|
119
|
-
return answer(message.id, async () => {
|
|
120
|
-
if (runtime || loading)
|
|
121
|
-
throw new Refused("state", "This frame has loaded a view already.");
|
|
122
|
-
loading = true;
|
|
123
|
-
for (const [slot, isBound] of Object.entries(message.slots))
|
|
124
|
-
early?.set(slot, isBound);
|
|
125
|
-
try {
|
|
126
|
-
const loaded = (await options.load(message.src));
|
|
127
|
-
const found = loaded?.default;
|
|
128
|
-
if (!isModuleDefinition(found) || found.placement !== "view")
|
|
129
|
-
throw new Refused("invalid", `${message.src} isn't a view module.`);
|
|
130
|
-
definition = found;
|
|
131
|
-
const created = createRuntime(found, {
|
|
132
|
-
self: message.self,
|
|
133
|
-
log,
|
|
134
|
-
// A view serves only ui.view@1, which the shell drives directly; nothing reaches its
|
|
135
|
-
// other exports, so their events go nowhere.
|
|
136
|
-
onEmit: () => { },
|
|
137
|
-
onListen: subscribe,
|
|
138
|
-
});
|
|
139
|
-
// As in a host module: start implements and registers handlers, then slots bind, so
|
|
140
|
-
// each bound slot's onBind runs once it is usable.
|
|
141
|
-
await created.start();
|
|
142
|
-
runtime = created;
|
|
143
|
-
for (const [slot, iface] of Object.entries(found.slots))
|
|
144
|
-
if (isShellInterface(iface))
|
|
145
|
-
bindings.set(slot, created.bind(slot, {
|
|
146
|
-
call: (method, input) => request({ op: "shell", method, input }, slot),
|
|
147
|
-
}));
|
|
148
|
-
const bound = early;
|
|
149
|
-
early = undefined;
|
|
150
|
-
for (const [slot, isBound] of bound ?? [])
|
|
151
|
-
if (isBound)
|
|
152
|
-
onSlot(slot, true);
|
|
153
|
-
}
|
|
154
|
-
catch (error) {
|
|
155
|
-
// Nothing is half-loaded: the frame can be asked to load again.
|
|
156
|
-
definition = undefined;
|
|
157
|
-
early = new Map();
|
|
158
|
-
throw error;
|
|
159
|
-
}
|
|
160
|
-
finally {
|
|
161
|
-
loading = false;
|
|
162
|
-
}
|
|
163
|
-
});
|
|
164
|
-
case "slot":
|
|
165
|
-
return onSlot(message.name, message.bound);
|
|
166
|
-
case "mount":
|
|
167
|
-
return answer(message.id, () => {
|
|
168
|
-
if (!runtime)
|
|
169
|
-
throw new Refused("state", "Nothing is loaded to mount.");
|
|
170
|
-
if (mounted)
|
|
171
|
-
throw new Refused("state", "The view is mounted already.");
|
|
172
|
-
options.theme?.(message.theme);
|
|
173
|
-
mounted = runtime.mount(viewExport(), options.root, {
|
|
174
|
-
theme: message.theme,
|
|
175
|
-
size: message.size,
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
case "resize":
|
|
179
|
-
return answer(message.id, () => {
|
|
180
|
-
if (!mounted)
|
|
181
|
-
throw new Refused("state", "The view isn't mounted.");
|
|
182
|
-
mounted.resize(message.size);
|
|
183
|
-
});
|
|
184
|
-
case "unmount":
|
|
185
|
-
return answer(message.id, () => {
|
|
186
|
-
const view = mounted;
|
|
187
|
-
mounted = undefined;
|
|
188
|
-
view?.unmount();
|
|
189
|
-
});
|
|
190
|
-
case "event": {
|
|
191
|
-
const subscription = subscriptions.get(message.sub);
|
|
192
|
-
if (!subscription)
|
|
193
|
-
return;
|
|
194
|
-
try {
|
|
195
|
-
bindings.get(subscription.slot)?.emit(subscription.event, message.payload);
|
|
196
|
-
}
|
|
197
|
-
catch (error) {
|
|
198
|
-
log.warn("An event didn't fit its schema.", { ...subscription, error: String(error) });
|
|
199
|
-
}
|
|
200
|
-
return;
|
|
201
|
-
}
|
|
202
|
-
case "end": {
|
|
203
|
-
// Ended by an unbind or the provider going: the interest stays for when it is usable again.
|
|
204
|
-
const subscription = subscriptions.get(message.sub);
|
|
205
|
-
if (!subscription)
|
|
206
|
-
return;
|
|
207
|
-
subscriptions.delete(message.sub);
|
|
208
|
-
const events = listened.get(subscription.slot);
|
|
209
|
-
if (events?.get(subscription.event) === message.sub)
|
|
210
|
-
events.set(subscription.event, undefined);
|
|
211
|
-
return;
|
|
212
|
-
}
|
|
213
|
-
case "reply": {
|
|
214
|
-
const waiting = pending.get(message.id);
|
|
215
|
-
if (!waiting)
|
|
216
|
-
return;
|
|
217
|
-
pending.delete(message.id);
|
|
218
|
-
if ("error" in message)
|
|
219
|
-
waiting.reject(errorFromBody(message.error, waiting.target));
|
|
220
|
-
else
|
|
221
|
-
waiting.resolve(message.result);
|
|
222
|
-
return;
|
|
223
|
-
}
|
|
224
|
-
}
|
|
225
|
-
};
|
|
226
|
-
port.onmessage = (event) => {
|
|
227
|
-
try {
|
|
228
|
-
void handle(event.data);
|
|
229
|
-
}
|
|
230
|
-
catch (error) {
|
|
231
|
-
log.error("The frame couldn't handle a message from the shell.", { error: String(error) });
|
|
232
|
-
}
|
|
233
|
-
};
|
|
234
|
-
return {
|
|
235
|
-
failed(error) {
|
|
236
|
-
log.error(error instanceof Error ? error.message : String(error), {
|
|
237
|
-
...(error instanceof Error && error.stack ? { stack: error.stack } : {}),
|
|
238
|
-
});
|
|
239
|
-
},
|
|
240
|
-
close() {
|
|
241
|
-
port.onmessage = null;
|
|
242
|
-
for (const [, waiting] of pending)
|
|
243
|
-
waiting.reject(new OutcomeUnknown("The frame closed."));
|
|
244
|
-
pending.clear();
|
|
245
|
-
port.close();
|
|
246
|
-
},
|
|
247
|
-
};
|
|
248
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
// The program the Hub spawns for a package Actor: `runner.js <package dir> <actorId>`, with its
|
|
2
|
-
// channel to the Hub on fd 3. It is bundled into one file, so the process needs to read only
|
|
3
|
-
// that file and the package's folder.
|
|
4
|
-
import { Socket } from "node:net";
|
|
5
|
-
import { Duplex as NodeDuplex } from "node:stream";
|
|
6
|
-
import { runHost } from "./host.js";
|
|
7
|
-
const [packageDir, actorId] = process.argv.slice(2);
|
|
8
|
-
if (!packageDir || !actorId) {
|
|
9
|
-
process.stderr.write("Usage: runner.js <package dir> <actorId>\n");
|
|
10
|
-
process.exit(2);
|
|
11
|
-
}
|
|
12
|
-
/** Anything as text, even what can't say itself (no prototype, a throwing `toString`). */
|
|
13
|
-
const text = (value) => {
|
|
14
|
-
try {
|
|
15
|
-
return String(value);
|
|
16
|
-
}
|
|
17
|
-
catch {
|
|
18
|
-
return "[unprintable]";
|
|
19
|
-
}
|
|
20
|
-
};
|
|
21
|
-
/** What JSON can't hold, as text: an error by its name and message, a bigint by its digits. */
|
|
22
|
-
const plain = (_key, value) => value instanceof Error
|
|
23
|
-
? `${text(value.name)}: ${text(value.message)}`
|
|
24
|
-
: typeof value === "bigint"
|
|
25
|
-
? String(value)
|
|
26
|
-
: value;
|
|
27
|
-
/**
|
|
28
|
-
* One JSON line per log call, on stderr, which the Hub keeps as the Actor's log: a module's
|
|
29
|
-
* `ctx.log`, or the runner's own (no module). Logging never throws: data JSON can't hold (a cycle)
|
|
30
|
-
* is written as text.
|
|
31
|
-
*/
|
|
32
|
-
const logFor = (module) => {
|
|
33
|
-
const line = (level) => (message, data) => {
|
|
34
|
-
const entry = (fields) => JSON.stringify({
|
|
35
|
-
level,
|
|
36
|
-
message: text(message),
|
|
37
|
-
...(fields === undefined ? {} : { data: fields }),
|
|
38
|
-
...(module === undefined ? {} : { module }),
|
|
39
|
-
at: new Date().toISOString(),
|
|
40
|
-
}, plain);
|
|
41
|
-
let written;
|
|
42
|
-
try {
|
|
43
|
-
written = entry(data);
|
|
44
|
-
}
|
|
45
|
-
catch {
|
|
46
|
-
written = entry(text(data));
|
|
47
|
-
}
|
|
48
|
-
process.stderr.write(`${written}\n`);
|
|
49
|
-
};
|
|
50
|
-
return { info: line("info"), warn: line("warn"), error: line("error") };
|
|
51
|
-
};
|
|
52
|
-
// The Hub's stop. Handled, it reaches the process even as PID 1 of a PID namespace, where an
|
|
53
|
-
// unhandled SIGTERM from outside is ignored.
|
|
54
|
-
process.on("SIGTERM", () => process.exit(0));
|
|
55
|
-
const pipe = new Socket({ fd: 3, readable: true, writable: true });
|
|
56
|
-
const channel = NodeDuplex.toWeb(pipe);
|
|
57
|
-
const host = await runHost({ packageDir, actorId, channel, log: logFor });
|
|
58
|
-
// The Hub going away ends the process: there is nothing left to serve.
|
|
59
|
-
await host.channel.closed;
|
|
60
|
-
process.exit(0);
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import { type Channel } from "./client.js";
|
|
2
|
-
import { type Duplex, type Log } from "./module.js";
|
|
3
|
-
export interface RunHostOptions {
|
|
4
|
-
/** The package's folder: `agentorg.json` and `dist/<module>.js`. */
|
|
5
|
-
packageDir: string;
|
|
6
|
-
/** The Actor this process runs, as the Hub named it. */
|
|
7
|
-
actorId: string;
|
|
8
|
-
/** The pipe to the Hub. */
|
|
9
|
-
channel: Duplex;
|
|
10
|
-
/** Where each module's `ctx.log` lines go, and (with no module) the runner's own. */
|
|
11
|
-
log(module?: string): Log;
|
|
12
|
-
}
|
|
13
|
-
export interface Host {
|
|
14
|
-
readonly channel: Channel;
|
|
15
|
-
/** The host modules running, by name. */
|
|
16
|
-
readonly modules: readonly string[];
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Run a package Actor's host modules over the pipe the Hub made for its process. Each module gets
|
|
20
|
-
* its own runtime, the same one `connect()` and the test context use, with its slots and exports
|
|
21
|
-
* named `<module>.<name>` on the wire. Every module's `start` runs before the hello, so the Hub
|
|
22
|
-
* never reaches an export before it is implemented; then slots are bound as the Hub says, and each
|
|
23
|
-
* `serve` stream goes to the module its export names. A `start` that throws is thrown from here.
|
|
24
|
-
*/
|
|
25
|
-
export declare function runHost(options: RunHostOptions): Promise<Host>;
|
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
2
|
-
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
3
|
-
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
4
|
-
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
5
|
-
});
|
|
6
|
-
}
|
|
7
|
-
return path;
|
|
8
|
-
};
|
|
9
|
-
import { readFile } from "node:fs/promises";
|
|
10
|
-
import { join } from "node:path";
|
|
11
|
-
import { pathToFileURL } from "node:url";
|
|
12
|
-
import { openChannel } from "./client.js";
|
|
13
|
-
import { isModuleDefinition } from "./module.js";
|
|
14
|
-
import { localServe, ModuleHost, noModule } from "./module-host.js";
|
|
15
|
-
import { createRuntime } from "./runtime.js";
|
|
16
|
-
/**
|
|
17
|
-
* Run a package Actor's host modules over the pipe the Hub made for its process. Each module gets
|
|
18
|
-
* its own runtime, the same one `connect()` and the test context use, with its slots and exports
|
|
19
|
-
* named `<module>.<name>` on the wire. Every module's `start` runs before the hello, so the Hub
|
|
20
|
-
* never reaches an export before it is implemented; then slots are bound as the Hub says, and each
|
|
21
|
-
* `serve` stream goes to the module its export names. A `start` that throws is thrown from here.
|
|
22
|
-
*/
|
|
23
|
-
export async function runHost(options) {
|
|
24
|
-
const manifest = JSON.parse(await readFile(join(options.packageDir, "agentorg.json"), "utf8"));
|
|
25
|
-
const hosts = new Map();
|
|
26
|
-
for (const [name, module] of Object.entries(manifest.modules)) {
|
|
27
|
-
if (module.placement !== "host")
|
|
28
|
-
continue;
|
|
29
|
-
const loaded = (await import(__rewriteRelativeImportExtension(pathToFileURL(join(options.packageDir, "dist", `${name}.js`)).href)));
|
|
30
|
-
const definition = loaded.default;
|
|
31
|
-
if (!isModuleDefinition(definition))
|
|
32
|
-
throw new Error(`dist/${name}.js doesn't export a module definition.`);
|
|
33
|
-
const log = options.log(name);
|
|
34
|
-
const host = new ModuleHost(`${name}.`, definition.slots, log);
|
|
35
|
-
host.runtime = createRuntime(definition, {
|
|
36
|
-
self: { actorId: options.actorId, module: name },
|
|
37
|
-
log,
|
|
38
|
-
...host.hooks(),
|
|
39
|
-
});
|
|
40
|
-
hosts.set(name, host);
|
|
41
|
-
}
|
|
42
|
-
// Every module's start, in the manifest's order, before the Hub can reach any of them.
|
|
43
|
-
for (const host of hosts.values())
|
|
44
|
-
await host.runtime.start();
|
|
45
|
-
/** The module a wire name belongs to, and the name within it. */
|
|
46
|
-
const route = (name) => {
|
|
47
|
-
const dot = name.indexOf(".");
|
|
48
|
-
const host = dot > 0 ? hosts.get(name.slice(0, dot)) : undefined;
|
|
49
|
-
return host && [host, name.slice(dot + 1)];
|
|
50
|
-
};
|
|
51
|
-
const routed = (serve) => {
|
|
52
|
-
const found = route(serve.export);
|
|
53
|
-
if (!found)
|
|
54
|
-
throw noModule(serve.export);
|
|
55
|
-
return [found[0].serve, localServe(serve, found[1])];
|
|
56
|
-
};
|
|
57
|
-
const channel = await openChannel({
|
|
58
|
-
channel: options.channel,
|
|
59
|
-
actorId: options.actorId,
|
|
60
|
-
log: options.log(),
|
|
61
|
-
onSlot(name, bound) {
|
|
62
|
-
const found = route(name);
|
|
63
|
-
found?.[0].onSlot(found[1], bound);
|
|
64
|
-
},
|
|
65
|
-
// A slot made at run time is the Actor's: every host module has it.
|
|
66
|
-
onExposed(name, exposure) {
|
|
67
|
-
for (const host of hosts.values())
|
|
68
|
-
host.onExposed(name, exposure);
|
|
69
|
-
},
|
|
70
|
-
serve: {
|
|
71
|
-
call: (serve, value) => {
|
|
72
|
-
const [handlers, local] = routed(serve);
|
|
73
|
-
return handlers.call(local, value);
|
|
74
|
-
},
|
|
75
|
-
subscribe: (serve, send, end) => {
|
|
76
|
-
const [handlers, local] = routed(serve);
|
|
77
|
-
return handlers.subscribe(local, send, end);
|
|
78
|
-
},
|
|
79
|
-
accept: (serve) => {
|
|
80
|
-
const [handlers, local] = routed(serve);
|
|
81
|
-
return handlers.accept(local);
|
|
82
|
-
},
|
|
83
|
-
serveHttp: (serve) => {
|
|
84
|
-
const [handlers, local] = routed(serve);
|
|
85
|
-
return handlers.serveHttp(local);
|
|
86
|
-
},
|
|
87
|
-
},
|
|
88
|
-
});
|
|
89
|
-
for (const host of hosts.values())
|
|
90
|
-
host.attach(channel);
|
|
91
|
-
return { channel, modules: [...hosts.keys()] };
|
|
92
|
-
}
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
import { type DescribedInterface } from "./interface.js";
|
|
2
|
-
import type { Placement } from "./module.js";
|
|
3
|
-
export declare const FORMAT = "agentorg.package/1";
|
|
4
|
-
/** An interface as `agentorg.json` records it, keyed by its `name@major`. */
|
|
5
|
-
export type ManifestInterface = DescribedInterface extends infer D ? D extends unknown ? Omit<D, "id"> : never : never;
|
|
6
|
-
export interface ManifestModule {
|
|
7
|
-
placement: Placement;
|
|
8
|
-
entry: string;
|
|
9
|
-
slots: Record<string, string>;
|
|
10
|
-
exports: Record<string, string>;
|
|
11
|
-
}
|
|
12
|
-
/** `agentorg.json`, generated from the package's code. */
|
|
13
|
-
export interface Manifest {
|
|
14
|
-
format: typeof FORMAT;
|
|
15
|
-
name: string;
|
|
16
|
-
version: string;
|
|
17
|
-
description?: string;
|
|
18
|
-
modules: Record<string, ManifestModule>;
|
|
19
|
-
interfaces: Record<string, ManifestInterface>;
|
|
20
|
-
/** The package's own wiring: `[ "module.slot", "module.export" ]`. Other slots are the installer's. */
|
|
21
|
-
connections: [string, string][];
|
|
22
|
-
/**
|
|
23
|
-
* Optional initial state for state slots, keyed by `"module.slot"`: the only runtime state a
|
|
24
|
-
* package may carry. `null` when there is none.
|
|
25
|
-
*/
|
|
26
|
-
seed: Record<string, unknown> | null;
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* The reserved name of a package's signature. It is detached: a file beside the package that signs
|
|
30
|
-
* the package hash, so it can never be inside what it signs.
|
|
31
|
-
*/
|
|
32
|
-
export declare const SIGNATURE = "agentorg.sig";
|
|
33
|
-
/** The canonical tree hash: SHA-256 over the sorted `[path, sha256(bytes)]` of every file. */
|
|
34
|
-
export declare function treeHash(files: Map<string, Uint8Array>): string;
|
|
35
|
-
/**
|
|
36
|
-
* Everything wrong with a manifest, empty when it's sound: its shape, each module's entry and
|
|
37
|
-
* interfaces, every interface's recorded hash against its schemas, and the package's connections,
|
|
38
|
-
* each a slot joined to an export of the same interface, every slot at most once.
|
|
39
|
-
*/
|
|
40
|
-
export declare function checkManifest(value: unknown): string[];
|
|
41
|
-
export type Verified = {
|
|
42
|
-
ok: true;
|
|
43
|
-
hash: string;
|
|
44
|
-
manifest: Manifest;
|
|
45
|
-
files: Map<string, Uint8Array>;
|
|
46
|
-
} | {
|
|
47
|
-
ok: false;
|
|
48
|
-
hash?: string;
|
|
49
|
-
problems: string[];
|
|
50
|
-
};
|
|
51
|
-
/**
|
|
52
|
-
* Check a `.agentorg` archive's bytes: it reads as a package (exactly `agentorg.json` and each
|
|
53
|
-
* module's entry), hashes to the expected hash, and its manifest is sound. Problems are returned,
|
|
54
|
-
* never thrown, so a Hub can report them as they are.
|
|
55
|
-
*/
|
|
56
|
-
export declare function verifyArchive(bytes: Uint8Array, expected: string): Verified;
|
|
@@ -1,165 +0,0 @@
|
|
|
1
|
-
import { hashOf, sha256 } from "./canonical.js";
|
|
2
|
-
import { hashInterface } from "./interface.js";
|
|
3
|
-
import { readTar } from "./tar.js";
|
|
4
|
-
export const FORMAT = "agentorg.package/1";
|
|
5
|
-
/**
|
|
6
|
-
* The reserved name of a package's signature. It is detached: a file beside the package that signs
|
|
7
|
-
* the package hash, so it can never be inside what it signs.
|
|
8
|
-
*/
|
|
9
|
-
export const SIGNATURE = "agentorg.sig";
|
|
10
|
-
const NAME = /^[a-z][A-Za-z0-9_]*$/;
|
|
11
|
-
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12
|
-
const own = (record, key) => Object.hasOwn(record, key) ? record[key] : undefined;
|
|
13
|
-
/** The canonical tree hash: SHA-256 over the sorted `[path, sha256(bytes)]` of every file. */
|
|
14
|
-
export function treeHash(files) {
|
|
15
|
-
return hashOf([...files.keys()].sort().map((path) => [path, sha256(files.get(path))]));
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Everything wrong with a manifest, empty when it's sound: its shape, each module's entry and
|
|
19
|
-
* interfaces, every interface's recorded hash against its schemas, and the package's connections,
|
|
20
|
-
* each a slot joined to an export of the same interface, every slot at most once.
|
|
21
|
-
*/
|
|
22
|
-
export function checkManifest(value) {
|
|
23
|
-
if (!isRecord(value))
|
|
24
|
-
return ["The manifest isn't a JSON object."];
|
|
25
|
-
const problems = [];
|
|
26
|
-
if (value.format !== FORMAT)
|
|
27
|
-
problems.push(`Unknown format ${JSON.stringify(value.format)}.`);
|
|
28
|
-
for (const field of ["name", "version"])
|
|
29
|
-
if (typeof value[field] !== "string" || !value[field])
|
|
30
|
-
problems.push(`The manifest needs a ${field}.`);
|
|
31
|
-
if ("signature" in value)
|
|
32
|
-
problems.push(`A signature is detached, in ${SIGNATURE} beside the package, not in the manifest.`);
|
|
33
|
-
const interfaces = isRecord(value.interfaces) ? value.interfaces : {};
|
|
34
|
-
if (!isRecord(value.interfaces))
|
|
35
|
-
problems.push("interfaces must be an object.");
|
|
36
|
-
for (const [id, entry] of Object.entries(interfaces)) {
|
|
37
|
-
if (!isRecord(entry) || typeof entry.hash !== "string") {
|
|
38
|
-
problems.push(`${id} has no recorded hash.`);
|
|
39
|
-
continue;
|
|
40
|
-
}
|
|
41
|
-
const { hash, ...schemas } = entry;
|
|
42
|
-
let recomputed;
|
|
43
|
-
try {
|
|
44
|
-
recomputed = hashInterface({ id, ...schemas });
|
|
45
|
-
}
|
|
46
|
-
catch {
|
|
47
|
-
recomputed = undefined;
|
|
48
|
-
}
|
|
49
|
-
if (recomputed !== hash)
|
|
50
|
-
problems.push(`${id}'s recorded hash doesn't match its schemas.`);
|
|
51
|
-
}
|
|
52
|
-
const modules = isRecord(value.modules) ? value.modules : {};
|
|
53
|
-
if (!isRecord(value.modules) || !Object.keys(modules).length)
|
|
54
|
-
problems.push("The manifest needs at least one module.");
|
|
55
|
-
const ids = {};
|
|
56
|
-
for (const [name, module] of Object.entries(modules)) {
|
|
57
|
-
if (!NAME.test(name))
|
|
58
|
-
problems.push(`${JSON.stringify(name)} isn't a valid module name.`);
|
|
59
|
-
if (!isRecord(module)) {
|
|
60
|
-
problems.push(`Module ${name} isn't an object.`);
|
|
61
|
-
continue;
|
|
62
|
-
}
|
|
63
|
-
if (module.placement !== "host" && module.placement !== "view")
|
|
64
|
-
problems.push(`Module ${name} has no placement of host or view.`);
|
|
65
|
-
if (module.entry !== `dist/${name}.js`)
|
|
66
|
-
problems.push(`Module ${name}'s entry must be dist/${name}.js.`);
|
|
67
|
-
for (const side of ["slots", "exports"]) {
|
|
68
|
-
const members = module[side];
|
|
69
|
-
if (!isRecord(members)) {
|
|
70
|
-
problems.push(`Module ${name} needs ${side}.`);
|
|
71
|
-
continue;
|
|
72
|
-
}
|
|
73
|
-
for (const [member, id] of Object.entries(members)) {
|
|
74
|
-
if (!NAME.test(member))
|
|
75
|
-
problems.push(`${name}.${member} isn't a valid name.`);
|
|
76
|
-
if (typeof id !== "string" || !own(interfaces, id))
|
|
77
|
-
problems.push(`${name}.${member} uses ${JSON.stringify(id)}, which isn't recorded.`);
|
|
78
|
-
else {
|
|
79
|
-
const recorded = ids[`${side}:${name}`] ?? {};
|
|
80
|
-
recorded[member] = id;
|
|
81
|
-
ids[`${side}:${name}`] = recorded;
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
if (!Array.isArray(value.connections))
|
|
87
|
-
problems.push("connections must be a list.");
|
|
88
|
-
const wired = new Set();
|
|
89
|
-
for (const connection of Array.isArray(value.connections) ? value.connections : []) {
|
|
90
|
-
const label = JSON.stringify(connection);
|
|
91
|
-
if (!Array.isArray(connection) ||
|
|
92
|
-
connection.length !== 2 ||
|
|
93
|
-
!connection.every((end) => typeof end === "string")) {
|
|
94
|
-
problems.push(`Connection ${label} must be ["module.slot", "module.export"].`);
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
const [from, to] = connection;
|
|
98
|
-
const end = (path, side) => {
|
|
99
|
-
const parts = path.split(".");
|
|
100
|
-
const id = parts.length === 2 ? own(ids[`${side}:${parts[0]}`] ?? {}, parts[1]) : undefined;
|
|
101
|
-
if (typeof id !== "string")
|
|
102
|
-
problems.push(`Connection ${label}: ${JSON.stringify(path)} isn't a${side === "slots" ? " slot" : "n export"} of a module here, as "module.${side === "slots" ? "slot" : "export"}".`);
|
|
103
|
-
return id;
|
|
104
|
-
};
|
|
105
|
-
const slot = end(from, "slots");
|
|
106
|
-
const exported = end(to, "exports");
|
|
107
|
-
if (slot && exported && slot !== exported)
|
|
108
|
-
problems.push(`Connection ${label} joins ${slot} to ${exported}.`);
|
|
109
|
-
if (wired.has(from))
|
|
110
|
-
problems.push(`${from} is connected twice.`);
|
|
111
|
-
wired.add(from);
|
|
112
|
-
}
|
|
113
|
-
if (value.seed !== null && !isRecord(value.seed))
|
|
114
|
-
problems.push(`seed must be null or an object keyed by "module.slot".`);
|
|
115
|
-
for (const key of isRecord(value.seed) ? Object.keys(value.seed) : []) {
|
|
116
|
-
const parts = key.split(".");
|
|
117
|
-
if (parts.length !== 2 ||
|
|
118
|
-
typeof own(ids[`slots:${parts[0]}`] ?? {}, parts[1]) !== "string")
|
|
119
|
-
problems.push(`seed ${JSON.stringify(key)} isn't a slot of a module here, as "module.slot".`);
|
|
120
|
-
}
|
|
121
|
-
return problems;
|
|
122
|
-
}
|
|
123
|
-
/**
|
|
124
|
-
* Check a `.agentorg` archive's bytes: it reads as a package (exactly `agentorg.json` and each
|
|
125
|
-
* module's entry), hashes to the expected hash, and its manifest is sound. Problems are returned,
|
|
126
|
-
* never thrown, so a Hub can report them as they are.
|
|
127
|
-
*/
|
|
128
|
-
export function verifyArchive(bytes, expected) {
|
|
129
|
-
let files;
|
|
130
|
-
try {
|
|
131
|
-
files = readTar(bytes);
|
|
132
|
-
}
|
|
133
|
-
catch (error) {
|
|
134
|
-
return { ok: false, problems: [error instanceof Error ? error.message : String(error)] };
|
|
135
|
-
}
|
|
136
|
-
const hash = treeHash(files);
|
|
137
|
-
const problems = [];
|
|
138
|
-
if (hash !== expected)
|
|
139
|
-
problems.push(`The package hashes to ${hash}, not ${expected}.`);
|
|
140
|
-
let manifest;
|
|
141
|
-
try {
|
|
142
|
-
manifest = JSON.parse(new TextDecoder().decode(files.get("agentorg.json")));
|
|
143
|
-
}
|
|
144
|
-
catch {
|
|
145
|
-
return {
|
|
146
|
-
ok: false,
|
|
147
|
-
hash,
|
|
148
|
-
problems: [...problems, "The package has no readable agentorg.json."],
|
|
149
|
-
};
|
|
150
|
-
}
|
|
151
|
-
problems.push(...checkManifest(manifest));
|
|
152
|
-
const expectedFiles = new Set([
|
|
153
|
-
"agentorg.json",
|
|
154
|
-
...Object.keys(isRecord(manifest?.modules) ? manifest.modules : {}).map((name) => `dist/${name}.js`),
|
|
155
|
-
]);
|
|
156
|
-
for (const path of expectedFiles)
|
|
157
|
-
if (!files.has(path))
|
|
158
|
-
problems.push(`${path} is missing from the package.`);
|
|
159
|
-
for (const path of files.keys())
|
|
160
|
-
if (!expectedFiles.has(path))
|
|
161
|
-
problems.push(`${path} doesn't belong in the package.`);
|
|
162
|
-
return problems.length
|
|
163
|
-
? { ok: false, hash, problems }
|
|
164
|
-
: { ok: true, hash, manifest: manifest, files };
|
|
165
|
-
}
|