mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 02:29:33 +01:00
codeman@1.49.0
6
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
9b8f853c94 |
fix(custom-model): keep a session's own config dir conversation across an endpoint
A claude session on its own CLAUDE_CONFIG_DIR launched on an endpoint with <isolated>/projects linked to the server's tree. The resume pin looks there, so apply found no transcript and started a new conversation, and on clear the endpoint's transcript stayed behind in the server's tree. The link now goes to <own dir>/projects when the session set one, so the conversation and what the endpoint run adds stay on the session's own account across an apply, a clear and a restart. It goes through linkRealHomeEntry(), which also creates a missing projects folder instead of leaving a dangling link, in the own dir and in ~/.claude/projects on the default path. A relative CLAUDE_CONFIG_DIR of the server gets no link, since joining it would create projects under the server's working directory. Rule #516: guardSessionConfigDirHome() now covers configDirVar, so all three apply sites (route, quick-start, boot recovery) probe the own dir bounded before the apply touches it, and a dir that does not answer falls back to the server's tree. Under test, HOME is a temp dir and CLAUDE_CONFIG_DIR is stripped by test/setup.ts, which a new test pins. Measured on a real Codeman server with a fake claude: apply and re-apply resume under the isolated dir with the transcript landing in the own dir, a clear resumes on the own dir, the isolated dir goes while the transcript stays, and the same holds across a server restart. The documented limits come out. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
db5222c4fa |
fix: keep a home value that is not a path off disk, and re-apply from the own home (release review)
getCustomModelForPersist() trusted homeEnvVar to name a path, but the registry types it as any env name, so a clis.json override could write a session's own credential to state.json. Only an absolute path is written now. A re-apply resolved the CLI's real home from what the session's map held, which under a selection is the injected directory, and recovery resolved none at all. An entry the own home lacks (settings.yaml) was then linked from the server's home on an endpoint switch and on recovery. The route now reads the new Session.ownEnvValue(), and recovery reads the clamped record through the same bounded guard, under the bulk cap since it walks every saved session. Also corrects the comment that said only a removed directory gets its links again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
10d43b993e |
fix(custom-model): give a session its own env values back when the selection goes
Applying a custom model writes the endpoint's values over the keys it injects, and clearing the model unset those keys. A session that had set one of them itself lost that value: its own DSH_HOME, CODEX_HOME, GROK_HOME or GEMINI_API_KEY was gone once the model was cleared, and so was CLAUDE_CONFIG_DIR, which silently moved a Claude session onto the default account. Switching endpoints did the same. setCustomModel() now records what the session held under each injected key and restores it on clear and on switch. Quick-start passes the caller's values to the Session constructor so they are seen before the selection lands. The selection overwrites the only other copy, tmux's setenv, so the session's own home directory has to survive a Codeman restart on its own. __customModel therefore stores that one path, the single exception to persisting keys only, and recovery runs it through clampEnvOverridesForOwner() so a revoked grant cannot bring it back. Any other own value, a credential included, stays in memory only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
ed67596387 |
fix(custom-model): pass context limits and selected model to CLIs, and add model picker filter
- opencode: write limit.context/output from the discovered context length (#749) - codex: override the native launch model when a custom endpoint is selected (#750), and set model_context_window - model picker: add a search/filter box with a no-matches line |
||
|
|
1cb0441bd8 |
fix(session): degrade the resume pin to the session id, not to nothing
A single pin that failed its transcript gate returned the options untouched, so `resumeSessionId` fell back to `_resumeSessionId` — undefined for an ordinary session — and the renderer emitted the bare `claude --dangerously-skip-permissions --session-id "<this.id>"`. Every session prompted before its first `/clear` owns a transcript under that id, so the dropped pin handed back exactly the refusal this branch removes, with no `||` branch to catch it. It was also a regression against master on the `restartCli()` path, which pinned `_claudeSessionId ?? this.id` and, since the constructor seeds that field, could never land unpinned. The pin now walks three candidates in priority order — the conversation chain's tail, the launch seed, then the session's own id — and takes the first one a transcript backs. A candidate that misses is passed over rather than ending the walk. Falling off the end pins nothing, which also settles the second half of the problem: the old code skipped the transcript check whenever the pin was the session's own id, so a genuinely new pane rendered the two-branch form after all. That costs a brand-new session claude's "No conversation found" line in its scrollback, and `wrapWithNice()` prefixes only the first branch of the rendered `a || b`, so the branch that actually runs loses its priority for the life of the session. With no transcript anywhere the bare `--session-id` is the correct command, so the comment claiming an unchanged shape is now true. The transcript lookup reads the server process's own `CLAUDE_CONFIG_DIR` when a session declares none. A pane inherits the server environment through tmux, so on an install that exports it the CLI writes its transcripts there and every lookup under `~/.claude` was a false negative — which under the old code meant the colliding command. `claudeCredentialsPath()` and `realClaudeConfigDir()` resolve the same directory the same way. The header sentence calling a skipped resume "the safe direction" described the opposite of what happens at this call site, and says so now. The create-path fallback writes `_resumeSessionId` alongside the create options. That branch leaves `isRestored` false, so `_claudeSessionId` is recomputed from the launch fields and settled on `this.id` while the CLI resumed the chain tail; the response viewer, Read My Mind and the unified-list alias map read that field until the next first-hand hook. Four new tests: a chain tail with no transcript while the session id has one, no transcript anywhere, the create path's alias, and the process-env lookup. All four fail against the previous commit. Two existing tests move with the gate — the guess-refusal test now backs the session's own id, and the custom-model restart test gives its working pane the transcript that makes `--session-id` collide in the first place, alongside a new one pinning the no-transcript case. CLAUDE.md described the pin as a `restartCli()`-only thing sourced from the live conversation id. All three halves of that moved here. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
942bf37e48 |
fix(custom-model): unset injected env on clear, resume on restart, select the model for pi/omp/grok
Custom Model Endpoint Profiles (#393) let a session point its CLI at a custom OpenAI-compatible endpoint by injecting env vars or a config file and restarting the CLI in place. Review of the apply path found four things, two of them destructive. This lands all four plus the smaller items from the same review. 1. Clearing a selection did not clear it. The injected vars reach the CLI via `tmux setenv`, which persists at the tmux-session level and is inherited by `respawn-pane` (measured: `setenv FOO bar` survived two successive `respawn-pane -k`), so deleting the keys from the session's envOverrides relaunched the CLI still pointed at the old endpoint, and for the configDir kinds at a HOME/CODEX_HOME/GROK_HOME that had just been deleted. `Session.setCustomModel()` now reports the removed keys, queues them (`_pendingEnvUnsets`), and `RespawnPaneOptions.unsetEnvKeys` carries them into `applyEnvOverrides()`, which `setenv -u`s them before re-applying the live overrides, on the same path that already unsets the legacy CLAUDE_CODE_EFFORT_LEVEL. Verified on a private tmux socket that `setenv -u HOME` hands the next respawn the global HOME back. 2. Applying a model to a local claude session killed the pane. The relaunch was `claude --session-id <id>` and Claude refuses an id that already has a transcript, and unlike the dead-pane respawn this one kills a working pane first. `restartCli()` now pins the live conversation id as the resume id for that respawn when the CLI's launch declares a `fallback` chain, which renders the same `--resume <id> || --session-id <id>` shape the docker and remote pane commands use. Gated on the registry shape, not the CLI id: an entry whose resume id is minted by the CLI itself never declares that chain. 3. pi, omp and grok wrote their config file and then launched without the `--model` that selects it, so the file was ignored. The registry entry now declares `customModelInjection.launchModel` (`custom/{modelId}` for pi and omp, grok's `[model.codeman-custom]` block name), the builder renders it, and `_withCustomModelLaunchModel()` applies it onto the respawn options through `legacyConfigField`, leaving the stored <Mode>Config untouched so a clear falls back to the user's own model. A model id the CLI's `model` token pattern cannot carry is refused with a 400 rather than silently dropped by the argv engine. 4. Remote (SSH) and Docker sessions reported `restarted: true` and changed nothing: their `restartCli()` reattaches the durable tmux rather than relaunching the agent, and the env lands on the local pane. Both are refused with a 400 until those paths are plumbed. Smaller items from the same review: - The selection survives a Codeman restart as the disk-only `__customModel` bookkeeping (endpoint, model, injected key NAMES, config dir, launch model; never the values, which carry the API key). Recovery re-derives the values from the endpoint store through the same apply path the route uses and keeps the bookkeeping even when the endpoint is gone, so a later clear still has keys to unset. - Discovery goes through `webviewFetch()`, so the RESOLVED address is judged by the same egress guard the web-tab proxy uses, and `baseUrl` reuses `webviewUrlSchema` (http(s) only, no embedded credentials, link-local and cloud-metadata addresses refused). undici's `fetch failed` wrapper is unwrapped so the user sees the ECONNREFUSED underneath. - `custom-model-hosts.json` is written 0600 via tmp+rename, the per-session config dir 0700/0600 (pi and omp embed the key literally), and that dir is removed with the session. - `PR.md` is gone from the repo root and the design doc moved to `docs/custom-model-endpoints-plan.md` with the LAN address and the personal name scrubbed; every reference follows. The guide's `authStyle` text matches the shipped schema (`bearer | api-key`, default `bearer`) and says that `customModelEndpointsEnabled` is read by nothing until the picker lands. - `config/tsconfig.scripts.json` typechecks `scripts/test-local-llm-harnesses.ts` (four real type errors fixed). It is not yet wired into `npm run typecheck` because that line differs on master; adding `&& tsc -p config/tsconfig.scripts.json` there is the one-line follow-up. Tests: `test/session-custom-model-restart.test.ts` drives a real Session and fails on the unfixed code for items 1 to 3; the route suite covers item 4 and the pattern refusal; `test/tmux-manager.test.ts` pins that the unsets run before the overrides and that a shell-metachar key never reaches tmux. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |