Commit Graph
3641 Commits
Author SHA1 Message Date
Codeman maintainer 5c1ec46b6f fix: keep a root=live listing inside the session folder (release review)
The lookup judges liveWorktree.path lexically and only when the pane moves,
while the route's probe and readdir both follow symlinks. A symlink put at
that path, or at a parent of it, without moving the pane re-rooted the listing
outside workingDir. Names and sizes leaked, while file-content and file-raw
still refused the paths.

The route now resolves both folders on every request and walks the worktree
only when it lies strictly inside the resolved workingDir, otherwise it walks
workingDir. Only the check uses the resolved paths: the walk keeps the session's
spelling, so a workspace reached through a symlink still gets paths relative
to workingDir.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-06 02:25:14 +01:00
Codeman maintainer 89a93c871f fix(files): list the git worktree an agent moved into (#765)
Claude Code's EnterWorktree moves the running process into
<repo>/.claude/worktrees/<name>, while Session.workingDir stays on the main
checkout. The Files panel kept walking workingDir, so it listed a tree the
agent had left.

paneCwd already follows the move, measured on Claude Code 2.1.318 in both
directions, so nothing new has to track the agent. It also follows every cd
in a shell, so a new SessionState.liveWorktree narrows it to a linked
worktree, read from the .git file without starting git.

Only a folder strictly below workingDir is ever an answer, and the listing
only starts there: returned paths stay relative to workingDir, so the
preview, raw and edit routes are unchanged and confinement does not widen.
A worktree outside the session folder stays unfollowed.

The panel asks with root=live, shows a strip naming the worktree with a
switch to the session folder, and follows the agent in and out while open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 23:47:38 +01:00
Codeman maintainer 46b85fa6d0 chore: bump Playwright to 1.64.1 and unpin the browser suite
Playwright supports Ubuntu 26.04 from 1.61.0, so the browser suite can go
back to ubuntu-latest. Raises the floor in package.json as well, because
the old ^1.58.0 still admitted versions that refuse to install on the
image every workflow now runs on. Bundled Chromium moves from 148 to 156.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 14:22:41 +01:00
Codeman maintainer aa463d9d28 ci: pin the browser suite to ubuntu-24.04
ubuntu-latest moved to 26.04 and the locked Playwright 1.60.0 refuses to
install chromium there (support starts at 1.61.0), so the nightly stopped
before running a test. Pin to the image of the last green run, so a failure
now points at our code rather than at a new OS and Chromium. Unpin when
Playwright is bumped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 14:15:43 +01:00
Codeman maintainer 9eac5ecf01 test: wait for the first read before starting the other edit history sessions
The gate belonged to whichever read arrived first, and sessions load their stores
independently, so under CI timing another session took it, the loop never reached
release() and the test timed out (master, CI run 41930703100). The code cannot block
one session on another: sync() only waits on its own slot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-05 00:21:12 +01:00
Codeman maintainer 2aa6016d33 chore: version packages
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
codeman@1.48.0
2026-11-05 00:04:01 +01:00
Codeman maintainer 1921a47aa8 docs: say exactly which routes refuse the Discord token file
The release note and the security doc read as if no file view could return it. The
attachment, folder and download routes refuse it; file-raw serves a session's own
workspace without the blocklist, so a session rooted at the home directory can
still read it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 18:28:32 +01:00
Codeman maintainer 4960bee779 chore: one changeset for the release, and no new em-dashes
Consolidates the four contributor changesets, and rewords the em-dashes this release
added in comments and docs. The five in test/settings-save-failure-ui.test.ts stay:
they assert existing toast text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 17:31:48 +01:00
Codeman maintainer eb3b08d58b docs: fix text the release left stale (release review)
The startup hint is no longer typed, a Discord reply is one of the input paths that
set fromUser, edit-history is a state file, POST /api/filesystem/mkdir is in the API
reference, and the store's header says which routes really refuse it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 17:29:09 +01:00
Codeman maintainer 7803d5616a fix: probe bounded before a realpath in clone and New folder (release review, #516)
Clone ran an unbounded realpath over every Docker case workspace, and the mkdir
route inherited the picker resolver's realpathSync, which freezes the whole server
on a mount that stopped answering. The picker's browse route has the same call and
is left as it was.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 17:29:08 +01:00
Codeman maintainer 345c901e81 fix: refuse an unlaunchable model id before quick-start asks to evict a model (#752)
The dedicated route got this order at merge and quick-start kept the old one, so
a user could agree to a swap only to get the 400. It also runs on the pure build
now, so a refused id writes no config dir to clean up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 17:29:08 +01:00
Codeman maintainer e68afdd2ac fix: bound the Discord table conversion input and keep received files off the watcher (release review, #741)
A table costs its widest cell times its rows, so one wide cell in an agent's last
message built a 202 MB string on the event loop although only 8 posts can ever go
out. Only what can be posted is converted now. A file a person sent from Discord
also fired attachment:detected as if the agent had produced it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 17:29:08 +01:00
Codeman maintainer 4276b53a8f fix: keep credential files out of the file routes and Discord uploads (release review)
The Discord bot token was readable through the attachment routes, because
discord.json was not on the sensitive list, and so were webhook.json,
custom-model-hosts.json and the generated custom-model configs. Config backups
were the wider gap: a dated copy of users.json or settings.json matched none of
the name-anchored patterns. All are blocked now.

`codeman notify --file` relied on folder confinement alone, which holds nothing
back when a tab's folder is the home directory, and it would also post a
workspace .env. It now applies the attachment blocklist to the real path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 17:28:52 +01:00
Codeman maintainer 126d967ba3 docs: put the remove() comment back on remove() (#693)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 17:04:46 +01:00
Codeman maintainer f36bea86c7 Merge pull request #693: feat: edit history panel for local claude sessions (files edited, diffs, generated images) 2026-11-04 17:04:46 +01:00
Codeman maintainer 9d04a4fb02 feat: drop the typed first-message hint from the Discord bridge (#741)
Owner decision. Typing the note into a brand-new non-Claude tab spent a model
turn per tab and, for a spawned worker or a scheduled run, landed with the first
real prompt. Claude keeps its hint through the system prompt, and every other CLI
is told nothing. The setting goes with the path it gated: sessionIdle, the fresh
set, isHintableSession and the session:idle wiring. sendInput loses `fromUser`,
which was only ever false for the hint, and the deps test pins that a reply is a
person's own input.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 17:03:14 +01:00
Codeman maintainer 7c8d440928 Merge pull request #741: feat(discord): two-way Discord bridge with a thread per tab 2026-11-04 16:59:16 +01:00
Codeman maintainer 91d157cae4 fix: name the pane directory field paneCwd and apply the review items for #740
`cwd` beside the fixed `workingDir` reads ambiguously on a public API surface, and
`paneCwd` says where the value comes from, like `paneExit`. Also pin the field on
the payload the browser really receives (getSessionStateWithRespawn), and give the
pane-directory text its own architecture-invariants paragraph.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 16:59:16 +01:00
Codeman maintainer 4f50af6a9f Merge pull request #740: feat(terminal): resolve relative path links against the pane's current directory 2026-11-04 16:57:30 +01:00
Codeman maintainerandDDT dc6f8d27e8 fix: keep a Bash( row out of the parenthesised path detector (#735)
A Bash( row holds a command, so its parentheses do not bound one spaced path:
`Bash(/tmp/a.out input.txt)` became a single link to a file that cannot exist and
lost master's `input.txt` link. The path tools keep linking a spaced name whole,
and a hard-wrapped Bash( row gets no spaced lookup either. Test rows from #734.

Co-Authored-By: DDT <141296842+Hugo-DDT@users.noreply.github.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 16:57:10 +01:00
Codeman maintainer 2526fdb0d8 style: format the DSH_HOME warning
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 16:55:58 +01:00
Codeman maintainer 76e9f364f9 Merge pull request #735: fix(links): preserve wrapped configuration filenames 2026-11-04 16:55:44 +01:00
Codeman maintainer 8c317d84c8 fix: apply the review items for #755 at merge
Say that settings.yaml is shared only until the session's first settings write
(dsh saves by rename, which replaces the link), warn when a session's own DSH_HOME
does not answer and the server's home is linked instead, test
guardSessionConfigDirHome, and document the linkFromRealHome exception and what a
custom-model dsh session does not carry over.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 16:55:44 +01:00
Codeman maintainer 4c29aedbc5 Merge pull request #755: feat(custom-model): DeepSeek Harness injection through a per-session patch 2026-11-04 16:54:32 +01:00
Codeman maintainer 6232dffe03 fix: apply the review items for #752 and #757 at merge
The launch-id check is pure, so it now runs before the context warning and the
swap confirmation: nobody agrees to evict a model only to get the 400. Also the
search-box and in-use comments, the model-plain-colon wording, and the wiki's
order of the picker's marks.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 16:53:26 +01:00
Codeman maintainer f7dfe091c5 Merge pull request #757: feat(custom-model): mark the model a session is using in the endpoint model picker 2026-11-04 16:51:56 +01:00
Codeman maintainer 3bcb55ce96 Merge pull request #752: fix(custom-model): context limits, Codex model override, context discovery and picker filter 2026-11-04 16:51:56 +01:00
Codeman maintainer 7b8e295647 fix: retire the OpenCode Console breach notice
A new install has no seen list, so every new OpenCode user was still warned about
an October incident that is long over. The mechanism stays for the next notice;
an empty list is now a valid file, and the validators keep running over whatever
it holds.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 16:51:56 +01:00
Codeman maintainer 0dbfc8dc2d fix: apply the review items for #744 at merge
Classify OpenSSL and LibreSSL's SSL_connect errors as unreachable again (`_` is a
word character, so \bssl\b missed them and the user read the temp directory as the
reason), point a cases-folder refusal at Clone Repo instead of Create New, and move
the mechanism and history out of CLAUDE.md into architecture-invariants.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 16:50:44 +01:00
Codeman maintainer 927c9a461e docs: place the New folder note after the picker overview (#745)
It sat between the "two places" list and the paragraph starting "It browses",
so that "It" read as New folder, and it said the button is not offered inside
the cases folder when the button shows and the route refuses.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 16:49:58 +01:00
Codeman maintainer d9d6fad698 fix: cap the first tab on every pass, before a selection widens it (#748)
selectSession() toggles .active at once while _syncTabStripCorner() only runs in
the debounced render, so a cap set after measuring left a newly selected first
tab wider than the room and dropped the first row below the toolbar until then.
max-width changes nothing on a narrower tab, so the cap is simply always on, and
the clear-before-measure and finish-the-animation loops go. The no-usable-room
test uses 8 tabs: at 40 the scroll fallback fires first and it passed at any
threshold.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 16:48:57 +01:00
Codeman maintainer 823013226d fix: record the settings baseline when a tunnel enable is abandoned (#736)
Both _abandonTunnelEnable() returns come after saveAppSettingsToStorage() wrote
the new values to this device but before _unsavedSettingsBaseline was set, so
after cancelling the no-password prompt the next Save sent no
showPlanUsageLimits flip and did not reload for a gesture-control change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 16:48:25 +01:00
Codeman maintainer 5e7ec1c522 Merge pull request #744: feat(cases): clone a repository into a custom folder 2026-11-04 16:47:48 +01:00
Codeman maintainer 1efe1d40c3 Merge pull request #745: feat(picker): New folder button in the path picker, on for Link Existing 2026-11-04 16:47:48 +01:00
Codeman maintainer 9d6f84f446 Merge pull request #748: fix(tabs): keep the L-shaped strip whichever tab is selected 2026-11-04 16:47:48 +01:00
Codeman maintainer 58f7dbc7ad Merge pull request #736: fix(settings): stop a failed settings write from saying it was saved 2026-11-04 16:47:48 +01:00
Codeman maintainer 7ed660ff11 Merge pull request #737: fix(mobile): show a press on the phone toolbar and accessory keys 2026-11-04 16:47:48 +01:00
Codeman maintainer 457dd54825 Merge pull request #738: test(docker): give the Update-Codeman.sh smoke harness a non-root appdata owner 2026-11-04 16:47:48 +01:00
Codeman maintainer de2bfb69c3 Merge pull request #742: test(tui): check the TUI pid option is unset in a way tmux 3.2a agrees with 2026-11-04 16:47:48 +01:00
Codeman maintainer 6670bc64b6 docs: add the Featured in Awesome AI Agents badge
Codeman was added to the Coding Agents section of NipunaRanasinghe/awesome-ai-agents (their PR #245, merged 2026-11-04).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 15:34:46 +01:00
RandalixandClaude Opus 5.5 109fd98038 fix(edit-history): colons in file:// paths, yield on forward reads, no store for unsupported
Follow-up from an own review pass of de436576:
- PATH_TOKEN_RE branch 1 stops at the next `file://` instead of at `:`,
  so `file:///tmp/plot-12:30.png` is found again; still linear.
- Forward reads yield between files like "Load older"; a store removed
  meanwhile ends the read and its printed paths are never probed.
- POST /edits/older and GET /edits/:entryId no longer load a store for
  remote, Docker or non-claude sessions (shared unsupportedList()).
- Time budgets widened (1 s per line, 3 s per chunk; ~3 s / 6.6 s before
  the fix) so the throttled suite does not flake.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 09:50:21 +01:00
RandalixandClaude Opus 5.5 de43657676 fix(edit-history): bounded image probe, linear path scan (review of #693)
- probeLocalPaths: every agent-printed candidate goes through
  probePathKind() first (no pastCap, bulk scan), sequentially; only a path
  that answered 'file' gets realpath + stat. A path on a mount that stopped
  answering no longer hangs the sync, a queued sync or remove().
- PATH_TOKEN_RE: branch 4 starts only at a token boundary (`:` excluded so
  URLs stay ignored), branch 1 stops at `:`. Linear in the line length
  (30,000 `#` took ~3 s before).
- Load older yields to the event loop between the files it parses.
- GET /edits answers unsupported without loading a store.
- CLAUDE.md paragraph trimmed to the rules; probe and regex rules added to
  architecture-invariants#edit-history-panel.

Tests: stall test through the real sync and probe with a stat that never
settles; time-budget tests with 30,000-character inputs and a 139-result
base64 chunk; route test asserts no store load for unsupported sessions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-03 09:46:23 +01:00
Devvyn 4aeab0d9ce fix(custom-model): keep the in-use picker honest about down endpoints and exited panes
Review round on PR #757. The route turns EVERY upstream failure into
isLlamaSwap: false, so the old line silently promised an unreachable
endpoint was merely mute, and the live-session check missed a null pid
(the PTY exited, the same test keep-warm applies).

- Require pid !== null in _getCustomModelInUseBySession, pinned by a
  'process exited' case in the marks-nothing table
- Reword #customModelPickUnknown to claim only that nothing was
  reported, true for a down endpoint too; drop the 'stays quiet for a
  failed probe' promise from changeset, docs and comments
- architecture-invariants: add the In-use tier, both pin fences
  (customModel not displayModel; stopped/null-pid/paneExit never
  count) and the unknown-line rule
- Mirror the wording through i18n (key + zh-CN), index.html fixture,
  styles.css comment, and the run-menu tests
2026-11-02 19:15:37 +08:00
Devvyn 4623ee0d12 fix(custom-model): keep the in-use changeset at mode 100644 like its neighbours 2026-11-02 19:05:22 +08:00
Devvyn e1c792f491 fix(custom-model): ignore a remembered model id the endpoint no longer lists
Round-four review, split fix 1: a stale 'last used' id kept the promotion truthy, so no row was tagged and the 'Nothing is marked' line stayed hidden. Derive it from promoted && models.includes(promoted).
2026-11-02 19:05:22 +08:00
Devvyn 1f0823c582 fix(custom-model): show which model a session is using when an endpoint cannot report it
Only llama-swap answers what is loaded, so behind a gateway such as Bifrost
nothing was marked and the picker fell back to discovery order apart from the
one CLI that had launched there before. A live session whose own injected
endpoint is that host now promotes its model as "In use by a session", under
its own tag and below llama-swap's "Currently loaded" answer, reading only
what Codeman injected rather than terminal text, and never a stopped session.
When genuinely nothing is known the picker says so instead of leaving an
unmarked wall, and stays quiet for an endpoint that merely failed to answer.
2026-11-02 19:05:22 +08:00
Devvyn 884e67d07e test(custom-model): pin the codex one-shot launch model on quick-start
Round-four review smaller item: one getCustomModelForPersist().launchModel expectation, like the pi/grok/omp tests beside it, pins #750 on the one-shot path.
2026-11-02 17:04:12 +08:00
Devvyn b177885dd7 docs(custom-model): say a PUT clears defaultContextLength and a learned figure wins
Round-four review smaller items: api-reference now states the opposite-of-apiKey behaviour for an omitted defaultContextLength, and the wiki sentence follows the code, modelContextLengths[id] ?? defaultContextLength: any stored figure beats the default.
2026-11-02 17:04:12 +08:00
Devvyn 5c8a557390 refactor(custom-model): one exported MAX_DISCOVERED_CONTEXT_TOKENS for routes and schema
Round-four review smaller item: the discovery comment claimed a shared ceiling while schemas.ts restated the literal twice; the constant now lives in schemas.ts (routes already import from it, no cycle) and both bounds reference it.
2026-11-02 17:04:12 +08:00
Devvyn 2cc5f3f9e6 fix(custom-model): keep the picker search box unfocused on touch devices
Round-four review item 4: focusing the search input on every picker open raises the OS keyboard over the list on phones; guard it the way readmymind-ui.js does.
2026-11-02 17:04:01 +08:00