openmausbot 0.1.84 → 0.1.86
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/KaTeX_AMS-Regular-BQhdFMY1.woff2 +0 -0
- package/dist/assets/KaTeX_AMS-Regular-DMm9YOAa.woff +0 -0
- package/dist/assets/KaTeX_AMS-Regular-DRggAlZN.ttf +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-ATXxdsX0.ttf +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-BEiXGLvX.woff +0 -0
- package/dist/assets/KaTeX_Caligraphic-Bold-Dq_IR9rO.woff2 +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-CTRA-rTL.woff +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-Di6jR-x-.woff2 +0 -0
- package/dist/assets/KaTeX_Caligraphic-Regular-wX97UBjC.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-BdnERNNW.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-BsDP51OF.woff +0 -0
- package/dist/assets/KaTeX_Fraktur-Bold-CL6g_b3V.woff2 +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-CB_wures.ttf +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-CTYiF6lA.woff2 +0 -0
- package/dist/assets/KaTeX_Fraktur-Regular-Dxdc4cR9.woff +0 -0
- package/dist/assets/KaTeX_Main-Bold-Cx986IdX.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Bold-Jm3AIy58.woff +0 -0
- package/dist/assets/KaTeX_Main-Bold-waoOVXN0.ttf +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-DxDJ3AOS.woff2 +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-DzxPMmG6.ttf +0 -0
- package/dist/assets/KaTeX_Main-BoldItalic-SpSLRI95.woff +0 -0
- package/dist/assets/KaTeX_Main-Italic-3WenGoN9.ttf +0 -0
- package/dist/assets/KaTeX_Main-Italic-BMLOBm91.woff +0 -0
- package/dist/assets/KaTeX_Main-Italic-NWA7e6Wa.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Regular-B22Nviop.woff2 +0 -0
- package/dist/assets/KaTeX_Main-Regular-Dr94JaBh.woff +0 -0
- package/dist/assets/KaTeX_Main-Regular-ypZvNtVU.ttf +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-B3XSjfu4.ttf +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-CZnvNsCZ.woff2 +0 -0
- package/dist/assets/KaTeX_Math-BoldItalic-iY-2wyZ7.woff +0 -0
- package/dist/assets/KaTeX_Math-Italic-DA0__PXp.woff +0 -0
- package/dist/assets/KaTeX_Math-Italic-flOr_0UB.ttf +0 -0
- package/dist/assets/KaTeX_Math-Italic-t53AETM-.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-CFMepnvq.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-D1sUS0GD.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Bold-DbIhKOiC.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-C3H0VqGB.woff2 +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-DN2j7dab.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Italic-YYjJ1zSn.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-BNo7hRIc.ttf +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-CS6fqUqJ.woff +0 -0
- package/dist/assets/KaTeX_SansSerif-Regular-DDBCnlJ7.woff2 +0 -0
- package/dist/assets/KaTeX_Script-Regular-C5JkGWo-.ttf +0 -0
- package/dist/assets/KaTeX_Script-Regular-D3wIWfF6.woff2 +0 -0
- package/dist/assets/KaTeX_Script-Regular-D5yQViql.woff +0 -0
- package/dist/assets/KaTeX_Size1-Regular-C195tn64.woff +0 -0
- package/dist/assets/KaTeX_Size1-Regular-Dbsnue_I.ttf +0 -0
- package/dist/assets/KaTeX_Size1-Regular-mCD8mA8B.woff2 +0 -0
- package/dist/assets/KaTeX_Size2-Regular-B7gKUWhC.ttf +0 -0
- package/dist/assets/KaTeX_Size2-Regular-Dy4dx90m.woff2 +0 -0
- package/dist/assets/KaTeX_Size2-Regular-oD1tc_U0.woff +0 -0
- package/dist/assets/KaTeX_Size3-Regular-CTq5MqoE.woff +0 -0
- package/dist/assets/KaTeX_Size3-Regular-DgpXs0kz.ttf +0 -0
- package/dist/assets/KaTeX_Size4-Regular-BF-4gkZK.woff +0 -0
- package/dist/assets/KaTeX_Size4-Regular-DWFBv043.ttf +0 -0
- package/dist/assets/KaTeX_Size4-Regular-Dl5lxZxV.woff2 +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-C0xS9mPB.woff +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-CO6r4hn1.woff2 +0 -0
- package/dist/assets/KaTeX_Typewriter-Regular-D3Ib7_Hf.ttf +0 -0
- package/dist/assets/abnfDiagram-O67JEVCF-DpUZNnFD.js +1 -0
- package/dist/assets/arc-DW7mrI4p.js +1 -0
- package/dist/assets/architectureDiagram-NJMV4G6O-CyeZ5WLZ.js +36 -0
- package/dist/assets/blockDiagram-BEXU5L5S-CBVaNjO7.js +140 -0
- package/dist/assets/c4Diagram-YGBWAQC7-sf8d41uT.js +38 -0
- package/dist/assets/channel-BXFkgus9.js +1 -0
- package/dist/assets/chunk-2Q5K7J3B-BOGvy7Y_.js +1 -0
- package/dist/assets/chunk-3FUC2YCW-BiF9zyiz.js +2 -0
- package/dist/assets/chunk-5VM5RSS4-EFuZ1SBZ.js +15 -0
- package/dist/assets/chunk-GTNCS2PH-pJLNSAT7.js +88 -0
- package/dist/assets/chunk-GWA4HPMP-Cb-3_3IT.js +1 -0
- package/dist/assets/chunk-JWPE2WC7-DAf5aogn.js +1 -0
- package/dist/assets/chunk-NETBCI7D-DR3kiwZz.js +1 -0
- package/dist/assets/chunk-WEXAMYUT-BmU8PeyM.js +1 -0
- package/dist/assets/chunk-XXDRQBXY-Buh8g8OT.js +1 -0
- package/dist/assets/classDiagram-v2-NBCMYWYE-BurfmMWM.js +217 -0
- package/dist/assets/cose-bilkent-JH36ORCC-KkGZUEkU.js +1 -0
- package/dist/assets/cynefin-OW5HDTMX-C3PpV96d.js +166 -0
- package/dist/assets/cynefinDiagram-VND7K2PF-Dt8JwJaI.js +62 -0
- package/dist/assets/cytoscape.esm-BB4DxJjf.js +321 -0
- package/dist/assets/dagre-6A5THRUB-DkjN8266.js +4 -0
- package/dist/assets/defaultLocale-DX6XiGOO.js +1 -0
- package/dist/assets/diagram-22UHCM2B-DUAJS0JV.js +200 -0
- package/dist/assets/diagram-3UASUU5V-Dw4KhF1a.js +24 -0
- package/dist/assets/diagram-ATOU4E4O-Dd1gmQqf.js +3 -0
- package/dist/assets/diagram-CDSNMT55-CjwGs0Yw.js +30 -0
- package/dist/assets/diagram-MLGK6HIB-BL-69Zrq.js +24 -0
- package/dist/assets/diagram-MPIPVDR6-5Zi2N7wo.js +41 -0
- package/dist/assets/ebnfDiagram-ZINNZB2B-D9NekWUX.js +1 -0
- package/dist/assets/elk-276RUBZZ-CkaSQjxw.js +27 -0
- package/dist/assets/erDiagram-OPXOYQCR-CdAVBV8-.js +99 -0
- package/dist/assets/flowDiagram-KWPJA3E3-Bm_lWWH7.js +213 -0
- package/dist/assets/ganttDiagram-FUAMR5RP-FZ8ejYWJ.js +292 -0
- package/dist/assets/gitGraphDiagram-X574FWY7-Dlv9rizZ.js +106 -0
- package/dist/assets/graph-D8UmR1vK.js +1 -0
- package/dist/assets/index-BGgqlWPJ.css +1 -0
- package/dist/assets/index-BtHo8ZKl.js +577 -0
- package/dist/assets/{index-DNa2umw-.js → index-h9FFNwTu.js} +1 -1
- package/dist/assets/infoDiagram-VRGFBTTK-BdQ_gW5B.js +2 -0
- package/dist/assets/init-Gi6I4Gst.js +1 -0
- package/dist/assets/ishikawaDiagram-OU5B5YK6-EwssEp2X.js +70 -0
- package/dist/assets/journeyDiagram-ZHPQQLJL-BX1G1vOd.js +139 -0
- package/dist/assets/kanban-definition-PNTS6WVX-BB4kAsyC.js +89 -0
- package/dist/assets/linear-3su2TG93.js +1 -0
- package/dist/assets/mermaid.core-CDD1E0s9.js +311 -0
- package/dist/assets/mindmap-definition-NLK3R4M7-Ba50MsNK.js +96 -0
- package/dist/assets/ordinal-Cboi1Yqb.js +1 -0
- package/dist/assets/pegDiagram-GJSIUBJH-DZLkkZlM.js +1 -0
- package/dist/assets/pieDiagram-5QR66LMP-DaTz77Uq.js +39 -0
- package/dist/assets/quadrantDiagram-O4NWA36T-CpaiidpR.js +7 -0
- package/dist/assets/railroadDiagram-XR7U4H2S-mN4JrMeI.js +1 -0
- package/dist/assets/requirementDiagram-PLB6GJNP-BSNDRpg7.js +84 -0
- package/dist/assets/sankeyDiagram-IPEJSGJF-FngzGNug.js +40 -0
- package/dist/assets/sequenceDiagram-PO4LG4MO-CM4pCC3L.js +169 -0
- package/dist/assets/sizeCapture-INFHLROL-CRICHXkw.js +1 -0
- package/dist/assets/stateDiagram-v2-GCMORJYK-oyTWpxH2.js +291 -0
- package/dist/assets/swimlanes-2SLR337P-D9h9mPBq.js +1 -0
- package/dist/assets/swimlanesDiagram-TC7HE7FX-BWrvB2ak.js +8 -0
- package/dist/assets/timeline-definition-EJHVYXUP-BJUlN9bW.js +120 -0
- package/dist/assets/usecaseDiagram-POWQR4AR-3uBNkbAb.js +370 -0
- package/dist/assets/vennDiagram-UO4OBE2U-D2odalzT.js +34 -0
- package/dist/assets/wardleyDiagram-VNRHLVJA-DHgFaB9S.js +78 -0
- package/dist/assets/xychartDiagram-PMCCYNJV-w5GYM2h0.js +7 -0
- package/dist/index.html +2 -2
- package/dist-server/companion/src/routes.js +1 -0
- package/dist-server/container-mcp.js +231 -17
- package/dist-server/drivers/agents-proxy.js +16097 -1411
- package/dist-server/enterprise/LICENSE +32 -0
- package/dist-server/enterprise/server/index.js +6 -5
- package/dist-server/hooks/omb-hook.js +74 -0
- package/dist-server/index.js +12495 -7584
- package/dist-server/local-computer-proxy.js +83 -1
- package/dist-server/local-computer.js +14 -2
- package/dist-server/mcp-server.js +3 -1
- package/dist-server/openmausbot.js +5458 -4587
- package/dist-server/pair-cli.js +5458 -4587
- package/dist-server/proxy-paths.js +1 -0
- package/dist-server/server/admin-activity.js +410 -0
- package/dist-server/server/agent-tool-policy.js +1 -0
- package/dist-server/server/bot-package.js +2 -0
- package/dist-server/server/bot-visibility.js +462 -0
- package/dist-server/server/box.js +25 -5
- package/dist-server/server/browser-engine.js +87 -10
- package/dist-server/server/browser-live.js +7 -5
- package/dist-server/server/browser-runtime.js +66 -11
- package/dist-server/server/channel-queue.js +2 -0
- package/dist-server/server/checkpoints.js +62 -18
- package/dist-server/server/cli-prompts.js +26 -2
- package/dist-server/server/cli.js +79 -10
- package/dist-server/server/commands.js +27 -0
- package/dist-server/server/compaction-summary.js +78 -0
- package/dist-server/server/composio.js +49 -11
- package/dist-server/server/config.js +137 -14
- package/dist-server/server/context-budget.js +29 -0
- package/dist-server/server/context-rebuild.js +72 -0
- package/dist-server/server/decision-log.js +209 -48
- package/dist-server/server/default-model-selection.js +20 -3
- package/dist-server/server/delegations.js +11 -9
- package/dist-server/server/digest.js +130 -0
- package/dist-server/server/drivers/acp/core.js +637 -238
- package/dist-server/server/drivers/acp/grok.js +4 -3
- package/dist-server/server/drivers/agents-call.js +1123 -0
- package/dist-server/server/drivers/agents-catalog.js +659 -0
- package/dist-server/server/drivers/agents-client.js +28 -0
- package/dist-server/server/drivers/agents-proxy.js +18 -1683
- package/dist-server/server/drivers/agents-result.js +23 -0
- package/dist-server/server/drivers/chat-mcp-tools.js +17 -2
- package/dist-server/server/drivers/claude.js +83 -16
- package/dist-server/server/drivers/codex-mcp-names.js +44 -0
- package/dist-server/server/drivers/codex.js +32 -4
- package/dist-server/server/drivers/grok.js +2 -1
- package/dist-server/server/drivers/openai-chat.js +66 -45
- package/dist-server/server/drivers/openai-compat.js +16 -8
- package/dist-server/server/enterprise.js +97 -16
- package/dist-server/server/external-runtime.js +83 -0
- package/dist-server/server/guarded-requests.js +60 -0
- package/dist-server/server/harness/http.js +61 -0
- package/dist-server/server/hooks/omb-hook.js +103 -0
- package/dist-server/server/hosted-models.js +151 -0
- package/dist-server/server/hosted-slack.js +11 -0
- package/dist-server/server/index.js +2810 -678
- package/dist-server/server/local-computer.js +21 -2
- package/dist-server/server/managed-desktop.js +79 -14
- package/dist-server/server/managed-policy.js +153 -0
- package/dist-server/server/mcp-bridge.js +10 -2
- package/dist-server/server/mcp-tool-images.js +37 -0
- package/dist-server/server/mcp-tool-schema.js +108 -0
- package/dist-server/server/message-db.js +108 -21
- package/dist-server/server/message-file.js +3 -2
- package/dist-server/server/model-context-window.js +7 -0
- package/dist-server/server/model-prices.js +121 -0
- package/dist-server/server/notify.js +10 -1
- package/dist-server/server/package-export.js +1 -0
- package/dist-server/server/peer-roster.js +17 -4
- package/dist-server/server/provider-icon.js +20 -0
- package/dist-server/server/proxy-paths.js +1 -0
- package/dist-server/server/recent-work.js +15 -0
- package/dist-server/server/request-auth.js +97 -0
- package/dist-server/server/room-handoffs.js +41 -13
- package/dist-server/server/routes/hosted-slack.js +20 -0
- package/dist-server/server/routes/table.js +14 -0
- package/dist-server/server/routine-requests.js +39 -1
- package/dist-server/server/routines.js +65 -9
- package/dist-server/server/shared-computer-control.js +31 -4
- package/dist-server/server/spend.js +111 -16
- package/dist-server/server/steer-queue.js +12 -1
- package/dist-server/server/store.js +384 -33
- package/dist-server/server/system-prompt.js +4 -4
- package/dist-server/server/team-backup.js +19 -2
- package/dist-server/server/thread-starters.js +53 -0
- package/dist-server/server/tool-results.js +72 -0
- package/dist-server/server/tts/grok.js +74 -0
- package/dist-server/server/tts/index.js +19 -1
- package/dist-server/server/usage-ledger.js +31 -8
- package/dist-server/server/webhooks.js +28 -0
- package/dist-server/server/workspace-backup-policy.js +9 -2
- package/dist-server/server/workspace-backup.js +7 -4
- package/dist-server/shared/approval-mode.js +7 -1
- package/dist-server/shared/digest.js +1 -0
- package/dist-server/shared/markdown-windows-paths.js +36 -0
- package/dist-server/shared/mention-boundary.js +15 -0
- package/dist-server/shared/provider-icon.js +110 -0
- package/dist-server/shared/routines.js +7 -1
- package/dist-server/shared/team-backup.js +5 -0
- package/dist-server/src/lib/composer-attachments.js +16 -0
- package/dist-server/vps-container-mcp.js +236 -22
- package/enterprise/README.md +33 -12
- package/enterprise/server/index.js +6 -5
- package/package.json +1 -1
- package/dist/assets/index-BbU5REzd.js +0 -310
- package/dist/assets/index-CLGfYlx_.css +0 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// Keep mention recognition identical in the renderer and server routing.
|
|
2
|
+
// Deliberately allow only opening punctuation/Markdown markers here: `/@bot`
|
|
3
|
+
// remains a URL path, while `(@bot)`, `【@bot】`, and `**@bot**` are tags.
|
|
4
|
+
const OPENING_MENTION_BOUNDARY = /[(*_~[{<'"\u2018\u201c\u3008\u300a\u300c\u300e\u3010\uff08]/u;
|
|
5
|
+
/** Return whether an at-sign starts a standalone mention at this offset. */
|
|
6
|
+
export function isMentionBoundary(text, at) {
|
|
7
|
+
if (at === 0)
|
|
8
|
+
return true;
|
|
9
|
+
const before = text[at - 1];
|
|
10
|
+
return /\s/u.test(before) || OPENING_MENTION_BOUNDARY.test(before);
|
|
11
|
+
}
|
|
12
|
+
/** A matched name must not be the prefix of a longer Unicode word. */
|
|
13
|
+
export function isMentionNameContinuation(value) {
|
|
14
|
+
return value !== undefined && /^[\p{L}\p{N}\p{M}_]/u.test(value);
|
|
15
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
export const PROVIDER_ICON_PRESETS = [
|
|
2
|
+
"openai", "anthropic", "google", "azure", "aws", "xai", "deepseek",
|
|
3
|
+
"meta", "mistral", "qwen", "moonshot", "cohere", "openrouter",
|
|
4
|
+
];
|
|
5
|
+
export const PROVIDER_ICON_MAX_BYTES = 128 * 1024;
|
|
6
|
+
export const PROVIDER_ICON_MAX_DIMENSION = 1024;
|
|
7
|
+
export const PROVIDER_ICON_MEDIA_TYPES = ["image/png", "image/jpeg", "image/webp"];
|
|
8
|
+
export const PROVIDER_ICON_LABELS = {
|
|
9
|
+
openai: "OpenAI",
|
|
10
|
+
anthropic: "Anthropic",
|
|
11
|
+
google: "Google Gemini",
|
|
12
|
+
azure: "Microsoft Azure",
|
|
13
|
+
aws: "Amazon Bedrock (AWS)",
|
|
14
|
+
xai: "xAI",
|
|
15
|
+
deepseek: "DeepSeek",
|
|
16
|
+
meta: "Meta",
|
|
17
|
+
mistral: "Mistral AI",
|
|
18
|
+
qwen: "Qwen",
|
|
19
|
+
moonshot: "Moonshot AI",
|
|
20
|
+
cohere: "Cohere",
|
|
21
|
+
openrouter: "OpenRouter",
|
|
22
|
+
};
|
|
23
|
+
function decodedBase64Bytes(value) {
|
|
24
|
+
const padding = value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0;
|
|
25
|
+
return Math.floor(value.length * 3 / 4) - padding;
|
|
26
|
+
}
|
|
27
|
+
function imageDimensions(bytes, mime) {
|
|
28
|
+
const u16be = (offset) => bytes[offset] * 256 + bytes[offset + 1];
|
|
29
|
+
const u16le = (offset) => bytes[offset] + bytes[offset + 1] * 256;
|
|
30
|
+
const u24le = (offset) => bytes[offset] + bytes[offset + 1] * 256 + bytes[offset + 2] * 65536;
|
|
31
|
+
const u32le = (offset) => bytes[offset] + bytes[offset + 1] * 0x100 + bytes[offset + 2] * 0x10000 + bytes[offset + 3] * 0x1000000;
|
|
32
|
+
const u32be = (offset) => bytes[offset] * 0x1000000 + bytes[offset + 1] * 0x10000 + bytes[offset + 2] * 0x100 + bytes[offset + 3];
|
|
33
|
+
if (mime === "image/png") {
|
|
34
|
+
if (bytes.length < 33 || bytes.slice(0, 8).join(",") !== "137,80,78,71,13,10,26,10" ||
|
|
35
|
+
String.fromCharCode(...bytes.slice(12, 16)) !== "IHDR" ||
|
|
36
|
+
bytes.slice(-8).join(",") !== "73,69,78,68,174,66,96,130")
|
|
37
|
+
return null;
|
|
38
|
+
return { width: u32be(16), height: u32be(20) };
|
|
39
|
+
}
|
|
40
|
+
if (mime === "image/jpeg") {
|
|
41
|
+
if (bytes.length < 12 || bytes[0] !== 0xff || bytes[1] !== 0xd8 || bytes.at(-2) !== 0xff || bytes.at(-1) !== 0xd9)
|
|
42
|
+
return null;
|
|
43
|
+
for (let offset = 2; offset + 8 < bytes.length;) {
|
|
44
|
+
if (bytes[offset] !== 0xff) {
|
|
45
|
+
offset += 1;
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const marker = bytes[offset + 1];
|
|
49
|
+
if ([0xc0, 0xc1, 0xc2, 0xc3, 0xc5, 0xc6, 0xc7, 0xc9, 0xca, 0xcb, 0xcd, 0xce, 0xcf].includes(marker)) {
|
|
50
|
+
return { height: u16be(offset + 5), width: u16be(offset + 7) };
|
|
51
|
+
}
|
|
52
|
+
if (marker === 0xd8 || marker === 0xd9 || marker === 0x01 || (marker >= 0xd0 && marker <= 0xd7)) {
|
|
53
|
+
offset += 2;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
const length = u16be(offset + 2);
|
|
57
|
+
if (length < 2)
|
|
58
|
+
return null;
|
|
59
|
+
offset += length + 2;
|
|
60
|
+
}
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
if (bytes.length < 30 || String.fromCharCode(...bytes.slice(0, 4)) !== "RIFF" ||
|
|
64
|
+
String.fromCharCode(...bytes.slice(8, 12)) !== "WEBP" || u32le(4) + 8 !== bytes.length)
|
|
65
|
+
return null;
|
|
66
|
+
const format = String.fromCharCode(...bytes.slice(12, 16));
|
|
67
|
+
if (format === "VP8X")
|
|
68
|
+
return { width: u24le(24) + 1, height: u24le(27) + 1 };
|
|
69
|
+
if (format === "VP8L" && bytes[20] === 0x2f) {
|
|
70
|
+
const bits = bytes[21] | bytes[22] << 8 | bytes[23] << 16 | bytes[24] << 24;
|
|
71
|
+
return { width: (bits & 0x3fff) + 1, height: ((bits >>> 14) & 0x3fff) + 1 };
|
|
72
|
+
}
|
|
73
|
+
if (format === "VP8 " && bytes[23] === 0x9d && bytes[24] === 0x01 && bytes[25] === 0x2a) {
|
|
74
|
+
return { width: u16le(26) & 0x3fff, height: u16le(28) & 0x3fff };
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
/** Validate the complete persisted value. Custom images are local data URLs,
|
|
79
|
+
* never remote URLs, and use magic bytes so a forged MIME label is rejected. */
|
|
80
|
+
export function providerIconError(icon) {
|
|
81
|
+
if (icon.kind === "preset") {
|
|
82
|
+
return PROVIDER_ICON_PRESETS.includes(icon.preset)
|
|
83
|
+
? null : "Choose a supported provider icon.";
|
|
84
|
+
}
|
|
85
|
+
const match = /^data:(image\/(?:png|jpeg|webp));base64,([A-Za-z0-9+/]+={0,2})$/.exec(icon.dataUrl);
|
|
86
|
+
if (!match)
|
|
87
|
+
return "Upload a PNG, JPEG, or WebP image.";
|
|
88
|
+
const byteLength = decodedBase64Bytes(match[2]);
|
|
89
|
+
if (byteLength > PROVIDER_ICON_MAX_BYTES) {
|
|
90
|
+
return "Provider icons must be 128 KB or smaller.";
|
|
91
|
+
}
|
|
92
|
+
let decoded;
|
|
93
|
+
try {
|
|
94
|
+
decoded = atob(match[2]);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
return "The uploaded image is not valid base64.";
|
|
98
|
+
}
|
|
99
|
+
if (decoded.length !== byteLength)
|
|
100
|
+
return "The uploaded image is not valid base64.";
|
|
101
|
+
const bytes = Uint8Array.from(decoded, (value) => value.charCodeAt(0));
|
|
102
|
+
const dimensions = imageDimensions(bytes, match[1]);
|
|
103
|
+
if (!dimensions)
|
|
104
|
+
return "The uploaded image is incomplete or does not match its file type.";
|
|
105
|
+
if (dimensions.width < 1 || dimensions.height < 1 || dimensions.width > PROVIDER_ICON_MAX_DIMENSION ||
|
|
106
|
+
dimensions.height > PROVIDER_ICON_MAX_DIMENSION || dimensions.width * dimensions.height > PROVIDER_ICON_MAX_DIMENSION ** 2) {
|
|
107
|
+
return `Provider icons must be at most ${PROVIDER_ICON_MAX_DIMENSION} × ${PROVIDER_ICON_MAX_DIMENSION} pixels.`;
|
|
108
|
+
}
|
|
109
|
+
return null;
|
|
110
|
+
}
|
|
@@ -1 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
/** The statuses both failure indicators count: a run that went wrong and has
|
|
2
|
+
* not been acknowledged. One home so the sidebar dot, the errors pill, the
|
|
3
|
+
* logs filter and the bulk-seen sweep cannot drift apart. */
|
|
4
|
+
export const ROUTINE_PROBLEM_STATUSES = ["failed", "missed"];
|
|
5
|
+
export function isRoutineProblemRun(run) {
|
|
6
|
+
return ROUTINE_PROBLEM_STATUSES.includes(run.status);
|
|
7
|
+
}
|
|
@@ -20,8 +20,13 @@ const task = z.object({
|
|
|
20
20
|
key,
|
|
21
21
|
title: z.string().max(2_000),
|
|
22
22
|
createdAt: timestamp,
|
|
23
|
+
// Travels only when the first message already named this task, so a
|
|
24
|
+
// restore cannot re-arm one generated title on a row that used it.
|
|
25
|
+
titleFromFirstMessage: z.literal(true).optional(),
|
|
23
26
|
openedBy: z.object({ botId: key, name, at: timestamp, kind: z.enum(["pair", "work"]).optional() }).optional(),
|
|
24
27
|
closedBy: z.object({ botId: key, name, at: timestamp }).optional(),
|
|
28
|
+
/** Only true travels. Absence is unpinned, including backups from before pins. */
|
|
29
|
+
pinned: z.literal(true).optional(),
|
|
25
30
|
activeLeafId: key.nullable(),
|
|
26
31
|
messages: z.array(message).max(100_000),
|
|
27
32
|
});
|
|
@@ -691,3 +691,19 @@ export async function intakeFiles(_files, _opts) {
|
|
|
691
691
|
notice: pathless && failed ? `${pathless} (${failed})` : (pathless ?? failed),
|
|
692
692
|
};
|
|
693
693
|
}
|
|
694
|
+
/**
|
|
695
|
+
* Whether the composer may pull keyboard focus back into its textarea after an
|
|
696
|
+
* attachment lands. The draft was the writer's place when focus is still there,
|
|
697
|
+
* has fallen to the page (a disabled element drops it), or sits on a control
|
|
698
|
+
* inside the composer such as the paperclip button after the file dialog. A
|
|
699
|
+
* focused control elsewhere — a dialog, the thread list — is left alone.
|
|
700
|
+
*/
|
|
701
|
+
export function composerShouldRefocus(active, input) {
|
|
702
|
+
if (!active || active === input)
|
|
703
|
+
return true;
|
|
704
|
+
const root = input.ownerDocument;
|
|
705
|
+
if (active === root.body || active === root.documentElement)
|
|
706
|
+
return true;
|
|
707
|
+
const composer = input.closest("[data-tour=composer]");
|
|
708
|
+
return Boolean(composer?.contains(active));
|
|
709
|
+
}
|
|
@@ -183,6 +183,86 @@ function probeLoginShellPath() {
|
|
|
183
183
|
);
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
// server/mcp-tool-schema.ts
|
|
187
|
+
var ROOT_COMBINATORS = ["anyOf", "oneOf", "allOf", "not"];
|
|
188
|
+
function isObject(value) {
|
|
189
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
190
|
+
}
|
|
191
|
+
function branches(value) {
|
|
192
|
+
return Array.isArray(value) ? value.filter(isObject) : [];
|
|
193
|
+
}
|
|
194
|
+
function objectShape(schema) {
|
|
195
|
+
const properties = isObject(schema.properties) ? { ...schema.properties } : {};
|
|
196
|
+
const required2 = new Set(Array.isArray(schema.required) ? schema.required.filter((key) => typeof key === "string") : []);
|
|
197
|
+
const adopt = (shape) => {
|
|
198
|
+
for (const [key, value] of Object.entries(shape.properties)) if (!(key in properties)) properties[key] = value;
|
|
199
|
+
};
|
|
200
|
+
for (const branch of branches(schema.allOf)) {
|
|
201
|
+
const shape = objectShape(branch);
|
|
202
|
+
adopt(shape);
|
|
203
|
+
for (const key of shape.required) required2.add(key);
|
|
204
|
+
}
|
|
205
|
+
for (const keyword of ["anyOf", "oneOf"]) {
|
|
206
|
+
const choices = branches(schema[keyword]).map(objectShape);
|
|
207
|
+
if (choices.length === 0) continue;
|
|
208
|
+
for (const choice of choices) adopt(choice);
|
|
209
|
+
for (const key of choices[0].required) {
|
|
210
|
+
if (choices.every((choice) => choice.required.includes(key))) required2.add(key);
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
return { properties, required: [...required2] };
|
|
214
|
+
}
|
|
215
|
+
function describesObject(type) {
|
|
216
|
+
return type === void 0 || type === "object" || Array.isArray(type) && type.includes("object");
|
|
217
|
+
}
|
|
218
|
+
function providerSafeInputSchema(schema) {
|
|
219
|
+
if (!isObject(schema) || !describesObject(schema.type)) return { type: "object", properties: {} };
|
|
220
|
+
if (schema.type === "object" && ROOT_COMBINATORS.every((keyword) => !(keyword in schema))) return schema;
|
|
221
|
+
const { properties, required: required2 } = objectShape(schema);
|
|
222
|
+
const safe = { ...schema, type: "object", properties };
|
|
223
|
+
for (const keyword of ROOT_COMBINATORS) delete safe[keyword];
|
|
224
|
+
if (required2.length > 0) safe.required = required2;
|
|
225
|
+
else delete safe.required;
|
|
226
|
+
return safe;
|
|
227
|
+
}
|
|
228
|
+
function createToolListNormalizer() {
|
|
229
|
+
const pending = /* @__PURE__ */ new Set();
|
|
230
|
+
const idKey = (id) => `${typeof id}:${String(id)}`;
|
|
231
|
+
return {
|
|
232
|
+
observeRequest(line) {
|
|
233
|
+
let frame;
|
|
234
|
+
try {
|
|
235
|
+
frame = JSON.parse(line);
|
|
236
|
+
} catch {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
if (isObject(frame) && frame.method === "tools/list" && (typeof frame.id === "number" || typeof frame.id === "string")) {
|
|
240
|
+
pending.add(idKey(frame.id));
|
|
241
|
+
}
|
|
242
|
+
},
|
|
243
|
+
rewriteResponse(line) {
|
|
244
|
+
if (pending.size === 0) return line;
|
|
245
|
+
let frame;
|
|
246
|
+
try {
|
|
247
|
+
frame = JSON.parse(line);
|
|
248
|
+
} catch {
|
|
249
|
+
return line;
|
|
250
|
+
}
|
|
251
|
+
if (!isObject(frame) || "method" in frame || !pending.delete(idKey(frame.id))) return line;
|
|
252
|
+
if (!isObject(frame.result) || !Array.isArray(frame.result.tools)) return line;
|
|
253
|
+
let changed = false;
|
|
254
|
+
const tools = frame.result.tools.map((tool) => {
|
|
255
|
+
if (!isObject(tool)) return tool;
|
|
256
|
+
const inputSchema = providerSafeInputSchema(tool.inputSchema);
|
|
257
|
+
if (inputSchema === tool.inputSchema) return tool;
|
|
258
|
+
changed = true;
|
|
259
|
+
return { ...tool, inputSchema };
|
|
260
|
+
});
|
|
261
|
+
return changed ? JSON.stringify({ ...frame, result: { ...frame.result, tools } }) : line;
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
}
|
|
265
|
+
|
|
186
266
|
// server/mcp-bridge.ts
|
|
187
267
|
var BRIDGE_INACTIVITY_MS = 45e3;
|
|
188
268
|
var PROBE_TIMEOUT_MS = 1e4;
|
|
@@ -352,8 +432,10 @@ function runMcpBridge(options) {
|
|
|
352
432
|
}
|
|
353
433
|
} : {}
|
|
354
434
|
});
|
|
435
|
+
const toolLists = createToolListNormalizer();
|
|
355
436
|
let pendingInput = Promise.resolve();
|
|
356
437
|
const inbound = createLineSplitter((line) => {
|
|
438
|
+
toolLists.observeRequest(line);
|
|
357
439
|
const completion = intercept(line);
|
|
358
440
|
if (completion) pendingInput = completion;
|
|
359
441
|
});
|
|
@@ -363,7 +445,7 @@ function runMcpBridge(options) {
|
|
|
363
445
|
inbound.flush();
|
|
364
446
|
void pendingInput.finally(() => child.stdin.end());
|
|
365
447
|
});
|
|
366
|
-
const outbound = createLineSplitter((line) => process.stdout.write(line + "\n"));
|
|
448
|
+
const outbound = createLineSplitter((line) => process.stdout.write(toolLists.rewriteResponse(line) + "\n"));
|
|
367
449
|
child.stdout.on("data", (chunk) => outbound.push(chunk));
|
|
368
450
|
child.stdout.on("end", () => outbound.flush());
|
|
369
451
|
const detach = () => {
|
|
@@ -1056,7 +1138,7 @@ __export(util_exports, {
|
|
|
1056
1138
|
getParsedType: () => getParsedType,
|
|
1057
1139
|
getSizableOrigin: () => getSizableOrigin,
|
|
1058
1140
|
hexToUint8Array: () => hexToUint8Array,
|
|
1059
|
-
isObject: () =>
|
|
1141
|
+
isObject: () => isObject2,
|
|
1060
1142
|
isPlainObject: () => isPlainObject,
|
|
1061
1143
|
issue: () => issue,
|
|
1062
1144
|
joinValues: () => joinValues,
|
|
@@ -1219,7 +1301,7 @@ function slugify(input) {
|
|
|
1219
1301
|
}
|
|
1220
1302
|
var captureStackTrace = "captureStackTrace" in Error ? Error.captureStackTrace : (..._args) => {
|
|
1221
1303
|
};
|
|
1222
|
-
function
|
|
1304
|
+
function isObject2(data) {
|
|
1223
1305
|
return typeof data === "object" && data !== null && !Array.isArray(data);
|
|
1224
1306
|
}
|
|
1225
1307
|
var allowsEval = /* @__PURE__ */ cached2(() => {
|
|
@@ -1238,7 +1320,7 @@ var allowsEval = /* @__PURE__ */ cached2(() => {
|
|
|
1238
1320
|
}
|
|
1239
1321
|
});
|
|
1240
1322
|
function isPlainObject(o) {
|
|
1241
|
-
if (
|
|
1323
|
+
if (isObject2(o) === false)
|
|
1242
1324
|
return false;
|
|
1243
1325
|
const ctor = o.constructor;
|
|
1244
1326
|
if (ctor === void 0)
|
|
@@ -1246,7 +1328,7 @@ function isPlainObject(o) {
|
|
|
1246
1328
|
if (typeof ctor !== "function")
|
|
1247
1329
|
return true;
|
|
1248
1330
|
const prot = ctor.prototype;
|
|
1249
|
-
if (
|
|
1331
|
+
if (isObject2(prot) === false)
|
|
1250
1332
|
return false;
|
|
1251
1333
|
if (Object.prototype.hasOwnProperty.call(prot, "isPrototypeOf") === false) {
|
|
1252
1334
|
return false;
|
|
@@ -3459,13 +3541,13 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
|
|
|
3459
3541
|
}
|
|
3460
3542
|
return propValues;
|
|
3461
3543
|
});
|
|
3462
|
-
const
|
|
3544
|
+
const isObject3 = isObject2;
|
|
3463
3545
|
const catchall = def.catchall;
|
|
3464
3546
|
let value;
|
|
3465
3547
|
inst._zod.parse = (payload, ctx) => {
|
|
3466
3548
|
value ?? (value = _normalized.value);
|
|
3467
3549
|
const input = payload.value;
|
|
3468
|
-
if (!
|
|
3550
|
+
if (!isObject3(input)) {
|
|
3469
3551
|
payload.issues.push({
|
|
3470
3552
|
expected: "object",
|
|
3471
3553
|
code: "invalid_type",
|
|
@@ -3592,7 +3674,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
|
|
|
3592
3674
|
return (payload, ctx) => fn(shape, payload, ctx);
|
|
3593
3675
|
};
|
|
3594
3676
|
let fastpass;
|
|
3595
|
-
const
|
|
3677
|
+
const isObject3 = isObject2;
|
|
3596
3678
|
const jit = !globalConfig.jitless;
|
|
3597
3679
|
const allowsEval2 = allowsEval;
|
|
3598
3680
|
const fastEnabled = jit && allowsEval2.value;
|
|
@@ -3601,7 +3683,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
|
|
|
3601
3683
|
inst._zod.parse = (payload, ctx) => {
|
|
3602
3684
|
value ?? (value = _normalized.value);
|
|
3603
3685
|
const input = payload.value;
|
|
3604
|
-
if (!
|
|
3686
|
+
if (!isObject3(input)) {
|
|
3605
3687
|
payload.issues.push({
|
|
3606
3688
|
expected: "object",
|
|
3607
3689
|
code: "invalid_type",
|
|
@@ -3777,7 +3859,7 @@ var $ZodDiscriminatedUnion = /* @__PURE__ */ $constructor("$ZodDiscriminatedUnio
|
|
|
3777
3859
|
});
|
|
3778
3860
|
inst._zod.parse = (payload, ctx) => {
|
|
3779
3861
|
const input = payload.value;
|
|
3780
|
-
if (!
|
|
3862
|
+
if (!isObject2(input)) {
|
|
3781
3863
|
payload.issues.push({
|
|
3782
3864
|
code: "invalid_type",
|
|
3783
3865
|
expected: "object",
|
|
@@ -14962,6 +15044,97 @@ function isModelVariant(value) {
|
|
|
14962
15044
|
return typeof value === "string" && value.length > 0 && value.length <= 256 && value.trim() === value && !new RegExp("\\p{Cc}", "u").test(value);
|
|
14963
15045
|
}
|
|
14964
15046
|
|
|
15047
|
+
// shared/provider-icon.ts
|
|
15048
|
+
var PROVIDER_ICON_PRESETS = [
|
|
15049
|
+
"openai",
|
|
15050
|
+
"anthropic",
|
|
15051
|
+
"google",
|
|
15052
|
+
"azure",
|
|
15053
|
+
"aws",
|
|
15054
|
+
"xai",
|
|
15055
|
+
"deepseek",
|
|
15056
|
+
"meta",
|
|
15057
|
+
"mistral",
|
|
15058
|
+
"qwen",
|
|
15059
|
+
"moonshot",
|
|
15060
|
+
"cohere",
|
|
15061
|
+
"openrouter"
|
|
15062
|
+
];
|
|
15063
|
+
var PROVIDER_ICON_MAX_BYTES = 128 * 1024;
|
|
15064
|
+
var PROVIDER_ICON_MAX_DIMENSION = 1024;
|
|
15065
|
+
function decodedBase64Bytes(value) {
|
|
15066
|
+
const padding = value.endsWith("==") ? 2 : value.endsWith("=") ? 1 : 0;
|
|
15067
|
+
return Math.floor(value.length * 3 / 4) - padding;
|
|
15068
|
+
}
|
|
15069
|
+
function imageDimensions(bytes, mime) {
|
|
15070
|
+
const u16be = (offset) => bytes[offset] * 256 + bytes[offset + 1];
|
|
15071
|
+
const u16le = (offset) => bytes[offset] + bytes[offset + 1] * 256;
|
|
15072
|
+
const u24le = (offset) => bytes[offset] + bytes[offset + 1] * 256 + bytes[offset + 2] * 65536;
|
|
15073
|
+
const u32le = (offset) => bytes[offset] + bytes[offset + 1] * 256 + bytes[offset + 2] * 65536 + bytes[offset + 3] * 16777216;
|
|
15074
|
+
const u32be = (offset) => bytes[offset] * 16777216 + bytes[offset + 1] * 65536 + bytes[offset + 2] * 256 + bytes[offset + 3];
|
|
15075
|
+
if (mime === "image/png") {
|
|
15076
|
+
if (bytes.length < 33 || bytes.slice(0, 8).join(",") !== "137,80,78,71,13,10,26,10" || String.fromCharCode(...bytes.slice(12, 16)) !== "IHDR" || bytes.slice(-8).join(",") !== "73,69,78,68,174,66,96,130") return null;
|
|
15077
|
+
return { width: u32be(16), height: u32be(20) };
|
|
15078
|
+
}
|
|
15079
|
+
if (mime === "image/jpeg") {
|
|
15080
|
+
if (bytes.length < 12 || bytes[0] !== 255 || bytes[1] !== 216 || bytes.at(-2) !== 255 || bytes.at(-1) !== 217) return null;
|
|
15081
|
+
for (let offset = 2; offset + 8 < bytes.length; ) {
|
|
15082
|
+
if (bytes[offset] !== 255) {
|
|
15083
|
+
offset += 1;
|
|
15084
|
+
continue;
|
|
15085
|
+
}
|
|
15086
|
+
const marker = bytes[offset + 1];
|
|
15087
|
+
if ([192, 193, 194, 195, 197, 198, 199, 201, 202, 203, 205, 206, 207].includes(marker)) {
|
|
15088
|
+
return { height: u16be(offset + 5), width: u16be(offset + 7) };
|
|
15089
|
+
}
|
|
15090
|
+
if (marker === 216 || marker === 217 || marker === 1 || marker >= 208 && marker <= 215) {
|
|
15091
|
+
offset += 2;
|
|
15092
|
+
continue;
|
|
15093
|
+
}
|
|
15094
|
+
const length = u16be(offset + 2);
|
|
15095
|
+
if (length < 2) return null;
|
|
15096
|
+
offset += length + 2;
|
|
15097
|
+
}
|
|
15098
|
+
return null;
|
|
15099
|
+
}
|
|
15100
|
+
if (bytes.length < 30 || String.fromCharCode(...bytes.slice(0, 4)) !== "RIFF" || String.fromCharCode(...bytes.slice(8, 12)) !== "WEBP" || u32le(4) + 8 !== bytes.length) return null;
|
|
15101
|
+
const format = String.fromCharCode(...bytes.slice(12, 16));
|
|
15102
|
+
if (format === "VP8X") return { width: u24le(24) + 1, height: u24le(27) + 1 };
|
|
15103
|
+
if (format === "VP8L" && bytes[20] === 47) {
|
|
15104
|
+
const bits = bytes[21] | bytes[22] << 8 | bytes[23] << 16 | bytes[24] << 24;
|
|
15105
|
+
return { width: (bits & 16383) + 1, height: (bits >>> 14 & 16383) + 1 };
|
|
15106
|
+
}
|
|
15107
|
+
if (format === "VP8 " && bytes[23] === 157 && bytes[24] === 1 && bytes[25] === 42) {
|
|
15108
|
+
return { width: u16le(26) & 16383, height: u16le(28) & 16383 };
|
|
15109
|
+
}
|
|
15110
|
+
return null;
|
|
15111
|
+
}
|
|
15112
|
+
function providerIconError(icon) {
|
|
15113
|
+
if (icon.kind === "preset") {
|
|
15114
|
+
return PROVIDER_ICON_PRESETS.includes(icon.preset) ? null : "Choose a supported provider icon.";
|
|
15115
|
+
}
|
|
15116
|
+
const match = /^data:(image\/(?:png|jpeg|webp));base64,([A-Za-z0-9+/]+={0,2})$/.exec(icon.dataUrl);
|
|
15117
|
+
if (!match) return "Upload a PNG, JPEG, or WebP image.";
|
|
15118
|
+
const byteLength = decodedBase64Bytes(match[2]);
|
|
15119
|
+
if (byteLength > PROVIDER_ICON_MAX_BYTES) {
|
|
15120
|
+
return "Provider icons must be 128 KB or smaller.";
|
|
15121
|
+
}
|
|
15122
|
+
let decoded;
|
|
15123
|
+
try {
|
|
15124
|
+
decoded = atob(match[2]);
|
|
15125
|
+
} catch {
|
|
15126
|
+
return "The uploaded image is not valid base64.";
|
|
15127
|
+
}
|
|
15128
|
+
if (decoded.length !== byteLength) return "The uploaded image is not valid base64.";
|
|
15129
|
+
const bytes = Uint8Array.from(decoded, (value) => value.charCodeAt(0));
|
|
15130
|
+
const dimensions = imageDimensions(bytes, match[1]);
|
|
15131
|
+
if (!dimensions) return "The uploaded image is incomplete or does not match its file type.";
|
|
15132
|
+
if (dimensions.width < 1 || dimensions.height < 1 || dimensions.width > PROVIDER_ICON_MAX_DIMENSION || dimensions.height > PROVIDER_ICON_MAX_DIMENSION || dimensions.width * dimensions.height > PROVIDER_ICON_MAX_DIMENSION ** 2) {
|
|
15133
|
+
return `Provider icons must be at most ${PROVIDER_ICON_MAX_DIMENSION} \xD7 ${PROVIDER_ICON_MAX_DIMENSION} pixels.`;
|
|
15134
|
+
}
|
|
15135
|
+
return null;
|
|
15136
|
+
}
|
|
15137
|
+
|
|
14965
15138
|
// server/mcp-registry.ts
|
|
14966
15139
|
var MAX_ARGS = 64;
|
|
14967
15140
|
var stdioEntrySchema = external_exports.object({
|
|
@@ -15002,11 +15175,26 @@ var MAX_LOCAL_VM_MAX_INSTANCES = 4;
|
|
|
15002
15175
|
function isValidSshAlias(value) {
|
|
15003
15176
|
return typeof value === "string" && SSH_ALIAS.test(value);
|
|
15004
15177
|
}
|
|
15178
|
+
var CDP_PORT = /^[0-9]{1,5}$/;
|
|
15179
|
+
var CDP_URL = /^(https?|wss?):\/\/\S+$/i;
|
|
15180
|
+
function isValidCdpTarget(value) {
|
|
15181
|
+
if (typeof value !== "string" || value === "") return false;
|
|
15182
|
+
if (CDP_PORT.test(value)) {
|
|
15183
|
+
const port = Number(value);
|
|
15184
|
+
return port >= 1 && port <= 65535;
|
|
15185
|
+
}
|
|
15186
|
+
return CDP_URL.test(value);
|
|
15187
|
+
}
|
|
15005
15188
|
var vpsConfigSchema = external_exports.object({
|
|
15006
15189
|
sshAlias: external_exports.string().refine((value) => value === "" || isValidSshAlias(value), {
|
|
15007
15190
|
message: "must be a simple SSH config alias"
|
|
15008
15191
|
}).optional()
|
|
15009
15192
|
});
|
|
15193
|
+
var browserEngineConfigSchema = external_exports.object({
|
|
15194
|
+
attachCdpUrl: external_exports.string().trim().max(2048).refine((value) => value === "" || isValidCdpTarget(value), {
|
|
15195
|
+
message: "browserEngine.attachCdpUrl must be a CDP port (1-65535) or an http(s)/ws(s) URL"
|
|
15196
|
+
}).optional()
|
|
15197
|
+
});
|
|
15010
15198
|
var roomConfigSchema = external_exports.object({
|
|
15011
15199
|
turnTimeoutMinutes: external_exports.number().int().min(MIN_ROOM_TURN_TIMEOUT_MINUTES).max(MAX_ROOM_TURN_TIMEOUT_MINUTES),
|
|
15012
15200
|
/** Room handoff tree lifetime. Active execution pauses this clock; the
|
|
@@ -15148,7 +15336,11 @@ var featureConfigSchema = external_exports.object({
|
|
|
15148
15336
|
/** Claude bots also load the MCP servers and connectors from this
|
|
15149
15337
|
* machine's own Claude Code setup (Plugins → MCP servers switch). Off by
|
|
15150
15338
|
* default: each extra tool costs tokens on every model call. */
|
|
15151
|
-
claudeUserMcp: external_exports.boolean().optional()
|
|
15339
|
+
claudeUserMcp: external_exports.boolean().optional(),
|
|
15340
|
+
/** LLM-generated titles for new bot threads. Off until explicitly
|
|
15341
|
+
* enabled; a one-shot that fails or answers junk leaves the first-message
|
|
15342
|
+
* snippet in place — see llmThreadTitlesEnabled. */
|
|
15343
|
+
llmThreadTitles: external_exports.boolean().optional()
|
|
15152
15344
|
});
|
|
15153
15345
|
var onboardingConfigSchema = external_exports.object({
|
|
15154
15346
|
/** ISO timestamp of finishing (or skipping to the end of) the welcome flow. */
|
|
@@ -15162,6 +15354,10 @@ var instanceConfigSchema = external_exports.object({
|
|
|
15162
15354
|
driver: external_exports.string().min(1),
|
|
15163
15355
|
displayName: optionalText,
|
|
15164
15356
|
accentColor: optionalText,
|
|
15357
|
+
icon: external_exports.discriminatedUnion("kind", [
|
|
15358
|
+
external_exports.object({ kind: external_exports.literal("preset"), preset: external_exports.enum(PROVIDER_ICON_PRESETS) }).strict(),
|
|
15359
|
+
external_exports.object({ kind: external_exports.literal("custom"), dataUrl: external_exports.string() }).strict().refine((icon) => providerIconError(icon) === null, { message: "Invalid provider icon" })
|
|
15360
|
+
]).optional(),
|
|
15165
15361
|
environment: external_exports.record(external_exports.string(), external_exports.string()).optional(),
|
|
15166
15362
|
enabled: external_exports.boolean().optional(),
|
|
15167
15363
|
config: external_exports.json().optional()
|
|
@@ -15176,6 +15372,20 @@ var defaultModelSelectionSchema = external_exports.object({
|
|
|
15176
15372
|
(selection) => selection.variant === void 0 || selection.effort === void 0,
|
|
15177
15373
|
"choose either a model variant or an effort level"
|
|
15178
15374
|
);
|
|
15375
|
+
var threadsConfigSchema = external_exports.object({
|
|
15376
|
+
maxConcurrentPerBot: external_exports.number().int().min(1).max(MAX_CONCURRENT_BOT_THREADS),
|
|
15377
|
+
/** Cap each per-thread events/ and native/ NDJSON log at this many
|
|
15378
|
+
* bytes; absent (the default) keeps today's unbounded growth (#1280). */
|
|
15379
|
+
eventLogMaxBytes: external_exports.number().int().min(MIN_THREAD_EVENT_LOG_BYTES).max(MAX_THREAD_EVENT_LOG_BYTES).optional(),
|
|
15380
|
+
/** Days a closed or archived thread's event logs survive (#1280).
|
|
15381
|
+
* Absent keeps them forever. */
|
|
15382
|
+
eventLogRetentionDays: external_exports.number().int().min(1).max(3650).optional()
|
|
15383
|
+
}).strict();
|
|
15384
|
+
var threadsPatchSchema = threadsConfigSchema.extend({
|
|
15385
|
+
maxConcurrentPerBot: threadsConfigSchema.shape.maxConcurrentPerBot.optional(),
|
|
15386
|
+
eventLogMaxBytes: threadsConfigSchema.shape.eventLogMaxBytes.nullable(),
|
|
15387
|
+
eventLogRetentionDays: threadsConfigSchema.shape.eventLogRetentionDays.nullable()
|
|
15388
|
+
});
|
|
15179
15389
|
var appConfigSchema = external_exports.object({
|
|
15180
15390
|
/** Verified by the dedicated domain endpoint, never a generic config patch. */
|
|
15181
15391
|
customDomain: external_exports.string().optional(),
|
|
@@ -15226,6 +15436,7 @@ var appConfigSchema = external_exports.object({
|
|
|
15226
15436
|
/** Voice settings and the selected voice id. `provider` picks the
|
|
15227
15437
|
* engine: "elevenlabs" (default; needs `key`), "fish" (needs its own
|
|
15228
15438
|
* `fishKey`), "system" (the Mac's built-in voices, no key), or
|
|
15439
|
+
* "xai" (Grok TTS, reusing `xai.key`), or
|
|
15229
15440
|
* "chatterbox" (a local OpenAI-compatible Chatterbox server; `baseUrl`
|
|
15230
15441
|
* and `model` are settings, not secrets). Cloud keys stay separate so
|
|
15231
15442
|
* switching providers never overwrites or misuses the other key. */
|
|
@@ -15233,7 +15444,7 @@ var appConfigSchema = external_exports.object({
|
|
|
15233
15444
|
key: optionalText,
|
|
15234
15445
|
fishKey: optionalText,
|
|
15235
15446
|
voice: optionalText,
|
|
15236
|
-
provider: external_exports.enum(["elevenlabs", "fish", "system", "chatterbox"]).optional(),
|
|
15447
|
+
provider: external_exports.enum(["elevenlabs", "fish", "system", "chatterbox", "xai"]).optional(),
|
|
15237
15448
|
baseUrl: external_exports.string().trim().max(2048).refine((value) => !value || /^https?:\/\//i.test(value), "the Chatterbox server address must start with http:// or https://").optional(),
|
|
15238
15449
|
model: optionalText
|
|
15239
15450
|
}).optional(),
|
|
@@ -15262,18 +15473,20 @@ var appConfigSchema = external_exports.object({
|
|
|
15262
15473
|
* system language. Unknown tags degrade to English in the renderer. */
|
|
15263
15474
|
language: optionalText,
|
|
15264
15475
|
rooms: roomConfigSchema.optional(),
|
|
15265
|
-
|
|
15266
|
-
|
|
15267
|
-
|
|
15268
|
-
|
|
15269
|
-
|
|
15270
|
-
|
|
15271
|
-
|
|
15272
|
-
|
|
15273
|
-
}).strict().optional(),
|
|
15476
|
+
context: external_exports.object({
|
|
15477
|
+
rebuildBytes: external_exports.number().int().min(1024).max(1e6).optional(),
|
|
15478
|
+
compactAt: external_exports.number().positive().max(1e7).optional(),
|
|
15479
|
+
autoCompact: external_exports.boolean().optional()
|
|
15480
|
+
}).optional(),
|
|
15481
|
+
threads: threadsConfigSchema.optional(),
|
|
15482
|
+
/** The authorization decision log (server/decision-log.ts): days of month
|
|
15483
|
+
* files kept, at least; OMB_DECISION_RETENTION_DAYS wins when set. */
|
|
15484
|
+
decisions: external_exports.object({ retentionDays: external_exports.number().int().min(1).max(3650).optional() }).strict().optional(),
|
|
15274
15485
|
localVm: localVmConfigSchema.optional(),
|
|
15275
15486
|
features: featureConfigSchema.optional(),
|
|
15276
15487
|
onboarding: onboardingConfigSchema.optional(),
|
|
15488
|
+
/** CDP attach target for a bot's browser; see browserEngineConfigSchema. */
|
|
15489
|
+
browserEngine: browserEngineConfigSchema.optional(),
|
|
15277
15490
|
browserProfiles: browserProfilesSchema.optional(),
|
|
15278
15491
|
instances: instanceConfigMapSchema.optional(),
|
|
15279
15492
|
/** User-configured MCP servers, mounted into every capable engine. Kept
|
|
@@ -15285,7 +15498,7 @@ var appConfigSchema = external_exports.object({
|
|
|
15285
15498
|
var storedAppConfigSchema = appConfigSchema.extend({
|
|
15286
15499
|
browserProfiles: storedBrowserProfilesSchema.optional()
|
|
15287
15500
|
});
|
|
15288
|
-
var appConfigPatchSchema = appConfigSchema.omit({ instances: true, mcpServers: true, cliStartup: true, customDomain: true });
|
|
15501
|
+
var appConfigPatchSchema = appConfigSchema.omit({ instances: true, mcpServers: true, cliStartup: true, customDomain: true }).extend({ threads: threadsPatchSchema.optional() });
|
|
15289
15502
|
var jsonObjectSchema = external_exports.record(external_exports.string(), external_exports.json());
|
|
15290
15503
|
var DATA_DIR = process.env.OMB_DATA_DIR ?? join2(homedir2(), ".openmausbot");
|
|
15291
15504
|
var LEGACY_DATA_DIR = join2(homedir2(), ".opengrokbot");
|
|
@@ -15312,6 +15525,7 @@ var SPAWNED_PROXIES = {
|
|
|
15312
15525
|
connectors: resolveProxy("connector-proxy"),
|
|
15313
15526
|
mcpGate: resolveProxy("mcp-gate"),
|
|
15314
15527
|
phone: resolveProxy("drivers/phone-proxy"),
|
|
15528
|
+
hook: resolveProxy("hooks/omb-hook"),
|
|
15315
15529
|
// Loaded by the external `pi` process via `-e`, not by this server — but
|
|
15316
15530
|
// resolved through the same single source of truth so the packaged layout
|
|
15317
15531
|
// check can assert it ships.
|
package/enterprise/README.md
CHANGED
|
@@ -5,24 +5,42 @@ folder has its own [LICENSE](./LICENSE); everything outside it is Apache 2.0.
|
|
|
5
5
|
|
|
6
6
|
**Delete this folder and you have the open-source edition.** Core only
|
|
7
7
|
reaches the layer through one hook point, `server/enterprise.ts`, which
|
|
8
|
-
loads `enterprise/server/index.ts`
|
|
9
|
-
open-source edition. No core file imports anything
|
|
8
|
+
loads `enterprise/server/index.ts` (or the bundled `index.js`) if it exists
|
|
9
|
+
and otherwise reports the open-source edition. No core file imports anything
|
|
10
|
+
from here.
|
|
11
|
+
|
|
12
|
+
Where core looks, in order: `OMB_ENTERPRISE_DIR` when it is set (and then
|
|
13
|
+
only there); otherwise beside the server root (a checkout's `enterprise/`,
|
|
14
|
+
the npm package's `<package>/enterprise/`), then inside it
|
|
15
|
+
(`dist-server/enterprise/`, which is all the Docker image and the packaged
|
|
16
|
+
desktop carry; `scripts/bundle-server.mjs` writes the bundled layer and this
|
|
17
|
+
LICENSE there).
|
|
10
18
|
|
|
11
19
|
## How a deployment turns enterprise
|
|
12
20
|
|
|
13
21
|
Set `OMB_LICENSE_KEY` on the server. The key is `omb1.<claims>.<signature>`:
|
|
14
22
|
the claims are visible JSON (who it is for, which entitlements, when it
|
|
15
23
|
expires), signed with an Ed25519 key whose public half is baked into
|
|
16
|
-
`server/license.ts`. Verification is offline, and one build serves
|
|
17
|
-
customer, because the key decides the feature set rather than the code.
|
|
24
|
+
`enterprise/server/license.ts`. Verification is offline, and one build serves
|
|
25
|
+
every customer, because the key decides the feature set rather than the code.
|
|
18
26
|
|
|
19
27
|
`GET /api/edition` reports the outcome:
|
|
20
28
|
|
|
21
29
|
```json
|
|
22
|
-
{ "edition": "enterprise", "customer": "Acme", "features": ["
|
|
23
|
-
{ "edition": "
|
|
30
|
+
{ "edition": "enterprise", "customer": "Acme", "features": ["budgets", "whitelabel"], "expiresAt": "2027-09-02", "expiresInDays": 12 }
|
|
31
|
+
{ "edition": "enterprise", "customer": "Acme", "features": ["budgets", "whitelabel"], "expiresAt": "2027-09-02", "expiresInDays": -2, "graceEndsAt": "2027-09-09", "notice": "OMB_LICENSE_KEY expired on 2027-09-02; enterprise features keep working until 2027-09-09 while it is renewed" }
|
|
32
|
+
{ "edition": "oss", "features": [], "notice": "enterprise layer disabled: OMB_LICENSE_KEY expired on 2027-09-02; renew it to keep enterprise features" }
|
|
24
33
|
```
|
|
25
34
|
|
|
35
|
+
`expiresInDays` is present whenever the key has an expiry; a non-admin
|
|
36
|
+
session's `/api/edition` leaves out `expiresInDays`, `graceEndsAt` and the
|
|
37
|
+
notice. From 30 days
|
|
38
|
+
before it, the server logs a warning at startup and admins see a banner in
|
|
39
|
+
Settings. After the expiry date the features keep working for a 7-day grace
|
|
40
|
+
period, with the notice above and a banner saying until when; then they stop,
|
|
41
|
+
without a restart. The key format and its signature check do not change: the
|
|
42
|
+
layer simply accepts a key that expired less than the grace period ago.
|
|
43
|
+
|
|
26
44
|
A missing, altered, or expired key does not stop an ordinary standalone
|
|
27
45
|
server: it runs the open-source edition and the notice says what to fix.
|
|
28
46
|
A workspace explicitly configured for hosted sign-in fails closed for remote
|
|
@@ -31,12 +49,15 @@ must not silently fall back to standalone email or pairing credentials.
|
|
|
31
49
|
|
|
32
50
|
## Entitlement ids
|
|
33
51
|
|
|
34
|
-
| id | grants |
|
|
35
|
-
|
|
36
|
-
| `whitelabel` | product name, tagline, accent colour, logo, favicon and support link from `brand.json` (below) |
|
|
37
|
-
| `sso` |
|
|
38
|
-
| `admin` | Settings → Workspaces and the optional hosted workspace sign-in adapter |
|
|
39
|
-
| `budgets` | per
|
|
52
|
+
| id | grants | status |
|
|
53
|
+
|---|---|---|
|
|
54
|
+
| `whitelabel` | product name, tagline, accent colour, logo, favicon and support link from `brand.json` (below) | shipped |
|
|
55
|
+
| `sso` | sign-in through a company identity provider | planned: nothing checks it yet |
|
|
56
|
+
| `admin` | Settings → Workspaces and the optional hosted workspace sign-in adapter | shipped |
|
|
57
|
+
| `budgets` | one monthly spend limit for the whole workspace, refusing new turns at the cap, with a warning percentage and admin notices (not per bot or per section) | shipped |
|
|
58
|
+
| `billing` | sell prices per model: a billable column in Usage → History and its CSV, and per-model prices that replace list prices in cost estimates | shipped |
|
|
59
|
+
|
|
60
|
+
[FEATURES](./FEATURES) is the authoritative list.
|
|
40
61
|
|
|
41
62
|
Core gates a feature with `entitled("id")` from `server/enterprise.ts`.
|
|
42
63
|
Unknown ids are carried in the key but grant nothing, so keys can be issued
|