negotium 0.1.7 → 0.1.9
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 +26 -2
- package/dist/canonical-mcp-bridge.js +14 -0
- package/dist/canonical-mcp-bridge.js.map +9 -0
- package/dist/chunk-10ct8814.js +429 -0
- package/dist/chunk-10ct8814.js.map +11 -0
- package/dist/chunk-18fzftjf.js +214 -0
- package/dist/chunk-18fzftjf.js.map +10 -0
- package/dist/chunk-1k7t7bnx.js +97 -0
- package/dist/chunk-1k7t7bnx.js.map +10 -0
- package/dist/chunk-1msje2zf.js +23 -0
- package/dist/chunk-1msje2zf.js.map +10 -0
- package/dist/chunk-2dgkah1z.js +706 -0
- package/dist/chunk-2dgkah1z.js.map +14 -0
- package/dist/chunk-3t4dtm26.js +61 -0
- package/dist/chunk-3t4dtm26.js.map +10 -0
- package/dist/chunk-3vn2vnj1.js +51 -0
- package/dist/chunk-3vn2vnj1.js.map +10 -0
- package/dist/chunk-6hknphtc.js +2054 -0
- package/dist/chunk-6hknphtc.js.map +29 -0
- package/dist/chunk-6tfzpcvk.js +2149 -0
- package/dist/chunk-6tfzpcvk.js.map +15 -0
- package/dist/chunk-8g0c4as0.js +23 -0
- package/dist/chunk-8g0c4as0.js.map +10 -0
- package/dist/chunk-9spx3h9n.js +279 -0
- package/dist/chunk-9spx3h9n.js.map +10 -0
- package/dist/chunk-c500xe9z.js +33 -0
- package/dist/chunk-c500xe9z.js.map +10 -0
- package/dist/chunk-e9b2xpff.js +147 -0
- package/dist/chunk-e9b2xpff.js.map +10 -0
- package/dist/chunk-edb07sjp.js +567 -0
- package/dist/chunk-edb07sjp.js.map +14 -0
- package/dist/chunk-eexqsee7.js +368 -0
- package/dist/chunk-eexqsee7.js.map +11 -0
- package/dist/chunk-efyxk97v.js +500 -0
- package/dist/chunk-efyxk97v.js.map +13 -0
- package/dist/chunk-epqxwkvh.js +3534 -0
- package/dist/chunk-epqxwkvh.js.map +20 -0
- package/dist/chunk-f1pzh3xh.js +115 -0
- package/dist/chunk-f1pzh3xh.js.map +10 -0
- package/dist/chunk-f5xgprg1.js +59 -0
- package/dist/chunk-f5xgprg1.js.map +10 -0
- package/dist/chunk-f97qybwk.js +584 -0
- package/dist/chunk-f97qybwk.js.map +11 -0
- package/dist/chunk-fvc7ncxd.js +252 -0
- package/dist/chunk-fvc7ncxd.js.map +10 -0
- package/dist/chunk-g7pvfj5e.js +574 -0
- package/dist/chunk-g7pvfj5e.js.map +14 -0
- package/dist/chunk-h8vmb9gf.js +315 -0
- package/dist/chunk-h8vmb9gf.js.map +10 -0
- package/dist/chunk-hgw7n8cm.js +43 -0
- package/dist/chunk-hgw7n8cm.js.map +10 -0
- package/dist/chunk-hsq7j9jk.js +126 -0
- package/dist/chunk-hsq7j9jk.js.map +10 -0
- package/dist/chunk-hwy3n31w.js +21 -0
- package/dist/chunk-hwy3n31w.js.map +9 -0
- package/dist/chunk-j0kjscb7.js +53 -0
- package/dist/chunk-j0kjscb7.js.map +10 -0
- package/dist/chunk-jzz91jwh.js +70 -0
- package/dist/chunk-jzz91jwh.js.map +10 -0
- package/dist/chunk-k9z47mab.js +247 -0
- package/dist/chunk-k9z47mab.js.map +12 -0
- package/dist/chunk-kbm35t7w.js +1331 -0
- package/dist/chunk-kbm35t7w.js.map +16 -0
- package/dist/chunk-m4veth0c.js +1649 -0
- package/dist/chunk-m4veth0c.js.map +17 -0
- package/dist/chunk-mhty3nna.js +150 -0
- package/dist/chunk-mhty3nna.js.map +11 -0
- package/dist/chunk-mmgh670x.js +248 -0
- package/dist/chunk-mmgh670x.js.map +11 -0
- package/dist/chunk-n0kk5xbq.js +2358 -0
- package/dist/chunk-n0kk5xbq.js.map +26 -0
- package/dist/chunk-nmv41qx9.js +2847 -0
- package/dist/chunk-nmv41qx9.js.map +23 -0
- package/dist/chunk-nqdp52aj.js +113 -0
- package/dist/chunk-nqdp52aj.js.map +12 -0
- package/dist/chunk-ns2m25dz.js +139 -0
- package/dist/chunk-ns2m25dz.js.map +10 -0
- package/dist/chunk-pkdmypdd.js +147 -0
- package/dist/chunk-pkdmypdd.js.map +11 -0
- package/dist/chunk-rmyfmrrr.js +1634 -0
- package/dist/chunk-rmyfmrrr.js.map +15 -0
- package/dist/chunk-sa874j5c.js +9 -0
- package/dist/chunk-sa874j5c.js.map +10 -0
- package/dist/chunk-sgsz2fpq.js +289 -0
- package/dist/chunk-sgsz2fpq.js.map +10 -0
- package/dist/chunk-sn51wnf1.js +3020 -0
- package/dist/chunk-sn51wnf1.js.map +32 -0
- package/dist/chunk-sqhr1a7e.js +587 -0
- package/dist/chunk-sqhr1a7e.js.map +11 -0
- package/dist/chunk-tmj5r2zv.js +2933 -0
- package/dist/chunk-tmj5r2zv.js.map +20 -0
- package/dist/chunk-vefj3880.js +56 -0
- package/dist/chunk-vefj3880.js.map +10 -0
- package/dist/chunk-vp2db42d.js +121 -0
- package/dist/chunk-vp2db42d.js.map +10 -0
- package/dist/chunk-wry79q55.js +108 -0
- package/dist/chunk-wry79q55.js.map +10 -0
- package/dist/chunk-x1arr7ze.js +63 -0
- package/dist/chunk-x1arr7ze.js.map +10 -0
- package/dist/chunk-z2xy5n2q.js +103 -0
- package/dist/chunk-z2xy5n2q.js.map +10 -0
- package/dist/hosted-agent.js +53 -0
- package/dist/hosted-agent.js.map +10 -0
- package/dist/main.js +132 -20
- package/dist/main.js.map +4 -4
- package/dist/runtime/scripts/faster-whisper-wrapper.py +87 -0
- package/dist/runtime/scripts/mcp-patchright-http.mjs +349 -0
- package/dist/runtime/src/agents/api-topic-agent-switch.ts +178 -0
- package/dist/runtime/src/agents/archiver.ts +396 -0
- package/dist/runtime/src/agents/auth-check.ts +64 -0
- package/dist/runtime/src/agents/claude-provider.ts +737 -0
- package/dist/runtime/src/agents/claude-registry.ts +115 -0
- package/dist/runtime/src/agents/codex-native-multi-agent.ts +177 -0
- package/dist/runtime/src/agents/codex-provider.ts +785 -0
- package/dist/runtime/src/agents/codex-registry.ts +115 -0
- package/dist/runtime/src/agents/codex-tree-kill.ts +365 -0
- package/dist/runtime/src/agents/contracts.ts +69 -0
- package/dist/runtime/src/agents/deep-map.ts +13 -0
- package/dist/runtime/src/agents/execution-host.ts +91 -0
- package/dist/runtime/src/agents/fixtures/claude-attachments.jsonl +2 -0
- package/dist/runtime/src/agents/fixtures/codex-shell.jsonl +5 -0
- package/dist/runtime/src/agents/fork.ts +65 -0
- package/dist/runtime/src/agents/hosted-agent.ts +49 -0
- package/dist/runtime/src/agents/idle-archiver.ts +128 -0
- package/dist/runtime/src/agents/index.ts +205 -0
- package/dist/runtime/src/agents/maestro-provider.ts +206 -0
- package/dist/runtime/src/agents/maestro-registry.ts +31 -0
- package/dist/runtime/src/agents/mcp-tools/ask-user.ts +280 -0
- package/dist/runtime/src/agents/mcp-tools/common.ts +21 -0
- package/dist/runtime/src/agents/mcp-tools/self-config.ts +220 -0
- package/dist/runtime/src/agents/mcp-tools/spawn-subagent.ts +525 -0
- package/dist/runtime/src/agents/mcp-tools/visuals.ts +88 -0
- package/dist/runtime/src/agents/model-catalog.ts +151 -0
- package/dist/runtime/src/agents/registry.ts +24 -0
- package/dist/runtime/src/agents/rollout/claude.ts +331 -0
- package/dist/runtime/src/agents/rollout/codex.ts +569 -0
- package/dist/runtime/src/agents/rollout/shared.ts +205 -0
- package/dist/runtime/src/agents/self-config-core.ts +415 -0
- package/dist/runtime/src/agents/task-events.ts +44 -0
- package/dist/runtime/src/agents/tool-format.ts +352 -0
- package/dist/runtime/src/agents/topic-agent-switch.ts +193 -0
- package/dist/runtime/src/agents/topic-cleanup.ts +231 -0
- package/dist/runtime/src/agents/vault-tool-policy.ts +33 -0
- package/dist/runtime/src/application/execute-external-user-turn.ts +23 -0
- package/dist/runtime/src/application/submit-user-message.ts +50 -0
- package/dist/runtime/src/application/switch-topic-effort.ts +48 -0
- package/dist/runtime/src/application/switch-topic-model.ts +79 -0
- package/dist/runtime/src/application/topic-service.ts +139 -0
- package/dist/runtime/src/application/vault-command.ts +170 -0
- package/dist/runtime/src/bus.ts +319 -0
- package/dist/runtime/src/index.ts +333 -0
- package/dist/runtime/src/mcp/agent-health-server.ts +309 -0
- package/dist/runtime/src/mcp/background-bash-server.ts +346 -0
- package/dist/runtime/src/mcp/canonical-bridge-config.ts +84 -0
- package/dist/runtime/src/mcp/canonical-proxy-server.ts +171 -0
- package/dist/runtime/src/mcp/dm-ipc.ts +60 -0
- package/dist/runtime/src/mcp/mcp-helpers.ts +40 -0
- package/dist/runtime/src/mcp/paddleocr-server.ts +105 -0
- package/dist/runtime/src/mcp/peer-bridge.ts +114 -0
- package/dist/runtime/src/mcp/runtime-spec.ts +137 -0
- package/dist/runtime/src/mcp/session-comm/bridge-ipc-config.ts +27 -0
- package/dist/runtime/src/mcp/session-comm/peer-forward.ts +165 -0
- package/dist/runtime/src/mcp/session-comm/runtime.ts +115 -0
- package/dist/runtime/src/mcp/session-comm/server.ts +649 -0
- package/dist/runtime/src/mcp/session-comm/topic-config.ts +131 -0
- package/dist/runtime/src/mcp/session-comm/topics.ts +229 -0
- package/dist/runtime/src/mcp/stdio-protect.ts +84 -0
- package/dist/runtime/src/mcp/system-health-server.ts +130 -0
- package/dist/runtime/src/mcp/task-server.ts +173 -0
- package/dist/runtime/src/mcp/token-stats-server.ts +98 -0
- package/dist/runtime/src/mcp/vault-http.ts +219 -0
- package/dist/runtime/src/mcp/vault-run.ts +153 -0
- package/dist/runtime/src/mcp/vault-server.ts +104 -0
- package/dist/runtime/src/mcp/wiki-server.ts +755 -0
- package/dist/runtime/src/media/file-events.ts +33 -0
- package/dist/runtime/src/media/text-extractor.ts +312 -0
- package/dist/runtime/src/media/video.ts +92 -0
- package/dist/runtime/src/outbox/file-ops.ts +210 -0
- package/dist/runtime/src/outbox/index.ts +8 -0
- package/dist/runtime/src/outbox/utils.ts +51 -0
- package/dist/runtime/src/platform/background-bash/manager.ts +279 -0
- package/dist/runtime/src/platform/config.ts +371 -0
- package/dist/runtime/src/platform/constants.ts +18 -0
- package/dist/runtime/src/platform/debug-users.ts +14 -0
- package/dist/runtime/src/platform/delay.ts +1 -0
- package/dist/runtime/src/platform/error.ts +9 -0
- package/dist/runtime/src/platform/file-utils.ts +16 -0
- package/dist/runtime/src/platform/jsonl.ts +202 -0
- package/dist/runtime/src/platform/lifecycle.ts +174 -0
- package/dist/runtime/src/platform/logger.ts +31 -0
- package/dist/runtime/src/platform/maestro-bootstrap-env.ts +3 -0
- package/dist/runtime/src/platform/mcp-config.ts +878 -0
- package/dist/runtime/src/platform/modules.ts +145 -0
- package/dist/runtime/src/platform/node-plugins.ts +46 -0
- package/dist/runtime/src/platform/playwright/manager.ts +1233 -0
- package/dist/runtime/src/prompts/agents/wiki-archiver.md +261 -0
- package/dist/runtime/src/prompts/builders.ts +368 -0
- package/dist/runtime/src/prompts/sessions/channel-system.md +48 -0
- package/dist/runtime/src/prompts/sessions/manager-system.md +37 -0
- package/dist/runtime/src/prompts/sessions/topic-system.md +47 -0
- package/dist/runtime/src/prompts/sessions/visual-design.md +86 -0
- package/dist/runtime/src/query/active-rooms.ts +534 -0
- package/dist/runtime/src/query/control.ts +313 -0
- package/dist/runtime/src/query/index.ts +24 -0
- package/dist/runtime/src/query/session-inbox-cleanup.ts +44 -0
- package/dist/runtime/src/query/session-inbox-path.ts +42 -0
- package/dist/runtime/src/query/state.ts +94 -0
- package/dist/runtime/src/query/types.ts +83 -0
- package/dist/runtime/src/runtime/ask-callbacks.ts +153 -0
- package/dist/runtime/src/runtime/attachments.ts +151 -0
- package/dist/runtime/src/runtime/background-sessions.ts +83 -0
- package/dist/runtime/src/runtime/channel-context.ts +107 -0
- package/dist/runtime/src/runtime/errors.ts +69 -0
- package/dist/runtime/src/runtime/event-heartbeat.ts +77 -0
- package/dist/runtime/src/runtime/file-hooks.ts +81 -0
- package/dist/runtime/src/runtime/footer.ts +23 -0
- package/dist/runtime/src/runtime/inbox.ts +946 -0
- package/dist/runtime/src/runtime/tasks.ts +56 -0
- package/dist/runtime/src/runtime/topic-config.ts +29 -0
- package/dist/runtime/src/runtime/turn-runner.ts +2298 -0
- package/dist/runtime/src/runtime/usage-alert.ts +84 -0
- package/dist/runtime/src/runtime/visual-html.ts +109 -0
- package/dist/runtime/src/runtime/visual-store.ts +430 -0
- package/dist/runtime/src/runtime/visuals.ts +171 -0
- package/dist/runtime/src/security/sanitize.ts +27 -0
- package/dist/runtime/src/security/sensitive-path.ts +34 -0
- package/dist/runtime/src/storage/activity-log.ts +152 -0
- package/dist/runtime/src/storage/api-messages.ts +617 -0
- package/dist/runtime/src/storage/api-topic-brief.ts +127 -0
- package/dist/runtime/src/storage/api-topic-config.ts +192 -0
- package/dist/runtime/src/storage/api-topics.ts +844 -0
- package/dist/runtime/src/storage/app-settings.ts +44 -0
- package/dist/runtime/src/storage/browser-profiles.ts +133 -0
- package/dist/runtime/src/storage/conversations.ts +268 -0
- package/dist/runtime/src/storage/forum/agent-settings.ts +20 -0
- package/dist/runtime/src/storage/forum/index.ts +4 -0
- package/dist/runtime/src/storage/forum/repository.ts +283 -0
- package/dist/runtime/src/storage/forum/schema.ts +300 -0
- package/dist/runtime/src/storage/forum-db.ts +23 -0
- package/dist/runtime/src/storage/runtime-events.ts +130 -0
- package/dist/runtime/src/storage/runtime-leases.ts +189 -0
- package/dist/runtime/src/storage/runtime-process-leases.ts +216 -0
- package/dist/runtime/src/storage/runtime-topic-state.ts +148 -0
- package/dist/runtime/src/storage/runtime-turn-requests.ts +301 -0
- package/dist/runtime/src/storage/self-schedules.ts +298 -0
- package/dist/runtime/src/storage/session-asks.ts +347 -0
- package/dist/runtime/src/storage/sqlite.ts +129 -0
- package/dist/runtime/src/storage/tasks.ts +179 -0
- package/dist/runtime/src/storage/token-stats.ts +144 -0
- package/dist/runtime/src/storage/topic-archive-state.ts +59 -0
- package/dist/runtime/src/storage/topic-archive.ts +74 -0
- package/dist/runtime/src/storage/topic-settings.ts +67 -0
- package/dist/runtime/src/storage/topic-transcript.ts +98 -0
- package/dist/runtime/src/storage/vault-crypto.ts +65 -0
- package/dist/runtime/src/storage/vault.ts +225 -0
- package/dist/runtime/src/storage/wiki-summary-names.ts +33 -0
- package/dist/runtime/src/storage/wiki.ts +85 -0
- package/dist/runtime/src/topics/create.ts +123 -0
- package/dist/runtime/src/topics/derive.ts +398 -0
- package/dist/runtime/src/topics/lifecycle.ts +311 -0
- package/dist/runtime/src/topics/links.ts +7 -0
- package/dist/runtime/src/topics/personal-general.ts +65 -0
- package/dist/runtime/src/topics/session.ts +381 -0
- package/dist/runtime/src/types/api.ts +497 -0
- package/dist/runtime/src/types.ts +257 -0
- package/dist/runtime/src/version.ts +1 -0
- package/dist/runtime/tsconfig.json +13 -0
- package/package.json +28 -3
- package/dist/main.d.ts +0 -3
- package/dist/main.d.ts.map +0 -1
package/dist/main.js
CHANGED
|
@@ -1,24 +1,136 @@
|
|
|
1
1
|
#!/usr/bin/env bun
|
|
2
2
|
// @bun
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (!__hasOwnProp.call(to, key))
|
|
13
|
-
__defProp(to, key, {
|
|
14
|
-
get: () => mod[key],
|
|
15
|
-
enumerable: true
|
|
16
|
-
});
|
|
17
|
-
return to;
|
|
18
|
-
};
|
|
19
|
-
var __require = import.meta.require;
|
|
3
|
+
import {
|
|
4
|
+
loadOtiumCli,
|
|
5
|
+
loadTelegramCli,
|
|
6
|
+
loadTerminalCli
|
|
7
|
+
} from "./chunk-8g0c4as0.js";
|
|
8
|
+
import {
|
|
9
|
+
__require,
|
|
10
|
+
__toESM
|
|
11
|
+
} from "./chunk-hwy3n31w.js";
|
|
20
12
|
|
|
21
|
-
// src/main.ts
|
|
22
|
-
|
|
13
|
+
// ../cli/src/main.ts
|
|
14
|
+
var [, , command, ...args] = process.argv;
|
|
15
|
+
function numericOption(values, name, fallback) {
|
|
16
|
+
const prefix = `--${name}=`;
|
|
17
|
+
const parsed = Number.parseInt(values.find((value) => value.startsWith(prefix))?.slice(prefix.length) ?? "", 10);
|
|
18
|
+
return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;
|
|
19
|
+
}
|
|
20
|
+
switch (command) {
|
|
21
|
+
case "init": {
|
|
22
|
+
const { initCommand } = await import("./chunk-vefj3880.js");
|
|
23
|
+
initCommand();
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
case "chat": {
|
|
27
|
+
const { chatCommand } = await import("./chunk-mmgh670x.js");
|
|
28
|
+
await chatCommand(args);
|
|
29
|
+
break;
|
|
30
|
+
}
|
|
31
|
+
case "serve": {
|
|
32
|
+
const { startDefaultNode } = await import("./chunk-rmyfmrrr.js");
|
|
33
|
+
const node = await startDefaultNode({
|
|
34
|
+
port: numericOption(args, "port", 7777),
|
|
35
|
+
advertise: true,
|
|
36
|
+
singleton: true
|
|
37
|
+
});
|
|
38
|
+
console.log(`negotium node listening on 127.0.0.1:${node.port} (ctrl-c to stop)`);
|
|
39
|
+
await node.completed;
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
case "__node-daemon": {
|
|
43
|
+
const { runNodeDaemon } = await import("./chunk-rmyfmrrr.js");
|
|
44
|
+
await runNodeDaemon({ port: numericOption(args, "port", 0) });
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
case "status": {
|
|
48
|
+
const { inspectNodeDaemon } = await import("./chunk-rmyfmrrr.js");
|
|
49
|
+
const status = await inspectNodeDaemon();
|
|
50
|
+
if (status.running && status.info) {
|
|
51
|
+
console.log(`negotium node running (pid ${status.info.pid}, 127.0.0.1:${status.info.port}, since ${status.info.startedAt})`);
|
|
52
|
+
} else if (status.info) {
|
|
53
|
+
console.log(`negotium node not responding (last pid ${status.info.pid}${status.error ? `: ${status.error}` : ""})`);
|
|
54
|
+
process.exitCode = 1;
|
|
55
|
+
} else {
|
|
56
|
+
console.log("negotium node is stopped");
|
|
57
|
+
}
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
case "stop": {
|
|
61
|
+
const { stopNodeDaemon } = await import("./chunk-rmyfmrrr.js");
|
|
62
|
+
const stopped = await stopNodeDaemon();
|
|
63
|
+
console.log(stopped ? "negotium node shutdown requested" : "negotium node is not running");
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
case "topics": {
|
|
67
|
+
const { topicsCommand } = await import("./chunk-3vn2vnj1.js");
|
|
68
|
+
topicsCommand();
|
|
69
|
+
break;
|
|
70
|
+
}
|
|
71
|
+
case "mcp": {
|
|
72
|
+
const { mcpCommand } = await import("./chunk-jzz91jwh.js");
|
|
73
|
+
mcpCommand(args);
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
case "vault": {
|
|
77
|
+
const { vaultCommand } = await import("./chunk-f1pzh3xh.js");
|
|
78
|
+
vaultCommand(args);
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
case "cron": {
|
|
82
|
+
const { cronCommand } = await import("./chunk-9spx3h9n.js");
|
|
83
|
+
await cronCommand(args);
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case "terminal": {
|
|
87
|
+
const { runTerminalCli } = await loadTerminalCli();
|
|
88
|
+
await runTerminalCli(args);
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
case "telegram": {
|
|
92
|
+
const { runTelegramCli } = await loadTelegramCli();
|
|
93
|
+
await runTelegramCli();
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
case "otium": {
|
|
97
|
+
const { runOtiumCli } = await loadOtiumCli();
|
|
98
|
+
await runOtiumCli(args);
|
|
99
|
+
break;
|
|
100
|
+
}
|
|
101
|
+
case "start":
|
|
102
|
+
case "adapters": {
|
|
103
|
+
const { adaptersCommand } = await import("./chunk-3t4dtm26.js");
|
|
104
|
+
await adaptersCommand(args);
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
default: {
|
|
108
|
+
console.log([
|
|
109
|
+
"negotium \u2014 turn this computer into an agent node",
|
|
110
|
+
"",
|
|
111
|
+
"usage: negotium <init|chat|serve|status|stop|topics|mcp|vault|cron|terminal|telegram|otium|start> [args]",
|
|
112
|
+
"",
|
|
113
|
+
" init bootstrap ~/.negotium and check agent auth",
|
|
114
|
+
" chat [topic] interactive chat (creates the topic if missing)",
|
|
115
|
+
" options: --agent=claude|codex|maestro",
|
|
116
|
+
" serve foreground long-lived node (default port 7777)",
|
|
117
|
+
" status show the local long-lived node status",
|
|
118
|
+
" stop stop the local long-lived node",
|
|
119
|
+
" topics list topics on this node",
|
|
120
|
+
" mcp list|add|remove|enable|disable manage node MCP manifest",
|
|
121
|
+
" vault list|set|get|del node secret store (encrypted at rest)",
|
|
122
|
+
" cron list|create|inspect|logs|run|pause|resume|restart|kill|reset|delete",
|
|
123
|
+
" terminal TUI client; auto-starts and connects to the local node",
|
|
124
|
+
" options: --embedded, --connect=http://host:port, --port=N",
|
|
125
|
+
" telegram Telegram adapter (configured from environment)",
|
|
126
|
+
" otium join|serve join an Otium workspace or serve its worker routes",
|
|
127
|
+
" start <terminal|telegram|otium> run one channel process",
|
|
128
|
+
" Terminal clients may run more than once and share one node"
|
|
129
|
+
].join(`
|
|
130
|
+
`));
|
|
131
|
+
if (command && command !== "help" && command !== "--help")
|
|
132
|
+
process.exitCode = 1;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
23
135
|
|
|
24
|
-
//# debugId=
|
|
136
|
+
//# debugId=29B5A521D233AB8564756E2164756E21
|
package/dist/main.js.map
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
|
-
"sources": ["
|
|
3
|
+
"sources": ["../../cli/src/main.ts"],
|
|
4
4
|
"sourcesContent": [
|
|
5
|
-
"#!/usr/bin/env bun\n\n
|
|
5
|
+
"#!/usr/bin/env bun\n\nimport { loadOtiumCli, loadTelegramCli, loadTerminalCli } from \"@/adapter-loader\";\n\nconst [, , command, ...args] = process.argv;\n\nfunction numericOption(values: string[], name: string, fallback: number): number {\n const prefix = `--${name}=`;\n const parsed = Number.parseInt(\n values.find((value) => value.startsWith(prefix))?.slice(prefix.length) ?? \"\",\n 10,\n );\n return Number.isInteger(parsed) && parsed >= 0 ? parsed : fallback;\n}\n\nswitch (command) {\n case \"init\": {\n const { initCommand } = await import(\"@/commands/init\");\n initCommand();\n break;\n }\n case \"chat\": {\n const { chatCommand } = await import(\"@/commands/chat\");\n await chatCommand(args);\n break;\n }\n case \"serve\": {\n const { startDefaultNode } = await import(\"@negotium/node\");\n const node = await startDefaultNode({\n port: numericOption(args, \"port\", 7777),\n advertise: true,\n singleton: true,\n });\n console.log(`negotium node listening on 127.0.0.1:${node.port} (ctrl-c to stop)`);\n await node.completed;\n break;\n }\n case \"__node-daemon\": {\n const { runNodeDaemon } = await import(\"@negotium/node\");\n await runNodeDaemon({ port: numericOption(args, \"port\", 0) });\n break;\n }\n case \"status\": {\n const { inspectNodeDaemon } = await import(\"@negotium/node\");\n const status = await inspectNodeDaemon();\n if (status.running && status.info) {\n console.log(\n `negotium node running (pid ${status.info.pid}, 127.0.0.1:${status.info.port}, since ${status.info.startedAt})`,\n );\n } else if (status.info) {\n console.log(\n `negotium node not responding (last pid ${status.info.pid}${status.error ? `: ${status.error}` : \"\"})`,\n );\n process.exitCode = 1;\n } else {\n console.log(\"negotium node is stopped\");\n }\n break;\n }\n case \"stop\": {\n const { stopNodeDaemon } = await import(\"@negotium/node\");\n const stopped = await stopNodeDaemon();\n console.log(stopped ? \"negotium node shutdown requested\" : \"negotium node is not running\");\n break;\n }\n case \"topics\": {\n const { topicsCommand } = await import(\"@/commands/topics\");\n topicsCommand();\n break;\n }\n case \"mcp\": {\n const { mcpCommand } = await import(\"@/commands/mcp\");\n mcpCommand(args);\n break;\n }\n case \"vault\": {\n const { vaultCommand } = await import(\"@/commands/vault\");\n vaultCommand(args);\n break;\n }\n case \"cron\": {\n const { cronCommand } = await import(\"@/commands/cron\");\n await cronCommand(args);\n break;\n }\n case \"terminal\": {\n const { runTerminalCli } = await loadTerminalCli();\n await runTerminalCli(args);\n break;\n }\n case \"telegram\": {\n const { runTelegramCli } = await loadTelegramCli();\n await runTelegramCli();\n break;\n }\n case \"otium\": {\n const { runOtiumCli } = await loadOtiumCli();\n await runOtiumCli(args);\n break;\n }\n case \"start\":\n case \"adapters\": {\n const { adaptersCommand } = await import(\"@/commands/adapters\");\n await adaptersCommand(args);\n break;\n }\n default: {\n console.log(\n [\n \"negotium — turn this computer into an agent node\",\n \"\",\n \"usage: negotium <init|chat|serve|status|stop|topics|mcp|vault|cron|terminal|telegram|otium|start> [args]\",\n \"\",\n \" init bootstrap ~/.negotium and check agent auth\",\n \" chat [topic] interactive chat (creates the topic if missing)\",\n \" options: --agent=claude|codex|maestro\",\n \" serve foreground long-lived node (default port 7777)\",\n \" status show the local long-lived node status\",\n \" stop stop the local long-lived node\",\n \" topics list topics on this node\",\n \" mcp list|add|remove|enable|disable manage node MCP manifest\",\n \" vault list|set|get|del node secret store (encrypted at rest)\",\n \" cron list|create|inspect|logs|run|pause|resume|restart|kill|reset|delete\",\n \" terminal TUI client; auto-starts and connects to the local node\",\n \" options: --embedded, --connect=http://host:port, --port=N\",\n \" telegram Telegram adapter (configured from environment)\",\n \" otium join|serve join an Otium workspace or serve its worker routes\",\n \" start <terminal|telegram|otium> run one channel process\",\n \" Terminal clients may run more than once and share one node\",\n ].join(\"\\n\"),\n );\n if (command && command !== \"help\" && command !== \"--help\") process.exitCode = 1;\n }\n}\n"
|
|
6
6
|
],
|
|
7
|
-
"mappings": "
|
|
8
|
-
"debugId": "
|
|
7
|
+
"mappings": "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",
|
|
8
|
+
"debugId": "29B5A521D233AB8564756E2164756E21",
|
|
9
9
|
"names": []
|
|
10
10
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""faster-whisper wrapper used by Otium media extraction.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
faster-whisper-wrapper.py INPUT --model MODEL --language LANG --output-dir DIR --output-format txt
|
|
6
|
+
|
|
7
|
+
Arguments are the subset used by the TypeScript media extractor:
|
|
8
|
+
--model faster-whisper model size (e.g. medium, large-v3, turbo)
|
|
9
|
+
--language ISO language code (e.g. ko)
|
|
10
|
+
--output-dir Directory to write output files to
|
|
11
|
+
--output-format Output format (txt supported)
|
|
12
|
+
|
|
13
|
+
The script transcribes INPUT and writes {basename}.txt to --output-dir.
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import argparse
|
|
19
|
+
import os
|
|
20
|
+
import sys
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def parse_args() -> argparse.Namespace:
|
|
24
|
+
parser = argparse.ArgumentParser()
|
|
25
|
+
parser.add_argument("input", help="Audio file path")
|
|
26
|
+
parser.add_argument("--model", default="medium", help="Whisper model size")
|
|
27
|
+
parser.add_argument("--language", default=None, help="Language code (e.g. ko)")
|
|
28
|
+
parser.add_argument("--output-dir", default=".", help="Output directory")
|
|
29
|
+
parser.add_argument("--output-format", default="txt", help="Output format")
|
|
30
|
+
return parser.parse_args()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def main() -> None:
|
|
34
|
+
args = parse_args()
|
|
35
|
+
|
|
36
|
+
if args.output_format != "txt":
|
|
37
|
+
print(f"Unsupported output format: {args.output_format}", file=sys.stderr)
|
|
38
|
+
sys.exit(1)
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
from faster_whisper import WhisperModel
|
|
42
|
+
except ImportError:
|
|
43
|
+
print(
|
|
44
|
+
"faster-whisper not installed. Run: uv pip install faster-whisper",
|
|
45
|
+
file=sys.stderr,
|
|
46
|
+
)
|
|
47
|
+
sys.exit(1)
|
|
48
|
+
|
|
49
|
+
compute_type = "int8" # CPU-friendly
|
|
50
|
+
model_size = args.model
|
|
51
|
+
# Normalize common model aliases to faster-whisper size identifiers.
|
|
52
|
+
if "turbo" in model_size:
|
|
53
|
+
model_size = "turbo"
|
|
54
|
+
elif "large-v3" in model_size:
|
|
55
|
+
model_size = "large-v3"
|
|
56
|
+
elif "large-v2" in model_size:
|
|
57
|
+
model_size = "large-v2"
|
|
58
|
+
elif "medium" in model_size:
|
|
59
|
+
model_size = "medium"
|
|
60
|
+
elif "small" in model_size:
|
|
61
|
+
model_size = "small"
|
|
62
|
+
elif "tiny" in model_size:
|
|
63
|
+
model_size = "tiny"
|
|
64
|
+
|
|
65
|
+
os.makedirs(args.output_dir, exist_ok=True)
|
|
66
|
+
|
|
67
|
+
model = WhisperModel(model_size, device="cpu", compute_type=compute_type)
|
|
68
|
+
|
|
69
|
+
segments, info = model.transcribe(
|
|
70
|
+
args.input,
|
|
71
|
+
language=args.language,
|
|
72
|
+
beam_size=5,
|
|
73
|
+
vad_filter=True,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
base = os.path.splitext(os.path.basename(args.input))[0]
|
|
77
|
+
out_path = os.path.join(args.output_dir, f"{base}.txt")
|
|
78
|
+
|
|
79
|
+
with open(out_path, "w", encoding="utf-8") as f:
|
|
80
|
+
for segment in segments:
|
|
81
|
+
f.write(segment.text.strip() + "\n")
|
|
82
|
+
|
|
83
|
+
print(f"Transcription written to {out_path}", file=sys.stderr)
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
if __name__ == "__main__":
|
|
87
|
+
main()
|
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createHmac, randomBytes, randomUUID, timingSafeEqual } from "node:crypto";
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { dirname, resolve } from "node:path";
|
|
5
|
+
import { pathToFileURL } from "node:url";
|
|
6
|
+
import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
|
|
7
|
+
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
8
|
+
import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js";
|
|
9
|
+
import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
|
|
10
|
+
import {
|
|
11
|
+
CallToolRequestSchema,
|
|
12
|
+
isInitializeRequest,
|
|
13
|
+
ListToolsRequestSchema,
|
|
14
|
+
} from "@modelcontextprotocol/sdk/types.js";
|
|
15
|
+
|
|
16
|
+
function parseCli(argv = process.argv.slice(2)) {
|
|
17
|
+
const options = { host: "127.0.0.1" };
|
|
18
|
+
for (let index = 0; index < argv.length; index += 1) {
|
|
19
|
+
const arg = argv[index];
|
|
20
|
+
const [flag, inlineValue] = arg.includes("=") ? arg.split(/=(.*)/s, 2) : [arg, undefined];
|
|
21
|
+
const nextValue = () => inlineValue ?? argv[++index];
|
|
22
|
+
switch (flag) {
|
|
23
|
+
case "--host":
|
|
24
|
+
options.host = nextValue();
|
|
25
|
+
break;
|
|
26
|
+
case "--port": {
|
|
27
|
+
const value = Number(nextValue());
|
|
28
|
+
if (!Number.isInteger(value) || value <= 0) throw new Error(`Invalid --port: ${value}`);
|
|
29
|
+
options.port = value;
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
case "--user-data-dir":
|
|
33
|
+
options.userDataDir = nextValue();
|
|
34
|
+
break;
|
|
35
|
+
case "--headless":
|
|
36
|
+
options.headless = true;
|
|
37
|
+
break;
|
|
38
|
+
case "--headed":
|
|
39
|
+
options.headless = false;
|
|
40
|
+
break;
|
|
41
|
+
default:
|
|
42
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (!options.port) throw new Error("--port is required");
|
|
46
|
+
return options;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const require = createRequire(import.meta.url);
|
|
50
|
+
const packageRoot = dirname(require.resolve("mcp-patchright/package.json"));
|
|
51
|
+
const [{ BrowserManager }, { handleTool }, { tools }] = await Promise.all([
|
|
52
|
+
import(pathToFileURL(resolve(packageRoot, "dist/browser/manager.js")).href),
|
|
53
|
+
import(pathToFileURL(resolve(packageRoot, "dist/tools/handlers.js")).href),
|
|
54
|
+
import(pathToFileURL(resolve(packageRoot, "dist/tools/registry.js")).href),
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
function createMcpServer(defaultStartOptions, sharedManager, owner) {
|
|
58
|
+
const server = new Server(
|
|
59
|
+
{ name: "mcp-patchright", version: "0.1.0" },
|
|
60
|
+
{ capabilities: { tools: {} } },
|
|
61
|
+
);
|
|
62
|
+
const manager = sharedManager ?? new BrowserManager(defaultStartOptions);
|
|
63
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools }));
|
|
64
|
+
server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
65
|
+
try {
|
|
66
|
+
return await manager.runAsOwner(owner, () =>
|
|
67
|
+
handleTool(manager, request.params.name, request.params.arguments ?? {}),
|
|
68
|
+
);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
return {
|
|
71
|
+
content: [
|
|
72
|
+
{
|
|
73
|
+
type: "text",
|
|
74
|
+
text: error instanceof Error ? `${error.name}: ${error.message}` : String(error),
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
isError: true,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
return server;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function requestOwner(req) {
|
|
85
|
+
const owner = req.header("x-browser-owner");
|
|
86
|
+
if (!owner || owner.length > 256) return undefined;
|
|
87
|
+
return owner;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function sseRequestOwner(req) {
|
|
91
|
+
const owner = requestOwner(req) ?? (typeof req.query.owner === "string" ? req.query.owner : "");
|
|
92
|
+
if (!owner || owner.length > 256) return undefined;
|
|
93
|
+
return owner;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const expectedCapability = process.env.NEGOTIUM_BROWSER_CAPABILITY;
|
|
97
|
+
if (!expectedCapability) throw new Error("NEGOTIUM_BROWSER_CAPABILITY is required");
|
|
98
|
+
|
|
99
|
+
function safeCapabilityEqual(provided, expectedValue) {
|
|
100
|
+
if (!provided) return false;
|
|
101
|
+
const actual = Buffer.from(provided);
|
|
102
|
+
const expected = Buffer.from(expectedValue);
|
|
103
|
+
return actual.length === expected.length && timingSafeEqual(actual, expected);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function hasCapability(req) {
|
|
107
|
+
const provided = req.header("x-browser-capability");
|
|
108
|
+
return safeCapabilityEqual(provided, expectedCapability);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function hasOwnerCapability(req, owner) {
|
|
112
|
+
const expected = createHmac("sha256", expectedCapability).update(owner).digest("hex");
|
|
113
|
+
return safeCapabilityEqual(req.header("x-browser-capability"), expected);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function requireCapability(req, res) {
|
|
117
|
+
if (hasCapability(req)) return true;
|
|
118
|
+
res.status(401).json({ ok: false, error: "invalid browser capability" });
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function requireOwnerCapability(req, res, owner) {
|
|
123
|
+
const queryCapability =
|
|
124
|
+
req.path === "/sse" && typeof req.query.capability === "string"
|
|
125
|
+
? req.query.capability
|
|
126
|
+
: undefined;
|
|
127
|
+
const expected = createHmac("sha256", expectedCapability).update(owner).digest("hex");
|
|
128
|
+
if (hasOwnerCapability(req, owner) || safeCapabilityEqual(queryCapability, expected)) return true;
|
|
129
|
+
res.status(401).json({ ok: false, error: "invalid browser owner capability" });
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Egress proxy is passed via env (not argv) so credentials stay out of `ps`.
|
|
134
|
+
// The parent backend sets NEGOTIUM_BROWSER_PROXY_* from resolveBrowserProxy().
|
|
135
|
+
function proxyFromEnv() {
|
|
136
|
+
const server = process.env.NEGOTIUM_BROWSER_PROXY_SERVER;
|
|
137
|
+
if (!server) return undefined;
|
|
138
|
+
const proxy = { server };
|
|
139
|
+
if (process.env.NEGOTIUM_BROWSER_PROXY_USERNAME)
|
|
140
|
+
proxy.username = process.env.NEGOTIUM_BROWSER_PROXY_USERNAME;
|
|
141
|
+
if (process.env.NEGOTIUM_BROWSER_PROXY_PASSWORD)
|
|
142
|
+
proxy.password = process.env.NEGOTIUM_BROWSER_PROXY_PASSWORD;
|
|
143
|
+
if (process.env.NEGOTIUM_BROWSER_PROXY_BYPASS)
|
|
144
|
+
proxy.bypass = process.env.NEGOTIUM_BROWSER_PROXY_BYPASS;
|
|
145
|
+
return proxy;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const options = parseCli();
|
|
149
|
+
const proxy = proxyFromEnv();
|
|
150
|
+
const defaultStartOptions = {
|
|
151
|
+
...(options.userDataDir ? { userDataDir: options.userDataDir } : {}),
|
|
152
|
+
...(options.headless !== undefined ? { headless: options.headless } : {}),
|
|
153
|
+
...(proxy ? { proxy } : {}),
|
|
154
|
+
};
|
|
155
|
+
const sharedManager = new BrowserManager(defaultStartOptions);
|
|
156
|
+
const app = createMcpExpressApp({ host: options.host });
|
|
157
|
+
|
|
158
|
+
const transports = {};
|
|
159
|
+
const servers = {};
|
|
160
|
+
const sessionOwners = {};
|
|
161
|
+
const sseTransports = {};
|
|
162
|
+
const sseServers = {};
|
|
163
|
+
const sseMessageTokens = {};
|
|
164
|
+
let httpServer;
|
|
165
|
+
|
|
166
|
+
app.get("/health", (_req, res) => {
|
|
167
|
+
res.json({
|
|
168
|
+
ok: true,
|
|
169
|
+
name: "mcp-patchright",
|
|
170
|
+
});
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
// Claude Code and Maestro use the legacy two-endpoint SSE transport. The
|
|
174
|
+
// initial connection is authenticated with the owner capability. A fresh,
|
|
175
|
+
// per-session token embedded in the advertised message endpoint prevents
|
|
176
|
+
// another loopback process from injecting JSON-RPC messages by session ID.
|
|
177
|
+
app.get("/sse", async (req, res) => {
|
|
178
|
+
const owner = sseRequestOwner(req);
|
|
179
|
+
if (!owner) {
|
|
180
|
+
res.status(400).json({ ok: false, error: "browser owner is required in SSE mode" });
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (!requireOwnerCapability(req, res, owner)) return;
|
|
184
|
+
|
|
185
|
+
const messageToken = randomBytes(32).toString("hex");
|
|
186
|
+
const transport = new SSEServerTransport(
|
|
187
|
+
`/message?token=${encodeURIComponent(messageToken)}`,
|
|
188
|
+
res,
|
|
189
|
+
);
|
|
190
|
+
const server = createMcpServer(defaultStartOptions, sharedManager, owner);
|
|
191
|
+
sseTransports[transport.sessionId] = transport;
|
|
192
|
+
sseServers[transport.sessionId] = server;
|
|
193
|
+
sseMessageTokens[transport.sessionId] = messageToken;
|
|
194
|
+
transport.onclose = () => {
|
|
195
|
+
const sessionId = transport.sessionId;
|
|
196
|
+
delete sseTransports[sessionId];
|
|
197
|
+
delete sseMessageTokens[sessionId];
|
|
198
|
+
const managedServer = sseServers[sessionId];
|
|
199
|
+
delete sseServers[sessionId];
|
|
200
|
+
void managedServer?.close().catch(() => undefined);
|
|
201
|
+
};
|
|
202
|
+
await server.connect(transport);
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
app.post("/message", async (req, res) => {
|
|
206
|
+
const sessionId = typeof req.query.sessionId === "string" ? req.query.sessionId : "";
|
|
207
|
+
const messageToken = typeof req.query.token === "string" ? req.query.token : "";
|
|
208
|
+
const transport = sseTransports[sessionId];
|
|
209
|
+
const expectedMessageToken = sseMessageTokens[sessionId];
|
|
210
|
+
if (!transport) {
|
|
211
|
+
res.status(404).send("SSE session not found");
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (!expectedMessageToken || !safeCapabilityEqual(messageToken, expectedMessageToken)) {
|
|
215
|
+
res.status(401).send("invalid SSE message token");
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
await transport.handlePostMessage(req, res, req.body);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
app.all("/mcp", async (req, res) => {
|
|
222
|
+
try {
|
|
223
|
+
const owner = requestOwner(req);
|
|
224
|
+
if (!owner) {
|
|
225
|
+
res.status(400).json({
|
|
226
|
+
jsonrpc: "2.0",
|
|
227
|
+
error: { code: -32600, message: "browser owner is required in HTTP mode" },
|
|
228
|
+
id: null,
|
|
229
|
+
});
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
if (!requireOwnerCapability(req, res, owner)) return;
|
|
233
|
+
const sessionId = req.headers["mcp-session-id"];
|
|
234
|
+
const normalizedSessionId = Array.isArray(sessionId)
|
|
235
|
+
? sessionId[0]
|
|
236
|
+
: typeof sessionId === "string"
|
|
237
|
+
? sessionId
|
|
238
|
+
: undefined;
|
|
239
|
+
let transport;
|
|
240
|
+
if (normalizedSessionId && transports[normalizedSessionId]) {
|
|
241
|
+
const existingTransport = transports[normalizedSessionId];
|
|
242
|
+
if (!(existingTransport instanceof StreamableHTTPServerTransport)) {
|
|
243
|
+
res.status(400).json({
|
|
244
|
+
jsonrpc: "2.0",
|
|
245
|
+
error: { code: -32000, message: "Session uses a different transport protocol" },
|
|
246
|
+
id: null,
|
|
247
|
+
});
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (sessionOwners[normalizedSessionId] !== owner) {
|
|
251
|
+
res.status(403).json({
|
|
252
|
+
jsonrpc: "2.0",
|
|
253
|
+
error: { code: -32001, message: "Browser owner does not match this session" },
|
|
254
|
+
id: null,
|
|
255
|
+
});
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
transport = existingTransport;
|
|
259
|
+
} else if (!normalizedSessionId && req.method === "POST" && isInitializeRequest(req.body)) {
|
|
260
|
+
let server;
|
|
261
|
+
transport = new StreamableHTTPServerTransport({
|
|
262
|
+
sessionIdGenerator: () => randomUUID(),
|
|
263
|
+
onsessioninitialized: (newSessionId) => {
|
|
264
|
+
if (!transport || !server) return;
|
|
265
|
+
transports[newSessionId] = transport;
|
|
266
|
+
servers[newSessionId] = server;
|
|
267
|
+
sessionOwners[newSessionId] = owner;
|
|
268
|
+
},
|
|
269
|
+
});
|
|
270
|
+
server = createMcpServer(defaultStartOptions, sharedManager, owner);
|
|
271
|
+
transport.onclose = () => {
|
|
272
|
+
const sid = transport?.sessionId;
|
|
273
|
+
if (sid) {
|
|
274
|
+
delete transports[sid];
|
|
275
|
+
delete sessionOwners[sid];
|
|
276
|
+
const managedServer = servers[sid];
|
|
277
|
+
delete servers[sid];
|
|
278
|
+
void managedServer?.close().catch(() => undefined);
|
|
279
|
+
}
|
|
280
|
+
};
|
|
281
|
+
await server.connect(transport);
|
|
282
|
+
} else {
|
|
283
|
+
res.status(400).json({
|
|
284
|
+
jsonrpc: "2.0",
|
|
285
|
+
error: { code: -32000, message: "Bad Request: No valid session ID provided" },
|
|
286
|
+
id: null,
|
|
287
|
+
});
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
await transport.handleRequest(req, res, req.body);
|
|
291
|
+
} catch (error) {
|
|
292
|
+
console.error("Error handling /mcp request:", error);
|
|
293
|
+
if (!res.headersSent) {
|
|
294
|
+
res.status(500).json({
|
|
295
|
+
jsonrpc: "2.0",
|
|
296
|
+
error: { code: -32603, message: "Internal server error" },
|
|
297
|
+
id: null,
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
app.delete("/owners", async (req, res) => {
|
|
304
|
+
if (!requireCapability(req, res)) return;
|
|
305
|
+
const owner = requestOwner(req);
|
|
306
|
+
if (!owner) {
|
|
307
|
+
res.status(400).json({ ok: false, error: "owner is required" });
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
const closed = await sharedManager.closeOwnerPages(owner);
|
|
311
|
+
res.json({ ok: true, owner, closed });
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
async function shutdown() {
|
|
315
|
+
for (const [sessionId, transport] of Object.entries(sseTransports)) {
|
|
316
|
+
await transport.close().catch(() => undefined);
|
|
317
|
+
delete sseTransports[sessionId];
|
|
318
|
+
delete sseMessageTokens[sessionId];
|
|
319
|
+
}
|
|
320
|
+
for (const [sessionId, server] of Object.entries(sseServers)) {
|
|
321
|
+
await server.close().catch(() => undefined);
|
|
322
|
+
delete sseServers[sessionId];
|
|
323
|
+
}
|
|
324
|
+
for (const [sessionId, transport] of Object.entries(transports)) {
|
|
325
|
+
await transport.close().catch(() => undefined);
|
|
326
|
+
delete transports[sessionId];
|
|
327
|
+
delete sessionOwners[sessionId];
|
|
328
|
+
}
|
|
329
|
+
for (const [sessionId, server] of Object.entries(servers)) {
|
|
330
|
+
await server.close().catch(() => undefined);
|
|
331
|
+
delete servers[sessionId];
|
|
332
|
+
}
|
|
333
|
+
await sharedManager.close().catch(() => undefined);
|
|
334
|
+
await new Promise((resolveClose) => httpServer?.close(() => resolveClose()));
|
|
335
|
+
process.exit(0);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
httpServer = app.listen(options.port, options.host, () => {
|
|
339
|
+
console.error(`mcp-patchright listening on http://${options.host}:${options.port}`);
|
|
340
|
+
console.error(` SSE: http://${options.host}:${options.port}/sse`);
|
|
341
|
+
console.error(` Streamable: http://${options.host}:${options.port}/mcp`);
|
|
342
|
+
});
|
|
343
|
+
httpServer.on("error", (error) => {
|
|
344
|
+
console.error("mcp-patchright HTTP server error:", error);
|
|
345
|
+
process.exit(1);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
process.on("SIGINT", () => void shutdown());
|
|
349
|
+
process.on("SIGTERM", () => void shutdown());
|