Commit Graph
1043 Commits
Author SHA1 Message Date
Codeman maintainer d1e0e0aea6 fix: address the release-prep review of #680
Claude history merges, never overwriting, into a project directory a deleted case of the new name left behind, instead of staying orphaned under the old key.
The free-target pre-check also refuses a dangling symlink (lstat), so stopSessions no longer ends sessions before a 409 EXISTS.
The rename dialog says stopped sessions are closed (their tabs go away) and, after a failed rename, how many were already closed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 14:43:13 +02:00
Codeman maintainer 9dec12b6e7 fix: address the release-prep review of #684
Re-read the per-IP failure count after the scrypt await, so concurrent failures from one IP are all counted (regression test added).
Reword the (username, IP) bucket comment: it grows with failed verifies per pair, not no faster than userFailures.
Reword the verify-first test comment: only the per-username bucket never denies a correct password.
Correct docs/multi-user-plan.md: the per-username bucket does not stop cross-IP brute force; the per-(username, IP) bucket caps verified guesses.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 14:32:36 +02:00
Codeman maintainer 9ba24a02df fix: apply the review items for #690 at merge
Boot prune keeps the inboxes of sessions on the reboot-restore offer (their records are already pruned and a rebuild reuses the id), with a case in test/agent-inbox-server-wiring.test.ts.
docs/wiki: post, inbox and ack in the codeman agent command block of Driving-Codeman-From-An-Agent, and "Keep agent inbox across restarts" in Settings-Reference.
codeman agent inbox prints message text through terminalSafeText (ANSI stripped, other C0, DEL and C1 controls shown as \xHH); --json stays as stored.
Shutdown flushes the inbox snapshot again after app.close(), for a post that lands after the first flush.
POST /api/cleanup-state drops the inboxes of the records it removes.
InboxPostSchema derives its fence from MAX_MESSAGE_BYTES instead of the literal.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 14:15:49 +02:00
Codeman maintainer 7783fcd0ce fix: apply the review items for #692 at merge
host-sensors: never await the PowerShell RAM probe on a read; keep the resolved total and show the memory in use alone until it answers (test with a held PowerShell)
test: rename the Windows sampler test that said the GPU counters are added "for good"
test: make host-sensors.test.ts's @fileoverview describe what that file covers
host-sensors: make the nvidiaSkipUntil JSDoc describe the back-off deadline
docs: Settings Reference says the host readings live inside System Stats and nothing is fetched while it is off

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 14:15:22 +02:00
Codeman maintainer b7897b6d0e fix: apply the review items for #684 at merge
Multi-user: add a (username, IP) failure bucket checked before verifyPassword, capped at AUTH_FAILURE_MAX, with the same decay as the other buckets; the per-IP pre-gate stays at AUTH_IP_FAILURE_MAX and the per-username bucket stays after the verify
A correct password now also clears that account's (username, IP) bucket, beside the IP and per-username buckets
The new bucket is disposed on server stop like the others; the comments above the gate and the constants' JSDoc describe the three buckets
Tests: 10 wrong then the correct password from one IP is a 429, the same account logs in from another IP, another account behind that IP is unaffected, and a correct password clears the pair bucket
test/multiuser-auth.test.ts: the spray test loops to AUTH_IP_FAILURE_MAX instead of a literal 50
Reworded the rate-limit lines in auth-config.ts, security-architecture.md, README.md, README.zh-CN.md, wiki/Security.md, endpoints.md (plus the plugin mirror), CLAUDE.md and architecture-invariants.md
docs/wiki/Remote-Access.md: add the multi-user note to the tunnel page

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 14:15:21 +02:00
Codeman maintainer 80e7bb1031 fix: apply the review items for #698 at merge
changeset: say Codex does not track the mouse "measured on 0.162.1 and 0.164.0", since 0.163.0 fullscreen was measured tracking it
docs/architecture-invariants.md: list page-keys-dialog-open and page-keys-menu-open among the [scroll] decisions

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 14:13:15 +02:00
Codeman maintainer 311d01c52b fix: apply the review items for #688 at merge
disarmTuiSwitchGuard matches the closed `#{client_tty},<tty>}` form, so a TUI on /dev/pts/4 no longer removes the hook armed for a second TUI on /dev/pts/41 (unit test plus a real-tmux case)
beginAttachHandoff arms the one-shot attach hook as its last tmux call before spawnSync, after the switch keys and the per-session dressing loop, with an order assertion in tui-app.test.ts and a sentence in the invariants paragraph
docs/remote-sessions.md and the buildRemoteLaunchCommand JSDoc show `remain-on-exit failed` at the end of the remote create chain

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 14:10:07 +02:00
Codeman maintainer 34a2966c19 fix: apply the review items for #689 at merge
Clamp the stored toolbar width to MIN_WIDTH in apply() and step the arrow keys from the width on screen, so a drag to the window edge or a held ArrowRight no longer stores a negative width or leaves an ArrowLeft dead zone (browser test added)
Drop Escape as a reset key on the handle: the global capture-phase Escape handler already closes every panel on it (static pin added)
Say in the changeset, the wiki and the densityFor comment that the percentages go at the narrowest step in the Compact style only, and drop Escape from the changeset

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 14:08:37 +02:00
Codeman maintainer d16172c4b8 fix: apply the review items for #685 at merge
palette agent switch: aria-hidden on .command-palette-agent, arrows lose role="button" and aria-label (no nested buttons in the row)
i18n: zh-CN entry for the "Agent for the new session (Left/Right to change)" tooltip
docs: Keyboard-Shortcuts Ctrl+K row says Left/Right change the agent on the New session row
test: pin the aria-hidden switch and the zh-CN tooltip entry in command-palette-ui.test.ts

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 14:05:12 +02:00
Codeman maintainer 4da6aee660 fix: apply the review items for #682 at merge
docs: architecture-invariants (arrow-key walk section) names the phone swipe beside the arrow keys as following the drawn order
docs: root CLAUDE.md (Owner tab layouts) carves the phone swipe out of "every other order consumer reads sessionOrder"
test: pin the grouped-tree branch of _stripSessionOrder() (sorted rail, header and web tab skipped, groups not interleaved)
test: the step-in case uses a drawn order (homelab, w1, w2) that master's canonical walk and the old arithmetic cannot satisfy

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 14:05:05 +02:00
Codeman maintainer d41ad16818 fix: apply the review items for #681 at merge
_notePaneHistory JSDoc names the responses it skips (an error envelope on any path, a refresh that lost its owner, a pull whose select generation moved)
selectSession records the pane count only for a non-error envelope (capture.json?.success !== false), pinned in the static guard of test/pane-history-memory.test.ts; the two invariant paragraphs now name the tab switch beside the refresh and the pull

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 14:02:21 +02:00
Codeman maintainer ac6d4aa2db fix: apply the review items for #680 at merge
Restore settings.json (caseOrder, lastUsedCase) when linked-cases.json cannot be written, with the rollback test extended
List Claude Code's per-project ~/.claude.json entry as not migrated in Core-Concepts.md and CLAUDE.md
Say in the 500 that the folder is now at the new path when moving it back fails
Describe the rename dialog's folder checkbox in Core-Concepts.md, carry stoppedSessions on errors, count 5 case SSE events

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 14:01:33 +02:00
Codeman maintainer f4f9001a4b fix: apply the review items for #678 at merge
docs: document the SSE connect timeout next to the staleness watchdog in src/web/CLAUDE.md and docs/architecture-invariants.md (clear order, replaced-EventSource guards, offline handler leaves the timer)
test: rename the offline case to "connectSSE() while offline cancels the pending timer" so it names the path it drives

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-24 13:59:17 +02:00
Devvyn 23a9d78cdd fix(host-sensors): never wait on a cold sampler, back off failing readers, one stats request at a time 2026-10-24 10:17:20 +08:00
Devvyn 77eefce4f6 fix(terminal): carry leftover travel into a notch's page, document the new rule 2026-10-24 10:12:58 +08:00
Devvyn 372df864b9 fix(terminal): review of the Codex menu wheel guard 2026-10-24 10:10:38 +08:00
Aamer Akhter 27c93b20fb fix(terminal): stop URL continuations from swallowing prose 2026-10-23 10:00:38 -04:00
Devvyn e1d6471808 feat(header): opt-in GPU and CPU clock readings after CPU and MEM 2026-10-23 21:36:10 +08:00
RandalixandClaude Opus 5.5 1c87cd2ac7 fix(edit-history): review round 3 — restored sessions read again, /clear reads the old conversation to its end, bounded memory
- remove() drops the session's slot once the file is gone: a session that comes
  back with the same id (reboot restore) starts afresh instead of answering
  `removed` until the next restart. A run in flight stays on its own slot's store,
  and the routes start a sync in the same tick as their session check, so a
  deletion right after it still stops that sync. A store that is not loaded is
  deleted without being parsed (deleteStore).
