openmausbot 0.1.94 → 0.1.96

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 (188) hide show
  1. package/dist/assets/{DesktopViewer-bxM7NV3N.js → DesktopViewer-DsnA23KM.js} +1 -1
  2. package/dist/assets/{abnfDiagram-O67JEVCF-BhMdJhRJ.js → abnfDiagram-O67JEVCF-Dkbd2hcj.js} +1 -1
  3. package/dist/assets/{arc-B5itKDcx.js → arc-Duj5Coy2.js} +1 -1
  4. package/dist/assets/{architectureDiagram-NJMV4G6O-C5d7UY6U.js → architectureDiagram-NJMV4G6O-uYUsDawP.js} +1 -1
  5. package/dist/assets/{blockDiagram-BEXU5L5S-BrZIhMmu.js → blockDiagram-BEXU5L5S-CWDlTpXe.js} +1 -1
  6. package/dist/assets/{c4Diagram-YGBWAQC7-7I0ArfbD.js → c4Diagram-YGBWAQC7-B0t15PDc.js} +1 -1
  7. package/dist/assets/channel-BZxwC-Gw.js +1 -0
  8. package/dist/assets/{chunk-2Q5K7J3B-BnEsyN36.js → chunk-2Q5K7J3B-BJSCL-HV.js} +1 -1
  9. package/dist/assets/{chunk-3FUC2YCW-BXATQ52s.js → chunk-3FUC2YCW-D3_ILccd.js} +2 -2
  10. package/dist/assets/{chunk-5VM5RSS4-B0BpTkEx.js → chunk-5VM5RSS4-D3dmwT_S.js} +1 -1
  11. package/dist/assets/{chunk-GTNCS2PH-BtLTz6FR.js → chunk-GTNCS2PH-Br73HFPD.js} +1 -1
  12. package/dist/assets/{chunk-GWA4HPMP-D6gcZOYt.js → chunk-GWA4HPMP-uSsjxubC.js} +1 -1
  13. package/dist/assets/{chunk-JWPE2WC7-DCLrosvf.js → chunk-JWPE2WC7-C40VWFyr.js} +1 -1
  14. package/dist/assets/{chunk-NETBCI7D-B9JsknV9.js → chunk-NETBCI7D-D6WNNYwU.js} +1 -1
  15. package/dist/assets/{chunk-WEXAMYUT-CsoTxw7z.js → chunk-WEXAMYUT-DOEhq64P.js} +1 -1
  16. package/dist/assets/{chunk-XXDRQBXY-0F_frB0c.js → chunk-XXDRQBXY-BqJEi6Pi.js} +1 -1
  17. package/dist/assets/{classDiagram-v2-NBCMYWYE-DkrpnflX.js → classDiagram-v2-NBCMYWYE-ByU_GnxT.js} +1 -1
  18. package/dist/assets/{cose-bilkent-JH36ORCC-BNDwYBt9.js → cose-bilkent-JH36ORCC-D-Uglxqq.js} +1 -1
  19. package/dist/assets/{cynefin-OW5HDTMX-JUkNr1Mk.js → cynefin-OW5HDTMX-CZWO7aYj.js} +1 -1
  20. package/dist/assets/{cynefinDiagram-VND7K2PF-DKeh9N4M.js → cynefinDiagram-VND7K2PF-C70-w0la.js} +1 -1
  21. package/dist/assets/{dagre-6A5THRUB-ve-6T_wX.js → dagre-6A5THRUB-CnhjhExB.js} +1 -1
  22. package/dist/assets/{diagram-22UHCM2B-BuJ2d8rT.js → diagram-22UHCM2B-bnjWCNb4.js} +1 -1
  23. package/dist/assets/{diagram-3UASUU5V-BgOs_Ni-.js → diagram-3UASUU5V-A4uTWoFV.js} +1 -1
  24. package/dist/assets/{diagram-ATOU4E4O-DMK6VmcP.js → diagram-ATOU4E4O-Zi6m3NUl.js} +1 -1
  25. package/dist/assets/{diagram-CDSNMT55-DksASlcY.js → diagram-CDSNMT55-DtCcmd5k.js} +1 -1
  26. package/dist/assets/{diagram-MLGK6HIB-Bgn8I5k6.js → diagram-MLGK6HIB-DofuETS3.js} +1 -1
  27. package/dist/assets/{diagram-MPIPVDR6-zK0jqO8N.js → diagram-MPIPVDR6-Dw2T9PuU.js} +1 -1
  28. package/dist/assets/{ebnfDiagram-ZINNZB2B-vKrbzTwr.js → ebnfDiagram-ZINNZB2B-DbrwPiem.js} +1 -1
  29. package/dist/assets/{elk-276RUBZZ-Bzv2mPNf.js → elk-276RUBZZ-BvCt1dCb.js} +1 -1
  30. package/dist/assets/{erDiagram-OPXOYQCR-CvOyYuxu.js → erDiagram-OPXOYQCR-Y-QKqPnU.js} +1 -1
  31. package/dist/assets/{flowDiagram-KWPJA3E3-CtbnDbc0.js → flowDiagram-KWPJA3E3-CDkL1B5w.js} +1 -1
  32. package/dist/assets/{ganttDiagram-FUAMR5RP-c4dMRYyG.js → ganttDiagram-FUAMR5RP-CKV5D2F6.js} +1 -1
  33. package/dist/assets/{gitGraphDiagram-X574FWY7-B34uaQho.js → gitGraphDiagram-X574FWY7-nL9iFTCv.js} +1 -1
  34. package/dist/assets/{index-CPiqc_DN.js → index-DreDnjOu.js} +1 -1
  35. package/dist/assets/index-Du7o6Dsf.js +610 -0
  36. package/dist/assets/index-KxG4bWSr.css +1 -0
  37. package/dist/assets/{infoDiagram-VRGFBTTK-o64ma4CI.js → infoDiagram-VRGFBTTK-C7aHjzsf.js} +1 -1
  38. package/dist/assets/{ishikawaDiagram-OU5B5YK6-DV4C9BAm.js → ishikawaDiagram-OU5B5YK6-KUZsNBTh.js} +1 -1
  39. package/dist/assets/{journeyDiagram-ZHPQQLJL-Bf0AHk1H.js → journeyDiagram-ZHPQQLJL-CGUuodFl.js} +1 -1
  40. package/dist/assets/{kanban-definition-PNTS6WVX-B1UMSKmE.js → kanban-definition-PNTS6WVX-Cy6r868Z.js} +1 -1
  41. package/dist/assets/{linear-BpKhuyLm.js → linear-Bl669148.js} +1 -1
  42. package/dist/assets/{mermaid.core-B_BKNCw5.js → mermaid.core-86Xqz5Mr.js} +5 -5
  43. package/dist/assets/{mindmap-definition-NLK3R4M7-DeARruT1.js → mindmap-definition-NLK3R4M7-G4DzHLrd.js} +1 -1
  44. package/dist/assets/{pegDiagram-GJSIUBJH-BOQEk_1D.js → pegDiagram-GJSIUBJH-K4eruzY0.js} +1 -1
  45. package/dist/assets/{pieDiagram-5QR66LMP-EIfoiTZo.js → pieDiagram-5QR66LMP-DYdR9PPq.js} +1 -1
  46. package/dist/assets/{quadrantDiagram-O4NWA36T-GgZwT-fi.js → quadrantDiagram-O4NWA36T-BCAh0nEy.js} +1 -1
  47. package/dist/assets/{railroadDiagram-XR7U4H2S-D9rDQomj.js → railroadDiagram-XR7U4H2S-p0dGRc4g.js} +1 -1
  48. package/dist/assets/{requirementDiagram-PLB6GJNP-DAh1MIeo.js → requirementDiagram-PLB6GJNP-tLeBG0aL.js} +1 -1
  49. package/dist/assets/{sankeyDiagram-IPEJSGJF-CPr6Uz64.js → sankeyDiagram-IPEJSGJF-QRuN16rV.js} +1 -1
  50. package/dist/assets/{sequenceDiagram-PO4LG4MO-BU6VIdcm.js → sequenceDiagram-PO4LG4MO-ueT1nVoa.js} +1 -1
  51. package/dist/assets/{sizeCapture-INFHLROL-qF2HO41r.js → sizeCapture-INFHLROL-wRS2zWg2.js} +1 -1
  52. package/dist/assets/{stateDiagram-v2-GCMORJYK-DlJ8G4MD.js → stateDiagram-v2-GCMORJYK-CYzA_hE1.js} +1 -1
  53. package/dist/assets/{swimlanes-2SLR337P-DzYE8I54.js → swimlanes-2SLR337P-kDnv6LMc.js} +1 -1
  54. package/dist/assets/swimlanesDiagram-TC7HE7FX-C7voMDle.js +8 -0
  55. package/dist/assets/{timeline-definition-EJHVYXUP-B7wzEQ0A.js → timeline-definition-EJHVYXUP-D1y2UbbH.js} +1 -1
  56. package/dist/assets/{usecaseDiagram-POWQR4AR-BvGgrxIP.js → usecaseDiagram-POWQR4AR-IqB4v9HX.js} +1 -1
  57. package/dist/assets/{vennDiagram-UO4OBE2U-CEECdgQg.js → vennDiagram-UO4OBE2U-BEi7KYVF.js} +1 -1
  58. package/dist/assets/{wardleyDiagram-VNRHLVJA-XQHA0P_P.js → wardleyDiagram-VNRHLVJA-Dkybo-Yf.js} +1 -1
  59. package/dist/assets/{xychartDiagram-PMCCYNJV-B5mLcZI2.js → xychartDiagram-PMCCYNJV-BAPFJLpg.js} +1 -1
  60. package/dist/index.html +2 -2
  61. package/dist-server/cloud-home-start.js +27 -13
  62. package/dist-server/companion/src/listener.js +39 -18
  63. package/dist-server/companion/src/routes.js +39 -0
  64. package/dist-server/container-mcp.js +16 -29
  65. package/dist-server/drivers/agents-proxy.js +161 -82
  66. package/dist-server/enterprise/server/index.js +2 -1
  67. package/dist-server/{browser-proxy.js → harness-mcp-proxy.js} +34 -19
  68. package/dist-server/index.js +4991 -4908
  69. package/dist-server/local-computer.js +2 -1
  70. package/dist-server/openmausbot.js +906 -1785
  71. package/dist-server/pair-cli.js +906 -1785
  72. package/dist-server/proxy-paths.js +2 -1
  73. package/dist-server/server/account-signin.js +0 -2
  74. package/dist-server/server/activity.js +201 -0
  75. package/dist-server/server/admin-activity.js +1 -4
  76. package/dist-server/server/auto-approve.js +25 -4
  77. package/dist-server/server/automatic-recovery.js +1 -1
  78. package/dist-server/server/boat-create-idempotency.js +0 -7
  79. package/dist-server/server/boat-delete-journal.js +0 -4
  80. package/dist-server/server/boat.js +4 -4
  81. package/dist-server/server/bot-package.js +1 -19
  82. package/dist-server/server/browser-runtime.js +1 -2
  83. package/dist-server/server/checkpoints.js +90 -148
  84. package/dist-server/server/chief-of-staff.js +9 -9
  85. package/dist-server/server/cli.js +33 -26
  86. package/dist-server/server/cloud-backend.js +0 -4
  87. package/dist-server/server/cloud-computer-tools.js +110 -0
  88. package/dist-server/server/cloud-home-start.js +12 -15
  89. package/dist-server/server/cloud-home.js +0 -5
  90. package/dist-server/server/cloud-lending.js +0 -3
  91. package/dist-server/server/cloud-move-http.js +44 -30
  92. package/dist-server/server/cloud-move.js +20 -18
  93. package/dist-server/server/composio.js +41 -5
  94. package/dist-server/server/computer-control.js +0 -15
  95. package/dist-server/server/computer-observation.js +0 -74
  96. package/dist-server/server/config.js +121 -65
  97. package/dist-server/server/container-computer.js +23 -24
  98. package/dist-server/server/control-client.js +4 -10
  99. package/dist-server/server/decider/jev.js +1 -4
  100. package/dist-server/server/decider/log.js +1 -3
  101. package/dist-server/server/decision-log.js +1 -4
  102. package/dist-server/server/delegations.js +3 -2
  103. package/dist-server/server/drivers/acp/core.js +11 -8
  104. package/dist-server/server/drivers/acp/opencode-go.js +17 -16
  105. package/dist-server/server/drivers/agents-call.js +88 -92
  106. package/dist-server/server/drivers/agents-catalog.js +90 -11
  107. package/dist-server/server/drivers/agents-proxy.js +10 -31
  108. package/dist-server/server/drivers/antigravity.js +1 -4
  109. package/dist-server/server/drivers/boatagent.js +23 -4
  110. package/dist-server/server/drivers/cerebras.js +3 -3
  111. package/dist-server/server/drivers/chat-mcp-tools.js +4 -7
  112. package/dist-server/server/drivers/claude-login-auth.js +2 -11
  113. package/dist-server/server/drivers/claude.js +16 -14
  114. package/dist-server/server/drivers/codex-device-auth.js +3 -1
  115. package/dist-server/server/drivers/codex.js +5 -4
  116. package/dist-server/server/drivers/grok.js +1 -1
  117. package/dist-server/server/drivers/openai-chat-protocol.js +4 -2
  118. package/dist-server/server/drivers/openai-chat.js +18 -11
  119. package/dist-server/server/drivers/prompt-split.js +4 -4
  120. package/dist-server/server/drivers/retry.js +8 -4
  121. package/dist-server/server/engine-install.js +1 -5
  122. package/dist-server/server/harness/bus.js +49 -0
  123. package/dist-server/server/harness/registry.js +0 -1
  124. package/dist-server/server/{browser-proxy.js → harness-mcp-proxy.js} +40 -20
  125. package/dist-server/server/index.js +1190 -971
  126. package/dist-server/server/lending-memory.js +12 -8
  127. package/dist-server/server/mcp-registry.js +35 -0
  128. package/dist-server/server/memory-entries.js +38 -8
  129. package/dist-server/server/memory-organize.js +1 -8
  130. package/dist-server/server/memory-topics.js +4 -4
  131. package/dist-server/server/memory-upkeep.js +13 -15
  132. package/dist-server/server/message-file.js +9 -13
  133. package/dist-server/server/outbound-counts.js +79 -0
  134. package/dist-server/server/outbound-requests.js +60 -0
  135. package/dist-server/server/package-import.js +1 -1
  136. package/dist-server/server/peer-delivery.js +5 -19
  137. package/dist-server/server/peer-roster.js +30 -4
  138. package/dist-server/server/profile-versions.js +0 -31
  139. package/dist-server/server/provider-key-check.js +2 -1
  140. package/dist-server/server/proxy-paths.js +2 -1
  141. package/dist-server/server/restart.js +40 -0
  142. package/dist-server/server/room-handoffs.js +17 -13
  143. package/dist-server/server/routes/bot-memory.js +0 -24
  144. package/dist-server/server/routine-requests.js +2 -5
  145. package/dist-server/server/routines.js +10 -5
  146. package/dist-server/server/server-launcher.js +53 -0
  147. package/dist-server/server/setup-mode.js +0 -2
  148. package/dist-server/server/skill-learn.js +0 -1
  149. package/dist-server/server/skill-library.js +0 -15
  150. package/dist-server/server/store.js +10 -2
  151. package/dist-server/server/surface.js +69 -28
  152. package/dist-server/server/system-prompt.js +17 -7
  153. package/dist-server/server/team-manifest.js +1 -6
  154. package/dist-server/server/team-memory.js +209 -0
  155. package/dist-server/server/thread-events.js +2 -2
  156. package/dist-server/server/tunnel.js +4 -1
  157. package/dist-server/server/turn-images.js +1 -21
  158. package/dist-server/server/turn-resources.js +19 -150
  159. package/dist-server/server/usage-ledger.js +3 -1
  160. package/dist-server/server/vps-computer.js +4 -14
  161. package/dist-server/server/workspace.js +87 -50
  162. package/dist-server/server-launcher.js +72 -0
  163. package/dist-server/shared/activity.js +3 -0
  164. package/dist-server/shared/ask-question.js +1 -1
  165. package/dist-server/shared/bot-avatar.js +8 -0
  166. package/dist-server/shared/cloud-computer.js +12 -0
  167. package/dist-server/shared/connector-scopes.js +78 -0
  168. package/dist-server/shared/failed-turn.js +25 -0
  169. package/dist-server/shared/live-approval.js +2 -2
  170. package/dist-server/shared/outbound.js +128 -0
  171. package/dist-server/shared/package-format.js +3 -3
  172. package/dist-server/shared/pairing-link.js +144 -0
  173. package/dist-server/shared/tool-surface.js +3 -2
  174. package/dist-server/vps-container-mcp.js +16 -29
  175. package/dist-server/workspace-backup.worker.js +14 -27
  176. package/enterprise/server/index.js +2 -1
  177. package/package.json +1 -1
  178. package/dist/assets/channel-CdJX6i8k.js +0 -1
  179. package/dist/assets/index-CPYrGsv1.js +0 -610
  180. package/dist/assets/index-CzT42GR8.css +0 -1
  181. package/dist/assets/swimlanesDiagram-TC7HE7FX-D-U4GtLQ.js +0 -8
  182. package/dist-server/server/claim-idle.js +0 -33
  183. package/dist-server/server/cloud-overflow.js +0 -167
  184. package/dist-server/server/drivers/chat-boat-tools.js +0 -90
  185. package/dist-server/server/drivers/grokagent.js +0 -4
  186. package/dist-server/server/openmaus-status-capsule.js +0 -329
  187. package/dist-server/server/tightening-requests.js +0 -435
  188. package/dist-server/shared/tightening-request.js +0 -87
