Commit Graph
2012 Commits
Author SHA1 Message Date
Devvyn 71fcefbaf2 fix(config-backup): ignore a Docker case's conversation id, list every ignored key, correct the retention and restart docs 2026-10-20 18:01:43 +08:00
Devvyn a0b9570457 fix(config-backup): age a snapshot from its successor, ignore activity-only rewrites, keep at least 2
Review round 3 on #661: retention aged each snapshot by its own createdAt, so the first change after a quiet month deleted the last good copy; it now ages from when the next snapshot was made. users.json lastLoginAt, settings.json lastUsedCase and intents.json recentPrompts/updatedAt are volatile keys for the change check. The keep count has a minimum of 2. Wiki restore paragraph aligned with RESTART_REQUIRED.
2026-10-20 18:01:43 +08:00
Devvyn 8b27e4beb6 fix(config-backup): origin is a stored random id, Settings refills after a settings restore, clis.json reloads
Review round 2 on #661: the hostname in the origin orphaned every snapshot when a Docker container was recreated, so the origin is a random id kept in <data dir>/config-backup-id; after restoring settings.json the Settings form is re-read from /api/settings so Save cannot write the old values back; the restore confirm names the files and the credential ones; clis.json is reloaded (reloadCliRegistry) and users.json needs no restart; API reference and route docs corrected.
2026-10-20 18:01:42 +08:00
Devvyn 247740fc77 fix(config-backup): redact webhook and intents, bounded folder probe, per-instance origin, reload intents on restore
Review round on #661: webhook.json and intents.json are redacted in compare and URL values lose userinfo/query; a custom folder is probed (bounded, pastCap) before each pass and in each route and only created when its parent exists; manifests record an origin and change check, prune, list, restore and diff are scoped to it; a restore reloads IntentStore, lists untouched files and treats settings.json as restart-required; remote-cases.json is tracked; stale .tmp-cfg-* folders are swept and a failed restore unlinks its temp; the group is hidden from non-admins; an empty days field saves 30.
2026-10-20 18:01:42 +08:00
Devvyn a2e49eb26d feat(config-backup): compare backups with each other and with the running config
Settings -> System -> Config backups gains a Compare view: a backup against the
running config, a backup against the one before it, or any two backups. Each
differing file lists its changed keys as before/after, plus files that appeared
or vanished. GET /api/config-backups/diff?from=&to= serves it (`to` defaults to
`current`; admin only in multi-user mode).

Credential values are never returned: .env, users.json and push-keys.json report
names only, and any other key that looks like a token, secret, password,
credential or key is reported as changed without its value. A non-JSON file
reports only that it differs, a file is cut at 200 changes, and a self-refreshed
discovery timestamp does not count as a difference.
2026-10-20 18:01:42 +08:00
Codeman maintainer f2230d5d3d feat(config): timestamped config backups with a configurable folder and retention
The files that hold a user's customization (settings.json, clis.json, custom-model-hosts.json,
webhook.json, intents.json, linked-cases.json, push-keys.json, users.json, .env) are plain JSON
in the data dir, rewritten by the server, the Settings UI and the CLI, with no copy to go back to.

A snapshot is taken at startup and whenever the tracked files' content changes (checked every
five minutes, and only written when a digest of the file set differs from the latest snapshot's),
into `<data dir>/backups/config` by default or any absolute folder. Retention keeps the newest
configBackupKeepCount (1-500) and, when configBackupKeepDays > 0, drops older ones; it only ever
deletes folders it made (name pattern and a parseable manifest) and never the newest.

GET/POST /api/config-backups list and back up now; POST .../:id/restore verifies every file against
the manifest's SHA-256, takes a pre-restore snapshot, then replaces files atomically with mode
0600, writing only allowlisted names. Snapshots are 0700 folders of 0600 files and all routes are
admin only in multi-user mode. Settings -> System gets the controls and a Restore list.
2026-10-20 18:01:42 +08:00
Devvyn e3c6f9f2c7 fix(file-viewer): the resize grip only starts on the primary button 2026-10-20 11:30:38 +08:00
JD 83d80578e4 fix(sessions): read the composer from a styled capture so a prompt suggestion is not a draft
Claude Code draws its prompt suggestion in an empty composer, the first letter in the reverse-video cursor cell and the rest faint, so a plain capture read it as typed text and keep-warm never nudged those sessions. The keep-warm pane read now uses capture-pane -e and drops the suggestion before checking the composer.