- A new conversation (/clear, resume) first reads the previous transcript, next
  to the new one, to its end with its subagents, so edits it got after the last
  read are not lost with its cursors. "Load older" reads the stored conversation
  while the switch is pending.
- At most MAX_LOADED_STORES (3) stores stay in memory; the least recently used one
  without a run is written if it changed (settle) and loads again on demand.
- Tmp files are named per process start, so a reused pid (a container's pid 1)
  no longer keeps a stale one through the startup sweep.
- load() keeps only a plain transcript id (the previous transcript's path is built
  from it) and no cursors without one; a pending Bash call with an id, cwd or
  agent id over 4,096 characters is not kept at parse time either.
- nextRange() is gone: production reads forward through the reader. The store
  tests mirror the reader's range choice, and a new end-to-end test runs the
  real reader, sync and store (/clear cases, 40 seeded random transcripts).
- The wiring guard scans all of src for holders of the sync.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 15:35:12 +02:00
Aamer Akhter 74a107cf4f fix(terminal): require path labels and preserve markdown context 2026-10-23 09:01:44 -04:00
RandalixandClaude Opus 5.5 321268754a fix(edit-history): review round 2 — whole lines around skipped ones, full-budget reads, orphan sweep
- Forward: after a line longer than the budget, the next line is read from
  its start instead of being skipped with it when it crosses the chunk end.
- Backward: the line before a skipped long line is read whole; a floor that
  turned out to be a line start no longer stalls.
- A chunk the shared forward budget cut short is not applied (it read as one
  over-long line) but read in a later pass, so a first open of a long main
  transcript reaches the subagents in the same sync.
- Load older reads a full budget block of up to three transcripts per click,
  taking turns, instead of splitting one budget (a normal Write longer than
  the share was skipped for good).
- A subagent transcript that vanished loses its cursor, so Load older does not
  stay on forever.
- POST /api/cleanup-state forgets the history of every record it drops; a
  startup sweep deletes edit-history files no session or record owns and
  stale tmp files of other processes.
- load() rebuilds entries from known fields (string diff lines, per-edit cap
  re-applied, ids counted against the byte cap), bounds pending Bash fields
  and agent ids, and does not parse a file over 32 MiB.
- No re-read after Codeman's own keep-alive turn.
- Tests: regression tests for each of the above (they fail on the previous
  commit); the remove-during-write test now meets the write under way; the
  sync and route tests remove their stores before the temp dir, so no late
  save recreates it in /tmp.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 15:00:43 +02:00
RandalixandClaude Opus 5.5 f5ce80dce2 fix(edit-history): re-read at the end of a turn on session:idle
transcript:complete fires on a `result` line, and claude's interactive transcript has
none (checked against a live session: user/assistant/system turn_duration, no result),
so an open panel never re-read at the end of a turn. A background subagent writes after
the Agent tool end that started it, so its edits stayed missing until the next edit-
capable tool end or a manual refresh.

The panel now re-reads on its session's session:idle, through _onSessionIdle (the SSE
handler map holds one handler per event). Live: a backgrounded subagent's Write shows
up in the open panel at the end of the turn, without a click.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 14:38:54 +02:00
RandalixandClaude Opus 5.5 dcdeaab98d fix(edit-history): review round 1 — record-bound deletion, load-time bounds, older reads per source
- The history is deleted when the session's persisted record goes (forgetEditHistory):
  kill via cleanupSession (a pinned record is only demoted and keeps it), the
  persisted-only DELETE, and stale cleanup at startup. After remove() neither a sync in
  flight nor a later request writes the file again; writes are serialized.
