negotium 0.1.12 → 0.1.13
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/dist/canonical-mcp-bridge.js +2 -3
- package/dist/canonical-mcp-bridge.js.map +1 -1
- package/dist/chunk-a9y2rwxf.js.map +1 -1
- package/dist/{chunk-j0kjscb7.js → chunk-s2gez3wg.js} +20 -2
- package/dist/{chunk-j0kjscb7.js.map → chunk-s2gez3wg.js.map} +2 -2
- package/dist/cron.js +49 -25
- package/dist/cron.js.map +15 -14
- package/dist/hosted-agent.js +3012 -17
- package/dist/hosted-agent.js.map +30 -3
- package/dist/main.js +31323 -36
- package/dist/main.js.map +198 -3
- package/dist/prompts.js +11 -8
- package/dist/prompts.js.map +4 -4
- package/dist/runtime/src/application/submit-user-message.ts +3 -0
- package/dist/runtime/src/index.ts +7 -0
- package/dist/runtime/src/mcp/runtime-spec.ts +3 -0
- package/dist/runtime/src/mcp/session-comm/server.ts +1 -1
- package/dist/runtime/src/platform/mcp-config.ts +13 -0
- package/dist/runtime/src/prompts/builders.ts +20 -6
- package/dist/runtime/src/query/active-rooms.ts +2 -0
- package/dist/runtime/src/runtime/delivery-ack.ts +112 -0
- package/dist/runtime/src/runtime/errors.ts +12 -12
- package/dist/runtime/src/runtime/turn-runner.ts +12 -0
- package/dist/runtime/src/storage/runtime-turn-requests.ts +1 -0
- package/dist/runtime/src/types/api.ts +2 -0
- package/dist/runtime/src/types.ts +2 -0
- package/dist/runtime/src/version.ts +1 -1
- package/dist/runtime-helpers.js.map +1 -1
- package/dist/storage.js.map +1 -1
- package/dist/types/packages/core/src/mcp/runtime-spec.d.ts +2 -0
- package/dist/types/packages/core/src/platform/mcp-config.d.ts +4 -0
- package/dist/types/packages/core/src/prompts/builders.d.ts +2 -0
- package/dist/types/packages/core/src/types/api.d.ts +2 -0
- package/dist/types/packages/core/src/types.d.ts +2 -0
- package/dist/types/packages/core/src/version.d.ts +1 -1
- package/dist/vault.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-00q25k7p.js +0 -2387
- package/dist/chunk-00q25k7p.js.map +0 -26
- package/dist/chunk-03kv7mvj.js +0 -2152
- package/dist/chunk-03kv7mvj.js.map +0 -15
- package/dist/chunk-05pm51dh.js +0 -589
- package/dist/chunk-05pm51dh.js.map +0 -11
- package/dist/chunk-0eh16bk1.js +0 -2936
- package/dist/chunk-0eh16bk1.js.map +0 -20
- package/dist/chunk-0yfqyv88.js +0 -108
- package/dist/chunk-0yfqyv88.js.map +0 -10
- package/dist/chunk-1k7t7bnx.js +0 -97
- package/dist/chunk-1k7t7bnx.js.map +0 -10
- package/dist/chunk-3gkfr9vb.js +0 -431
- package/dist/chunk-3gkfr9vb.js.map +0 -11
- package/dist/chunk-5akd1gbj.js +0 -281
- package/dist/chunk-5akd1gbj.js.map +0 -10
- package/dist/chunk-7k19pcg8.js +0 -577
- package/dist/chunk-7k19pcg8.js.map +0 -14
- package/dist/chunk-81tbfbmt.js +0 -10
- package/dist/chunk-81tbfbmt.js.map +0 -10
- package/dist/chunk-82qhv1mq.js +0 -512
- package/dist/chunk-82qhv1mq.js.map +0 -13
- package/dist/chunk-8dy7e2a9.js +0 -103
- package/dist/chunk-8dy7e2a9.js.map +0 -10
- package/dist/chunk-8f2sqmrj.js +0 -1712
- package/dist/chunk-8f2sqmrj.js.map +0 -18
- package/dist/chunk-9hjeemfz.js +0 -372
- package/dist/chunk-9hjeemfz.js.map +0 -10
- package/dist/chunk-a4aa2ccv.js +0 -141
- package/dist/chunk-a4aa2ccv.js.map +0 -10
- package/dist/chunk-bsg215q3.js +0 -3536
- package/dist/chunk-bsg215q3.js.map +0 -20
- package/dist/chunk-bxnfsc7w.js +0 -58
- package/dist/chunk-bxnfsc7w.js.map +0 -10
- package/dist/chunk-c500xe9z.js +0 -33
- package/dist/chunk-c500xe9z.js.map +0 -10
- package/dist/chunk-cngrf7ab.js +0 -149
- package/dist/chunk-cngrf7ab.js.map +0 -10
- package/dist/chunk-d7tprf06.js +0 -53
- package/dist/chunk-d7tprf06.js.map +0 -10
- package/dist/chunk-ddnrmkrv.js +0 -61
- package/dist/chunk-ddnrmkrv.js.map +0 -10
- package/dist/chunk-edb07sjp.js +0 -567
- package/dist/chunk-edb07sjp.js.map +0 -14
- package/dist/chunk-ejcm6zx8.js +0 -591
- package/dist/chunk-ejcm6zx8.js.map +0 -11
- package/dist/chunk-ezs352qs.js +0 -237
- package/dist/chunk-ezs352qs.js.map +0 -11
- package/dist/chunk-f5xgprg1.js +0 -59
- package/dist/chunk-f5xgprg1.js.map +0 -10
- package/dist/chunk-fbtb3v0s.js +0 -1339
- package/dist/chunk-fbtb3v0s.js.map +0 -16
- package/dist/chunk-ffefbd3r.js +0 -17
- package/dist/chunk-ffefbd3r.js.map +0 -10
- package/dist/chunk-gaknyw04.js +0 -708
- package/dist/chunk-gaknyw04.js.map +0 -14
- package/dist/chunk-gxmny6tq.js +0 -1637
- package/dist/chunk-gxmny6tq.js.map +0 -15
- package/dist/chunk-h7bj5zwb.js +0 -3069
- package/dist/chunk-h7bj5zwb.js.map +0 -32
- package/dist/chunk-hp4g7wx7.js +0 -46
- package/dist/chunk-hp4g7wx7.js.map +0 -10
- package/dist/chunk-hwy3n31w.js +0 -21
- package/dist/chunk-hwy3n31w.js.map +0 -9
- package/dist/chunk-jzz91jwh.js +0 -70
- package/dist/chunk-jzz91jwh.js.map +0 -10
- package/dist/chunk-k778y16p.js +0 -153
- package/dist/chunk-k778y16p.js.map +0 -11
- package/dist/chunk-mh5mexsf.js +0 -147
- package/dist/chunk-mh5mexsf.js.map +0 -11
- package/dist/chunk-mnwaext5.js +0 -318
- package/dist/chunk-mnwaext5.js.map +0 -10
- package/dist/chunk-nkgs40ch.js +0 -23
- package/dist/chunk-nkgs40ch.js.map +0 -10
- package/dist/chunk-pz57vwsm.js +0 -250
- package/dist/chunk-pz57vwsm.js.map +0 -11
- package/dist/chunk-r6kdp7gn.js +0 -252
- package/dist/chunk-r6kdp7gn.js.map +0 -10
- package/dist/chunk-rkvrkcgx.js +0 -117
- package/dist/chunk-rkvrkcgx.js.map +0 -10
- package/dist/chunk-s74rdyqe.js +0 -117
- package/dist/chunk-s74rdyqe.js.map +0 -12
- package/dist/chunk-sa874j5c.js +0 -9
- package/dist/chunk-sa874j5c.js.map +0 -10
- package/dist/chunk-sffqdkvq.js +0 -122
- package/dist/chunk-sffqdkvq.js.map +0 -10
- package/dist/chunk-tcs9qjps.js +0 -64
- package/dist/chunk-tcs9qjps.js.map +0 -10
- package/dist/chunk-wx83ep8e.js +0 -131
- package/dist/chunk-wx83ep8e.js.map +0 -10
- package/dist/chunk-xag86ng3.js +0 -122
- package/dist/chunk-xag86ng3.js.map +0 -10
- package/dist/chunk-xfdkep71.js +0 -371
- package/dist/chunk-xfdkep71.js.map +0 -11
- package/dist/chunk-xhm1rfpt.js +0 -2907
- package/dist/chunk-xhm1rfpt.js.map +0 -24
- package/dist/chunk-xpcps28p.js +0 -2138
- package/dist/chunk-xpcps28p.js.map +0 -29
- package/dist/chunk-yb4rbev9.js +0 -214
- package/dist/chunk-yb4rbev9.js.map +0 -10
package/dist/chunk-0yfqyv88.js
DELETED
|
@@ -1,108 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
// @bun
|
|
3
|
-
import {
|
|
4
|
-
__require,
|
|
5
|
-
__toESM
|
|
6
|
-
} from "./chunk-hwy3n31w.js";
|
|
7
|
-
|
|
8
|
-
// ../../adapters/terminal/src/cli.ts
|
|
9
|
-
function option(args, name) {
|
|
10
|
-
const prefix = `--${name}=`;
|
|
11
|
-
return args.find((arg) => arg.startsWith(prefix))?.slice(prefix.length);
|
|
12
|
-
}
|
|
13
|
-
function hasFlag(args, name) {
|
|
14
|
-
return args.includes(`--${name}`);
|
|
15
|
-
}
|
|
16
|
-
function terminalOptionsFromArgs(args) {
|
|
17
|
-
const userId = option(args, "user")?.trim() || "local";
|
|
18
|
-
const preferredTopic = option(args, "topic")?.trim() || undefined;
|
|
19
|
-
const requestedAgent = option(args, "agent")?.trim() || process.env.TERMINAL_ADAPTER_AGENT?.trim();
|
|
20
|
-
const defaultAgent = requestedAgent === "claude" || requestedAgent === "codex" || requestedAgent === "maestro" ? requestedAgent : undefined;
|
|
21
|
-
const parsedPort = Number.parseInt(option(args, "port") ?? "0", 10);
|
|
22
|
-
const port = Number.isInteger(parsedPort) && parsedPort >= 0 ? parsedPort : 0;
|
|
23
|
-
const embedded = hasFlag(args, "embedded");
|
|
24
|
-
const connect = option(args, "connect")?.trim().replace(/\/+$/, "") || undefined;
|
|
25
|
-
return { userId, preferredTopic, defaultAgent, port, embedded, connect };
|
|
26
|
-
}
|
|
27
|
-
async function spawnNodeDaemon(port) {
|
|
28
|
-
const entry = process.argv[1];
|
|
29
|
-
if (!entry)
|
|
30
|
-
throw new Error("cannot locate the Negotium CLI entrypoint");
|
|
31
|
-
const { LOG_DIR } = await import("./chunk-h7bj5zwb.js");
|
|
32
|
-
const child = Bun.spawn({
|
|
33
|
-
cmd: [process.execPath, entry, "__node-daemon", `--port=${port}`],
|
|
34
|
-
detached: true,
|
|
35
|
-
env: {
|
|
36
|
-
...process.env,
|
|
37
|
-
LOG_LEVEL: process.env.NEGOTIUM_NODE_LOG_LEVEL?.trim() || "info"
|
|
38
|
-
},
|
|
39
|
-
stdin: "ignore",
|
|
40
|
-
stdout: "ignore",
|
|
41
|
-
stderr: Bun.file(`${LOG_DIR}/node-daemon.log`)
|
|
42
|
-
});
|
|
43
|
-
child.unref();
|
|
44
|
-
}
|
|
45
|
-
async function runDaemonChild(args) {
|
|
46
|
-
const parsed = Number.parseInt(option(args, "port") ?? "0", 10);
|
|
47
|
-
const port = Number.isInteger(parsed) && parsed >= 0 ? parsed : 0;
|
|
48
|
-
const { runNodeDaemon } = await import("./chunk-gxmny6tq.js");
|
|
49
|
-
await runNodeDaemon({ port });
|
|
50
|
-
}
|
|
51
|
-
async function ensureLocalNode(port) {
|
|
52
|
-
const { inspectNodeDaemon, waitForNodeDaemon } = await import("./chunk-gxmny6tq.js");
|
|
53
|
-
const deadline = Date.now() + 15000;
|
|
54
|
-
let lastError = "node did not become ready";
|
|
55
|
-
while (Date.now() < deadline) {
|
|
56
|
-
const status = await inspectNodeDaemon();
|
|
57
|
-
if (status.running)
|
|
58
|
-
return waitForNodeDaemon(1000);
|
|
59
|
-
if (status.error)
|
|
60
|
-
lastError = status.error;
|
|
61
|
-
await spawnNodeDaemon(port);
|
|
62
|
-
try {
|
|
63
|
-
return await waitForNodeDaemon(1500);
|
|
64
|
-
} catch (error) {
|
|
65
|
-
lastError = error instanceof Error ? error.message : String(error);
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
throw new Error(`Negotium node failed to start: ${lastError}`);
|
|
69
|
-
}
|
|
70
|
-
async function runTerminalCli(args = process.argv.slice(2)) {
|
|
71
|
-
if (args[0] === "__node-daemon") {
|
|
72
|
-
await runDaemonChild(args.slice(1));
|
|
73
|
-
return;
|
|
74
|
-
}
|
|
75
|
-
process.env.LOG_LEVEL ??= "silent";
|
|
76
|
-
const options = terminalOptionsFromArgs(args);
|
|
77
|
-
if (options.embedded && options.connect) {
|
|
78
|
-
throw new Error("--embedded and --connect cannot be used together");
|
|
79
|
-
}
|
|
80
|
-
if (!process.stdin.isTTY || !process.stdout.isTTY) {
|
|
81
|
-
throw new Error("terminal-adapter requires an interactive TTY");
|
|
82
|
-
}
|
|
83
|
-
const { startTerminalAdapter } = await import("./chunk-bsg215q3.js");
|
|
84
|
-
let client;
|
|
85
|
-
if (!options.embedded) {
|
|
86
|
-
const { NODE_CONTROL_TOKEN } = await import("./chunk-h7bj5zwb.js");
|
|
87
|
-
const { RemoteNegotiumClient } = await import("./chunk-05pm51dh.js");
|
|
88
|
-
const connection = options.connect ? {
|
|
89
|
-
baseUrl: options.connect,
|
|
90
|
-
token: process.env.NEGOTIUM_CONTROL_TOKEN?.trim() || NODE_CONTROL_TOKEN
|
|
91
|
-
} : await ensureLocalNode(options.port);
|
|
92
|
-
client = new RemoteNegotiumClient({ userId: options.userId, ...connection });
|
|
93
|
-
}
|
|
94
|
-
const adapter = startTerminalAdapter({ ...options, client });
|
|
95
|
-
try {
|
|
96
|
-
await adapter.completed;
|
|
97
|
-
} catch (error) {
|
|
98
|
-
await Promise.resolve(adapter.stop()).catch(() => {});
|
|
99
|
-
throw error;
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
if (false) {}
|
|
103
|
-
export {
|
|
104
|
-
terminalOptionsFromArgs,
|
|
105
|
-
runTerminalCli
|
|
106
|
-
};
|
|
107
|
-
|
|
108
|
-
//# debugId=353978517FE6790B64756E2164756E21
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../adapters/terminal/src/cli.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"#!/usr/bin/env bun\n\nfunction option(args: string[], name: string): string | undefined {\n const prefix = `--${name}=`;\n return args.find((arg) => arg.startsWith(prefix))?.slice(prefix.length);\n}\n\nfunction hasFlag(args: string[], name: string): boolean {\n return args.includes(`--${name}`);\n}\n\nexport function terminalOptionsFromArgs(args: string[]): {\n userId: string;\n preferredTopic?: string;\n defaultAgent?: \"claude\" | \"codex\" | \"maestro\";\n port: number;\n embedded: boolean;\n connect?: string;\n} {\n const userId = option(args, \"user\")?.trim() || \"local\";\n const preferredTopic = option(args, \"topic\")?.trim() || undefined;\n const requestedAgent =\n option(args, \"agent\")?.trim() || process.env.TERMINAL_ADAPTER_AGENT?.trim();\n const defaultAgent =\n requestedAgent === \"claude\" || requestedAgent === \"codex\" || requestedAgent === \"maestro\"\n ? requestedAgent\n : undefined;\n const parsedPort = Number.parseInt(option(args, \"port\") ?? \"0\", 10);\n const port = Number.isInteger(parsedPort) && parsedPort >= 0 ? parsedPort : 0;\n const embedded = hasFlag(args, \"embedded\");\n const connect = option(args, \"connect\")?.trim().replace(/\\/+$/, \"\") || undefined;\n return { userId, preferredTopic, defaultAgent, port, embedded, connect };\n}\n\nasync function spawnNodeDaemon(port: number): Promise<void> {\n const entry = process.argv[1];\n if (!entry) throw new Error(\"cannot locate the Negotium CLI entrypoint\");\n const { LOG_DIR } = await import(\"@negotium/core\");\n const child = Bun.spawn({\n cmd: [process.execPath, entry, \"__node-daemon\", `--port=${port}`],\n detached: true,\n env: {\n ...process.env,\n LOG_LEVEL: process.env.NEGOTIUM_NODE_LOG_LEVEL?.trim() || \"info\",\n },\n stdin: \"ignore\",\n stdout: \"ignore\",\n stderr: Bun.file(`${LOG_DIR}/node-daemon.log`),\n });\n child.unref();\n}\n\nasync function runDaemonChild(args: string[]): Promise<void> {\n const parsed = Number.parseInt(option(args, \"port\") ?? \"0\", 10);\n const port = Number.isInteger(parsed) && parsed >= 0 ? parsed : 0;\n const { runNodeDaemon } = await import(\"@negotium/node\");\n await runNodeDaemon({ port });\n}\n\nasync function ensureLocalNode(\n port: number,\n): Promise<import(\"@negotium/node\").NodeDaemonConnection> {\n const { inspectNodeDaemon, waitForNodeDaemon } = await import(\"@negotium/node\");\n const deadline = Date.now() + 15_000;\n let lastError = \"node did not become ready\";\n while (Date.now() < deadline) {\n const status = await inspectNodeDaemon();\n if (status.running) return waitForNodeDaemon(1_000);\n if (status.error) lastError = status.error;\n await spawnNodeDaemon(port);\n try {\n return await waitForNodeDaemon(1_500);\n } catch (error) {\n lastError = error instanceof Error ? error.message : String(error);\n }\n }\n throw new Error(`Negotium node failed to start: ${lastError}`);\n}\n\n/** Environment/argv wrapper shipped as the `negotium-terminal` executable. */\nexport async function runTerminalCli(args = process.argv.slice(2)): Promise<void> {\n if (args[0] === \"__node-daemon\") {\n await runDaemonChild(args.slice(1));\n return;\n }\n\n // Pino binds its destination when core is first imported. Silence host logs\n // before the dynamic adapter import so stderr cannot corrupt the alt screen.\n process.env.LOG_LEVEL ??= \"silent\";\n\n const options = terminalOptionsFromArgs(args);\n if (options.embedded && options.connect) {\n throw new Error(\"--embedded and --connect cannot be used together\");\n }\n if (!process.stdin.isTTY || !process.stdout.isTTY) {\n throw new Error(\"terminal-adapter requires an interactive TTY\");\n }\n\n const { startTerminalAdapter } = await import(\"@/index\");\n let client: import(\"@/client\").NegotiumClient | undefined;\n if (!options.embedded) {\n const { NODE_CONTROL_TOKEN } = await import(\"@negotium/core\");\n const { RemoteNegotiumClient } = await import(\"@/client\");\n const connection = options.connect\n ? {\n baseUrl: options.connect,\n token: process.env.NEGOTIUM_CONTROL_TOKEN?.trim() || NODE_CONTROL_TOKEN,\n }\n : await ensureLocalNode(options.port);\n client = new RemoteNegotiumClient({ userId: options.userId, ...connection });\n }\n const adapter = startTerminalAdapter({ ...options, client });\n try {\n await adapter.completed;\n } catch (error) {\n await Promise.resolve(adapter.stop()).catch(() => {});\n throw error;\n }\n}\n\nif (import.meta.main) {\n runTerminalCli().catch((error) => {\n process.stderr.write(\n `negotium-terminal: ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n process.exitCode = 1;\n });\n}\n"
|
|
6
|
-
],
|
|
7
|
-
"mappings": "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",
|
|
8
|
-
"debugId": "353978517FE6790B64756E2164756E21",
|
|
9
|
-
"names": []
|
|
10
|
-
}
|
package/dist/chunk-1k7t7bnx.js
DELETED
|
@@ -1,97 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import"./chunk-hwy3n31w.js";
|
|
3
|
-
|
|
4
|
-
// ../../packages/core/src/mcp/session-comm/peer-forward.ts
|
|
5
|
-
var activeBridge = null;
|
|
6
|
-
var PEER_BRIDGE_URL_ENV = "NEGOTIUM_PEER_SESSION_BRIDGE_URL";
|
|
7
|
-
var PEER_BRIDGE_TOKEN_ENV = "NEGOTIUM_PEER_SESSION_BRIDGE_TOKEN";
|
|
8
|
-
var PEER_BRIDGE_TIMEOUT_MS = 5000;
|
|
9
|
-
function loopbackBridgeConfig() {
|
|
10
|
-
const rawUrl = process.env[PEER_BRIDGE_URL_ENV]?.trim();
|
|
11
|
-
const token = process.env[PEER_BRIDGE_TOKEN_ENV]?.trim();
|
|
12
|
-
if (!rawUrl || !token)
|
|
13
|
-
return null;
|
|
14
|
-
try {
|
|
15
|
-
const url = new URL(rawUrl);
|
|
16
|
-
if (url.protocol !== "http:" || !["127.0.0.1", "::1", "localhost"].includes(url.hostname)) {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
|
-
return { url: url.toString(), token };
|
|
20
|
-
} catch {
|
|
21
|
-
return null;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
async function callLoopbackBridge(request) {
|
|
25
|
-
const config = loopbackBridgeConfig();
|
|
26
|
-
if (!config)
|
|
27
|
-
return { configured: false, result: null };
|
|
28
|
-
try {
|
|
29
|
-
const response = await fetch(config.url, {
|
|
30
|
-
method: "POST",
|
|
31
|
-
headers: {
|
|
32
|
-
authorization: `Bearer ${config.token}`,
|
|
33
|
-
"content-type": "application/json"
|
|
34
|
-
},
|
|
35
|
-
body: JSON.stringify(request),
|
|
36
|
-
signal: AbortSignal.timeout(PEER_BRIDGE_TIMEOUT_MS)
|
|
37
|
-
});
|
|
38
|
-
if (!response.ok)
|
|
39
|
-
return { configured: true, result: null };
|
|
40
|
-
return { configured: true, result: await response.json() };
|
|
41
|
-
} catch {
|
|
42
|
-
return { configured: true, result: null };
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
function registerPeerSessionBridge(bridge) {
|
|
46
|
-
activeBridge = bridge;
|
|
47
|
-
return () => {
|
|
48
|
-
if (activeBridge === bridge)
|
|
49
|
-
activeBridge = null;
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
async function forwardToPeer(args) {
|
|
53
|
-
if (activeBridge)
|
|
54
|
-
return activeBridge.forward(args);
|
|
55
|
-
const forwarded = await callLoopbackBridge({ action: "forward", args });
|
|
56
|
-
if (forwarded.result)
|
|
57
|
-
return forwarded.result;
|
|
58
|
-
return {
|
|
59
|
-
ok: false,
|
|
60
|
-
error: forwarded.configured ? "remote session bridge is configured but unavailable" : "remote nodes are not connected on this negotium node (standalone mode)"
|
|
61
|
-
};
|
|
62
|
-
}
|
|
63
|
-
async function peerSessionsForUser(userId, sourceQueryId) {
|
|
64
|
-
if (activeBridge)
|
|
65
|
-
return activeBridge.sessions(userId, sourceQueryId);
|
|
66
|
-
const sessions = await callLoopbackBridge({
|
|
67
|
-
action: "sessions",
|
|
68
|
-
userId,
|
|
69
|
-
sourceQueryId
|
|
70
|
-
});
|
|
71
|
-
if (sessions.result)
|
|
72
|
-
return sessions.result;
|
|
73
|
-
if (sessions.configured)
|
|
74
|
-
return { ok: false, nodes: [] };
|
|
75
|
-
return { ok: true, nodes: [] };
|
|
76
|
-
}
|
|
77
|
-
async function deliverPeerReply(route, sourceTitle, replyText, kind) {
|
|
78
|
-
if (activeBridge)
|
|
79
|
-
return activeBridge.reply(route, sourceTitle, replyText, kind);
|
|
80
|
-
return (await callLoopbackBridge({
|
|
81
|
-
action: "reply",
|
|
82
|
-
route,
|
|
83
|
-
sourceTitle,
|
|
84
|
-
replyText,
|
|
85
|
-
kind
|
|
86
|
-
})).result ?? false;
|
|
87
|
-
}
|
|
88
|
-
export {
|
|
89
|
-
registerPeerSessionBridge,
|
|
90
|
-
peerSessionsForUser,
|
|
91
|
-
forwardToPeer,
|
|
92
|
-
deliverPeerReply
|
|
93
|
-
};
|
|
94
|
-
|
|
95
|
-
export { registerPeerSessionBridge, deliverPeerReply };
|
|
96
|
-
|
|
97
|
-
//# debugId=C6D7A2F8FD57D92564756E2164756E21
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"version": 3,
|
|
3
|
-
"sources": ["../../../packages/core/src/mcp/session-comm/peer-forward.ts"],
|
|
4
|
-
"sourcesContent": [
|
|
5
|
-
"/**\n * Remote-node forwarding adapter hook.\n *\n * Addressing keeps the `\"<node>/<topic>\"` shape so cross-node session-comm can\n * plug in later (an otium-hub adapter, a negotium peer protocol, …) without\n * changing tool contracts. On a standalone node every remote call fails\n * gracefully and `peerSessionsForUser` contributes nothing to peek listings.\n */\n\nexport interface PeerForwardArgs {\n action: \"tell\" | \"ask\" | \"abort\";\n toNode: string;\n toTopic: string;\n userId: string;\n fromKey?: string;\n fromTitle?: string;\n fromTopicId?: string;\n message?: string;\n requestId?: string;\n depth?: number;\n fromDepth?: number;\n /** Hub turn authorizing a worker-originated peer call. */\n sourceQueryId?: string;\n}\n\nexport type PeerForwardResult = { ok: true } | { ok: false; error: string };\n\nexport interface RemoteReplyRoute {\n nodeName: string;\n nodeCellId: string;\n topicId: string;\n userId: string;\n requestId: string;\n}\n\nexport interface PeerSessionBridge {\n forward(args: PeerForwardArgs): Promise<PeerForwardResult>;\n sessions(userId: string, sourceQueryId?: string): Promise<PeerSessionsResult>;\n reply(\n route: RemoteReplyRoute,\n sourceTitle: string,\n replyText: string,\n kind: \"reply\" | \"error\",\n ): Promise<boolean>;\n}\n\nlet activeBridge: PeerSessionBridge | null = null;\n\nconst PEER_BRIDGE_URL_ENV = \"NEGOTIUM_PEER_SESSION_BRIDGE_URL\";\nconst PEER_BRIDGE_TOKEN_ENV = \"NEGOTIUM_PEER_SESSION_BRIDGE_TOKEN\";\nconst PEER_BRIDGE_TIMEOUT_MS = 5_000;\n\ntype IpcRequest =\n | { action: \"forward\"; args: PeerForwardArgs }\n | { action: \"sessions\"; userId: string; sourceQueryId?: string }\n | {\n action: \"reply\";\n route: RemoteReplyRoute;\n sourceTitle: string;\n replyText: string;\n kind: \"reply\" | \"error\";\n };\n\nfunction loopbackBridgeConfig(): { url: string; token: string } | null {\n const rawUrl = process.env[PEER_BRIDGE_URL_ENV]?.trim();\n const token = process.env[PEER_BRIDGE_TOKEN_ENV]?.trim();\n if (!rawUrl || !token) return null;\n try {\n const url = new URL(rawUrl);\n if (url.protocol !== \"http:\" || ![\"127.0.0.1\", \"::1\", \"localhost\"].includes(url.hostname)) {\n return null;\n }\n return { url: url.toString(), token };\n } catch {\n return null;\n }\n}\n\nasync function callLoopbackBridge<T>(\n request: IpcRequest,\n): Promise<{ configured: boolean; result: T | null }> {\n const config = loopbackBridgeConfig();\n if (!config) return { configured: false, result: null };\n try {\n const response = await fetch(config.url, {\n method: \"POST\",\n headers: {\n authorization: `Bearer ${config.token}`,\n \"content-type\": \"application/json\",\n },\n body: JSON.stringify(request),\n signal: AbortSignal.timeout(PEER_BRIDGE_TIMEOUT_MS),\n });\n if (!response.ok) return { configured: true, result: null };\n return { configured: true, result: (await response.json()) as T };\n } catch {\n return { configured: true, result: null };\n }\n}\n\nexport function registerPeerSessionBridge(bridge: PeerSessionBridge): () => void {\n activeBridge = bridge;\n return () => {\n if (activeBridge === bridge) activeBridge = null;\n };\n}\n\nexport async function forwardToPeer(args: PeerForwardArgs): Promise<PeerForwardResult> {\n if (activeBridge) return activeBridge.forward(args);\n const forwarded = await callLoopbackBridge<PeerForwardResult>({ action: \"forward\", args });\n if (forwarded.result) return forwarded.result;\n return {\n ok: false,\n error: forwarded.configured\n ? \"remote session bridge is configured but unavailable\"\n : \"remote nodes are not connected on this negotium node (standalone mode)\",\n };\n}\n\nexport interface PeerSessionEntry {\n name: string;\n agent: string | null;\n hasSession: boolean;\n description?: string;\n}\n\nexport interface PeerSessionsResult {\n ok: boolean;\n nodes?: Array<{ node: string; error?: string; sessions?: PeerSessionEntry[] }>;\n}\n\nexport async function peerSessionsForUser(\n userId: string,\n sourceQueryId?: string,\n): Promise<PeerSessionsResult> {\n if (activeBridge) return activeBridge.sessions(userId, sourceQueryId);\n const sessions = await callLoopbackBridge<PeerSessionsResult>({\n action: \"sessions\",\n userId,\n sourceQueryId,\n });\n if (sessions.result) return sessions.result;\n if (sessions.configured) return { ok: false, nodes: [] };\n return { ok: true, nodes: [] };\n}\n\nexport async function deliverPeerReply(\n route: RemoteReplyRoute,\n sourceTitle: string,\n replyText: string,\n kind: \"reply\" | \"error\",\n): Promise<boolean> {\n if (activeBridge) return activeBridge.reply(route, sourceTitle, replyText, kind);\n return (\n (\n await callLoopbackBridge<boolean>({\n action: \"reply\",\n route,\n sourceTitle,\n replyText,\n kind,\n })\n ).result ?? false\n );\n}\n"
|
|
6
|
-
],
|
|
7
|
-
"mappings": ";;;;AA8CA,IAAI,eAAyC;AAE7C,IAAM,sBAAsB;AAC5B,IAAM,wBAAwB;AAC9B,IAAM,yBAAyB;AAa/B,SAAS,oBAAoB,GAA0C;AAAA,EACrE,MAAM,SAAS,QAAQ,IAAI,sBAAsB,KAAK;AAAA,EACtD,MAAM,QAAQ,QAAQ,IAAI,wBAAwB,KAAK;AAAA,EACvD,KAAK,WAAW;AAAA,IAAO,OAAO;AAAA,EAC9B,IAAI;AAAA,IACF,MAAM,MAAM,IAAI,IAAI,MAAM;AAAA,IAC1B,IAAI,IAAI,aAAa,YAAY,CAAC,aAAa,OAAO,WAAW,EAAE,SAAS,IAAI,QAAQ,GAAG;AAAA,MACzF,OAAO;AAAA,IACT;AAAA,IACA,OAAO,EAAE,KAAK,IAAI,SAAS,GAAG,MAAM;AAAA,IACpC,MAAM;AAAA,IACN,OAAO;AAAA;AAAA;AAIX,eAAe,kBAAqB,CAClC,SACoD;AAAA,EACpD,MAAM,SAAS,qBAAqB;AAAA,EACpC,KAAK;AAAA,IAAQ,OAAO,EAAE,YAAY,OAAO,QAAQ,KAAK;AAAA,EACtD,IAAI;AAAA,IACF,MAAM,WAAW,MAAM,MAAM,OAAO,KAAK;AAAA,MACvC,QAAQ;AAAA,MACR,SAAS;AAAA,QACP,eAAe,UAAU,OAAO;AAAA,QAChC,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,KAAK,UAAU,OAAO;AAAA,MAC5B,QAAQ,YAAY,QAAQ,sBAAsB;AAAA,IACpD,CAAC;AAAA,IACD,KAAK,SAAS;AAAA,MAAI,OAAO,EAAE,YAAY,MAAM,QAAQ,KAAK;AAAA,IAC1D,OAAO,EAAE,YAAY,MAAM,QAAS,MAAM,SAAS,KAAK,EAAQ;AAAA,IAChE,MAAM;AAAA,IACN,OAAO,EAAE,YAAY,MAAM,QAAQ,KAAK;AAAA;AAAA;AAIrC,SAAS,yBAAyB,CAAC,QAAuC;AAAA,EAC/E,eAAe;AAAA,EACf,OAAO,MAAM;AAAA,IACX,IAAI,iBAAiB;AAAA,MAAQ,eAAe;AAAA;AAAA;AAIhD,eAAsB,aAAa,CAAC,MAAmD;AAAA,EACrF,IAAI;AAAA,IAAc,OAAO,aAAa,QAAQ,IAAI;AAAA,EAClD,MAAM,YAAY,MAAM,mBAAsC,EAAE,QAAQ,WAAW,KAAK,CAAC;AAAA,EACzF,IAAI,UAAU;AAAA,IAAQ,OAAO,UAAU;AAAA,EACvC,OAAO;AAAA,IACL,IAAI;AAAA,IACJ,OAAO,UAAU,aACb,wDACA;AAAA,EACN;AAAA;AAeF,eAAsB,mBAAmB,CACvC,QACA,eAC6B;AAAA,EAC7B,IAAI;AAAA,IAAc,OAAO,aAAa,SAAS,QAAQ,aAAa;AAAA,EACpE,MAAM,WAAW,MAAM,mBAAuC;AAAA,IAC5D,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,EACF,CAAC;AAAA,EACD,IAAI,SAAS;AAAA,IAAQ,OAAO,SAAS;AAAA,EACrC,IAAI,SAAS;AAAA,IAAY,OAAO,EAAE,IAAI,OAAO,OAAO,CAAC,EAAE;AAAA,EACvD,OAAO,EAAE,IAAI,MAAM,OAAO,CAAC,EAAE;AAAA;AAG/B,eAAsB,gBAAgB,CACpC,OACA,aACA,WACA,MACkB;AAAA,EAClB,IAAI;AAAA,IAAc,OAAO,aAAa,MAAM,OAAO,aAAa,WAAW,IAAI;AAAA,EAC/E,QAEI,MAAM,mBAA4B;AAAA,IAChC,QAAQ;AAAA,IACR;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,CAAC,GACD,UAAU;AAAA;",
|
|
8
|
-
"debugId": "C6D7A2F8FD57D92564756E2164756E21",
|
|
9
|
-
"names": []
|
|
10
|
-
}
|
package/dist/chunk-3gkfr9vb.js
DELETED
|
@@ -1,431 +0,0 @@
|
|
|
1
|
-
// @bun
|
|
2
|
-
import"./chunk-h7bj5zwb.js";
|
|
3
|
-
import"./chunk-tcs9qjps.js";
|
|
4
|
-
import"./chunk-7k19pcg8.js";
|
|
5
|
-
import"./chunk-8dy7e2a9.js";
|
|
6
|
-
import"./chunk-9hjeemfz.js";
|
|
7
|
-
import"./chunk-1k7t7bnx.js";
|
|
8
|
-
import"./chunk-xhm1rfpt.js";
|
|
9
|
-
import"./chunk-mnwaext5.js";
|
|
10
|
-
import"./chunk-xpcps28p.js";
|
|
11
|
-
import"./chunk-fbtb3v0s.js";
|
|
12
|
-
import {
|
|
13
|
-
getTopic,
|
|
14
|
-
isTopicShared,
|
|
15
|
-
isTopicVisible,
|
|
16
|
-
upsertTopic
|
|
17
|
-
} from "./chunk-ejcm6zx8.js";
|
|
18
|
-
import"./chunk-hp4g7wx7.js";
|
|
19
|
-
import"./chunk-s74rdyqe.js";
|
|
20
|
-
import"./chunk-k778y16p.js";
|
|
21
|
-
import"./chunk-xag86ng3.js";
|
|
22
|
-
import"./chunk-wx83ep8e.js";
|
|
23
|
-
import"./chunk-00q25k7p.js";
|
|
24
|
-
import"./chunk-gaknyw04.js";
|
|
25
|
-
import"./chunk-mh5mexsf.js";
|
|
26
|
-
import"./chunk-ezs352qs.js";
|
|
27
|
-
import"./chunk-j0kjscb7.js";
|
|
28
|
-
import"./chunk-82qhv1mq.js";
|
|
29
|
-
import"./chunk-ffefbd3r.js";
|
|
30
|
-
import {
|
|
31
|
-
db
|
|
32
|
-
} from "./chunk-81tbfbmt.js";
|
|
33
|
-
import"./chunk-sffqdkvq.js";
|
|
34
|
-
import"./chunk-f5xgprg1.js";
|
|
35
|
-
import"./chunk-hwy3n31w.js";
|
|
36
|
-
|
|
37
|
-
// ../../adapters/otium/src/store.ts
|
|
38
|
-
import { createHash } from "crypto";
|
|
39
|
-
db.exec(`
|
|
40
|
-
CREATE TABLE IF NOT EXISTS otium_peer_sessions (
|
|
41
|
-
host_node_id TEXT NOT NULL,
|
|
42
|
-
host_topic_id TEXT NOT NULL,
|
|
43
|
-
local_topic_id TEXT NOT NULL,
|
|
44
|
-
binding_mode TEXT NOT NULL DEFAULT 'mirror',
|
|
45
|
-
created_at TEXT NOT NULL,
|
|
46
|
-
PRIMARY KEY (host_node_id, host_topic_id)
|
|
47
|
-
)
|
|
48
|
-
`);
|
|
49
|
-
var peerSessionColumns = new Set(db.query("PRAGMA table_info(otium_peer_sessions)").all().map((row) => row.name));
|
|
50
|
-
if (!peerSessionColumns.has("binding_mode")) {
|
|
51
|
-
db.exec("ALTER TABLE otium_peer_sessions ADD COLUMN binding_mode TEXT NOT NULL DEFAULT 'mirror'");
|
|
52
|
-
}
|
|
53
|
-
db.run(`UPDATE api_topics
|
|
54
|
-
SET visibility = 'hidden', access_mode = 'shared'
|
|
55
|
-
WHERE id IN (
|
|
56
|
-
SELECT local_topic_id FROM otium_peer_sessions WHERE binding_mode = 'mirror'
|
|
57
|
-
)`);
|
|
58
|
-
db.run(`UPDATE api_topics
|
|
59
|
-
SET access_mode = 'shared'
|
|
60
|
-
WHERE id IN (SELECT local_topic_id FROM otium_peer_sessions)`);
|
|
61
|
-
db.exec(`
|
|
62
|
-
CREATE TABLE IF NOT EXISTS otium_peer_turn_requests (
|
|
63
|
-
host_node_id TEXT NOT NULL,
|
|
64
|
-
request_id TEXT NOT NULL,
|
|
65
|
-
host_topic_id TEXT NOT NULL,
|
|
66
|
-
status TEXT NOT NULL CHECK (status IN
|
|
67
|
-
('claimed', 'running', 'finished', 'failed')),
|
|
68
|
-
error TEXT,
|
|
69
|
-
created_at TEXT NOT NULL,
|
|
70
|
-
updated_at TEXT NOT NULL,
|
|
71
|
-
PRIMARY KEY (host_node_id, request_id)
|
|
72
|
-
)
|
|
73
|
-
`);
|
|
74
|
-
db.exec(`
|
|
75
|
-
CREATE TABLE IF NOT EXISTS otium_peer_terminal_outbox (
|
|
76
|
-
host_node_id TEXT NOT NULL,
|
|
77
|
-
request_id TEXT NOT NULL,
|
|
78
|
-
seq INTEGER NOT NULL,
|
|
79
|
-
event_json TEXT NOT NULL,
|
|
80
|
-
created_at INTEGER NOT NULL,
|
|
81
|
-
updated_at INTEGER NOT NULL,
|
|
82
|
-
PRIMARY KEY (host_node_id, request_id)
|
|
83
|
-
)
|
|
84
|
-
`);
|
|
85
|
-
db.exec(`
|
|
86
|
-
CREATE TABLE IF NOT EXISTS otium_peer_inbox_requests (
|
|
87
|
-
from_cell_id TEXT NOT NULL,
|
|
88
|
-
request_id TEXT NOT NULL,
|
|
89
|
-
kind TEXT NOT NULL CHECK (kind IN ('tell', 'ask')),
|
|
90
|
-
topic_id TEXT NOT NULL,
|
|
91
|
-
payload_hash TEXT NOT NULL,
|
|
92
|
-
created_at TEXT NOT NULL,
|
|
93
|
-
PRIMARY KEY (from_cell_id, request_id, kind)
|
|
94
|
-
)
|
|
95
|
-
`);
|
|
96
|
-
db.exec(`
|
|
97
|
-
CREATE TABLE IF NOT EXISTS otium_remote_asks (
|
|
98
|
-
request_id TEXT PRIMARY KEY,
|
|
99
|
-
expected_cell_id TEXT NOT NULL,
|
|
100
|
-
user_id TEXT NOT NULL,
|
|
101
|
-
caller_topic_id TEXT NOT NULL,
|
|
102
|
-
from_key TEXT NOT NULL,
|
|
103
|
-
to_key TEXT NOT NULL,
|
|
104
|
-
source_query_id TEXT,
|
|
105
|
-
created_at INTEGER NOT NULL
|
|
106
|
-
)
|
|
107
|
-
`);
|
|
108
|
-
db.exec(`
|
|
109
|
-
CREATE INDEX IF NOT EXISTS idx_otium_remote_asks_created
|
|
110
|
-
ON otium_remote_asks(created_at)
|
|
111
|
-
`);
|
|
112
|
-
db.exec(`
|
|
113
|
-
CREATE TABLE IF NOT EXISTS otium_peer_reply_outbox (
|
|
114
|
-
node_cell_id TEXT NOT NULL,
|
|
115
|
-
request_id TEXT NOT NULL,
|
|
116
|
-
node_name TEXT NOT NULL,
|
|
117
|
-
topic_id TEXT NOT NULL,
|
|
118
|
-
user_id TEXT NOT NULL,
|
|
119
|
-
source_title TEXT NOT NULL,
|
|
120
|
-
reply_text TEXT NOT NULL,
|
|
121
|
-
kind TEXT NOT NULL CHECK (kind IN ('reply', 'error')),
|
|
122
|
-
created_at INTEGER NOT NULL,
|
|
123
|
-
updated_at INTEGER NOT NULL,
|
|
124
|
-
PRIMARY KEY (node_cell_id, request_id)
|
|
125
|
-
)
|
|
126
|
-
`);
|
|
127
|
-
function getPeerSession(hostNodeId, hostTopicId) {
|
|
128
|
-
return db.query("SELECT * FROM otium_peer_sessions WHERE host_node_id = ? AND host_topic_id = ?").get(hostNodeId, hostTopicId) ?? null;
|
|
129
|
-
}
|
|
130
|
-
function createPeerSession(hostNodeId, hostTopicId, localTopicId) {
|
|
131
|
-
const row = {
|
|
132
|
-
host_node_id: hostNodeId,
|
|
133
|
-
host_topic_id: hostTopicId,
|
|
134
|
-
local_topic_id: localTopicId,
|
|
135
|
-
binding_mode: "mirror",
|
|
136
|
-
created_at: new Date().toISOString()
|
|
137
|
-
};
|
|
138
|
-
db.run("INSERT INTO otium_peer_sessions (host_node_id, host_topic_id, local_topic_id, binding_mode, created_at) VALUES (?, ?, ?, ?, ?)", [row.host_node_id, row.host_topic_id, row.local_topic_id, row.binding_mode, row.created_at]);
|
|
139
|
-
return row;
|
|
140
|
-
}
|
|
141
|
-
function bindPeerSession(hostNodeId, hostTopicId, localTopicId, mode = "shared") {
|
|
142
|
-
const row = {
|
|
143
|
-
host_node_id: hostNodeId,
|
|
144
|
-
host_topic_id: hostTopicId,
|
|
145
|
-
local_topic_id: localTopicId,
|
|
146
|
-
binding_mode: mode,
|
|
147
|
-
created_at: new Date().toISOString()
|
|
148
|
-
};
|
|
149
|
-
db.run(`INSERT INTO otium_peer_sessions
|
|
150
|
-
(host_node_id, host_topic_id, local_topic_id, binding_mode, created_at)
|
|
151
|
-
VALUES (?, ?, ?, ?, ?)
|
|
152
|
-
ON CONFLICT(host_node_id, host_topic_id) DO UPDATE SET
|
|
153
|
-
local_topic_id = excluded.local_topic_id,
|
|
154
|
-
binding_mode = excluded.binding_mode,
|
|
155
|
-
created_at = excluded.created_at`, [hostNodeId, hostTopicId, localTopicId, mode, row.created_at]);
|
|
156
|
-
return row;
|
|
157
|
-
}
|
|
158
|
-
function unbindPeerSession(hostNodeId, hostTopicId) {
|
|
159
|
-
return db.run("DELETE FROM otium_peer_sessions WHERE host_node_id = ? AND host_topic_id = ?", [
|
|
160
|
-
hostNodeId,
|
|
161
|
-
hostTopicId
|
|
162
|
-
]).changes === 1;
|
|
163
|
-
}
|
|
164
|
-
function unbindSharedPeerSessionsForLocalTopic(localTopicId) {
|
|
165
|
-
return db.run("DELETE FROM otium_peer_sessions WHERE local_topic_id = ? AND binding_mode = 'shared'", [localTopicId]).changes;
|
|
166
|
-
}
|
|
167
|
-
function listPeerSessions() {
|
|
168
|
-
return db.query("SELECT * FROM otium_peer_sessions").all();
|
|
169
|
-
}
|
|
170
|
-
function cleanupPeerStateForLocalTopic(localTopicId) {
|
|
171
|
-
return db.transaction(() => {
|
|
172
|
-
const terminalOutbox = db.run(`DELETE FROM otium_peer_terminal_outbox
|
|
173
|
-
WHERE EXISTS (
|
|
174
|
-
SELECT 1 FROM otium_peer_turn_requests turn_request
|
|
175
|
-
JOIN otium_peer_sessions session
|
|
176
|
-
ON session.host_node_id = turn_request.host_node_id
|
|
177
|
-
AND session.host_topic_id = turn_request.host_topic_id
|
|
178
|
-
WHERE session.local_topic_id = ?
|
|
179
|
-
AND turn_request.host_node_id = otium_peer_terminal_outbox.host_node_id
|
|
180
|
-
AND turn_request.request_id = otium_peer_terminal_outbox.request_id
|
|
181
|
-
)`, [localTopicId]).changes;
|
|
182
|
-
const turns = db.run(`DELETE FROM otium_peer_turn_requests
|
|
183
|
-
WHERE EXISTS (
|
|
184
|
-
SELECT 1 FROM otium_peer_sessions session
|
|
185
|
-
WHERE session.local_topic_id = ?
|
|
186
|
-
AND session.host_node_id = otium_peer_turn_requests.host_node_id
|
|
187
|
-
AND session.host_topic_id = otium_peer_turn_requests.host_topic_id
|
|
188
|
-
)`, [localTopicId]).changes;
|
|
189
|
-
const inboxRequests = db.run("DELETE FROM otium_peer_inbox_requests WHERE topic_id = ?", [
|
|
190
|
-
localTopicId
|
|
191
|
-
]).changes;
|
|
192
|
-
const remoteAsks = db.run("DELETE FROM otium_remote_asks WHERE caller_topic_id = ?", [
|
|
193
|
-
localTopicId
|
|
194
|
-
]).changes;
|
|
195
|
-
const sessions = db.run("DELETE FROM otium_peer_sessions WHERE local_topic_id = ?", [
|
|
196
|
-
localTopicId
|
|
197
|
-
]).changes;
|
|
198
|
-
return { sessions, turns, terminalOutbox, inboxRequests, remoteAsks };
|
|
199
|
-
})();
|
|
200
|
-
}
|
|
201
|
-
function failInterruptedPeerTurnRequestsOnStartup() {
|
|
202
|
-
return db.run(`UPDATE otium_peer_turn_requests
|
|
203
|
-
SET status = 'failed', error = 'worker restarted during turn', updated_at = ?
|
|
204
|
-
WHERE status IN ('claimed', 'running')
|
|
205
|
-
AND NOT EXISTS (
|
|
206
|
-
SELECT 1 FROM otium_peer_terminal_outbox terminal
|
|
207
|
-
WHERE terminal.host_node_id = otium_peer_turn_requests.host_node_id
|
|
208
|
-
AND terminal.request_id = otium_peer_turn_requests.request_id
|
|
209
|
-
)`, [new Date().toISOString()]).changes;
|
|
210
|
-
}
|
|
211
|
-
function claimPeerTurnRequest(hostNodeId, requestId, hostTopicId) {
|
|
212
|
-
const now = new Date().toISOString();
|
|
213
|
-
const inserted = db.run(`INSERT OR IGNORE INTO otium_peer_turn_requests
|
|
214
|
-
(host_node_id, request_id, host_topic_id, status, created_at, updated_at)
|
|
215
|
-
VALUES (?, ?, ?, 'claimed', ?, ?)`, [hostNodeId, requestId, hostTopicId, now, now]);
|
|
216
|
-
const row = getPeerTurnRequest(hostNodeId, requestId);
|
|
217
|
-
if (!row)
|
|
218
|
-
throw new Error("otium peer turn request claim disappeared");
|
|
219
|
-
return { claimed: inserted.changes === 1, row };
|
|
220
|
-
}
|
|
221
|
-
function getPeerTurnRequest(hostNodeId, requestId) {
|
|
222
|
-
return db.query("SELECT * FROM otium_peer_turn_requests WHERE host_node_id = ? AND request_id = ?").get(hostNodeId, requestId) ?? null;
|
|
223
|
-
}
|
|
224
|
-
function setPeerTurnRequestStatus(hostNodeId, requestId, status, error = null) {
|
|
225
|
-
db.run(`UPDATE otium_peer_turn_requests
|
|
226
|
-
SET status = ?, error = ?, updated_at = ?
|
|
227
|
-
WHERE host_node_id = ? AND request_id = ?`, [status, error, new Date().toISOString(), hostNodeId, requestId]);
|
|
228
|
-
}
|
|
229
|
-
function markPeerTurnRequestRunning(hostNodeId, requestId) {
|
|
230
|
-
setPeerTurnRequestStatus(hostNodeId, requestId, "running");
|
|
231
|
-
}
|
|
232
|
-
function markPeerTurnRequestFinished(hostNodeId, requestId) {
|
|
233
|
-
setPeerTurnRequestStatus(hostNodeId, requestId, "finished");
|
|
234
|
-
}
|
|
235
|
-
function markPeerTurnRequestFailed(hostNodeId, requestId, error) {
|
|
236
|
-
setPeerTurnRequestStatus(hostNodeId, requestId, "failed", error);
|
|
237
|
-
}
|
|
238
|
-
function upsertPeerTerminalOutbox(args) {
|
|
239
|
-
const now = Date.now();
|
|
240
|
-
db.run(`INSERT INTO otium_peer_terminal_outbox
|
|
241
|
-
(host_node_id, request_id, seq, event_json, created_at, updated_at)
|
|
242
|
-
VALUES (?, ?, ?, ?, ?, ?)
|
|
243
|
-
ON CONFLICT(host_node_id, request_id) DO UPDATE SET
|
|
244
|
-
seq = excluded.seq, event_json = excluded.event_json, updated_at = excluded.updated_at`, [args.hostNodeId, args.requestId, args.seq, JSON.stringify(args.event), now, now]);
|
|
245
|
-
}
|
|
246
|
-
function listPeerTerminalOutbox(limit = 100) {
|
|
247
|
-
return db.query("SELECT * FROM otium_peer_terminal_outbox ORDER BY created_at LIMIT ?").all(limit);
|
|
248
|
-
}
|
|
249
|
-
function acknowledgePeerTerminal(hostNodeId, requestId) {
|
|
250
|
-
return db.transaction(() => {
|
|
251
|
-
const removed = db.run("DELETE FROM otium_peer_terminal_outbox WHERE host_node_id = ? AND request_id = ?", [hostNodeId, requestId]).changes;
|
|
252
|
-
if (removed !== 1)
|
|
253
|
-
return false;
|
|
254
|
-
markPeerTurnRequestFinished(hostNodeId, requestId);
|
|
255
|
-
return true;
|
|
256
|
-
})();
|
|
257
|
-
}
|
|
258
|
-
function peerInboxPayloadHash(value) {
|
|
259
|
-
return createHash("sha256").update(JSON.stringify(value)).digest("hex");
|
|
260
|
-
}
|
|
261
|
-
function claimPeerInboxRequest(args) {
|
|
262
|
-
const inserted = db.run(`INSERT OR IGNORE INTO otium_peer_inbox_requests
|
|
263
|
-
(from_cell_id, request_id, kind, topic_id, payload_hash, created_at)
|
|
264
|
-
VALUES (?, ?, ?, ?, ?, ?)`, [
|
|
265
|
-
args.fromCellId,
|
|
266
|
-
args.requestId,
|
|
267
|
-
args.kind,
|
|
268
|
-
args.topicId,
|
|
269
|
-
args.payloadHash,
|
|
270
|
-
new Date().toISOString()
|
|
271
|
-
]);
|
|
272
|
-
if (inserted.changes === 1)
|
|
273
|
-
return { outcome: "claimed" };
|
|
274
|
-
const existing = db.query("SELECT payload_hash FROM otium_peer_inbox_requests WHERE from_cell_id = ? AND request_id = ? AND kind = ?").get(args.fromCellId, args.requestId, args.kind);
|
|
275
|
-
if (!existing)
|
|
276
|
-
return { outcome: "conflict" };
|
|
277
|
-
return { outcome: existing.payload_hash === args.payloadHash ? "replay" : "conflict" };
|
|
278
|
-
}
|
|
279
|
-
function releasePeerInboxRequest(fromCellId, requestId, kind) {
|
|
280
|
-
db.run("DELETE FROM otium_peer_inbox_requests WHERE from_cell_id = ? AND request_id = ? AND kind = ?", [fromCellId, requestId, kind]);
|
|
281
|
-
}
|
|
282
|
-
function createRemoteAsk(args) {
|
|
283
|
-
const result = db.run(`INSERT OR IGNORE INTO otium_remote_asks
|
|
284
|
-
(request_id, expected_cell_id, user_id, caller_topic_id, from_key, to_key,
|
|
285
|
-
source_query_id, created_at)
|
|
286
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)`, [
|
|
287
|
-
args.requestId,
|
|
288
|
-
args.expectedCellId,
|
|
289
|
-
args.userId,
|
|
290
|
-
args.callerTopicId,
|
|
291
|
-
args.from,
|
|
292
|
-
args.to,
|
|
293
|
-
args.sourceQueryId ?? null,
|
|
294
|
-
args.createdAt ?? Date.now()
|
|
295
|
-
]);
|
|
296
|
-
return result.changes === 1;
|
|
297
|
-
}
|
|
298
|
-
function getRemoteAsk(requestId) {
|
|
299
|
-
return db.query("SELECT * FROM otium_remote_asks WHERE request_id = ?").get(requestId) ?? null;
|
|
300
|
-
}
|
|
301
|
-
function deleteRemoteAsk(requestId) {
|
|
302
|
-
return db.run("DELETE FROM otium_remote_asks WHERE request_id = ?", [requestId]).changes === 1;
|
|
303
|
-
}
|
|
304
|
-
function pruneRemoteAsks(olderThan) {
|
|
305
|
-
return db.run("DELETE FROM otium_remote_asks WHERE created_at < ?", [olderThan]).changes;
|
|
306
|
-
}
|
|
307
|
-
function upsertPeerReplyOutbox(args) {
|
|
308
|
-
const now = Date.now();
|
|
309
|
-
db.run(`INSERT INTO otium_peer_reply_outbox
|
|
310
|
-
(node_cell_id, request_id, node_name, topic_id, user_id, source_title,
|
|
311
|
-
reply_text, kind, created_at, updated_at)
|
|
312
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
313
|
-
ON CONFLICT(node_cell_id, request_id) DO UPDATE SET
|
|
314
|
-
node_name = excluded.node_name,
|
|
315
|
-
topic_id = excluded.topic_id,
|
|
316
|
-
user_id = excluded.user_id,
|
|
317
|
-
source_title = excluded.source_title,
|
|
318
|
-
reply_text = excluded.reply_text,
|
|
319
|
-
kind = excluded.kind,
|
|
320
|
-
updated_at = excluded.updated_at`, [
|
|
321
|
-
args.nodeCellId,
|
|
322
|
-
args.requestId,
|
|
323
|
-
args.nodeName,
|
|
324
|
-
args.topicId,
|
|
325
|
-
args.userId,
|
|
326
|
-
args.sourceTitle,
|
|
327
|
-
args.replyText,
|
|
328
|
-
args.kind,
|
|
329
|
-
now,
|
|
330
|
-
now
|
|
331
|
-
]);
|
|
332
|
-
}
|
|
333
|
-
function listPeerReplyOutbox(limit = 100) {
|
|
334
|
-
return db.query("SELECT * FROM otium_peer_reply_outbox ORDER BY created_at LIMIT ?").all(limit);
|
|
335
|
-
}
|
|
336
|
-
function deletePeerReplyOutbox(nodeCellId, requestId) {
|
|
337
|
-
return db.run("DELETE FROM otium_peer_reply_outbox WHERE node_cell_id = ? AND request_id = ?", [
|
|
338
|
-
nodeCellId,
|
|
339
|
-
requestId
|
|
340
|
-
]).changes === 1;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
// ../../adapters/otium/src/bindings.ts
|
|
344
|
-
function ownsTopic(localTopicId, userId) {
|
|
345
|
-
const topic = getTopic(localTopicId);
|
|
346
|
-
if (!topic)
|
|
347
|
-
return { ok: false, error: "local topic not found", status: 404 };
|
|
348
|
-
if (!isTopicVisible(topic)) {
|
|
349
|
-
return { ok: false, error: "internal topics have no user access mode", status: 409 };
|
|
350
|
-
}
|
|
351
|
-
if (!topic.participants.some((participant) => participant.userId === userId)) {
|
|
352
|
-
return { ok: false, error: "local topic is not visible to this user", status: 403 };
|
|
353
|
-
}
|
|
354
|
-
if (!topic.participants.some((participant) => participant.userId === userId && participant.role === "owner")) {
|
|
355
|
-
return {
|
|
356
|
-
ok: false,
|
|
357
|
-
error: "only a topic owner can change its access mode",
|
|
358
|
-
status: 403
|
|
359
|
-
};
|
|
360
|
-
}
|
|
361
|
-
return { ok: true, topic };
|
|
362
|
-
}
|
|
363
|
-
function bindOtiumTopic(options) {
|
|
364
|
-
const topic = getTopic(options.localTopicId);
|
|
365
|
-
if (!topic)
|
|
366
|
-
return { ok: false, error: "local topic not found", status: 404 };
|
|
367
|
-
if (!isTopicVisible(topic)) {
|
|
368
|
-
return { ok: false, error: "hidden local topics cannot be shared", status: 409 };
|
|
369
|
-
}
|
|
370
|
-
if (!topic.participants.some((participant) => participant.userId === options.userId)) {
|
|
371
|
-
return { ok: false, error: "local topic is not visible to this user", status: 403 };
|
|
372
|
-
}
|
|
373
|
-
if (!isTopicShared(topic)) {
|
|
374
|
-
return { ok: false, error: "private topics must be shared explicitly first", status: 409 };
|
|
375
|
-
}
|
|
376
|
-
const previous = getPeerSession(options.hostNodeId, options.hostTopicId);
|
|
377
|
-
bindPeerSession(options.hostNodeId, options.hostTopicId, options.localTopicId, "shared");
|
|
378
|
-
return {
|
|
379
|
-
ok: true,
|
|
380
|
-
localTopicId: options.localTopicId,
|
|
381
|
-
replaced: Boolean(previous && previous.local_topic_id !== options.localTopicId)
|
|
382
|
-
};
|
|
383
|
-
}
|
|
384
|
-
function shareOtiumTopic(options) {
|
|
385
|
-
const owned = ownsTopic(options.localTopicId, options.userId);
|
|
386
|
-
if (!owned.ok)
|
|
387
|
-
return owned;
|
|
388
|
-
if (!isTopicShared(owned.topic)) {
|
|
389
|
-
upsertTopic({ ...owned.topic, accessMode: "shared" });
|
|
390
|
-
}
|
|
391
|
-
return bindOtiumTopic(options);
|
|
392
|
-
}
|
|
393
|
-
function setOtiumTopicPrivate(options) {
|
|
394
|
-
const owned = ownsTopic(options.localTopicId, options.userId);
|
|
395
|
-
if (!owned.ok)
|
|
396
|
-
return owned;
|
|
397
|
-
const removedBindings = unbindSharedPeerSessionsForLocalTopic(options.localTopicId);
|
|
398
|
-
if (isTopicShared(owned.topic)) {
|
|
399
|
-
upsertTopic({ ...owned.topic, accessMode: "private" });
|
|
400
|
-
}
|
|
401
|
-
return { ok: true, localTopicId: options.localTopicId, removedBindings };
|
|
402
|
-
}
|
|
403
|
-
function unbindOtiumTopic(hostNodeId, hostTopicId) {
|
|
404
|
-
return unbindPeerSession(hostNodeId, hostTopicId);
|
|
405
|
-
}
|
|
406
|
-
function listOtiumTopicBindings() {
|
|
407
|
-
return listPeerSessions().map((row) => {
|
|
408
|
-
const topic = getTopic(row.local_topic_id);
|
|
409
|
-
return {
|
|
410
|
-
hostNodeId: row.host_node_id,
|
|
411
|
-
hostTopicId: row.host_topic_id,
|
|
412
|
-
localTopicId: row.local_topic_id,
|
|
413
|
-
transport: row.binding_mode === "shared" ? "shared-binding" : "internal-mirror",
|
|
414
|
-
...topic ? { topicAccessMode: topic.accessMode ?? "private" } : {},
|
|
415
|
-
...topic ? { localTopicTitle: topic.title } : {},
|
|
416
|
-
localTopicExists: Boolean(topic),
|
|
417
|
-
createdAt: row.created_at
|
|
418
|
-
};
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
export {
|
|
422
|
-
unbindOtiumTopic,
|
|
423
|
-
shareOtiumTopic,
|
|
424
|
-
setOtiumTopicPrivate,
|
|
425
|
-
listOtiumTopicBindings,
|
|
426
|
-
bindOtiumTopic
|
|
427
|
-
};
|
|
428
|
-
|
|
429
|
-
export { getPeerSession, createPeerSession, cleanupPeerStateForLocalTopic, failInterruptedPeerTurnRequestsOnStartup, claimPeerTurnRequest, getPeerTurnRequest, markPeerTurnRequestRunning, markPeerTurnRequestFailed, upsertPeerTerminalOutbox, listPeerTerminalOutbox, acknowledgePeerTerminal, peerInboxPayloadHash, claimPeerInboxRequest, releasePeerInboxRequest, createRemoteAsk, getRemoteAsk, deleteRemoteAsk, pruneRemoteAsks, upsertPeerReplyOutbox, listPeerReplyOutbox, deletePeerReplyOutbox, bindOtiumTopic, shareOtiumTopic, setOtiumTopicPrivate, unbindOtiumTopic, listOtiumTopicBindings };
|
|
430
|
-
|
|
431
|
-
//# debugId=65C2ED917F2D30E764756E2164756E21
|