openmausbot 0.1.97 → 0.1.98

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.
Files changed (144) hide show
  1. package/dist/assets/ActivityPanel-H6D3SD39.js +1 -0
  2. package/dist/assets/BotSettingsDialog-Dqz_AiBZ.js +7 -0
  3. package/dist/assets/CloudBackendPicker-iezpJFpF.js +1 -0
  4. package/dist/assets/ComputerPanel-DZPj-IWu.js +1 -0
  5. package/dist/assets/DesktopViewer-utONms1p.js +5 -0
  6. package/dist/assets/InspectorPanel-OVaBVrzC.js +5 -0
  7. package/dist/assets/KeyboardShortcutsModal-gk9mvHj_.js +1 -0
  8. package/dist/assets/LocalVmWorkspace-DLIvd2kC.js +1 -0
  9. package/dist/assets/MacLocalControl-bJv8yiPB.js +1 -0
  10. package/dist/assets/NewBotDialog-1qGOAdUM.js +2 -0
  11. package/dist/assets/RemoteAgentSettingsPanel-DqKr0HkO.js +1 -0
  12. package/dist/assets/RoutinesPage-BM2D4qGi.js +1 -0
  13. package/dist/assets/RoutinesSection-Dny9ra-c.js +1 -0
  14. package/dist/assets/SettingsModal-gC6XJJmt.js +11 -0
  15. package/dist/assets/TeamMapPage-B6fuu4r_.js +8 -0
  16. package/dist/assets/TriggersPanel-j0qTP2CO.js +1 -0
  17. package/dist/assets/VisibilitySection-DT0FqPvu.js +12 -0
  18. package/dist/assets/WebhooksPanel--YQyCjKO.js +3 -0
  19. package/dist/assets/{abnfDiagram-O67JEVCF-k1UCNXb7.js → abnfDiagram-O67JEVCF-BsjcFX0-.js} +1 -1
  20. package/dist/assets/activity-BxOkayvD.js +1 -0
  21. package/dist/assets/{arc-BUWGa9UU.js → arc-CJNA94c6.js} +1 -1
  22. package/dist/assets/architectureDiagram-NJMV4G6O-dz2ud7lP.js +36 -0
  23. package/dist/assets/{blockDiagram-BEXU5L5S-Ag9nLW4H.js → blockDiagram-BEXU5L5S-ChBEALoR.js} +1 -1
  24. package/dist/assets/brain-CFZ7PEXc.js +1 -0
  25. package/dist/assets/{c4Diagram-YGBWAQC7-Bh0sjgUa.js → c4Diagram-YGBWAQC7-KZNRKDQe.js} +1 -1
  26. package/dist/assets/channel-WhFyujhZ.js +1 -0
  27. package/dist/assets/{chunk-2Q5K7J3B-BFBcIIqu.js → chunk-2Q5K7J3B-BLLwmCET.js} +1 -1
  28. package/dist/assets/{chunk-3FUC2YCW-Dvfpex-f.js → chunk-3FUC2YCW-CQxyreBZ.js} +2 -2
  29. package/dist/assets/{chunk-5VM5RSS4-CMjP2YZW.js → chunk-5VM5RSS4-D6sFMW0u.js} +1 -1
  30. package/dist/assets/{chunk-GTNCS2PH-BryoeTc7.js → chunk-GTNCS2PH-BaZ1YgLF.js} +1 -1
  31. package/dist/assets/{chunk-GWA4HPMP-BhfvcchO.js → chunk-GWA4HPMP-CcalphmC.js} +1 -1
  32. package/dist/assets/{chunk-JWPE2WC7-bcCVp8rp.js → chunk-JWPE2WC7-CSk8R3ve.js} +1 -1
  33. package/dist/assets/{chunk-NETBCI7D-yKIjIlkQ.js → chunk-NETBCI7D-CTmLjA57.js} +1 -1
  34. package/dist/assets/{chunk-WEXAMYUT-D3Zqbmup.js → chunk-WEXAMYUT-CM9Z77Ne.js} +1 -1
  35. package/dist/assets/{chunk-XXDRQBXY-CjVoIMG6.js → chunk-XXDRQBXY-B1fxpMS2.js} +1 -1
  36. package/dist/assets/{classDiagram-v2-NBCMYWYE-mUCWdVyH.js → classDiagram-v2-NBCMYWYE-DCCyoLpj.js} +1 -1
  37. package/dist/assets/computer-control-NLov352p.js +1 -0
  38. package/dist/assets/cose-bilkent-JH36ORCC-KyImBKvE.js +1 -0
  39. package/dist/assets/{cynefin-OW5HDTMX-BpRrxoO4.js → cynefin-OW5HDTMX-fsZc6MGa.js} +1 -1
  40. package/dist/assets/{cynefinDiagram-VND7K2PF-D3VBWCPK.js → cynefinDiagram-VND7K2PF-CGmHsShB.js} +1 -1
  41. package/dist/assets/{dagre-6A5THRUB-DxEIACOO.js → dagre-6A5THRUB-Dah1h-CH.js} +1 -1
  42. package/dist/assets/{diagram-22UHCM2B-BANgZEOS.js → diagram-22UHCM2B-BIu71OyV.js} +1 -1
  43. package/dist/assets/{diagram-3UASUU5V-Cnq7nJir.js → diagram-3UASUU5V-gxhUB_Mu.js} +1 -1
  44. package/dist/assets/{diagram-ATOU4E4O-4TBDIWnz.js → diagram-ATOU4E4O-CBhusUBn.js} +1 -1
  45. package/dist/assets/{diagram-CDSNMT55-CD_B39D4.js → diagram-CDSNMT55-BdPrc86x.js} +1 -1
  46. package/dist/assets/{diagram-MLGK6HIB-CzvnFhEC.js → diagram-MLGK6HIB-Clp110R_.js} +1 -1
  47. package/dist/assets/{diagram-MPIPVDR6-C4w2SNml.js → diagram-MPIPVDR6-DJKfbugw.js} +1 -1
  48. package/dist/assets/{ebnfDiagram-ZINNZB2B-gkUEBm2s.js → ebnfDiagram-ZINNZB2B-DnsltoBu.js} +1 -1
  49. package/dist/assets/{elk-276RUBZZ-B_56X6mw.js → elk-276RUBZZ-jWdq6gqH.js} +1 -1
  50. package/dist/assets/{erDiagram-OPXOYQCR-C_oByoDS.js → erDiagram-OPXOYQCR-DArPVf8u.js} +1 -1
  51. package/dist/assets/{flowDiagram-KWPJA3E3-CR9xXJkC.js → flowDiagram-KWPJA3E3-D2HZ-2f7.js} +1 -1
  52. package/dist/assets/ganttDiagram-FUAMR5RP--o0KIxEo.js +292 -0
  53. package/dist/assets/{gitGraphDiagram-X574FWY7-VJ6-Tp_p.js → gitGraphDiagram-X574FWY7-CsoXr2D7.js} +1 -1
  54. package/dist/assets/image-plus-BbVjGHin.js +1 -0
  55. package/dist/assets/index-BrPW5HDO.css +1 -0
  56. package/dist/assets/index-C3NqfdVU.js +585 -0
  57. package/dist/assets/{index-Cp4S4NOL.js → index-CJTp9JEp.js} +1 -1
  58. package/dist/assets/{infoDiagram-VRGFBTTK-2Lu9te4D.js → infoDiagram-VRGFBTTK-g-6lNp7r.js} +1 -1
  59. package/dist/assets/{ishikawaDiagram-OU5B5YK6-DR49XY-e.js → ishikawaDiagram-OU5B5YK6-B1d6qVTV.js} +1 -1
  60. package/dist/assets/{journeyDiagram-ZHPQQLJL-ZoR0M305.js → journeyDiagram-ZHPQQLJL-BTPuiU6T.js} +1 -1
  61. package/dist/assets/{kanban-definition-PNTS6WVX-DLKHxrO-.js → kanban-definition-PNTS6WVX-bDDuRJvP.js} +1 -1
  62. package/dist/assets/{linear-BASsfWly.js → linear-BVVKbEMy.js} +1 -1
  63. package/dist/assets/{mermaid.core-BVidiPkk.js → mermaid.core-JJdoKyKB.js} +5 -5
  64. package/dist/assets/{mindmap-definition-NLK3R4M7-g_Qx0U5C.js → mindmap-definition-NLK3R4M7-B4aE3T0q.js} +1 -1
  65. package/dist/assets/module-DCUsy2BQ.js +3 -0
  66. package/dist/assets/page-visible-BBo_Zm8g.js +1 -0
  67. package/dist/assets/{pegDiagram-GJSIUBJH-DI9Cjs8w.js → pegDiagram-GJSIUBJH-DFKQWpR7.js} +1 -1
  68. package/dist/assets/{pieDiagram-5QR66LMP-sRI0Uhr5.js → pieDiagram-5QR66LMP-Iv7OKVJi.js} +1 -1
  69. package/dist/assets/{quadrantDiagram-O4NWA36T-CamKTby3.js → quadrantDiagram-O4NWA36T-U2YnfwBk.js} +1 -1
  70. package/dist/assets/{railroadDiagram-XR7U4H2S-DOLlkbf3.js → railroadDiagram-XR7U4H2S-CuPy6RqM.js} +1 -1
  71. package/dist/assets/remote-desktop-panel-BNEj7tUx.js +1 -0
  72. package/dist/assets/{requirementDiagram-PLB6GJNP-DrRQ5r97.js → requirementDiagram-PLB6GJNP-bMI5AK7T.js} +1 -1
  73. package/dist/assets/{sankeyDiagram-IPEJSGJF-DGS_lXcX.js → sankeyDiagram-IPEJSGJF-BKcFE2WQ.js} +1 -1
  74. package/dist/assets/{sequenceDiagram-PO4LG4MO-CkjWqwtf.js → sequenceDiagram-PO4LG4MO-Bn9q88kl.js} +1 -1
  75. package/dist/assets/{sizeCapture-INFHLROL-CepRgful.js → sizeCapture-INFHLROL-Cvmdq9HD.js} +1 -1
  76. package/dist/assets/{stateDiagram-v2-GCMORJYK-hykr-9RS.js → stateDiagram-v2-GCMORJYK-JJQYw3eQ.js} +1 -1
  77. package/dist/assets/{swimlanes-2SLR337P-CKOHEZbI.js → swimlanes-2SLR337P-BkSCBEwp.js} +1 -1
  78. package/dist/assets/swimlanesDiagram-TC7HE7FX-CmTirbVT.js +8 -0
  79. package/dist/assets/table-file.worker-KkMx-SNx.js +10 -0
  80. package/dist/assets/{timeline-definition-EJHVYXUP-CB8pJ6AC.js → timeline-definition-EJHVYXUP-DsaM4GHr.js} +1 -1
  81. package/dist/assets/{usecaseDiagram-POWQR4AR-DrclJHdl.js → usecaseDiagram-POWQR4AR-3FOwLq7B.js} +1 -1
  82. package/dist/assets/user-DcZBnAuv.js +1 -0
  83. package/dist/assets/{vennDiagram-UO4OBE2U-zS23qjv8.js → vennDiagram-UO4OBE2U-DyNjJsKt.js} +1 -1
  84. package/dist/assets/{wardleyDiagram-VNRHLVJA-52jgeKxz.js → wardleyDiagram-VNRHLVJA-Y4ZMcnBC.js} +1 -1
  85. package/dist/assets/{xychartDiagram-PMCCYNJV-DSdl9rQ8.js → xychartDiagram-PMCCYNJV-BXZpg955.js} +1 -1
  86. package/dist/index.html +2 -2
  87. package/dist-server/cloud-home-start.js +19 -8
  88. package/dist-server/container-mcp.js +8 -0
  89. package/dist-server/desktop-entry.mjs +54 -0
  90. package/dist-server/drivers/agents-proxy.js +21 -4
  91. package/dist-server/index.js +1412 -821
  92. package/dist-server/openmausbot.js +837 -571
  93. package/dist-server/pair-cli.js +837 -571
  94. package/dist-server/permission-proxy.js +2 -0
  95. package/dist-server/server/atomic.js +70 -2
  96. package/dist-server/server/cloud-home-start.js +3 -3
  97. package/dist-server/server/config.js +22 -1
  98. package/dist-server/server/connector-card-text.js +15 -0
  99. package/dist-server/server/default-model-selection.js +7 -4
  100. package/dist-server/server/drivers/acp/core.js +10 -0
  101. package/dist-server/server/drivers/acp/grok.js +47 -5
  102. package/dist-server/server/drivers/agents-catalog.js +24 -4
  103. package/dist-server/server/drivers/agents-proxy.js +1 -0
  104. package/dist-server/server/drivers/chat-mcp-tools.js +5 -3
  105. package/dist-server/server/drivers/claude-login-auth.js +1 -1
  106. package/dist-server/server/drivers/claude.js +35 -11
  107. package/dist-server/server/drivers/codex-device-auth.js +27 -319
  108. package/dist-server/server/drivers/device-auth.js +342 -0
  109. package/dist-server/server/drivers/openai-chat.js +12 -4
  110. package/dist-server/server/fleet-agent.js +18 -5
  111. package/dist-server/server/harness/http.js +5 -2
  112. package/dist-server/server/harness/registry.js +19 -0
  113. package/dist-server/server/harness-capabilities.js +7 -4
  114. package/dist-server/server/hosted-models.js +3 -1
  115. package/dist-server/server/index.js +268 -54
  116. package/dist-server/server/key-rejections.js +57 -0
  117. package/dist-server/server/message-file.js +7 -4
  118. package/dist-server/server/permission-proxy.js +4 -0
  119. package/dist-server/server/provider-key-check.js +5 -1
  120. package/dist-server/server/request-auth.js +1 -1
  121. package/dist-server/server/room-turn-timeout.js +28 -0
  122. package/dist-server/server/routes/thread-models.js +36 -0
  123. package/dist-server/server/routines.js +2 -2
  124. package/dist-server/server/skills.js +3 -2
  125. package/dist-server/server/store.js +148 -60
  126. package/dist-server/server/team-backup.js +19 -4
  127. package/dist-server/server/thread-model.js +25 -0
  128. package/dist-server/server/turn-continuation.js +8 -2
  129. package/dist-server/server/webhook-ingress.js +8 -3
  130. package/dist-server/server/webhooks.js +40 -5
  131. package/dist-server/shared/device-sign-in.js +57 -0
  132. package/dist-server/shared/team-backup.js +2 -0
  133. package/dist-server/shared/thread-model.js +13 -0
  134. package/dist-server/vps-container-mcp.js +8 -0
  135. package/dist-server/workspace-backup.worker.js +41 -22
  136. package/package.json +1 -1
  137. package/dist/assets/DesktopViewer-CPidMCtt.js +0 -5
  138. package/dist/assets/architectureDiagram-NJMV4G6O-DiPor3UT.js +0 -36
  139. package/dist/assets/channel-DR8eD6QW.js +0 -1
  140. package/dist/assets/cose-bilkent-JH36ORCC-BBmR1bbX.js +0 -1
  141. package/dist/assets/ganttDiagram-FUAMR5RP-gtYBTu0B.js +0 -292
  142. package/dist/assets/index-CpaIXRLp.js +0 -614
  143. package/dist/assets/index-Z81SMsgR.css +0 -1
  144. package/dist/assets/swimlanesDiagram-TC7HE7FX-D-8vqZ4-.js +0 -8
