The tab layout's 512 refs also count pinned sessions kept as stopped records, so
the ceiling holds at the default MAX_WEBVIEWS and with no pinned closed sessions.
SKILL.md, verbs.md (both copies) and the cron guide no longer give a fixed 50/25.
Co-Authored-By: Christian Haberl <116439789+christianhaberl@users.noreply.github.com>
Co-Authored-By: Claude <noreply@anthropic.com>
An owner's tab layout holds at most MAX_TAB_REFS (512) refs, counting saved web
tabs (up to MAX_WEBVIEWS, 50 by default) as well as sessions. With a ceiling of
500, session creation could still fail with HTTP 500 on the layout limit before
the capacity message. 512 - 50 = 462; a test pins the ceiling plus MAX_WEBVIEWS
inside MAX_TAB_REFS so the two limits cannot drift apart again.
Co-Authored-By: Christian Haberl <116439789+christianhaberl@users.noreply.github.com>
Co-Authored-By: Claude <noreply@anthropic.com>
The proxy hands undici the request body as a stream and dropped the browser's
content-length, assuming undici recomputes it. For a stream it cannot: undici
frames it as Transfer-Encoding: chunked. A dashboard that reads only
Content-Length (Python's http.server, many small Go/C servers) then saw an
empty body on every POST through a web tab. Found on a WoL dashboard whose
Shut down posted {"confirm":true} and was refused for a missing flag on every
click through Codeman, while curl straight at it worked.
buildUpstreamRequestHeaders now puts the browser's content-length back when a
body goes upstream (relayBodyLength), it is a plain number, and no
transfer-encoding contradicts it. GET/HEAD never carry it. undici 6.28 frames
the stream with that length and fails cleanly on a mismatch. Side effect:
a DELETE/OPTIONS with content-length 0 now goes upstream with neither header
nor body instead of an empty chunked body.
test/webview-proxy-body-framing.test.ts pins it end to end against a
Content-Length-only upstream; it fails on the old code with
"expected 'chunked' to be null".
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Review follow-up. Other bounds assume a small session count: an owner's
tab layout holds at most MAX_TAB_REFS (512) refs and PUT
/api/session-order accepts at most 500 ids, so with
CODEMAN_MAX_SESSIONS=600 the 513th session creation answered HTTP 500
instead of the capacity message. The value is now clamped to a named
MAX_CONCURRENT_SESSIONS_CEILING of 500; any digit string above it
(including one past the safe-integer range) resolves to 500 instead of
falling back to 50. The resolver reads process.env directly, the unused
env parameter is gone.
Docs: a CODEMAN_MAX_SESSIONS row in the Settings Reference environment
table, the env name next to the cap in the cron guide and the
architecture invariants, and both copies of the skill's endpoints
reference now give the per-user cap as half the global cap (25 by
default). The changeset says "1 to 500". The test drops the
`as unknown as string` casts and adds '1000', '501' and an
out-of-range value, each refusing at 500.
Co-Authored-By: Christian Haberl <116439789+christianhaberl@users.noreply.github.com>
Co-Authored-By: Claude <noreply@anthropic.com>
The cap of 50 concurrent sessions was a hard-coded constant, so a machine
with the memory for more (or a small box that wants fewer) had to patch the
source. CODEMAN_MAX_SESSIONS now sets it at startup. The default stays 50,
and anything that is not a positive integer (empty, 0, negative, fractional,
1e3, out of safe-integer range) falls back to it, so a typo never locks
session creation.
Every site keeps reading MAX_CONCURRENT_SESSIONS, so the session routes,
cron launches, the scheduled-run loop and the multi-user per-user cap (half
the global cap unless CODEMAN_MAX_SESSIONS_PER_USER is set) all follow the
variable. The test goes through sessionCapacityState and
sessionCapacityMessage, the check every session-creating route uses.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The message ran 66 words over five sentences, which pushed the update
toast's buttons off a 360x640 phone. It also repeated the card's own
eyebrow ("Security notice for OpenCode users:"), placed the breached
"legacy system" inside the Console (no source says so), and closed with
an unsourced line about the CLI not being affected. The new text (55
words) says what OpenCode said, including its own reassurance that a
user who got no email was not affected, which matters because the card
goes to every opencode user while about 1.4% of Console users were hit.
The zh-CN text follows it and uses 撤销 for revoking keys.
published moves to 2026-10-17, so the notice is already live in every
timezone when the release lands: a browser still on the 17th would
otherwise take the plain update toast and get the notice later as a
separate card. docs/releasing.md says both things for the next notice.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
src/web/CLAUDE.md gets the load-bearing rules (hand-maintained file,
strictly-true availability, one surface per notice per load, seen only
on a user action, no CLI-id branching, theme tokens only), and
docs/releasing.md a section on adding a notice, its fields, and letting
`expires` retire it.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
GitHub Copilot CLI (`copilot`) becomes a run mode: Run menu, welcome
screen, cron and CLI management once it is installed, tmux-backed like
the other agent CLIs, working/idle and the model read off its footer,
launch options through `copilotConfig` (model, resume, continue, the
multi-user-clamped allowAll), Custom Model Endpoints via Copilot's BYOK
variables, MCP sync of its mcp-config.json, a status probe, and the
`codeman agent` verbs (spawn waits for its composer, read returns its
last answer).
The plan-usage quota row that earlier rounds carried was split out on
review and is not part of this merge.
Merge-time commits on top: the wider COPILOT_* clamp and the zh-CN
README rows (maintainer), the Docker sign-in docs, divider rows inside
an answer kept by `agent read`, route tests for the screen-read
last-response branch, and doc drift (Past Sessions, wheelForward JSDoc,
COPILOT_/OMP_ in the env prefix lists).
Verified before merge on Copilot CLI 1.0.98: injected keystrokes,
bracketed paste and Enter reach the TUI in tmux (github/copilot-cli#4180
does not reproduce), a shell tool call completes inside tmux (#4223 does
not reproduce), and a session driven through this branch answered over
send-and-wait.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
docs/api-reference.md (the signal notes and the idle/working rows), and the
wiki's Notifications-And-Approvals, Keeping-Agents-Running and Troubleshooting
pages, plus docs/grok-integration.md, still called Antigravity's working and
idle status unreliable. It now declares a working line and prompt marker like
Codex, OpenCode, Gemini, Pi and OMP, so only Grok stays on generic cues. The
Troubleshooting entry for a session stuck showing busy also says that an
Antigravity session waiting on a shell-command approval shows busy until it is
answered, and the API reference says the same of its idle signal.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The new App Settings row had no zh-CN entry, so it read in English in a
Chinese UI, and docs/wiki/Settings-Reference.md did not list it. Adds the
label and description to i18n.js, a row in the Agents & CLIs table, and a
JSDOM test that runs the real translator over the real index.html.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
- docs/cli-registry.md said Session history resume goes through
copilotConfig.resumeSessionId / continueSession. Past Sessions sends only
`continueSession: true` (terminal-ui.js, the modeConfigKey table);
resumeSessionId is for API callers.
- The wheelForward JSDoc in cli-registry/types.ts read as if the value had
effect. Nothing reads it (it is in the DECLARED-FOR-LATER list); the
browser gate is _shouldForwardWheelToApp in terminal-ui.js with its own
per-CLI rules, which the comment now says.
- The env-prefix lists in the CLAUDE.md Security table and the
allowedEnvPrefixes() comment in schemas.ts stopped at DEEPSEEK_, missing
both OMP_ and the new COPILOT_; the Multi-CLI prefix rule missed OMP_.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The suffix is part of the pill's text line, which the Tiles style hides (it
shows WS live) and phones hide too, so the page promised a suffix some users
never see.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The reflow around the new UTF-8 sentence left one 120-character line; the
paragraph is wrapped at about 90 columns like the rest of the page.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
docs/api-reference.md and the case-path.ts @fileoverview still said a custom
folder must not be, or be inside, the cases directory. After #567 only the
cases directory itself and its direct children are refused (those are what
GET /api/cases lists as local cases); a folder further down is allowed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
CLAUDE.md (Prompt uploads) and architecture-invariants still named
_promptAttachKind() as the filter every surface reads. That stays true, but
the surfaces now admit through _admitPromptAttachments(), which is what says
how many files a pick skipped. A new surface that filtered on the classifier
directly would drop files silently.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Both Docker sections said "or set COPILOT_GITHUB_TOKEN for the session",
which cannot work: a docker quick-start refuses envOverrides
(session-routes.ts), and Copilot's dockerExecEnvNames is empty, so a token
in the server environment is not forwarded into the container either. The
sentence now says to sign in inside the container and why the token route
does not exist.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The COPILOT_ prefix admits every variable Copilot reads, and the 1.0.98
bundle reads far more than `copilot help environment` lists. Only
COPILOT_HOME, COPILOT_ALLOW_ALL and the BYOK trio were privileged, so a
non-granted multi-user owner could still hand back what the allowAll
clamp removed:
- approval: COPILOT_PLAN_THEN_AUTOPILOT, COPILOT_ASSISTED_APPROVAL
- code with no approval row: COPILOT_CLI_DIST_DIR runs <dir>/index.js
in place of the CLI, the package caches choose the CLI build,
COPILOT_EDITOR, COPILOT_PROVIDER_API_KEY_COMMAND and
COPILOT_AHP_HOST_BIN are executed, skills, provider configs and hooks
are loaded from the named places (the DSH_HOME class)
- token redirects: COPILOT_API_URL and the other API bases receive the
CLI's sign-in token, which in multi-user mode is the operator's (all
users share the OS account and ~/.copilot), and the rest of the BYOK
provider family re-aims a Codeman custom endpoint (the
DEEPSEEK_BASE_URL / OMP_AUTH_BROKER_URL class)
All are now privilegedEnvKeys. The registry schema capped that list at 8;
the cap is now 48, since a longer deny list only takes more away from
non-granted owners. The test sends one of each class through the real
schema (they all pass it) and the real clamp. The docs say the list is
read from the 1.0.98 bundle and that a variable a later release adds is
not covered until it is listed.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Add pinCliSessionName (synced, default OFF), re-read at each spawn and respawn.
Off keeps the #457 behaviour; on pins every non-blank tab name as --name.
Update the docs, JSDoc and changeset that stated the old rule.
The Remote SSH section claimed the same flags and clamp as a local launch, but defaultRemoteCommandForMode starts a bare copilot (pinned in test/location-overlay-commands.test.ts). Nothing in the UI sets copilotConfig.model, so the model rows now say API callers, or COPILOT_MODEL for a custom endpoint.
Review of 8659ba25..be987fbb:
- Usage: a Free account answers premium_interactions {entitlement: 0, remaining: 0,
percent_remaining: 0, unlimited: false, has_quota: false}, which read as 100% used. The parser now
returns null when has_quota is false or the entitlement is not positive, with that payload as a
fixture. Free meters chat (200) and completions (2000) too, so the comment no longer says they
are unlimited on every plan.
- agent read: rows were skipped until a `❯ <prompt>` row, so an answer taller than the pane
(prompt scrolled off the top) read as "". With no prompt row AND no banner / trust dialog on
screen, the rows above the composer are now the tail of the last answer. Text typed in the
composer (a prompt-shaped row between the two rules) is not a prompt row.
- Page keys: measured on 1.0.95 in tmux that Copilot pages on PageUp/PageDown (three PageUp moved
lines 109-140 to 010-042, PageDown returned) as well as on SGR wheel reports, so copilot joins
claude and opencode in _localScrollbackIsHollow(); the stale-tracking-flag fallback the comment
and docs describe is now true, for the main pane and a TerminalTile (same function), with tests.
- X-GitHub-Api-Version is 2022-11-28, a version GitHub supports (verified against the live
endpoint); readPlanUsageTelemetryEnabled() is checked before isCopilotAvailable() so a switched-off
chip skips the resolver probe too.
- Palette label for Copilot in panels-ui.js; stale comments in types/session.ts and stock.ts.
- Docs: Past Sessions continues with --continue (resumeSessionId is for API callers), nothing sets
continueSession on a respawn, and only a tab name the user set is passed as --name; the usage
wording for Free; the wheel and mouse-strip paragraphs in CLAUDE.md and
architecture-invariants; the changeset describes the whole feature.
- New docs/copilot-integration.md in the shape of the other CLI guides: install and identity
probe, authentication (keychain vs plain-text config.json, COPILOT_GITHUB_TOKEN), what Codeman
wires up (Run button --yolo and its clamp, model, resume, continue, --name rule), BYOK custom
endpoints, terminal behaviour (drag selection, wheel and touch), the codeman agent verbs
(ready mark, read), plan usage, Docker, Remote SSH, what is deliberately not wired, known gaps.
- Agent-CLIs wiki: the eleven-modes table, a GitHub Copilot CLI section, the env prefix row, the
feature-comparison rows and the status endpoint list.
- README, Home, FAQ, Core Concepts, Docker Cases, Remote SSH, Contributing, The Dashboard and
Custom Model Endpoints: mode lists and counts; CLAUDE.md: stack line, SessionMode, prefixes,
resolver list, external-CLI notes and the plan-usage source; api-reference MCP target wording;
the env allowlist error message names COPILOT_*.
Copilot's TUI turns mouse tracking on itself. Under `strip-mux-only` those DECSETs reached
xterm, which then reported a plain drag to the TUI instead of selecting (only Shift+drag
selected), so Auto Copy and copy-on-select did nothing. This is the failure opencode had and
`strip-mux-and-mouse` was added for: the DECSETs are stripped, a drag is a local selection and
clicks still reach the CLI through the browser's hand-encoded tap (`cliMouseTracking`).
Stripping them also stops xterm from encoding the wheel for the CLI, so
`_shouldForwardWheelToApp` now forwards it as SGR reports while Copilot is tracking the mouse
(the same bytes xterm sent natively, which is what scrolling was verified against). Shift+wheel
stays on local scrollback and a stale flag falls back to PageUp/PageDown.
Tests: the strip flavor for copilot (stripped DECSETs, 3J kept, cliMouseTracking, direct-PTY
untouched) and the wheel gate (forwards while tracking, no other non-claude mode changes).
- Drop GH_TOKEN / GITHUB_TOKEN from env.allowedKeys. The allowlist is one global list with no
mode context, so they were settable on every session. COPILOT_GITHUB_TOKEN is already admitted
by the COPILOT_ prefix.
- Declare capabilities.mcpConfig (copilot-json, COPILOT_HOME relocation) so Settings does not
list Copilot as unsupported while the sync-only target also lists it. The sync-only row is
skipped while the run mode is enabled.
- Require a leading alphanumeric on the resume id (path-segment in the registry, matching regex in
the schema): --resume's value is optional, so `--resume --yolo` made --yolo its own flag and
bypassed the allowAll clamp. Golden cases added; "ids only" wording corrected.
- Remove the unread overlays.credStore line and document signing in inside a Docker container.
- Add the zh-CN "Run GitHub Copilot" string, pin the new declarations in tests and update the
MCP registry expectations.
Copilot (`copilot`, npm @github/copilot) as a stock CLI entry with the same launch options as the other agent CLIs: model (--model), resume (--resume), continue (--continue) and allow-all (--yolo, clamped off for non-granted multi-user owners). Adds a resolver and GET /api/copilot/status probe, the agent-image package, Run-menu/mobile/logo entries, skill docs and tests.
Review round: the footer hint is drawn only at rest, so nothing arms the idle check while the Run this command list is up. The stock.ts comment, wiki, changeset and test now say a pending approval shows as working until answered, and the test pins busy during the confirmation. Adds the antigravity copy of the reattached-pane settle test, and updates the promptGlyph comment and the fixture header.
agy animates an 8-dot braille spinner (⣯ ⡿ ⣻ ⣾ ⣷ ⣟ ⢿ ⣽) with a label one row above
the composer, none of which is in SPINNER_PATTERN, and the entry declared no
workDetect, so no frame ever marked a tab working.
Declare the working line from the live pane and the footer hint `? for shortcuts`
as the idle-arming mark. The composer's `>` cannot be the glyph: the echoed
prompt starts with it too. Tests use verbatim captures from agy 1.3.3.
Follow-up to the previous commit, after a fact check against the code.
- Answer surfaces: the header bell answers Claude prompts, the phone
strip only Claude dialogs (and only with the inbox on), and push
Approve/Deny only a Claude permission prompt (PUSH_EVENT_MAP gives
actions to permission_prompt alone). README, its Chinese mirror, the
notifications page and the phone guide now say so.
- Antigravity and Grok Build: after the 3 s launch settle, idle is armed
only by Claude's prompt marker and working only by a braille spinner,
so "idle when output stops changing" was wrong. The wiki, the grok
guide and the API reference now call their status unreliable.
- DeepSeek Harness: its idle and working reports become stop and
agent_working, which drive respawn, waits and the inbox but not the
session's own working/idle display. Keeping Agents Running says that,
and that the respawn path needs the status bridge.
- The wait section of the API reference no longer calls exit the only
dependable signal for screen-checked modes; the inbox page names how
Codex and DeepSeek items clear; Core Concepts and Hooks And
Integrations no longer call DeepSeek "the one" exception; Agent CLIs
notes that Codex dialogs still raise the red alert; the inbox design
doc notes the alert-only items.
- Skill: stop and blocked list deepseek, and SKILL.md no longer says
codex has neither a transcript nor blocked. Mirrored with
scripts/sync-plugin.mjs.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The README (and its Chinese mirror) said the Approvals Inbox queues every
pending prompt and answers it from the bell or the phone. It holds prompts
from Claude Code, Codex (screen-read) and DeepSeek Harness only, and only
Claude's are answerable: Codex and DeepSeek items are alerts that say to
answer in the terminal, with no Approve/Deny on the push or the phone strip.
The wiki, the TUI guide and the phone guide now say the same.
Keeping Agents Running, Troubleshooting and the API reference still said
every CLI but Claude, Codex and DeepSeek falls back to output
stabilization. OpenCode, Gemini CLI, Pi and OMP declare
capabilities.workDetect too and get the same screen check; only
Antigravity and Grok Build declare none. Core Concepts now mentions
Codex's screen-read dialogs, and the respawn gotcha notes that DeepSeek's
own end-of-turn report reaches the respawn controller.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
An Excel or Notepad CSV/TXT export (UTF-16 with a BOM, or Windows-1252) was refused as "File bytes do not match declared type", which reads like a corrupt file. Name the encoding and tell the user to save it as UTF-8.
- docs/api-reference.md: a non-admin's GET /api/settings omits
voiceSettings.apiKey, caseOrder and lastUsedCase; a new "System
operations" table for the admin-only routes and the scoped
POST /api/auth/revoke; the error-code table now lists FORBIDDEN and the
other multi-user codes (PASSWORD_CHANGE_REQUIRED, USER_NOT_FOUND,
USER_EXISTS, LAST_ADMIN).
- docs/wiki/Multi-User-Mode.md: what a regular user reads, that their run
mode and respawn presets stay theirs on the device, the slow sign-in
case, and the admin-only system operations.
- docs/multi-user-plan.md: Settings and System ops rows marked implemented.
- CLAUDE.md: the Multi-user mode paragraph names the new pieces and tests.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
api-reference gains a Settings section (GET/PUT /api/settings, the model
config, the case order and PUT /api/config, with the 403 FORBIDDEN a non-admin
gets in multi-user mode). The Multi-User Mode wiki page explains what a regular
user's App Settings save does now, Settings-Reference links it, the plan's
Settings row is marked implemented, and CLAUDE.md notes the gate for the
Multi-user paragraph and for anyone adding a settings write.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
feat(codex): raise codex approval, question and trust dialogs as BLOCKED
Conflict resolved against #634 in src/session.ts _probePaneWorking():
#624's assignment (a dialog on screen is never work) is kept, and #634's
trust-dialog verdict block (log the hold once, remember the reading)
follows it, before _readWatching().
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
feat(shortcuts): rebindable previous/next session, duplicate-chord refusal, rebinds stay out of the PTY
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
On codex-cli 0.162.0, with 0.163.0 released, every launch first shows the
"Update available" prompt, and choosing Skip leads to a variant of the
workspace trust prompt: "2. Back to Agent Command Center" over the key-hint
row "enter continue · esc back". The pattern only accepted cancel,
interrupt, quit, answer or all as the closing word, so a fresh git repo
launched from Codeman sat on that trust prompt reading idle, with no red
alert and no blocked signal (measured live on a throwaway instance).
Adding "back" is safe because the hint row must still START with one of
the anchored hints ("enter continue" here): the popups the user opens at
the keyboard (/model, /permissions, /review, Implement this plan?) end in
"esc back" too, but their row starts with "enter select", so they stay
unmatched, as every existing negative fixture confirms. The new fixture is
the live capture with the scratch path replaced.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The Docker rule was applied to the CASE folder and its common git dir
only. A Docker case can be linked to any host folder, including a managed
worktree (`<repo>/.claude/worktrees/<name>`), which is a natural setup for
running one of the parallel agents in a container. Removing that worktree
from the local case's dialog, or through Close Session's "Kill & remove
worktree", ran `git worktree remove`, which runs a git status INSIDE the
tree (container-written files, checkout filters on this machine) and then
deletes the whole tree, ignored files included, while the container still
mounts it. Reproduced on an isolated instance: DELETE answered 200 and the
Docker case's workspace was gone.
That contradicts the invariant the PR itself documents in CLAUDE.md ("git
never runs ... at or inside a Docker workspace"). removeCaseWorktree now
refuses (400) a present worktree that is, sits inside, or holds a Docker
case workspace, before any git runs; the DELETE route passes the Docker
roots it already reads for the case check. A worktree whose folder is gone
is unaffected (git only drops its record there). Unit and route tests
cover both directions and an unrelated Docker workspace; docs updated.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>