- load() re-bounds a damaged file: cursors, pending Bash calls (MAX_PENDING_BASH) and
  subagent labels (MAX_AGENTS, oldest unused dropped first).
- Load older reads one block of every transcript, budget split between them, and only
  the files it asked for; a block short of budget reads its end. A line longer than the
  budget is skipped going back as well (floorMidLine).
- Concurrent first callers share one store; a forward request folded with an older one
  still reads forward.
- Images outside the workspace get no thumbnail (one attachment id per render); a click
  opens the shared preview, which registers once with notify: false.
- Docs: per-edit diff cap, deletion rule, load-time bounds, thumbnails, follow triggers.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 14:30:05 +02:00
RandalixandClaude Opus 5.5 95e2272f89 feat(edit-history): edit history panel for local claude sessions
Part 1 of #643 (local sessions only; remote follows as its own PR). An
opt-in, per-device header button opens a panel with the active session's
edits, newest first: every Edit/Write/MultiEdit/NotebookEdit of the main
agent and its subagents with its diff, plus images a Bash call rendered or
the agent sent. Remote, Docker and non-claude sessions answer `unsupported`.

- Reads only on request: `?sync=1` when the panel opens; while it is open on
  that session it re-reads after an edit-capable `transcript:tool_end` or a
  `transcript:complete` from the existing transcript watcher. No hook, timer,
  second watcher or new SSE event; a wiring guard pins it.
