Commit Graph
3526 Commits
Author SHA1 Message Date
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 3ca1d4832e test(ralph): pin the case name a Ralph loop start registers with
Merge-time fix for #676 (review finding 2). POST /api/ralph-loop/start now
passes { caseName } to addSession so the session lands in its case's default
session group, and nothing tested it. The registration-order test asserts the
placement argument; it fails against the route without the change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:29:50 +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
Codeman maintainer 9d30a7ff36 Merge pull request #674: fix(mobile): give a sideways drag on the terminal to the session swipe alone
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:28:49 +02:00
Codeman maintainer 04faa0d3f1 Merge pull request #664: fix(terminal): forward touch scrolling for native SGR mouse tracking
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:28:49 +02:00
Aamer Akhter 536eca8f3d fix(sse): retry an EventSource connect attempt that never opens
An EventSource whose request never gets response headers stays in
CONNECTING without firing open or error, so the backoff never runs and
the staleness watchdog (which only judges a 'connected' stream) cannot
see it. Bound each attempt with a 15s connect timeout: if open has not
fired, close the attempt and retry through the same path onerror uses.

The timer is cleared on open, on failure and at the top of every
connectSSE(), and both the timeout and the failure handler ignore an
EventSource that has since been replaced.
2026-10-22 13:28:43 -04:00
Aamer Akhter 3489f6cc80 fix(tmux): send prompts that start with a hyphen literally
`send-keys -l <text>` keeps parsing options after `-l`, so text starting
with `-` was read as a flag ("unknown flag -x", "invalid flag --") and
never typed. End option parsing with `--` at every send-keys -l site in
sendInput() and sendInputToPane(), as set-buffer already does.
2026-10-22 13:26:04 -04:00
Codeman maintainer 6d2763d50b docs(test): a bare vitest is isolated now, and the guards need the sandbox HOME
Merge-time fix for #660. CLAUDE.md and architecture-invariants still said a
raw npx vitest skips setup.ts, contradicting the updated Testing note: both
now say it resolves the root vitest.config.ts (and why that file must stay).
The architecture-invariants entry for safeRmHomeTree adds the sandbox-HOME
requirement (isSandboxedHome, TEST_HOME_PREFIX), the same rule for
isUnderTestHome, the route-harness assert and the 2026-10-10 incident.
CLAUDE.md's repo-root preamble lists vitest.config.ts with its reason, so a
tidy-up does not move it into config/ and reopen #640. The
assertSandboxedHome JSDoc no longer claims every route test is covered: only
the ones built on createRouteTestHarness are.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:25:52 +02:00
Codeman maintainer 6310868696 fix(test): bound the temp-HOME removal by a deadline, not an attempt count
Merge-time fix for #660. afterAll runs under vitest's 10 s hookTimeout, and
each failed removal attempt costs rmSync's own retry sleeps (50 + 100 + 150
ms) plus the 250 ms wait, so 20 attempts overran it: with a writer still
filling $HOME/.claude/backups, the file failed with "Hook timed out in
10000ms" after its test passed, and the "leave it to the exit backstop" branch
was never reached. The loop now stops after about 5 s. Checked with a
temporary (uncommitted) test that leaves a child process writing there for
20 s: before, the file failed at 11 s with the hook timeout; after, it passes
in under 6 s.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:25:04 +02:00
Codeman maintainer b4275e690e Merge pull request #665: fix(response-viewer): open markdown links to file paths in the preview, not as a same-origin URL
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:23:17 +02:00
Codeman maintainer cef64dc052 Merge pull request #659: feat(file-viewer): resize and expand the window, back/forward between previewed files
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:23:17 +02:00
Codeman maintainer b67018b318 Merge pull request #670: fix(input): keep the line breaks of a multi-line mux prompt, pasted as one block
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:23:17 +02:00
6eaaa960ff fix(tmux): keep browser keys from switching a tab onto another session (#669)
Squash of PR #669. Browser terminals could be moved onto another session
by tmux's prefix keys: Ctrl+B then ), (, s or w switched the tab's tmux
client to a different session while the tab kept the original's name.
Codeman's tmux socket now keeps only Ctrl+B Ctrl+B (send-prefix) in its
prefix table, and codeman tui and scripts/tmux-manager.sh get F1 as their
way out instead of Ctrl+B d.

Merge-time fixes by the maintainer: on an empty prefix table the
unbind-key that fails no longer skips binding send-prefix; a key tmux lists
escaped (prefix C-\ shows as C-\\) compares equal, so the reset does not rerun on every create;
and reconcileSessions() reduces the table at boot when the socket has live
sessions, so sessions that survive an upgrade are covered too.

Co-authored-by: christianhaberl <116439789+christianhaberl@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:23:17 +02:00
Codeman maintainer 620e7728ec Merge pull request #667: fix(mux): give a discovered tmux session its pane's directory, not the server cwd
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:23:09 +02:00
Codeman maintainer 6cf5ab05d6 docs: config backups section in architecture-invariants, CLAUDE.md pointer and State Files
Merge-time fix for #661, as promised in the reviews. The long Config backups
paragraph in CLAUDE.md moves into a new architecture-invariants section that
gives each rule with the reason behind it (allowlist, volatile keys, retention
by successor and the date floor, the origin id, retention after a bad or
reset settings.json, the bounded probe, one walk per pass, verify before
write, the undo copy and the partial-restore answer, the reload hooks,
redaction, admin only). CLAUDE.md keeps the short rules and a pointer, and the
State Files list names config-backup-id and backups/config/ with the
retention each manifest records.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:21:02 +02:00
Codeman maintainer fde23e3a07 fix(response-viewer): keep a path link's label in the prose font, pin its edges
Merge-time fix for #665.

- A markdown link converted to a preview link became `a.rv-path`, so its
  label ("Our incident record") took the path style: monospace, 0.92em
  and `word-break: break-all`, which split prose mid-word on a phone. The
  anchor now also carries `rv-path-link`, and
  `.rv-text a.rv-path.rv-path-link` resets font and word-break, as the
  File Viewer does for its labelled document links.
- The first new test adds `/tmp/a.json?raw=true` (pins the `?query`
  strip) and `/tmp/` (pins the trailing-slash folder check, since
  findFilePathLinks finds no folder in a bare `/tmp/`), and checks the
  new class.
- The `_linkifyFilePaths` JSDoc and docs/architecture-invariants.md say
  the function also rewrites anchors whose href is a scheme-less,
  non-`//` path, on purpose without FILE_PATH_LINK_PATTERN's root and
  extension filter.
- Mobile Guide: "a web link" in the response viewer opens a tab.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:20:01 +02:00
Codeman maintainer ebb50ef53a fix(config-backup): reuse the newest backup as the undo copy when nothing changed
Merge-time fix for #661. The pre-restore copy was forced, so a restore made
while the live files equalled the newest backup spent a retention slot on a
duplicate. It now goes through the normal change check: when nothing changed
since the newest backup, no copy is made and safetySnapshot names that
backup. Two tests that relied on the forced copy now change a file before the
restore; a new one pins the reuse.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:18:59 +02:00
Codeman maintainer a198b815d2 docs: update the swipe limits and note what pauses or replaces a swipe
Merge-time fix for #674: the mobile-handlers.js @fileoverview still
gave the old 300 ms and 100 px limits (now 500 ms and 50 px), and the
Mobile Guide now says a visible text selection pauses the swipe and a
terminal wider than the screen pans instead of switching.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:18:51 +02:00
Codeman maintainer 6fb9c4ed8a fix(mobile): hand a sideways-opening drag back to the scroll past the swipe's drift limit
Merge-time fix for #674: the first travel past the tap slop decided the
axis for the whole contact, so a scroll that opened on a thumb arc
(+9 px across, +5 px down, then straight down) locked as 'swipe'. Every
later touchmove returned before the scroll code and SwipeHandler gave
the swipe up at its 50 px drift limit, so the gesture did nothing. Past
SwipeHandler.maxVerticalDrift the drag is now handed to 'y' (and the
published axis with it), so it scrolls; a clean sideways swipe, a
vertical scroll and a long-press drag are unchanged.

The source pin in test/session-swipe-gesture.test.ts moves with the
code and also pins the drift value, and a new browser test drives the
real touch listeners: the thumb-arc drag ends as a scroll (it fails
without the fallback, axis stays 'swipe') and a clean sideways swipe
stays a swipe with nothing scrolled. The architecture note and
src/web/CLAUDE.md now say a swipe drag is consumed only up to that
limit.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:18:51 +02:00
Codeman maintainer 8a216df12f fix(config-backup): read the backup folder once per pass
Merge-time fix for #661. A pass listed the folder and parsed every manifest
three times: for the recorded-retention fallback, for the change check and
for the prune (and restore listed it twice more). On a network folder that
is every manifest read three times every five minutes.

runConfigBackupPass (config-backup.ts) now reads the folder once, shares the
names with the temp sweep and the manifests with withRecordedRetention, the
snapshot and the prune, and prepends the snapshot it just made (always the
newest, by the date floor) to the listing retention counts. runConfigBackup
in the route keeps the settings read and the bounded probe and calls it.
restoreConfigBackup lists once for the recorded retention and the pre-restore
snapshot. The exported createConfigBackup, latestBackupRetention,
withRecordedRetention and pruneConfigBackups keep their signatures
(latestBackupRetention and withRecordedRetention take an optional pre-read
listing). A recording node:fs test pins one
readdir and one read per manifest per pass, and that the new snapshot counts
toward retention.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:17:36 +02:00
Codeman maintainer 73ff2339d8 docs(file-viewer): list Alt+Left/Right in the shortcut overlay and help
Merge-time fix for #659.

- Alt+Left/Right (File Viewer back/forward) is a display-only entry in
  DEFAULT_SHORTCUTS, so the Ctrl+? overlay lists it, and a row in the
  help modal's Panels group, pinned in help-modal-shortcuts.test.ts.
  zh-CN entry for the new label; the "Restore size" entry is dropped,
  since nothing shows that string any more.
- The wiki row moves from "Sessions and tabs" to "Everything else".
- The grip comment in styles.css says only phones hide the grip;
  tablets show and use it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:17:05 +02:00
Codeman maintainer df521267ae fix(file-viewer): keep the Expand label fixed while it is pressed
Merge-time fix for #659.

The Expand button swapped its title and aria-label to "Restore size"
while on, so a screen reader announced "Restore size, pressed". The
label now stays "Expand" and aria-pressed alone carries the state, the
way the MD, Lines and Wrap toggles work.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:17:05 +02:00
Codeman maintainer 922b077cc9 test(config-backup): pin Back up now against a custom folder that does not answer
Merge-time fix for #661. The unreachable-folder table covered GET, diff and
restore; POST /api/config-backups (Back up now) now has its row too.
runConfigBackup already probes before it touches the folder, and the row
fails when the temp sweep is moved ahead of the probe.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:14:27 +02:00
Codeman maintainer 0952a2ee47 fix(config-backup): a restore that fails partway names what it restored and what failed
Merge-time fix for #661. A restore that could not write one file (a full
disk, a directory where the file should be) used to stop there and answer a
bare 500, naming neither the files it had already put back nor the
pre-restore copy, and the Settings form was not re-read, so the next Save
wrote the old settings back over a restored settings.json.

