chore: one changeset for 1.46.0

Replaces the six contributor changesets (#694, #707, #708, #709, #718,
#713) with one consolidated minor changeset covering all 14 PRs, with the
Thanks section first and the release-review fixes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Codeman maintainer committed 2026-10-27 03:11:52 +01:00
1 parent cc08016a76
commit de1aab9b86
7 files changed
+40 -45

No files matched your search

-17
View File
@@ -1,17 +0,0 @@
---
"aicodeman": minor
---
Add experimental bounded agent inspection with expiring scoped cursors (the newest 8 kept per caller and session) and explicit pane snapshots, plus staged local Codex input and single-use hash-confirmed submission receipts. Verify the exact composer, caret, lifecycle and input revision before sending Enter, and serialize dispatch against managed input and auxiliary key operations.
The three new CLI verbs (`codeman agent inspect`, `stage`, `submit`) and their HTTP routes (`/api/v1` and `/api`) are labeled experimental, so the versioning policy's rule for experimental surfaces applies: their shape and behavior may change in minor or patch releases. They are opt-in behind a new synced setting, `agentCoordinationEnabled` (App Settings, Cross-session features, "Experimental agent coordination", default OFF, translated for zh-CN): while it is off all three routes answer `403 FORBIDDEN` with a message naming it, and the CLI verbs print that refusal verbatim.
Codex rollout attribution remembers the attributed file per session and re-verifies only that file's head on later calls, rescanning only the date directories not older than it for a codex `/new`, so a large never-pruned `~/.codex/sessions` store no longer falls back to a pane snapshot or costs a full walk per call. An unexpected inspection read error answers `422 OPERATION_FAILED` and is logged with the session id and error code only, instead of a retryable `409`.
The guarded composer read takes its glyph and footer from the CLI registry: codex's `workDetect.promptGlyph` and a new `workDetect.composerFooterLine` capability (config-supplied regex, compiled through the ReDoS guard). Only a CLI declaring it takes guarded input. Codex's footer effort words are now one shared list for this and `modelDetect.screenLine`.
Stage waits for the pane to show what it typed: it re-reads the composer every 50 ms for up to one second and issues a receipt only for a frame showing exactly the message (Codex repaints 30 to 60 ms after the keys, so the first capture was often stale and stage refused with the text already typed). Every refusal after typing now says the message may be in the composer and points at the Ctrl+U recovery. A visible-frame pane capture reads the screen and the caret in one tmux invocation, falling back to the two separate calls only for output it cannot split; a call that fails is not repeated. Stage refuses messages that would change what Enter does (codex: a leading `/` or `!`, or a last word starting with `@` or `$`, which open a command or completion popup) and frames with a suggestion popup above the composer, from three new registry fields (`workDetect.composerPopupLine`, `composerCommandPrefixes`, `composerCompletionSigils`). Submit waits until 250 ms after the staged keys before sending Enter, since codex turns an Enter within 120 ms of typed text into a newline. Input that arrives while a guarded submit holds its input lease (the few milliseconds of its Enter) is held and written in arrival order once the lease is released, so a browser keystroke, a Shift+Enter or Ctrl+Enter, or an approval answer typed in that window is no longer lost; a WebSocket frame is acknowledged only once it is written. `POST /api/sessions/:id/input` answers `409 CONFLICT` with its seq returned for that span instead of a `200` for input that was never written, and a lease that would hold more than 256 inputs or 1 MiB closes the terminal WebSocket (code 1013) so the browser resends in order, and answers `send-key` with `409 CONFLICT`.
Document the initial local Codex support and conversation-attribution limits in the API, CLI and packaged skill. Other modes retain labeled snapshots or refuse unverifiable guarded input.
SubmitVerifier Enter re-presses now use the shared input boundary and update `lastSubmitAt` for each retry on every supported CLI. This keeps submission timestamps consistent with delivered Enter attempts while preventing a stale retry from bypassing a guarded submission.
+40
View File
@@ -0,0 +1,40 @@
---
"aicodeman": minor
"xterm-zerolag-input": patch
---
### Thanks
- @JDProfresh for five PRs: a phone keyboard that no longer costs Claude its transcript (#711, measured in #672), a + on each session tab that starts a session beside it (#712, shaped in Discussion #700), a tunnel that needs its own opt-in instead of the LAN one (#718, from their report #706), a settings.json that two writers can no longer tear (#719), and a DeepSeek test that passes on current Node (#710).
- @aakhter for six PRs: `codeman agent spawn` in a project directory (#708), worker ids kept when the readiness check fails (#709), the offline Codex history reader (#707), experimental bounded inspection and guarded submission for agents (#694, from Discussion #695), links that follow URLs and paths across wrapped rows and table cells (#686), and file paths with spaces linked as one path (#687).
- @opticon454 for the Fetch button and fetch interval in the Git status window (#714).
- @johoja12 for Cmd+K arrows that switch the CLI both ways after you type a case name (#717).
**Fetch from the Git status window (#714).** The Git status window has a Fetch button next to Refresh. It runs `git fetch` for the repositories it lists and shows each one's result. An optional interval runs it for you: off by default, app-wide in App Settings, Bottom bar, with a per-session override in Session Options, Git. A fetch only moves remote-tracking refs (HEAD, the index and the working tree stay as they are), it never runs for a Docker or remote session, and it is bounded in time, output and concurrency.
**Start a session beside any tab (#712, opt-in).** Turn on **New Session Button on Tabs** (App Settings, Tabs) and each session tab gets a +: pick any CLI its case can run (a Docker case offers what its container has) and the new session starts in that case or worktree and that tab's group, without touching the toolbar's case or Run mode. The row menu offers the same as "New session here…" for the keyboard.
**The phone keyboard no longer costs Claude its transcript (#711).** Every keyboard open and close used to resize the PTY, and Claude Code answers each height change by reprinting only the tail that fits, so lines above it were lost from tmux for good (25 of 100 in five keyboard cycles). A local Claude session now keeps its rows while the keyboard is up and slides the screen so the composer stays above the keyboard. On by default as **Keep Size Under Keyboard** (App Settings, per device); off restores the old resize. Fullscreen Claude (mouse tracking on) still resizes as before.
**Typing stays smooth in a long prompt (#713).** The local echo overlay (the instant preview of what you type) rebuilt every character of the prompt on each keystroke, so on a phone-class CPU a 4,000-character prompt took most of a second per key. It now rebuilds only the line that changed, with one paint layer per line, so a keystroke costs the same however long the prompt is. Every character still sits on its terminal cell. This ships in `xterm-zerolag-input` too.
**Links survive wrapping and spaces (#686, #687).** A URL or path a CLI wrapped inside a table cell or an indented paragraph now links whole instead of in fragments, URLs keep balanced parentheses (`…/Team-Space(QA)Archive/…`), a full-width table divider no longer glues onto the row below, and OSC 8 hyperlinks open through Codeman's own opener after a confirmation. A file path with spaces (`/mnt/c/OneDrive - Contoso/report.docx`, `Saved to: ~/My Docs/plan.md`) links as one path in the terminal and the response viewer when the line bounds it, and a shell prompt that prints its working directory no longer turns the whole command line into one link.
**`codeman agent spawn` in a project directory (#708).** Without a case name, `spawn` starts the worker in the current directory, or in an existing directory given with `--working-dir`, through `POST /api/v1/sessions` and the mode's start route. Named cases still use quick-start. `--json` prints `{ sessionId, workingDir, created: true }` plus `ready`, `readinessError` or `startupError`. An empty `--working-dir`, a bare spawn from your home directory (it would install Codeman's hooks into `~/.claude`; pass `--working-dir ~` to mean it) and an unknown `--mode` are refused with exit 4 before any request.
**Read saved Codex conversations offline (#707).** `codeman history read` reads Codex's saved rollouts without a Codeman server: by file, by Codex session id, or a whole conversation with its sub-agents and forks, filtered by topic or UTC date with whole turns kept. Reads and output have separate, raisable budgets, and anything it could not read or attribute (a compressed `.jsonl.zst` rollout, a file still being written) is reported through `complete: false` instead of failing the lookup. The codeman skill routes to it.
**Experimental: bounded inspection and guarded submission for agents (#694, opt-in).** `codeman agent inspect` reads bounded, cursor-paged evidence from another session (a local Codex session's attributed rollout records, otherwise a labelled pane snapshot), and `agent stage` / `agent submit` type one line into a verified local Codex composer and later send exactly one Enter against a hash-confirmed receipt. Off by default behind **Experimental agent coordination** (App Settings, Cross-session features); while off the three routes answer `403 FORBIDDEN` naming the setting. These routes and verbs are experimental under the versioning policy and may change in a minor or patch release. During the few milliseconds of a guarded submit, other input is held and written in order afterwards; a tagged input POST in that window answers `409 CONFLICT` so its sender retries, and an untagged one (the phone keys, the Stop button) is held and answered once written.
**Cmd+K arrows switch the CLI both ways (#717).** After typing a case name in Cmd+K, plain Left and Right now both change the New session row's CLI whenever the caret is at either end of the query (only Right did before). Inside the query the arrows move the caret as usual.
**Fixes.**
- **Security: a LAN install's acknowledgement no longer opens a public tunnel (#718).** `CODEMAN_ALLOW_UNAUTHENTICATED_NETWORK` (and `--allow-unauthenticated-network`), which the installer writes for every LAN install without a password, also let the Cloudflare tunnel start, so one click on the welcome screen's tunnel link published full terminal control to a public URL with no login and no confirm. It now covers the network bind only. An unauthenticated tunnel has its own opt-in, `CODEMAN_ALLOW_UNAUTHENTICATED_TUNNEL=1` or `codeman web --allow-unauthenticated-tunnel` (carried by `codeman web -d` and `codeman service install`), which the installer never writes; if you relied on the network variable to start the tunnel without a password, set one of those. With no password and no multi-user mode, the browser now asks before every tunnel enable, using the new `loginConfigured` field of `GET /api/tunnel/status`.
- **settings.json can no longer be torn (#719).** A quick-start's `lastUsedCase` write was not awaited and not atomic, so it could overlap the next settings save and leave one write's bytes over the tail of the other, after which every reader saw `{}`. Every write to settings.json now goes through one serialized writer that writes a temp file and renames it into place, and a file that does not parse is refused with `409 CONFLICT` instead of being overwritten with only the writer's own keys. A case rename checks this before it ends any session.
- **A worker id is never lost (#709).** When `codeman agent spawn` created a worker but its readiness request failed, it exited without the new session id. It now prints the id (and `--json` carries it) and exits 1, so the caller can inspect or delete the worker. `codeman agent` and `codeman mcp` also name the error code (such as `ECONNREFUSED`) when a request fails with an empty message.
- **The DeepSeek transcript test passes on Node 24.22+ and 26.10+ (#710).** It pinned Node's old zstd decoder, which stopped at the first frame until nodejs/node#65865.
**Fixes applied while landing.** The Git fetch interval field is no longer reset by a session update while you type in it, a session holding only half an override shows the app's value for the other half, reading a repository's `core.sshCommand` no longer doubles the fetch timeout, a `GIT_SSH` in the server's environment is honoured, and the Fetch button's disabled and busy styles no longer reach other icon buttons and stop pulsing under reduced motion (#714). A + launch keeps the toolbar on its own case, and pressing the + again closes its picker (#712). The fetch scheduler no longer logs the text of a malformed settings.json on every 15-second tick (the parser's message could quote an API key; it now says the file is not valid JSON, once), and a fetch is skipped while the Docker case list cannot be read, so it can never run inside a Docker workspace (#714). A case rename answers `409 CONFLICT` for a settings.json it cannot write before it ends any session (#719). The unauthenticated-tunnel warning no longer fires in multi-user mode, where the tunnel has a login in front of it (#718). Untagged input during a guarded submit is held instead of refused, and the skill's staging guide says so (#694). A shell prompt line (a spaced working directory followed by `$` included) and a labelled `../` spaced path link as they should, and a bold label or inline code before a path in the response viewer splits it as the terminal does (#687); a URL whose row soft-wraps no longer glues a trailing column onto the next path, and in a table a link in the column right of a wrapped URL stays clickable on the URL's first row (#686). The keyboard hold reads the terminal's height only while rows are held (#711). The README, the plugin's README and its marketplace description now say the codeman skill reads saved Codex conversations outside a Codeman session and refuses everything else there (#707).
**Docs and tests.** New sections for the keyboard hold (next to the terminal geometry rule it is an exception to), the tab +, Git fetch, the settings writer, the tunnel opt-in, the directory spawn, the offline history reader and the experimental agent routes, in CLAUDE.md, the API reference, the architecture notes, the wiki and the codeman skill.
-5
View File
@@ -1,5 +0,0 @@
---
'aicodeman': minor
---
Add offline `codeman history read` for saved Codex transcripts by file, native session ID, or conversation family (spawned sub-agents and forks included), with whole-turn topic and UTC date filters. A forked or spawned thread's copy of its parent's history is dropped, so every record belongs to the thread that wrote it. Store attribution has its own budget (`--metadata-bytes`), separate from the transcript budget (`--scan-bytes`), and every bound is raisable (`--max-entries` too), so id lookups keep working on stores of thousands of rollouts. A store file that cannot be attributed, an unreadable directory, or a rollout a running Codex is still appending to no longer fails the lookup; each is reported through `complete: false`, as is a Codex rollout compressed to `.jsonl.zst` (counted in `compressedFiles` and named when a lookup misses). A parent file read to prove where a forked copy ends is charged to `--scan-bytes` once, and a parent that cannot be read leaves that boundary unproven instead of failing the child. Assistant records carry Codex's own phase and user records none. The Past Sessions scanner and the offline reader now share one Codex rollout format module, including the injected-context rule.
-7
View File
@@ -1,7 +0,0 @@
---
"aicodeman": minor
---
Allow `codeman agent spawn` to start workers in the current project directory or an existing directory selected with `--working-dir`, while preserving explicit case quick-start behavior. A directory launch uses `POST /api/v1/sessions` followed by the mode's start route (`/interactive` or `/shell`), and its `--json` output is `{ sessionId, workingDir, created: true }`, plus `ready` when a readiness wait ran, `readinessError` when that call failed, and `startupError` when the start failed (exit 1). Only an omitted case means "use a directory": an empty case name still goes to quick-start, which refuses it, and an empty or whitespace-only `--working-dir` is refused locally (exit 4) before any request instead of resolving to the cwd. A cwd that resolves to the home directory is refused the same way, because the server would install its workspace hooks (and an injected skill) into `~/.claude`; an explicit `--working-dir ~` is still accepted.
One change for named-case spawns too: an unknown `--mode` is now refused locally (exit 4) before any request, where it used to reach quick-start and come back as the server's 400 (exit 1).
-5
View File
@@ -1,5 +0,0 @@
---
'aicodeman': patch
---
Preserve the created session ID in agent spawn output when the readiness request fails with a transport error.
-5
View File
@@ -1,5 +0,0 @@
---
'aicodeman': patch
---
Security fix: `CODEMAN_ALLOW_UNAUTHENTICATED_NETWORK` (and `--allow-unauthenticated-network`) no longer lets the Cloudflare tunnel start without a password. It now acknowledges only an unauthenticated network bind, which is what the installer writes it for on a LAN install without a password, so on those installs one click on the welcome screen's tunnel link published full terminal control to a public URL with no login and no confirm. An unauthenticated tunnel has its own opt-in now, `CODEMAN_ALLOW_UNAUTHENTICATED_TUNNEL=1` or `codeman web --allow-unauthenticated-tunnel` (carried by `codeman web -d` and `codeman service install`), which the installer never writes. If you relied on the network variable to start the tunnel without a password, set one of those instead. Without it the server still accepts an enable that carries `acknowledgeUnauthTunnel: true`, as before. With no password and no multi-user mode, the browser now asks before every tunnel enable from the welcome link, the tunnel panel and App Settings, whatever the server would accept, using the new `loginConfigured` field of `GET /api/tunnel/status`.
@@ -1,6 +0,0 @@
---
"aicodeman": patch
"xterm-zerolag-input": patch
---
**Typing stays smooth in a long prompt.** The local echo overlay (the instant preview of what you type before the session echoes it back) used to throw away and rebuild every character of the prompt on each keystroke, so the longer the prompt, the slower each key. On a phone-class CPU it dropped below 60 fps at about 300 characters, and at about 4,000 characters a single keystroke took most of a second to appear. It now rebuilds only the line that changed, and each line is one paint layer instead of one layer per character, so a keystroke costs the same however long the prompt is. What you see is unchanged: every character still sits on its terminal cell, within 1/8 px. This ships in `xterm-zerolag-input` as well: the README's rendering section describes the new layout.