@@ -0,0 +1,57 @@
1
+ // Where a person enters the one-time code that signs an engine's CLI in on
2
+ // the machine running OpenMausBot (`codex login --device-auth`, `grok login
3
+ // --device-auth`). The server reads the page and the code from the CLI's
4
+ // output with these rules, and the app checks them again before it shows a
5
+ // link. Neither ever turns arbitrary output into a link, or lets a token ride
6
+ // along in one.
7
+ const CODEX_PAGE = "https://auth.openai.com/codex/device";
8
+ const RULES = {
9
+ codex: {
10
+ page: (value) => (/^https:\/\/auth\.openai\.com\/codex\/device\/?$/.test(value) ? CODEX_PAGE : null),
11
+ code: /^[A-Z0-9]{4,8}-[A-Z0-9]{4,8}$/,
12
+ },
13
+ grok: {
14
+ // xAI's own sign-in hosts. The page may carry the code itself (the
15
+ // provider's "complete" link); nothing else may ride in its query.
16
+ page: (value) => {
17
+ if (!/^https:\/\/[^\s#]+$/.test(value))
18
+ return null;
19
+ let url;
20
+ try {
21
+ url = new URL(value);
22
+ }
23
+ catch {
24
+ return null;
25
+ }
26
+ if (url.username || url.password || url.port || !/(^|\.)(x\.ai|grok\.com)$/.test(url.hostname))
27
+ return null;
28
+ return [...url.searchParams.keys()].every((key) => key === "user_code") ? url.href : null;
29
+ },
30
+ code: /^[A-Z0-9]{4,12}(?:-[A-Z0-9]{2,12}){0,3}$/,
31
+ },
32
+ };
33
+ /** The provider's own page for entering `userCode`, or null for anything
34
+ * else. A code carried in the page's link must be that same code. */
35
+ export function deviceSignInLink(provider, value, userCode) {
36
+ const page = value ? RULES[provider].page(value) : null;
37
+ if (!page)
38
+ return null;
39
+ return [...new URL(page).searchParams.values()].every((carried) => carried === userCode) ? page : null;
40
+ }
41
+ /** A one-time code as this provider formats it. */
42
+ export function isDeviceSignInCode(provider, value) {
43
+ return typeof value === "string" && RULES[provider].code.test(value);
44
+ }
45
+ /** The page and the code from a CLI's output, once both lines have arrived
46
+ * whole: output arrives in chunks that may stop halfway through a code, so
47
+ * the last, unfinished line is never read. `text` is already free of
48
+ * terminal styling. */
49
+ export function deviceSignInPrompt(provider, text) {
50
+ const lines = text.split(/\r?\n/).slice(0, -1).map((line) => line.trim());
51
+ const at = lines.findIndex((line) => RULES[provider].page(line) !== null);
52
+ if (at < 0)
53
+ return null;
54
+ const userCode = lines.slice(at + 1).map((line) => line.replace(/^code:\s*/i, "")).find((line) => isDeviceSignInCode(provider, line));
55
+ const authorizationUrl = userCode ? deviceSignInLink(provider, lines[at], userCode) : null;
56
+ return authorizationUrl && userCode ? { authorizationUrl, userCode } : null;
57
+ }
@@ -29,6 +29,8 @@ const task = z.object({
29
29
  closedBy: z.object({ botId: key, name, at: timestamp }).optional(),
30
30
  /** Only true travels. Absence is unpinned, including backups from before pins. */
31
31
  pinned: z.literal(true).optional(),
32
+ /** A conversation's own turn ceiling. Absence keeps the group default. */
33
+ turnTimeoutMinutes: z.number().int().min(1).max(1_440).optional(),
32
34
  activeLeafId: key.nullable(),
33
35
  messages: z.array(message).max(100_000),
34
36
  });
@@ -0,0 +1,13 @@
1
+ /** The same engine, model, effort and variant. */
2
+ export function sameModelSelection(a, b) {
3
+ if (!a || !b)
4
+ return a === b;
5
+ return a.instanceId === b.instanceId && a.model === b.model && a.effort === b.effort && a.variant === b.variant;
6
+ }
7
+ /** A bot's threads that run on a model of their own, different from the
8
+ * bot's: the ones "Switch them too" moves onto the bot's model. Reads the
9
+ * wire shape, where only followsBotModel === false is a thread's own pick, so
10
+ * a server too old to send it counts none. */
11
+ export function threadsOnOwnModel(botModel, tasks) {
12
+ return tasks.filter((task) => task.followsBotModel === false && !sameModelSelection(task.modelSelection ?? botModel, botModel));
13
+ }
@@ -16210,6 +16210,8 @@ var BROWSER_PROFILE_ID = /^[a-z0-9_-]{1,40}$/;
16210
16210
  var FISH_TTS_MODELS = ["s2.1-pro", "s2.1-pro-free"];
16211
16211
  var MIN_ROOM_TURN_TIMEOUT_MINUTES = 1;
16212
16212
  var MAX_ROOM_TURN_TIMEOUT_MINUTES = 1440;
16213
+ var MIN_MCP_CALL_TIMEOUT_MINUTES = 1;
16214
+ var MAX_MCP_CALL_TIMEOUT_MINUTES = 60;
16213
16215
  var DEFAULT_ROOM_HANDOFF_LIFETIME_MINUTES = 30;
16214
16216
  var DEFAULT_ROOM_HANDOFF_MIN_RUNWAY_MINUTES = 10;
16215
16217
  var DEFAULT_ROOM_HANDOFF_HARD_CAP_MINUTES = 240;
@@ -16255,6 +16257,11 @@ var roomConfigSchema = external_exports.object({
16255
16257
  (rooms) => (rooms.handoffMinRunwayMinutes ?? DEFAULT_ROOM_HANDOFF_MIN_RUNWAY_MINUTES) <= (rooms.handoffLifetimeMinutes ?? DEFAULT_ROOM_HANDOFF_LIFETIME_MINUTES) && (rooms.handoffLifetimeMinutes ?? DEFAULT_ROOM_HANDOFF_LIFETIME_MINUTES) <= (rooms.handoffHardCapMinutes ?? DEFAULT_ROOM_HANDOFF_HARD_CAP_MINUTES),
16256
16258
  { message: "rooms handoff bounds must satisfy handoffMinRunwayMinutes <= handoffLifetimeMinutes <= handoffHardCapMinutes" }
16257
16259
  );
16260
+ var mcpConfigSchema = external_exports.object({
16261
+ /** Ceiling (minutes) for one bot MCP tool call. Missing values resolve to
16262
+ * 10, preserving the historic chat-mcp-tools constant. */
16263
+ callTimeoutMinutes: external_exports.number().int().min(MIN_MCP_CALL_TIMEOUT_MINUTES).max(MAX_MCP_CALL_TIMEOUT_MINUTES).optional()
16264
+ }).strict();
16258
16265
  var localVmConfigSchema = external_exports.object({
16259
16266
  mode: external_exports.enum(["shared", "per-bot", "pool"]).optional(),
16260
16267
  maxInstances: external_exports.number().int().min(MIN_LOCAL_VM_MAX_INSTANCES).max(MAX_LOCAL_VM_MAX_INSTANCES).optional(),
@@ -16593,6 +16600,7 @@ var appConfigSchema = external_exports.object({
16593
16600
  * system language. Unknown tags degrade to English in the renderer. */
16594
16601
  language: optionalText,
16595
16602
  rooms: roomConfigSchema.optional(),
16603
+ mcp: mcpConfigSchema.optional(),
16596
16604
  context: external_exports.object({
16597
16605
  rebuildBytes: external_exports.number().int().min(1024).max(1e6).optional(),
16598
16606
  compactAt: external_exports.number().positive().max(1e7).optional(),
@@ -12,17 +12,17 @@ import { createCipheriv, createDecipheriv, createHash, randomBytes, randomUUID a
12
12
  import {
13
13
  chmodSync,
14
14
  closeSync as closeSync2,
15
- constants,
15
+ constants as constants2,
16
16
  cpSync,
17
17
  createReadStream,
18
18
  createWriteStream,
19
19
  existsSync,
20
- fstatSync,
20
+ fstatSync as fstatSync2,
21
21
  fsyncSync as fsyncSync2,
22
- lstatSync,
22
+ lstatSync as lstatSync2,
23
23
  mkdirSync,
24
24
  openSync as openSync2,
25
- readFileSync,
25
+ readFileSync as readFileSync2,
26
26
  readdirSync,
27
27
  readSync,
28
28
  realpathSync,
@@ -3007,7 +3007,18 @@ var To = (s4) => {
3007
3007
 
3008
3008
  // server/atomic.ts
3009
3009
  import { randomUUID } from "node:crypto";
3010
- import { closeSync, fsyncSync, openSync, renameSync, unlinkSync, writeFileSync } from "node:fs";
3010
+ import {
3011
+ closeSync,
3012
+ constants,
3013
+ fstatSync,
3014
+ fsyncSync,
3015
+ lstatSync,
3016
+ openSync,
3017
+ readFileSync,
3018
+ renameSync,
3019
+ unlinkSync,
3020
+ writeFileSync
3021
+ } from "node:fs";
3011
3022
  var RENAME_RETRY_DELAYS_MS = [5, 10, 20, 40, 80];
3012
3023
  var RETRYABLE_RENAME_CODES = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY"]);
3013
3024
  function sleepSync(ms2) {
@@ -3031,7 +3042,7 @@ function writeFileAtomic(path, data, options2 = {}) {
3031
3042
  try {
3032
3043
  fd = openSync(tmp, "w", options2.mode);
3033
3044
  writeFileSync(fd, data);
3034
- fsyncSync(fd);
3045
+ if (options2.durable !== false) fsyncSync(fd);
3035
3046
  closeSync(fd);
3036
3047
  fd = null;
3037
3048
  renameWithRetry(tmp, path);
@@ -18769,6 +18780,8 @@ var BROWSER_PROFILE_ID = /^[a-z0-9_-]{1,40}$/;
18769
18780
  var FISH_TTS_MODELS = ["s2.1-pro", "s2.1-pro-free"];
18770
18781
  var MIN_ROOM_TURN_TIMEOUT_MINUTES = 1;
18771
18782
  var MAX_ROOM_TURN_TIMEOUT_MINUTES = 1440;
18783
+ var MIN_MCP_CALL_TIMEOUT_MINUTES = 1;
18784
+ var MAX_MCP_CALL_TIMEOUT_MINUTES = 60;
18772
18785
  var DEFAULT_ROOM_HANDOFF_LIFETIME_MINUTES = 30;
18773
18786
  var DEFAULT_ROOM_HANDOFF_MIN_RUNWAY_MINUTES = 10;
18774
18787
  var DEFAULT_ROOM_HANDOFF_HARD_CAP_MINUTES = 240;
@@ -18814,6 +18827,11 @@ var roomConfigSchema = external_exports.object({
18814
18827
  (rooms) => (rooms.handoffMinRunwayMinutes ?? DEFAULT_ROOM_HANDOFF_MIN_RUNWAY_MINUTES) <= (rooms.handoffLifetimeMinutes ?? DEFAULT_ROOM_HANDOFF_LIFETIME_MINUTES) && (rooms.handoffLifetimeMinutes ?? DEFAULT_ROOM_HANDOFF_LIFETIME_MINUTES) <= (rooms.handoffHardCapMinutes ?? DEFAULT_ROOM_HANDOFF_HARD_CAP_MINUTES),
18815
18828
  { message: "rooms handoff bounds must satisfy handoffMinRunwayMinutes <= handoffLifetimeMinutes <= handoffHardCapMinutes" }
18816
18829
  );
18830
+ var mcpConfigSchema = external_exports.object({
18831
+ /** Ceiling (minutes) for one bot MCP tool call. Missing values resolve to
18832
+ * 10, preserving the historic chat-mcp-tools constant. */
18833
+ callTimeoutMinutes: external_exports.number().int().min(MIN_MCP_CALL_TIMEOUT_MINUTES).max(MAX_MCP_CALL_TIMEOUT_MINUTES).optional()
18834
+ }).strict();
18817
18835
  var localVmConfigSchema = external_exports.object({
18818
18836
  mode: external_exports.enum(["shared", "per-bot", "pool"]).optional(),
18819
18837
  maxInstances: external_exports.number().int().min(MIN_LOCAL_VM_MAX_INSTANCES).max(MAX_LOCAL_VM_MAX_INSTANCES).optional(),
@@ -19152,6 +19170,7 @@ var appConfigSchema = external_exports.object({
19152
19170
  * system language. Unknown tags degrade to English in the renderer. */
19153
19171
  language: optionalText,
19154
19172
  rooms: roomConfigSchema.optional(),
19173
+ mcp: mcpConfigSchema.optional(),
19155
19174
  context: external_exports.object({
19156
19175
  rebuildBytes: external_exports.number().int().min(1024).max(1e6).optional(),
19157
19176
  compactAt: external_exports.number().positive().max(1e7).optional(),
@@ -19312,14 +19331,14 @@ function forbiddenArchivePath(path) {
19312
19331
  }
19313
19332
  function folder(path) {
19314
19333
  mkdirSync(path, { recursive: true, mode: 448 });
19315
- const stat = lstatSync(path);
19334
+ const stat = lstatSync2(path);
19316
19335
  if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error("The backup directory must be a real directory, not a symbolic link.");
19317
19336
  chmodSync(path, 448);
19318
19337
  }
19319
19338
  function backupRoot(dataDir2) {
19320
19339
  const root = resolve(dataDir2);
19321
19340
  if (root === parse3(root).root) throw new Error("A filesystem root cannot be a workspace backup target.");
19322
- const stat = lstatSync(root);
19341
+ const stat = lstatSync2(root);
19323
19342
  if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error("The workspace data directory must not be a symbolic link.");
19324
19343
  const path = join2(root, ".backups");
19325
19344
  folder(path);
@@ -19329,7 +19348,7 @@ function jobPath(dataDir2, id) {
19329
19348
  if (!ID.test(id)) throw new Error("Invalid workspace backup identifier.");
19330
19349
  const path = join2(backupRoot(dataDir2), id);
19331
19350
  if (entryExists(path)) {
19332
- const stat = lstatSync(path);
19351
+ const stat = lstatSync2(path);
19333
19352
  if (!stat.isDirectory() || stat.isSymbolicLink()) throw new Error("Unsafe workspace backup job directory.");
19334
19353
  }
19335
19354
  return path;
@@ -19347,7 +19366,7 @@ function record2(value) {
19347
19366
  }
19348
19367
  function entryExists(path) {
19349
19368
  try {
19350
- lstatSync(path);
19369
+ lstatSync2(path);
19351
19370
  return true;
19352
19371
  } catch (error51) {
19353
19372
  if (error51.code === "ENOENT") return false;
@@ -19355,11 +19374,11 @@ function entryExists(path) {
19355
19374
  }
19356
19375
  }
19357
19376
  function privateJson(path) {
19358
- const fd = openSync2(path, constants.O_RDONLY | constants.O_NOFOLLOW);
19377
+ const fd = openSync2(path, constants2.O_RDONLY | constants2.O_NOFOLLOW);
19359
19378
  try {
19360
- const stat = fstatSync(fd);
19379
+ const stat = fstatSync2(fd);
19361
19380
  if (!stat.isFile() || stat.size > MAX_METADATA_BYTES) throw new Error("Workspace backup metadata is too large or is not a regular file.");
19362
- return JSON.parse(readFileSync(fd, "utf8"));
19381
+ return JSON.parse(readFileSync2(fd, "utf8"));
19363
19382
  } finally {
19364
19383
  closeSync2(fd);
19365
19384
  }
@@ -19408,10 +19427,10 @@ function passwordKey(password, salt) {
19408
19427
  });
19409
19428
  }
19410
19429
  function copyRegular(source, destination) {
19411
- const input = openSync2(source, constants.O_RDONLY | constants.O_NOFOLLOW);
19430
+ const input = openSync2(source, constants2.O_RDONLY | constants2.O_NOFOLLOW);
19412
19431
  let output;
19413
19432
  try {
19414
- const before = fstatSync(input);
19433
+ const before = fstatSync2(input);
19415
19434
  if (!before.isFile() || before.size > MAX_WORKSPACE_BACKUP_BYTES) throw new Error("A workspace file is not regular or exceeds the 10 GB backup limit.");
19416
19435
  const mode = before.mode & 64 ? 448 : 384;
19417
19436
  output = openSync2(destination, "wx", mode);
@@ -19427,8 +19446,8 @@ function copyRegular(source, destination) {
19427
19446
  let offset = 0;
19428
19447
  while (offset < count) offset += writeSync(output, chunk, offset, count - offset);
19429
19448
  }
19430
- const after = fstatSync(input);
19431
- const current = lstatSync(source);
19449
+ const after = fstatSync2(input);
19450
+ const current = lstatSync2(source);
19432
19451
  if (size !== before.size || after.mtimeMs !== before.mtimeMs || after.ctimeMs !== before.ctimeMs || current.ino !== before.ino || current.dev !== before.dev || current.isSymbolicLink()) {
19433
19452
  throw new Error("A workspace file changed during backup. Stop its writer and retry.");
19434
19453
  }
@@ -19440,9 +19459,9 @@ function copyRegular(source, destination) {
19440
19459
  }
19441
19460
  }
19442
19461
  function hashFile(path) {
19443
- const fd = openSync2(path, constants.O_RDONLY | constants.O_NOFOLLOW);
19462
+ const fd = openSync2(path, constants2.O_RDONLY | constants2.O_NOFOLLOW);
19444
19463
  try {
19445
- if (!fstatSync(fd).isFile()) throw new Error("The workspace archive contains an unsafe file.");
19464
+ if (!fstatSync2(fd).isFile()) throw new Error("The workspace archive contains an unsafe file.");
19446
19465
  const hash2 = createHash("sha256");
19447
19466
  const chunk = Buffer.allocUnsafe(1024 * 1024);
19448
19467
  for (; ; ) {
@@ -19499,7 +19518,7 @@ async function createWorkspaceBackupSnapshot(dataDir2, options2, jobId2) {
19499
19518
  const root = realpathSync(dataDir2);
19500
19519
  const sourceDb = join2(root, "messages.db");
19501
19520
  if (existsSync(sourceDb)) {
19502
- if (lstatSync(sourceDb).isSymbolicLink()) throw new Error("The message database must not be a symbolic link.");
19521
+ if (lstatSync2(sourceDb).isSymbolicLink()) throw new Error("The message database must not be a symbolic link.");
19503
19522
  const db = new DatabaseSync(sourceDb, { readOnly: true });
19504
19523
  const completionPulse = setInterval(() => {
19505
19524
  }, 25);
@@ -19524,7 +19543,7 @@ async function createWorkspaceBackupSnapshot(dataDir2, options2, jobId2) {
19524
19543
  if (forbiddenArchivePath(path2)) throw new Error("A workspace filename conflicts with a protected authentication or runtime path.");
19525
19544
  if (!validRelative(path2)) throw new Error("A workspace filename cannot be safely restored on supported platforms.");
19526
19545
  const source = join2(directory, name);
19527
- const stat = lstatSync(source);
19546
+ const stat = lstatSync2(source);
19528
19547
  if (name === "node_modules" && (stat.isDirectory() || stat.isSymbolicLink())) {
19529
19548
  skippedDependencies++;
19530
19549
  continue;
@@ -19568,7 +19587,7 @@ async function createWorkspaceBackupSnapshot(dataDir2, options2, jobId2) {
19568
19587
  }
19569
19588
  writeJson(destination, value);
19570
19589
  }
19571
- copied = { size: lstatSync(destination).size, mode: 384, sha256: hashFile(destination) };
19590
+ copied = { size: lstatSync2(destination).size, mode: 384, sha256: hashFile(destination) };
19572
19591
  } else copied = copyRegular(path2 === "messages.db" ? join2(snapshot, "messages-snapshot.db") : source, destination);
19573
19592
  bytes += copied.size;
19574
19593
  if (bytes > MAX_WORKSPACE_BACKUP_BYTES) throw new Error("The workspace exceeds the 10 GB backup limit.");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "openmausbot",
3
- "version": "0.1.97",
3
+ "version": "0.1.98",
4
4
  "description": "Run the OpenMausBot server anywhere and pair your devices to it",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",