- Main transcript: the path the transcript watcher follows (hook-reported),
  else `<id>.jsonl` under the session's own CLAUDE_CONFIG_DIR override or
  the server's config dir. A config dir set outside Codeman is found with
  the next hook; until then the panel says so.
- Store: dataPath('edit-history')/<id>.json, 0600 via tmp+rename, capped at
  500 entries and 4 MiB of diff text per session, deleted with the session,
  blocked in isSensitivePath, never fed to /api/search. Every route goes
  through findSessionOrFail with req.
- Images only through existing file surfaces: file-raw inside the
  workspace, the attachment route with notify:false outside it.
- textContent rendering, bounded byte-offset reads, marker-class header
  button, hidden on phones (locked in the mobile policy test).

Docs: Working-With-Files, Settings-Reference, architecture invariants, API
reference, CLAUDE.md key pattern.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 14:00:48 +02:00
Devvyn f3c90abeb0 fix(header): settle the divider when readings change, keep density to the header layout, restore the chosen width 2026-10-23 19:58:40 +08:00
Aamer Akhter 40a9528be1 fix(terminal): keep unrelated rows out of wrapped links 2026-10-23 07:26:15 -04:00
Aamer Akhter efa647d257 fix(terminal): exclude relative prose and trim spaced paths linearly 2026-10-23 07:26:15 -04:00
RandalixandClaude Opus 5.5 a1a33cf050 fix(agent-inbox): review round 1
- codeman agent post: accept text that starts with "-" (markdown from a
  file), --json and -h stay options.
- DELETE /api/sessions/:id on a persisted-only row drops the inbox a detach
  kept.
- inbox --wait: wait.ended is exit 3 only when the session list no longer has
  the session; a restart or detach ending the wait is exit 2 (wait again).
- A read whose client hung up during ?wait= marks nothing seen.
- InboxPostSchema bound is 4x the byte cap, so every oversize message gets
  the store's "post a file path" answer.
- Store: restore sorts oldest first; the TTL sweep checks every message,
  not only the first.
- Docs: admins can act as any session of the receiver's owner (now tested
  for admin and non-admin); a peek with ?wait= does not block; exit codes.