Also from review: an off status carries no window, automation and an unreadable composer retry instead of stopping, a failed evaluation re-arms a retry, a trigger during an evaluation queues one follow-up that remove() cancels, and the cap's clock is seeded from lastSubmitAt for pre-upgrade state.
2026-10-19 19:58:14 -04:00
JD 5db6c633d3 fix(sessions): leave a pending idle alert to the user through a keep-alive turn
Only a human spends an idle alert, but the keep-alive turn resolved an unseen one three ways: its working transition, its stop hook, and its own idle prompt replacing the item with a pre-acknowledged one. While the turn runs, a pending idle item is now left exactly as found, the page's stop handler returns on the keep-alive reason before clearing hooks or raising Response Complete, and session:working/session:idle carry keepAlive so the stuck-detection timer neither restarts nor re-arms.

The window that marks the turn closes on its own idle prompt or any other submit instead of a fixed three minutes, which a slow turn's idle prompt (sent a minute after the turn ends) could outlast. The service keeps the default and cap in memory, read through a strict reader so a mid-write read is retried rather than kept, and the cap is clamped before the strict settings save.
2026-10-19 01:42:00 -04:00
JD 71a51df2e2 feat(sessions): keep an idle session's prompt cache warm with a guarded keep-alive turn
Claude Code lets a subscription's one-hour prompt cache expire after an hour idle, and the first turn back re-writes the whole conversation at the cache-write rate; nearly every gap over an hour goes cold, while the saving is concentrated in gaps of one to four hours. Codeman now sends one short keep-alive turn five minutes before the expiry Claude Code reports on its statusline, so the next real prompt still reads the conversation from cache, and stops two hours (configurable) after the last real prompt.

Codeman owns the idle policy for these sessions, as agreed in Discussion #554: a launch with keep-warm on also carries idleCompaction: false in its one --settings JSON, so Claude Code's own idle compaction cannot replace the conversation with a summary a minute before the nudge. It is decided once per launch (keep-warm on, the statusLine exporter injected, Claude Code 2.1.290 or newer, an unknown version fails closed like --name), recorded on the mux record, and picked up by any relaunch; a launch with keep-warm off is byte-identical. A session switched on after launch is kept warm best-effort and the readout says so.

Every guard lives in one pure rulebook: the opt-in (an agent-spawned session does not inherit the app default), a launch that reports cache state, a warm 1h cache with enough tokens at stake and no compaction this gap, a live pane, no usage-limit pause, no respawn, Ralph, task or waiting agent, idle, no open dialog, an empty composer and no recent keystroke. The nudge is a submit and moves lastSubmitAt, which the response viewer's conversation correlation needs; the cap counts from its own persisted lastRealPromptAt instead. Read My Mind drops the exact nudge text, and the turn's stop hook and idle prompt open pre-acknowledged so nothing alerts. The last cache report and the clock survive a restart, so the timer re-arms.
2026-10-18 15:19:08 -04:00
JD 6f785e116f fix(response-viewer): open markdown links to file paths in the preview, not as a same-origin URL
Codex cites files as [label](/abs/path). The chat view gave those links target=_blank, so a click opened <origin>/abs/path and landed on a Fastify 404. Path-shaped hrefs now take the linkified-path shape the file preview already opens; scheme, protocol-relative and fragment links are unchanged.
2026-10-18 14:33:26 -04:00
Ludo Fourrage 971192ce02 fix(terminal): forward touch scrolling for native SGR mouse tracking 2026-10-18 17:00:18 +00:00
Saqeb Akhter dbb41c70cf chore: merge upstream master and retain tracked scrolling fixes
Resolve Copilot forwarding and registry/documentation overlaps against upstream e63bb65b. Reuse upstream always policy for measured version-independent forwarders and test slow clicks for Claude, Codex and Copilot.
2026-10-18 14:07:36 +04:00
Devvyn 2cd0d82544 fix(file-viewer): phones ignore expand and the grip, folder paging follows history, swallow Alt+arrows
Under 600px the window stays full screen whatever Expand or a drag says, and both
controls are hidden. Stepping onto a folder-grid entry goes through the grid so its
index follows. Alt+left/right is swallowed at the ends of the list too. Adds tests
for the key handler, the grip clamp and the history/grid case, zh-CN titles and wiki lines.
2026-10-18 18:03:54 +08:00
Saqeb Akhter 1b6c2664b6 fix(terminal): prepay isolated small wheel ticks without amplifying streams
Address the remaining PR #645 review: preserve shell Ctrl/sideways local scrolling, restore the paging threshold export, document tile leading-report lifetime, and update internal and user scrolling documentation.

