openmausbot 0.1.93 → 0.1.95
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/assets/{DesktopViewer-CKNR3SEW.js → DesktopViewer-BwWpc4RK.js} +1 -1
- package/dist/assets/{abnfDiagram-O67JEVCF-Ckrm1I1X.js → abnfDiagram-O67JEVCF-jsQkIqTn.js} +1 -1
- package/dist/assets/{arc-BBdBuCgB.js → arc-7kei4Hsu.js} +1 -1
- package/dist/assets/{architectureDiagram-NJMV4G6O-CDdA3Hjs.js → architectureDiagram-NJMV4G6O-CRWDFDMq.js} +1 -1
- package/dist/assets/{blockDiagram-BEXU5L5S-AUrsx1YR.js → blockDiagram-BEXU5L5S-CTKW_IKs.js} +1 -1
- package/dist/assets/{c4Diagram-YGBWAQC7-BEqQ0Unh.js → c4Diagram-YGBWAQC7-BBTW7-6M.js} +1 -1
- package/dist/assets/channel-DS2NbT5x.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-CEEuvd4C.js → chunk-2Q5K7J3B-M_Ox-MkD.js} +1 -1
- package/dist/assets/{chunk-3FUC2YCW-DyANCiHl.js → chunk-3FUC2YCW-D2YiN-Ud.js} +2 -2
- package/dist/assets/{chunk-5VM5RSS4-Dx_Slpw9.js → chunk-5VM5RSS4-BmVYJ0f8.js} +1 -1
- package/dist/assets/{chunk-GTNCS2PH-Dl7h7iiD.js → chunk-GTNCS2PH-BtiLVVnZ.js} +1 -1
- package/dist/assets/{chunk-GWA4HPMP-BLx07SPb.js → chunk-GWA4HPMP-DFYSb6J6.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-BMxDj3n7.js → chunk-JWPE2WC7-mknKBzgV.js} +1 -1
- package/dist/assets/{chunk-NETBCI7D-CN66PT4H.js → chunk-NETBCI7D-DgSYGiOu.js} +1 -1
- package/dist/assets/{chunk-WEXAMYUT-6HwhsDKw.js → chunk-WEXAMYUT-C7ZvuguH.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-gWnLt7SN.js → chunk-XXDRQBXY-CPqxINpA.js} +1 -1
- package/dist/assets/{classDiagram-v2-NBCMYWYE-CMS5l2ea.js → classDiagram-v2-NBCMYWYE-Cd6xfJaC.js} +1 -1
- package/dist/assets/{cose-bilkent-JH36ORCC-CV7sQwIG.js → cose-bilkent-JH36ORCC-BSXY5qRh.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-CSyl-7vl.js → cynefin-OW5HDTMX-D_lhEMj1.js} +1 -1
- package/dist/assets/{cynefinDiagram-VND7K2PF-BCLKL6az.js → cynefinDiagram-VND7K2PF-Da9FrFwk.js} +1 -1
- package/dist/assets/{dagre-6A5THRUB-DiaZs6S1.js → dagre-6A5THRUB-T77jMOXe.js} +1 -1
- package/dist/assets/{diagram-22UHCM2B-BeTtmt3I.js → diagram-22UHCM2B-Dkj96X5E.js} +1 -1
- package/dist/assets/{diagram-3UASUU5V-CsdBG-QQ.js → diagram-3UASUU5V-CMi9zlD_.js} +1 -1
- package/dist/assets/{diagram-ATOU4E4O-BczvdbR1.js → diagram-ATOU4E4O-CXK6YUfS.js} +1 -1
- package/dist/assets/{diagram-CDSNMT55-DHTTTMhi.js → diagram-CDSNMT55-BE7B1u9Q.js} +1 -1
- package/dist/assets/{diagram-MLGK6HIB-RTjHyd8z.js → diagram-MLGK6HIB-CCMQphKr.js} +1 -1
- package/dist/assets/{diagram-MPIPVDR6-BDenHEH_.js → diagram-MPIPVDR6-iHJ_-tGH.js} +1 -1
- package/dist/assets/{ebnfDiagram-ZINNZB2B-BSiRSbtL.js → ebnfDiagram-ZINNZB2B-DONsCWQ7.js} +1 -1
- package/dist/assets/{elk-276RUBZZ-BCAElss-.js → elk-276RUBZZ-CU_WOaXk.js} +1 -1
- package/dist/assets/{erDiagram-OPXOYQCR-C4_1ZPJe.js → erDiagram-OPXOYQCR-BeYwM04G.js} +1 -1
- package/dist/assets/{flowDiagram-KWPJA3E3-Bcb4Z75S.js → flowDiagram-KWPJA3E3-Bdw9DqEl.js} +1 -1
- package/dist/assets/{ganttDiagram-FUAMR5RP-BiPOzxzb.js → ganttDiagram-FUAMR5RP-C9iwq3qm.js} +1 -1
- package/dist/assets/{gitGraphDiagram-X574FWY7-B1wtF3ZS.js → gitGraphDiagram-X574FWY7-Dx-VWzUg.js} +1 -1
- package/dist/assets/{index-BkYwilkG.js → index-KygHRE3E.js} +1 -1
- package/dist/assets/index-NF7XCHAy.css +1 -0
- package/dist/assets/index-X_5ydXIE.js +610 -0
- package/dist/assets/{infoDiagram-VRGFBTTK-A19No71U.js → infoDiagram-VRGFBTTK-BG7uaEd4.js} +1 -1
- package/dist/assets/{ishikawaDiagram-OU5B5YK6-BQsqJ_cV.js → ishikawaDiagram-OU5B5YK6-D72WAXnM.js} +1 -1
- package/dist/assets/{journeyDiagram-ZHPQQLJL-DAO0pVan.js → journeyDiagram-ZHPQQLJL-DKH1gjYT.js} +1 -1
- package/dist/assets/{kanban-definition-PNTS6WVX-NepmKEe2.js → kanban-definition-PNTS6WVX-3upm9JUT.js} +1 -1
- package/dist/assets/{linear-bq1PTDTW.js → linear-CcR4pc0-.js} +1 -1
- package/dist/assets/{mermaid.core-s4LTbQle.js → mermaid.core-C6yU5FSS.js} +5 -5
- package/dist/assets/{mindmap-definition-NLK3R4M7-LtdbgHFH.js → mindmap-definition-NLK3R4M7-DOI2xEuv.js} +1 -1
- package/dist/assets/{pegDiagram-GJSIUBJH-tdbaCxiK.js → pegDiagram-GJSIUBJH-BVWJSgLd.js} +1 -1
- package/dist/assets/{pieDiagram-5QR66LMP-DvkbpW8l.js → pieDiagram-5QR66LMP-jtbYezhq.js} +1 -1
- package/dist/assets/{quadrantDiagram-O4NWA36T-Do4KaH-E.js → quadrantDiagram-O4NWA36T-g0u8mtPX.js} +1 -1
- package/dist/assets/{railroadDiagram-XR7U4H2S-BQWULOAs.js → railroadDiagram-XR7U4H2S-k8689Wny.js} +1 -1
- package/dist/assets/{requirementDiagram-PLB6GJNP-w9kei1FU.js → requirementDiagram-PLB6GJNP-DsJ22PDt.js} +1 -1
- package/dist/assets/{sankeyDiagram-IPEJSGJF-D2gRy0e8.js → sankeyDiagram-IPEJSGJF-CneWBRgG.js} +1 -1
- package/dist/assets/{sequenceDiagram-PO4LG4MO-a2sO5_Eo.js → sequenceDiagram-PO4LG4MO-DWsFCWap.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-CiPJmFEB.js → sizeCapture-INFHLROL-Bvf0YE3S.js} +1 -1
- package/dist/assets/{stateDiagram-v2-GCMORJYK-DAkUUlL7.js → stateDiagram-v2-GCMORJYK-Bxb3Iei8.js} +1 -1
- package/dist/assets/{swimlanes-2SLR337P-DANf2R8Y.js → swimlanes-2SLR337P-DLkk7W4A.js} +1 -1
- package/dist/assets/swimlanesDiagram-TC7HE7FX-C6bZtBXk.js +8 -0
- package/dist/assets/{timeline-definition-EJHVYXUP-BKpQmzrT.js → timeline-definition-EJHVYXUP-KR9bIHYC.js} +1 -1
- package/dist/assets/{usecaseDiagram-POWQR4AR-BtI7qLN-.js → usecaseDiagram-POWQR4AR-DfsOrj8t.js} +1 -1
- package/dist/assets/{vennDiagram-UO4OBE2U-gXJXrAG_.js → vennDiagram-UO4OBE2U-DRSTzG3h.js} +1 -1
- package/dist/assets/{wardleyDiagram-VNRHLVJA-GU8Po5-n.js → wardleyDiagram-VNRHLVJA-DtEdhPgT.js} +1 -1
- package/dist/assets/{xychartDiagram-PMCCYNJV-BF4J30g6.js → xychartDiagram-PMCCYNJV-B-XhTxjG.js} +1 -1
- package/dist/index.html +2 -2
- package/dist-server/cloud-home-start.js +3 -1
- package/dist-server/companion/src/routes.js +60 -0
- package/dist-server/container-mcp.js +94 -77
- package/dist-server/drivers/agents-proxy.js +96 -39
- package/dist-server/drivers/pi-mcp-extension.ts +245 -299
- package/dist-server/enterprise/server/index.js +3 -1
- package/dist-server/{browser-proxy.js → harness-mcp-proxy.js} +35 -19
- package/dist-server/index.js +18242 -13645
- package/dist-server/local-computer.js +3 -1
- package/dist-server/mcp-gate.js +147 -19
- package/dist-server/mcp-remote-proxy.js +437 -0
- package/dist-server/openmausbot.js +9618 -10058
- package/dist-server/pair-cli.js +9618 -10058
- package/dist-server/permission-proxy.js +65 -1
- package/dist-server/proxy-paths.js +3 -1
- package/dist-server/server/account-signin.js +0 -2
- package/dist-server/server/activity.js +201 -0
- package/dist-server/server/auto-approve.js +39 -11
- package/dist-server/server/automatic-recovery.js +1 -1
- package/dist-server/server/boat-create-idempotency.js +0 -7
- package/dist-server/server/boat-delete-journal.js +0 -4
- package/dist-server/server/bot-package.js +1 -19
- package/dist-server/server/browser-live.js +14 -5
- package/dist-server/server/browser-runtime.js +7 -2
- package/dist-server/server/channel-queue.js +4 -1
- package/dist-server/server/chief-of-staff.js +2 -3
- package/dist-server/server/cli.js +32 -12
- package/dist-server/server/cloud-backend.js +0 -4
- package/dist-server/server/cloud-computer-tools.js +110 -0
- package/dist-server/server/cloud-home.js +0 -1
- package/dist-server/server/cloud-lending.js +0 -3
- package/dist-server/server/cloud-move-http.js +9 -3
- package/dist-server/server/cloud-move.js +18 -0
- package/dist-server/server/composio.js +31 -2
- package/dist-server/server/computer-control.js +0 -15
- package/dist-server/server/computer-observation.js +0 -74
- package/dist-server/server/computer-wait.js +33 -13
- package/dist-server/server/config.js +73 -11
- package/dist-server/server/container-computer.js +7 -19
- package/dist-server/server/contracts.js +9 -0
- package/dist-server/server/control-client.js +4 -10
- package/dist-server/server/decision-log.js +9 -6
- package/dist-server/server/delegations.js +47 -22
- package/dist-server/server/drivers/acp/core.js +64 -13
- package/dist-server/server/drivers/acp/grok.js +208 -3
- package/dist-server/server/drivers/agents-call.js +70 -29
- package/dist-server/server/drivers/agents-catalog.js +34 -12
- package/dist-server/server/drivers/agents-proxy.js +8 -30
- package/dist-server/server/drivers/antigravity.js +1 -4
- package/dist-server/server/drivers/boatagent.js +25 -4
- package/dist-server/server/drivers/cerebras.js +3 -3
- package/dist-server/server/drivers/chat-mcp-tools.js +29 -19
- package/dist-server/server/drivers/claude.js +33 -19
- package/dist-server/server/drivers/codex.js +84 -10
- package/dist-server/server/drivers/openai-chat.js +14 -9
- package/dist-server/server/drivers/pi.js +48 -4
- package/dist-server/server/drivers/retry.js +8 -4
- package/dist-server/server/engine-install.js +1 -5
- package/dist-server/server/environment.js +3 -0
- package/dist-server/server/guarded-requests.js +2 -1
- package/dist-server/server/harness/registry.js +0 -1
- package/dist-server/server/{browser-proxy.js → harness-mcp-proxy.js} +40 -20
- package/dist-server/server/index.js +1929 -507
- package/dist-server/server/lending-memory.js +12 -8
- package/dist-server/server/live-call-controller.js +868 -0
- package/dist-server/server/live-call.js +216 -0
- package/dist-server/server/mcp-gate-config.js +43 -12
- package/dist-server/server/mcp-gate.js +127 -25
- package/dist-server/server/mcp-http.js +46 -8
- package/dist-server/server/mcp-remote-proxy.js +108 -0
- package/dist-server/server/memory-entries.js +38 -8
- package/dist-server/server/memory-organize.js +1 -8
- package/dist-server/server/memory-topics.js +4 -4
- package/dist-server/server/memory-upkeep.js +13 -15
- package/dist-server/server/message-file.js +5 -9
- package/dist-server/server/new-bot-defaults.js +3 -0
- package/dist-server/server/outbound-counts.js +79 -0
- package/dist-server/server/outbound-requests.js +60 -0
- package/dist-server/server/package-import.js +1 -1
- package/dist-server/server/peer-delivery.js +1 -0
- package/dist-server/server/peer-provenance.js +4 -2
- package/dist-server/server/permission-proxy.js +15 -1
- package/dist-server/server/plan-usage.js +797 -0
- package/dist-server/server/proxy-paths.js +3 -1
- package/dist-server/server/redact.js +2 -0
- package/dist-server/server/request-auth.js +3 -2
- package/dist-server/server/room-handoffs.js +5 -13
- package/dist-server/server/routes/live.js +98 -0
- package/dist-server/server/routine-requests.js +1 -1
- package/dist-server/server/routines.js +5 -1
- package/dist-server/server/setup-mode.js +0 -2
- package/dist-server/server/skill-learn.js +0 -1
- package/dist-server/server/skill-library.js +195 -3
- package/dist-server/server/skills-library-migration.js +235 -0
- package/dist-server/server/skills.js +66 -3
- package/dist-server/server/steer-queue.js +13 -1
- package/dist-server/server/store.js +41 -5
- package/dist-server/server/surface.js +74 -23
- package/dist-server/server/system-prompt.js +4 -4
- package/dist-server/server/team-backup.js +2 -1
- package/dist-server/server/team-memory.js +209 -0
- package/dist-server/server/thread-events.js +3 -3
- package/dist-server/server/tunnel.js +20 -1
- package/dist-server/server/turn-log.js +10 -0
- package/dist-server/server/turn-resources.js +124 -0
- package/dist-server/server/vps-computer.js +4 -14
- package/dist-server/server/workspace.js +85 -47
- package/dist-server/shared/activity.js +3 -0
- package/dist-server/shared/ask-question.js +13 -0
- package/dist-server/shared/bot-avatar.js +8 -0
- package/dist-server/shared/call-consent.js +28 -0
- package/dist-server/shared/connector-scopes.js +78 -0
- package/dist-server/shared/live-approval.js +124 -0
- package/dist-server/shared/live-call.js +176 -0
- package/dist-server/shared/outbound.js +128 -0
- package/dist-server/shared/skill-md.js +10 -0
- package/dist-server/shared/team-backup.js +3 -0
- package/dist-server/shared/tool-scope-support.js +25 -0
- package/dist-server/shared/tool-scope.js +136 -0
- package/dist-server/shared/tool-surface.js +3 -2
- package/dist-server/src/lib/thread-refs.js +406 -0
- package/dist-server/vps-container-mcp.js +94 -77
- package/dist-server/workspace-backup.worker.js +89 -100
- package/enterprise/server/index.js +3 -1
- package/package.json +1 -1
- package/dist/assets/channel-BU94VpxE.js +0 -1
- package/dist/assets/index-Biji-bfL.css +0 -1
- package/dist/assets/index-DZlhoES0.js +0 -597
- package/dist/assets/swimlanesDiagram-TC7HE7FX-CdHxG8aM.js +0 -8
- package/dist-server/server/drivers/chat-boat-tools.js +0 -90
- package/dist-server/server/drivers/grokagent.js +0 -4
- package/dist-server/server/openmaus-status-capsule.js +0 -329
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
// "#QA PR 245" in prose becomes a link to that thread. Bots are asked to
|
|
2
|
+
// write a thread's title as #Title when they mention one, and the person
|
|
3
|
+
// may type the same. Resolution mirrors @mention resolution for bots:
|
|
4
|
+
// word-start, longest known title first, case-insensitive — titles hold
|
|
5
|
+
// spaces, so the longest known title following the "#" wins. Nothing else
|
|
6
|
+
// is a link: "#123" issue numbers, "# Heading" markers (the parser never
|
|
7
|
+
// hands those here) and unknown titles all stay plain text.
|
|
8
|
+
const WORD_CHAR = /[\p{L}\p{N}_]/u;
|
|
9
|
+
/** a "#" glued to one of these is not a word start: C#Title, ', ##x */
|
|
10
|
+
const NOT_WORD_START = /[\p{L}\p{N}_#&]/u;
|
|
11
|
+
/** Spacing a pasted thread token needs on each side: a lead space after
|
|
12
|
+
* any char the resolver refuses as a word start — word chars, but also #
|
|
13
|
+
* and &, so a paste after them cannot glue into ##Title — and a trail
|
|
14
|
+
* space before a plain word char. */
|
|
15
|
+
export function threadTokenSpacing(text, start, end) {
|
|
16
|
+
return {
|
|
17
|
+
lead: start > 0 && NOT_WORD_START.test(text[start - 1] ?? "") ? " " : "",
|
|
18
|
+
trail: end < text.length && WORD_CHAR.test(text[end] ?? "") ? " " : "",
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
/** Only a title that is a real name can be linked: "123" would turn every
|
|
22
|
+
* issue number into a thread link. */
|
|
23
|
+
function linkable(title) {
|
|
24
|
+
return title.length > 0 && !/^\d+$/.test(title);
|
|
25
|
+
}
|
|
26
|
+
/** Known titles, longest first, each with every thread that carries it in
|
|
27
|
+
* the caller's (recency) order. */
|
|
28
|
+
function groupTitles(threads) {
|
|
29
|
+
const groups = new Map();
|
|
30
|
+
const seen = new Set();
|
|
31
|
+
for (const thread of threads) {
|
|
32
|
+
const title = thread.title.trim();
|
|
33
|
+
const key = `${thread.botId}/${thread.threadId}`;
|
|
34
|
+
if (!linkable(title) || seen.has(key))
|
|
35
|
+
continue;
|
|
36
|
+
seen.add(key);
|
|
37
|
+
const lower = title.toLowerCase();
|
|
38
|
+
const group = groups.get(lower);
|
|
39
|
+
if (group)
|
|
40
|
+
group.candidates.push({ ...thread, title });
|
|
41
|
+
else
|
|
42
|
+
groups.set(lower, { lower, candidates: [{ ...thread, title }] });
|
|
43
|
+
}
|
|
44
|
+
return [...groups.values()].sort((a, b) => b.lower.length - a.lower.length);
|
|
45
|
+
}
|
|
46
|
+
/** Which of several same-titled threads a mention means: the current
|
|
47
|
+
* bot's, else the most recently active, else the first — flagged so the
|
|
48
|
+
* link can say which bot it landed on. */
|
|
49
|
+
function pick(candidates, currentBotId) {
|
|
50
|
+
const resolved = (thread, ambiguous) => ({
|
|
51
|
+
botId: thread.botId, botName: thread.botName, threadId: thread.threadId, title: thread.title, ambiguous,
|
|
52
|
+
});
|
|
53
|
+
if (candidates.length === 1)
|
|
54
|
+
return resolved(candidates[0], false);
|
|
55
|
+
const own = candidates.filter((thread) => thread.botId === currentBotId);
|
|
56
|
+
if (own.length === 1)
|
|
57
|
+
return resolved(own[0], false);
|
|
58
|
+
const pool = own.length > 1 ? own : candidates;
|
|
59
|
+
const stamps = pool.map((thread) => thread.activeAt);
|
|
60
|
+
if (stamps.every((stamp) => typeof stamp === "number")) {
|
|
61
|
+
const newest = Math.max(...stamps);
|
|
62
|
+
const latest = pool.filter((thread) => thread.activeAt === newest);
|
|
63
|
+
if (latest.length === 1)
|
|
64
|
+
return resolved(latest[0], false);
|
|
65
|
+
}
|
|
66
|
+
return resolved(pool[0], true);
|
|
67
|
+
}
|
|
68
|
+
/** Split `text` into plain runs and linked "#Title" runs. The linked run
|
|
69
|
+
* keeps the person's own spelling ("#qa pr 245" stays as typed). */
|
|
70
|
+
export function resolveThreadRefs(text, threads, currentBotId) {
|
|
71
|
+
const groups = groupTitles(threads);
|
|
72
|
+
if (!groups.length || !text.includes("#"))
|
|
73
|
+
return [{ text }];
|
|
74
|
+
const spans = [];
|
|
75
|
+
let last = 0;
|
|
76
|
+
let at = text.indexOf("#");
|
|
77
|
+
while (at !== -1) {
|
|
78
|
+
const before = at > 0 ? text[at - 1] : "";
|
|
79
|
+
const start = at + 1;
|
|
80
|
+
let matched = null;
|
|
81
|
+
if (!before || !NOT_WORD_START.test(before)) {
|
|
82
|
+
for (const group of groups) {
|
|
83
|
+
const end = start + group.lower.length;
|
|
84
|
+
if (text.slice(start, end).toLowerCase() !== group.lower)
|
|
85
|
+
continue;
|
|
86
|
+
const after = text[end] ?? "";
|
|
87
|
+
if (after && WORD_CHAR.test(after))
|
|
88
|
+
continue;
|
|
89
|
+
matched = { end, ref: pick(group.candidates, currentBotId) };
|
|
90
|
+
break;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (matched) {
|
|
94
|
+
if (at > last)
|
|
95
|
+
spans.push({ text: text.slice(last, at) });
|
|
96
|
+
spans.push({ text: text.slice(at, matched.end), ref: matched.ref });
|
|
97
|
+
last = matched.end;
|
|
98
|
+
at = text.indexOf("#", matched.end);
|
|
99
|
+
}
|
|
100
|
+
else {
|
|
101
|
+
at = text.indexOf("#", at + 1);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (last < text.length)
|
|
105
|
+
spans.push({ text: text.slice(last) });
|
|
106
|
+
return spans.length ? spans : [{ text }];
|
|
107
|
+
}
|
|
108
|
+
const THREAD_URL_PREFIX = "openmausbot://thread/";
|
|
109
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
110
|
+
const ID_LIMIT = 256;
|
|
111
|
+
const plainId = (value) => {
|
|
112
|
+
// oxlint-disable-next-line no-control-regex -- a thread id never carries control characters
|
|
113
|
+
if (!value || value.length > ID_LIMIT || /[\u0000-\u001f]/.test(value))
|
|
114
|
+
return null;
|
|
115
|
+
return value;
|
|
116
|
+
};
|
|
117
|
+
/** The canonical link for a thread a person can copy. */
|
|
118
|
+
export function threadRefUrl(ref) {
|
|
119
|
+
return THREAD_URL_PREFIX + encodeURIComponent(ref.threadId) + "?bot=" + encodeURIComponent(ref.botId);
|
|
120
|
+
}
|
|
121
|
+
/** Parse a canonical thread link; null for anything else, including
|
|
122
|
+
* near-misses with extra path, extra query or a foreign scheme. */
|
|
123
|
+
export function parseThreadRefUrl(value) {
|
|
124
|
+
const raw = value.trim();
|
|
125
|
+
if (!raw.toLowerCase().startsWith(THREAD_URL_PREFIX))
|
|
126
|
+
return null;
|
|
127
|
+
let url;
|
|
128
|
+
try {
|
|
129
|
+
url = new URL(raw);
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
if (url.username || url.password || url.port || url.hash)
|
|
135
|
+
return null;
|
|
136
|
+
if (url.hostname.toLowerCase() !== "thread")
|
|
137
|
+
return null;
|
|
138
|
+
let threadId;
|
|
139
|
+
try {
|
|
140
|
+
threadId = decodeURIComponent(url.pathname.slice(1));
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
if (!threadId || threadId.includes("/") || url.pathname.slice(1) !== encodeURIComponent(threadId))
|
|
146
|
+
return null;
|
|
147
|
+
const keys = [...url.searchParams.keys()];
|
|
148
|
+
if (keys.some((key) => key !== "bot"))
|
|
149
|
+
return null;
|
|
150
|
+
const bot = url.searchParams.get("bot");
|
|
151
|
+
if (keys.length > 1 || (bot !== null && !bot))
|
|
152
|
+
return null;
|
|
153
|
+
const thread = plainId(threadId);
|
|
154
|
+
const owner = bot === null ? undefined : plainId(bot);
|
|
155
|
+
if (!thread || owner === null)
|
|
156
|
+
return null;
|
|
157
|
+
return owner ? { threadId: thread, botId: owner } : { threadId: thread };
|
|
158
|
+
}
|
|
159
|
+
/** Whether a value is shaped like a thread link at all — even one that
|
|
160
|
+
* fails strict parsing. Markdown must never hand such a URL to the shell
|
|
161
|
+
* as an external link, live or dead. */
|
|
162
|
+
export function looksLikeThreadRefUrl(value) {
|
|
163
|
+
return value.trim().toLowerCase().startsWith(THREAD_URL_PREFIX);
|
|
164
|
+
}
|
|
165
|
+
/** A raw thread id on its own: the UUID form the server mints. */
|
|
166
|
+
export function isThreadUuid(value) {
|
|
167
|
+
return UUID.test(value.trim());
|
|
168
|
+
}
|
|
169
|
+
/** Resolve an address (or bare UUID) against the visible threads. The
|
|
170
|
+
* link's own bot wins when it names one; otherwise the same preference a
|
|
171
|
+
* #Title mention uses: the open bot's thread, then the newest, then a
|
|
172
|
+
* deterministic first — flagged ambiguous so the chip can name the bot. */
|
|
173
|
+
export function resolveThreadRefAddress(threads, address, currentBotId) {
|
|
174
|
+
const candidates = threads.filter((thread) => thread.threadId === address.threadId);
|
|
175
|
+
if (!candidates.length)
|
|
176
|
+
return null;
|
|
177
|
+
const pinned = address.botId ? candidates.filter((thread) => thread.botId === address.botId) : [];
|
|
178
|
+
if (pinned.length === 1)
|
|
179
|
+
return { ...pinned[0], title: pinned[0].title.trim(), ambiguous: false };
|
|
180
|
+
if (pinned.length > 1)
|
|
181
|
+
return pick(pinned, currentBotId);
|
|
182
|
+
// a pinned owner missing from the visible threads is a dead reference:
|
|
183
|
+
// never fall through to another bot's same-id thread
|
|
184
|
+
if (address.botId)
|
|
185
|
+
return null;
|
|
186
|
+
return pick(candidates, currentBotId);
|
|
187
|
+
}
|
|
188
|
+
// ── sent-message serialization ─────────────────────────────────────────
|
|
189
|
+
// A resolvable #Title becomes a markdown link whose URL carries the thread
|
|
190
|
+
// id, so bots and API consumers keep the machine-readable reference. The
|
|
191
|
+
// label keeps the title readable; escapes keep brackets in titles parseable.
|
|
192
|
+
const escapeThreadLabel = (title) => title.replace(/[[\]\\]/g, "\\$&");
|
|
193
|
+
const unescapeThreadLabel = (label) => label.replace(/\\(.)/g, "$1");
|
|
194
|
+
/** The markdown shape a thread reference is sent as. */
|
|
195
|
+
export function threadRefMarkdown(ref) {
|
|
196
|
+
return "[" + escapeThreadLabel(ref.title) + "](" + threadRefUrl(ref) + ")";
|
|
197
|
+
}
|
|
198
|
+
const MARKDOWN_LINK_LABEL = /\[((?:\\.|[^\\\]])*)\]\(/y;
|
|
199
|
+
const INLINE_LINK_SPACE = " \t\n\r";
|
|
200
|
+
/** The CommonMark inline-link tail after "[label](": optional whitespace,
|
|
201
|
+
* an angle-bracket destination (spaces allowed) or a bare destination with
|
|
202
|
+
* balanced parentheses, optional whitespace, an optional quoted title, and
|
|
203
|
+
* the closing ")". Returns the tail length plus the bare destination for
|
|
204
|
+
* resolution, or null when no complete link closes here. */
|
|
205
|
+
function inlineLinkTail(rest, from) {
|
|
206
|
+
let at = from;
|
|
207
|
+
while (at < rest.length && INLINE_LINK_SPACE.includes(rest.charAt(at)))
|
|
208
|
+
at += 1;
|
|
209
|
+
const destStart = at;
|
|
210
|
+
let destination = "";
|
|
211
|
+
if (rest.charAt(at) === "<") {
|
|
212
|
+
const close = rest.indexOf(">", at + 1);
|
|
213
|
+
if (close === -1)
|
|
214
|
+
return null;
|
|
215
|
+
destination = rest.slice(at + 1, close);
|
|
216
|
+
at = close + 1;
|
|
217
|
+
}
|
|
218
|
+
else {
|
|
219
|
+
let depth = 0;
|
|
220
|
+
while (at < rest.length) {
|
|
221
|
+
const ch = rest.charAt(at);
|
|
222
|
+
if (ch === "(")
|
|
223
|
+
depth += 1;
|
|
224
|
+
else if (ch === ")") {
|
|
225
|
+
if (depth === 0)
|
|
226
|
+
break;
|
|
227
|
+
depth -= 1;
|
|
228
|
+
}
|
|
229
|
+
else if (INLINE_LINK_SPACE.includes(ch))
|
|
230
|
+
break;
|
|
231
|
+
at += 1;
|
|
232
|
+
}
|
|
233
|
+
if (depth !== 0)
|
|
234
|
+
return null;
|
|
235
|
+
destination = rest.slice(destStart, at);
|
|
236
|
+
}
|
|
237
|
+
while (at < rest.length && INLINE_LINK_SPACE.includes(rest.charAt(at)))
|
|
238
|
+
at += 1;
|
|
239
|
+
const titleQuote = rest.charAt(at);
|
|
240
|
+
if (titleQuote === '"' || titleQuote === "'") {
|
|
241
|
+
const close = rest.indexOf(titleQuote, at + 1);
|
|
242
|
+
if (close === -1)
|
|
243
|
+
return null;
|
|
244
|
+
at = close + 1;
|
|
245
|
+
}
|
|
246
|
+
else if (titleQuote === "(") {
|
|
247
|
+
let depth = 1;
|
|
248
|
+
at += 1;
|
|
249
|
+
while (at < rest.length && depth > 0) {
|
|
250
|
+
const ch = rest.charAt(at);
|
|
251
|
+
if (ch === "(")
|
|
252
|
+
depth += 1;
|
|
253
|
+
else if (ch === ")")
|
|
254
|
+
depth -= 1;
|
|
255
|
+
at += 1;
|
|
256
|
+
}
|
|
257
|
+
if (depth !== 0)
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
while (at < rest.length && INLINE_LINK_SPACE.includes(rest.charAt(at)))
|
|
261
|
+
at += 1;
|
|
262
|
+
if (rest.charAt(at) !== ")")
|
|
263
|
+
return null;
|
|
264
|
+
return { tail: at + 1 - from, destination };
|
|
265
|
+
}
|
|
266
|
+
/** Split text into plain runs and the spans resolution must never touch.
|
|
267
|
+
* Every markdown link is kept verbatim — a #Title inside a label would
|
|
268
|
+
* nest links — and so is code: inline backticks and fenced blocks quote
|
|
269
|
+
* their contents, so only plain runs carry #Title mentions. */
|
|
270
|
+
function splitThreadLinkMarkdown(text) {
|
|
271
|
+
if (!text.includes("](") && !text.includes("`"))
|
|
272
|
+
return [{ raw: text }];
|
|
273
|
+
const spans = [];
|
|
274
|
+
let plain = "";
|
|
275
|
+
const flush = () => {
|
|
276
|
+
if (plain)
|
|
277
|
+
spans.push({ raw: plain });
|
|
278
|
+
plain = "";
|
|
279
|
+
};
|
|
280
|
+
let at = 0;
|
|
281
|
+
while (at < text.length) {
|
|
282
|
+
const rest = text.slice(at);
|
|
283
|
+
const guarded = (end) => {
|
|
284
|
+
flush();
|
|
285
|
+
spans.push({ raw: text.slice(at, end), code: true });
|
|
286
|
+
at = end;
|
|
287
|
+
};
|
|
288
|
+
if (rest.startsWith("```")) {
|
|
289
|
+
const close = rest.indexOf("```", 3);
|
|
290
|
+
guarded(close === -1 ? text.length : at + close + 3);
|
|
291
|
+
continue;
|
|
292
|
+
}
|
|
293
|
+
const ticks = /^`+/.exec(rest)?.[0];
|
|
294
|
+
if (ticks) {
|
|
295
|
+
const close = rest.indexOf(ticks, ticks.length);
|
|
296
|
+
guarded(close === -1 ? text.length : at + close + ticks.length);
|
|
297
|
+
continue;
|
|
298
|
+
}
|
|
299
|
+
MARKDOWN_LINK_LABEL.lastIndex = 0;
|
|
300
|
+
const open = MARKDOWN_LINK_LABEL.exec(rest);
|
|
301
|
+
const tail = open && inlineLinkTail(rest, open[0].length);
|
|
302
|
+
if (open && tail) {
|
|
303
|
+
flush();
|
|
304
|
+
const raw = rest.slice(0, open[0].length + tail.tail);
|
|
305
|
+
spans.push({ raw, link: { label: open[1], address: parseThreadRefUrl(tail.destination) } });
|
|
306
|
+
at += raw.length;
|
|
307
|
+
continue;
|
|
308
|
+
}
|
|
309
|
+
plain += text[at];
|
|
310
|
+
at += 1;
|
|
311
|
+
}
|
|
312
|
+
flush();
|
|
313
|
+
return spans.length ? spans : [{ raw: text }];
|
|
314
|
+
}
|
|
315
|
+
/** The text a send carries: resolvable #Title runs become canonical links;
|
|
316
|
+
* existing links and unknown titles pass through untouched. */
|
|
317
|
+
export function serializeThreadRefs(text, threads, currentBotId) {
|
|
318
|
+
if (!groupTitles(threads).length)
|
|
319
|
+
return text;
|
|
320
|
+
return splitThreadLinkMarkdown(text)
|
|
321
|
+
.map((span) => (span.link || span.code) ? span.raw : resolveThreadRefs(span.raw, threads, currentBotId)
|
|
322
|
+
.map((run) => run.ref ? threadRefMarkdown(run.ref) : run.text)
|
|
323
|
+
.join(""))
|
|
324
|
+
.join("");
|
|
325
|
+
}
|
|
326
|
+
export function splitThreadRefsForDisplay(text, threads, currentBotId) {
|
|
327
|
+
const spans = [];
|
|
328
|
+
for (const span of splitThreadLinkMarkdown(text)) {
|
|
329
|
+
if (span.link) {
|
|
330
|
+
const ref = span.link.address ? resolveThreadRefAddress(threads, span.link.address, currentBotId) : null;
|
|
331
|
+
spans.push(ref ? { text: unescapeThreadLabel(span.link.label), ref } : { text: span.raw });
|
|
332
|
+
}
|
|
333
|
+
else if (span.code) {
|
|
334
|
+
spans.push({ text: span.raw });
|
|
335
|
+
}
|
|
336
|
+
else {
|
|
337
|
+
spans.push(...resolveThreadRefs(span.raw, threads, currentBotId));
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return spans.length ? spans : [{ text }];
|
|
341
|
+
}
|
|
342
|
+
/** The whole paste is one thread reference — a canonical link, the markdown
|
|
343
|
+
* link shape messages carry, or a raw UUID — and it resolves to a visible
|
|
344
|
+
* thread: the #Title token the composer holds, plus what it resolved to.
|
|
345
|
+
* null when the paste is not a reference or names no known thread, so an
|
|
346
|
+
* unknown id stays plain text. */
|
|
347
|
+
export function threadTokenFromPaste(pasted, threads, currentBotId) {
|
|
348
|
+
const trimmed = pasted.trim();
|
|
349
|
+
if (!trimmed)
|
|
350
|
+
return null;
|
|
351
|
+
const wrapped = /^\[((?:\\.|[^\\\]])*)\]\((openmausbot:\/\/thread\/[^()\s]*)\)$/.exec(trimmed);
|
|
352
|
+
const address = wrapped
|
|
353
|
+
? parseThreadRefUrl(wrapped[2])
|
|
354
|
+
: parseThreadRefUrl(trimmed) ?? (isThreadUuid(trimmed) ? { threadId: trimmed } : null);
|
|
355
|
+
if (!address)
|
|
356
|
+
return null;
|
|
357
|
+
const ref = resolveThreadRefAddress(threads, address, currentBotId);
|
|
358
|
+
if (!ref)
|
|
359
|
+
return null;
|
|
360
|
+
// '#Title' is the token of choice, but a numeric or '#' prefixed title
|
|
361
|
+
// can never re-resolve through that spelling — those pastes hold the
|
|
362
|
+
// canonical markdown link instead, which sends and displays the same.
|
|
363
|
+
const title = ref.title.trim();
|
|
364
|
+
const token = linkable(title) && !title.startsWith("#") ? `#${title}` : threadRefMarkdown(ref);
|
|
365
|
+
return { token, ref };
|
|
366
|
+
}
|
|
367
|
+
const OPAQUE = new Set(["link", "linkReference", "image", "imageReference", "definition", "html", "mention"]);
|
|
368
|
+
export const THREAD_REF_NODE = "threadRef";
|
|
369
|
+
function linkNode(text, ref) {
|
|
370
|
+
return {
|
|
371
|
+
type: THREAD_REF_NODE,
|
|
372
|
+
data: {
|
|
373
|
+
hName: "span",
|
|
374
|
+
hProperties: {
|
|
375
|
+
"data-thread-bot": ref.botId,
|
|
376
|
+
"data-thread-bot-name": ref.botName,
|
|
377
|
+
"data-thread-id": ref.threadId,
|
|
378
|
+
"data-thread-title": ref.title,
|
|
379
|
+
"data-thread-ambiguous": ref.ambiguous ? "true" : "false",
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
children: [{ type: "text", value: text }],
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
/** A unified attacher: `remarkPlugins={[remarkThreadRefs(threads, botId)]}`. */
|
|
386
|
+
export function remarkThreadRefs(threads, currentBotId) {
|
|
387
|
+
return () => (tree) => {
|
|
388
|
+
if (!threads.length)
|
|
389
|
+
return;
|
|
390
|
+
const visit = (node) => {
|
|
391
|
+
if (!node.children || OPAQUE.has(node.type))
|
|
392
|
+
return;
|
|
393
|
+
node.children = node.children.flatMap((child) => {
|
|
394
|
+
if (child.type !== "text" || typeof child.value !== "string") {
|
|
395
|
+
visit(child);
|
|
396
|
+
return [child];
|
|
397
|
+
}
|
|
398
|
+
const spans = resolveThreadRefs(child.value, threads, currentBotId);
|
|
399
|
+
if (!spans.some((span) => span.ref))
|
|
400
|
+
return [child];
|
|
401
|
+
return spans.map((span) => (span.ref ? linkNode(span.text, span.ref) : { type: "text", value: span.text }));
|
|
402
|
+
});
|
|
403
|
+
};
|
|
404
|
+
visit(tree);
|
|
405
|
+
};
|
|
406
|
+
}
|
|
@@ -628,7 +628,7 @@ import { promisify } from "node:util";
|
|
|
628
628
|
|
|
629
629
|
// server/config.ts
|
|
630
630
|
import { homedir as homedir2 } from "node:os";
|
|
631
|
-
import { join as
|
|
631
|
+
import { join as join2 } from "node:path";
|
|
632
632
|
|
|
633
633
|
// node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
|
|
634
634
|
var external_exports = {};
|
|
@@ -15930,6 +15930,48 @@ function normalizeCronSchedule(value, after = Date.now()) {
|
|
|
15930
15930
|
return schedule;
|
|
15931
15931
|
}
|
|
15932
15932
|
|
|
15933
|
+
// shared/tool-scope.ts
|
|
15934
|
+
var SERVER_NAME = /^[a-z][a-z0-9_-]{0,31}$/;
|
|
15935
|
+
var CONTROL_CHARACTER = /[\x00-\x1f\x7f]/;
|
|
15936
|
+
var MAX_SELECTORS = 256;
|
|
15937
|
+
var MAX_SELECTOR_LENGTH = 1024;
|
|
15938
|
+
function validName(name) {
|
|
15939
|
+
return typeof name === "string" && name.trim().length > 0 && name.length <= MAX_SELECTOR_LENGTH && !CONTROL_CHARACTER.test(name) && !name.includes("*");
|
|
15940
|
+
}
|
|
15941
|
+
function selectorIdentity(selector) {
|
|
15942
|
+
if (selector.length > MAX_SELECTOR_LENGTH || CONTROL_CHARACTER.test(selector)) return;
|
|
15943
|
+
if (selector.startsWith("native:")) {
|
|
15944
|
+
const name = selector.slice(7);
|
|
15945
|
+
if (name === "*" || validName(name)) return { kind: "native", name };
|
|
15946
|
+
} else if (selector.startsWith("mcp:")) {
|
|
15947
|
+
const separator = selector.indexOf(":", 4);
|
|
15948
|
+
if (separator < 0) return;
|
|
15949
|
+
const server = selector.slice(4, separator);
|
|
15950
|
+
const name = selector.slice(separator + 1);
|
|
15951
|
+
if (SERVER_NAME.test(server) && (name === "*" || validName(name))) {
|
|
15952
|
+
return { kind: "mcp", server, name };
|
|
15953
|
+
}
|
|
15954
|
+
}
|
|
15955
|
+
}
|
|
15956
|
+
function parseToolScope(value) {
|
|
15957
|
+
if (value === void 0) return { ok: true, scope: void 0 };
|
|
15958
|
+
const invalid = { ok: false, error: "Tool selection must contain only valid allow and deny lists." };
|
|
15959
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return invalid;
|
|
15960
|
+
const prototype = Object.getPrototypeOf(value);
|
|
15961
|
+
if (prototype !== Object.prototype && prototype !== null) return invalid;
|
|
15962
|
+
const scope = {};
|
|
15963
|
+
for (const key of Reflect.ownKeys(value)) {
|
|
15964
|
+
if (key !== "allow" && key !== "deny") return invalid;
|
|
15965
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
15966
|
+
if (!descriptor || !("value" in descriptor)) return invalid;
|
|
15967
|
+
const list = descriptor.value;
|
|
15968
|
+
if (!Array.isArray(list) || list.length > MAX_SELECTORS) return invalid;
|
|
15969
|
+
if (!Array.from(list).every((entry) => typeof entry === "string" && selectorIdentity(entry))) return invalid;
|
|
15970
|
+
scope[key] = [...new Set(list)];
|
|
15971
|
+
}
|
|
15972
|
+
return { ok: true, scope };
|
|
15973
|
+
}
|
|
15974
|
+
|
|
15933
15975
|
// server/new-bot-defaults.ts
|
|
15934
15976
|
var strings = (max, length) => external_exports.array(external_exports.string().max(length)).max(max);
|
|
15935
15977
|
var clock = external_exports.string().regex(/^(?:[01]\d|2[0-3]):[0-5]\d$/);
|
|
@@ -15964,6 +16006,10 @@ var botDefaultsProfileSchema = profilePatchSchema.extend({
|
|
|
15964
16006
|
browser: external_exports.boolean().optional(),
|
|
15965
16007
|
browserProfile: external_exports.string().max(100).nullable().optional(),
|
|
15966
16008
|
mcpServers: strings(100, 100).nullable().optional(),
|
|
16009
|
+
toolScope: external_exports.custom((value) => value !== void 0 && parseToolScope(value).ok, "Invalid tool selection").transform((value) => {
|
|
16010
|
+
const parsed = parseToolScope(value);
|
|
16011
|
+
return parsed.ok ? parsed.scope : value;
|
|
16012
|
+
}).nullable().optional(),
|
|
15967
16013
|
parkDirectMessages: external_exports.boolean().optional()
|
|
15968
16014
|
}).strict();
|
|
15969
16015
|
var scheduleSchema = external_exports.discriminatedUnion("type", [
|
|
@@ -16160,76 +16206,6 @@ var remoteMutationSchema = remoteEntrySchema.extend({
|
|
|
16160
16206
|
var CLOUD_SEAT_IDLE_STOP_MS = 5 * 6e4;
|
|
16161
16207
|
var CLOUD_SEAT_SLEEP_RETRY_MAX_MS = 10 * 6e4;
|
|
16162
16208
|
|
|
16163
|
-
// server/proxy-paths.ts
|
|
16164
|
-
import { existsSync as existsSync2 } from "node:fs";
|
|
16165
|
-
import { dirname as dirname2, join as join2 } from "node:path";
|
|
16166
|
-
import { fileURLToPath } from "node:url";
|
|
16167
|
-
var SERVER_ROOT = dirname2(fileURLToPath(import.meta.url));
|
|
16168
|
-
function resolveProxy(relative) {
|
|
16169
|
-
const source = join2(SERVER_ROOT, `${relative}.ts`);
|
|
16170
|
-
return existsSync2(source) ? source : join2(SERVER_ROOT, `${relative}.js`);
|
|
16171
|
-
}
|
|
16172
|
-
var SPAWNED_PROXIES = {
|
|
16173
|
-
browser: resolveProxy("browser-proxy"),
|
|
16174
|
-
localComputer: resolveProxy("local-computer-proxy"),
|
|
16175
|
-
permission: resolveProxy("permission-proxy"),
|
|
16176
|
-
containerMcp: resolveProxy("container-mcp"),
|
|
16177
|
-
vpsContainerMcp: resolveProxy("vps-container-mcp"),
|
|
16178
|
-
agents: resolveProxy("drivers/agents-proxy"),
|
|
16179
|
-
dweb: resolveProxy("drivers/dweb-proxy"),
|
|
16180
|
-
connectors: resolveProxy("connector-proxy"),
|
|
16181
|
-
mcpGate: resolveProxy("mcp-gate"),
|
|
16182
|
-
phone: resolveProxy("drivers/phone-proxy"),
|
|
16183
|
-
hook: resolveProxy("hooks/omb-hook"),
|
|
16184
|
-
// Loaded by the external `pi` process via `-e`, not by this server — but
|
|
16185
|
-
// resolved through the same single source of truth so the packaged layout
|
|
16186
|
-
// check can assert it ships.
|
|
16187
|
-
piMcpExtension: resolveProxy("drivers/pi-mcp-extension")
|
|
16188
|
-
};
|
|
16189
|
-
|
|
16190
|
-
// server/enterprise.ts
|
|
16191
|
-
var layerSchema = external_exports.object({
|
|
16192
|
-
customer: external_exports.string().min(1),
|
|
16193
|
-
features: external_exports.array(external_exports.string().min(1)),
|
|
16194
|
-
expiresAt: external_exports.string().nullable()
|
|
16195
|
-
});
|
|
16196
|
-
var DAY_MS = 24 * 60 * 6e4;
|
|
16197
|
-
|
|
16198
|
-
// server/sessions.ts
|
|
16199
|
-
var PAIRING_CODE_TTL_MS = 5 * 6e4;
|
|
16200
|
-
function daysMs(value, fallbackDays) {
|
|
16201
|
-
const days = Number(value);
|
|
16202
|
-
const ok = Number.isInteger(days) && days >= 1 && days <= 3650;
|
|
16203
|
-
return (ok ? days : fallbackDays) * 24 * 60 * 6e4;
|
|
16204
|
-
}
|
|
16205
|
-
var SESSION_TTL_MS = daysMs(process.env.OMB_SESSION_TTL_DAYS, 30);
|
|
16206
|
-
var SESSION_MAX_AGE_MS = daysMs(process.env.OMB_SESSION_MAX_DAYS, 180);
|
|
16207
|
-
var SESSION_RENEW_WHEN_LEFT_MS = SESSION_TTL_MS / 2;
|
|
16208
|
-
var STREAM_TICKET_TTL_MS = 5 * 6e4;
|
|
16209
|
-
var scopeSchema = external_exports.enum(["admin", "client"]);
|
|
16210
|
-
var sessionSchema = external_exports.object({
|
|
16211
|
-
id: external_exports.string().min(1),
|
|
16212
|
-
tokenHash: external_exports.string().length(64),
|
|
16213
|
-
label: external_exports.string().max(80),
|
|
16214
|
-
scopes: external_exports.array(scopeSchema).min(1),
|
|
16215
|
-
createdAt: external_exports.number(),
|
|
16216
|
-
lastSeenAt: external_exports.number(),
|
|
16217
|
-
expiresAt: external_exports.number(),
|
|
16218
|
-
/** Set when the session came from an account sign-in rather than a code. */
|
|
16219
|
-
userId: external_exports.string().max(256).optional(),
|
|
16220
|
-
email: external_exports.string().max(320).optional(),
|
|
16221
|
-
/** Set only by the internal verified-portal issuance path, never by email or pairing input. */
|
|
16222
|
-
membershipAuthority: external_exports.literal("portal").optional(),
|
|
16223
|
-
/** A browser sign-in (PairingCode `browser`): accepted only as its browser's cookie, never as a bearer token. */
|
|
16224
|
-
cookieOnly: external_exports.literal(true).optional(),
|
|
16225
|
-
/** Whose OMB Cloud a browser sign-in signed in to (its PairingCode `owner`). */
|
|
16226
|
-
owner: external_exports.string().max(254).optional()
|
|
16227
|
-
});
|
|
16228
|
-
var fileSchema = external_exports.object({ version: external_exports.literal(1), sessions: external_exports.array(sessionSchema) });
|
|
16229
|
-
|
|
16230
|
-
// server/cloud-home.ts
|
|
16231
|
-
var CLOUD_PAIRING_NONCE_MS = 10 * 6e4;
|
|
16232
|
-
|
|
16233
16209
|
// server/config.ts
|
|
16234
16210
|
var optionalText = external_exports.string().optional();
|
|
16235
16211
|
var SSH_ALIAS = /^[A-Za-z0-9][A-Za-z0-9_.-]{0,127}$/;
|
|
@@ -16437,7 +16413,11 @@ var featureConfigSchema = external_exports.object({
|
|
|
16437
16413
|
* may offer a per-second-billed cloud seat, but only through an explicit
|
|
16438
16414
|
* consent card or a configured allowlist — never a silent Auto default.
|
|
16439
16415
|
* Off until baked; see cloudOverflowEnabled for how to enable it by hand. */
|
|
16440
|
-
cloudOverflow: external_exports.boolean().optional()
|
|
16416
|
+
cloudOverflow: external_exports.boolean().optional(),
|
|
16417
|
+
/** Opt-in shared skills library: one store at the data dir that bots
|
|
16418
|
+
* read by assignment instead of per-workspace copies. Off until
|
|
16419
|
+
* explicitly enabled — see skillsLibraryEnabled. */
|
|
16420
|
+
skillsLibrary: external_exports.boolean().optional()
|
|
16441
16421
|
});
|
|
16442
16422
|
var onboardingConfigSchema = external_exports.object({
|
|
16443
16423
|
/** ISO timestamp of finishing (or skipping to the end of) the welcome flow. */
|
|
@@ -16590,6 +16570,15 @@ var appConfigSchema = external_exports.object({
|
|
|
16590
16570
|
baseUrl: external_exports.string().trim().max(2048).refine((value) => !value || /^https?:\/\//i.test(value), "the decision model address must start with http:// or https://").optional(),
|
|
16591
16571
|
jobs: external_exports.object({ roomRouting: external_exports.boolean().optional() }).optional()
|
|
16592
16572
|
}).optional(),
|
|
16573
|
+
/** Live calls: an OpenAI project key for GPT-Live, kept apart from every
|
|
16574
|
+
* other OpenAI credential so a Live call never bills an image or engine key
|
|
16575
|
+
* the user did not hand to it. `voice` is a GPT-Live built-in voice name. */
|
|
16576
|
+
live: external_exports.object({
|
|
16577
|
+
key: optionalText,
|
|
16578
|
+
voice: external_exports.string().trim().max(40).regex(/^[a-z]*$/, "a Live voice is a lowercase built-in voice name").optional(),
|
|
16579
|
+
readTypedReplies: external_exports.boolean().optional(),
|
|
16580
|
+
idleMinutes: external_exports.number().int().min(1).max(60).optional()
|
|
16581
|
+
}).optional(),
|
|
16593
16582
|
/** Avatar provider credentials stay separate; choosing a router never reuses a cloud key. */
|
|
16594
16583
|
imageGen: external_exports.object({
|
|
16595
16584
|
provider: external_exports.enum(["openai", "xai", "custom"]).optional(),
|
|
@@ -16659,10 +16648,10 @@ var storedAppConfigSchema = appConfigSchema.extend({
|
|
|
16659
16648
|
var appConfigPatchSchema = appConfigSchema.omit({ instances: true, mcpServers: true, cliStartup: true, customDomain: true }).extend({ threads: threadsPatchSchema.optional(), newBots: newBotsPatchSchema.optional() });
|
|
16660
16649
|
var jsonObjectSchema = external_exports.record(external_exports.string(), external_exports.json());
|
|
16661
16650
|
var DEFAULT_CAPTURE_QUIET_MS = 2 * 6e4;
|
|
16662
|
-
var DATA_DIR = process.env.OMB_DATA_DIR ??
|
|
16663
|
-
var LEGACY_DATA_DIR =
|
|
16664
|
-
var EVENTS_DIR =
|
|
16665
|
-
var NATIVE_DIR =
|
|
16651
|
+
var DATA_DIR = process.env.OMB_DATA_DIR ?? join2(homedir2(), ".openmausbot");
|
|
16652
|
+
var LEGACY_DATA_DIR = join2(homedir2(), ".opengrokbot");
|
|
16653
|
+
var EVENTS_DIR = join2(DATA_DIR, "events");
|
|
16654
|
+
var NATIVE_DIR = join2(DATA_DIR, "native");
|
|
16666
16655
|
var OPENAI_API_INSTANCE = "openai";
|
|
16667
16656
|
var OPENROUTER_API_INSTANCE = "openrouter";
|
|
16668
16657
|
var XAI_API_INSTANCE = "xaiApi";
|
|
@@ -16692,6 +16681,35 @@ var API_KEY_FLEET = {
|
|
|
16692
16681
|
}
|
|
16693
16682
|
};
|
|
16694
16683
|
|
|
16684
|
+
// server/proxy-paths.ts
|
|
16685
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
16686
|
+
import { dirname as dirname2, join as join3 } from "node:path";
|
|
16687
|
+
import { fileURLToPath } from "node:url";
|
|
16688
|
+
var SERVER_ROOT = dirname2(fileURLToPath(import.meta.url));
|
|
16689
|
+
function resolveProxy(relative) {
|
|
16690
|
+
const source = join3(SERVER_ROOT, `${relative}.ts`);
|
|
16691
|
+
return existsSync2(source) ? source : join3(SERVER_ROOT, `${relative}.js`);
|
|
16692
|
+
}
|
|
16693
|
+
var SPAWNED_PROXIES = {
|
|
16694
|
+
// The built-in browser and the cloud computer: argv[2] picks which.
|
|
16695
|
+
harnessMcp: resolveProxy("harness-mcp-proxy"),
|
|
16696
|
+
localComputer: resolveProxy("local-computer-proxy"),
|
|
16697
|
+
permission: resolveProxy("permission-proxy"),
|
|
16698
|
+
containerMcp: resolveProxy("container-mcp"),
|
|
16699
|
+
vpsContainerMcp: resolveProxy("vps-container-mcp"),
|
|
16700
|
+
agents: resolveProxy("drivers/agents-proxy"),
|
|
16701
|
+
dweb: resolveProxy("drivers/dweb-proxy"),
|
|
16702
|
+
connectors: resolveProxy("connector-proxy"),
|
|
16703
|
+
mcpGate: resolveProxy("mcp-gate"),
|
|
16704
|
+
mcpRemote: resolveProxy("mcp-remote-proxy"),
|
|
16705
|
+
phone: resolveProxy("drivers/phone-proxy"),
|
|
16706
|
+
hook: resolveProxy("hooks/omb-hook"),
|
|
16707
|
+
// Loaded by the external `pi` process via `-e`, not by this server — but
|
|
16708
|
+
// resolved through the same single source of truth so the packaged layout
|
|
16709
|
+
// check can assert it ships.
|
|
16710
|
+
piMcpExtension: resolveProxy("drivers/pi-mcp-extension")
|
|
16711
|
+
};
|
|
16712
|
+
|
|
16695
16713
|
// server/container-computer.ts
|
|
16696
16714
|
var run = promisify(execFile2);
|
|
16697
16715
|
var CUA_DRIVER_VERSION = "0.20.0";
|
|
@@ -16707,7 +16725,6 @@ var DISPLAY = ":1";
|
|
|
16707
16725
|
var CUA_SOCKET = "/run/user/1000/openmausbot-cua.sock";
|
|
16708
16726
|
var CUA_EXECUTABLE = "/usr/local/libexec/openmausbot/cua-driver";
|
|
16709
16727
|
var MEMORY_BYTES = 4 * 1024 * 1024 * 1024;
|
|
16710
|
-
var SHM_BYTES = 512 * 1024 * 1024;
|
|
16711
16728
|
function cuaExecArgs(args2, options = {}) {
|
|
16712
16729
|
return [
|
|
16713
16730
|
"exec",
|