- Tests: partial PUT /api/settings keeps persistence on.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 12:45:48 +02:00
RandalixandClaude Opus 5.5 c6dfaa2cac feat(agent): per-session agent inbox (discussion #558)
A coordinator can leave text for a worker without typing into its pane.

- Store (src/web/agent-inbox.ts): read until ack by id, seen only for the
  receiver, 16 KiB/message, 512 KiB + 200 messages per inbox, full = 409
  CONFLICT (never drops the oldest), 12 h TTL from each message's createdAt.
- Routes (routes/inbox-routes.ts): POST/GET /api/sessions/:id/inbox
  (?wait= parks while nothing is unseen), POST .../inbox/ack (receiver
  only, 403 otherwise), GET /api/agent-inbox/summary (owner-scoped counts,
  not in toState()). Caller = resolveParentSessionId().
- Inbox waiters are the wait registry's third kind: same caps, ended by
  cancelAll/cancelEverything.
- Opt-in snapshot (agentInboxPersistEnabled, synced, default off):
  agent-inbox.json via dataPath(), 0600 tmp+rename, off deletes it, boot
  prune only after a successful restore. Dropped on delete, kept on detach.
- CLI: codeman agent post | inbox [--wait] | ack, INBOX column in ls.
- waitCapacityResponse/abortOnClientHangUp moved to route-helpers.ts
  unchanged.
- Docs: api-reference, README, CLAUDE.md, architecture-invariants, skill +
  plugin mirror.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-23 12:45:48 +02:00
DDTandDDT 9fc2773176 fix(tmux): bind nested prefix before unbind so an empty table cannot abort the chain
A user tmux config that leaves the prefix table empty makes
unbind-key -a -T prefix fail and drop later commands in the \; chain,
including send-prefix and remain-on-exit failed. Bind C-q send-prefix,
clear the table, then bind it again.

Also accept macOS ttys in the TUI switch-guard test without reading
/proc, and describe the client_pid hook escape as defensive on tmux 3.4.

Co-authored-by: DDT <1786035110@qq.com>
2026-10-23 09:08:48 +00:00
DDTandDDT daeea54495 fix(tmux): stop nested prefix keys and TUI Alt+digits from moving other clients
Docker and owned-remote tmux servers kept the stock prefix table, so Ctrl+Q
then )/(/s/w/L switch-client'd the inner client onto a sibling. Those create
chains now leave only C-q send-prefix.

codeman tui bound M-1..M-9 in the server-wide root table. The keys stay, but
switch-client runs only for the attaching client (tty plus a one-shot pid).
A browser tab's Esc-then-digit no longer jumps sessions, and a killed TUI
leaves a binding that matches no live client.

Co-authored-by: DDT <1786035110@qq.com>
2026-10-23 07:41:46 +00:00
Aamer Akhter 175e3b8320 fix(auth): keep the single-user login throttle at 10, widen only the multi-user pre-gate
Single-user mode has no per-username bucket, so its per-IP bucket is the
only limit on guesses against the one password, and behind a tunnel every
client shares 127.0.0.1. Put it back on AUTH_FAILURE_MAX (10).

AUTH_IP_FAILURE_MAX (50) now gates only the multi-user per-IP pre-gate,
which runs before the scrypt verify and so refuses even a correct password;
the per-username bucket still caps each account at 10.

Move the headroom test out of the single-user suite and add a multi-user
test that sprays wrong passwords across usernames (9 each) and expects 401
for the first 50, then 429 for the 51st and for a correct password.

Update the docs that still described 10 per IP for every mode, and resync
the plugin mirror of the codeman skill.
2026-10-22 21:21:49 -04:00
Aamer Akhter ebb9e00de9 fix(auth): widen the per-IP login throttle to 50, keep the per-account lockout at 10
One AUTH_FAILURE_MAX (10 per 15 min) gated the single-user per-IP
bucket, the multi-user per-IP pre-gate, the per-username lockout and the
hook-secret bucket. Clients sharing one egress IP (NAT, a tunnel, an
automated client retrying) were throttled after 10 failures in total.

Add AUTH_IP_FAILURE_MAX = 50 and use it for the two per-IP login buckets
only. The per-username lockout and the hook-secret bucket keep
AUTH_FAILURE_MAX = 10, so guessing against any one account, or against
the hook secret, is no easier than before.
2026-10-22 17:23:03 -04:00
Devvyn 1cad4dd848 fix(cases): address review of the rename route
Only an admin's rename touches the server-wide settings.json, which is now
written before linked-cases.json with the registry restored on failure. The
Resume list follows a renamed folder, the owner's default session group is
carried over, remote sessions are never listed or stopped, errorCode maps
EXISTS and BUSY, and the unmigrated items are documented.
2026-10-23 04:15:46 +08:00
Devvyn ab0bc0aecd feat(cases): rename a case and its folder, with a lock and live-session handling 2026-10-23 04:12:37 +08:00
JD 84adb701d7 fix(terminal): load tmux history instead of paging Claude after a hollow tab switch
After a server restart the byte recording a tab switch replays (`?tail=`) holds only the tmux client's attach repaint, so an inline Claude session came back with an empty local buffer while tmux still held its scrollback. The hollow-buffer fallback then sent PageUp/PageDown to Claude, which moved the composer cursor instead of the transcript, until a page reload. Pre-existing on an unmodified build; every restart of the server showed it.

The paging fallback now stands down when the last capture reported tmux scrollback (`paneHistoryLines` > 0), dropping the gesture debt and any page keys already queued, so the gesture falls through to the local path, whose scroll-to-top pull fetches `full=1` and the gesture scrolls on from there. Zero and unknown counts keep paging (fullscreen Claude, codex, opencode, remote and Docker panes). The pull no longer inherits a downgrade refusal's 60 s latch for such a buffer, drops a completion that outlived a tab switch back to the same session (select generation, not only the session id), records no count from an error envelope (a JSON 5xx would otherwise forget it and hand the next gesture back to paging), and re-positions the local-echo overlay after its rewrite. The refresh path records its count only once it still owns the terminal, for the same reason. The `[scroll]` line prints `paneHistoryLines` so an unloaded buffer reads apart from a hollow one, and the invariant docs record the exception.

Measured with phone emulation after a restart: before, the second visit landed at baseY 0 and every swipe sent PageUp; after, the first swipe fetched the history once with nothing sent to Claude and the gesture scrolled 21 rows, with an unsent draft intact on the overlay.
2026-10-22 15:13:01 -04:00
JD 116961f3a8 fix(mobile): swipe through sessions in the order the strip draws them
nextSession/prevSession walk the canonical sessionOrder, but the case and state tab layouts, a sorted rail and named groups reorder the strip, so with any of them a swipe jumped to tabs that were not next to the current one on screen. The swipe now asks for the drawn order, read with the same walk the strip's arrow keys already use (factored out as _visibleTabRows); Alt+[ / Alt+], Ctrl+Tab and Alt+1..9 keep the canonical order. An active session the list does not draw steps in at the first or last row, and an empty drawn list goes nowhere instead of falling back to a hidden session.
2026-10-22 15:11:21 -04:00
Codeman maintainer a85da87378 Merge pull request #674: fix(mobile): give a sideways drag on the terminal to the session swipe alone
Second merge of #674: the author pushed the thumb-arc handback from the review themselves (e8fc08be), byte-identical in code to the merge-time fix already here, so this brings their round in and keeps the browser test and docs added at merge.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

# Conflicts:
#	docs/wiki/Mobile-Guide.md
#	src/web/public/terminal-ui.js
#	test/session-swipe-gesture.test.ts
2026-10-22 20:32:13 +02:00
Codeman maintainer 463a083a23 Merge pull request #676: feat(tabs): per-case default session group
Conflict in CLAUDE.md's State Files line resolved by keeping #661's new
config-backup entries and this PR's "case default groups" in state.json.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:54:54 +02:00
Codeman maintainer 3b6818449e Merge pull request #661: feat(config): timestamped config backups with a configurable folder and retention
Conflicts in CLAUDE.md, README.md, docs/api-reference.md and
src/web/server.ts were additions beside #662's Copilot quota read and
#666's keep-warm sections; both sides kept.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:54:40 +02:00
JD e8fc08beb3 fix(mobile): hand a swipe-locked drag back to the scroll past the swipe's drift limit
A scroll whose first move past the tap slop leaned sideways (a thumb arc) locked as 'swipe' for the whole contact, and SwipeHandler drops a swipe at 50 px of vertical drift, so the gesture did nothing. Past that limit the drag is now a 'y' scroll. Also brings the mobile-handlers fileoverview to the current 500 ms / 50 px limits and notes in the Mobile Guide that a selection pauses the swipe and a wide terminal pans instead.
2026-10-22 13:53:48 -04:00
Codeman maintainer 9045b18553 Merge pull request #660: fix(test): make a bare vitest invocation use the isolated CI config
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:53:43 +02:00
DevvynandClaude Opus 5.5 33d697afe3 fix(custom-model): warn when parallel llama.cpp slots leave too little context per request (#658)
Squash of PR #658. Discovery records each llama.cpp model's parallel slot
count (from --parallel/-np, or /props total_slots when the launch command
states none), and a Claude launch warns when the context split across
those slots leaves less than 40K tokens per request. An explicit
--parallel beside a /props context records a slot count of 1, so a later
round overwrites an earlier count, and a non-2xx /props is remembered per
launch command while a network error is retried.

Merge-time fix by the maintainer: the architecture-invariants sentence on
the explicit --parallel case now says it records a slot count of 1.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:32:24 +02:00
Codeman maintainer 0c1578581f docs: case default groups in CLAUDE.md, and the Cases handler count
Merge-time fix for #676 (review finding 3 and nit 9). The State Files entry
for state.json names the new caseDefaultGroups key, and the Owner tab layouts
paragraph says where a case's default session group sits in the placement
order of sessionCreated() and that only TabLayoutService reads or writes it.
The wiki endpoint map counts the two new case routes (37 to 39).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:32:23 +02:00
DevvynandClaude Opus 5.5 34cf798b10 feat(copilot): plan-usage chip row for the monthly premium-request quota (#662)
Squash of PR #662. The header plan-usage chip gains a Copilot row: the
calendar-month premium-request quota, with the request counts and the
reset in the tooltip, read every 10 minutes from GitHub's
copilot_internal/user endpoint with the Copilot CLI's own sign-in token.
It rides showPlanUsageLimits and is on by default while the CLI is
installed and signed in; any failure leaves the chip without the row.

Merge-time fixes by the maintainer: the gates (setting, then token, then
the CLI probe) live in readCopilotPlanUsageIfEnabled() so a host with no
Copilot sign-in never runs the login-shell probe each tick, with a test
that Plan Usage Limits off means no request; the X-GitHub-Api-Version
header the Copilot CLI itself does not send is dropped; and CLAUDE.md,
architecture-invariants, README and copilot-integration describe the read.
The hooks-config import in server.ts was merged with #666's.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:32:17 +02:00
Codeman maintainer 9b8cb82c3b fix(tabs): leave the default-group options alone when the groups did not change
Merge-time fix for #676 (review nit 6). Once a Case settings popover had been
opened, every adopted tab layout (each create, delete and reorder) replaced
both selects' options, even with the popover hidden and the group list
unchanged, so a session created elsewhere could reset a native dropdown the
user had open. _refreshCaseDefaultGroupOptions now returns early when the ids
and names are the same. A vm case pins it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:32:12 +02:00
Codeman maintainer a3efc9b963 fix(tabs): keep the case-default GET read-only, forget a stale id outside the rollback
Merge-time fix for #676 (review nits 4 and 5). sessionCreated forgot a stale
case default inside the try whose catch rolls the registration back; it now
does so after the try, once the session is committed, so the cleanup can
never drop a committed session from the live map. caseDefaultGroup (behind
GET /api/cases/:name/default-group) no longer deletes a stale id as a side
effect: it reports Ungrouped and leaves the value for the next creation to
forget. The two tests that expected the read to clear it now expect it to
write nothing; the creation test still pins the cleanup.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:31:21 +02:00
Codeman maintainer f80f107445 Merge pull request #666: feat(sessions): keep an idle session's prompt cache warm with a guarded keep-alive turn
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:31:08 +02:00
Codeman maintainer 3652670a7d Merge pull request #645: fix(terminal): isolate scroll batches and support tracked Codex scrolling
The remote-history PATH bootstrap that rode along in this PR was left out
at merge (it belongs in its own PR that routes every remote tmux call
through one wrapper), so 242bbfcd's title overstates what lands here.

Conflicts in CLAUDE.md and docs/architecture-invariants.md resolved by
keeping this PR's rewrite of the wheel/touch paragraphs and re-adding
#664's touch-forwarding sentence to both.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:29:53 +02:00
Codeman maintainer 5a677bf03c fix(tabs): a Claude worktree session gets its case's default group too
Merge-time fix for #676 (review finding 1 and nit 7). The Git worktrees modal
launches Claude through POST /api/sessions with workingDir
<case>/.claude/worktrees/<name>, which inferLocalCaseName did not recognise,
so the session landed in Ungrouped while the same gesture for any other CLI
(quick-start with the case name) landed in the group. The inference now
strips a trailing .claude/worktrees/<name> lexically before its two checks,
reusing CLAUDE_WORKTREE_PATH (hoisted to module scope). It also runs only for
a named workingDir, never on the server's own cwd, as the hook and skill
injection above already do. Route tests for both, failing without the fix;
api-reference and architecture-invariants say so.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:29:25 +02:00