Refs: https://github.com/johoja12/Codeman/issues/7
2026-10-18 13:59:28 +04:00
Devvyn 08e57ed708 feat(file-viewer): resize and expand the window, back/forward between previewed files 2026-10-18 17:45:31 +08:00
Codeman maintainer e63bb65b36 chore: version packages
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 10:03:55 +02:00
Codeman maintainer f744c503c5 Merge branch 'relnext/security-notices': security notices, starting with the OpenCode Console breach
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 10:03:02 +02:00
Codeman maintainer 613fc86d70 fix(ui): touch-sized notice buttons on any coarse pointer, no mid-word break in a Chinese title
A phone in landscape is wider than 599px, so the 44px targets now follow (pointer: coarse) instead of the width. A balanced title broke the zh-CN text inside 入侵; :lang(zh) keeps CJK runs whole and breaks at the title's spaces and colon.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 10:02:49 +02:00
Codeman maintainer 82c34fba99 fix(ui): notice buttons act once, links send no referrer, solo windows defer
- A closing notice card stays in the DOM for its 200 ms fade, and its
  link and "See what's new" buttons still worked there: a double click
  opened the notice twice. close() now makes the card inert and every
  button handler does nothing once it is closing.
- Notice links (and the combined card's "See what's new") open with
  noopener,noreferrer. noopener alone still sent this instance's origin,
  which can be a tailnet name or a tunnel URL, as the Referer. The plain
  update toast is unchanged.
- The https rule is checked again at the button
  (CodemanSecurityNotices.urlOk): a caller handing showSecurityNotice or
  showUpdateNotice an unchecked URL gets no link button.
- A detached session window (/session/:id) is rendered without
  __codemanCliAvailable, so it could never select the OpenCode notice,
  yet it took the update toast and recorded the version, and the
  dashboard then showed the notice as a separate card. While any notice
  is pending, a solo window now shows and records nothing and leaves
  both to the dashboard; with none pending it shows the plain toast as
  before.
- The wiring tests pin the page's own clock (JSDOM gives the window its
  own Date). On the real clock 18 of them would have failed on every push
  from 2027-01-01, when the fixture notice expires. New tests pin the
  once-only close directly (the old double-click comment claimed more
  than it checked), the single open, the sink check, the solo windows,
  the scroll cap and the light-skin ink.
- CLAUDE.md now says the public .json files are served no-cache, the
  exception to the year-long immutable cache.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 09:30:22 +02:00
Codeman maintainer ee6b115023 fix(ui): keep the security notice card reachable and readable everywhere
- The card is capped to the room below the toast stack's top and
  scrolls inside itself. The stack is fixed and cannot scroll, so on a
  phone in landscape the update toast's buttons sat below the screen
  with only the × left, which records the notice unread. The accent bar
  becomes a background layer, which stays put while the content scrolls.
- Small amber text and the primary button use --notice-ink, darkened a
  step on the four light skins, where --yellow measured 3.9 to 4.4:1 for
  the 10.6px eyebrow (now 5.1 or better, the button label 5.7 or better).
- The update toast that carries a notice frames itself in the accent
  colour and leaves the amber to the warning section inside it.
- The × uses --text-dim (2.4:1 on og before, 5.5 now).
- Phones: every button fills its row (a wrapped Dismiss no longer sits
  stray at the left) and is 44px tall, and the × gets a 44px box.
- The title balances its lines, and the card matches the plain toast's
  420px so a toast stacked under it lines up.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 09:30:13 +02:00
Codeman maintainer 5e405bbbb9 fix(ui): shorten the OpenCode notice to what OpenCode said, live from 17 October
The message ran 66 words over five sentences, which pushed the update
toast's buttons off a 360x640 phone. It also repeated the card's own
eyebrow ("Security notice for OpenCode users:"), placed the breached
"legacy system" inside the Console (no source says so), and closed with
an unsourced line about the CLI not being affected. The new text (55
words) says what OpenCode said, including its own reassurance that a
user who got no email was not affected, which matters because the card
goes to every opencode user while about 1.4% of Console users were hit.
The zh-CN text follows it and uses 撤销 for revoking keys.

