Commit Graph

5 Commits

Author SHA1 Message Date
nntrivi2001 0a86dfb8c5 feat(settings): add AI Router profiles and attach one per lane
A new **AI Router** tab in Settings, next to Codex, stores named router
endpoints (9Router, OpenRouter, a self-hosted gateway) as profiles: a base
URL, an API key, a default model and an optional per-tier override. The tab
only stores them; a lane CHOOSES one in the Add-lane modal, via a Native /
AI Router radio, and that choice is written into the lane's own config.

The two CLIs are configured differently, and the difference is theirs:

  - a claude lane gets eight `env` keys merged into its own
    `.claude/settings.local.json` (`.local` because the value holds a key);
  - a codex lane gets `$CODEX_HOME/<name>.config.toml` — the layer
    `codex -p <name>` loads — because Codex has NO project-level config.
    Its base `config.toml` is never touched.

Native is a built-in profile rather than a code branch, so "go back to
native" is the same write path. It blanks the two connection variables
instead of removing them (an absent key at project scope lets a USER-level
router apply) and removes the model names instead of writing them (writing
them would override the user's own global model choice).

Key material never leaves the server: profiles live one file each under
`<CLAUDE_HOME>/agenthub-routers/` (0700/0600), `GET /api/ai-routers`
reports only `hasKey`, and there is deliberately no route returning one
profile in full.

Three things this had to get right, each found by review and verified
against the real tools rather than assumed:

  - `wire_api = "chat"` is rejected outright by codex-cli 0.149 ("no longer
    supported"), so every codex lane on a router would have failed to start.
    The layer writes "responses", and writes `env_key` only when the profile
    actually has a key — naming an unset variable is itself a startup error.
  - The key must never be TYPED into a pane. `tmux.sendCommand` used
    `send-keys` with a `KEY='…' cmd` prefix, which the dashboard streams to
    every attached browser and bash appends to history; it now takes over the
    idle pane with `respawn-pane -k -e`, passing env through argv the way
    `newSession` always has. Verified on tmux 3.4: multi-element argv arrives
    intact and the pane renders no trace of the value.
  - Attaching COPIES a profile, so editing or deleting one in Settings has to
    reach the lanes already using it. An edit re-applies it (a rotated key
    would otherwise never reach the lane still holding the revoked one); a
    delete resets those lanes to native and removes the Codex layer file.
    Both report per-lane failures, which the tab surfaces.

`.claude/settings.local.json` is added to the lane's git exclude, for both
native and router lanes: `agenthub lanes reset` runs `git clean -fd` without
`-x`, so an un-excluded settings file is deleted on reset — and untracked
meant the key was committable.

DB: `lanes.router_profile`, nullable, additive. Written only by
`setRouterProfile` beside the disk write, never through `PATCHABLE`.
2026-09-14 16:04:57 +07:00
nntrivi2001 2942ced3ec style(config): give Codex the same tab bar as Claude Code, drop the Cursor tab
The Codex tab strip wrapped onto a second row while Claude Code's stayed
one scrollable row, so two panels that are meant to be twins read as
different components. Both now render the same ConfigTabBar — the
scroller lifted out of CcConfig, with the fade edges and chevrons that
only appear when there is somewhere to scroll. The deferral note in
CodexConfig that predicted this is gone with it.

The bar also carries role="tablist"/"tab" and aria-selected now: Codex
had them, Claude Code did not, and one of the two had to win.

Cursor's placeholder tab goes away with the machinery that served only
it — the optional Panel, the "soon" badge, the coming-soon card, and
their four i18n keys.

Element.scrollBy and friends move to test-setup: jsdom has none of them,
and the tab bar now calls them from both pages.
2026-09-09 14:44:25 +07:00
nntrivi2001 8015730adf feat(codex): create and customize Codex config from /settings
Adds the Codex config panel (skills/agents/rules/memory/config editing,
mcp/plugins/marketplaces add-remove via the codex CLI) as the last piece
of parity with the Claude Code settings tab, plus the codex_config_changed
WebSocket type the client was missing, and docs for the new
/api/codex-config surface.
2026-09-08 21:09:28 +07:00
nntrivi2001 bcfeeb5140 feat(sessions): merge the activity feed into a tab on /sessions
Sessions and Activity Feed are two views of the same event pipeline, so
they now share one page: /sessions renders a tab bar (Sessions | Activity
Feed) with the active view in the ?view= query param, and /activity
redirects to /sessions?view=events. The sidebar entry is dropped.

The tab bar itself moves out of SettingsHub into components/PageTabs so
both hubs share it, and DocumentTitle loses the two branches for paths
that now only redirect.
2026-08-26 09:17:17 +07:00
nntrivi2001 341197aac0 feat(settings): host Claude config as a tab in Settings
Settings becomes a tabbed shell (SettingsHub) with one tab per AI tool:
Dashboard (existing settings), Claude Code (CcConfig), plus Codex and
Cursor placeholders. Active tab lives in the ?tool= query param, and the
old /cc-config route redirects to /settings?tool=claude-code. The
standalone sidebar entry is dropped.

Adding a tool is one entry in TOOL_TABS plus its i18n label.
2026-08-26 09:01:00 +07:00