restoreConfigBackup now writes every verified file it can, then throws
ConfigBackupPartialRestoreError with restored, failed (name and error),
untouched and safetySnapshot. The route runs the same reload hooks and audit
for the files written as a full restore does, and answers 500 with the error
envelope plus those fields (and restartRequired) in data, as the tab-layout
409 carries its layout. Settings refills the form when settings.json is among
the restored files, also on that path. Tests: a unit case where a later file
is still restored, the clis.json-as-a-directory route case, and two vm cases
for the Settings handler.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:14:08 +02:00
Codeman maintainer a02a5879ca test(terminal): give the native SGR touch browser test its own describe
Merge-time fix for #664 (optional item): the drag-and-momentum test
for xterm's own SGR mouse tracking sits in its own describe, nested so
it keeps the file's page and touch dispatcher, and the file overview
mentions it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:12:25 +02:00
Codeman maintainer 76c17e5c4e fix(terminal): log xterm's mouse encoding with each scroll routing decision
Merge-time fix for #664 (optional item): _logScrollRouting now prints
mouseEncoding (xterm's coreMouseService.activeEncoding, 'unknown' when
the private cannot be read) and counts it in the per-session signature,
since an app switching encodings changes where a touch drag goes. Adds
a unit test for that line and one asserting SGR_PIXELS fails closed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:12:25 +02:00
Codeman maintainer d38291b143 docs: describe touch forwarding to native SGR mouse tracking
Merge-time fix for #664: CLAUDE.md and architecture-invariants still
said touch forwards only for claude/copilot and shares the wheel's
gate. Both now name the extra branch in _shouldForwardTouchToApp: a
drag also forwards as SGR wheel reports while xterm itself tracks the
mouse with SGR encoding, and DEFAULT, X10 and SGR-pixel apps fail
closed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:12:25 +02:00
Codeman maintainer 0fcf52d38a fix(terminal): keep the touch forwarding gate's comments with their code
Merge-time fix for #664: _shouldForwardTouchToApp had landed between
_shouldForwardWheelToApp and the `target` comment that documents it, so
it now sits above that comment. Its own comment names both sessions a
local scroll fails in (a direct PTY, where the app is on xterm's
alternate screen, and a tmux-backed session, where xterm stays in the
normal buffer holding stale tmux repaints), and the touch handler's
comment no longer says touch shares the wheel's gate unchanged.
Comments only.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:12:16 +02:00
Codeman maintainer 6c97d63499 docs: give the composer frame's mux-fallback rule its current reason
Merge-time fix for #670.