published moves to 2026-10-17, so the notice is already live in every
timezone when the release lands: a browser still on the 17th would
otherwise take the plain update toast and get the notice later as a
separate card. docs/releasing.md says both things for the next notice.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 09:30:13 +02:00
Saqeb Akhter 8cb3441dd9 fix(terminal): address scrolling review and preserve upstream speed policies
Fix transport-timer regression coverage, zero-delta tile handling and capability documentation. Record isolated Codex 0.163.0 transcript and approval evidence; defer event/batch rate and coarse paging policy changes.

Refs: https://github.com/johoja12/Codeman/issues/7
2026-10-18 11:23:05 +04:00
Codeman maintainer 54d0699abd docs: how security notices work, and how to add and retire one
src/web/CLAUDE.md gets the load-bearing rules (hand-maintained file,
strictly-true availability, one surface per notice per load, seen only
on a user action, no CLI-id branching, theme tokens only), and
docs/releasing.md a section on adding a notice, its fields, and letting
`expires` retire it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:59:39 +02:00
Codeman maintainer 50bae2d371 feat(ui): security notices, shown only to users of the affected CLI
A hand-maintained src/web/public/security-notices.json carries warnings
about things outside Codeman that its users should act on. The first:
OpenCode's report of unauthorized access to its legacy Console, which
may have exposed provider API keys saved there.

- Pure core in constants.js (CodemanSecurityNotices): select() keeps the
  notices that apply now (inclusive local-day dates, not yet seen, https
  links, malformed entries skipped), and one naming a CLI only when
  window.__codemanCliAvailable[cli] === true. Unknown means not
  installed: a warning about software you do not have is noise. The CLI
  id is data in the JSON; no code branches on it. plan() decides the
  surface, so a load shows each notice once.
- An existing install on a new version gets the notice INSIDE the
  release's update toast: the highlights as before, a warning section,
  and the notice's link next to "See what's new". With no notice the
  update toast is the plain one it always was.
- Everyone else (a fresh install, a same-version reload) gets its own
  card in the toast stack: shield, "Security notice" eyebrow, title,
  message, the link, Dismiss and the ×; amber-to-red accent bar, theme
  tokens only (dark and light skins), full width on phones, an
  opacity/transform entrance and none under prefers-reduced-motion,
  role=alert.
- A notice is recorded as seen only when the user closes it, dismisses it
  or follows its link, never when it appears. Storage blocked shows
  nothing. The notice's own text is textContent and carries its own
  zh-CN, so i18n.js leaves it alone; the card's own copy translates.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:59:39 +02:00
Codeman maintainer ada2309721 fix(web): serve the public JSON data files no-cache, not immutable
The static plugin gave every file under public/ a year of `immutable`,
including the JSON the page fetches at runtime: whats-new.json (rewritten
every release), the new security-notices.json (edited by hand) and
manifest.json. None of them is content-hashed or `?v=`-busted, so a
browser could keep last release's copy, and a security notice added in a
later release might never reach it. A `.json` file now revalidates
(`no-cache`); every other static asset keeps its immutable year, and a
route that set its own Cache-Control still wins.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:59:39 +02:00
Codeman maintainer 8e6abf4bfd Merge pull request #592: feat(cli-registry): GitHub Copilot CLI as a run mode
GitHub Copilot CLI (`copilot`) becomes a run mode: Run menu, welcome
screen, cron and CLI management once it is installed, tmux-backed like
the other agent CLIs, working/idle and the model read off its footer,
launch options through `copilotConfig` (model, resume, continue, the
multi-user-clamped allowAll), Custom Model Endpoints via Copilot's BYOK
variables, MCP sync of its mcp-config.json, a status probe, and the
`codeman agent` verbs (spawn waits for its composer, read returns its
last answer).

The plan-usage quota row that earlier rounds carried was split out on
review and is not part of this merge.

Merge-time commits on top: the wider COPILOT_* clamp and the zh-CN
README rows (maintainer), the Docker sign-in docs, divider rows inside
an answer kept by `agent read`, route tests for the screen-read
last-response branch, and doc drift (Past Sessions, wheelForward JSDoc,
COPILOT_/OMP_ in the env prefix lists).

