openmausbot 0.1.86 → 0.1.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -3
- package/dist/assets/{abnfDiagram-O67JEVCF-DpUZNnFD.js → abnfDiagram-O67JEVCF-qd9VD3GV.js} +1 -1
- package/dist/assets/{arc-DW7mrI4p.js → arc-3RwkUjRe.js} +1 -1
- package/dist/assets/{architectureDiagram-NJMV4G6O-CyeZ5WLZ.js → architectureDiagram-NJMV4G6O-CFKSJS7a.js} +1 -1
- package/dist/assets/{blockDiagram-BEXU5L5S-CBVaNjO7.js → blockDiagram-BEXU5L5S-CG1rEfWD.js} +1 -1
- package/dist/assets/{c4Diagram-YGBWAQC7-sf8d41uT.js → c4Diagram-YGBWAQC7-CBW9N664.js} +1 -1
- package/dist/assets/channel-CnRnO3tF.js +1 -0
- package/dist/assets/{chunk-2Q5K7J3B-BOGvy7Y_.js → chunk-2Q5K7J3B-2mRfTksB.js} +1 -1
- package/dist/assets/{chunk-3FUC2YCW-BiF9zyiz.js → chunk-3FUC2YCW-Cv1dpErj.js} +2 -2
- package/dist/assets/{chunk-5VM5RSS4-EFuZ1SBZ.js → chunk-5VM5RSS4-B7IACJp-.js} +1 -1
- package/dist/assets/{chunk-GTNCS2PH-pJLNSAT7.js → chunk-GTNCS2PH-An0hZtYa.js} +1 -1
- package/dist/assets/{chunk-GWA4HPMP-Cb-3_3IT.js → chunk-GWA4HPMP-BcJB2nEm.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-DAf5aogn.js → chunk-JWPE2WC7-CV_W7TN7.js} +1 -1
- package/dist/assets/{chunk-NETBCI7D-DR3kiwZz.js → chunk-NETBCI7D-Bcs_kwnA.js} +1 -1
- package/dist/assets/{chunk-WEXAMYUT-BmU8PeyM.js → chunk-WEXAMYUT-lrx_DxFP.js} +1 -1
- package/dist/assets/{chunk-XXDRQBXY-Buh8g8OT.js → chunk-XXDRQBXY-DabHlLGM.js} +1 -1
- package/dist/assets/{classDiagram-v2-NBCMYWYE-BurfmMWM.js → classDiagram-v2-NBCMYWYE-BnHj6P7d.js} +1 -1
- package/dist/assets/{cose-bilkent-JH36ORCC-KkGZUEkU.js → cose-bilkent-JH36ORCC-CfLp6UDi.js} +1 -1
- package/dist/assets/{cynefin-OW5HDTMX-C3PpV96d.js → cynefin-OW5HDTMX-Dm4dbVA1.js} +1 -1
- package/dist/assets/{cynefinDiagram-VND7K2PF-Dt8JwJaI.js → cynefinDiagram-VND7K2PF-B9mH-PID.js} +1 -1
- package/dist/assets/{dagre-6A5THRUB-DkjN8266.js → dagre-6A5THRUB-DDc_NVQJ.js} +1 -1
- package/dist/assets/{diagram-22UHCM2B-DUAJS0JV.js → diagram-22UHCM2B-lwr8Ip8-.js} +1 -1
- package/dist/assets/{diagram-3UASUU5V-Dw4KhF1a.js → diagram-3UASUU5V-BLLe6dmI.js} +1 -1
- package/dist/assets/{diagram-ATOU4E4O-Dd1gmQqf.js → diagram-ATOU4E4O-6eUIq4lz.js} +1 -1
- package/dist/assets/{diagram-CDSNMT55-CjwGs0Yw.js → diagram-CDSNMT55-O-pRN7VQ.js} +1 -1
- package/dist/assets/{diagram-MLGK6HIB-BL-69Zrq.js → diagram-MLGK6HIB-BietvGAI.js} +1 -1
- package/dist/assets/{diagram-MPIPVDR6-5Zi2N7wo.js → diagram-MPIPVDR6-Bd2Cl62X.js} +1 -1
- package/dist/assets/{ebnfDiagram-ZINNZB2B-D9NekWUX.js → ebnfDiagram-ZINNZB2B-B6iDy69W.js} +1 -1
- package/dist/assets/{elk-276RUBZZ-CkaSQjxw.js → elk-276RUBZZ-DQVHfKe0.js} +1 -1
- package/dist/assets/{erDiagram-OPXOYQCR-CdAVBV8-.js → erDiagram-OPXOYQCR-BWdVp2tQ.js} +1 -1
- package/dist/assets/{flowDiagram-KWPJA3E3-Bm_lWWH7.js → flowDiagram-KWPJA3E3-WLE6rKB4.js} +1 -1
- package/dist/assets/{ganttDiagram-FUAMR5RP-FZ8ejYWJ.js → ganttDiagram-FUAMR5RP-BbjS-4gn.js} +1 -1
- package/dist/assets/{gitGraphDiagram-X574FWY7-Dlv9rizZ.js → gitGraphDiagram-X574FWY7-Dpy2QSGq.js} +1 -1
- package/dist/assets/index-BIMdIbaw.css +1 -0
- package/dist/assets/index-CHnODCr2.js +583 -0
- package/dist/assets/{index-h9FFNwTu.js → index-CIaHn5NS.js} +1 -1
- package/dist/assets/{infoDiagram-VRGFBTTK-BdQ_gW5B.js → infoDiagram-VRGFBTTK-D_jKWlKe.js} +1 -1
- package/dist/assets/{ishikawaDiagram-OU5B5YK6-EwssEp2X.js → ishikawaDiagram-OU5B5YK6-DLJohSuK.js} +1 -1
- package/dist/assets/{journeyDiagram-ZHPQQLJL-BX1G1vOd.js → journeyDiagram-ZHPQQLJL-DPOFj0qN.js} +1 -1
- package/dist/assets/{kanban-definition-PNTS6WVX-BB4kAsyC.js → kanban-definition-PNTS6WVX-BI7v-xpK.js} +1 -1
- package/dist/assets/{linear-3su2TG93.js → linear-C2pWPSxO.js} +1 -1
- package/dist/assets/{mermaid.core-CDD1E0s9.js → mermaid.core-CR-j5WQU.js} +5 -5
- package/dist/assets/{mindmap-definition-NLK3R4M7-Ba50MsNK.js → mindmap-definition-NLK3R4M7-lz9GvXRh.js} +1 -1
- package/dist/assets/{pegDiagram-GJSIUBJH-DZLkkZlM.js → pegDiagram-GJSIUBJH-Dl4_ia61.js} +1 -1
- package/dist/assets/{pieDiagram-5QR66LMP-DaTz77Uq.js → pieDiagram-5QR66LMP-DWuT3n88.js} +1 -1
- package/dist/assets/{quadrantDiagram-O4NWA36T-CpaiidpR.js → quadrantDiagram-O4NWA36T-DXWe9Jx7.js} +1 -1
- package/dist/assets/{railroadDiagram-XR7U4H2S-mN4JrMeI.js → railroadDiagram-XR7U4H2S-COY1IBVY.js} +1 -1
- package/dist/assets/{requirementDiagram-PLB6GJNP-BSNDRpg7.js → requirementDiagram-PLB6GJNP-DnyVuhsQ.js} +1 -1
- package/dist/assets/{sankeyDiagram-IPEJSGJF-FngzGNug.js → sankeyDiagram-IPEJSGJF-BSc4NdGK.js} +1 -1
- package/dist/assets/{sequenceDiagram-PO4LG4MO-CM4pCC3L.js → sequenceDiagram-PO4LG4MO-kqEU2EGq.js} +1 -1
- package/dist/assets/{sizeCapture-INFHLROL-CRICHXkw.js → sizeCapture-INFHLROL-BvB4bkWD.js} +1 -1
- package/dist/assets/{stateDiagram-v2-GCMORJYK-oyTWpxH2.js → stateDiagram-v2-GCMORJYK-BIrqNv7y.js} +1 -1
- package/dist/assets/{swimlanes-2SLR337P-D9h9mPBq.js → swimlanes-2SLR337P-CFnalQUE.js} +1 -1
- package/dist/assets/swimlanesDiagram-TC7HE7FX-C4a8qNGj.js +8 -0
- package/dist/assets/{timeline-definition-EJHVYXUP-BJUlN9bW.js → timeline-definition-EJHVYXUP-CsSWJnSQ.js} +1 -1
- package/dist/assets/{usecaseDiagram-POWQR4AR-3uBNkbAb.js → usecaseDiagram-POWQR4AR-DkAmJ1EE.js} +1 -1
- package/dist/assets/{vennDiagram-UO4OBE2U-D2odalzT.js → vennDiagram-UO4OBE2U-C3vd9drL.js} +1 -1
- package/dist/assets/{wardleyDiagram-VNRHLVJA-DHgFaB9S.js → wardleyDiagram-VNRHLVJA-j26CM-pi.js} +1 -1
- package/dist/assets/{xychartDiagram-PMCCYNJV-w5GYM2h0.js → xychartDiagram-PMCCYNJV-BYu1Q_at.js} +1 -1
- package/dist/index.html +2 -2
- package/dist-server/browser-proxy.js +2 -1
- package/dist-server/companion/src/routes.js +8 -1
- package/dist-server/connector-proxy.js +105 -1
- package/dist-server/container-mcp.js +1032 -165
- package/dist-server/drivers/agents-proxy.js +338 -29
- package/dist-server/drivers/phone-proxy.js +33 -2
- package/dist-server/index.js +40590 -31811
- package/dist-server/local-computer-proxy.js +5 -3
- package/dist-server/local-computer.js +53 -17
- package/dist-server/mcp-gate.js +2 -0
- package/dist-server/mcp-server.js +5 -3
- package/dist-server/message-search.worker.js +52 -0
- package/dist-server/openmausbot.js +4457 -1399
- package/dist-server/pair-cli.js +4457 -1399
- package/dist-server/permission-proxy.js +29 -9
- package/dist-server/server/admission.js +81 -0
- package/dist-server/server/aside-queue.js +294 -0
- package/dist-server/server/attachments.js +98 -1
- package/dist-server/server/auto-approve.js +4 -3
- package/dist-server/server/auto-vm-claims.js +1 -0
- package/dist-server/server/bot-attachment.js +107 -0
- package/dist-server/server/bot-overview.js +19 -0
- package/dist-server/server/bot-package.js +18 -292
- package/dist-server/server/bot-profile.js +5 -17
- package/dist-server/server/box-create-idempotency.js +3 -3
- package/dist-server/server/box.js +57 -55
- package/dist-server/server/browser-proxy.js +3 -2
- package/dist-server/server/browser-runtime.js +37 -1
- package/dist-server/server/cli-api-setup.js +1 -0
- package/dist-server/server/cli.js +2 -2
- package/dist-server/server/command-allowlist.js +154 -0
- package/dist-server/server/composio.js +297 -1
- package/dist-server/server/computer-wait.js +22 -9
- package/dist-server/server/config.js +84 -12
- package/dist-server/server/connector-advertisement.js +165 -0
- package/dist-server/server/connector-proxy.js +14 -2
- package/dist-server/server/connector-verdict.js +168 -0
- package/dist-server/server/container-computer.js +61 -1
- package/dist-server/server/contracts.js +22 -0
- package/dist-server/server/default-model-selection.js +9 -0
- package/dist-server/server/delegations.js +85 -34
- package/dist-server/server/drivers/acp/core.js +80 -20
- package/dist-server/server/drivers/acp/cursor.js +3 -7
- package/dist-server/server/drivers/acp/droid.js +4 -7
- package/dist-server/server/drivers/acp/gemini.js +4 -4
- package/dist-server/server/drivers/acp/grok.js +4 -9
- package/dist-server/server/drivers/acp/hermes.js +3 -5
- package/dist-server/server/drivers/acp/opencode-go.js +2 -5
- package/dist-server/server/drivers/acp/qwen.js +9 -15
- package/dist-server/server/drivers/agents-call.js +179 -13
- package/dist-server/server/drivers/agents-catalog.js +134 -10
- package/dist-server/server/drivers/boxagent.js +160 -36
- package/dist-server/server/drivers/builtIn.js +2 -0
- package/dist-server/server/drivers/chat-box-tools.js +90 -0
- package/dist-server/server/drivers/chat-images.js +54 -0
- package/dist-server/server/drivers/chat-mcp-tools.js +38 -8
- package/dist-server/server/drivers/chat-tool-approval.js +70 -18
- package/dist-server/server/drivers/claude.js +38 -19
- package/dist-server/server/drivers/codex-catalog.js +14 -6
- package/dist-server/server/drivers/codex-identity.js +2 -1
- package/dist-server/server/drivers/codex-instructions.js +48 -6
- package/dist-server/server/drivers/codex-release.js +48 -0
- package/dist-server/server/drivers/codex-tool-surface.js +20 -0
- package/dist-server/server/drivers/codex.js +102 -55
- package/dist-server/server/drivers/mistral.js +115 -0
- package/dist-server/server/drivers/openai-chat.js +180 -33
- package/dist-server/server/drivers/openai-compat.js +1 -0
- package/dist-server/server/drivers/permission-command.js +35 -0
- package/dist-server/server/drivers/phone-proxy.js +47 -2
- package/dist-server/server/drivers/pi.js +306 -28
- package/dist-server/server/drivers/prompt-split.js +110 -0
- package/dist-server/server/drivers/session-idle.js +29 -0
- package/dist-server/server/env-path.js +15 -0
- package/dist-server/server/fleet.js +1 -1
- package/dist-server/server/group-thread-usage.js +103 -0
- package/dist-server/server/guarded-requests.js +2 -2
- package/dist-server/server/harness/registry.js +1 -0
- package/dist-server/server/harness-capabilities.js +46 -0
- package/dist-server/server/hosted-models.js +1 -1
- package/dist-server/server/index.js +2396 -505
- package/dist-server/server/local-computer.js +72 -23
- package/dist-server/server/managed-desktop.js +1 -1
- package/dist-server/server/mcp-bridge.js +6 -6
- package/dist-server/server/message-db.js +22 -42
- package/dist-server/server/message-file.js +9 -1
- package/dist-server/server/message-search-query.js +43 -0
- package/dist-server/server/message-search-worker.js +80 -0
- package/dist-server/server/message-search.worker.js +21 -0
- package/dist-server/server/model-requests.js +248 -0
- package/dist-server/server/new-bot-defaults.js +115 -0
- package/dist-server/server/options-card.js +21 -0
- package/dist-server/server/org-library.js +1065 -0
- package/dist-server/server/package-export.js +627 -39
- package/dist-server/server/package-import.js +458 -0
- package/dist-server/server/package-parts.js +87 -0
- package/dist-server/server/peer-approval.js +16 -7
- package/dist-server/server/peer-delivery.js +60 -0
- package/dist-server/server/peer-roster.js +67 -0
- package/dist-server/server/presets.js +492 -0
- package/dist-server/server/profile-requests.js +66 -39
- package/dist-server/server/profile-revision.js +9 -1
- package/dist-server/server/profile-versions.js +6 -3
- package/dist-server/server/provider-key-check.js +3 -2
- package/dist-server/server/published-teams.js +80 -0
- package/dist-server/server/room-handoffs.js +19 -3
- package/dist-server/server/routes/bot-presets.js +25 -0
- package/dist-server/server/routine-requests.js +35 -10
- package/dist-server/server/routines.js +41 -1
- package/dist-server/server/section-context.js +10 -0
- package/dist-server/server/skill-fetch.js +72 -14
- package/dist-server/server/skills.js +35 -61
- package/dist-server/server/steer-queue.js +3 -2
- package/dist-server/server/store.js +291 -17
- package/dist-server/server/surface.js +10 -4
- package/dist-server/server/system-prompt.js +38 -6
- package/dist-server/server/team-backup.js +6 -2
- package/dist-server/server/team-computers.js +10 -0
- package/dist-server/server/team-library.js +6 -2
- package/dist-server/server/team-manifest.js +4 -3
- package/dist-server/server/team-setup-requests.js +139 -27
- package/dist-server/server/thread-events.js +20 -2
- package/dist-server/server/tightening-requests.js +405 -0
- package/dist-server/server/tts/chatterbox.js +27 -5
- package/dist-server/server/turn-context.js +2 -0
- package/dist-server/server/turn-watchdog.js +12 -3
- package/dist-server/server/usage-ledger.js +19 -2
- package/dist-server/server/vps-computer.js +139 -51
- package/dist-server/server/vps-container-mcp.js +7 -0
- package/dist-server/server/vps-ssh.js +36 -7
- package/dist-server/server/workspace-backup-policy.js +12 -0
- package/dist-server/server/workspace-backup.js +42 -5
- package/dist-server/server/workspace-backup.worker.js +10 -0
- package/dist-server/server/workspace.js +1 -1
- package/dist-server/shared/approval-mode.js +1 -1
- package/dist-server/shared/ask-question.js +207 -12
- package/dist-server/shared/bot-profile.js +15 -0
- package/dist-server/shared/command-allowlist.js +1 -0
- package/dist-server/shared/credential-request.js +6 -2
- package/dist-server/shared/line-diff.js +23 -0
- package/dist-server/shared/model-request.js +1 -0
- package/dist-server/shared/options-card.js +51 -0
- package/dist-server/shared/package-format.js +967 -0
- package/dist-server/shared/profile-request.js +5 -4
- package/dist-server/shared/skill-md.js +64 -0
- package/dist-server/shared/team-backup.js +7 -0
- package/dist-server/shared/tightening-request.js +87 -0
- package/dist-server/shared/wire.js +4 -0
- package/dist-server/src/lib/composer-attachments.js +25 -3
- package/dist-server/vps-container-mcp.js +1132 -171
- package/dist-server/workspace-backup.worker.js +19474 -0
- package/enterprise/README.md +1 -1
- package/package.json +1 -1
- package/dist/assets/channel-BXFkgus9.js +0 -1
- package/dist/assets/index-BGgqlWPJ.css +0 -1
- package/dist/assets/index-BtHo8ZKl.js +0 -577
- package/dist/assets/swimlanesDiagram-TC7HE7FX-BWrvB2ak.js +0 -8
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* Durable payload carried by a profile confirmation card (propose_profile).
|
|
3
3
|
*
|
|
4
4
|
* The fields a bot may propose for itself (`cwd` is the working folder its
|
|
5
|
-
* tools run in; "" means its private workspace
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* tools run in; "" means its private workspace; `notifications` and
|
|
6
|
+
* `speakReplies` are the alert and voice toggles). `before` is the snapshot
|
|
7
|
+
* the user was shown; `expectedRevision` is a hash of the target's whole
|
|
8
|
+
* profile at proposal time so a confirmation fails closed if anything moved.
|
|
8
9
|
*/
|
|
9
|
-
export const PROFILE_REQUEST_FIELDS = ["name", "title", "description", "soul", "cwd"];
|
|
10
|
+
export const PROFILE_REQUEST_FIELDS = ["name", "title", "description", "soul", "cwd", "notifications", "speakReplies"];
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// SKILL.md reading shared by the server skill store, the package format and
|
|
2
|
+
// the renderer. Pure text only: no filesystem, no Node globals, so the same
|
|
3
|
+
// rules validate a skill wherever it is read (server/skills.ts re-exports
|
|
4
|
+
// these under their historical names).
|
|
5
|
+
/** Spec rule: lowercase alphanumerics with single hyphens, 1-64 chars,
|
|
6
|
+
* folder name must equal it. The regex IS the traversal gate — no dots, no
|
|
7
|
+
* slashes, no way to name a skill "..". */
|
|
8
|
+
const SKILL_NAME = /^[a-z0-9]+(?:-[a-z0-9]+)*$/;
|
|
9
|
+
export const SKILL_NAME_MAX = 64;
|
|
10
|
+
export const DESCRIPTION_MAX = 1024;
|
|
11
|
+
/** One SKILL.md may be at most this large; the spec recommends <5k tokens. */
|
|
12
|
+
export const SKILL_FILE_MAX_BYTES = 256 * 1024;
|
|
13
|
+
export function isSkillName(name) {
|
|
14
|
+
return name.length >= 1 && name.length <= SKILL_NAME_MAX && SKILL_NAME.test(name);
|
|
15
|
+
}
|
|
16
|
+
/** Minimal frontmatter reader for the two required keys plus the two we
|
|
17
|
+
* display. Deliberately not a YAML engine: values are single-line strings in
|
|
18
|
+
* every skill the spec's own examples show, and a parser that cannot
|
|
19
|
+
* evaluate anchors or tags cannot be surprised by them. */
|
|
20
|
+
export function parseSkillMd(raw) {
|
|
21
|
+
const match = raw.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n?([\s\S]*)$/);
|
|
22
|
+
if (!match)
|
|
23
|
+
return { error: "SKILL.md has no YAML frontmatter (--- block) at the top" };
|
|
24
|
+
const fields = {};
|
|
25
|
+
for (const line of match[1].split(/\r?\n/)) {
|
|
26
|
+
const kv = line.match(/^([A-Za-z][\w-]*):\s*(.*)$/);
|
|
27
|
+
if (!kv)
|
|
28
|
+
continue;
|
|
29
|
+
fields[kv[1].toLowerCase()] = kv[2].replace(/^["']|["']$/g, "").trim();
|
|
30
|
+
}
|
|
31
|
+
const name = fields.name ?? "";
|
|
32
|
+
const description = fields.description ?? "";
|
|
33
|
+
if (!isSkillName(name)) {
|
|
34
|
+
return { error: `frontmatter name ${JSON.stringify(name)} is not a valid skill name (lowercase, hyphens, max ${SKILL_NAME_MAX})` };
|
|
35
|
+
}
|
|
36
|
+
if (!description || description.length > DESCRIPTION_MAX) {
|
|
37
|
+
return { error: `frontmatter description is required and must be at most ${DESCRIPTION_MAX} characters` };
|
|
38
|
+
}
|
|
39
|
+
return {
|
|
40
|
+
name,
|
|
41
|
+
description,
|
|
42
|
+
license: fields.license || undefined,
|
|
43
|
+
compatibility: fields.compatibility || undefined,
|
|
44
|
+
body: match[2] ?? "",
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
/** Static red flags before a human review. Presence is a warning shown in
|
|
48
|
+
* the review screen, never a silent rejection — the reviewer decides. These
|
|
49
|
+
* are the three patterns the public registry audits actually caught. */
|
|
50
|
+
export function scanSkillText(raw) {
|
|
51
|
+
const warnings = [];
|
|
52
|
+
if (/[A-Za-z0-9+/]{120,}={0,2}/.test(raw)) {
|
|
53
|
+
warnings.push("contains a long base64-looking blob — a common wrapper for hidden instructions or payloads");
|
|
54
|
+
}
|
|
55
|
+
if (/\b(curl|wget)\b[^\n]{0,200}\|\s*(ba|z|da)?sh\b/.test(raw)) {
|
|
56
|
+
warnings.push("pipes a download straight into a shell (curl|sh) — never enable without understanding why");
|
|
57
|
+
}
|
|
58
|
+
// zero-width and bidi-control characters hide text from the reviewer while
|
|
59
|
+
// the model still reads it — the invisible-instruction trick
|
|
60
|
+
if (/[---]/.test(raw)) {
|
|
61
|
+
warnings.push("contains invisible Unicode characters (zero-width or bidi controls) — text you cannot see");
|
|
62
|
+
}
|
|
63
|
+
return warnings;
|
|
64
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import { CONNECTOR_SLUG_PATTERN, CONNECTOR_TOOL_NAME_PATTERN } from "./wire.js";
|
|
2
3
|
export const MAX_TEAM_BACKUP_BYTES = 50 * 1024 * 1024;
|
|
3
4
|
export const TEAM_BACKUP_CONTENTS = "Bot profiles, instructions, sections, rooms, playbooks, routines, each bot's memory (MEMORY.md, topic notes and daily logs) and conversation text (all tasks and branches).";
|
|
4
5
|
export const TEAM_BACKUP_EXCLUSIONS = "Files, images, custom avatars, account connections, model settings and permissions are not included. Action cards are saved as text. Memory is saved with secrets removed. Imported routines start paused.";
|
|
@@ -57,6 +58,11 @@ const memory = z.object({
|
|
|
57
58
|
topics: z.array(z.object({ name: z.string().regex(/^[\w][\w .-]{0,199}\.md$/), text: memoryText })).max(1_000),
|
|
58
59
|
logs: z.array(z.object({ name: z.string().regex(/^\d{4}-\d{2}-\d{2}\.md$/), text: memoryText })).max(10_000),
|
|
59
60
|
});
|
|
61
|
+
/** The private backup is the one portable format grants travel in, so the
|
|
62
|
+
* shape is checked with the same patterns the store validates patches
|
|
63
|
+
* against. Shareable exports never carry grants at all, and an import
|
|
64
|
+
* always lands bots grant-less whatever the file says. */
|
|
65
|
+
const connectorTools = z.record(z.string().regex(CONNECTOR_SLUG_PATTERN), z.object({ tools: z.union([z.literal("*"), z.array(z.string().regex(CONNECTOR_TOOL_NAME_PATTERN)).min(1).max(500)]) }));
|
|
60
66
|
const backupSchema = z.object({
|
|
61
67
|
format: z.literal("openmaus.backup"),
|
|
62
68
|
version: z.literal(1),
|
|
@@ -77,6 +83,7 @@ const backupSchema = z.object({
|
|
|
77
83
|
chiefOfStaff: z.boolean(),
|
|
78
84
|
hidden: z.boolean(),
|
|
79
85
|
playbooks: z.array(playbook).max(200),
|
|
86
|
+
connectorTools: connectorTools.optional(),
|
|
80
87
|
memory: memory.optional(),
|
|
81
88
|
})).min(1).max(200),
|
|
82
89
|
groups: z.array(z.object({
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Durable payload carried by a tightening card (propose_tightening).
|
|
3
|
+
*
|
|
4
|
+
* Authority reductions a bot may propose for itself or (for a Chief) a
|
|
5
|
+
* section peer. Direction is enforced by shape: the intents cannot express
|
|
6
|
+
* an escalation — approvalMode targets stop below full and custom, the
|
|
7
|
+
* booleans only carry their tightening value, and the list fields only
|
|
8
|
+
* carry removals. `validateTightening` then checks the remaining
|
|
9
|
+
* state-relative direction (an upward move inside ask/edits/auto, a grant
|
|
10
|
+
* that is not currently held) against live bot state, at propose AND again
|
|
11
|
+
* at confirm, so a card that sat open can never apply a transition that
|
|
12
|
+
* stopped being a reduction. Escalation stays human-only in Edit Profile.
|
|
13
|
+
*/
|
|
14
|
+
import { APPROVAL_MODES } from "./approval-mode.js";
|
|
15
|
+
/** Targets a proposal may name. "full" and "custom" are owner-only. */
|
|
16
|
+
export const TIGHTENING_MODE_TARGETS = ["ask", "edits", "auto"];
|
|
17
|
+
/** Direction check against live state. Pure: the caller supplies the
|
|
18
|
+
* snapshot, at propose and again at confirm. Every rejection names the
|
|
19
|
+
* field and the allowed direction. */
|
|
20
|
+
export function validateTightening(before, intents) {
|
|
21
|
+
const after = {
|
|
22
|
+
...before,
|
|
23
|
+
alwaysAllow: [...before.alwaysAllow],
|
|
24
|
+
mcpServers: [...before.mcpServers],
|
|
25
|
+
skills: [...before.skills],
|
|
26
|
+
};
|
|
27
|
+
if (intents.approvalMode !== undefined) {
|
|
28
|
+
const to = intents.approvalMode;
|
|
29
|
+
const from = before.approvalMode;
|
|
30
|
+
const reduces = from === "custom"
|
|
31
|
+
? to === "ask"
|
|
32
|
+
: APPROVAL_MODES.indexOf(to) < APPROVAL_MODES.indexOf(from);
|
|
33
|
+
if (!reduces) {
|
|
34
|
+
return {
|
|
35
|
+
ok: false,
|
|
36
|
+
error: `approvalMode can only tighten: down the selector order (ask, edits, auto, full), or custom to ask. "${to}" does not reduce "${from}".`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
after.approvalMode = to;
|
|
40
|
+
}
|
|
41
|
+
if (intents.composio !== undefined) {
|
|
42
|
+
if (!before.composio)
|
|
43
|
+
return { ok: false, error: "composio is already off; it may only be turned off" };
|
|
44
|
+
after.composio = false;
|
|
45
|
+
}
|
|
46
|
+
if (intents.browser !== undefined) {
|
|
47
|
+
if (!before.browser)
|
|
48
|
+
return { ok: false, error: "browser is already off; it may only be turned off" };
|
|
49
|
+
after.browser = false;
|
|
50
|
+
}
|
|
51
|
+
if (intents.approvePeerComms !== undefined) {
|
|
52
|
+
if (before.approvePeerComms)
|
|
53
|
+
return { ok: false, error: "approvePeerComms is already on; it may only be turned on" };
|
|
54
|
+
after.approvePeerComms = true;
|
|
55
|
+
}
|
|
56
|
+
if (intents.alwaysAllow !== undefined) {
|
|
57
|
+
const removals = [...new Set(intents.alwaysAllow)];
|
|
58
|
+
if (!removals.length)
|
|
59
|
+
return { ok: false, error: "alwaysAllow must name at least one grant to remove" };
|
|
60
|
+
const unknown = removals.filter((key) => !before.alwaysAllow.includes(key));
|
|
61
|
+
if (unknown.length) {
|
|
62
|
+
return { ok: false, error: `alwaysAllow entries may only be removed, never added; not currently granted: ${unknown.join(", ")}` };
|
|
63
|
+
}
|
|
64
|
+
after.alwaysAllow = before.alwaysAllow.filter((key) => !removals.includes(key));
|
|
65
|
+
}
|
|
66
|
+
if (intents.mcpServers !== undefined) {
|
|
67
|
+
const removals = [...new Set(intents.mcpServers)];
|
|
68
|
+
if (!removals.length)
|
|
69
|
+
return { ok: false, error: "mcpServers must name at least one server to unmount" };
|
|
70
|
+
const unknown = removals.filter((name) => !before.mcpServers.includes(name));
|
|
71
|
+
if (unknown.length) {
|
|
72
|
+
return { ok: false, error: `mcpServers may only unmount servers this bot currently mounts; not mounted: ${unknown.join(", ")}` };
|
|
73
|
+
}
|
|
74
|
+
after.mcpServers = before.mcpServers.filter((name) => !removals.includes(name));
|
|
75
|
+
}
|
|
76
|
+
if (intents.skills !== undefined) {
|
|
77
|
+
const removals = [...new Set(intents.skills)];
|
|
78
|
+
if (!removals.length)
|
|
79
|
+
return { ok: false, error: "skills must name at least one skill to disable" };
|
|
80
|
+
const unknown = removals.filter((name) => !before.skills.includes(name));
|
|
81
|
+
if (unknown.length) {
|
|
82
|
+
return { ok: false, error: `skills may only be disabled, never enabled; not currently enabled: ${unknown.join(", ")}` };
|
|
83
|
+
}
|
|
84
|
+
after.skills = before.skills.filter((name) => !removals.includes(name));
|
|
85
|
+
}
|
|
86
|
+
return { ok: true, after };
|
|
87
|
+
}
|
|
@@ -6,3 +6,7 @@ export const EFFORT_LEVELS = ["none", "low", "medium", "high", "xhigh", "max"];
|
|
|
6
6
|
export function isEffortLevel(value) {
|
|
7
7
|
return typeof value === "string" && EFFORT_LEVELS.includes(value);
|
|
8
8
|
}
|
|
9
|
+
/** Lowercased Composio service slug, e.g. `gmail`. */
|
|
10
|
+
export const CONNECTOR_SLUG_PATTERN = /^[a-z0-9][a-z0-9_-]{0,80}$/;
|
|
11
|
+
/** Composio tool names are upper-snake, e.g. `GMAIL_SEND_EMAIL`. */
|
|
12
|
+
export const CONNECTOR_TOOL_NAME_PATTERN = /^[A-Z][A-Z0-9_]{0,127}$/;
|
|
@@ -426,6 +426,11 @@ export function isPrivateAttachmentPath(path) {
|
|
|
426
426
|
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}\.[a-z0-9]+$/i
|
|
427
427
|
.test(attachmentBasename(path));
|
|
428
428
|
}
|
|
429
|
+
/** The exact wrapper lines composeMessage writes around a pasted block. The
|
|
430
|
+
* bot needs them to tell pasted from typed text; a person reading their own
|
|
431
|
+
* message does not. Anything else on the line keeps the tag visible. */
|
|
432
|
+
const PASTED_TEXT_OPEN = /^ {0,3}<pasted-text(?:[\t ]+index="\d+")?[\t ]*>[\t ]*$/i;
|
|
433
|
+
const PASTED_TEXT_CLOSE = /^[\t ]*<\/pasted-text>[\t ]*$/i;
|
|
429
434
|
/** Recognise CommonMark-style fenced code without pulling a Markdown parser
|
|
430
435
|
* into the composer bundle. An unterminated fence deliberately protects the
|
|
431
436
|
* rest of the message: examples must never turn into actionable attachments. */
|
|
@@ -511,8 +516,10 @@ function transcriptBlockStarting(line) {
|
|
|
511
516
|
}
|
|
512
517
|
const TRANSCRIPT_ATTACHMENT_TAG = /^<attached-(image|file)[\t ]+path="([^"\r\n]*)"(?:[\t ]+name="([^"\r\n]*)")?[\t ]*\/>[\t ]*$/;
|
|
513
518
|
/** Split a stored user message into its display text and attachments for
|
|
514
|
-
* transcript rendering. Markdown exports preserve whitespace; bubbles trim it.
|
|
515
|
-
|
|
519
|
+
* transcript rendering. Markdown exports preserve whitespace; bubbles trim it.
|
|
520
|
+
* Bubbles also hide the `<pasted-text>` wrapper lines and show only what was
|
|
521
|
+
* pasted; exports keep the message exactly as the bot received it. */
|
|
522
|
+
export function splitTranscriptAttachments(text, trimDisplay = true, hidePasteWrappers = true) {
|
|
516
523
|
const images = [];
|
|
517
524
|
const files = [];
|
|
518
525
|
let display = "";
|
|
@@ -541,6 +548,8 @@ export function splitTranscriptAttachments(text, trimDisplay = true) {
|
|
|
541
548
|
block = null;
|
|
542
549
|
}
|
|
543
550
|
else if (line.toLowerCase().includes(block.closingToken)) {
|
|
551
|
+
if (block.hiddenWrapper && PASTED_TEXT_CLOSE.test(line))
|
|
552
|
+
consumed = true;
|
|
544
553
|
block = null;
|
|
545
554
|
}
|
|
546
555
|
}
|
|
@@ -565,8 +574,13 @@ export function splitTranscriptAttachments(text, trimDisplay = true) {
|
|
|
565
574
|
consumed = true;
|
|
566
575
|
}
|
|
567
576
|
}
|
|
568
|
-
if (!consumed)
|
|
577
|
+
if (!consumed) {
|
|
569
578
|
block = transcriptBlockStarting(line);
|
|
579
|
+
if (hidePasteWrappers && block?.kind === "untilToken" && block.closingToken === "</pasted-text>" && PASTED_TEXT_OPEN.test(line)) {
|
|
580
|
+
block = { ...block, hiddenWrapper: true };
|
|
581
|
+
consumed = true;
|
|
582
|
+
}
|
|
583
|
+
}
|
|
570
584
|
}
|
|
571
585
|
if (!consumed)
|
|
572
586
|
display += text.slice(cursor, wholeLineEnd);
|
|
@@ -635,6 +649,14 @@ export function attachmentImageUrl(path) {
|
|
|
635
649
|
return null;
|
|
636
650
|
return `/api/attachments/${encodeURIComponent(name)}`;
|
|
637
651
|
}
|
|
652
|
+
/** Voice notes park as bare generated .mp3 filenames; anything else stays
|
|
653
|
+
* out of an <audio> src rather than 404ing on a private path. */
|
|
654
|
+
export function attachmentAudioUrl(path) {
|
|
655
|
+
const name = attachmentBasename(path);
|
|
656
|
+
if (!/^[A-Za-z0-9-]+\.mp3$/.test(name))
|
|
657
|
+
return null;
|
|
658
|
+
return `/api/attachments/${encodeURIComponent(name)}`;
|
|
659
|
+
}
|
|
638
660
|
/** One intake path for files arriving by drop OR by the composer's attach
|
|
639
661
|
* button, so a picked file and a dropped one can never behave differently.
|
|
640
662
|
* Uploaders are injected for deterministic tests: callers own the network,
|