@geohar/un-bien 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +726 -0
- package/dist/actions/handlers.d.ts +77 -0
- package/dist/actions/handlers.js +26 -0
- package/dist/actions/handlers.js.map +1 -0
- package/dist/actions/registry.d.ts +39 -0
- package/dist/actions/registry.js +62 -0
- package/dist/actions/registry.js.map +1 -0
- package/dist/bin/supervisord.d.ts +2 -0
- package/dist/bin/supervisord.js +86 -0
- package/dist/bin/supervisord.js.map +1 -0
- package/dist/config.d.ts +84 -0
- package/dist/config.js +115 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon/client.d.ts +20 -0
- package/dist/daemon/client.js +131 -0
- package/dist/daemon/client.js.map +1 -0
- package/dist/daemon/control_protocol.d.ts +176 -0
- package/dist/daemon/control_protocol.js +63 -0
- package/dist/daemon/control_protocol.js.map +1 -0
- package/dist/daemon/cron_log.d.ts +45 -0
- package/dist/daemon/cron_log.js +71 -0
- package/dist/daemon/cron_log.js.map +1 -0
- package/dist/daemon/cron_registry.d.ts +80 -0
- package/dist/daemon/cron_registry.js +198 -0
- package/dist/daemon/cron_registry.js.map +1 -0
- package/dist/daemon/id.d.ts +24 -0
- package/dist/daemon/id.js +36 -0
- package/dist/daemon/id.js.map +1 -0
- package/dist/daemon/install.d.ts +170 -0
- package/dist/daemon/install.js +603 -0
- package/dist/daemon/install.js.map +1 -0
- package/dist/daemon/registry.d.ts +63 -0
- package/dist/daemon/registry.js +153 -0
- package/dist/daemon/registry.js.map +1 -0
- package/dist/daemon/rpc_child.d.ts +194 -0
- package/dist/daemon/rpc_child.js +419 -0
- package/dist/daemon/rpc_child.js.map +1 -0
- package/dist/daemon/supervisor.d.ts +93 -0
- package/dist/daemon/supervisor.js +666 -0
- package/dist/daemon/supervisor.js.map +1 -0
- package/dist/extension_ui_bridge.d.ts +26 -0
- package/dist/extension_ui_bridge.js +341 -0
- package/dist/extension_ui_bridge.js.map +1 -0
- package/dist/index.d.ts +197 -0
- package/dist/index.js +5750 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/mesh_result.d.ts +10 -0
- package/dist/mcp/mesh_result.js +42 -0
- package/dist/mcp/mesh_result.js.map +1 -0
- package/dist/mcp/mesh_server.d.ts +16 -0
- package/dist/mcp/mesh_server.js +373 -0
- package/dist/mcp/mesh_server.js.map +1 -0
- package/dist/mesh/canonical.d.ts +30 -0
- package/dist/mesh/canonical.js +63 -0
- package/dist/mesh/canonical.js.map +1 -0
- package/dist/mesh/client.d.ts +18 -0
- package/dist/mesh/client.js +127 -0
- package/dist/mesh/client.js.map +1 -0
- package/dist/mesh/encoding.d.ts +38 -0
- package/dist/mesh/encoding.js +217 -0
- package/dist/mesh/encoding.js.map +1 -0
- package/dist/mesh/self_revoke.d.ts +73 -0
- package/dist/mesh/self_revoke.js +407 -0
- package/dist/mesh/self_revoke.js.map +1 -0
- package/dist/mesh/siblings.d.ts +49 -0
- package/dist/mesh/siblings.js +159 -0
- package/dist/mesh/siblings.js.map +1 -0
- package/dist/mesh/types.d.ts +34 -0
- package/dist/mesh/types.js +11 -0
- package/dist/mesh/types.js.map +1 -0
- package/dist/mesh/verify.d.ts +17 -0
- package/dist/mesh/verify.js +86 -0
- package/dist/mesh/verify.js.map +1 -0
- package/dist/pairing/crypto.d.ts +8 -0
- package/dist/pairing/crypto.js +22 -0
- package/dist/pairing/crypto.js.map +1 -0
- package/dist/pairing/qr.d.ts +59 -0
- package/dist/pairing/qr.js +127 -0
- package/dist/pairing/qr.js.map +1 -0
- package/dist/pairing/storage.d.ts +120 -0
- package/dist/pairing/storage.js +614 -0
- package/dist/pairing/storage.js.map +1 -0
- package/dist/panel_bridge.d.ts +15 -0
- package/dist/panel_bridge.js +409 -0
- package/dist/panel_bridge.js.map +1 -0
- package/dist/paths.d.ts +39 -0
- package/dist/paths.js +51 -0
- package/dist/paths.js.map +1 -0
- package/dist/protocol/codec.d.ts +7 -0
- package/dist/protocol/codec.js +48 -0
- package/dist/protocol/codec.js.map +1 -0
- package/dist/protocol/types.d.ts +404 -0
- package/dist/protocol/types.js +2 -0
- package/dist/protocol/types.js.map +1 -0
- package/dist/rooms.d.ts +42 -0
- package/dist/rooms.js +78 -0
- package/dist/rooms.js.map +1 -0
- package/dist/session/bridge.d.ts +37 -0
- package/dist/session/bridge.js +134 -0
- package/dist/session/bridge.js.map +1 -0
- package/dist/session/broker.d.ts +189 -0
- package/dist/session/broker.js +527 -0
- package/dist/session/broker.js.map +1 -0
- package/dist/session/broker_remote.d.ts +74 -0
- package/dist/session/broker_remote.js +581 -0
- package/dist/session/broker_remote.js.map +1 -0
- package/dist/session/cwd_lock.d.ts +33 -0
- package/dist/session/cwd_lock.js +127 -0
- package/dist/session/cwd_lock.js.map +1 -0
- package/dist/session/debug_log.d.ts +3 -0
- package/dist/session/debug_log.js +32 -0
- package/dist/session/debug_log.js.map +1 -0
- package/dist/session/envelope.d.ts +33 -0
- package/dist/session/envelope.js +117 -0
- package/dist/session/envelope.js.map +1 -0
- package/dist/session/global_config.d.ts +33 -0
- package/dist/session/global_config.js +73 -0
- package/dist/session/global_config.js.map +1 -0
- package/dist/session/ipc.d.ts +27 -0
- package/dist/session/ipc.js +22 -0
- package/dist/session/ipc.js.map +1 -0
- package/dist/session/leader_election.d.ts +32 -0
- package/dist/session/leader_election.js +108 -0
- package/dist/session/leader_election.js.map +1 -0
- package/dist/session/local_config.d.ts +67 -0
- package/dist/session/local_config.js +193 -0
- package/dist/session/local_config.js.map +1 -0
- package/dist/session/mesh_node.d.ts +116 -0
- package/dist/session/mesh_node.js +596 -0
- package/dist/session/mesh_node.js.map +1 -0
- package/dist/session/peer.d.ts +139 -0
- package/dist/session/peer.js +474 -0
- package/dist/session/peer.js.map +1 -0
- package/dist/session/peer_inventory.d.ts +13 -0
- package/dist/session/peer_inventory.js +48 -0
- package/dist/session/peer_inventory.js.map +1 -0
- package/dist/session/peer_limits.d.ts +9 -0
- package/dist/session/peer_limits.js +24 -0
- package/dist/session/peer_limits.js.map +1 -0
- package/dist/session/rpc_envelope.d.ts +108 -0
- package/dist/session/rpc_envelope.js +221 -0
- package/dist/session/rpc_envelope.js.map +1 -0
- package/dist/session/rpc_inbound.d.ts +55 -0
- package/dist/session/rpc_inbound.js +136 -0
- package/dist/session/rpc_inbound.js.map +1 -0
- package/dist/session/setup_wizard.d.ts +39 -0
- package/dist/session/setup_wizard.js +63 -0
- package/dist/session/setup_wizard.js.map +1 -0
- package/dist/session/tools.d.ts +24 -0
- package/dist/session/tools.js +272 -0
- package/dist/session/tools.js.map +1 -0
- package/dist/session/wizard.d.ts +13 -0
- package/dist/session/wizard.js +20 -0
- package/dist/session/wizard.js.map +1 -0
- package/dist/transport/peer_channel.d.ts +52 -0
- package/dist/transport/peer_channel.js +145 -0
- package/dist/transport/peer_channel.js.map +1 -0
- package/dist/transport/pi_forward_client.d.ts +29 -0
- package/dist/transport/pi_forward_client.js +68 -0
- package/dist/transport/pi_forward_client.js.map +1 -0
- package/dist/transport/relay_client.d.ts +96 -0
- package/dist/transport/relay_client.js +210 -0
- package/dist/transport/relay_client.js.map +1 -0
- package/dist/ui/footer.d.ts +32 -0
- package/dist/ui/footer.js +34 -0
- package/dist/ui/footer.js.map +1 -0
- package/docs/daemon.md +289 -0
- package/package.json +92 -0
- package/service-templates/launchd.plist.template +35 -0
- package/service-templates/systemd.service.template +19 -0
- package/service-templates/task-launcher.vbs.template +10 -0
- package/service-templates/task-scheduler.xml.template +38 -0
- package/skills/agent-network/SKILL.md +310 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plan/25 Wave D — pure formatter for the `/unbien peers` output.
|
|
3
|
+
*
|
|
4
|
+
* Lives in its own module so it can be unit-tested without booting the full
|
|
5
|
+
* extension (no keychain access, no relay client, no mocks needed). The
|
|
6
|
+
* extension imports the function and wraps it with the `_sessionPeer`
|
|
7
|
+
* `list_peers` request.
|
|
8
|
+
*
|
|
9
|
+
* Input shape: the broker's `list_peers_reply` body returns peer names as
|
|
10
|
+
* plain strings — local peers without a prefix (`sess-1`, `agent-2`),
|
|
11
|
+
* cross-PC peers with a `<pc_label>:<peer>` prefix (`casa:sess-3`).
|
|
12
|
+
*/
|
|
13
|
+
export function formatPeerInventory(peers, selfName) {
|
|
14
|
+
const locals = [];
|
|
15
|
+
const remotes = new Map();
|
|
16
|
+
for (const p of peers) {
|
|
17
|
+
if (selfName && p === selfName)
|
|
18
|
+
continue;
|
|
19
|
+
const idx = p.indexOf(":");
|
|
20
|
+
if (idx > 0 && idx < p.length - 1) {
|
|
21
|
+
const label = p.slice(0, idx);
|
|
22
|
+
const name = p.slice(idx + 1);
|
|
23
|
+
const bucket = remotes.get(label) ?? [];
|
|
24
|
+
bucket.push(name);
|
|
25
|
+
remotes.set(label, bucket);
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
locals.push(p);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
const lines = [" local:"];
|
|
32
|
+
if (locals.length === 0) {
|
|
33
|
+
lines.push(" (none)");
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
for (const n of locals.sort())
|
|
37
|
+
lines.push(` ${n}`);
|
|
38
|
+
}
|
|
39
|
+
const sortedLabels = [...remotes.keys()].sort();
|
|
40
|
+
for (const label of sortedLabels) {
|
|
41
|
+
lines.push("");
|
|
42
|
+
lines.push(` remote:${label}`);
|
|
43
|
+
for (const n of (remotes.get(label) ?? []).sort())
|
|
44
|
+
lines.push(` ${n}`);
|
|
45
|
+
}
|
|
46
|
+
return lines.join("\n");
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=peer_inventory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer_inventory.js","sourceRoot":"","sources":["../../src/session/peer_inventory.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,MAAM,UAAU,mBAAmB,CACjC,KAAe,EACf,QAAiB;IAEjB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,MAAM,OAAO,GAAG,IAAI,GAAG,EAAoB,CAAC;IAC5C,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;QACtB,IAAI,QAAQ,IAAI,CAAC,KAAK,QAAQ;YAAE,SAAS;QACzC,MAAM,GAAG,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QAC3B,IAAI,GAAG,GAAG,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAClC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;YAC9B,MAAM,IAAI,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;YAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClB,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACjB,CAAC;IACH,CAAC;IACD,MAAM,KAAK,GAAa,CAAC,UAAU,CAAC,CAAC;IACrC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxB,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC3B,CAAC;SAAM,CAAC;QACN,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,IAAI,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IACxD,CAAC;IACD,MAAM,YAAY,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;IAChD,KAAK,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;QACjC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACf,KAAK,CAAC,IAAI,CAAC,YAAY,KAAK,EAAE,CAAC,CAAC;QAChC,KAAK,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC5E,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { PeerInfo } from "./broker.js";
|
|
2
|
+
/** Shared wire limits measured in JavaScript UTF-16 code units (`.length`). */
|
|
3
|
+
export declare const MAX_PEERS_UPDATE_ENTRIES = 1024;
|
|
4
|
+
export declare const MAX_CWD_LENGTH = 4096;
|
|
5
|
+
export declare const MAX_NAME_LENGTH = 256;
|
|
6
|
+
export declare const MAX_ADDRESS_LENGTH = 4352;
|
|
7
|
+
export declare function isBoundedPeerInfo(value: unknown): value is PeerInfo;
|
|
8
|
+
export declare function isBoundedPeerRoster(infos: readonly PeerInfo[]): boolean;
|
|
9
|
+
export declare function isBoundedPeerAddresses(addresses: readonly unknown[]): boolean;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/** Shared wire limits measured in JavaScript UTF-16 code units (`.length`). */
|
|
2
|
+
export const MAX_PEERS_UPDATE_ENTRIES = 1024;
|
|
3
|
+
export const MAX_CWD_LENGTH = 4096;
|
|
4
|
+
export const MAX_NAME_LENGTH = 256;
|
|
5
|
+
export const MAX_ADDRESS_LENGTH = 4352;
|
|
6
|
+
export function isBoundedPeerInfo(value) {
|
|
7
|
+
if (!value || typeof value !== "object")
|
|
8
|
+
return false;
|
|
9
|
+
const { cwd, name, address } = value;
|
|
10
|
+
return (typeof cwd === "string" &&
|
|
11
|
+
cwd.length <= MAX_CWD_LENGTH &&
|
|
12
|
+
typeof name === "string" &&
|
|
13
|
+
name.length <= MAX_NAME_LENGTH &&
|
|
14
|
+
typeof address === "string" &&
|
|
15
|
+
address.length <= MAX_ADDRESS_LENGTH);
|
|
16
|
+
}
|
|
17
|
+
export function isBoundedPeerRoster(infos) {
|
|
18
|
+
return (infos.length <= MAX_PEERS_UPDATE_ENTRIES && infos.every(isBoundedPeerInfo));
|
|
19
|
+
}
|
|
20
|
+
export function isBoundedPeerAddresses(addresses) {
|
|
21
|
+
return (addresses.length <= MAX_PEERS_UPDATE_ENTRIES &&
|
|
22
|
+
addresses.every((address) => typeof address === "string" && address.length <= MAX_ADDRESS_LENGTH));
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=peer_limits.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer_limits.js","sourceRoot":"","sources":["../../src/session/peer_limits.ts"],"names":[],"mappings":"AAEA,+EAA+E;AAC/E,MAAM,CAAC,MAAM,wBAAwB,GAAG,IAAI,CAAC;AAC7C,MAAM,CAAC,MAAM,cAAc,GAAG,IAAI,CAAC;AACnC,MAAM,CAAC,MAAM,eAAe,GAAG,GAAG,CAAC;AACnC,MAAM,CAAC,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEvC,MAAM,UAAU,iBAAiB,CAAC,KAAc;IAC9C,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACtD,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,KAAiB,CAAC;IACjD,OAAO,CACL,OAAO,GAAG,KAAK,QAAQ;QACvB,GAAG,CAAC,MAAM,IAAI,cAAc;QAC5B,OAAO,IAAI,KAAK,QAAQ;QACxB,IAAI,CAAC,MAAM,IAAI,eAAe;QAC9B,OAAO,OAAO,KAAK,QAAQ;QAC3B,OAAO,CAAC,MAAM,IAAI,kBAAkB,CACrC,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAA0B;IAC5D,OAAO,CACL,KAAK,CAAC,MAAM,IAAI,wBAAwB,IAAI,KAAK,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAC3E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,SAA6B;IAClE,OAAO,CACL,SAAS,CAAC,MAAM,IAAI,wBAAwB;QAC5C,SAAS,CAAC,KAAK,CACb,CAAC,OAAO,EAAE,EAAE,CACV,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,CAAC,MAAM,IAAI,kBAAkB,CACtE,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
/**
|
|
3
|
+
* One mesh-envelope wrapper message (docs/rpc-envelope.md). `type` is the
|
|
4
|
+
* PROTOCOL-NAMESPACE discriminator (NOT direction) and names the payload field:
|
|
5
|
+
* "rpc" -> `.rpc` — byte-faithful pi rpc frame (pi's rpc handler acts).
|
|
6
|
+
* "evt" -> `.evt` — forwarded pi bus event (app view plane).
|
|
7
|
+
* "ub" -> `.ub` — un-bien's OWN protocol; inner `.type` = hello /
|
|
8
|
+
* session_sync / session_launch / ...; the inner type +
|
|
9
|
+
* receiver role decide who acts and which direction.
|
|
10
|
+
* Direction is carried by the inner frame `.type` + receiver role, never `type`.
|
|
11
|
+
* `ts` (epoch ms) and `protocolVersion` (decode-guard) are cross-cutting and stay
|
|
12
|
+
* top-level. Each plane now stamps its real type ("rpc"/"evt"/"ub"); legacy
|
|
13
|
+
* `"env"` is still ACCEPTED on read for one transition, never stamped.
|
|
14
|
+
*/
|
|
15
|
+
export interface EnvelopeMessage {
|
|
16
|
+
type?: string;
|
|
17
|
+
ts?: number;
|
|
18
|
+
/** Envelope/pi-rpc protocol version for client decode-guarding. Cross-cutting. */
|
|
19
|
+
protocolVersion?: number;
|
|
20
|
+
rpc?: unknown;
|
|
21
|
+
/** un-bien display sidecar riding ALONGSIDE `rpc` in the same envelope. For
|
|
22
|
+
* edit-family `tool_execution_start` frames it carries `{ hunks }` display
|
|
23
|
+
* diff data; the `rpc` frame itself stays byte-faithful (raw args). */
|
|
24
|
+
aux?: {
|
|
25
|
+
hunks?: unknown[];
|
|
26
|
+
} & Record<string, unknown>;
|
|
27
|
+
evt?: {
|
|
28
|
+
channel: string;
|
|
29
|
+
data: unknown;
|
|
30
|
+
};
|
|
31
|
+
/** un-bien's own protocol plane (`type:"ub"`). The inner frame is one of
|
|
32
|
+
* ``UbFrame`` — handshake fields (caps, sessionId) nest in the `hello`
|
|
33
|
+
* variant, NOT at the envelope top level. */
|
|
34
|
+
ub?: UbFrame;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The un-bien plane's inner frames — un-bien's OWN protocol (we own these, so
|
|
38
|
+
* they are typed, unlike the opaque byte-faithful pi `rpc` frame). The inner
|
|
39
|
+
* `.type` + receiver role decide who acts and which direction it flows.
|
|
40
|
+
*/
|
|
41
|
+
export type UbFrame = {
|
|
42
|
+
type: "hello";
|
|
43
|
+
caps: string[];
|
|
44
|
+
sessionId?: string;
|
|
45
|
+
} | {
|
|
46
|
+
type: "session_sync";
|
|
47
|
+
id?: string;
|
|
48
|
+
limit?: number;
|
|
49
|
+
} | {
|
|
50
|
+
type: "session_sync_end";
|
|
51
|
+
in_reply_to?: string;
|
|
52
|
+
session_started_at?: number;
|
|
53
|
+
truncated?: boolean;
|
|
54
|
+
} | {
|
|
55
|
+
type: "session_launch";
|
|
56
|
+
id?: string;
|
|
57
|
+
mode: string;
|
|
58
|
+
cwd?: string;
|
|
59
|
+
name?: string;
|
|
60
|
+
};
|
|
61
|
+
/** Legacy wrapper marker for the rpc/evt plane — still stamped + accepted during
|
|
62
|
+
* the transition (the explicit rpc/evt namespace split is a later wave). */
|
|
63
|
+
export declare const ENVELOPE_KIND = "env";
|
|
64
|
+
/** un-bien-owned plane wrapper marker. */
|
|
65
|
+
export declare const UB_KIND = "ub";
|
|
66
|
+
/** pi-owned plane wrapper markers: the rpc spine + the evt view plane. */
|
|
67
|
+
export declare const RPC_KIND = "rpc";
|
|
68
|
+
export declare const EVT_KIND = "evt";
|
|
69
|
+
/**
|
|
70
|
+
* True if a decoded inbound object is a mesh-envelope frame (any plane) rather
|
|
71
|
+
* than a stock ClientMessage — by REAL wrapper type ("rpc"/"evt"/"ub", or legacy
|
|
72
|
+
* "env" accepted one transition) OR by payload FIELD-PRESENCE. The single source
|
|
73
|
+
* of truth for both inbound guards (PlainPeerChannel._onLine + index.ts's
|
|
74
|
+
* reconnect attach path) so they cannot drift — kept intentionally permissive so
|
|
75
|
+
* it routes correctly regardless of which plane's frame arrives first.
|
|
76
|
+
*/
|
|
77
|
+
export declare function isEnvelopeFrame(obj: Record<string, unknown>): boolean;
|
|
78
|
+
/** un-bien-plane INNER frame type for the capability handshake. */
|
|
79
|
+
export declare const HELLO_KIND = "hello";
|
|
80
|
+
/**
|
|
81
|
+
* Build the capability handshake sent to a peer on attach — the envelope-native
|
|
82
|
+
* replacement for the stock `session_history.capabilities`. Rides the un-bien
|
|
83
|
+
* plane (`type:"ub"`) as a `hello` inner frame the APP handles; caps + sessionId
|
|
84
|
+
* nest inside it, protocolVersion stays top-level.
|
|
85
|
+
*/
|
|
86
|
+
export declare function helloEnvelope(caps: string[], sessionId?: string, protocolVersion?: number): EnvelopeMessage;
|
|
87
|
+
type Payload = Record<string, unknown>;
|
|
88
|
+
/** Event names we register a `pi.on()` cue for (the live plane). */
|
|
89
|
+
export declare const RPC_EVENT_NAMES: readonly string[];
|
|
90
|
+
/**
|
|
91
|
+
* Pure map: a `pi.on()` event (name + payload) → its rpc-envelope `{ rpc }`
|
|
92
|
+
* message, or `null` when the event carries no streamed frame. Exported for
|
|
93
|
+
* conformance tests against the captured `pi --mode rpc` corpus.
|
|
94
|
+
*/
|
|
95
|
+
export declare function envelopeForEvent(name: string, payload: Payload): EnvelopeMessage | null;
|
|
96
|
+
/**
|
|
97
|
+
* Register the live-plane `pi.on()` handlers; each fires `broadcast` with the
|
|
98
|
+
* rpc-envelope frame. Returns a handle whose `dispose()` stops broadcasting
|
|
99
|
+
* (pi.on has no unregister, so we gate on a disposed flag).
|
|
100
|
+
*/
|
|
101
|
+
export declare function createRpcEnvelope(pi: ExtensionAPI, broadcast: (env: EnvelopeMessage) => void, opts?: {
|
|
102
|
+
enrichArgs?: (tool: string, args: unknown) => {
|
|
103
|
+
hunks: unknown[];
|
|
104
|
+
} | null;
|
|
105
|
+
}): {
|
|
106
|
+
dispose(): void;
|
|
107
|
+
};
|
|
108
|
+
export {};
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
// Reconstruct pi's `--mode rpc` EVENT PLANE in-process from `pi.on()` and
|
|
2
|
+
// broadcast each frame as an rpc-envelope `{ rpc }` message.
|
|
3
|
+
//
|
|
4
|
+
// `pi --mode rpc` builds its event stream by subscribing to the session and
|
|
5
|
+
// piping every `AgentSessionEvent` through `toJsonEvent` (pi
|
|
6
|
+
// modes/rpc/rpc-mode.ts:355 `session.subscribe(e => output(toJsonEvent(e)))`).
|
|
7
|
+
// An in-process extension can't call `session.subscribe` (host-only), but
|
|
8
|
+
// `pi.on()` delivers the same underlying events — so we source them from the
|
|
9
|
+
// bus instead and emit byte-faithful rpc frames. The only streamed frame
|
|
10
|
+
// `pi.on()` can't give is `entry_appended` (subscribe-only); that's the
|
|
11
|
+
// getEntries reconstruction path, deferred. See docs/rpc-on-event-map.md.
|
|
12
|
+
//
|
|
13
|
+
// Note: extension `on()` payloads are a SUPERSET of the rpc/AgentEvent frame
|
|
14
|
+
// (e.g. `turn_start` carries `turnIndex`/`timestamp` the rpc frame lacks), so
|
|
15
|
+
// each builder selects exactly the rpc fields rather than passing the payload
|
|
16
|
+
// through.
|
|
17
|
+
//
|
|
18
|
+
// ⚠️ DRIFT HAZARD — THE FRAME SHAPES BELOW MUST MATCH pi's `--mode rpc` OUTPUT.
|
|
19
|
+
// These builders + `toJsonEvent` reproduce what pi writes to rpc stdout
|
|
20
|
+
// (pi modes/json-event.ts `toJsonEvent` + modes/rpc/rpc-mode.ts `output(...)`,
|
|
21
|
+
// pi 0.84.3). We CANNOT call pi's own function: `@earendil-works/pi-coding-agent`
|
|
22
|
+
// ships an `exports` map that exposes ONLY `.` (dist/index.js), there is no
|
|
23
|
+
// `json-event` module in `dist`, and the `toJsonEvent` symbol appears nowhere
|
|
24
|
+
// in the published package (inlined away) — so it is neither importable nor
|
|
25
|
+
// deep-importable. This is therefore a HAND-KEPT MIRROR. If pi changes a wire
|
|
26
|
+
// frame, this drifts silently. The guard is CONFORMANCE against the captured
|
|
27
|
+
// real `pi --mode rpc` corpus (un-bien Tests/Fixtures/rpc-stream/*, the actual
|
|
28
|
+
// pi bytes; see docs/rpc-on-event-map.md + the cross-repo corpus plan item):
|
|
29
|
+
// replay those and assert our output matches. Update BOTH this file and the
|
|
30
|
+
// fixtures together when bumping the pinned pi version.
|
|
31
|
+
/** Legacy wrapper marker for the rpc/evt plane — still stamped + accepted during
|
|
32
|
+
* the transition (the explicit rpc/evt namespace split is a later wave). */
|
|
33
|
+
export const ENVELOPE_KIND = "env";
|
|
34
|
+
/** un-bien-owned plane wrapper marker. */
|
|
35
|
+
export const UB_KIND = "ub";
|
|
36
|
+
/** pi-owned plane wrapper markers: the rpc spine + the evt view plane. */
|
|
37
|
+
export const RPC_KIND = "rpc";
|
|
38
|
+
export const EVT_KIND = "evt";
|
|
39
|
+
/**
|
|
40
|
+
* True if a decoded inbound object is a mesh-envelope frame (any plane) rather
|
|
41
|
+
* than a stock ClientMessage — by REAL wrapper type ("rpc"/"evt"/"ub", or legacy
|
|
42
|
+
* "env" accepted one transition) OR by payload FIELD-PRESENCE. The single source
|
|
43
|
+
* of truth for both inbound guards (PlainPeerChannel._onLine + index.ts's
|
|
44
|
+
* reconnect attach path) so they cannot drift — kept intentionally permissive so
|
|
45
|
+
* it routes correctly regardless of which plane's frame arrives first.
|
|
46
|
+
*/
|
|
47
|
+
export function isEnvelopeFrame(obj) {
|
|
48
|
+
return (obj.type === RPC_KIND ||
|
|
49
|
+
obj.type === EVT_KIND ||
|
|
50
|
+
obj.type === UB_KIND ||
|
|
51
|
+
obj.type === ENVELOPE_KIND ||
|
|
52
|
+
obj.rpc !== undefined ||
|
|
53
|
+
obj.evt !== undefined ||
|
|
54
|
+
obj.ub !== undefined);
|
|
55
|
+
}
|
|
56
|
+
/** un-bien-plane INNER frame type for the capability handshake. */
|
|
57
|
+
export const HELLO_KIND = "hello";
|
|
58
|
+
/**
|
|
59
|
+
* Build the capability handshake sent to a peer on attach — the envelope-native
|
|
60
|
+
* replacement for the stock `session_history.capabilities`. Rides the un-bien
|
|
61
|
+
* plane (`type:"ub"`) as a `hello` inner frame the APP handles; caps + sessionId
|
|
62
|
+
* nest inside it, protocolVersion stays top-level.
|
|
63
|
+
*/
|
|
64
|
+
export function helloEnvelope(caps, sessionId, protocolVersion = 1) {
|
|
65
|
+
const hello = sessionId
|
|
66
|
+
? { type: "hello", caps, sessionId }
|
|
67
|
+
: { type: "hello", caps };
|
|
68
|
+
return { type: UB_KIND, protocolVersion, ub: hello };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Drop the cumulative `partial` snapshot from a streaming assistant delta so
|
|
72
|
+
* wire size stays linear; a `toolcall_start` keeps the constant-sized `id` +
|
|
73
|
+
* `toolName`. Defensive (no throws) — this runs inside an SDK event callback.
|
|
74
|
+
*
|
|
75
|
+
* ⚠️ MUST MATCH pi `modes/json-event.ts` `toJsonAssistantMessageEvent` byte for
|
|
76
|
+
* byte (unexported — see the module header). Verified against the real
|
|
77
|
+
* `pi --mode rpc` capture; keep the conformance fixtures in lockstep.
|
|
78
|
+
*/
|
|
79
|
+
function stripPartial(ame) {
|
|
80
|
+
if (ame.type === "toolcall_start") {
|
|
81
|
+
const toolCall = ame.partial?.content?.[ame.contentIndex ?? -1];
|
|
82
|
+
const { partial: _p, ...rest } = ame;
|
|
83
|
+
return { ...rest, id: toolCall?.id, toolName: toolCall?.name };
|
|
84
|
+
}
|
|
85
|
+
if (!("partial" in ame))
|
|
86
|
+
return { ...ame };
|
|
87
|
+
const { partial: _p, ...rest } = ame;
|
|
88
|
+
return rest;
|
|
89
|
+
}
|
|
90
|
+
const BUILDERS = {
|
|
91
|
+
agent_start: () => ({ type: "agent_start" }),
|
|
92
|
+
agent_end: (p) => ({
|
|
93
|
+
type: "agent_end",
|
|
94
|
+
messages: p.messages,
|
|
95
|
+
willRetry: p.willRetry ?? false,
|
|
96
|
+
}),
|
|
97
|
+
agent_settled: () => ({ type: "agent_settled" }),
|
|
98
|
+
turn_start: () => ({ type: "turn_start" }),
|
|
99
|
+
turn_end: (p) => ({
|
|
100
|
+
type: "turn_end",
|
|
101
|
+
message: p.message,
|
|
102
|
+
toolResults: p.toolResults ?? [],
|
|
103
|
+
}),
|
|
104
|
+
message_start: (p) => ({ type: "message_start", message: p.message }),
|
|
105
|
+
message_update: (p) => ({
|
|
106
|
+
type: "message_update",
|
|
107
|
+
usage: p.message?.usage,
|
|
108
|
+
assistantMessageEvent: stripPartial((p.assistantMessageEvent ?? {})),
|
|
109
|
+
}),
|
|
110
|
+
message_end: (p) => ({ type: "message_end", message: p.message }),
|
|
111
|
+
tool_execution_start: (p) => ({
|
|
112
|
+
type: "tool_execution_start",
|
|
113
|
+
toolCallId: p.toolCallId,
|
|
114
|
+
toolName: p.toolName,
|
|
115
|
+
args: p.args,
|
|
116
|
+
}),
|
|
117
|
+
tool_execution_update: (p) => ({
|
|
118
|
+
type: "tool_execution_update",
|
|
119
|
+
toolCallId: p.toolCallId,
|
|
120
|
+
toolName: p.toolName,
|
|
121
|
+
args: p.args,
|
|
122
|
+
partialResult: p.partialResult,
|
|
123
|
+
}),
|
|
124
|
+
tool_execution_end: (p) => ({
|
|
125
|
+
type: "tool_execution_end",
|
|
126
|
+
toolCallId: p.toolCallId,
|
|
127
|
+
toolName: p.toolName,
|
|
128
|
+
result: p.result,
|
|
129
|
+
isError: p.isError ?? false,
|
|
130
|
+
}),
|
|
131
|
+
// DEAD ON THE LIVE PLANE — pi does NOT deliver queue_update to extensions.
|
|
132
|
+
// AgentSession._emitQueueUpdate() (pi agent-session.ts) calls only this._emit()
|
|
133
|
+
// (the host `subscribe` stream that `pi --mode rpc` consumes) and NEVER
|
|
134
|
+
// this._extensionRunner.emit(), so pi.on("queue_update") registered from
|
|
135
|
+
// RPC_EVENT_NAMES NEVER FIRES. (Every other event we forward IS fanned to
|
|
136
|
+
// extensions via _emitExtensionEvent(); queue_update is the lone exception, and
|
|
137
|
+
// the ExtensionAPI exposes only hasPendingMessages():boolean — no queue text,
|
|
138
|
+
// no subscribe.) So the fork CANNOT send a queue snapshot; the queued display
|
|
139
|
+
// is APP-OWNED (optimistic chip cleared on model-consumption). Kept only to
|
|
140
|
+
// document the frame shape the app's (now dead) handler once consumed. See
|
|
141
|
+
// design 01M158S7.
|
|
142
|
+
queue_update: (p) => ({
|
|
143
|
+
type: "queue_update",
|
|
144
|
+
steering: p.steering ?? [],
|
|
145
|
+
followUp: p.followUp ?? [],
|
|
146
|
+
}),
|
|
147
|
+
};
|
|
148
|
+
// The extension fires `session_compact` (not the subscribe-only `compaction_end`)
|
|
149
|
+
// with the persisted `compactionEntry`. Remap to the rpc `compaction_end` frame
|
|
150
|
+
// the consumer renders. See docs/rpc-on-event-map.md table A.
|
|
151
|
+
function compactionEndFrame(p) {
|
|
152
|
+
const entry = p.compactionEntry;
|
|
153
|
+
return {
|
|
154
|
+
type: "compaction_end",
|
|
155
|
+
reason: p.reason,
|
|
156
|
+
result: entry
|
|
157
|
+
? { summary: entry.summary, tokensBefore: entry.tokensBefore }
|
|
158
|
+
: null,
|
|
159
|
+
aborted: false,
|
|
160
|
+
willRetry: p.willRetry ?? false,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/** Event names we register a `pi.on()` cue for (the live plane). */
|
|
164
|
+
export const RPC_EVENT_NAMES = [
|
|
165
|
+
...Object.keys(BUILDERS),
|
|
166
|
+
"session_compact",
|
|
167
|
+
];
|
|
168
|
+
/**
|
|
169
|
+
* Pure map: a `pi.on()` event (name + payload) → its rpc-envelope `{ rpc }`
|
|
170
|
+
* message, or `null` when the event carries no streamed frame. Exported for
|
|
171
|
+
* conformance tests against the captured `pi --mode rpc` corpus.
|
|
172
|
+
*/
|
|
173
|
+
export function envelopeForEvent(name, payload) {
|
|
174
|
+
if (name === "session_compact")
|
|
175
|
+
return { rpc: compactionEndFrame(payload) };
|
|
176
|
+
const build = BUILDERS[name];
|
|
177
|
+
return build ? { rpc: build(payload) } : null;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Register the live-plane `pi.on()` handlers; each fires `broadcast` with the
|
|
181
|
+
* rpc-envelope frame. Returns a handle whose `dispose()` stops broadcasting
|
|
182
|
+
* (pi.on has no unregister, so we gate on a disposed flag).
|
|
183
|
+
*/
|
|
184
|
+
export function createRpcEnvelope(pi, broadcast, opts) {
|
|
185
|
+
let disposed = false;
|
|
186
|
+
// SAFETY: pi.on's public typing is a narrower event-name union; the live
|
|
187
|
+
// plane subscribes by string name, which is valid at runtime for every
|
|
188
|
+
// RPC_EVENT_NAMES entry (they are real AgentSessionEvent names).
|
|
189
|
+
const on = pi.on;
|
|
190
|
+
for (const name of RPC_EVENT_NAMES) {
|
|
191
|
+
on(name, (payload) => {
|
|
192
|
+
if (disposed)
|
|
193
|
+
return;
|
|
194
|
+
const p = (payload ?? {});
|
|
195
|
+
let env = envelopeForEvent(name, p);
|
|
196
|
+
if (!env)
|
|
197
|
+
return;
|
|
198
|
+
if (name === "tool_execution_start" && opts?.enrichArgs) {
|
|
199
|
+
const enriched = opts.enrichArgs(p.toolName, p.args);
|
|
200
|
+
if (enriched && Array.isArray(enriched.hunks)) {
|
|
201
|
+
env = { ...env, aux: { hunks: enriched.hunks } };
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
// OUTPUT enrichment is app-side (design 01M177AF): the app classifies the
|
|
205
|
+
// persisted result in its reducer (live + get_entries replay). No
|
|
206
|
+
// aux.output is emitted here; only aux.hunks (input Edit diff) rides live.
|
|
207
|
+
try {
|
|
208
|
+
broadcast(env);
|
|
209
|
+
}
|
|
210
|
+
catch {
|
|
211
|
+
/* best-effort: never let a broadcast error escape into the SDK callback */
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
dispose() {
|
|
217
|
+
disposed = true;
|
|
218
|
+
},
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
//# sourceMappingURL=rpc_envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc_envelope.js","sourceRoot":"","sources":["../../src/session/rpc_envelope.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import type { SessionEntry } from "@earendil-works/pi-coding-agent";
|
|
2
|
+
import type { EnvelopeMessage } from "./rpc_envelope.js";
|
|
3
|
+
/** Native pi `get_entries` result: the raw entry log + the leaf cursor to
|
|
4
|
+
* resume from. The app reduces `entries` into its transcript itself. */
|
|
5
|
+
export interface GetEntriesResult {
|
|
6
|
+
entries: SessionEntry[];
|
|
7
|
+
leafId: string | null;
|
|
8
|
+
}
|
|
9
|
+
/** Build a `{ rpc: response }` envelope. Correlates by the command's `id`. */
|
|
10
|
+
export declare function rpcResponse(command: string, id: string | undefined, result: {
|
|
11
|
+
success: boolean;
|
|
12
|
+
data?: unknown;
|
|
13
|
+
error?: string;
|
|
14
|
+
}): EnvelopeMessage;
|
|
15
|
+
/** SDK-facing operations the dispatcher needs; wired to fork primitives. */
|
|
16
|
+
export interface RpcCommandHandlers {
|
|
17
|
+
prompt(message: string, opts: {
|
|
18
|
+
id?: string;
|
|
19
|
+
images?: unknown;
|
|
20
|
+
streamingBehavior?: string;
|
|
21
|
+
}): Promise<void>;
|
|
22
|
+
steer(message: string, opts: {
|
|
23
|
+
images?: unknown;
|
|
24
|
+
}): Promise<void>;
|
|
25
|
+
followUp(message: string, opts: {
|
|
26
|
+
images?: unknown;
|
|
27
|
+
}): Promise<void>;
|
|
28
|
+
abort(): Promise<void>;
|
|
29
|
+
/** Switch the live model; resolves to the wire Model object for the response. */
|
|
30
|
+
setModel(provider: string, modelId: string): Promise<unknown>;
|
|
31
|
+
/** Set the thinking (reasoning-effort) level. */
|
|
32
|
+
setThinkingLevel(level: string): Promise<void>;
|
|
33
|
+
/** List configured models (pi `get_available_models`); resolves to Model[].
|
|
34
|
+
* Optional while the surface is being wired — an unset handler falls through
|
|
35
|
+
* to the transitional stock path (returns null from dispatch). */
|
|
36
|
+
getAvailableModels?(): Promise<unknown>;
|
|
37
|
+
/** Manually compact context (pi `compact`); resolves to the CompactionResult. */
|
|
38
|
+
compact?(customInstructions?: string): Promise<unknown>;
|
|
39
|
+
/** Start a fresh session (pi `new_session`); resolves to {cancelled}. */
|
|
40
|
+
newSession?(parentSession?: string): Promise<unknown>;
|
|
41
|
+
/** Clear the steering/follow-up queue (pi `clear_queue`); resolves to the
|
|
42
|
+
* removed {steering, followUp} text. */
|
|
43
|
+
clearQueue?(): Promise<unknown>;
|
|
44
|
+
/** Return the session ENTRY log (pi `get_entries`); resolves to
|
|
45
|
+
* `{ entries, leafId }`. `since` slices to entries AFTER that entry id
|
|
46
|
+
* (the native delta cursor). This is the transcript source — the app
|
|
47
|
+
* reduces the raw entries itself; the fork does NOT replay them. */
|
|
48
|
+
getEntries?(since?: string): Promise<GetEntriesResult>;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Map an inbound rpc command frame to an SDK call and produce the response
|
|
52
|
+
* envelope. Returns `null` for commands we don't handle yet (ignored —
|
|
53
|
+
* forward-compatible). A handler throw becomes `success:false` with the message.
|
|
54
|
+
*/
|
|
55
|
+
export declare function dispatchRpcCommand(frame: Record<string, unknown>, handlers: RpcCommandHandlers): Promise<EnvelopeMessage | null>;
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
// App -> fork inbound: interpret an envelope-carried pi `RpcCommand` and drive
|
|
2
|
+
// the SDK, then answer with a `{ rpc: { type:"response", ... } }` envelope back
|
|
3
|
+
// to the sender. This is the NEW-protocol-native inbound path — it does NOT go
|
|
4
|
+
// through the stock `ClientMessage` / `_routeClientMessageFrom` switch (that,
|
|
5
|
+
// with its `error`/`cancelled`/`pong` ServerMessage replies, is old protocol,
|
|
6
|
+
// retired). The SDK primitives the handlers wrap (sendUserMessage/_wakeAgent,
|
|
7
|
+
// ctx.abort) are pi itself, not old protocol.
|
|
8
|
+
//
|
|
9
|
+
// Command shapes: pi.dev/docs/latest/rpc. v1 surface = prompt / steer /
|
|
10
|
+
// follow_up / abort / set_model / set_thinking_level. get_state / get_entries /
|
|
11
|
+
// compact / bash follow (they need the fuller ctx.sessionManager).
|
|
12
|
+
/** Build a `{ rpc: response }` envelope. Correlates by the command's `id`. */
|
|
13
|
+
export function rpcResponse(command, id, result) {
|
|
14
|
+
const frame = {
|
|
15
|
+
type: "response",
|
|
16
|
+
command,
|
|
17
|
+
success: result.success,
|
|
18
|
+
};
|
|
19
|
+
if (id !== undefined)
|
|
20
|
+
frame.id = id;
|
|
21
|
+
if (result.data !== undefined)
|
|
22
|
+
frame.data = result.data;
|
|
23
|
+
if (result.error !== undefined)
|
|
24
|
+
frame.error = result.error;
|
|
25
|
+
return { rpc: frame };
|
|
26
|
+
}
|
|
27
|
+
function str(v) {
|
|
28
|
+
return typeof v === "string" ? v : "";
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Map an inbound rpc command frame to an SDK call and produce the response
|
|
32
|
+
* envelope. Returns `null` for commands we don't handle yet (ignored —
|
|
33
|
+
* forward-compatible). A handler throw becomes `success:false` with the message.
|
|
34
|
+
*/
|
|
35
|
+
export async function dispatchRpcCommand(frame, handlers) {
|
|
36
|
+
const command = typeof frame.type === "string" ? frame.type : undefined;
|
|
37
|
+
if (!command)
|
|
38
|
+
return null;
|
|
39
|
+
const id = typeof frame.id === "string" ? frame.id : undefined;
|
|
40
|
+
try {
|
|
41
|
+
switch (command) {
|
|
42
|
+
case "prompt":
|
|
43
|
+
await handlers.prompt(str(frame.message), {
|
|
44
|
+
id,
|
|
45
|
+
images: frame.images,
|
|
46
|
+
streamingBehavior: typeof frame.streamingBehavior === "string"
|
|
47
|
+
? frame.streamingBehavior
|
|
48
|
+
: undefined,
|
|
49
|
+
});
|
|
50
|
+
return rpcResponse("prompt", id, { success: true });
|
|
51
|
+
case "steer":
|
|
52
|
+
await handlers.steer(str(frame.message), {
|
|
53
|
+
images: frame.images,
|
|
54
|
+
});
|
|
55
|
+
return rpcResponse("steer", id, { success: true });
|
|
56
|
+
case "follow_up":
|
|
57
|
+
await handlers.followUp(str(frame.message), {
|
|
58
|
+
images: frame.images,
|
|
59
|
+
});
|
|
60
|
+
return rpcResponse("follow_up", id, { success: true });
|
|
61
|
+
case "abort":
|
|
62
|
+
await handlers.abort();
|
|
63
|
+
return rpcResponse("abort", id, { success: true });
|
|
64
|
+
case "set_model": {
|
|
65
|
+
const data = await handlers.setModel(str(frame.provider), str(frame.modelId));
|
|
66
|
+
return rpcResponse("set_model", id, {
|
|
67
|
+
success: true,
|
|
68
|
+
data,
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
case "set_thinking_level":
|
|
72
|
+
await handlers.setThinkingLevel(str(frame.level));
|
|
73
|
+
return rpcResponse("set_thinking_level", id, {
|
|
74
|
+
success: true,
|
|
75
|
+
});
|
|
76
|
+
case "get_available_models": {
|
|
77
|
+
if (!handlers.getAvailableModels)
|
|
78
|
+
return null;
|
|
79
|
+
const data = await handlers.getAvailableModels();
|
|
80
|
+
return rpcResponse("get_available_models", id, {
|
|
81
|
+
success: true,
|
|
82
|
+
data,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
case "compact": {
|
|
86
|
+
if (!handlers.compact)
|
|
87
|
+
return null;
|
|
88
|
+
const data = await handlers.compact(typeof frame.customInstructions === "string"
|
|
89
|
+
? frame.customInstructions
|
|
90
|
+
: undefined);
|
|
91
|
+
return rpcResponse("compact", id, {
|
|
92
|
+
success: true,
|
|
93
|
+
data,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
case "new_session": {
|
|
97
|
+
if (!handlers.newSession)
|
|
98
|
+
return null;
|
|
99
|
+
const data = await handlers.newSession(typeof frame.parentSession === "string"
|
|
100
|
+
? frame.parentSession
|
|
101
|
+
: undefined);
|
|
102
|
+
return rpcResponse("new_session", id, {
|
|
103
|
+
success: true,
|
|
104
|
+
data,
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
case "clear_queue": {
|
|
108
|
+
if (!handlers.clearQueue)
|
|
109
|
+
return null;
|
|
110
|
+
const data = await handlers.clearQueue();
|
|
111
|
+
return rpcResponse("clear_queue", id, {
|
|
112
|
+
success: true,
|
|
113
|
+
data,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
case "get_entries": {
|
|
117
|
+
if (!handlers.getEntries)
|
|
118
|
+
return null;
|
|
119
|
+
const data = await handlers.getEntries(typeof frame.since === "string" ? frame.since : undefined);
|
|
120
|
+
return rpcResponse("get_entries", id, {
|
|
121
|
+
success: true,
|
|
122
|
+
data,
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
default:
|
|
126
|
+
return null; // unhandled command: ignore (forward-compat)
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
return rpcResponse(command, id, {
|
|
131
|
+
success: false,
|
|
132
|
+
error: err instanceof Error ? err.message : String(err),
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
//# sourceMappingURL=rpc_inbound.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rpc_inbound.js","sourceRoot":"","sources":["../../src/session/rpc_inbound.ts"],"names":[],"mappings":"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"}
|