@agentorg/cli 0.0.3 → 0.0.4
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 +14 -10
- package/dist/bundled/index.json +4 -4
- package/dist/bundled/{sha256-87e121cbe58279f3a633e61c9773b61fc17fd53eac3d7c6f037925cbfd5d5384.agentorg → sha256-01d69bc3888c2a53963f4413d47de909d129ad27c78e9af6d830bb50c3478419.agentorg} +0 -0
- package/dist/bundled/{sha256-51ecf151e590f5e57f28229d4cb36e4932a2f1670e50ddf1a3ccf335a1ee146d.agentorg → sha256-84165e3be5c904fc971d983dab31102e07cca725d8629a6fd7d118fa3a0a88b8.agentorg} +0 -0
- package/dist/bundled/sha256-ade9132b3f34b4c39db92adeadc7e540dc745e4a81b5b54f5d45bf9ec92bca75.agentorg +0 -0
- package/dist/bundled/{sha256-b76ec31282e5b863ee9569dfd9d50b283a21101cbe1b3fac23d1cbcf16b9a408.agentorg → sha256-f4330f5987f37d8cf3aeb44d2f831b573641a87186daa2f811f0c35ba04804f0.agentorg} +0 -0
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/build.d.ts +2 -2
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/build.js +14 -4
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/hub-actor.js +8 -0
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/index.d.ts +1 -1
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/index.js +1 -1
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/router.js +40 -16
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/state.d.ts +63 -0
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/state.js +177 -36
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/storage.d.ts +2 -1
- package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/storage.js +3 -2
- package/{node_modules → dist/node_modules}/@agentorg/hub/package.json +3 -0
- package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/hub.d.ts +43 -3
- package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/hub.js +40 -3
- package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/index.d.ts +1 -0
- package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/index.js +1 -0
- package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/installer.d.ts +37 -0
- package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/installer.js +34 -3
- package/dist/node_modules/@agentorg/interfaces/dist/src/rules.d.ts +35 -0
- package/dist/node_modules/@agentorg/interfaces/dist/src/rules.js +37 -0
- package/dist/node_modules/@agentorg/kit/dist/src/chat.d.ts +37 -0
- package/dist/node_modules/@agentorg/kit/dist/src/chat.js +131 -0
- package/dist/node_modules/@agentorg/kit/dist/src/components.d.ts +94 -0
- package/dist/node_modules/@agentorg/kit/dist/src/components.js +66 -0
- package/dist/node_modules/@agentorg/kit/dist/src/icons.d.ts +17 -0
- package/dist/node_modules/@agentorg/kit/dist/src/icons.js +30 -0
- package/dist/node_modules/@agentorg/kit/dist/src/index.d.ts +6 -0
- package/dist/node_modules/@agentorg/kit/dist/src/index.js +10 -0
- package/dist/node_modules/@agentorg/kit/dist/src/markdown.d.ts +9 -0
- package/dist/node_modules/@agentorg/kit/dist/src/markdown.js +14 -0
- package/dist/node_modules/@agentorg/kit/dist/src/resizable.d.ts +5 -0
- package/dist/node_modules/@agentorg/kit/dist/src/resizable.js +8 -0
- package/dist/node_modules/@agentorg/kit/dist/src/styles.d.ts +11 -0
- package/dist/node_modules/@agentorg/kit/dist/src/styles.js +166 -0
- package/dist/node_modules/@agentorg/kit/package.json +44 -0
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/frame/runtime.js +172 -17
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/host/runner.js +168 -11
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/client.d.ts +18 -0
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/client.js +24 -3
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-base.d.ts +8 -0
- package/dist/node_modules/@agentorg/sdk/dist/src/frame-base.js +64 -0
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-entry.js +4 -4
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-host.d.ts +1 -10
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-host.js +0 -23
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-protocol.d.ts +0 -8
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame.d.ts +0 -2
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame.js +0 -8
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/host.js +5 -0
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/index.d.ts +1 -1
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/module-host.d.ts +6 -1
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/module-host.js +24 -1
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/module.d.ts +30 -1
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/package.js +111 -6
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/runtime.d.ts +22 -1
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/runtime.js +114 -0
- package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/testing.d.ts +14 -2
- package/dist/node_modules/@agentorg/sdk/dist/src/testing.js +89 -0
- package/{node_modules → dist/node_modules}/@agentorg/shell/dist/app.css +27 -144
- package/dist/node_modules/@agentorg/shell/dist/app.js +219 -0
- package/{node_modules → dist/node_modules}/@agentorg/shell/package.json +1 -0
- package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/index.d.ts +1 -1
- package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/ops.d.ts +14 -1
- package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/ops.js +22 -2
- package/dist/src/cli.js +23 -0
- package/dist/src/gateway.js +42 -1
- package/dist/src/rules.d.ts +71 -0
- package/dist/src/rules.js +157 -0
- package/package.json +13 -16
- package/dist/bundled/sha256-e4c0e857cea3a721998effe2ca859c4011978b9bc36e63c058bfc17c27a1772e.agentorg +0 -0
- package/node_modules/@agentorg/sdk/dist/src/testing.js +0 -51
- package/node_modules/@agentorg/shell/dist/app.js +0 -9
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/hub-actor.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/logs.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/logs.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/net.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/net.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/processes.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/processes.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/router.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/server.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/server.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/validate-worker.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/validate-worker.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/validate.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/hub/dist/src/validate.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/account-login.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/account-login.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/chat.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/chat.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/http-egress.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/http-egress.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/kv.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/kv.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/layout.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/layout.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/llm-session.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/llm-session.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/storage-admin.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/storage-admin.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/ui-shell.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/ui-shell.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/ui-view.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/dist/src/ui-view.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/interfaces/package.json +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/build.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/build.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/canonical.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/canonical.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/cli.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/cli.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/client-http.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/client-http.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/describe.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/describe.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/errors.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/errors.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-entry.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/frame-protocol.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/host-main.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/host-main.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/host.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/index.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/interface.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/interface.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/manifest-api.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/manifest-api.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/manifest.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/manifest.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/module.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/package.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/person-commands.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/person-commands.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/tar.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/dist/src/tar.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/sdk/package.json +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/shell/dist/agent-bindings.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/shell/dist/index.html +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/shell/src/agent-bindings.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/bytes.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/bytes.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/frames.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/frames.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/index.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/transports.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/transports.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/yamux.d.ts +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/dist/src/yamux.js +0 -0
- /package/{node_modules → dist/node_modules}/@agentorg/wire/package.json +0 -0
|
@@ -23,6 +23,27 @@ const HUB_EXPORTS = {
|
|
|
23
23
|
audit: hubAudit,
|
|
24
24
|
};
|
|
25
25
|
const NAME = /^[a-z][A-Za-z0-9_]*$/;
|
|
26
|
+
/** The longest name of a slot made at run time, so a tool named `<slot>__<method>` fits. */
|
|
27
|
+
const EXPOSED_MAX = 48;
|
|
28
|
+
/** Exposure requests one Actor may have open toward one other at a time. */
|
|
29
|
+
const MAX_OPEN_EXPOSURES = 32;
|
|
30
|
+
/** The Actors that are the Hub itself: they take no slots. */
|
|
31
|
+
const BUILTIN = new Set(["hub", "storage", "net"]);
|
|
32
|
+
/**
|
|
33
|
+
* The default name of a slot exposing `exportName` of the Actor named `providerName`: the name's
|
|
34
|
+
* ASCII words camelCased, `_`, and the export's last part; the export's part alone when the name
|
|
35
|
+
* has no ASCII letters.
|
|
36
|
+
*/
|
|
37
|
+
export function exposedName(providerName, exportName) {
|
|
38
|
+
const words = (providerName.match(/[A-Za-z0-9]+/g) ?? []).map((word) => word.toLowerCase());
|
|
39
|
+
const joined = words
|
|
40
|
+
.map((word, i) => (i ? word[0]?.toUpperCase() + word.slice(1) : word))
|
|
41
|
+
.join("");
|
|
42
|
+
const letters = joined.replace(/^[^A-Za-z]+/, "");
|
|
43
|
+
const camel = letters && (letters[0] ?? "").toLowerCase() + letters.slice(1);
|
|
44
|
+
const part = exportName.slice(exportName.lastIndexOf(".") + 1);
|
|
45
|
+
return (camel ? `${camel}_${part}` : part).slice(0, EXPOSED_MAX);
|
|
46
|
+
}
|
|
26
47
|
const MEMBER = /^[a-z][A-Za-z0-9_]*(\.[a-z][A-Za-z0-9_]*)?$/;
|
|
27
48
|
const now = () => new Date().toISOString();
|
|
28
49
|
const digest = (secret) => createHash("sha256").update(secret).digest();
|
|
@@ -52,6 +73,9 @@ const MIGRATIONS = [
|
|
|
52
73
|
CREATE TABLE audit (
|
|
53
74
|
seq INTEGER PRIMARY KEY AUTOINCREMENT, at TEXT NOT NULL, actor TEXT NOT NULL,
|
|
54
75
|
kind TEXT NOT NULL, details TEXT NOT NULL);`,
|
|
76
|
+
// Exposure: an Actor made for another (provenance only), and requests to expose.
|
|
77
|
+
`ALTER TABLE actors ADD COLUMN installed_for TEXT;
|
|
78
|
+
ALTER TABLE requests ADD COLUMN exposed INTEGER NOT NULL DEFAULT 0;`,
|
|
55
79
|
];
|
|
56
80
|
/** Whether a process with this pid runs now. */
|
|
57
81
|
function alive(pid) {
|
|
@@ -101,7 +125,11 @@ const bindingOf = (row) => ({
|
|
|
101
125
|
interface: String(row.interface),
|
|
102
126
|
madeBy: String(row.made_by),
|
|
103
127
|
at: String(row.at),
|
|
128
|
+
...(row.exposed ? { exposed: true } : {}),
|
|
104
129
|
});
|
|
130
|
+
/** A binding's columns, with whether its slot was made at run time. */
|
|
131
|
+
const BINDING = `b.*, (SELECT d.dynamic FROM declarations d
|
|
132
|
+
WHERE d.actor = b.consumer AND d.side = 'slot' AND d.name = b.slot) AS exposed`;
|
|
105
133
|
const requestOf = (row) => ({
|
|
106
134
|
requestId: String(row.id),
|
|
107
135
|
consumer: String(row.consumer),
|
|
@@ -112,6 +140,7 @@ const requestOf = (row) => ({
|
|
|
112
140
|
requestedBy: String(row.requested_by),
|
|
113
141
|
at: String(row.at),
|
|
114
142
|
needs: row.needs === "slot" ? "slot" : "export",
|
|
143
|
+
...(row.exposed ? { exposed: true } : {}),
|
|
115
144
|
});
|
|
116
145
|
const other = (side) => (side === "export" ? "slot" : "export");
|
|
117
146
|
/**
|
|
@@ -302,7 +331,7 @@ export class HubState {
|
|
|
302
331
|
// ── Actors ──────────────────────────────────────────────────────────────────
|
|
303
332
|
#actor(actorId) {
|
|
304
333
|
const row = this.#db
|
|
305
|
-
.prepare("SELECT id, name, package, state, restarts, last_exit FROM actors WHERE id = ?")
|
|
334
|
+
.prepare("SELECT id, name, package, state, restarts, last_exit, installed_for FROM actors WHERE id = ?")
|
|
306
335
|
.get(actorId);
|
|
307
336
|
return (row && {
|
|
308
337
|
actorId: String(row.id),
|
|
@@ -311,12 +340,18 @@ export class HubState {
|
|
|
311
340
|
state: row.state,
|
|
312
341
|
restarts: Number(row.restarts),
|
|
313
342
|
...(row.last_exit ? { lastExit: JSON.parse(String(row.last_exit)) } : {}),
|
|
343
|
+
...(row.installed_for ? { installedFor: String(row.installed_for) } : {}),
|
|
314
344
|
});
|
|
315
345
|
}
|
|
346
|
+
/** An Actor as a refusal names it: "Name (id)", or the id alone when there's no such Actor. */
|
|
347
|
+
named(actorId) {
|
|
348
|
+
const actor = this.#actor(actorId);
|
|
349
|
+
return actor ? `${actor.name} (${actor.actorId})` : actorId;
|
|
350
|
+
}
|
|
316
351
|
actor(actorId) {
|
|
317
352
|
const actor = this.#actor(actorId);
|
|
318
353
|
if (!actor)
|
|
319
|
-
throw new Refused("unknown", `No Actor ${actorId}.`);
|
|
354
|
+
throw new Refused("unknown", `No Actor ${actorId}; hub.actors.list lists them.`);
|
|
320
355
|
return actor;
|
|
321
356
|
}
|
|
322
357
|
/** The host sandbox's status changed: every package Actor's record (its `host`) differs. */
|
|
@@ -337,18 +372,24 @@ export class HubState {
|
|
|
337
372
|
}
|
|
338
373
|
#require(caller, hubExport) {
|
|
339
374
|
if (!this.holds(caller, hubExport))
|
|
340
|
-
throw new Refused("forbidden", `${caller} isn't bound to hub.${hubExport}@1.`);
|
|
375
|
+
throw new Refused("forbidden", `${this.named(caller)} isn't bound to hub.${hubExport}@1; a manager (the person) can bind it, or do this for it.`);
|
|
341
376
|
}
|
|
342
377
|
/** Create an Actor: one that runs a package, or an external one, whose credential comes back once. */
|
|
343
378
|
createActor(caller, input) {
|
|
344
379
|
this.#require(caller, "actors");
|
|
380
|
+
if (input.for !== undefined) {
|
|
381
|
+
if (!this.isManager(caller))
|
|
382
|
+
throw new Refused("forbidden", `Only a manager says whom an Actor is made for; ${this.named(caller)} isn't one. Create it without for.`);
|
|
383
|
+
this.#open(input.for);
|
|
384
|
+
}
|
|
345
385
|
const actorId = `act_${randomBytes(8).toString("hex")}`;
|
|
346
386
|
const credential = input.package ? undefined : randomBytes(32).toString("base64url");
|
|
347
|
-
const insert = this.#db.prepare("INSERT INTO actors (id, name, package, state, credential, created_at) VALUES (?, ?, ?, 'created', ?, ?)");
|
|
387
|
+
const insert = this.#db.prepare("INSERT INTO actors (id, name, package, state, credential, created_at, installed_for) VALUES (?, ?, ?, 'created', ?, ?, ?)");
|
|
388
|
+
const madeFor = input.for ?? null;
|
|
348
389
|
this.#transaction(() => {
|
|
349
390
|
if (input.package) {
|
|
350
391
|
const { manifest } = this.package(input.package);
|
|
351
|
-
insert.run(actorId, input.name, input.package, null, now());
|
|
392
|
+
insert.run(actorId, input.name, input.package, null, now(), madeFor);
|
|
352
393
|
for (const [module, m] of Object.entries(manifest.modules))
|
|
353
394
|
for (const [side, members] of [
|
|
354
395
|
["slot", m.slots],
|
|
@@ -365,23 +406,24 @@ export class HubState {
|
|
|
365
406
|
this.#insertBinding({ consumer: actorId, slot, provider: actorId, export: exported }, HUB);
|
|
366
407
|
}
|
|
367
408
|
else
|
|
368
|
-
insert.run(actorId, input.name, "external", digest(credential), now());
|
|
409
|
+
insert.run(actorId, input.name, "external", digest(credential), now(), madeFor);
|
|
369
410
|
this.#audit(caller, "actor.create", {
|
|
370
411
|
actorId,
|
|
371
412
|
name: input.name,
|
|
372
413
|
package: input.package ?? "external",
|
|
414
|
+
...(input.for === undefined ? {} : { for: input.for }),
|
|
373
415
|
});
|
|
374
416
|
this.#emit(() => this.#events.actorChanged?.(actorId));
|
|
375
417
|
for (const initial of input.bindings ?? []) {
|
|
376
418
|
const wiring = { consumer: actorId, ...initial };
|
|
377
419
|
if (!this.sides(caller, wiring).export)
|
|
378
|
-
throw new Refused("forbidden", `${caller} can't grant ${initial.provider}'s ${initial.export}.`);
|
|
420
|
+
throw new Refused("forbidden", `${this.named(caller)} can't grant ${this.named(initial.provider)}'s ${initial.export}. Create it without that binding, then it can ask for it with hub.grants.request, or the provider or a manager can bind it.`);
|
|
379
421
|
if (!input.package && !this.declaration(actorId, "slot", initial.slot)) {
|
|
380
422
|
if (!NAME.test(initial.slot))
|
|
381
423
|
throw new Refused("invalid", `${JSON.stringify(initial.slot)} isn't a valid slot name.`);
|
|
382
424
|
const offered = this.declaration(initial.provider, "export", initial.export);
|
|
383
425
|
if (!offered)
|
|
384
|
-
throw new Refused("unknown", `${initial.provider} offers no ${initial.export}.`);
|
|
426
|
+
throw new Refused("unknown", `${this.named(initial.provider)} offers no ${initial.export}; hub.exports.list lists what it offers.`);
|
|
385
427
|
this.#declare(actorId, "slot", initial.slot, offered.iface, false);
|
|
386
428
|
}
|
|
387
429
|
this.#insertBinding(wiring, caller);
|
|
@@ -403,14 +445,14 @@ export class HubState {
|
|
|
403
445
|
this.#require(caller, "actors");
|
|
404
446
|
const actor = this.actor(actorId);
|
|
405
447
|
if (actor.package === "external" || actor.package === "builtin")
|
|
406
|
-
throw new Refused("state", `${actorId} isn't a package Actor
|
|
448
|
+
throw new Refused("state", `${this.named(actorId)} isn't a package Actor, so the Hub doesn't run its process.`);
|
|
407
449
|
return actor;
|
|
408
450
|
}
|
|
409
451
|
/** Refused unless the caller may start the Actor and it can be started now; changes nothing. */
|
|
410
452
|
checkStart(caller, actorId) {
|
|
411
453
|
const actor = this.#packageActor(caller, actorId);
|
|
412
454
|
if (actor.state !== "created" && actor.state !== "stopped")
|
|
413
|
-
throw new Refused("state", `${actorId} is ${actor.state}.`);
|
|
455
|
+
throw new Refused("state", `${this.named(actorId)} is ${actor.state === "running" ? "already running" : "closed and can't start again; make another"}.`);
|
|
414
456
|
}
|
|
415
457
|
/** Start a package Actor: recorded as running; the Hub spawns its process. */
|
|
416
458
|
start(caller, actorId) {
|
|
@@ -424,7 +466,7 @@ export class HubState {
|
|
|
424
466
|
stop(caller, actorId) {
|
|
425
467
|
const actor = this.#packageActor(caller, actorId);
|
|
426
468
|
if (actor.state !== "running")
|
|
427
|
-
throw new Refused("state", `${actorId} is ${actor.state}.`);
|
|
469
|
+
throw new Refused("state", `${this.named(actorId)} is ${actor.state}, not running.`);
|
|
428
470
|
this.#transaction(() => {
|
|
429
471
|
this.#db.prepare("UPDATE actors SET state = 'stopped' WHERE id = ?").run(actorId);
|
|
430
472
|
this.#audit(caller, "actor.stop", { actorId });
|
|
@@ -436,7 +478,7 @@ export class HubState {
|
|
|
436
478
|
this.#require(caller, "actors");
|
|
437
479
|
const actor = this.actor(actorId);
|
|
438
480
|
if (actorId === HUB || actorId === PERSON || actorId === STORAGE || actorId === NET)
|
|
439
|
-
throw new Refused("forbidden", `${actorId} can't be closed.`);
|
|
481
|
+
throw new Refused("forbidden", `${this.named(actorId)} is built in and can't be closed.`);
|
|
440
482
|
if (actor.state === "closed")
|
|
441
483
|
return;
|
|
442
484
|
this.#transaction(() => {
|
|
@@ -557,7 +599,7 @@ export class HubState {
|
|
|
557
599
|
#open(actorId) {
|
|
558
600
|
const actor = this.actor(actorId);
|
|
559
601
|
if (actor.state === "closed")
|
|
560
|
-
throw new Refused("state", `${actorId} is closed.`);
|
|
602
|
+
throw new Refused("state", `${this.named(actorId)} is closed for good; make another.`);
|
|
561
603
|
return actor;
|
|
562
604
|
}
|
|
563
605
|
/**
|
|
@@ -568,7 +610,7 @@ export class HubState {
|
|
|
568
610
|
declareExternal(actorId, declares) {
|
|
569
611
|
const actor = this.#open(actorId);
|
|
570
612
|
if (actor.package !== "external")
|
|
571
|
-
throw new Refused("forbidden", `${actorId} declares through its package.`);
|
|
613
|
+
throw new Refused("forbidden", `${this.named(actorId)} declares through its package; an Actor of another package declares otherwise.`);
|
|
572
614
|
this.#transaction(() => {
|
|
573
615
|
for (const [side, members] of [
|
|
574
616
|
["slot", declares.slots],
|
|
@@ -578,6 +620,14 @@ export class HubState {
|
|
|
578
620
|
if (!NAME.test(name))
|
|
579
621
|
throw new Refused("invalid", `${JSON.stringify(name)} isn't a valid name.`);
|
|
580
622
|
this.#checked(iface);
|
|
623
|
+
if (side === "slot") {
|
|
624
|
+
// The Actor's own slots are its to name: an exposure under the same name yields,
|
|
625
|
+
// with its binding, and requests to make one under it close.
|
|
626
|
+
if (this.declaration(actorId, side, name)?.dynamic)
|
|
627
|
+
this.#drop(actorId, side, name);
|
|
628
|
+
for (const open of this.#pending("consumer = ? AND slot = ? AND exposed = 1", actorId, name))
|
|
629
|
+
this.#decide(open, "closed");
|
|
630
|
+
}
|
|
581
631
|
const known = this.declaration(actorId, side, name);
|
|
582
632
|
if (known &&
|
|
583
633
|
this.#isBound(actorId, side, name) &&
|
|
@@ -622,7 +672,7 @@ export class HubState {
|
|
|
622
672
|
if (!MEMBER.test(name))
|
|
623
673
|
throw new Refused("invalid", `${JSON.stringify(name)} isn't a valid export name.`);
|
|
624
674
|
if (this.declaration(actorId, "export", name))
|
|
625
|
-
throw new Refused("conflict", `${actorId} already offers ${name}.`);
|
|
675
|
+
throw new Refused("conflict", `${this.named(actorId)} already offers ${name}; offer it under another name${this.declaration(actorId, "export", name)?.dynamic ? ", or withdraw it first" : ""}.`);
|
|
626
676
|
this.#checked(iface);
|
|
627
677
|
this.#transaction(() => {
|
|
628
678
|
this.#declare(actorId, "export", name, iface, true);
|
|
@@ -634,7 +684,7 @@ export class HubState {
|
|
|
634
684
|
withdraw(actorId, name) {
|
|
635
685
|
const declared = this.declaration(actorId, "export", name);
|
|
636
686
|
if (!declared?.dynamic)
|
|
637
|
-
throw new Refused("unknown", `${actorId} offers no ${name} at run time to withdraw.`);
|
|
687
|
+
throw new Refused("unknown", `${this.named(actorId)} offers no ${name} at run time to withdraw; only exports offered at run time can be.`);
|
|
638
688
|
this.#transaction(() => {
|
|
639
689
|
this.#drop(actorId, "export", name);
|
|
640
690
|
this.#audit(actorId, "export.withdraw", { export: name });
|
|
@@ -673,7 +723,7 @@ export class HubState {
|
|
|
673
723
|
// ── Bindings: a binding is the grant ────────────────────────────────────────
|
|
674
724
|
binding(consumer, slot) {
|
|
675
725
|
const row = this.#db
|
|
676
|
-
.prepare(
|
|
726
|
+
.prepare(`SELECT ${BINDING} FROM bindings b WHERE consumer = ? AND slot = ?`)
|
|
677
727
|
.get(consumer, slot);
|
|
678
728
|
return row && bindingOf(row);
|
|
679
729
|
}
|
|
@@ -691,9 +741,9 @@ export class HubState {
|
|
|
691
741
|
bindings(actor) {
|
|
692
742
|
const rows = actor
|
|
693
743
|
? this.#db
|
|
694
|
-
.prepare(
|
|
744
|
+
.prepare(`SELECT ${BINDING} FROM bindings b WHERE consumer = ? OR provider = ? ORDER BY b.rowid`)
|
|
695
745
|
.all(actor, actor)
|
|
696
|
-
: this.#db.prepare(
|
|
746
|
+
: this.#db.prepare(`SELECT ${BINDING} FROM bindings b ORDER BY b.rowid`).all();
|
|
697
747
|
return rows.map(bindingOf);
|
|
698
748
|
}
|
|
699
749
|
/** A manager is bound to the hub's `hub.bindings@1`; there is no other role. */
|
|
@@ -737,10 +787,10 @@ export class HubState {
|
|
|
737
787
|
this.#open(wiring.provider);
|
|
738
788
|
const slot = this.declaration(wiring.consumer, "slot", wiring.slot);
|
|
739
789
|
if (!slot)
|
|
740
|
-
throw new Refused("unknown", `${wiring.consumer} has no slot ${wiring.slot}.`);
|
|
790
|
+
throw new Refused("unknown", `${this.named(wiring.consumer)} has no slot ${wiring.slot}; hub.grants.expose makes one at run time.`);
|
|
741
791
|
const exported = this.declaration(wiring.provider, "export", wiring.export);
|
|
742
792
|
if (!exported)
|
|
743
|
-
throw new Refused("unknown", `${wiring.provider} offers no ${wiring.export}.`);
|
|
793
|
+
throw new Refused("unknown", `${this.named(wiring.provider)} offers no ${wiring.export}; hub.exports.list lists what it offers.`);
|
|
744
794
|
const fit = compareInterfaces(slot.iface, exported.iface);
|
|
745
795
|
if (fit === "unrelated")
|
|
746
796
|
throw new Refused("conflict", `${wiring.slot} takes ${slot.iface.id}; ${wiring.export} offers ${exported.iface.id}.`);
|
|
@@ -751,7 +801,7 @@ export class HubState {
|
|
|
751
801
|
#insertBinding(wiring, madeBy) {
|
|
752
802
|
const iface = this.#ends(wiring);
|
|
753
803
|
if (this.binding(wiring.consumer, wiring.slot))
|
|
754
|
-
throw new Refused("bound", `${wiring.consumer}'s ${wiring.slot} is already bound; unbind it first.`);
|
|
804
|
+
throw new Refused("bound", `${this.named(wiring.consumer)}'s ${wiring.slot} is already bound; unbind it first.`);
|
|
755
805
|
const at = now();
|
|
756
806
|
this.#db
|
|
757
807
|
.prepare("INSERT INTO bindings (consumer, slot, provider, export, interface, made_by, at) VALUES (?, ?, ?, ?, ?, ?, ?)")
|
|
@@ -761,14 +811,19 @@ export class HubState {
|
|
|
761
811
|
this.#emit(() => this.#events.bound?.(record));
|
|
762
812
|
}
|
|
763
813
|
#removeBindings(where, ...params) {
|
|
764
|
-
const removed = this.#db.prepare(`SELECT
|
|
814
|
+
const removed = this.#db.prepare(`SELECT ${BINDING} FROM bindings b WHERE ${where}`).all(...params).map(bindingOf);
|
|
765
815
|
if (!removed.length)
|
|
766
816
|
return;
|
|
767
|
-
if (removed.some((b) => b.consumer === PERSON && b.provider === HUB))
|
|
817
|
+
if (removed.some((b) => b.consumer === PERSON && b.provider === HUB && !b.exposed))
|
|
768
818
|
throw new Refused("forbidden", "The person's hub bindings stay, so someone can always manage the Hub.");
|
|
769
819
|
// Requests whose requester held its end through these bindings can't be approved any more.
|
|
770
820
|
const open = this.#pending("1 = 1");
|
|
771
821
|
this.#db.prepare(`DELETE FROM bindings WHERE ${where}`).run(...params);
|
|
822
|
+
// A slot made at run time goes with its binding.
|
|
823
|
+
const dropExposed = this.#db.prepare("DELETE FROM declarations WHERE actor = ? AND side = 'slot' AND name = ? AND dynamic = 1");
|
|
824
|
+
for (const binding of removed)
|
|
825
|
+
if (binding.exposed)
|
|
826
|
+
dropExposed.run(binding.consumer, binding.slot);
|
|
772
827
|
this.#emit(() => this.#events.unbound?.(removed));
|
|
773
828
|
for (const pending of open)
|
|
774
829
|
if (!this.#standing(pending.request))
|
|
@@ -783,7 +838,7 @@ export class HubState {
|
|
|
783
838
|
bind(caller, wiring) {
|
|
784
839
|
const sides = this.sides(caller, wiring);
|
|
785
840
|
if (!sides.export && !sides.slot)
|
|
786
|
-
throw new Refused("forbidden", `${caller} holds neither end of this binding.`);
|
|
841
|
+
throw new Refused("forbidden", `${this.named(caller)} holds neither end of this binding: the export side is ${this.named(wiring.provider)}, an Actor bound to that export, or a manager; the slot side is ${this.named(wiring.consumer)} or a manager. Ask one of them.`);
|
|
787
842
|
if (!(sides.export && sides.slot)) {
|
|
788
843
|
const has = sides.export ? "export" : "slot";
|
|
789
844
|
if (!this.#asked(wiring, has))
|
|
@@ -805,9 +860,9 @@ export class HubState {
|
|
|
805
860
|
unbind(caller, consumer, slot) {
|
|
806
861
|
const binding = this.binding(consumer, slot);
|
|
807
862
|
if (!binding)
|
|
808
|
-
throw new Refused("unknown", `${consumer}'s ${slot} isn't bound.`);
|
|
863
|
+
throw new Refused("unknown", `${this.named(consumer)}'s ${slot} isn't bound.`);
|
|
809
864
|
if (caller !== consumer && caller !== binding.provider && !this.isManager(caller))
|
|
810
|
-
throw new Refused("forbidden", `${caller} can't unbind ${consumer}'s ${slot}.`);
|
|
865
|
+
throw new Refused("forbidden", `${this.named(caller)} can't unbind ${this.named(consumer)}'s ${slot}: its consumer, its provider or a manager can.`);
|
|
811
866
|
this.#transaction(() => {
|
|
812
867
|
this.#removeBindings("consumer = ? AND slot = ?", consumer, slot);
|
|
813
868
|
this.#audit(caller, "unbind", {
|
|
@@ -818,6 +873,84 @@ export class HubState {
|
|
|
818
873
|
});
|
|
819
874
|
});
|
|
820
875
|
}
|
|
876
|
+
/**
|
|
877
|
+
* Expose an export to one Actor: a slot made on `to` at run time, typed by the export's
|
|
878
|
+
* interface and bound to it, in one step. The authority is a binding's, with `to` as the
|
|
879
|
+
* consumer: with both ends it is made (approving any open request for it); with one, it is a
|
|
880
|
+
* request to the other end's approvers, who approve by exposing the same; with neither, it is
|
|
881
|
+
* refused. The same export already exposed to `to` gives that slot back.
|
|
882
|
+
*/
|
|
883
|
+
expose(caller, input) {
|
|
884
|
+
const to = this.#open(input.to);
|
|
885
|
+
const provider = this.#open(input.provider);
|
|
886
|
+
// Authority first, as bind's: a caller with neither end learns nothing more.
|
|
887
|
+
const ends = { consumer: to.actorId, provider: provider.actorId, export: input.export };
|
|
888
|
+
const sides = this.sides(caller, { ...ends, slot: "" });
|
|
889
|
+
if (!sides.export && !sides.slot)
|
|
890
|
+
throw new Refused("forbidden", `${this.named(caller)} can't expose ${input.export} of ${this.named(provider.actorId)} to ${this.named(to.actorId)}: that takes the provider's side (it, an Actor bound to that export, or a manager) or ${this.named(to.actorId)}'s (it, or a manager). Ask one of them to expose it.`);
|
|
891
|
+
if (BUILTIN.has(to.actorId))
|
|
892
|
+
throw new Refused("forbidden", `${this.named(to.actorId)} is the Hub itself and takes no slots.`);
|
|
893
|
+
const offered = this.declaration(provider.actorId, "export", input.export);
|
|
894
|
+
if (!offered)
|
|
895
|
+
throw new Refused("unknown", `${this.named(provider.actorId)} offers no ${input.export}.`);
|
|
896
|
+
if (offered.iface.kind !== "rpc")
|
|
897
|
+
throw new Refused("unsupported", `Only an rpc export can be exposed; ${input.export} is ${offered.iface.kind}.`);
|
|
898
|
+
const same = (row) => row.provider === provider.actorId && row.export === input.export;
|
|
899
|
+
const already = this.bindings(to.actorId).find((b) => b.consumer === to.actorId && b.exposed && same(b));
|
|
900
|
+
if (already && (input.as === undefined || input.as === already.slot))
|
|
901
|
+
return { exposed: true, slot: already.slot };
|
|
902
|
+
const requested = this.#db
|
|
903
|
+
.prepare("SELECT * FROM requests WHERE status = 'open' AND exposed = 1 AND consumer = ?")
|
|
904
|
+
.all(to.actorId).map(requestOf);
|
|
905
|
+
// An open request's name for this export is taken again, so approving needs no `as`.
|
|
906
|
+
const slot = input.as ??
|
|
907
|
+
requested.find(same)?.slot ??
|
|
908
|
+
this.#freeName(to.actorId, exposedName(provider.name, input.export), requested);
|
|
909
|
+
if (!NAME.test(slot) || slot.length > EXPOSED_MAX)
|
|
910
|
+
throw new Refused("invalid", `${JSON.stringify(slot)} isn't a slot name: one word of letters, digits and _, at most ${EXPOSED_MAX}.`);
|
|
911
|
+
// A request reserves no name: the first exposure made under it has it, and the rest close.
|
|
912
|
+
if (this.declaration(to.actorId, "slot", slot))
|
|
913
|
+
throw new Refused("conflict", `${this.named(to.actorId)} already has a slot ${slot}; name another with as.`);
|
|
914
|
+
const wiring = { ...ends, slot };
|
|
915
|
+
if (!(sides.export && sides.slot)) {
|
|
916
|
+
const has = sides.export ? "export" : "slot";
|
|
917
|
+
if (!this.#asked(wiring, has)) {
|
|
918
|
+
const mine = requested.filter((r) => r.requestedBy === caller && !(same(r) && r.slot === slot));
|
|
919
|
+
if (mine.length >= MAX_OPEN_EXPOSURES)
|
|
920
|
+
throw new Refused("limit", `${this.named(caller)} has ${MAX_OPEN_EXPOSURES} exposures to ${this.named(to.actorId)} waiting; wait for them to be decided, or withdraw one by exposing it.`);
|
|
921
|
+
const request = this.#ask(caller, wiring, "", other(has), true);
|
|
922
|
+
return { exposed: false, slot, requestId: request.requestId };
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
this.#transaction(() => {
|
|
926
|
+
// Settled: this slot's requests (approved if for this export), and this export's requests
|
|
927
|
+
// to `to` under other names, which can't be made any more.
|
|
928
|
+
const pending = this.#pending("consumer = ? AND (slot = ? OR (exposed = 1 AND provider = ? AND export = ?))", wiring.consumer, wiring.slot, wiring.provider, wiring.export);
|
|
929
|
+
this.#declare(to.actorId, "slot", slot, offered.iface, true);
|
|
930
|
+
this.#insertBinding(wiring, caller);
|
|
931
|
+
for (const open of pending)
|
|
932
|
+
this.#decide(open, same(open.request) && open.request.slot === slot ? "approved" : "closed");
|
|
933
|
+
this.#audit(caller, "expose", { ...wiring });
|
|
934
|
+
});
|
|
935
|
+
return { exposed: true, slot };
|
|
936
|
+
}
|
|
937
|
+
/** A name free on `to`: `base`, else `base_2`, `base_3`…, each within the longest name. */
|
|
938
|
+
#freeName(to, base, requested) {
|
|
939
|
+
const taken = (name) => !!this.declaration(to, "slot", name) || requested.some((r) => r.slot === name);
|
|
940
|
+
for (let n = 1;; n++) {
|
|
941
|
+
const suffix = n === 1 ? "" : `_${n}`;
|
|
942
|
+
const name = base.slice(0, EXPOSED_MAX - suffix.length) + suffix;
|
|
943
|
+
if (!taken(name))
|
|
944
|
+
return name;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
/** Remove a slot made by `expose`, with its binding: its consumer, its provider or a manager may. */
|
|
948
|
+
unexpose(caller, to, slot) {
|
|
949
|
+
const binding = this.binding(to, slot);
|
|
950
|
+
if (!binding?.exposed)
|
|
951
|
+
throw new Refused("unknown", `${this.named(to)} has no slot ${slot} made by expose; unbind a declared slot instead.`);
|
|
952
|
+
this.unbind(caller, to, slot);
|
|
953
|
+
}
|
|
821
954
|
/**
|
|
822
955
|
* Ask for a binding the caller holds one end of; it goes to the other end's approvers. Asking
|
|
823
956
|
* again for the same wiring while a request is open returns that request.
|
|
@@ -825,9 +958,9 @@ export class HubState {
|
|
|
825
958
|
request(caller, wiring, reason) {
|
|
826
959
|
const sides = this.sides(caller, wiring);
|
|
827
960
|
if (!sides.export && !sides.slot)
|
|
828
|
-
throw new Refused("forbidden", `${caller} holds neither end of this binding.`);
|
|
961
|
+
throw new Refused("forbidden", `${this.named(caller)} holds neither end of this binding: the export side is ${this.named(wiring.provider)}, an Actor bound to that export, or a manager; the slot side is ${this.named(wiring.consumer)} or a manager. Ask one of them.`);
|
|
829
962
|
if (sides.export && sides.slot)
|
|
830
|
-
throw new Refused("state", `${caller} holds both ends: bind it instead.`);
|
|
963
|
+
throw new Refused("state", `${this.named(caller)} holds both ends: bind it instead.`);
|
|
831
964
|
const has = sides.export ? "export" : "slot";
|
|
832
965
|
if (this.#asked(wiring, has))
|
|
833
966
|
throw new Refused("state", "The other end has asked already: bind to approve.");
|
|
@@ -841,10 +974,12 @@ export class HubState {
|
|
|
841
974
|
.map(requestOf)
|
|
842
975
|
.some((request) => this.#standing(request));
|
|
843
976
|
}
|
|
844
|
-
#ask(caller, wiring, reason, needs) {
|
|
845
|
-
|
|
977
|
+
#ask(caller, wiring, reason, needs, exposed = false) {
|
|
978
|
+
// An exposure's slot doesn't exist until it is approved; `expose` checked its ends.
|
|
979
|
+
if (!exposed)
|
|
980
|
+
this.#ends(wiring);
|
|
846
981
|
if (this.binding(wiring.consumer, wiring.slot))
|
|
847
|
-
throw new Refused("bound", `${wiring.consumer}'s ${wiring.slot} is already bound.`);
|
|
982
|
+
throw new Refused("bound", `${this.named(wiring.consumer)}'s ${wiring.slot} is already bound; unbind it first.`);
|
|
848
983
|
const open = this.#db
|
|
849
984
|
.prepare("SELECT * FROM requests WHERE status = 'open' AND requested_by = ? AND consumer = ? AND slot = ? AND provider = ? AND export = ?")
|
|
850
985
|
.get(caller, wiring.consumer, wiring.slot, wiring.provider, wiring.export);
|
|
@@ -857,12 +992,18 @@ export class HubState {
|
|
|
857
992
|
reason,
|
|
858
993
|
requestedBy: caller,
|
|
859
994
|
at: now(),
|
|
995
|
+
...(exposed ? { exposed: true } : {}),
|
|
860
996
|
};
|
|
861
997
|
this.#transaction(() => {
|
|
862
998
|
this.#db
|
|
863
|
-
.prepare("INSERT INTO requests (id, consumer, slot, provider, export, reason, requested_by, at, status, needs) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'open', ?)")
|
|
864
|
-
.run(request.requestId, wiring.consumer, wiring.slot, wiring.provider, wiring.export, reason, caller, request.at, needs);
|
|
865
|
-
this.#audit(caller, "request", {
|
|
999
|
+
.prepare("INSERT INTO requests (id, consumer, slot, provider, export, reason, requested_by, at, status, needs, exposed) VALUES (?, ?, ?, ?, ?, ?, ?, ?, 'open', ?, ?)")
|
|
1000
|
+
.run(request.requestId, wiring.consumer, wiring.slot, wiring.provider, wiring.export, reason, caller, request.at, needs, exposed ? 1 : 0);
|
|
1001
|
+
this.#audit(caller, "request", {
|
|
1002
|
+
...wiring,
|
|
1003
|
+
needs,
|
|
1004
|
+
requestId: request.requestId,
|
|
1005
|
+
...(exposed ? { exposed: true } : {}),
|
|
1006
|
+
});
|
|
866
1007
|
const approvers = this.approvers(request).filter((a) => a !== caller);
|
|
867
1008
|
this.#emit(() => this.#events.requested?.(request, approvers));
|
|
868
1009
|
});
|
|
@@ -919,7 +1060,7 @@ export class HubState {
|
|
|
919
1060
|
decline(caller, requestId) {
|
|
920
1061
|
const request = this.requests(caller).find((r) => r.requestId === requestId);
|
|
921
1062
|
if (!request)
|
|
922
|
-
throw new Refused("unknown", `No open request ${requestId} for ${caller} to decide.`);
|
|
1063
|
+
throw new Refused("unknown", `No open request ${requestId} for ${this.named(caller)} to decide; hub.grants.requests lists those it can.`);
|
|
923
1064
|
this.#transaction(() => {
|
|
924
1065
|
const [pending] = this.#pending("id = ?", requestId);
|
|
925
1066
|
if (pending)
|
|
@@ -21,10 +21,11 @@ export declare class Storage {
|
|
|
21
21
|
* Seed the store of (consumer, slot), all or none, if it holds nothing: `storage.admin@1`'s
|
|
22
22
|
* `seed`. Each entry has kv@1's limits, and together they count toward the consumer's quota.
|
|
23
23
|
*/
|
|
24
|
+
/** `named` is the consumer as a refusal names it: "Name (id)". */
|
|
24
25
|
seed(consumer: string, slot: string, entries: {
|
|
25
26
|
key: string;
|
|
26
27
|
value: unknown;
|
|
27
|
-
}[]): void;
|
|
28
|
+
}[], named?: string): void;
|
|
28
29
|
/** Every store of an Actor, gone: it was closed for good. */
|
|
29
30
|
deleteConsumer(consumer: string): void;
|
|
30
31
|
/**
|
|
@@ -139,7 +139,8 @@ export class Storage {
|
|
|
139
139
|
* Seed the store of (consumer, slot), all or none, if it holds nothing: `storage.admin@1`'s
|
|
140
140
|
* `seed`. Each entry has kv@1's limits, and together they count toward the consumer's quota.
|
|
141
141
|
*/
|
|
142
|
-
|
|
142
|
+
/** `named` is the consumer as a refusal names it: "Name (id)". */
|
|
143
|
+
seed(consumer, slot, entries, named = consumer) {
|
|
143
144
|
const keys = new Set();
|
|
144
145
|
const rows = entries.map(({ key, value }) => {
|
|
145
146
|
checkKey(key);
|
|
@@ -159,7 +160,7 @@ export class Storage {
|
|
|
159
160
|
if (this.#db
|
|
160
161
|
.prepare("SELECT 1 FROM store WHERE consumer = ? AND slot = ? LIMIT 1")
|
|
161
162
|
.get(consumer, slot))
|
|
162
|
-
throw new Refused("not_empty", `The store of ${
|
|
163
|
+
throw new Refused("not_empty", `The store of ${named}'s ${slot} isn't empty.`);
|
|
163
164
|
const used = this.#db.prepare("SELECT used FROM usage WHERE consumer = ?").get(consumer);
|
|
164
165
|
if (Number(used?.used ?? 0) + total > this.#limits.maxPerConsumer)
|
|
165
166
|
throw new Refused("quota", `An Actor's stores hold at most ${this.#limits.maxPerConsumer} bytes.`);
|
|
@@ -23,9 +23,12 @@
|
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
25
|
"@agentorg/interfaces": "0.0.0",
|
|
26
|
+
"@agentorg/kit": "0.0.0",
|
|
26
27
|
"@agentorg/sdk": "0.0.0",
|
|
27
28
|
"@agentorg/wire": "0.0.0",
|
|
28
29
|
"ajv": "^8.20.0",
|
|
30
|
+
"react": "^19.3.1",
|
|
31
|
+
"react-dom": "^19.3.1",
|
|
29
32
|
"ws": "^8.22.1",
|
|
30
33
|
"zod": "^4.6.7"
|
|
31
34
|
},
|
|
@@ -36,8 +36,8 @@ export declare const hubPackages: import("@agentorg/sdk").RpcInterface<"hub.pack
|
|
|
36
36
|
/**
|
|
37
37
|
* Build a package from its source, given as data (`package.json` and files under `src/`, up to
|
|
38
38
|
* 768 KiB), and add it as `add` does. It's `agentorg build`'s build, reading no tsconfig; its
|
|
39
|
-
* files import only `@agentorg/sdk`, `@agentorg/interfaces`
|
|
40
|
-
* the package's folder, never by a pattern. A build that fails is
|
|
39
|
+
* files import only `@agentorg/sdk`, `@agentorg/interfaces`, `zod`, `react`, `react-dom` and
|
|
40
|
+
* `@agentorg/kit` by name, and nothing outside the package's folder, never by a pattern. A build that fails is
|
|
41
41
|
* `Refused("build")` with the build's message, so the source can be fixed and built again.
|
|
42
42
|
*/
|
|
43
43
|
build: import("@agentorg/sdk").MethodSpec<z.ZodObject<{
|
|
@@ -75,6 +75,7 @@ export declare const Actor: z.ZodObject<{
|
|
|
75
75
|
reason: z.ZodOptional<z.ZodString>;
|
|
76
76
|
}, z.core.$strip>>;
|
|
77
77
|
views: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
78
|
+
installedFor: z.ZodOptional<z.ZodString>;
|
|
78
79
|
}, z.core.$strip>;
|
|
79
80
|
/** One line of an Actor's log, from its `ctx.log` or its process's own output. */
|
|
80
81
|
export declare const LogLine: z.ZodObject<{
|
|
@@ -93,11 +94,13 @@ export declare const hubActors: import("@agentorg/sdk").RpcInterface<"hub.actors
|
|
|
93
94
|
/**
|
|
94
95
|
* With a package, an Actor that runs it; without, an external one, whose credential is returned
|
|
95
96
|
* once. `bindings` wire the new Actor's slots at once, with the caller's export-side authority
|
|
96
|
-
* (the creation is the slot side's yes), for example to its own `hub.grants@1`.
|
|
97
|
+
* (the creation is the slot side's yes), for example to its own `hub.grants@1`. `for` names
|
|
98
|
+
* the Actor it is made for, recorded as `installedFor`; only a manager may give it.
|
|
97
99
|
*/
|
|
98
100
|
create: import("@agentorg/sdk").MethodSpec<z.ZodObject<{
|
|
99
101
|
name: z.ZodString;
|
|
100
102
|
package: z.ZodOptional<z.ZodString>;
|
|
103
|
+
for: z.ZodOptional<z.ZodString>;
|
|
101
104
|
bindings: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
102
105
|
slot: z.ZodString;
|
|
103
106
|
provider: z.ZodString;
|
|
@@ -130,6 +133,7 @@ export declare const hubActors: import("@agentorg/sdk").RpcInterface<"hub.actors
|
|
|
130
133
|
reason: z.ZodOptional<z.ZodString>;
|
|
131
134
|
}, z.core.$strip>>;
|
|
132
135
|
views: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
136
|
+
installedFor: z.ZodOptional<z.ZodString>;
|
|
133
137
|
}, z.core.$strip>>;
|
|
134
138
|
}, z.core.$strip>>;
|
|
135
139
|
get: import("@agentorg/sdk").MethodSpec<z.ZodObject<{
|
|
@@ -156,6 +160,7 @@ export declare const hubActors: import("@agentorg/sdk").RpcInterface<"hub.actors
|
|
|
156
160
|
reason: z.ZodOptional<z.ZodString>;
|
|
157
161
|
}, z.core.$strip>>;
|
|
158
162
|
views: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
163
|
+
installedFor: z.ZodOptional<z.ZodString>;
|
|
159
164
|
}, z.core.$strip>>;
|
|
160
165
|
start: import("@agentorg/sdk").MethodSpec<z.ZodObject<{
|
|
161
166
|
actorId: z.ZodString;
|
|
@@ -193,6 +198,8 @@ export declare const hubActors: import("@agentorg/sdk").RpcInterface<"hub.actors
|
|
|
193
198
|
actor: z.ZodString;
|
|
194
199
|
}, z.core.$strip>>;
|
|
195
200
|
}, 1>;
|
|
201
|
+
/** A slot made at run time: one segment, at most 48 characters, so tools named from it fit. */
|
|
202
|
+
export declare const SlotName: z.ZodString;
|
|
196
203
|
export declare const Binding: z.ZodObject<{
|
|
197
204
|
consumer: z.ZodString;
|
|
198
205
|
slot: z.ZodString;
|
|
@@ -201,6 +208,7 @@ export declare const Binding: z.ZodObject<{
|
|
|
201
208
|
interface: z.ZodString;
|
|
202
209
|
madeBy: z.ZodString;
|
|
203
210
|
at: z.ZodString;
|
|
211
|
+
exposed: z.ZodOptional<z.ZodLiteral<true>>;
|
|
204
212
|
}, z.core.$strip>;
|
|
205
213
|
export declare const BindingRequest: z.ZodObject<{
|
|
206
214
|
consumer: z.ZodString;
|
|
@@ -215,6 +223,7 @@ export declare const BindingRequest: z.ZodObject<{
|
|
|
215
223
|
reason: z.ZodString;
|
|
216
224
|
requestedBy: z.ZodString;
|
|
217
225
|
at: z.ZodString;
|
|
226
|
+
exposed: z.ZodOptional<z.ZodLiteral<true>>;
|
|
218
227
|
}, z.core.$strip>;
|
|
219
228
|
/**
|
|
220
229
|
* `hub.grants@1`: binding with the caller's own authority, so it is safe to give any Actor. A
|
|
@@ -241,6 +250,32 @@ export declare const hubGrants: import("@agentorg/sdk").RpcInterface<"hub.grants
|
|
|
241
250
|
consumer: z.ZodString;
|
|
242
251
|
slot: z.ZodString;
|
|
243
252
|
}, z.core.$strip>, z.ZodObject<{}, z.core.$strip>>;
|
|
253
|
+
/**
|
|
254
|
+
* Expose an `rpc` export to one Actor: a slot made on `to`, typed by the export's interface,
|
|
255
|
+
* named `as` (by default the provider's name camelCased, `_`, and the export's last part, made
|
|
256
|
+
* unique on `to`), and bound to the export, in one step. Its authority is a binding's: with
|
|
257
|
+
* both ends it is made; with one, it is a request to the other end's approvers, who approve it
|
|
258
|
+
* by calling `expose` with the request's fields. The same export already exposed to `to`
|
|
259
|
+
* gives that slot back.
|
|
260
|
+
*/
|
|
261
|
+
expose: import("@agentorg/sdk").MethodSpec<z.ZodObject<{
|
|
262
|
+
provider: z.ZodString;
|
|
263
|
+
export: z.ZodString;
|
|
264
|
+
to: z.ZodString;
|
|
265
|
+
as: z.ZodOptional<z.ZodString>;
|
|
266
|
+
}, z.core.$strip>, z.ZodUnion<readonly [z.ZodObject<{
|
|
267
|
+
exposed: z.ZodLiteral<true>;
|
|
268
|
+
slot: z.ZodString;
|
|
269
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
270
|
+
exposed: z.ZodLiteral<false>;
|
|
271
|
+
slot: z.ZodString;
|
|
272
|
+
requestId: z.ZodString;
|
|
273
|
+
}, z.core.$strip>]>>;
|
|
274
|
+
/** Remove a slot made by `expose`, with its binding: as `unbind`, the consumer, the provider or a manager may. */
|
|
275
|
+
unexpose: import("@agentorg/sdk").MethodSpec<z.ZodObject<{
|
|
276
|
+
to: z.ZodString;
|
|
277
|
+
slot: z.ZodString;
|
|
278
|
+
}, z.core.$strip>, z.ZodObject<{}, z.core.$strip>>;
|
|
244
279
|
request: import("@agentorg/sdk").MethodSpec<z.ZodObject<{
|
|
245
280
|
consumer: z.ZodString;
|
|
246
281
|
slot: z.ZodString;
|
|
@@ -265,6 +300,7 @@ export declare const hubGrants: import("@agentorg/sdk").RpcInterface<"hub.grants
|
|
|
265
300
|
reason: z.ZodString;
|
|
266
301
|
requestedBy: z.ZodString;
|
|
267
302
|
at: z.ZodString;
|
|
303
|
+
exposed: z.ZodOptional<z.ZodLiteral<true>>;
|
|
268
304
|
}, z.core.$strip>>;
|
|
269
305
|
}, z.core.$strip>>;
|
|
270
306
|
decline: import("@agentorg/sdk").MethodSpec<z.ZodObject<{
|
|
@@ -290,6 +326,7 @@ export declare const hubGrants: import("@agentorg/sdk").RpcInterface<"hub.grants
|
|
|
290
326
|
reason: z.ZodString;
|
|
291
327
|
requestedBy: z.ZodString;
|
|
292
328
|
at: z.ZodString;
|
|
329
|
+
exposed: z.ZodOptional<z.ZodLiteral<true>>;
|
|
293
330
|
status: z.ZodEnum<{
|
|
294
331
|
approved: "approved";
|
|
295
332
|
closed: "closed";
|
|
@@ -313,6 +350,7 @@ export declare const hubGrants: import("@agentorg/sdk").RpcInterface<"hub.grants
|
|
|
313
350
|
reason: z.ZodString;
|
|
314
351
|
requestedBy: z.ZodString;
|
|
315
352
|
at: z.ZodString;
|
|
353
|
+
exposed: z.ZodOptional<z.ZodLiteral<true>>;
|
|
316
354
|
}, z.core.$strip>>;
|
|
317
355
|
/**
|
|
318
356
|
* A request the subscriber could approve, or made, was approved (its binding made), declined,
|
|
@@ -332,6 +370,7 @@ export declare const hubGrants: import("@agentorg/sdk").RpcInterface<"hub.grants
|
|
|
332
370
|
reason: z.ZodString;
|
|
333
371
|
requestedBy: z.ZodString;
|
|
334
372
|
at: z.ZodString;
|
|
373
|
+
exposed: z.ZodOptional<z.ZodLiteral<true>>;
|
|
335
374
|
}, z.core.$strip>;
|
|
336
375
|
status: z.ZodEnum<{
|
|
337
376
|
approved: "approved";
|
|
@@ -357,6 +396,7 @@ export declare const hubBindings: import("@agentorg/sdk").RpcInterface<"hub.bind
|
|
|
357
396
|
interface: z.ZodString;
|
|
358
397
|
madeBy: z.ZodString;
|
|
359
398
|
at: z.ZodString;
|
|
399
|
+
exposed: z.ZodOptional<z.ZodLiteral<true>>;
|
|
360
400
|
}, z.core.$strip>>;
|
|
361
401
|
}, z.core.$strip>>;
|
|
362
402
|
}, {}, 1>;
|