@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
|
@@ -135,6 +135,113 @@ export function createRuntime(definition, options) {
|
|
|
135
135
|
throw new Refused("unimplemented", `${name} hasn't been implemented yet.`);
|
|
136
136
|
return state.impl;
|
|
137
137
|
};
|
|
138
|
+
const exposed = new Map();
|
|
139
|
+
const exposedWatchers = new Set();
|
|
140
|
+
/** Run the `onExposed` handlers; one that throws is logged and the rest still run. */
|
|
141
|
+
const exposedChanged = () => {
|
|
142
|
+
const failed = (error) => options.log.error("An onExposed handler threw.", { error: String(error) });
|
|
143
|
+
for (const fn of [...exposedWatchers])
|
|
144
|
+
try {
|
|
145
|
+
const done = fn();
|
|
146
|
+
if (done instanceof Promise)
|
|
147
|
+
done.catch(failed);
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
failed(error);
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
/** Subscribe to an exposed slot's event while the module listens and nothing is live. */
|
|
154
|
+
const listenExposed = (slot, state, event) => {
|
|
155
|
+
const entry = state.events.get(event);
|
|
156
|
+
if (state.gone || !entry || entry.stop || !entry.fns.size)
|
|
157
|
+
return;
|
|
158
|
+
// A subscription may end before `subscribe` returns: then nothing is live.
|
|
159
|
+
let ended = false;
|
|
160
|
+
let stop;
|
|
161
|
+
stop = state.source.subscribe(event, (payload) => {
|
|
162
|
+
for (const fn of [...entry.fns])
|
|
163
|
+
try {
|
|
164
|
+
fn(payload);
|
|
165
|
+
}
|
|
166
|
+
catch (error) {
|
|
167
|
+
options.log.error("An event handler threw.", { slot, event, error: String(error) });
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
// Ended by the provider going: the interest stays for when it is usable again.
|
|
171
|
+
() => {
|
|
172
|
+
ended = true;
|
|
173
|
+
if (entry.stop === stop)
|
|
174
|
+
entry.stop = undefined;
|
|
175
|
+
});
|
|
176
|
+
if (!ended)
|
|
177
|
+
entry.stop = stop;
|
|
178
|
+
};
|
|
179
|
+
const exposedHandle = (slot, state) => {
|
|
180
|
+
const { described, provider } = state.source;
|
|
181
|
+
return Object.freeze({
|
|
182
|
+
slot,
|
|
183
|
+
described,
|
|
184
|
+
provider: Object.freeze({ actor: provider.actor, export: provider.export }),
|
|
185
|
+
call: Object.freeze(Object.fromEntries((described.kind === "rpc" ? Object.keys(described.methods) : []).map((method) => [
|
|
186
|
+
method,
|
|
187
|
+
async (input) => {
|
|
188
|
+
if (state.gone)
|
|
189
|
+
throw new NotConnected(slot);
|
|
190
|
+
return state.source.call(method, input);
|
|
191
|
+
},
|
|
192
|
+
]))),
|
|
193
|
+
on(event, fn) {
|
|
194
|
+
if (described.kind !== "rpc" || !own(described.events, event))
|
|
195
|
+
throw new TypeError(`${slot} has no event ${event}.`);
|
|
196
|
+
const entry = state.events.get(event) ?? { fns: new Set() };
|
|
197
|
+
state.events.set(event, entry);
|
|
198
|
+
entry.fns.add(fn);
|
|
199
|
+
listenExposed(slot, state, event);
|
|
200
|
+
return () => {
|
|
201
|
+
entry.fns.delete(fn);
|
|
202
|
+
if (entry.fns.size)
|
|
203
|
+
return;
|
|
204
|
+
entry.stop?.();
|
|
205
|
+
entry.stop = undefined;
|
|
206
|
+
};
|
|
207
|
+
},
|
|
208
|
+
});
|
|
209
|
+
};
|
|
210
|
+
const unexpose = (slot) => {
|
|
211
|
+
const state = exposed.get(slot);
|
|
212
|
+
if (!state)
|
|
213
|
+
return;
|
|
214
|
+
exposed.delete(slot);
|
|
215
|
+
state.gone = true;
|
|
216
|
+
for (const entry of state.events.values()) {
|
|
217
|
+
entry.stop?.();
|
|
218
|
+
entry.stop = undefined;
|
|
219
|
+
}
|
|
220
|
+
exposedChanged();
|
|
221
|
+
};
|
|
222
|
+
const expose = (slot, source) => {
|
|
223
|
+
const here = exposed.get(slot);
|
|
224
|
+
if (here &&
|
|
225
|
+
here.source.described.hash === source.described.hash &&
|
|
226
|
+
here.source.provider.actor === source.provider.actor &&
|
|
227
|
+
here.source.provider.export === source.provider.export) {
|
|
228
|
+
// Usable again: the same export, its provider back. What was listened to resumes.
|
|
229
|
+
here.source = source;
|
|
230
|
+
for (const [event, entry] of here.events) {
|
|
231
|
+
entry.stop?.();
|
|
232
|
+
entry.stop = undefined;
|
|
233
|
+
listenExposed(slot, here, event);
|
|
234
|
+
}
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
if (here)
|
|
238
|
+
unexpose(slot);
|
|
239
|
+
// The handle reads the state, so it is made after; nothing reads it in between.
|
|
240
|
+
const state = { source, gone: false, events: new Map() };
|
|
241
|
+
state.handle = exposedHandle(slot, state);
|
|
242
|
+
exposed.set(slot, state);
|
|
243
|
+
exposedChanged();
|
|
244
|
+
};
|
|
138
245
|
const ctx = {
|
|
139
246
|
slots: Object.fromEntries(Object.entries(definition.slots).map(([name, iface]) => [name, slotHandle(name, iface)])),
|
|
140
247
|
exports: Object.assign(Object.fromEntries(Object.entries(definition.exports).map(([name, iface]) => [
|
|
@@ -154,6 +261,11 @@ export function createRuntime(definition, options) {
|
|
|
154
261
|
}),
|
|
155
262
|
self: options.self,
|
|
156
263
|
log: options.log,
|
|
264
|
+
exposed: () => Object.freeze([...exposed.values()].map((state) => state.handle)),
|
|
265
|
+
onExposed(fn) {
|
|
266
|
+
exposedWatchers.add(fn);
|
|
267
|
+
return () => void exposedWatchers.delete(fn);
|
|
268
|
+
},
|
|
157
269
|
};
|
|
158
270
|
const serving = (exportName) => {
|
|
159
271
|
const state = target(exportName, "http");
|
|
@@ -226,6 +338,8 @@ export function createRuntime(definition, options) {
|
|
|
226
338
|
if (state.binding)
|
|
227
339
|
notify(slot, state.binds);
|
|
228
340
|
},
|
|
341
|
+
expose,
|
|
342
|
+
unexpose,
|
|
229
343
|
async call(exportName, method, input, caller) {
|
|
230
344
|
const state = target(exportName, "rpc");
|
|
231
345
|
const spec = own(state.iface.methods, method);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { z } from "zod";
|
|
2
|
-
import type
|
|
2
|
+
import { type Interface, type RpcInterface, type StreamInterface } from "./interface.js";
|
|
3
3
|
import type { Duplex, Handlers, InterfaceMap, ModuleDefinition } from "./module.js";
|
|
4
4
|
import { type Binding, type ModuleRuntime } from "./runtime.js";
|
|
5
5
|
/** A fake bound to a slot in a test: handlers for `rpc`, a function for `stream` and `http`. */
|
|
@@ -22,8 +22,20 @@ export interface LogLine {
|
|
|
22
22
|
* as the Hub validates it: bad input is `Refused` with code `invalid`, and an unbound slot or a
|
|
23
23
|
* withdrawn export throws `NotConnected`.
|
|
24
24
|
*/
|
|
25
|
-
export interface TestContext<S extends InterfaceMap, X extends InterfaceMap> extends Omit<ModuleRuntime<S, X>, "bind" | "call"> {
|
|
25
|
+
export interface TestContext<S extends InterfaceMap, X extends InterfaceMap> extends Omit<ModuleRuntime<S, X>, "bind" | "call" | "expose"> {
|
|
26
26
|
bind<K extends keyof S & string>(slot: K, provider: Provider<S[K]>): Binding;
|
|
27
|
+
/**
|
|
28
|
+
* Make a slot at run time, as `hub.grants.expose` does: an `rpc` export faked by `handlers`,
|
|
29
|
+
* whose values are checked against `iface` as the Hub checks them. `provider` names whose
|
|
30
|
+
* export it is (by default a made-up Actor's, `export`). Exposing the same slot again with the
|
|
31
|
+
* same interface and provider makes it usable again; `emit` sends its events.
|
|
32
|
+
*/
|
|
33
|
+
expose<I extends RpcInterface>(slot: string, iface: I, handlers: Provider<I>, provider?: {
|
|
34
|
+
actor: string;
|
|
35
|
+
export: string;
|
|
36
|
+
}): Binding;
|
|
37
|
+
/** The slot made at run time goes, as when its binding is removed. */
|
|
38
|
+
unexpose(slot: string): void;
|
|
27
39
|
/** Call an export as `caller`; by default as the module's own Actor. */
|
|
28
40
|
call(exportName: string, method: string, input: unknown, caller?: string): Promise<unknown>;
|
|
29
41
|
readonly emitted: Emitted[];
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { Refused } from "./errors.js";
|
|
2
|
+
import { describeInterface, } from "./interface.js";
|
|
3
|
+
import { check, createRuntime, } from "./runtime.js";
|
|
4
|
+
export function createTestContext(definition, options = {}) {
|
|
5
|
+
const emitted = [];
|
|
6
|
+
const logs = [];
|
|
7
|
+
const line = (level) => (message, fields) => void logs.push(fields === undefined ? { level, message } : { level, message, fields });
|
|
8
|
+
const log = { info: line("info"), warn: line("warn"), error: line("error") };
|
|
9
|
+
const self = options.actorId ?? "test-actor";
|
|
10
|
+
const runtime = createRuntime(definition, {
|
|
11
|
+
self: { actorId: self, module: options.module ?? "main" },
|
|
12
|
+
log,
|
|
13
|
+
onEmit: (exportName, event, payload, to) => void emitted.push({
|
|
14
|
+
export: exportName,
|
|
15
|
+
event,
|
|
16
|
+
payload,
|
|
17
|
+
...(to === undefined ? {} : { to }),
|
|
18
|
+
}),
|
|
19
|
+
});
|
|
20
|
+
return {
|
|
21
|
+
...runtime,
|
|
22
|
+
call: (exportName, method, input, caller = self) => runtime.call(exportName, method, input, caller),
|
|
23
|
+
bind(slot, fake) {
|
|
24
|
+
const iface = definition.slots[slot];
|
|
25
|
+
let provider;
|
|
26
|
+
if (iface.kind === "rpc") {
|
|
27
|
+
const handlers = fake;
|
|
28
|
+
// The module itself is the caller of its own slot.
|
|
29
|
+
const call = { caller: self };
|
|
30
|
+
provider = {
|
|
31
|
+
async call(method, input) {
|
|
32
|
+
const handler = Object.hasOwn(handlers, method) ? handlers[method] : undefined;
|
|
33
|
+
if (!handler)
|
|
34
|
+
throw new Refused("unimplemented", `${slot}.${method} isn't faked.`);
|
|
35
|
+
return handler(input, call);
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
else if (iface.kind === "stream") {
|
|
40
|
+
const open = fake;
|
|
41
|
+
provider = { open: async (params) => open(params) };
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const fetch = fake;
|
|
45
|
+
provider = { fetch: async (request) => fetch(request) };
|
|
46
|
+
}
|
|
47
|
+
return runtime.bind(slot, provider);
|
|
48
|
+
},
|
|
49
|
+
expose(slot, iface, fake, provider = { actor: "test-provider", export: "export" }) {
|
|
50
|
+
const handlers = fake;
|
|
51
|
+
const listeners = new Map();
|
|
52
|
+
runtime.expose(slot, {
|
|
53
|
+
described: describeInterface(iface),
|
|
54
|
+
provider,
|
|
55
|
+
async call(method, input) {
|
|
56
|
+
const spec = Object.hasOwn(iface.methods, method) ? iface.methods[method] : undefined;
|
|
57
|
+
if (!spec)
|
|
58
|
+
throw new Refused("unknown", `${slot} has no method ${method}.`);
|
|
59
|
+
// JSON both ways, as through the Hub, and checked as JSON.
|
|
60
|
+
const parsed = check(spec.input, JSON.parse(JSON.stringify(input ?? null)), `${slot}.${method} input`);
|
|
61
|
+
const handler = Object.hasOwn(handlers, method) ? handlers[method] : undefined;
|
|
62
|
+
if (!handler)
|
|
63
|
+
throw new Refused("unimplemented", `${slot}.${method} isn't faked.`);
|
|
64
|
+
const output = check(spec.output, await handler(parsed, { caller: self }), `${slot}.${method} output`, "bad_output");
|
|
65
|
+
return JSON.parse(JSON.stringify(output ?? null));
|
|
66
|
+
},
|
|
67
|
+
subscribe(event, onEvent) {
|
|
68
|
+
const set = listeners.get(event) ?? new Set();
|
|
69
|
+
listeners.set(event, set);
|
|
70
|
+
set.add(onEvent);
|
|
71
|
+
return () => void set.delete(onEvent);
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
return {
|
|
75
|
+
emit(event, payload) {
|
|
76
|
+
const spec = Object.hasOwn(iface.events, event) ? iface.events[event] : undefined;
|
|
77
|
+
if (!spec)
|
|
78
|
+
throw new TypeError(`${slot} has no event ${event}.`);
|
|
79
|
+
const value = JSON.parse(JSON.stringify(check(spec.payload, payload, `${slot}.${event}`, "bad_output")));
|
|
80
|
+
for (const fn of [...(listeners.get(event) ?? [])])
|
|
81
|
+
fn(value);
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
},
|
|
85
|
+
unexpose: (slot) => runtime.unexpose(slot),
|
|
86
|
+
emitted,
|
|
87
|
+
logs,
|
|
88
|
+
};
|
|
89
|
+
}
|
|
@@ -333,9 +333,22 @@ a {
|
|
|
333
333
|
.stage {
|
|
334
334
|
flex: 1;
|
|
335
335
|
min-height: 0;
|
|
336
|
-
display: flex;
|
|
337
336
|
gap: 8px;
|
|
338
337
|
}
|
|
338
|
+
/* The resizable panels hold the chat and the column: what's inside fills them. */
|
|
339
|
+
.panel {
|
|
340
|
+
display: flex;
|
|
341
|
+
flex-direction: column;
|
|
342
|
+
min-width: 0;
|
|
343
|
+
}
|
|
344
|
+
.panel > * {
|
|
345
|
+
flex: 1;
|
|
346
|
+
min-height: 0;
|
|
347
|
+
}
|
|
348
|
+
/* In the gap between the chat and the widgets: it takes no room, and only its line shows. */
|
|
349
|
+
.stage > .kit-resize-handle {
|
|
350
|
+
margin: 0 -8px;
|
|
351
|
+
}
|
|
339
352
|
.container {
|
|
340
353
|
background: var(--surface);
|
|
341
354
|
border-radius: var(--radius);
|
|
@@ -349,40 +362,16 @@ a {
|
|
|
349
362
|
flex: 1;
|
|
350
363
|
}
|
|
351
364
|
.widgets {
|
|
352
|
-
/* Its width is the divider's, and never more than half the stage. */
|
|
353
|
-
max-width: 50%;
|
|
354
|
-
flex: none;
|
|
355
365
|
display: flex;
|
|
356
366
|
flex-direction: column;
|
|
357
367
|
gap: 8px;
|
|
358
368
|
min-height: 0;
|
|
359
369
|
}
|
|
370
|
+
/* The column's height is shared: each widget fills its share, at least 220 px, never its content's. */
|
|
360
371
|
.widgets .container {
|
|
361
|
-
flex:
|
|
362
|
-
|
|
363
|
-
/* In the gap between the chat and the widgets: it takes no room, and only its line shows. */
|
|
364
|
-
.divider {
|
|
365
|
-
width: 8px;
|
|
366
|
-
margin: 0 -8px;
|
|
367
|
-
flex: none;
|
|
368
|
-
cursor: col-resize;
|
|
369
|
-
touch-action: none;
|
|
370
|
-
display: flex;
|
|
371
|
-
justify-content: center;
|
|
372
|
-
outline: 0;
|
|
373
|
-
}
|
|
374
|
-
.divider::after {
|
|
375
|
-
content: "";
|
|
376
|
-
width: 2px;
|
|
377
|
-
border-radius: 1px;
|
|
378
|
-
background: transparent;
|
|
379
|
-
}
|
|
380
|
-
.divider:hover::after,
|
|
381
|
-
.divider:focus-visible::after,
|
|
382
|
-
.divider:active::after {
|
|
383
|
-
background: var(--ring);
|
|
372
|
+
flex: 1 1 0;
|
|
373
|
+
min-height: 220px;
|
|
384
374
|
}
|
|
385
|
-
|
|
386
375
|
/* A placed view's frame: its header is the shell's, the body is the view's own DOM. */
|
|
387
376
|
.view-head {
|
|
388
377
|
height: 40px;
|
|
@@ -398,18 +387,16 @@ a {
|
|
|
398
387
|
color: var(--muted);
|
|
399
388
|
font-weight: 400;
|
|
400
389
|
}
|
|
401
|
-
.view-head .icon-
|
|
390
|
+
.view-head .kit-icon-button {
|
|
402
391
|
margin-left: auto;
|
|
403
392
|
width: 26px;
|
|
404
393
|
height: 26px;
|
|
405
394
|
}
|
|
395
|
+
/* The frame fills what its placement leaves under the header. */
|
|
406
396
|
.view-body {
|
|
407
397
|
padding: 4px 14px 14px;
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
/* Its view reported its height: the frame takes it, and the body fits the frame. */
|
|
411
|
-
.view-body.sized {
|
|
412
|
-
height: auto;
|
|
398
|
+
flex: 1;
|
|
399
|
+
min-height: 0;
|
|
413
400
|
}
|
|
414
401
|
/*
|
|
415
402
|
* A view's own frame. Its color scheme is the frame document's, so the browser paints no backdrop
|
|
@@ -434,36 +421,11 @@ a {
|
|
|
434
421
|
color: var(--muted);
|
|
435
422
|
font-size: 13px;
|
|
436
423
|
}
|
|
437
|
-
.menu {
|
|
438
|
-
position: absolute;
|
|
439
|
-
right: 8px;
|
|
440
|
-
top: 38px;
|
|
441
|
-
background: var(--raised);
|
|
442
|
-
border-radius: 10px;
|
|
443
|
-
padding: 4px;
|
|
444
|
-
min-width: 150px;
|
|
445
|
-
z-index: 5;
|
|
446
|
-
box-shadow: 0 12px 28px rgb(0 0 0 / 0.35);
|
|
447
|
-
}
|
|
448
|
-
.menu button {
|
|
449
|
-
display: block;
|
|
450
|
-
width: 100%;
|
|
451
|
-
text-align: left;
|
|
452
|
-
border: 0;
|
|
453
|
-
background: transparent;
|
|
454
|
-
padding: 7px 10px;
|
|
455
|
-
border-radius: 7px;
|
|
456
|
-
font-size: 13px;
|
|
457
|
-
}
|
|
458
|
-
.menu button:hover {
|
|
459
|
-
background: var(--hover);
|
|
460
|
-
}
|
|
461
|
-
.menu button:disabled,
|
|
462
424
|
.ghost:disabled {
|
|
463
425
|
opacity: 0.6;
|
|
464
426
|
cursor: default;
|
|
465
427
|
}
|
|
466
|
-
.menu-note {
|
|
428
|
+
.kit-menu .menu-note {
|
|
467
429
|
text-align: left;
|
|
468
430
|
padding: 4px 10px 6px;
|
|
469
431
|
max-width: 200px;
|
|
@@ -478,10 +440,14 @@ a {
|
|
|
478
440
|
align-content: start;
|
|
479
441
|
align-items: start;
|
|
480
442
|
}
|
|
443
|
+
/* Home's placements have a height of their own; the view fills it. */
|
|
481
444
|
.home .placed {
|
|
482
445
|
background: var(--card);
|
|
483
446
|
border-radius: 12px;
|
|
484
447
|
position: relative;
|
|
448
|
+
height: 300px;
|
|
449
|
+
display: flex;
|
|
450
|
+
flex-direction: column;
|
|
485
451
|
}
|
|
486
452
|
.home-empty {
|
|
487
453
|
margin: auto;
|
|
@@ -537,28 +503,6 @@ a {
|
|
|
537
503
|
flex: 1;
|
|
538
504
|
min-height: 0;
|
|
539
505
|
}
|
|
540
|
-
.tabs {
|
|
541
|
-
display: inline-flex;
|
|
542
|
-
gap: 2px;
|
|
543
|
-
background: var(--hover);
|
|
544
|
-
padding: 3px;
|
|
545
|
-
border-radius: 10px;
|
|
546
|
-
align-self: flex-start;
|
|
547
|
-
}
|
|
548
|
-
.tabs button {
|
|
549
|
-
border: 0;
|
|
550
|
-
background: transparent;
|
|
551
|
-
padding: 5px 12px;
|
|
552
|
-
border-radius: 8px;
|
|
553
|
-
font-size: 13px;
|
|
554
|
-
color: var(--muted);
|
|
555
|
-
}
|
|
556
|
-
.tabs button[aria-selected="true"] {
|
|
557
|
-
background: var(--surface);
|
|
558
|
-
color: var(--fg);
|
|
559
|
-
font-weight: 600;
|
|
560
|
-
box-shadow: 0 1px 2px rgb(0 0 0 / 0.2);
|
|
561
|
-
}
|
|
562
506
|
table {
|
|
563
507
|
width: 100%;
|
|
564
508
|
border-collapse: collapse;
|
|
@@ -603,29 +547,6 @@ tr:hover td {
|
|
|
603
547
|
}
|
|
604
548
|
|
|
605
549
|
/* ---------- Dialog ---------- */
|
|
606
|
-
.scrim {
|
|
607
|
-
position: fixed;
|
|
608
|
-
inset: 0;
|
|
609
|
-
background: rgb(0 0 0 / 0.5);
|
|
610
|
-
display: grid;
|
|
611
|
-
place-items: center;
|
|
612
|
-
z-index: 20;
|
|
613
|
-
padding: 16px;
|
|
614
|
-
}
|
|
615
|
-
.dialog {
|
|
616
|
-
width: min(440px, 100%);
|
|
617
|
-
background: var(--surface);
|
|
618
|
-
border-radius: 18px;
|
|
619
|
-
padding: 20px;
|
|
620
|
-
display: flex;
|
|
621
|
-
flex-direction: column;
|
|
622
|
-
gap: 16px;
|
|
623
|
-
box-shadow: 0 24px 60px rgb(0 0 0 / 0.45);
|
|
624
|
-
}
|
|
625
|
-
.dialog h2 {
|
|
626
|
-
margin: 0;
|
|
627
|
-
font-size: 16px;
|
|
628
|
-
}
|
|
629
550
|
.field {
|
|
630
551
|
height: 38px;
|
|
631
552
|
border-radius: 10px;
|
|
@@ -658,38 +579,6 @@ tr:hover td {
|
|
|
658
579
|
.grants .mono {
|
|
659
580
|
margin-left: auto;
|
|
660
581
|
}
|
|
661
|
-
.toggle {
|
|
662
|
-
width: 30px;
|
|
663
|
-
height: 18px;
|
|
664
|
-
border-radius: 9px;
|
|
665
|
-
background: var(--raised);
|
|
666
|
-
border: 0;
|
|
667
|
-
position: relative;
|
|
668
|
-
padding: 0;
|
|
669
|
-
flex: none;
|
|
670
|
-
}
|
|
671
|
-
.toggle::after {
|
|
672
|
-
content: "";
|
|
673
|
-
position: absolute;
|
|
674
|
-
top: 2px;
|
|
675
|
-
left: 2px;
|
|
676
|
-
width: 14px;
|
|
677
|
-
height: 14px;
|
|
678
|
-
border-radius: 50%;
|
|
679
|
-
background: var(--faint);
|
|
680
|
-
transition: left 0.12s;
|
|
681
|
-
}
|
|
682
|
-
.toggle[aria-checked="true"] {
|
|
683
|
-
background: var(--ok);
|
|
684
|
-
}
|
|
685
|
-
.toggle[aria-checked="true"]::after {
|
|
686
|
-
left: 14px;
|
|
687
|
-
background: white;
|
|
688
|
-
}
|
|
689
|
-
.toggle:disabled {
|
|
690
|
-
opacity: 0.5;
|
|
691
|
-
cursor: default;
|
|
692
|
-
}
|
|
693
582
|
.actions {
|
|
694
583
|
display: flex;
|
|
695
584
|
justify-content: flex-end;
|
|
@@ -712,12 +601,6 @@ tr:hover td {
|
|
|
712
601
|
font-size: 13px;
|
|
713
602
|
}
|
|
714
603
|
|
|
715
|
-
@media (max-width: 1100px) {
|
|
716
|
-
.widgets,
|
|
717
|
-
.divider {
|
|
718
|
-
display: none;
|
|
719
|
-
}
|
|
720
|
-
}
|
|
721
604
|
@media (max-width: 760px) {
|
|
722
605
|
.sidebar {
|
|
723
606
|
display: none;
|
|
@@ -858,7 +741,7 @@ tr:hover td {
|
|
|
858
741
|
color: var(--muted);
|
|
859
742
|
font-size: 13px;
|
|
860
743
|
}
|
|
861
|
-
.dialog .steps {
|
|
744
|
+
.kit-dialog .steps {
|
|
862
745
|
display: flex;
|
|
863
746
|
flex-direction: column;
|
|
864
747
|
gap: 14px;
|