Verified before merge on Copilot CLI 1.0.98: injected keystrokes,
bracketed paste and Enter reach the TUI in tmux (github/copilot-cli#4180
does not reproduce), a shell tool call completes inside tmux (#4223 does
not reproduce), and a session driven through this branch answered over
send-and-wait.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:17:06 +02:00
Codeman maintainer 9fc7781442 Merge pull request #647: fix(web): hold the WS pill's queued-bytes suffix until a backlog persists
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:16:43 +02:00
Codeman maintainer 7504a2bc8b Merge pull request #567: fix(cases): only refuse the cases folder and its direct children for a custom-folder case
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:16:42 +02:00
Codeman maintainer d2f6021132 Merge pull request #646: feat(sessions): launch every Claude session with --name set to its tab name
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:16:41 +02:00
Codeman maintainer 66a6319af9 Merge pull request #644: feat(links): make .diff and .patch paths clickable
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:16:41 +02:00
Codeman maintainer 7edea53841 Merge pull request #653: test(uploads): pin the browser's copies of the document list to ALLOWED_DOCUMENT_EXTS
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

# Conflicts:
#	CLAUDE.md
2026-10-18 08:16:40 +02:00
Codeman maintainer 5481fd599b Merge pull request #651: fix(uploads): say how many files a mixed pick, drop or paste skipped
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