TmuxManager.sendInput() now keeps line feeds and strips only `\r`. The
rule that the composer's bracketed-paste frame must never take the mux
fallback still holds, because the frame maps its line breaks to `\r`:
on tmux the lines weld into one, pasted inside a second pair of markers,
and get submitted. docs/architecture-invariants.md and src/web/CLAUDE.md
now say that instead of "strips every \r and \n" and "pastes the
frame's own markers inside a second paste".

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:12:03 +02:00
Codeman maintainer 0ca64f8256 fix(settings): re-evaluate the keep-warm only when its default or cap changes
Merge-time fix for #666 (the review's nit). The settings PUT called
`rescheduleAll()` whenever the body carried either keep-warm key, and the
browser sends both on every App Settings save, so every save of anything
re-read the settings and re-evaluated every session. It now compares the
merged settings with the stored ones, following the rule that a settings
action resolves from `merged`, never from the raw body.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:11:06 +02:00
Codeman maintainer 2a56b2a997 fix(hooks): keep a keep-alive turn's hooks out of the run summary
Merge-time fix for #666. `recordHookEvent()` ran for every `stop`, the run
summary files a `stop` as a warning, and the Away digest lists warnings under
Needs Attention, so each keep-alive nudge added a row there and to the
session's Summary timeline. The hook route now skips the run summary while
`keepAliveReason` is set (the keep-alive turn's `stop` and `idle_prompt`).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:10:48 +02:00
Codeman maintainer a56038ebef test(terminal): guard the xterm mouse-service privates touch forwarding reads
Merge-time fix for #664: _shouldForwardTouchToApp reads
terminal._core.coreMouseService.activeEncoding, an xterm private. The
bundle-string loop in test/xterm-private-api.test.ts now checks
coreMouseService and activeEncoding too, and both failure messages name
_shouldForwardTouchToApp, so an xterm upgrade that renames either field
cannot silently stop touch forwarding to native SGR tracking apps.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:10:27 +02:00
Codeman maintainer f334b59dd3 fix(sessions): log an unreadable settings.json once and retry only sessions that can nudge
Merge-time fix for #666. The strict settings reader plus the retry after a
throw is right for a read that lands mid-write, but a settings.json that
stays broken (a hand edit with a trailing comma) made every session, keep-warm
off included, re-read the file and log a line every 60 seconds until it was
fixed (11 reads and 11 log lines in ten simulated minutes for one session).

The settings read now fails inside `evaluate()`: a given failure is logged
once until a read succeeds, and the retry is armed only for a session that
could nudge (its choice not `false`, the exporter `injected`, a warm report).
Other throws keep the generic retry in `schedule()`.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:10:26 +02:00
Codeman maintainer e408fa21bc fix(sessions): retry a failed keep-alive write before the expiry and close its window
Merge-time fix for #666. A nudge only goes out inside the last five minutes
before `expiresAt`, so the check armed a whole `KEEP_WARM_LEAD_MS` after a
failed write landed at or past the expiry and stopped with "too close to
expiry": the retry the status promised never happened. The window
`beginKeepAliveTurn()` opened also stayed open for its ten-minute ceiling
with no turn running.

A failed write now ends the window (`endKeepAliveTurn()` joins
`KeepWarmSessionView`; `Session` already has it) and re-arms at
`min(now + KEEP_WARM_RETRY_MS, expiresAt - KEEP_WARM_LAST_CHANCE_MS)`. The
test advances the clock and sees the second write, and a second one pins
that the retry never lands past the last-chance line.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:10:11 +02:00
Codeman maintainer 6d1a542018 fix(test): pin that a deleted pane directory is not adopted on rediscovery
Merge-time fix for #667.

tmux reports the directory of a pane whose directory was deleted while it
ran as `/path (deleted)` (tmux 3.4 on Linux). Today the rediscovered
session falls back to the server cwd only because isValidPath() rejects
the parentheses; this row in the wiring test keeps a later relaxation of
the path pattern from quietly adopting a dead directory.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:10:08 +02:00
Codeman maintainer 7db4d90bb6 test(terminal): rename the Codex wheel browser test after what it drives
Merge-time fix for #645: the describe title mentioned "remote" and the
fork's #13, but the test drives the local primary pane.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:04:32 +02:00
Codeman maintainer 0fa79b37ed fix(terminal): name any tracked CLI in the tile's wheel-forwarding comments
Merge-time fix for #645: the tile's paging gate comment (and the two
other tile comments describing the same route, the @fileoverview bullet
and the wheel listener's) still said the wheel is forwarded to Claude's
fullscreen renderer. Forwarding now covers every tracked CLI the shared
gate accepts, tracked Codex included. Comments only.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:04:32 +02:00
Codeman maintainer ac8409920b docs: say Codex approval prompts do raise the action alert
Merge-time fix for #645: architecture-invariants said Codex has no hook
alert, so tabAlerts === 'action' could not see its approval prompt. It
can: src/web/screen-blocked.ts reads Codex dialogs off the pane
(capabilities.workDetect.blockedLine) and broadcasts
hook:permission_prompt, which becomes the 'action' tab alert, and both
page-key fallbacks check it. The sentence now says the alert exists and
that the SGR wheel path deliberately does not consult it, because the
0.163.0 measurement showed wheel reports leave the approval selection
unchanged.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:04:32 +02:00
Codeman maintainer 71bf7288e0 fix(remote): leave the remote-history PATH bootstrap out of this PR
Merge-time fix for #645: the PATH bootstrap for remote history reads
(src/remote-pane-history.ts, src/remote-hosts.ts and its test) is a
separate fix from the scroll work. On its own it does not reach a host
whose tmux lives only under /opt/homebrew/bin, because the link
precheck, the launch, the alive probe and discovery still run a bare
tmux through the same non-interactive ssh shell. It belongs in a
follow-up PR that routes every remote tmux call through one wrapper.
These files are restored to the PR's merge base; every scroll change
stays.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:03:04 +02:00
Codeman maintainer 30a60f7bb5 Merge pull request #673: fix(mobile): keep the keyboard up when an accessory key is pressed
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:02:18 +02:00
Codeman maintainer 28a7c9bdf5 Merge pull request #668: feat(limits): make the global session cap configurable with CODEMAN_MAX_SESSIONS
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-22 19:02:18 +02:00
Aamer Akhter 74c980413a feat: per-case default session group
Case settings gains a "Default session group" selector (Ungrouped plus every
named tab group of the owner). A new session of the case lands in that group
in the same versioned layout write that registers it, so it is drawn in place
with no Ungrouped-to-group jump.

- Stored per owner and case in state.json (caseDefaultGroups), as the group's
  stable id or null for Ungrouped; read and written only through
  TabLayoutService under the owner lock.
- Precedence in sessionCreated: explicit tabGroupId, then the parent
  placement, then the case default, else Ungrouped. A deleted or foreign id
  never fails a spawn and is forgotten only after the creating write lands.
- POST /api/quick-start (local, linked, remote, Docker) and
  /api/ralph-loop/start pass their case; POST /api/sessions infers it
  lexically from workingDir. The create response carries tabLayout when a
  case default placed the session.
- GET/PUT /api/cases/:name/default-group; deleting a case (or an admin
  deleting a user's case folder) forgets the value.
- The selector mirrors desktop and phone, reverts on a refused save, and is
  redrawn from every adopted tab layout; zh-CN strings added.
2026-10-22 03:42:42 -04:00
JD 63cada938d fix(mobile): give a sideways drag on the terminal to the session swipe alone
The terminal's touch handler and the session swipe judged every gesture separately, so a sideways flick also ended as a tap on the session being left (a link, a CLI click, a keyboard toggle) or as a vertical scroll. The terminal now locks the dominant axis past the tap slop, hands a sideways drag it cannot pan to the swipe and publishes the axis, and the swipe stands aside for scrolls, pans, a lift the terminal consumed (its selection gesture), touch selections, a second finger and surfaces with controls of their own. A touch that starts outside the terminal resets the published axis, so swiping from the phone home screen into a session keeps working after a terminal scroll. A deliberate swipe gets 500ms instead of 300ms, and vertical drift cancels it mid-gesture instead of only at the lift.
2026-10-21 21:40:27 -04:00
JD d56b90b7c6 fix(mobile): keep the keyboard up when an accessory key is pressed
An accessory key that acts on the terminal (arrows, Tab, Esc, Ctrl, scroll, clear input) took focus on press, so every tap blurred the terminal and the click handler had to focus it again: a blur/focus pair per tap that started a keyboard dismissal and shifted the toolbar each time. Such a key now cancels the mousedown default instead, the same pattern as the Attach input, so the terminal never loses focus on the press; the click-time refocus stays as the fallback. A first tap on clear/compact only arms the confirm and is treated the same way.
2026-10-21 21:40:23 -04:00
Saqeb Akhter 242bbfcd31 fix(terminal): capture remote history and preserve isolated wheel travel (#7) 2026-10-22 02:01:17 +04:00
8c8ff383c2 fix(skill): sendwait refuses an empty prompt; verbs.md says it joins lines
A prompt made only of blank lines joined to nothing, and sendwait then sent
a bare Enter onto whatever sat on the worker's composer. It now refuses
with "sendwait: empty prompt" (the test fails without the check).
reference/verbs.md still said sendwait takes one line and a multi-line
prompt can sit unsent; it now says sendwait joins the lines with a space,
which loses their layout, so long multi-line content belongs in a file.
Plugin mirror regenerated.

Co-Authored-By: Christian Haberl <116439789+christianhaberl@users.noreply.github.com>
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 23:42:12 +02:00
b9b6ce57b7 docs(changeset): mention that sendwait now joins multi-line prompts
Co-Authored-By: Christian Haberl <116439789+christianhaberl@users.noreply.github.com>
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 23:38:17 +02:00
9a00c2feaa fix(tmux): drop a leading blank line made of spaces, not only line breaks
`"  \nfix it\r"` still pasted a blank first line, because the leading strip
only matched `\n`. /^\s*\n/ drops everything up to the last leading line
break, mirroring the trimEnd() at the other end, and the first real line
keeps its indentation. The test row fails with the old pattern.

Co-Authored-By: Christian Haberl <116439789+christianhaberl@users.noreply.github.com>
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 23:31:06 +02:00
2fe9105bab fix(skill): sendwait joins a multi-line prompt onto one line
sendwait posted its prompt as is. With the mux now keeping line breaks, a
multi-line prompt goes in as a paste, and right after spawn_worker returns it
can land inside Claude Code's Enter-ignore window. Neither the Enter loop
here nor the server's submit check recognises a pasted block that is still on
the composer, so `Review this:\n- item 1` sat unsent while the re-wait ran
out. sendwait now trims each line, drops blank ones and joins the rest with a
space before building the body, the same result as toSingleLine, like every
other waiting sender.

The preamble stamp moves to 1.43.1 so cached preambles pick the change up;
the plugin mirror is regenerated with scripts/sync-plugin.mjs. The new test
runs the real preamble.sh with CURL stubbed and fails without the join.
docs/api-reference.md gets the submit-check sentence the README and wiki
already carry.

Co-Authored-By: Christian Haberl <116439789+christianhaberl@users.noreply.github.com>
Co-Authored-By: Claude <noreply@anthropic.com>
2026-10-21 23:31:05 +02:00