feat: AI commit messages, change tree, router behavesAs, sidebar times (v2.2.0)
- Changes panel: Files and Changes merged into one panel; the overview's groups drawn as a folder tree (compacted chains, file counts, fold, stage/unstage a whole folder) - AI-suggested commit message for what is staged (POST /api/lanes/:id/git/commit-message, claude -p --safe-mode, haiku) - AI Router: optional "Behaves as" Claude model id, written as modelPicker options into the router's --settings file (issue #56) - Sidebar: session rows show last activity, live rows their start time; a closed Terminal row can be removed (DELETE /api/run/history/:id) - Every pane's CLI starts only once a client is attached; claude panes no longer forced inline; tmux scrollbar one column wide - Update notifier: "Check for updates" reopens a closed notice
This commit is contained in:
@@ -8,7 +8,8 @@
|
||||
* theirs, not a choice made here:
|
||||
*
|
||||
* - **Claude Code** gets `--settings=<file>`: a settings file holding the
|
||||
* profile's eight `env` keys, `<data dir>/router-settings/<name>.json`
|
||||
* profile's eight `env` keys (plus `modelPicker` rows when the profile
|
||||
* sets `behavesAs`), `<data dir>/router-settings/<name>.json`
|
||||
* (0600). The command-line layer outranks the project-local and user
|
||||
* settings (verified on 2.1.286), so two sessions of one workspace can run
|
||||
* on two routers, and the key stays out of argv — only the path is there.
|
||||
@@ -73,12 +74,29 @@ function writeSecret(file, body) {
|
||||
fs.chmodSync(file, 0o600); // an existing file keeps its mode on write
|
||||
}
|
||||
|
||||
/**
|
||||
* `modelPicker` rows telling Claude Code which known model each of the router's
|
||||
* own names behaves as — without one, a name like 9Router's `agent` draws an
|
||||
* "isn't described by this version's model catalog" warning and a 200k
|
||||
* compact window (issue #56). Only when the profile sets `behavesAs`: this
|
||||
* layer's `modelPicker` replaces the user's own for the session. A bare
|
||||
* `claude-*` id is skipped, since Claude Code already knows it.
|
||||
*/
|
||||
function modelPicker(profile) {
|
||||
if (!profile.behavesAs) return {};
|
||||
const names = new Set([profile.model, ...Object.values(profile.models || {})]);
|
||||
const options = [...names]
|
||||
.filter((m) => m && !m.startsWith("claude-"))
|
||||
.map((model) => ({ model, behavesAs: profile.behavesAs }));
|
||||
return options.length ? { modelPicker: { options } } : {};
|
||||
}
|
||||
|
||||
function writeClaudeSettings(profile) {
|
||||
const file = claudeSettingsPath(profile.name);
|
||||
// Empty values are left out: a blank key in the command-line layer would
|
||||
// blank the user's own setting, not leave it alone.
|
||||
const env = Object.fromEntries(Object.entries(envForProfile(profile)).filter(([, v]) => v));
|
||||
writeSecret(file, `${JSON.stringify({ env }, null, 2)}\n`);
|
||||
writeSecret(file, `${JSON.stringify({ env, ...modelPicker(profile) }, null, 2)}\n`);
|
||||
return file;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user