@@ -1,167 +0,0 @@
1
- /** Consent, cost, and idle-stop policy for overflowing a local computer
2
- * wait onto a per-second-billed cloud seat (#1655).
3
- *
4
- * Like server/claim-idle.ts this module is deliberately synchronous and
5
- * clock-injected: the server decides every transition on its single
6
- * thread and tests pin time exactly. Nothing here starts or stops a
7
- * machine — the wiring does, and only when the decision says to. Keep
8
- * this module free of server imports. */
9
- import { computerWaitDuration } from "./computer-wait.js";
10
- /** Default idle stop: a cloud seat no real screen work has touched for
11
- * this long is stopped (archived), because billing runs per second while
12
- * it runs. "A few idle minutes" per the issue. */
13
- export const CLOUD_SEAT_IDLE_STOP_MS = 5 * 60_000;
14
- /** Retry cadence for an idle stop that failed (#1655): the first retry
15
- * after one minute, doubling per failure up to ten. A failed stop keeps
16
- * its lease — the seat still bills — so the sweep always retries instead
17
- * of abandoning a running machine. */
18
- export const CLOUD_SEAT_SLEEP_RETRY_MS = 60_000;
19
- export const CLOUD_SEAT_SLEEP_RETRY_MAX_MS = 10 * 60_000;
20
- export function cloudOverflowAction(situation) {
21
- if (!situation.featureEnabled || !situation.cloudConfigured || situation.perSecondCostUsd === null)
22
- return { kind: "off" };
23
- if (situation.started)
24
- return { kind: "none" };
25
- if (situation.consented)
26
- return { kind: "start" };
27
- if (situation.offered)
28
- return { kind: "none" };
29
- return { kind: "offer" };
30
- }
31
- /** Per-conversation consent plus the offer bookkeeping that keeps the
32
- * card to one per conversation until it is revoked. A thread the operator
33
- * allowlisted in config carries standing consent and never needs the
34
- * card. */
35
- export class CloudOverflowConsent {
36
- grants = new Map();
37
- offers = new Map();
38
- revocations = new Set();
39
- /** Consent for this conversation. With `perSecondCostUsd`, a card
40
- * consent counts only at the rate its card showed — an allowlisted
41
- * thread carries the operator's standing consent, and the operator is
42
- * also the one who sets the rate. */
43
- consented(threadId, allowlistedThreads = new Set(), perSecondCostUsd) {
44
- if (this.revocations.has(threadId))
45
- return false;
46
- if (allowlistedThreads.has(threadId))
47
- return true;
48
- const grant = this.grants.get(threadId);
49
- if (!grant)
50
- return false;
51
- return perSecondCostUsd === undefined || grant.perSecondCostUsd === perSecondCostUsd;
52
- }
53
- /** `perSecondCostUsd` is the rate the answered card showed. */
54
- grant(threadId, perSecondCostUsd, now = Date.now()) {
55
- this.revocations.delete(threadId);
56
- this.grants.set(threadId, { at: now, perSecondCostUsd });
57
- }
58
- /** Revoking also clears the offered mark, so a later wait in the same
59
- * conversation may ask again instead of meeting silence. */
60
- revoke(threadId) {
61
- const had = this.grants.delete(threadId);
62
- this.revocations.add(threadId);
63
- this.offers.delete(threadId);
64
- return had;
65
- }
66
- /** A card is outstanding for this conversation — at the given rate
67
- * when one is supplied, so a config change re-offers with the new
68
- * price instead of meeting silence at the old one. */
69
- offered(threadId, perSecondCostUsd) {
70
- const offer = this.offers.get(threadId);
71
- if (!offer)
72
- return false;
73
- return perSecondCostUsd === undefined || offer.perSecondCostUsd === perSecondCostUsd;
74
- }
75
- /** The rate the outstanding card showed, or null when no card is out. */
76
- offeredRate(threadId) {
77
- return this.offers.get(threadId)?.perSecondCostUsd ?? null;
78
- }
79
- markOffered(threadId, perSecondCostUsd, now = Date.now()) {
80
- this.offers.set(threadId, { at: now, perSecondCostUsd });
81
- }
82
- }
83
- /** One running cloud seat started by overflow. `touch` is called only
84
- * for real computer tool completions on that seat — screen-poller frames
85
- * never reach it, exactly like #1653's activity clock, so preview
86
- * traffic cannot keep a paid machine awake. */
87
- export class CloudSeatLease {
88
- botId;
89
- threadId;
90
- /** The claim generation that started the seat: a stop releases the Box
91
- * claim for exactly this owner, never a newer turn's. */
92
- generation;
93
- startedAt;
94
- idleStopMs;
95
- lastActivityAt;
96
- sleepRetryNotBefore = 0;
97
- sleepRetryMs = CLOUD_SEAT_SLEEP_RETRY_MS;
98
- constructor(init) {
99
- const idleStopMs = init.idleStopMs ?? CLOUD_SEAT_IDLE_STOP_MS;
100
- if (!Number.isFinite(idleStopMs) || idleStopMs <= 0)
101
- throw new Error("Cloud seat idle stop window must be positive");
102
- this.botId = init.botId;
103
- this.threadId = init.threadId;
104
- this.generation = init.generation;
105
- this.startedAt = init.now ?? Date.now();
106
- this.lastActivityAt = this.startedAt;
107
- this.idleStopMs = idleStopMs;
108
- }
109
- touch(now = Date.now()) {
110
- this.lastActivityAt = now;
111
- // Real work earns a fresh stop attempt: the backoff only paces
112
- // retries against an idle seat that keeps failing to sleep.
113
- this.sleepRetryNotBefore = 0;
114
- this.sleepRetryMs = CLOUD_SEAT_SLEEP_RETRY_MS;
115
- }
116
- /** An idle stop may run now — true until a failure defers it. */
117
- sleepDue(now = Date.now()) {
118
- return now >= this.sleepRetryNotBefore;
119
- }
120
- /** The idle stop failed: keep the lease and back off, bounded, so the
121
- * sweep retries gently instead of hammering a sick Box — and never
122
- * abandons a seat that still bills. */
123
- deferSleep(now = Date.now()) {
124
- this.sleepRetryNotBefore = now + this.sleepRetryMs;
125
- this.sleepRetryMs = Math.min(this.sleepRetryMs * 2, CLOUD_SEAT_SLEEP_RETRY_MAX_MS);
126
- }
127
- idleFor(now = Date.now()) {
128
- return Math.max(0, now - this.lastActivityAt);
129
- }
130
- idleElapsed(now = Date.now()) {
131
- return now - this.lastActivityAt >= this.idleStopMs;
132
- }
133
- }
134
- /** Dollars per second at rate-card precision: enough places for small
135
- * per-second rates to stay visible, trailing zeros trimmed but never
136
- * past two decimals. */
137
- export function formatPerSecondUsd(perSecondCostUsd) {
138
- let text = perSecondCostUsd.toFixed(6).replace(/0+$/, "");
139
- if (text.endsWith("."))
140
- text += "00";
141
- else {
142
- const decimals = text.length - text.indexOf(".") - 1;
143
- if (decimals < 2)
144
- text += "0".repeat(2 - decimals);
145
- }
146
- return "$" + text;
147
- }
148
- /** The consent card (#1655): the per-second cost sits beside the local
149
- * wait picture before any choice is made, and nothing starts without an
150
- * explicit consent the person still has to give. */
151
- export function cloudOverflowOfferText(opts) {
152
- const idleStopMs = opts.idleStopMs ?? CLOUD_SEAT_IDLE_STOP_MS;
153
- const estimate = opts.waitEstimateMs === undefined ? "" : ` Recent local waits here have taken about ${computerWaitDuration(opts.waitEstimateMs)}.`;
154
- return `This computer is busy. Its work can overflow to a cloud computer for ${formatPerSecondUsd(opts.perSecondCostUsd)} per second.${estimate} Nothing starts without your consent — allow cloud overflow for this conversation to start it; the cloud computer stops after ${computerWaitDuration(idleStopMs)} idle.`;
155
- }
156
- export function cloudSeatStartedText(opts) {
157
- const idleStopMs = opts.idleStopMs ?? CLOUD_SEAT_IDLE_STOP_MS;
158
- return `Cloud computer started at ${formatPerSecondUsd(opts.perSecondCostUsd)} per second. It stops automatically after ${computerWaitDuration(idleStopMs)} idle, and the local wait continues until this computer is free.`;
159
- }
160
- export function cloudSeatStoppedText(idleMs) {
161
- return `Cloud computer stopped after ${computerWaitDuration(idleMs)} idle — billing pauses while it sleeps.`;
162
- }
163
- export function cloudOverflowConsentText(allowed, idleStopMs = CLOUD_SEAT_IDLE_STOP_MS) {
164
- return allowed
165
- ? `Cloud overflow allowed for this conversation. A waiting turn may start the cloud computer; it stops after ${computerWaitDuration(idleStopMs)} idle.`
166
- : "Cloud overflow consent revoked. Waits stay local, and no cloud computer starts without a new consent.";
167
- }
@@ -1,90 +0,0 @@
1
- import { isolatedRemoteCommand, runCommand, screenshotBoat } from "../boat.js";
2
- import { createControlClient, CONTROL_REFUSAL_PLAIN } from "../control-client.js";
3
- const coordinate = { type: "integer", minimum: 0, maximum: 32767 };
4
- const tool = (name, description, properties = {}, required = []) => ({ name, description, inputSchema: { type: "object", properties, required, additionalProperties: false } });
5
- const TOOLS = [
6
- tool("screenshot", "See the assigned cloud desktop at native pixel resolution."),
7
- tool("get_screen_size", "Get the cloud desktop width and height."),
8
- tool("click", "Click a point on the cloud desktop.", { x: coordinate, y: coordinate, button: { type: "string", enum: ["left", "middle", "right"] }, count: { type: "integer", minimum: 1, maximum: 3 } }, ["x", "y"]),
9
- tool("move", "Move the cloud mouse pointer.", { x: coordinate, y: coordinate }, ["x", "y"]),
10
- tool("drag", "Drag on the cloud desktop.", { x: coordinate, y: coordinate, to_x: coordinate, to_y: coordinate }, ["x", "y", "to_x", "to_y"]),
11
- tool("type_text", "Type Unicode text into the focused cloud application.", { text: { type: "string", maxLength: 4000 } }, ["text"]),
12
- tool("key_press", "Press an X11 key or shortcut.", { key: { type: "string", pattern: "^[A-Za-z0-9_+]+$", minLength: 1, maxLength: 100 } }, ["key"]),
13
- tool("scroll", "Scroll at a point on the cloud desktop.", { x: coordinate, y: coordinate, direction: { type: "string", enum: ["up", "down", "left", "right"] }, amount: { type: "integer", minimum: 1, maximum: 30 } }, ["x", "y", "direction"]),
14
- tool("open_url", "Request opening an HTTP or HTTPS URL in the cloud desktop browser; inspect the screen to confirm it loaded.", { url: { type: "string", pattern: "^https?://", maxLength: 2000 } }, ["url"]),
15
- tool("exec", "Run a shell command on the assigned cloud computer.", { command: { type: "string", minLength: 1, maxLength: 4000 } }, ["command"]),
16
- ];
17
- const quote = (value) => "'" + value.replace(/'/g, "'\\''") + "'";
18
- const buttons = { left: 1, middle: 2, right: 3 };
19
- const scrollButtons = { up: 4, down: 5, left: 6, right: 7 };
20
- /** Uses only the leased descriptor supplied by the harness. Schema validation
21
- * and user approval happen in the shared chat tool executor before this call. */
22
- export class ChatBoatClient {
23
- closed = false;
24
- control;
25
- descriptor;
26
- constructor(descriptor) {
27
- this.descriptor = descriptor;
28
- if (!descriptor.control?.url || !descriptor.control.token)
29
- throw new Error("Cloud computer control gate missing");
30
- this.control = createControlClient(descriptor.control);
31
- }
32
- async tools() { return TOOLS; }
33
- async close() { this.closed = true; }
34
- async call(_method, params, signal) {
35
- signal.throwIfAborted();
36
- if (this.closed)
37
- throw new Error("Cloud computer session closed");
38
- const state = await this.control.state(true);
39
- signal.throwIfAborted();
40
- if (this.closed)
41
- throw new Error("Cloud computer session closed");
42
- if (state.held || state.blockedReason)
43
- return { isError: true, content: [{ type: "text", text: state.blockedReason || CONTROL_REFUSAL_PLAIN }] };
44
- const { name, arguments: a } = params;
45
- const config = { box: { token: this.descriptor.token } };
46
- const id = this.descriptor.boxId;
47
- if (name === "screenshot") {
48
- const shot = await screenshotBoat(config, "", id, { signal, nativeSize: true });
49
- signal.throwIfAborted();
50
- return { content: [{ type: "image", mimeType: "image/jpeg", data: shot.png }] };
51
- }
52
- const mouse = `xdotool mousemove --sync ${a.x} ${a.y}`;
53
- let command;
54
- switch (name) {
55
- case "get_screen_size":
56
- command = "xdotool getdisplaygeometry";
57
- break;
58
- case "click":
59
- command = `${mouse} click --repeat ${a.count ?? 1} --delay 100 ${buttons[String(a.button ?? "left")]}`;
60
- break;
61
- case "move":
62
- command = mouse;
63
- break;
64
- case "drag":
65
- command = `${mouse} mousedown 1 mousemove --sync ${a.to_x} ${a.to_y} mouseup 1`;
66
- break;
67
- case "type_text":
68
- command = `printf %s ${quote(Buffer.from(String(a.text)).toString("base64"))} | base64 -d | xclip -selection clipboard && xdotool key --clearmodifiers ctrl+v`;
69
- break;
70
- case "key_press":
71
- command = `xdotool key --clearmodifiers ${quote(String(a.key))}`;
72
- break;
73
- case "scroll":
74
- command = `${mouse} click --repeat ${a.amount ?? 3} --delay 80 ${scrollButtons[String(a.direction)]}`;
75
- break;
76
- case "open_url":
77
- command = `nohup xdg-open ${quote(String(a.url))} >/dev/null 2>&1 </dev/null &`;
78
- break;
79
- case "exec":
80
- command = String(a.command);
81
- break;
82
- default: throw new Error("Unknown cloud computer tool");
83
- }
84
- const result = await runCommand(config, id, isolatedRemoteCommand(command), { signal });
85
- signal.throwIfAborted();
86
- if (name === "open_url" && result.ok)
87
- return { content: [{ type: "text", text: "Browser launch requested. Page loading is not confirmed; inspect the screen before continuing." }] };
88
- return { isError: !result.ok, content: [{ type: "text", text: JSON.stringify(result) }] };
89
- }
90
- }
@@ -1,4 +0,0 @@
1
- // Back-compat re-export: the Grok Build ACP driver moved to acp/grok.ts,
2
- // riding the shared acp/core.ts runtime. Kept here so existing imports and
3
- // dist-server references keep resolving.
4
- export { GrokAgentDriver } from "./acp/grok.js";
@@ -1,329 +0,0 @@
1
- import { createHash } from "node:crypto";
2
- import { closeSync, constants, fstatSync, lstatSync, openSync, readFileSync, } from "node:fs";
3
- import { homedir } from "node:os";
4
- import { dirname, join } from "node:path";
5
- import { z } from "zod";
6
- import { parseJson } from "./schema.js";
7
- const SCHEMA = "aos.openmausbot_status.v1";
8
- const TTL_SECONDS = 300;
9
- const MAX_CACHE_BYTES = 16_384;
10
- const DIGEST = /^sha256:[a-f0-9]{64}$/;
11
- const UTC_TIMESTAMP = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/;
12
- const digestSchema = z.string().regex(DIGEST);
13
- const slotSchema = z.object({
14
- slot: z.string().regex(/^vm-[1-4]$/),
15
- container: z.enum(["running", "stopped", "missing"]),
16
- readiness: z.enum(["ready", "not_ready"]),
17
- network: z.enum(["loopback", "unsafe", "unknown"]),
18
- security: z.enum(["hardened", "unsafe", "unknown"]),
19
- persistence: z.enum(["durable", "unsafe", "unknown"]),
20
- }).strict();
21
- const uiSchema = z.object({
22
- two_up: z.boolean(),
23
- max_visible: z.union([z.literal(1), z.literal(2)]),
24
- max_interactive: z.literal(1),
25
- default_watch_only: z.boolean(),
26
- }).strict();
27
- const capsuleSchema = z.object({
28
- schema: z.literal(SCHEMA),
29
- observed_at: z.string().regex(UTC_TIMESTAMP),
30
- fresh_until: z.string().regex(UTC_TIMESTAMP),
31
- ttl_seconds: z.literal(TTL_SECONDS),
32
- source_sha256: digestSchema.nullable(),
33
- dual_view_sha256: digestSchema.nullable(),
34
- receipt_sha256: digestSchema,
35
- refresh_status: z.enum(["success", "failed"]),
36
- failure_reason: z.enum([
37
- "config_unavailable",
38
- "bots_unavailable",
39
- "vm_status_unavailable",
40
- "capacity_exceeded",
41
- "source_hash_unavailable",
42
- "source_hash_mismatch",
43
- ]).optional(),
44
- runtime_state: z.enum(["ready", "degraded", "unknown"]),
45
- mode: z.enum(["shared", "per-bot", "unknown"]),
46
- max_instances: z.number().int().min(1).max(4).nullable(),
47
- ready_count: z.number().int().min(0).max(4),
48
- slots: z.array(slotSchema).max(4),
49
- ui: uiSchema,
50
- }).strict();
51
- const jsonObjectSchema = z.record(z.string(), z.custom());
52
- export const OPENMAUS_STATUS_CACHE_PATH = join(homedir(), ".local/state/aos-session-bridge/openmausbot/latest.json");
53
- function canonicalValue(value) {
54
- if (Array.isArray(value))
55
- return value.map(canonicalValue);
56
- const parsedObject = jsonObjectSchema.safeParse(value);
57
- if (!parsedObject.success)
58
- return value;
59
- const sorted = {};
60
- for (const key of Object.keys(parsedObject.data).sort()) {
61
- const child = parsedObject.data[key];
62
- if (child !== undefined)
63
- sorted[key] = canonicalValue(child);
64
- }
65
- return sorted;
66
- }
67
- function canonical(value) {
68
- return JSON.stringify(canonicalValue(value));
69
- }
70
- function sha256(value) {
71
- return `sha256:${createHash("sha256").update(value, "utf8").digest("hex")}`;
72
- }
73
- function timestamp(value) {
74
- const parsed = Date.parse(value);
75
- if (!Number.isFinite(parsed))
76
- return null;
77
- if (new Date(parsed).toISOString().replace(".000Z", "Z") !== value)
78
- return null;
79
- return parsed;
80
- }
81
- function expectedUi(twoUp) {
82
- return {
83
- two_up: twoUp,
84
- max_visible: twoUp ? 2 : 1,
85
- max_interactive: 1,
86
- default_watch_only: twoUp,
87
- };
88
- }
89
- function sameUi(left, right) {
90
- return (left.two_up === right.two_up &&
91
- left.max_visible === right.max_visible &&
92
- left.max_interactive === right.max_interactive &&
93
- left.default_watch_only === right.default_watch_only);
94
- }
95
- function unsignedDocument(capsule) {
96
- const document = {
97
- schema: capsule.schema,
98
- observed_at: capsule.observed_at,
99
- fresh_until: capsule.fresh_until,
100
- ttl_seconds: capsule.ttl_seconds,
101
- source_sha256: capsule.source_sha256,
102
- dual_view_sha256: capsule.dual_view_sha256,
103
- refresh_status: capsule.refresh_status,
104
- runtime_state: capsule.runtime_state,
105
- mode: capsule.mode,
106
- max_instances: capsule.max_instances,
107
- ready_count: capsule.ready_count,
108
- slots: capsule.slots.map((slot) => ({
109
- slot: slot.slot,
110
- container: slot.container,
111
- readiness: slot.readiness,
112
- network: slot.network,
113
- security: slot.security,
114
- persistence: slot.persistence,
115
- })),
116
- ui: {
117
- two_up: capsule.ui.two_up,
118
- max_visible: capsule.ui.max_visible,
119
- max_interactive: capsule.ui.max_interactive,
120
- default_watch_only: capsule.ui.default_watch_only,
121
- },
122
- };
123
- if (capsule.failure_reason !== undefined)
124
- document.failure_reason = capsule.failure_reason;
125
- return document;
126
- }
127
- function validSlotState(slot) {
128
- return (slot.readiness !== "ready" ||
129
- (slot.container === "running" &&
130
- slot.network === "loopback" &&
131
- slot.security === "hardened" &&
132
- slot.persistence === "durable"));
133
- }
134
- function validateCapsule(value) {
135
- const parsed = capsuleSchema.safeParse(value);
136
- if (!parsed.success)
137
- return null;
138
- const capsule = parsed.data;
139
- const observed = timestamp(capsule.observed_at);
140
- const freshUntil = timestamp(capsule.fresh_until);
141
- if (observed === null || freshUntil === null || freshUntil - observed !== TTL_SECONDS * 1000)
142
- return null;
143
- if (capsule.receipt_sha256 !== sha256(canonical(unsignedDocument(capsule))))
144
- return null;
145
- if (!capsule.slots.every((slot, index) => slot.slot === `vm-${index + 1}` && validSlotState(slot))) {
146
- return null;
147
- }
148
- const readyCount = capsule.slots.filter((slot) => slot.readiness === "ready").length;
149
- if (capsule.ready_count !== readyCount)
150
- return null;
151
- const twoUp = Boolean(capsule.refresh_status === "success" &&
152
- capsule.mode === "per-bot" &&
153
- capsule.max_instances !== null &&
154
- capsule.max_instances >= 2 &&
155
- capsule.source_sha256 !== null &&
156
- capsule.dual_view_sha256 !== null &&
157
- capsule.source_sha256 === capsule.dual_view_sha256);
158
- if (!sameUi(capsule.ui, expectedUi(twoUp)))
159
- return null;
160
- if (capsule.refresh_status === "failed") {
161
- if (capsule.failure_reason === undefined ||
162
- capsule.runtime_state !== "unknown" ||
163
- capsule.mode !== "unknown" ||
164
- capsule.max_instances !== null ||
165
- capsule.ready_count !== 0 ||
166
- capsule.slots.length !== 0 ||
167
- !sameUi(capsule.ui, expectedUi(false)))
168
- return null;
169
- }
170
- else {
171
- const expectedRuntime = capsule.slots.length > 0 && readyCount === capsule.slots.length ? "ready" : "degraded";
172
- if (capsule.failure_reason !== undefined ||
173
- capsule.runtime_state !== expectedRuntime ||
174
- (capsule.mode !== "shared" && capsule.mode !== "per-bot") ||
175
- capsule.max_instances === null ||
176
- readyCount > capsule.max_instances ||
177
- capsule.source_sha256 === null ||
178
- capsule.dual_view_sha256 === null ||
179
- capsule.source_sha256 !== capsule.dual_view_sha256)
180
- return null;
181
- }
182
- return capsule;
183
- }
184
- function privateCache(path) {
185
- const uid = process.getuid?.();
186
- if (uid === undefined)
187
- return null;
188
- let descriptor = null;
189
- try {
190
- const parentStatus = lstatSync(dirname(path));
191
- const fileStatus = lstatSync(path);
192
- if (parentStatus.isSymbolicLink() ||
193
- !parentStatus.isDirectory() ||
194
- parentStatus.uid !== uid ||
195
- (parentStatus.mode & 0o777) !== 0o700)
196
- return null;
197
- if (fileStatus.isSymbolicLink() ||
198
- !fileStatus.isFile() ||
199
- fileStatus.uid !== uid ||
200
- (fileStatus.mode & 0o777) !== 0o600 ||
201
- fileStatus.size > MAX_CACHE_BYTES)
202
- return null;
203
- descriptor = openSync(path, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
204
- const openedStatus = fstatSync(descriptor);
205
- if (!openedStatus.isFile() ||
206
- openedStatus.uid !== uid ||
207
- (openedStatus.mode & 0o777) !== 0o600 ||
208
- openedStatus.dev !== fileStatus.dev ||
209
- openedStatus.ino !== fileStatus.ino ||
210
- openedStatus.size > MAX_CACHE_BYTES)
211
- return null;
212
- const contents = readFileSync(descriptor);
213
- return contents.length <= MAX_CACHE_BYTES ? contents : null;
214
- }
215
- catch {
216
- return null;
217
- }
218
- finally {
219
- if (descriptor !== null) {
220
- try {
221
- closeSync(descriptor);
222
- }
223
- catch {
224
- // Cleanup failures must not escape the fail-closed cache read.
225
- }
226
- }
227
- }
228
- }
229
- function unknownDigest(reason, freshness = "unknown", receipt) {
230
- return {
231
- schema: SCHEMA,
232
- freshness,
233
- reason,
234
- ...receipt,
235
- runtimeState: "unknown",
236
- mode: "unknown",
237
- maxInstances: null,
238
- readyCount: 0,
239
- slots: [],
240
- ui: {
241
- twoUp: false,
242
- maxVisible: 1,
243
- maxInteractive: 1,
244
- defaultWatchOnly: false,
245
- oneActiveController: true,
246
- },
247
- };
248
- }
249
- export function readOpenMausStatus(options = {}) {
250
- const raw = privateCache(options.cachePath ?? OPENMAUS_STATUS_CACHE_PATH);
251
- if (raw === null)
252
- return unknownDigest("missing_or_insecure");
253
- let capsule;
254
- try {
255
- capsule = validateCapsule(parseJson(raw.toString("utf8")));
256
- }
257
- catch {
258
- capsule = null;
259
- }
260
- if (capsule === null)
261
- return unknownDigest("invalid");
262
- const observed = timestamp(capsule.observed_at);
263
- const freshUntil = timestamp(capsule.fresh_until);
264
- const now = (options.now ?? new Date()).getTime();
265
- const receipt = { observedAt: capsule.observed_at, receiptSha256: capsule.receipt_sha256 };
266
- if (!Number.isFinite(now) || now < observed)
267
- return unknownDigest("clock_skew");
268
- if (now >= freshUntil)
269
- return unknownDigest("stale", "stale", receipt);
270
- if (capsule.refresh_status === "failed")
271
- return unknownDigest("refresh_failed", "fresh", receipt);
272
- const result = {
273
- schema: SCHEMA,
274
- freshness: "fresh",
275
- ...receipt,
276
- runtimeState: capsule.runtime_state,
277
- mode: capsule.mode,
278
- maxInstances: capsule.max_instances,
279
- readyCount: capsule.ready_count,
280
- slots: capsule.slots,
281
- ui: {
282
- twoUp: capsule.ui.two_up,
283
- maxVisible: capsule.ui.max_visible,
284
- maxInteractive: 1,
285
- defaultWatchOnly: capsule.ui.default_watch_only,
286
- oneActiveController: true,
287
- },
288
- };
289
- if (capsule.source_sha256 !== null)
290
- result.sourceSha256 = capsule.source_sha256;
291
- if (capsule.dual_view_sha256 !== null)
292
- result.dualViewSha256 = capsule.dual_view_sha256;
293
- return result;
294
- }
295
- export function openMausStatusSystemPrompt(options = {}) {
296
- const status = readOpenMausStatus(options);
297
- const receipt = [
298
- status.observedAt ? `observed_at=${status.observedAt}` : null,
299
- status.receiptSha256 ? `receipt_sha256=${status.receiptSha256}` : null,
300
- status.sourceSha256 ? `source_sha256=${status.sourceSha256}` : null,
301
- status.dualViewSha256 ? `accepted_dual_view_sha256=${status.dualViewSha256}` : null,
302
- status.sourceSha256 && status.dualViewSha256
303
- ? `source_match=${status.sourceSha256 === status.dualViewSha256}`
304
- : null,
305
- ].filter(Boolean).join("; ");
306
- const runtime = status.freshness === "fresh" && status.reason === undefined
307
- ? [
308
- `runtime_state=${status.runtimeState}`,
309
- `mode=${status.mode}`,
310
- `maximum_instances=${status.maxInstances}`,
311
- `ready_count=${status.readyCount}`,
312
- ].join("; ")
313
- : "runtime_state=unknown; mode=unknown; maximum_instances=unknown; ready_count=0";
314
- const slots = status.slots.length
315
- ? status.slots
316
- .map((slot) => `${slot.slot}(container=${slot.container},readiness=${slot.readiness},network=${slot.network},security=${slot.security},persistence=${slot.persistence})`)
317
- .join(",")
318
- : "none";
319
- return [
320
- "TRUSTED OPENMAUSBOT STATUS (read-only, validated, no transcript or credential data):",
321
- `schema=${status.schema}; freshness=${status.freshness}${status.reason ? `; reason=${status.reason}` : ""}`,
322
- receipt || "receipt=unavailable",
323
- runtime,
324
- `anonymous_slots=${slots}`,
325
- `ui.two_up=${status.ui.twoUp}; ui.max_visible=${status.ui.maxVisible}; ui.max_interactive=1; ui.default_watch_only=${status.ui.defaultWatchOnly}; one_active_controller=true`,
326
- "Opening a viewer or two-up workspace never starts or provisions a VM. Only one pane may be interactive at a time; switching control must release the previous pane before activating the next.",
327
- "Treat missing, stale, failed, clock-skewed, malformed, or receipt-hash-mismatched runtime data as unknown. Do not infer bot identities, viewer URLs, paths, messages, models, accounts, or credentials from this block.",
328
- ].join("\n");
329
- }