# Conflicts:
#	CLAUDE.md
2026-10-18 08:16:10 +02:00
Codeman maintainer 3c16eccd47 Merge pull request #652: fix(uploads): say a refused text upload is not UTF-8 instead of a type mismatch
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:15:52 +02:00
Codeman maintainer 14a9e66547 Merge origin/master into #644: keep diff|patch beside #621's tsv and zip
Master's #621 added tsv and zip to both file-link extension groups in
constants.js while this branch added diff|patch to the same lines. The
resolution keeps both, in master's order with diff|patch after sql where the
PR put it; the rooted and relative groups stay identical, and every upload
document extension plus .diff/.patch still links in both patterns.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:12:35 +02:00
Codeman maintainer 8870cfc7dc fix(#646): translate the Pin tab names row and list it in the Settings reference
The new App Settings row had no zh-CN entry, so it read in English in a
Chinese UI, and docs/wiki/Settings-Reference.md did not list it. Adds the
label and description to i18n.js, a row in the Agents & CLIs table, and a
JSDOM test that runs the real translator over the real index.html.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:10:17 +02:00
Codeman maintainer 44f87de9a7 fix(#592): doc drift around Copilot's resume, wheelForward and the env prefixes
- docs/cli-registry.md said Session history resume goes through
  copilotConfig.resumeSessionId / continueSession. Past Sessions sends only
  `continueSession: true` (terminal-ui.js, the modeConfigKey table);
  resumeSessionId is for API callers.
- The wheelForward JSDoc in cli-registry/types.ts read as if the value had
  effect. Nothing reads it (it is in the DECLARED-FOR-LATER list); the
  browser gate is _shouldForwardWheelToApp in terminal-ui.js with its own
  per-CLI rules, which the comment now says.
- The env-prefix lists in the CLAUDE.md Security table and the
  allowedEnvPrefixes() comment in schemas.ts stopped at DEEPSEEK_, missing
  both OMP_ and the new COPILOT_; the Multi-CLI prefix rule missed OMP_.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:09:39 +02:00
Codeman maintainer 67ca0954db fix(#647): read the pending queue once per indicator update
The try/catch around _pendingBytes() could not keep _updateConnectionIndicator()
from throwing, because _computeConnectionDescriptor() read the queue again,
unguarded, right after; its test only passed because it stubbed the compute
out. The update now reads the queue once and hands the totals to the compute
(which still reads a fresh queue when called on its own), so the hot input
path walks the queue once per keystroke and ACK instead of twice. The stubbed
test is gone: the COD-133 combinatorial test already pins never-throw.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:08:46 +02:00
Codeman maintainer d8850d1b50 fix(#653): export ALLOWED_DOCUMENT_EXTS as ReadonlySet<string>
Now that the set is exported for the parity test, type it read-only like
VIDEO_ATTACHMENT_EXTENSIONS, so an importer cannot add to the live upload
allowlist.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:08:24 +02:00
Codeman maintainer d170ad2295 fix(#592): a rule inside a Copilot answer stays part of it in agent read
The pane segmenter ended the response block at every full-width rule, so
an answer that draws one (a markdown `---`, a passage quoted between two
rules) read as only its last section: `Summary / ──── / Details` came
back as "Details", and the existing test pinned that by expecting the
quoted passage without its "Here it is:" lead-in.

Inside an open response a rule is now held and written into the text as
`---` once more of the same answer follows, so a rule that only separates
the answer from the footer never trails it. The composer's own two rules
(the last rule/❯/rule triple) are still boundaries. The old test now
expects both parts, and a new one pins a Summary/rule/Details answer as
one block; both fail without the change.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:07:11 +02:00
Codeman maintainer af52de4d05 fix(#567): separate refusal messages for the cases folder and a direct child
The one message read "That folder is in the cases folder (...), where it is
already listed as a case" for the cases folder itself too, which is not in
itself and is never listed, and "already listed" is not true for a direct
child that does not exist yet. Two messages now, both still pointing at plain
Create New.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:05:39 +02:00
Codeman maintainer 9722c5bafe fix(#567): document the cases-folder rule as the folder and its direct children
docs/api-reference.md and the case-path.ts @fileoverview still said a custom
folder must not be, or be inside, the cases directory. After #567 only the
cases directory itself and its direct children are refused (those are what
GET /api/cases lists as local cases); a folder further down is allowed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-10-18 08:05:39 +02:00
Devvyn 76479fdc96 feat(sessions): make pinning every tab name an opt-in setting
Add pinCliSessionName (synced, default OFF), re-read at each spawn and respawn.
Off keeps the #457 behaviour; on pins every non-blank tab name as --name.
Update the docs, JSDoc and changeset that stated the old rule.
2026-10-18 13:58:09 +08:00
Devvyn e37f1f1483 fix(copilot): agent read keeps shell prompts and ruled paragraphs inside an answer
A submitted prompt is only a prompt at column 0 or 1, so an indented shell prompt in a code block stays answer text. Only the last rule, composer row, rule triple is the composer, so a paragraph between two rules in an answer is no longer dropped. A test for each.
2026-10-18 00:47:54 +08:00
Devvyn 6cca5465a9 fix(copilot): a model value must start with a letter or digit
Like resumeSessionId, model follows a flag, so --model --yolo made --yolo its own flag and bypassed the allowAll clamp. New model-plain token pattern, the same rule in the create schema, and golden and schema tests.
2026-10-18 00:47:54 +08:00
Devvyn 740474ebca fix(copilot): Free plan usage, tall answers in agent read, page-key fallback, review nits
Review of 8659ba25..be987fbb:

- Usage: a Free account answers premium_interactions {entitlement: 0, remaining: 0,
  percent_remaining: 0, unlimited: false, has_quota: false}, which read as 100% used. The parser now
  returns null when has_quota is false or the entitlement is not positive, with that payload as a
  fixture. Free meters chat (200) and completions (2000) too, so the comment no longer says they
  are unlimited on every plan.
- agent read: rows were skipped until a `❯ <prompt>` row, so an answer taller than the pane
  (prompt scrolled off the top) read as "". With no prompt row AND no banner / trust dialog on
  screen, the rows above the composer are now the tail of the last answer. Text typed in the
  composer (a prompt-shaped row between the two rules) is not a prompt row.
- Page keys: measured on 1.0.95 in tmux that Copilot pages on PageUp/PageDown (three PageUp moved
  lines 109-140 to 010-042, PageDown returned) as well as on SGR wheel reports, so copilot joins
  claude and opencode in _localScrollbackIsHollow(); the stale-tracking-flag fallback the comment
  and docs describe is now true, for the main pane and a TerminalTile (same function), with tests.
- X-GitHub-Api-Version is 2022-11-28, a version GitHub supports (verified against the live
  endpoint); readPlanUsageTelemetryEnabled() is checked before isCopilotAvailable() so a switched-off
  chip skips the resolver probe too.
- Palette label for Copilot in panels-ui.js; stale comments in types/session.ts and stock.ts.
- Docs: Past Sessions continues with --continue (resumeSessionId is for API callers), nothing sets
  continueSession on a respawn, and only a tab name the user set is passed as --name; the usage
  wording for Free; the wheel and mouse-strip paragraphs in CLAUDE.md and
  architecture-invariants; the changeset describes the whole feature.
2026-10-18 00:47:54 +08:00
Devvyn 5b77c271b0 docs(copilot): document GitHub Copilot CLI in full
- New docs/copilot-integration.md in the shape of the other CLI guides: install and identity
  probe, authentication (keychain vs plain-text config.json, COPILOT_GITHUB_TOKEN), what Codeman
  wires up (Run button --yolo and its clamp, model, resume, continue, --name rule), BYOK custom
  endpoints, terminal behaviour (drag selection, wheel and touch), the codeman agent verbs
  (ready mark, read), plan usage, Docker, Remote SSH, what is deliberately not wired, known gaps.
- Agent-CLIs wiki: the eleven-modes table, a GitHub Copilot CLI section, the env prefix row, the
  feature-comparison rows and the status endpoint list.
- README, Home, FAQ, Core Concepts, Docker Cases, Remote SSH, Contributing, The Dashboard and
  Custom Model Endpoints: mode lists and counts; CLAUDE.md: stack line, SessionMode, prefixes,
  resolver list, external-CLI notes and the plan-usage source; api-reference MCP target wording;
  the env allowlist error message names COPILOT_*.
2026-10-18 00:47:53 +08:00
Devvyn 89a82c68d1 fix(copilot): codeman agent read returns the last answer
`/api/sessions/:id/last-response` fell through to the Claude transcript scan for copilot (not in the
external-CLI list), so `codeman agent read` answered empty even with an answer on screen. Copilot
is a repainting full-screen TUI whose stream is absolute cursor moves, so the buffer cannot be cut
into lines either; the route now reads the pane's visible screen (tmux capture-pane) for such
modes and falls back to the buffer where there is no pane.

The segmenter gets a small per-CLI "pane dialect" row instead of another branch in the
Codex-oriented loop: `❯ <prompt>  HH:MM`, `● <answer>` with indented continuation, the cwd /
`Session: N AIC used` row, composer, footer and the `┃` scrollbar gutter are chrome, and
everything before the first prompt (banner, trust dialog) is dropped so a session that has not
been asked anything answers nothing rather than serving its logo.

Fixture is a real Copilot 1.0.95 pane. Tool-call rows are not modelled and read as answer text.
2026-10-18 00:47:47 +08:00
Devvyn d732b46797 fix(copilot): keep a drag a local selection so Auto Copy works
Copilot's TUI turns mouse tracking on itself. Under `strip-mux-only` those DECSETs reached
xterm, which then reported a plain drag to the TUI instead of selecting (only Shift+drag
selected), so Auto Copy and copy-on-select did nothing. This is the failure opencode had and
`strip-mux-and-mouse` was added for: the DECSETs are stripped, a drag is a local selection and
clicks still reach the CLI through the browser's hand-encoded tap (`cliMouseTracking`).

Stripping them also stops xterm from encoding the wheel for the CLI, so
`_shouldForwardWheelToApp` now forwards it as SGR reports while Copilot is tracking the mouse
(the same bytes xterm sent natively, which is what scrolling was verified against). Shift+wheel
stays on local scrollback and a stale flag falls back to PageUp/PageDown.

Tests: the strip flavor for copilot (stripped DECSETs, 3J kept, cliMouseTracking, direct-PTY
untouched) and the wheel gate (forwards while tracking, no other non-claude mode changes).
2026-10-18 00:47:47 +08:00
Devvyn dc87ef724c fix(cli-registry): address review on GitHub Copilot run mode
- Drop GH_TOKEN / GITHUB_TOKEN from env.allowedKeys. The allowlist is one global list with no
  mode context, so they were settable on every session. COPILOT_GITHUB_TOKEN is already admitted
  by the COPILOT_ prefix.
- Declare capabilities.mcpConfig (copilot-json, COPILOT_HOME relocation) so Settings does not
  list Copilot as unsupported while the sync-only target also lists it. The sync-only row is
  skipped while the run mode is enabled.
- Require a leading alphanumeric on the resume id (path-segment in the registry, matching regex in
  the schema): --resume's value is optional, so `--resume --yolo` made --yolo its own flag and
  bypassed the allowAll clamp. Golden cases added; "ids only" wording corrected.
- Remove the unread overlays.credStore line and document signing in inside a Docker container.
- Add the zh-CN "Run GitHub Copilot" string, pin the new declarations in tests and update the
  MCP registry expectations.
2026-10-18 00:47:47 +08:00