| build(release): unify downloads and automate changelog (#673) | 2 个月前 |
| CI: Linux shards run four test files at once Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 10 小时前 |
| Add OSS Scanner build and threat model Anthropic's OSS Scanner builds .oss-scanner/Dockerfile from the default branch, then audits the image with no network and emails findings privately to the SECURITY.md contact. The Dockerfile installs every workspace with pnpm (corepack, frozen lockfile), builds the server bundle and the web UI, and skips Electron and browser downloads. The core security suites pass in it offline. threat_model.md tells the scanner what OpenMausBot is, its trust boundaries, which behaviours are deliberate (Full access by default, no OpenMausBot approval prompts, engine-native permissions), what counts as a vulnerability, how to rate severity, and how to reproduce and patch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 15 天前 |
| fix(openai-chat): parse the leftover buffer on stream EOF (#1377) * test(openai-chat): parse the SSE tail after an unterminated final frame * fix(openai-chat): parse the leftover buffer on stream EOF The SSE reader only parsed complete newline-terminated data: lines. On EOF it flushed the decoder into the buffer but never ran that leftover text through the same line parser, so a final finish_reason/usage frame that arrives as the last bytes before the socket closes (no trailing newline, no [DONE]) was silently dropped: either the turn threw "Stream ended before completion", or, if an earlier frame had already set finishReason, it returned with usage still null. Extract the per-line handling into consumeDataLine() and call it once more on EOF with the leftover buffer, mirroring what the main loop already does per line. * fix(openai-chat): treat a stream cut mid-frame as an end, not a malformed frame The EOF flush this PR adds also ran the malformed-frame path on a truncated tail, which turned a clean stop into a hard failure. `delta-context.e2e` caught it on Windows: offers the results again when the person stops the return turn before the provider acts on it — AssertionError: expected 'failed' to be 'settled' When a person stops a turn (or a connection drops) the socket closes with a partial frame in the buffer. On main that leftover never entered the parse path at all — the `indexOf("\n")` loop cannot fire for it — so the turn settled. With the flush it is parsed, JSON.parse throws, `malformedFrame` is set, and `calls.finish()` throws "provider stream contained a malformed completion frame". An incomplete frame at EOF is expected; only a properly newline-terminated frame that will not parse means the provider sent something bad. So the flush stays and passes `atEof`, which suppresses only that flag. Adds the truncated-tail test that branch never had: a complete finish_reason frame followed by a cut-off one must settle ok. Mutation-checked — dropping the `atEof` guard fails it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> --------- Co-authored-by: omb-dev (lima-snitch) <banana-monkey-tree@users.noreply.github.com> Co-authored-by: Milind Soni <46266943+milind-soni@users.noreply.github.com> Co-authored-by: milind-soni <milindsoni201@gmail.com> Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> | 1 个月前 |
| chore: add .well-known/funding-manifest-urls for funding.json provenance Lists https://mausbot.com/funding.json so fundingjson.org / FLOSS/fund crawlers can verify that this repository belongs to the manifest's entity. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> | 13 天前 |
| Merge #4429 at c775e804a # Conflicts: # scripts/ci-scope.mjs # server/drivers/agents-catalog-goldens/bridged.profiles.json # server/drivers/agents-catalog-goldens/profiles.json # server/drivers/agents-catalog-wire.test.ts # server/index.ts | 9 小时前 |
| fix(linux): skip the optional AppArmor 4 policy only on unrestricted hosts (#3876) The .deb postinst skipped the browser's optional allowlist only when the userns restriction sysctl was absent. Ubuntu 22.04 + HWE exposes the sysctl set to 0, so the hook still installed an abi/4.0 policy that AppArmor 3.0 cannot parse, aborting package configuration. Key the skip on the restriction value instead: a host with the restriction enabled still fails closed when the policy cannot be loaded. | 6 天前 |
| Security: better-auth 1.7.7 and happy-dom 21.0.4 (#4010) * Security: better-auth 1.7.7 and happy-dom 21.0.4 better-auth 1.7.1 -> 1.7.7 in the control plane (GHSA-965c-763c-88jm / CVE-2026-114607: OAuth state accepted as a Magic Link token) and happy-dom ^20.14.5 -> ^21.0.4 for tests (GHSA-834v-8h66-3h79 / CVE-2026-115895: unvalidated ESM import aliases ran code on the host). The lockfile is regenerated with pnpm against registry.npmjs.org. Better Auth 1.7.3+ validates the schema as each auth instance starts and makes auth requests wait on it. The control plane makes an instance per request, so that is one more D1 round trip per request; turn it off, since the pinned migrations fix the schema. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Control plane: drop the account.issuer column Better Auth 1.7.3+ never writes 0001 created account.issuer NOT NULL with a unique index for Better Auth 1.7.1. From 1.7.3 Better Auth restored the 1.6 account schema and never writes issuer, so every new account row would be refused. 0011 applies Better Auth's SQLite cleanup from its 1.7 upgrade guide: drop the index, then the column. A test writes an account row on the migrated schema. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 4 天前 |
| Test ports: each vitest worker picks from its own (#4412) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 12 小时前 |
| MausBot connector: run a Cloud home on its owner's own server, over one outbound connection (#3732) A new connector/ folder, published with every release as ghcr.io/milind-soni/mausbot-connector for linux/amd64 and linux/arm64. - install.sh (curl ... | sudo sh -s -- <code>) checks the server, and says how to fix each failure in plain words: operating system, x86-64, Docker 24+ (offering to install it), AppArmor, user namespaces, CPU, memory, disk, network and clock. It installs the bot box's AppArmor and seccomp profiles, starts the connector, runs the box probe and enrols with the one-time code. Running it again repairs. uninstall never deletes the data unless --delete-data is typed. - The connector enrols once, then holds one WebSocket to the Admin, re-opened with backoff. Every 30 s it sends a heartbeat: host health, and the home's state, image and signed health. It runs only the protocol's jobs: start, stop, restart, update, status, backup, restore, export-disk, import-disk, host-health and self-update. - There is no shell, arguments are checked, and images must be our registry's, by digest. - Replies are sent again on each connection until the Admin acknowledges them. - update copies /data aside, swaps the container, and waits up to 10 minutes for the new image's signed health. Otherwise it puts back the previous image and the copy. - A home that stopped on its own is started again. Until the image clears it itself, the connector first clears the data-directory lease a killed home leaves. - self-update keeps the running connector until the new one has connected; one atomic rename settles which one won. - The agent token and the home's environment are kept 0600 in the state volume and never logged. - connector/src/protocol.ts holds the message types and checks, for the Admin side to copy. Tests: unit tests with a fake Docker, and a fake Admin over a real WebSocket. An end-to-end run on a stock Ubuntu 24.04 runner (connector-e2e.yml) covers install, start with the box at 32/32, update, an unclean kill, a forced rollback and uninstall. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 |
| Own-server homes: trust only the tunnel to name a client, and start again after an unclean kill (#3727) * Own-server homes: trust only the tunnel to name a client, and start again after an unclean kill The edge's client-address header and trusted peers now come from the launcher. On Fly (FLY_APP_NAME is set) it is Fly-Client-IP from Fly's private ranges, exactly as before. On an own server it is Cf-Connecting-IP, only from the home's own loopback, where the Cloudflare tunnel connects from; a header from any other peer is ignored. A header forged through the published port no longer gets a fresh pairing-lockout count. A home killed uncleanly on Docker never started again on its volume. Every container on a host shares the boot id and its pids start again from 1, so the next server took the dead one's lease for a live process: its own. Lease records on Linux now name their pid namespace and their process's start time. A record from another container is never judged by this one's pids, and a reused pid is not its owner. The launcher locks the volume (flock on its root) for as long as it runs, so a second home beside a live one refuses to start, and with the volume held it clears the records another machine or container left. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Test the edge's client-address settings the same on a Windows (CRLF) checkout Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 |
| Merge pull request #4449 from milind-soni/train/nov4-c Train 3: customer fixes, waiting-on-you, the inbox and the send cap (merge with Create a merge commit) | 2 小时前 |
| Merge #4354 at 102071aa8 | 9 小时前 |
| Cleanup: delete comments in shared, scripts, companion and Cloudflare Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 21 天前 |
| evals: a small live tool-choice eval, and why the tool bridge stays off by default Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 17 小时前 |
| feat(web): support an installable phone web app | 24 天前 |
| Merge pull request #4449 from milind-soni/train/nov4-c Train 3: customer fixes, waiting-on-you, the inbox and the send cap (merge with Create a merge commit) | 2 小时前 |
| Merge pull request #4449 from milind-soni/train/nov4-c Train 3: customer fixes, waiting-on-you, the inbox and the send cap (merge with Create a merge commit) | 2 小时前 |
| Merge pull request #4449 from milind-soni/train/nov4-c Train 3: customer fixes, waiting-on-you, the inbox and the send cap (merge with Create a merge commit) | 2 小时前 |
| feat(skills): social post previews, with local videos that play in the chat (#4209) * feat(skills): social post previews, with local videos that play in the chat A bundled skill: a bot fills in posts.html and shows how a post looks on Instagram, LinkedIn, X, Threads, Facebook, TikTok, Reels and Shorts, with carousels, quiet checks sourced from each platform's docs, and light and dark. A video in a folder page stays on disk: show_html records its path and file identity, and the page files route streams only the asked-for bytes from the open handle while it is still that same file. Publishing leaves video out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(skills): read the template's data block on a CRLF checkout too Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 2 天前 |
| Merge pull request #4449 from milind-soni/train/nov4-c Train 3: customer fixes, waiting-on-you, the inbox and the send cap (merge with Create a merge commit) | 2 小时前 |
| feat(skills): social post previews, with local videos that play in the chat (#4209) * feat(skills): social post previews, with local videos that play in the chat A bundled skill: a bot fills in posts.html and shows how a post looks on Instagram, LinkedIn, X, Threads, Facebook, TikTok, Reels and Shorts, with carousels, quiet checks sourced from each platform's docs, and light and dark. A video in a folder page stays on disk: show_html records its path and file identity, and the page files route streams only the asked-for bytes from the open handle while it is still that same file. Publishing leaves video out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(skills): read the template's data block on a CRLF checkout too Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 2 天前 |
| feat(self-hosting): add full-stack rootless Podman deployment (#849) Co-authored-by: milind-soni <milindsoni201@gmail.com> | 1 个月前 |
| feat(deploy): add configurable local Docker Compose setup (#838) * feat(deploy): add configurable local Docker Compose setup * fix(deploy): reap orphaned agent processes with Docker init * fix(compose): address healthcheck and HTTPS trust review | 1 个月前 |
| MausBot connector: run a Cloud home on its owner's own server, over one outbound connection (#3732) A new connector/ folder, published with every release as ghcr.io/milind-soni/mausbot-connector for linux/amd64 and linux/arm64. - install.sh (curl ... | sudo sh -s -- <code>) checks the server, and says how to fix each failure in plain words: operating system, x86-64, Docker 24+ (offering to install it), AppArmor, user namespaces, CPU, memory, disk, network and clock. It installs the bot box's AppArmor and seccomp profiles, starts the connector, runs the box probe and enrols with the one-time code. Running it again repairs. uninstall never deletes the data unless --delete-data is typed. - The connector enrols once, then holds one WebSocket to the Admin, re-opened with backoff. Every 30 s it sends a heartbeat: host health, and the home's state, image and signed health. It runs only the protocol's jobs: start, stop, restart, update, status, backup, restore, export-disk, import-disk, host-health and self-update. - There is no shell, arguments are checked, and images must be our registry's, by digest. - Replies are sent again on each connection until the Admin acknowledges them. - update copies /data aside, swaps the container, and waits up to 10 minutes for the new image's signed health. Otherwise it puts back the previous image and the copy. - A home that stopped on its own is started again. Until the image clears it itself, the connector first clears the data-directory lease a killed home leaves. - self-update keeps the running connector until the new one has connected; one atomic rename settles which one won. - The agent token and the home's environment are kept 0600 in the state volume and never logged. - connector/src/protocol.ts holds the message types and checks, for the Admin side to copy. Tests: unit tests with a fake Docker, and a fake Admin over a real WebSocket. An end-to-end run on a stock Ubuntu 24.04 runner (connector-e2e.yml) covers install, start with the box at 32/32, update, an unclean kill, a forced rollback and uninstall. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 |
| chore: remove the Teach a skill recorder for now (#1034) * chore: remove the Teach a skill recorder for now The screen-and-narration recorder was not finished enough to ship, so the page, its Electron bridge, the Recorder.app build step and the AssemblyAI narration settings go. Bots can still draft skills for review: the flag becomes features.skillAuthoring (migrated once at startup), /learn and skill_manage staging are unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: milind-soni <milindsoni201@gmail.com> * chore(package): exclude every stale recorder-helper artifact from the bundle package:prepare does not clean electron/resources, so a machine that once ran build:recorder could still ship the loose helper files alongside the app. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Signed-off-by: milind-soni <milindsoni201@gmail.com> --------- Signed-off-by: milind-soni <milindsoni201@gmail.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 1 个月前 |
| refactor: simplify duplicated runtime and tooling (#604) | 2 个月前 |
| AGENTS.md: when to write a comment, and a guard against history in comments Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 21 天前 |
| chore(contributors): remove mandatory DCO sign-off (#1029) | 1 个月前 |
| Contributor infrastructure: vitest suite, CI, contributing guidelines - 51 tests: registry shadow-downgrade, event bus invariants, store persistence, claude/codex driver contracts against scripted fake CLIs (canonical event stream, argv/env hygiene, interrupts, permission broker over its socket), and an API smoke test that boots the real server against a throwaway home dir - server/testing/: in-memory fake driver + env-var-driven fake claude stream-json CLI and fake codex app-server; event recorder that waits on events instead of sleeping - CI on macOS/Linux/Windows (the windows leg is the guardrail for the in-progress Windows port; POSIX-only spawn tests self-skip there) - CONTRIBUTING.md (dev setup, driver SPI checklist, platform + secrets rules), CODE_OF_CONDUCT.md, SECURITY.md, issue forms, PR template - test files excluded from the dist-server build; engines + packageManager pinned Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> | 2 个月前 |
| Pre-push checks only what a push changes, in seconds (#4415) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 12 小时前 |
| fix(docker): build and publish the server image for linux/arm64 (#4263) * fix(docker): build and publish the server image for linux/arm64 The Dockerfile fetched Chrome for Testing, which has no Linux ARM64 build, and copied the x64 DuckDB tree, so `docker build` failed on a Raspberry Pi or ARM server. The JavaScript build now runs once on the build host's CPU; the DuckDB tree and the browser follow the image's CPU (Debian's Chromium on arm64, linked at the same path). CI boots the arm64 image on GitHub's ARM runner, and publish pushes the server image for amd64 and arm64. The Cloud home image stays amd64. Closes #4060 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Key the arm64 Chromium layer on Debian's newest bookworm build Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> Co-authored-by: Milind Soni <46266943+milind-soni@users.noreply.github.com> | 1 天前 |
| Adopt Apache License 2.0 (#291) * Adopt Apache License 2.0 * Complete Apache-only relicensing | 2 个月前 |
| docs(licensing): name Supamaus Software Private Limited as trademark owner (#2293) The OpenMausBot and MausBot names and the mascot are trademarks of Supamaus Software Private Limited, not an individual. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 29 天前 |
| Move from Grok Bot: one popup, one dialog, no sign-in (#4306) * Move from Grok Bot: one full-window flow, no sign-in and no network Each Bot writes its own setup; the person brings it back found in Downloads, pasted or dropped, sees what comes over, and gets a checklist of what is left. Replaces the share link, the public card fetch, Sign in with Cursor and the finish-setup screen. An old cursor-session.json is deleted at start. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: lint and locale hash cleanup Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: Settings → Import in a browser too; the flow holds focus Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: welcome-screen tests, plain-words check, ordinary colours only Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: clamp the instructions preview to two lines Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: say why a found Bot can't be read, keep what a partial add brought, take drops anywhere Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: the flow is a rarely opened screen, not preloaded Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: one button in Settings, one dialog, the plain flow Copy the message, bring back the reply, preview, import, report. Removes the onboarding entries, the Templates card, the full-window screens, the checklist and the sign-in rows. Skills come on unless the skill scan flags them, event routines go to a notes file in the bot's memory, routines are named <Bot>: <routine>, and an existing server or an already moved Bot is a conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: plain words in the dialog's reasons Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: a once-only popup, and the dialog cut to names and counts The popup goes first in the once-only notices queue: after the welcome on a new install and at the next launch otherwise, with Let's start opening the same dialog. It reads nothing on this computer. The preview and the report are now the Bot's name, a count per kind and a few plain lines. Nothing reads the Grok Bot app's chats any more, only its list of Bots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 |
| Agents tools: delete_trigger on its own, memory_log back, and merged tools name what they were (#3786) * agents tools: advertise compact schemas, hold every call to the full one callTool now checks every call against the tool's full input schema before anything runs: lengths, numeric bounds, item counts, repeats and patterns, at any depth, with a null read as a field left out. A call out of bounds is refused in words that name each field and its limit. tools/list then leaves out only bounds that check enforces and the model does not need: non-empty and non-negative floors, limits the description already states, and caps no sensible value comes near (200 characters, 32 items). Free-form objects keep additionalProperties: true for Moonshot. Where a tool already caps or cuts a value itself (assignment_status wait_ms, vm_exec timeout, session_search limit, and four reasons or search strings), the bound comes out of the schema so a quiet cap does not turn into a refusal. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: merge tool families into action tools of one access class Twelve tools fold into the tool beside them, each merge inside one access class, so nothing a bot could only read can now change anything: - list_triggers + list_trigger_events -> trigger_info (read-only: list, events) - create_trigger + manage_trigger -> trigger (create, update, pause, resume, run_now, delete); the trigger fields are written once, not twice - create_room -> manage_room action create (Chief-only, as both were) - memory_log -> memory_update action log - session_read -> session_search with a hit's thread_id and message_id (read-only) - update_widget -> show_widget with widget_id; update_html -> show_html with app_id - x_user_posts, x_post, x_profile -> x_search action user_posts, post, profile Every old name still runs: callTool and the proxy resolve it to the same call of its action tool, only where that tool is listed; the chat runtime answers it unlisted; find_tool reads it as its tool. A tool selection keeps meaning what it meant: a selector naming an old tool allows or refuses exactly those calls, now checked per call with its arguments on every engine path (gate, Pi, chat runtime). Outbound tools (post_to_room, publish_page, send_voice_note) keep their own names. Prompts, results, docs, the dashboards skill and Activity labels use the new names; two chip labels are added in all 15 languages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: list fewer tools on turns that cannot use them Two more switches in a turn's agents profile, each listing only what the server would let that turn do: - OMB_COMPUTER_SELECTION: select_computer is listed only on a person's own request that may pick its computer, the same turns the selection route accepts. A hand-off, a routine or webhook run, a continuation, a room and an external runtime are refused a selection, so they are not shown it. - OMB_ROOM: a room's turn is not listed show_widget or show_html, which a room refuses. Both switches ride the HTTP mount's settings too, so an engine reaching the agents server over HTTP is listed the same tools. The Chief's setup tools stay on hand-offs: a teammate is told to send team setup to its Chief with coordinate_bots, which arrives as a hand-off. The catalog tests gain a room turn and a hand-off turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: lock in the smaller catalog Regenerated the goldens and lowered every BUDGET_BASELINE to the bytes now measured, so the saving cannot creep back. Three bridged baselines were already below what main measured and stay where they are. memory_update's log sentence is shorter, so a bridged turn, which lists memory_update, ends no larger than before. The fullest profile goes from 59 tools and 75,018 bytes to 49 tools and 65,045 bytes; a Chief's default turn from 45 tools and 63,098 bytes to 38 and 54,089; a non-Chief's from 37 and 53,167 to 31 and 45,050. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * agents tools: no remembered allow reaches further; merged tools name what they were An engine that remembers "always allow" by a tool's name must not let one answer cover more than each of the tools that merged did on its own: - delete_trigger is its own tool (manage_trigger's delete). trigger keeps create, update, pause, resume and run_now, and refuses a delete before anything is sent; delete_trigger only ever deletes. - memory_log is its own tool again: inside memory_update, an allow given for a log line would have covered remove and forget. A test holds every action tool to it: each one's furthest call reaches no further than each of its members did alone, and its actions match the table. In a tool selection, manage_trigger still covers deleting. Each merged tool's description now names its old tools, e.g. "(was create_trigger / manage_trigger)", so a model following a saved skill finds it on engines that refuse unlisted names. The aliases move to shared/agents-tool-names.ts, one table for the call path and selection. Goldens regenerated. Every catalog profile stays within 2% of its baseline, so none is raised; every bridged baseline is lowered to the measured bytes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 |
| Merge remote-tracking branch 'origin/main' into chain/fix-usage-spend-packaging # Conflicts: # server/index.ts | 1 个月前 |
| Cancel trial / Cancel plan with a short survey on the plan card (#3747) Customers couldn't find how to cancel: the plan card only said Manage in your browser. Now, for the account that pays for a plan that runs, the plan card says Cancel trial (during a free trial) or Cancel plan, in this computer's Settings (Usage & billing, Plan in Simple mode; MausBot Cloud in Advanced) and on the Cloud's own page in home mode. Its sheet asks the main reason with one-tap chips, offers two optional boxes (what they expected, what we could have done better) and a call with Milind, and never needs an answer to cancel. After: when it ends, that nothing more is charged, how long its files are kept, and Keep my plan. - Main reads the plan's renewal from the session's own primary Cloud (parseCloudRenewal); the Cloud's id stays in main. - cancelPlan sends the survey first (8 s, let go on any failure), then the cancel for the session's own Cloud; keepPlan turns renewal back on. The page sends only the survey's words: cloudAccount.cancelPlan/keepPlan here, cloudPlan.cancel/keep on the Cloud's page (only from the person's click). - An Admin without the routes (its own 404, 405 or 501) opens the Cloud page's billing instead; one that sends no renewal keeps today's card. - 41 strings in every locale; a dev-only preview page (cancel-plan-preview.html). Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 |
| Dev-only gallery of the Cloud sheet's states cloud-buy-preview.html (like onboarding-preview.html: served by the Vite dev server, never in the build) renders the real sheet over a mock window in any state and skin: ?state=choose|sign-in-email|sign-in-code| sign-in-wrong|sign-in-sso|sign-in-done|pay|pay-late|setup|ready|has-cloud| unreachable&skin=<any of the nine>&staging=1. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 19 天前 |
| fix(browser): a bot's browser really closes, closes when idle, and nothing a crash leaves keeps running A team of 5-25 bots can run headless on one machine, each with its own built-in browser: an agent-browser daemon and its Chrome. agent-browser detaches both (setsid, and Chrome in a process group of its own), so whatever OMB does not close runs on: for the engine's one-hour idle, or for ever once a daemon was killed under its Chrome. Measured on this Mac with the bundled engine: 10 browsers a crashed server left (50 processes, 2.4 GB) and 10 Chromes whose daemons were killed (40 processes, 2.2 GB) ran on after the next start; now both are gone. - close verifies: it answers true only once the engine no longer lists the daemon and nothing of the process tree read before the close runs. Past the deadline the daemon gets TERM first, alone, so it can still save the sign-ins from its Chrome; the rest is killed by process group, and a process in no group of the tree's own by its pid (Windows: taskkill /T). Every pid is matched by start time; zombies count as gone; a stopped Chrome's temporary profile folder is removed as the daemon would have. Linux reads /proc, so the slim image without ps works the same (server/browser-processes.ts). - close is never sent to a browser that is not running: the CLI started a daemon just to stop it and left its .config file behind. The control environment still carries no launch flags, so close never launches. - BrowserSweep (browser-lifecycle-cleanup.ts), at boot, every minute and at shutdown: closes this data dir's browsers nothing here uses (a crash's leftovers), stops Chromes whose daemon was killed (found by the session their environment names) and closes idle ones. It replaces the shutdown- only closeServerBrowsers. Temporary sessions carry a data-dir tag so a crash's leftovers are still recognisably ours; nothing else under the same HOME, and never My Chrome, is touched. - Idle close after browserEngine.idleTimeoutMinutes (1-60, default 10): never while a turn holds the browser, a bot call (a tool listing included), a person's hold or input, or an open Browser panel uses it. A browser a turn registered but never called counts from the sweep's first look. Saved sign-ins are kept; the bot's next call reopens it and is told its pages are gone. - Docker and Podman compose files: init: true and shm_size: 512m, as the desktop containers; documented in docs/browser-packaging.md. Without an init, 41 exited browser processes were never collected in OMB's image. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 22 天前 |
| Windows: lend a PC's apps and screen, say plainly when it can't, and let a Cloud's bot ask to turn it on (#3950) * ci(windows): start computer control as the installed app does and lend it A Windows smoke that runs electron/cua.mjs's packaged branch unchanged, in Electron's main process, then takes a Cloud's first look at the PC through the lend path (computer_tools, get_screen_size, list_apps). It reports the driver's mode and whether apps and screen would be lent, and sends no input. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(windows): settle each answer with a statement in the lend smoke Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(windows): lend a PC's apps and screen, say plainly when it can't, and let a Cloud's bot ask to turn it on Computer control on Windows starts once, at launch. When it didn't (a helper Windows Security stopped, or a slow first start), nothing tried again, nothing was recorded (the driver's error carried only its kind, and console output is lost in the packaged app), the app showed nothing and reported Windows as unsupported, and a Cloud's bot was told to have the person "check computer control", which no Windows screen offers, then offered its own cloud computer. - Computer control keeps the reason Windows gave and logs every change to the app's log. On Windows a start that failed for a passing reason is tried again by itself, twice; a blocked or missing helper waits for the person. - The taskbar or menu-bar icon says what the Clouds can't use and why, with the one fix ("Screen control isn't running on this PC", Start screen control). The Computer panel on a PC says the same with a Start button. - A Cloud's bot that needs the person's computer and can't use it calls ask_for_computer: one card with what it wants and why, the reason, and a one-tap Turn on (resume, start screen control, ask macOS, or run commands after the computer's own confirmation), or Get MausBot when the app there is closed, missing or too old. The app on that computer, paused or not, hears the ask and shows its own prompt once, one at a time; the first answer wins. Once the computer lends what was needed the bot's waiting call returns, or its request goes on by itself. Only on the person's own Cloud. - Every "not available" answer a bot gets there points it at the card, and the Cloud prompt says never to switch to its cloud computer unless asked. - The person can keep writing while a Turn on card waits. - CI's Windows CUA job runs for changes to the modules it starts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(lending): a neutral computer name in the ask tests Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(lending): the help names the PC's screen-control status and the Turn on card, in the app's words Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(windows): the lent screen's driver gets Windows' own folders cua-driver 0.28.2 keeps its settings, history and cursor themes under LOCALAPPDATA and APPDATA; the lend path started its proxy without them. They hold no secret, and the app's keys still never reach it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(windows): the lend smoke reports the lending decision the app makes, with why and the fix Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * ci(windows): on a pull request the lend smoke runs the base branch first, so one run shows the change Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(lending): screenshots of the PC's status and the Turn on card, light and dark Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(lending): the ask's internal route answers from its own module, so server/index.ts gains no route Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Windows Defender check: build the real installer, install it like a download, and report what Windows Security does A hand-run job on a fresh GitHub Windows machine (workflow_dispatch, or the "defender-check" label on a pull request while the workflow isn't on main): builds the NSIS installer the way the release's Windows job does, turns Defender's protection on the way a home PC has it (GitHub's image turns most of it off and excludes every drive), saves the installer to Downloads with a browser's Zone.Identifier (ZoneId=3), scans it, installs it silently (first the way a double-click starts it), opens the app for two minutes and presses Start screen control through the app's DevTools port. The summary and the defender-check artifact say what the machine allowed, Defender's detections and Operational events 1116, 1117, 1006-1008 and 1015, whether cua-driver-background.exe runs, the app log's computer-control lines and whether Start screen control worked. The run fails when Windows Security flagged the app or screen control doesn't run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Windows Defender check: show what holds a downloaded installer, and check Defender's cloud When the double-click start of the downloaded installer is still waiting after 30 s with no installer running, the check records the windows on screen, whether SmartScreen runs and a screenshot, then stops waiting instead of sitting out five minutes. It also records Defender's cloud connection (MpCmdRun -ValidateMapsConnection), the signatures' age, what GitHub's passive-mode policy means on a machine Defender reports in Normal mode, and a screenshot of the app after two minutes. A workflow test keeps the check's build step for step the same as the release's Windows job. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Windows lend smoke: read electron-builder.yml the same with CRLF line endings git checks electron-builder.yml out with CRLF on a Windows runner, so the smoke found none of the CUA resources it places and stopped before starting anything (the first CI run that reached the Windows CUA job). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 4 天前 |
| Move from Grok Bot: one popup, one dialog, no sign-in (#4306) * Move from Grok Bot: one full-window flow, no sign-in and no network Each Bot writes its own setup; the person brings it back found in Downloads, pasted or dropped, sees what comes over, and gets a checklist of what is left. Replaces the share link, the public card fetch, Sign in with Cursor and the finish-setup screen. An old cursor-session.json is deleted at start. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: lint and locale hash cleanup Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: Settings → Import in a browser too; the flow holds focus Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: welcome-screen tests, plain-words check, ordinary colours only Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: clamp the instructions preview to two lines Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: say why a found Bot can't be read, keep what a partial add brought, take drops anywhere Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: the flow is a rarely opened screen, not preloaded Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: one button in Settings, one dialog, the plain flow Copy the message, bring back the reply, preview, import, report. Removes the onboarding entries, the Templates card, the full-window screens, the checklist and the sign-in rows. Skills come on unless the skill scan flags them, event routines go to a notes file in the bot's memory, routines are named <Bot>: <routine>, and an existing server or an already moved Bot is a conflict. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: plain words in the dialog's reasons Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Move from Grok Bot: a once-only popup, and the dialog cut to names and counts The popup goes first in the once-only notices queue: after the welcome on a new install and at the next launch otherwise, with Let's start opening the same dialog. It reads nothing on this computer. The preview and the report are now the Bot's name, a count per kind and a few plain lines. Nothing reads the Grok Bot app's chats any more, only its list of Bots. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 |
| fix(page): the page opens with the product's name as its title (#4187) The title stayed OpenMausBot until /api/brand answered, and for good if it failed. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 2 天前 |
| Maus: morphing face engine on the existing lit body (#31) The mascot's face was ten hand-drawn SVG blocks with no motion of their own — everything moved via the CSS motion library around them. This swaps the face for the GrokBot morph engine while keeping that body and library untouched: 25 expressions as 48-point rings per eye, spring-interpolated, 39 named states each with an expression pool, drift cadence and blink rhythm, plus gaze and a spherical turn. The silhouette is identical on both sides (MAUS_PATH is the app's BODY), so only the coordinate frames differ. FACE_TO_BODY inverts the engine's fit and reapplies the rotation the body already carries, derived from MAUS_FIT_SCALE/OFFSET rather than eyeballed. It has to be expressed in pre-rotation space, so the face group nests inside .maus-solid: that group is styled `transform-box: view-box; transform-origin: 100px 100px` while also carrying a transform attribute, and browsers apply the CSS origin on top of the attribute's own rotate-about-point. The body is really drawn at translate(-28.17 40.23) of where the attribute alone puts it, which is what the viewBox is framed around. Nesting the face under the same group inherits that instead of fighting it. Faces now look at you. Each of the 25 expressions was authored at its own longitude on the implied sphere (-25.6° to +48.9°), so at turn 0 the maus faced wherever its current expression happened to be drawn — `idle` rests at +27.6°, a permanent glance right. centreOffset() cancels the pair's longitude so turn 0 means forward and `turn` measures from there. It reads the live morphing rings, so the face stays forward through an expression change rather than swinging as each new one lands, and only the pair is re-centred — each eye keeps its authored position, so the expressions stay distinct. Off via `forward={false}`. Geometry was measured, not guessed, by hit-testing all 25 expressions against the silhouette: faceScale clips past 0.4937 (so 0.47 stays), eyeScale past 1.336 and mouthStroke past 22.7 with authored gaze, rising to 1.812 and full gaze once centred. The face therefore cannot get bigger, only bolder — hence eyeScale 1.12 and mouthStroke 11, both clear in either mode. One rAF drives every avatar instead of one per instance, and a settled face is not redrawn; 163 avatars hold 60fps. Also: - states replace the ten expression names, with live bot state routed to states the old set could not express (busy -> working, tool failure -> alerting, unread -> notifying). Bots saved under the old names are translated on read by normalizeState(), so a downgrade survives. - the appearance picker offered 15 states showing 8 pictures, since states share resting faces and differ only in what they drift to. It now lists one state per distinct face. - the motion preview grid is gone: motions already have 13 real triggers in the reducer, and it was the sole dispatcher of previewMascotMotion. - mascot-preview.html is a dev-only tuning harness (Vite builds only index.html) with live geometry sliders and every state and motion. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com> | 2 个月前 |
| feat(deploy): add configurable local Docker Compose setup (#838) * feat(deploy): add configurable local Docker Compose setup * fix(deploy): reap orphaned agent processes with Docker init * fix(compose): address healthcheck and HTTPS trust review | 1 个月前 |
| feat(onboarding): welcome flow, feature reel, and guided tour for new users (#1056) * feat(onboarding): welcome flow, feature reel, and guided tour for new users Replace the four-step onboarding dialog with a three-layer first run: - Welcome flow: one card that morphs between beats (hello, reel, engines, permissions, phone, meet your bot) with view transitions and the mascot as a single guide. Engines step rebuilt as one list with status pills. - Feature reel: six scenes drawn in code (agents, hands, apps, channels, automations, terminal), each reporting mascot cues. No media to ship. - Guided tour: spotlights on the live interface with Next on every step. It opens the Tools menu and points at items before opening the pages behind them, opens and closes the Computer panel, and returns to the chat at the end. Progress persists in the server's onboarding record so a reload resumes on the same step. - First-conversation spotlights for the first approval and connect-app cards. Persistence moves from localStorage to an `onboarding` block in the server config (completedAt, version, reelSeen, hintsSeen), with one release of grace for installs that finished the old gate. Settings gains replay entries for both tours. A dev gallery at onboarding-preview.html renders every beat in every skin. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0113vCkNqDK2wqDzCyWihBHZ * fix(onboarding): slide the spotlight between tour steps instead of remounting The guided tour remounted its spotlight on every step, so each Next dimmed the whole window again and eased back down to the next control, which read as a stutter on the desktop app. The spotlight now stays mounted: the cutout and the card slide to the new anchor on transform, and a new anchor that is not on screen yet keeps the previous rectangle until it appears. The card's entrance keyframes moved to an inner layer, since their final `transform: none` overrode the positioning transform. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0113vCkNqDK2wqDzCyWihBHZ * fix(server): do not rebuild the provider fleet on onboarding writes Every config write whose keys were not on the fleet-neutral list disposed and reloaded every engine child, which takes seconds on a real install. The guided tour writes `onboarding` on every step, so each Next click stalled for four to five seconds on the desktop app. The fixture's fake engine hid it. The rule moves into config.ts as `providerReloadKeys` with `onboarding` added to the neutral set, and gets a test. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0113vCkNqDK2wqDzCyWihBHZ --------- Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> Co-authored-by: milind-soni <milindsoni201@gmail.com> | 1 个月前 |
| Make a server of your own your bots' home, as My Cloud is (#3948) * Make a server of your own your bots' home, as My Cloud is A person with bots on this computer and on their own server had two places whose bots could not work together, and bringing them together meant a backup export and import by hand. Now a server of their own offers "Make <server> my home" on its circle: one tap moves this computer's bots, chats, memory, skills, logins, apps and keys, and routines there with the same one-time move My Cloud uses (copy, quiet moment, freeze, final pass, check, switch), its "needs you / Try again" line included. This computer then stops for good, so no routine runs twice, and it works for that server by itself as it does for My Cloud: no access dialog, only the menu bar item and Pause. Only for a server that is the person's alone: an admin session where the sign-in list names no members and no other admin, never a Cloud, a team's Cloud or a hosted workspace. Such a server says so on /api/auth/session (`own`), takes the move's routes from that session, and turns lending on once a move arrived. Any other server keeps today's explicit "Share this computer?" flow. Connected apps through MausBot's service stay on this computer when the server has no such service, so the move's check still passes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * test(remote sessions): a server nobody else signs in to says before pairing that it takes its owner's move Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 5 天前 |
| chore(release): bump version to 0.1.140 (#4315) * chore(release): bump version to 0.1.140 * chore(release): keep ChatView's limit at its real size after main moved Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: milind-soni <milindsoni201@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 1 天前 |
| Security: better-auth 1.7.7 and happy-dom 21.0.4 (#4010) * Security: better-auth 1.7.7 and happy-dom 21.0.4 better-auth 1.7.1 -> 1.7.7 in the control plane (GHSA-965c-763c-88jm / CVE-2026-114607: OAuth state accepted as a Magic Link token) and happy-dom ^20.14.5 -> ^21.0.4 for tests (GHSA-834v-8h66-3h79 / CVE-2026-115895: unvalidated ESM import aliases ran code on the host). The lockfile is regenerated with pnpm against registry.npmjs.org. Better Auth 1.7.3+ validates the schema as each auth instance starts and makes auth requests wait on it. The control plane makes an instance per request, so that is one more D1 round trip per request; turn it off, since the pinned migrations fix the schema. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * Control plane: drop the account.issuer column Better Auth 1.7.3+ never writes 0001 created account.issuer NOT NULL with a unique index for Better Auth 1.7.1. From 1.7.3 Better Auth restored the 1.6 account schema and never writes issuer, so every new account row would be refused. 0011 applies Better Auth's SQLite cleanup from its 1.7 upgrade guide: drop the index, then the column. A test writes an account row on the migrated schema. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 4 天前 |
| Update dependencies with published security advisories dompurify 3.4.17 (through mermaid), fast-uri 3.1.9 (through ajv), zod 4.6.7, and Next.js 16.4.3 for the docs site. What remains in pnpm audit --prod is test and docs build tooling (vitest's happy-dom, the docs site's vite), which never ships. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 9 天前 |
| A decision a bot asks you is a tap-to-answer card, and questions and approvals get one calm card (#3777) * Bot-coloured main buttons: Send, Allow and the answers a bot waits for The composer's Send button and the primary answer on a bot's cards now use that bot's own colour, the same flat fill and ink as its Simple bubble (userBubbleTone), in Advanced and Simple mode and on the phone layout. - Composer: Send (and Simple's round Stop) use the bot's colour. A room keeps the accent, as its composer already does. - Approvals in the composer: Allow once / Confirm / Enable take the colour of the bot that asked. Deny, Cancel and Always allow keep their looks. - Question, key, sign-in and connect cards in a chat or a room: Submit, Save securely, Done and Connect securely take the asking bot's colour. - Team inbox: Allow on the chat's card and in the panel, and the reply Send, take the colour of the bot the line is from; a teammate's line stays plain. One mechanism: src/lib/bot-button.ts reads the bubble tone and sets four custom properties; an unlayered .bot-button rule paints from them, so the Midnight/Daylight neutral primary pill and the accent utilities never repaint it. Hover and press step the fill away from its ink, so the label only gains contrast; focus is a 2px ring in the skin's focus colour, 2px off the fill; disabled uses the same quiet colours as a disabled accent button. Tests: bot-button.test.ts checks every preset colour in every skin (label on rest, hover and press at 4.5:1 or better, focus ring 3:1 on the app, card, composer and panel surfaces, disabled label 3:1), and the composer, card and inbox tests check the buttons carry the asking bot's tone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * refactor(host): move the waiting-on-the-person chips and the park port out of server/index.ts A pure move into server/host/ask-cards.ts: the chip a delegating conversation gets while its teammate waits on the person, its settle, and the coordinator's park port. Function bodies are unchanged; their singletons come in as deps. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(runtime): a teammate asks a decision with set answers as a card, and its NEEDS INPUT question becomes one too A bot doing work another bot handed it is told to ask a decision with a few set answers (yes or no, or "only this / also that / no") with its engine's question tool, writing the choices itself in the person's language, and to keep NEEDS INPUT for open questions. The envelope names the tool only when the engine has one and the bot's tool selection keeps it: ask_user on Claude, Pi and the chat runtimes, and an ACP agent's own question tool where it has one (askTool, a new engine capability). The card is the ordinary question card, so on a Team Cloud its copy reaches the person's inbox with the same choices and a tap there answers the bot, which carries on with that answer in the same turn. - A NEEDS INPUT question a teammate parks on becomes a question card with a reply field in its conversation, in place of the line (the line keeps the words before it). It goes out as a question, so on a team its copy reaches the person's inbox too, and an answer from the card, the copy or a line in the chat answers the waiting work. Stop and an expired wait close the card with their own state (OptionCardData.stopped, expired). - A line the person types while the bot's turn waits on its own question card answers that card, as a tap would; so does a reply to the card or to its copy in the inbox. A stop command still stops. - The conversation that handed the work on is not given a chip about the question when it is the person's own inbox: the card's copy is there. - The requester resumed with a teammate's question is told it is already in front of the person, not to repeat it or ask it again. - An approval nobody answered in time is marked expired. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * feat(ui): one calm card for a bot's question and approval, in the chat and in the inbox The question, the open question and the approval are one card family, the same in a chat, on the inbox card and in the inbox panel, in Simple and Advanced, in both skins and at phone width: - A raised card (the composer's surface and its 0.5px hairline, the new ELEVATED_CARD) led by one line in secondary ink with the asking bot's small face: "Biber asks", "Biber wants to run a command". An inbox copy's line links back to the conversation it was asked in. The question follows in clear ink at reading size; a long command or detail folds after three lines. - Choices are full-width buttons, one per answer, at least 36px tall and 44 on touch, whose labels wrap instead of being cut. The tapped one shows it is on its way while the others wait; a failed send says so in place and takes another. No letter keys: a choice is pressed. - The one primary action is the asking bot's colour (the bot-button from the bot-coloured buttons work); Deny is neutral; Always allow and Cancel turn are quiet. One recipe in AskCard.tsx: primary, secondary and quiet, in two sizes. - A settled card is one calm line with a check: "You chose: Ja, nur den Abschlusstext", or "You answered: ..." for the person's own words. Stopped and expired questions, and an approval that timed out, have their own lines. - The open question a NEEDS INPUT line becomes is the same card with a reply field. A question's copy in the inbox carries no caption above it, and an approval's while it waits in the dock; the inbox card leaves the answers of the line it sits under to that line's own card. - The inbox panel's reading view uses the same question card, approval card and reply field; its rows' buttons get focus rings and touch sizes, and the panel's slide-in respects reduced motion. German has every card string, and every locale has the new ones. question-cards-preview.html mounts the real chat, inbox card and panel over a fixed store for side-by-side captures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(question-cards): the verification page, the runtime and team notes, and the e2e helpers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(question-cards): before and after pictures; the preview's key card names its help link Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(team): a person's first question leaves no waiting chip beside its inbox copy The chip check asked whose inbox the requester's chat already was, and a person's chat with their Chief only became their inbox once something was delivered there. It now asks whether that chat is, or would become, the inbox of the person the card is asked of. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * docs(question-cards): the approval in the inbox panel, and in German Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(question-cards): a typed line answers a card only in handed-on work or through an inbox copy Anywhere else a line typed while a question card waits is steered into the running turn or queued, as before, so the steering and queue paths keep working. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(question-cards): drivers keep their size, command text in whole pixels, the row says an approval got no answer in time Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * fix(question-cards): the wire types stay within 1,000 lines, and expired says it covers no answer in time Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 6 天前 |
| fix(page): the page opens with the product's name as its title (#4187) The title stayed OpenMausBot until /api/brand answered, and for good if it failed. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 2 天前 |
| Room to grow: memory never takes the workspace down, says why in one line, retries, and offers the plan that fixes it - Everything a bot runs starts first in the kernel's line when memory runs out (oom_score_adj 1000): its engine and tools as before, and now its browser (agent-browser, its daemon and Chrome) and the helper engines; the root supervisor is -1000. - A turn stopped for memory ends with one plain line ("Ran out of room, so I closed the browser to keep everything else running."), and a run no Chief retries starts once more by itself when there is room. - The health report carries the day's memory pressure (`room`): waits and their time, stops, kernel kills, stalled minutes. - The room card, where the usage meter's card is: the Admin's offer (the plan that fixes it, its price) with Upgrade through the usual preview and confirmation and Not now, a tip on the top plan, Restart now after the upgrade; never mid-turn. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 5 天前 |
| Add companion/: a sidecar that lets a paired phone reach the harness A phone cannot reach the harness, and should not be able to. The loopback gate refuses any request whose Host is not local, which is exactly right for a process holding provider keys and an approval switch — the guarantee is structural, and weakening it to let a phone in would weaken it for everyone. So this does not weaken it. `companion/` is a separate process that speaks to the harness as this machine, over loopback, exactly as the desktop window does. The harness needs no changes and does not know the sidecar exists. phone ──LAN/tailnet──▶ companion :8810 ──loopback──▶ harness :8799 Three sockets, and the split between them is the security model: :8810 0.0.0.0 devices — token required, allowlisted, scrubbed :8811 127.0.0.1 you — pairing and revocation, never off-machine :8799 127.0.0.1 the harness, unmodified - **Pairing** is a six-digit code shown on the computer and typed into the phone, redeemed once, inside a window, for a token. A token is per-device and revocable, and revocation is loopback-only: losing the phone must not mean losing the ability to lock it out. - **The allowlist is default deny**, per method and path — the list is every request the app makes, and nothing else. A route the harness gains later is closed to devices until someone adds it here on purpose. Anything else gets "no route", which keeps a stolen token from enumerating the API. - **A browser is refused before the token is read.** A native app sends no Origin; anything that does has found this port and has no business on it. - **Responses are scrubbed** of the harness's own bookkeeping, on JSON and on the SSE stream alike. The SSE transform emits an event the moment it is complete and never touches the blank-line terminator or the `id:` line — both of which have silently broken this project before. - **Ports stay clear of the harness**, which owns two: itself, and the webhook receiver one above it. Overlap is refused by name before anything binds, rather than raced for and lost by whoever started second. - **Discovery** is a zero-dependency mDNS responder, so the phone finds the computer by name on a LAN. Failing is not an error anyone has to fix — pairing by typed address still works, and the page says so. Tests boot a real harness and drive it through a real proxy, because every bug this design can have lives in the seam between them and none are visible to a unit test: SSE arriving but never terminating an event, a cursor dropped in transit, the loopback gate rejecting a proxied request. The allowlist is tested directly, including that a route it has never heard of is denied. Nothing here is wired into the app — `pnpm companion` runs it, and running it is the opt-in. The Settings toggle is a separate change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> | 2 个月前 |
| feat(server): per-bot connector tool grants data model and PATCH validation (#1756) | 1 个月前 |
| feat(pi): give the pi engine hands — mount harness MCP integrations pi core ships no MCP client, so the pi driver now mirrors the Claude driver's integration mount: computer (cloud box / Local VM / VPS), Composio, peer agents, phone, and dweb all become stdio JSON-RPC 2.0 servers handed to a small pi extension shipped by OpenMausBot. - server/drivers/pi-mcp-extension.ts: a pi extension (loaded via -e) that reads OMB_MCP_CONFIG, spawns each stdio MCP server, does the initialize/tools-list handshake, converts JSON Schema to typebox (best effort), and registers every tool with pi.registerTool. - server/drivers/pi.ts: buildMcpServers() mirrors the Claude driver; the MCP config rides a 0600 temp file (never argv) removed on settle; capabilities flip computerMcp/composioMcp/agentsMcp/phoneMcp on. localComputerMcp stays off: host control needs the harness permission broker, which the pi RPC bridge does not wire yet. - proxy-paths/bundle-server: resolve + ship the extension verbatim as .ts (never bundled — pi resolves its own @earendil-works and typebox). - tsconfig: exclude the extension from OpenMausBot typecheck. The pi repo itself is untouched — this is an extension over pi's public registerTool API, not a core change. | 2 个月前 |
| MausBot connector: run a Cloud home on its owner's own server, over one outbound connection (#3732) A new connector/ folder, published with every release as ghcr.io/milind-soni/mausbot-connector for linux/amd64 and linux/arm64. - install.sh (curl ... | sudo sh -s -- <code>) checks the server, and says how to fix each failure in plain words: operating system, x86-64, Docker 24+ (offering to install it), AppArmor, user namespaces, CPU, memory, disk, network and clock. It installs the bot box's AppArmor and seccomp profiles, starts the connector, runs the box probe and enrols with the one-time code. Running it again repairs. uninstall never deletes the data unless --delete-data is typed. - The connector enrols once, then holds one WebSocket to the Admin, re-opened with backoff. Every 30 s it sends a heartbeat: host health, and the home's state, image and signed health. It runs only the protocol's jobs: start, stop, restart, update, status, backup, restore, export-disk, import-disk, host-health and self-update. - There is no shell, arguments are checked, and images must be our registry's, by digest. - Replies are sent again on each connection until the Admin acknowledges them. - update copies /data aside, swaps the container, and waits up to 10 minutes for the new image's signed health. Otherwise it puts back the previous image and the copy. - A home that stopped on its own is started again. Until the image clears it itself, the connector first clears the data-directory lease a killed home leaves. - self-update keeps the running connector until the new one has connected; one atomic rename settles which one won. - The agent token and the home's environment are kept 0600 in the state volume and never logged. - connector/src/protocol.ts holds the message types and checks, for the Admin side to copy. Tests: unit tests with a fake Docker, and a fake Admin over a real WebSocket. An end-to-end run on a stock Ubuntu 24.04 runner (connector-e2e.yml) covers install, start with the box at 32/32, update, an unclean kill, a forced rollback and uninstall. Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com> | 7 天前 |
| feat(cloud): usage meter in the sidebar and Settings, with Upgrade that changes the plan People close to a limit of their MausBot Cloud plan see it before they hit it, and can move up in one tap and a confirm. - Sidebar card, above the person's name (not in the icon rail), only while an allowance is at 80% or more: the one or two fullest, used of included with a bar (amber from 80%, red at 100%), when they start over, Upgrade to the next plan, See all usage, and Hide for now (for this month at this level: it comes back at 100%, and next month). Never in a browser, without a paid plan, or on a Team Cloud unless the plan is that team's. - Settings → General → MausBot Cloud usage: every allowance with its meter, when they start over, Upgrade to the next plan (the others as links), or that this is the top plan. - Upgrade: main asks the Admin for Dodo's own preview (nothing changes), the confirm says the new price, today's prorated charge and the next payment in plain words, and only the confirm's own button sends the change, with the confirmation main kept from that preview (never in a page; once; ten minutes). Both bridge calls need a click; main only moves to a plan the verified session lists. On the new plan, still going through, a declined card, a changed price or a failure each get one plain line, and the session is read again so the new plan and allowances show at once. Where the Admin can't change plans from the app, Upgrade opens the Cloud page instead. The numbers come from the Admin's desktop session (`cloud.usage`, openmaus-cloud feat/usage-meter), parsed and checked in cloud-home.mjs, kept on the account's state and handed to this computer's page and the person's own Cloud page alike through cloudPlanSnapshot. The cloud-plan:* channels move to electron/cloud-plan-ipc.mjs, and the sidebar's foot to SidebarFooter.tsx, so main.mjs and Sidebar.tsx shrink. Copy in all 13 locales (Polish included); screenshots (light and dark) in docs/verification/evidence/usage-meter/ from usage-meter-preview.html. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 12 天前 |
| CI: Linux shards run four test files at once Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 10 小时前 |