zidane 5.6.3 → 5.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { a as ExecutionContext, i as ExecResult, n as ContextCapabilities, o as ExecutionHandle, r as ContextType, s as SpawnConfig } from "./types-KukEp-mi.js";
2
2
  import { t as SandboxProvider } from "./index-CbS75MD3.js";
3
3
  import { $t as SpawnHookContext, Bt as McpToolHookContext, D as SkillConfig, Dt as OpenAIParams, F as SessionRun, Ft as AgentRunOptions, Gt as PromptPart, Ht as OAuthRefreshHookContext, I as SessionStore, It as AgentStats, Jt as SessionContentBlock, Kt as PromptTextPart, Lt as ChildRunStats, M as CreateSessionOptions, N as Session, Nt as AgentBehavior, P as SessionData, Pt as AgentClock, Qt as SessionTurn, Rt as DEFAULT_AGENT_CLOCK, S as ReadStateMap, Ut as PromptDocumentPart, Wt as PromptImagePart, Xt as SessionHookContext, Yt as SessionEndStatus, Zt as SessionMessage, _n as ClassifiedError, an as ToolResultTextContent, b as ToolMap, bn as matchesContextExceeded, cn as toolOutputByteLength, ct as StreamCallbacks, dn as AgentBudgetExceededError, dt as ToolResult, en as StreamHookContext, fn as AgentContextExceededError, ft as ToolSpec, gn as CONTEXT_EXCEEDED_MESSAGE_PATTERNS, i as AgentOptions, in as ToolResultImageContent, j as SkillsConfig, jt as AnthropicParams, k as SkillResource, kt as CerebrasParams, ln as toolResultToText, lt as StreamOptions, mn as AgentToolNotAllowedError, nn as ToolHookContext, on as TurnFinishReason, ot as Provider, p as McpConnection, pn as AgentProviderError, pt as TurnResult, qt as RunHookMap, r as AgentHooks, rn as ToolResultContent, sn as TurnUsage, st as ProviderCapabilities, t as Agent, tn as ThinkingLevel, un as AgentAbortedError, ut as ToolCall, v as ToolContext, vn as ClassifiedErrorKind, x as ReadStateEntry, y as ToolDef, yt as OpenRouterParams, z as RemoteStoreOptions, zt as McpServerConfig } from "./agent-D70rr6Uk.js";
4
- import { H as ModelUsage, L as InteractionToolOptions, S as SpawnToolState, U as flattenTurns, W as statsByModel, b as ChildAgent, h as ValidationResult, t as Preset, x as SpawnToolOptions } from "./index-DKpXHp1c.js";
4
+ import { H as ModelUsage, L as InteractionToolOptions, S as SpawnToolState, U as flattenTurns, W as statsByModel, b as ChildAgent, h as ValidationResult, t as Preset, x as SpawnToolOptions } from "./index-8mn3PIaa.js";
5
5
  export { type Agent, AgentAbortedError, type AgentBehavior, AgentBudgetExceededError, type AgentClock, AgentContextExceededError, type AgentHooks, type AgentOptions, AgentProviderError, type AgentRunOptions, type AgentStats, AgentToolNotAllowedError, type AnthropicParams, CONTEXT_EXCEEDED_MESSAGE_PATTERNS, type CerebrasParams, type ChildAgent, type ChildRunStats, type ClassifiedError, type ClassifiedErrorKind, type ContextCapabilities, type ContextType, type CreateSessionOptions, DEFAULT_AGENT_CLOCK, type ExecResult, type ExecutionContext, type ExecutionHandle, type InteractionToolOptions, type McpConnection, type McpServerConfig, type McpToolHookContext, type ModelUsage, type OAuthRefreshHookContext, type OpenAIParams, type OpenRouterParams, type Preset, type PromptDocumentPart, type PromptImagePart, type PromptPart, type PromptTextPart, type Provider, type ProviderCapabilities, type ReadStateEntry, type ReadStateMap, type RemoteStoreOptions, type RunHookMap, type SandboxProvider, type Session, type SessionContentBlock, type SessionData, type SessionEndStatus, type SessionHookContext, type SessionMessage, type SessionRun, type SessionStore, type SessionTurn, type SkillConfig, type SkillResource, type SkillsConfig, type SpawnConfig, type SpawnHookContext, type SpawnToolOptions, type SpawnToolState, type StreamCallbacks, type StreamHookContext, type StreamOptions, type ThinkingLevel, type ToolCall, type ToolContext, type ToolDef, type ToolHookContext, type ToolMap, type ToolResult, type ToolResultContent, type ToolResultImageContent, type ToolResultTextContent, type ToolSpec, type TurnFinishReason, type TurnResult, type TurnUsage, type ValidationResult, flattenTurns, matchesContextExceeded, statsByModel, toolOutputByteLength, toolResultToText };
package/docs/CHAT.md CHANGED
@@ -115,6 +115,7 @@ The table below indexes every named export; sections further down dive into the
115
115
  |---|---|
116
116
  | `agents` | Multi-profile registry — `AgentProfile`, `AgentRegistry`, `AgentAccent`, `BUILD_AGENT`, `PLAN_AGENT`, `BUILTIN_AGENTS`, `DEFAULT_AGENT_ID`, `DEFAULT_PERSIST_EXCLUDE_TOOLS`, `resolveAgentId`, `singleAgentRegistry`, `accentColor`. See **Agents** below. |
117
117
  | `agent-prompt` | Composable system-prompt fragments — `IDENTITY_PREFIX`, `DOING_TASKS_DOCTRINE`, `ACTIONS_WITH_CARE_DOCTRINE`, `TOKEN_DISCIPLINE_DOCTRINE`, `COMMUNICATION_DOCTRINE`, `SUBAGENT_GUIDANCE`, `PLAN_MODE_DOCTRINE`, `PLAN_MODE_DOCTRINE_NO_PROMPTS`, `INTERACTION_GUIDANCE`, `INTERACTION_GUIDANCE_NO_PROMPTS`, `envSection`, `buildBuildSystem`, `buildPlanSystem`. Types: `BuildSystemOptions`, `EnvSectionOptions`. See **System prompt** below. |
118
+ | `agents-md` | Personal-instructions discovery — `discoverAgentsMd({ cwd, home, prefix, scope })` walks `~/.agents/AGENTS.md`, `~/.{prefix}/AGENTS.md`, `~/.claude/CLAUDE.md`, `<repo>/AGENTS.md`, `<repo>/.agents/AGENTS.md`, `<repo>/.{prefix}/AGENTS.md`, `<repo>/CLAUDE.md` and loads **every** file that exists (broadest → narrowest, deduped by absolute path; empty / whitespace-only files skipped). The `scope` option (`'none'` / `'user'` / `'project'` / `'both'`, default `'both'`) restricts which scopes contribute — `'none'` short-circuits before any filesystem access. Renders a `userInstructions` block consumed by `buildBuildSystem` / `buildPlanSystem`. Types: `AgentsMdFile`, `AgentsMdResult`, `AgentsMdScope`. |
118
119
  | `auth` | `detectAuth(dataDir, providers)` reports which providers have usable credentials and which auth method each accepts. `ProviderAuth.methods[].source` is `'apikey' \| 'oauth'`. |
119
120
  | `auto-compact` | `shouldAutoCompact(input)` — pure predicate returning `'fire' \| 'skip'`. See **Auto-compaction**. |
120
121
  | `boot-profiler` | `bootTick(label)` / `bootProfileEnabled()` — `ZIDANE_BOOT_PROFILE=1` opt-in wall-clock checkpoints for boot-path perf work. |
@@ -122,7 +123,8 @@ The table below indexes every named export; sections further down dive into the
122
123
  | `color-gradient` | `blendHsl`, `buildLinearRamp` — HSL-space ramp builders shared by the TUI's throbber + title overlay. |
123
124
  | `completion` | Extensible prompt autocompletion. `CompletionProvider<TItem>`, `useCompletion`, helpers (`findActiveTrigger`, `applyInsert`, `collectReferences`, `mergeReferences`). See **Completion**. |
124
125
  | `completion-skills`, `completion-files` | Built-in `/` (skills) + `@` (files) providers. Submit helpers: `uniqueSkillNamesFromReferences`, `uniqueFilesFromReferences`. |
125
- | `config` + `config-context` | `resolveConfig`, `useConfig`, `ChatOptions`, `ResolvedConfig`, `ResolvedPaths`, `ModelInfo`, `ProviderRegistry`. See **Required options**. |
126
+ | `config` + `config-context` | `resolveConfig`, `resolveStoragePaths`, `useConfig`, `ChatOptions`, `ResolvedConfig`, `ResolvedPaths`, `ModelInfo`, `ProviderRegistry`. See **Required options**. |
127
+ | `xdg` | XDG Base Directory resolver — `resolveStorageDirs({ prefix, storageDir?, home?, platform?, env? })` returns `{ configDir, dataDir, stateDir, cacheDir, mode }`. Honors `XDG_*_HOME` / `ZIDANE_*_DIR` env vars; preserves legacy `~/<prefix>/` for existing setups. Types: `StorageDirs`, `StorageMode`, `StorageSlot`. See **Storage-slot layout**. |
126
128
  | `credentials` | AI-provider credential store. `setProviderCredential`, `readProviderCredential`, `removeProviderCredential`, `readCredentials`, `writeCredentials`, `credentialsPath`, `applyApiKeyEnv` (called by `resolveConfig` before any factory runs). Owner-only file mode. |
127
129
  | `discovery-context` + `discovery-slot` | Live catalog plumbing: `DiscoveryProvider`, `useDiscovery`, `useDiscoveryOptional`, `createDiscoverySlot` (stale-while-revalidate primitive). Propagates fresh catalogs (files, skills, MCPs) into open modals. See **Discovery context** below. |
128
130
  | `edit-approval` | Pure helpers bridging the safe-mode gate to the host-side per-hunk flow — `resolveApprovalForPayload`, `maskToOutcomeKinds`, `buildEditOutcomesAnnotation`, `parseEditOutcomesFromResult`, `summarizeOutcomes`, `ResolvedApproval`. See **Per-edit approval**. |
@@ -133,7 +135,7 @@ The table below indexes every named export; sections further down dive into the
133
135
  | `generate-title` | `generateSessionTitle({ session, provider, model, signal? })` + `cleanTitle`. |
134
136
  | `hints` | Footer + prompt-hint plumbing — `Hint`, `hintsLength`, `clipHintsToWidth`, `truncateTrailing`. Plain-text math; rendering is the consumer's job. |
135
137
  | `interactions` | Plan + Q&A protocol (`present_plan`, `ask_user`). See **Interactions** and `docs/INTERACTIONS.md`. |
136
- | `keybindings` | Action catalog + JSONC overrides — `KEYBINDING_DEFS`, `KEYBINDING_DEF_BY_ACTION`, `DEFAULT_KEYBINDINGS`, `parseBindingSpec`, `matchesBinding`, `mergeKeybindings`, `readKeybindings`, `ensureKeybindingsFile`, `keybindingsPath`, `stripJsonComments`. See **Keybindings**. |
138
+ | `keybindings` | Action catalog + JSONC overrides — `KEYBINDING_DEFS`, `KEYBINDING_DEF_BY_ACTION`, `DEFAULT_KEYBINDINGS`, `parseBindingSpec`, `matchesBinding`, `mergeKeybindings`, `formatBindingForDisplay`, `groupBindings`, `KEYBINDING_KEY_COL_WIDTH`, `readKeybindings`, `ensureKeybindingsFile`, `keybindingsPath`, `stripJsonComments`. See **Keybindings**. |
137
139
  | `markdown-segments` | `splitMarkdownCodeBlocks(text)` → `MarkdownSegment[]` (`'prose' \| 'code'`). Lets transcript renderers wrap fences with custom chrome (copy buttons, language pills) without re-parsing. |
138
140
  | `mcp-auth-state` | Pure reducer — `reduceMcpAuth(state, event)`, `getMcpAuthStatus`, `McpAuthStatus`, `McpAuthEvent`, `McpAuthStateMap`. See **MCP OAuth state**. |
139
141
  | `mcp-auth-context` | React provider — `McpAuthProvider`, `useMcpAuthState`, `useMcpAuthDispatch`. Two contexts split so dispatch consumers don't re-render on state churn. |
@@ -145,12 +147,12 @@ The table below indexes every named export; sections further down dive into the
145
147
  | `path-display` | `formatPathForCwd(projectRel, projectRoot, cwd)` — rewrites a project-root-relative path (as emitted by `listProjectFiles`) into the form the agent's CWD-resolving tools actually find. Wired into `createFilesCompletionProvider({ formatPath })` by the TUI shell. |
146
148
  | `project-root` | `findGitRoot(cwd)` — walks upward looking for `.git`, returns absolute path or `null`. Used for session scope tagging + export anchors. |
147
149
  | `prompt-segments` | `splitPromptSegments(text, refs)` → `PromptSegment[]`. GUI maps the same segments to inline-block chip pills. |
148
- | `project-user-paths` | `projectUserPaths({ subPath, cwd, home, prefix })` — shared search-order builder for project + user config discovery. Powers `defaultSkillScanPaths` (`'skills'`) and `defaultMcpsConfigPaths` (`'mcps.json'`); the same convention extends to any new discovery surface. |
150
+ | `project-user-paths` | `projectUserPaths({ subPath, cwd, home, prefix })` — shared search-order builder for project + user config discovery. Powers `defaultSkillScanPaths` (`'skills'`) and `defaultMcpsConfigPaths` (calls it twice, once per `mcps.json` / `mcp.json`); the same convention extends to any new discovery surface. |
149
151
  | `providers` | `ProviderDescriptor` registry + helpers — `BUILTIN_PROVIDERS`, built-ins (`anthropicDescriptor`, `openaiDescriptor`, `openrouterDescriptor`, `cerebrasDescriptor`), `modelsForDescriptor`, `getModelInfo`, `getContextWindow`, `effectiveContextWindow`, `modelSupportsReasoning`, `OUTPUT_RESERVE_TOKENS`, `credKeyOf`, `piIdOf`. |
150
152
  | `safe-mode` | Per-project safelist + matchers — `IMPLICITLY_SAFE_TOOLS`, `suggestSafelistEntry`, `addToSafelist`, `getSafelist`, `isOnSafelist`, `matchesSafelistEntry`, `readProjects`, `writeProjects`, `projectsFilePath`. |
151
153
  | `safe-mode-context` | `SafeModeProvider` owns a FIFO approval queue. `useSafeModeQueue()` returns the live array; `useSafeModeActions()` returns stable `{ requestApproval, resolveHead, denyAll }`. |
152
154
  | `session-export` | `renderSession`, `resolveSessionExportTarget`, `writeSessionExport`, `SessionExportFormat`, `SessionExportAnchor`, `SessionExportTarget`. |
153
- | `settings-context` | `SettingsProvider`, `useSettings`, `DEFAULT_SETTINGS`, `SETTINGS_TOGGLES`, `SETTINGS_CHOICES`, `BooleanSettingKey`. See **Settings**. |
155
+ | `settings-context` | `SettingsProvider`, `useSettings`, `DEFAULT_SETTINGS`, `SETTINGS_TOGGLES`, `SETTINGS_CHOICES`, `SETTINGS_CATEGORIES`, `BooleanSettingKey`, `SettingsCategory`, `SettingsCategoryDescriptor`. See **Settings**. |
154
156
  | `skills-discovery` | `discoverProjectSkills`, `buildSkillsConfig`, `defaultSkillScanPaths`. |
155
157
  | `store` | Session reconstruction + persisted UI state + transcript view rules — `eventsFromTurns`, `lastContextSizeFromTurns`, `listSessionMeta`, `deriveSessionTitle`, `titleFromTurns`, `selectableTurnIds`, `stripSpawnTokensLine`, `toolCallPreview`, `toolResultText`, `createStateStore`, `loadState`, `saveState`, `isVisible`, `marginTopFor`, `isEditErrorResult`, `isTurnHighlighted`, `sumRunCosts`, `turnSelectionOwnership`, `TuiState`, `StateStoreApi`. |
156
158
  | `streaming` | `useStreamBuffer`, `finalizeStreamingMarkdown`, `finalizeStreamingMarkdownForOwner`, `turnContextSize`. Per-owner finalize handles concurrent parent + child streams. |
@@ -200,24 +202,53 @@ resolveConfig({
200
202
  | Var | Effect |
201
203
  |---|---|
202
204
  | `ZIDANE_PREFIX` | Overrides `options.prefix`. |
203
- | `ZIDANE_STORAGE_DIR` | Overrides `options.storageDir`. |
205
+ | `ZIDANE_STORAGE_DIR` | Pin all four storage slots to a single dir (legacy single-dir layout). When unset, the XDG resolver kicks in on Linux (or any platform with an `XDG_*_HOME` set / per-slot `ZIDANE_*_DIR` set). |
206
+ | `ZIDANE_CONFIG_DIR` | Override the XDG config slot (default `$XDG_CONFIG_HOME/zidane`). Ignored when `ZIDANE_STORAGE_DIR` is set. |
207
+ | `ZIDANE_DATA_DIR` | Override the XDG data slot (default `$XDG_DATA_HOME/zidane`). |
208
+ | `ZIDANE_STATE_DIR` | Override the XDG state slot (default `$XDG_STATE_HOME/zidane`). |
209
+ | `ZIDANE_CACHE_DIR` | Override the XDG cache slot (default `$XDG_CACHE_HOME/zidane`). |
204
210
  | `ZIDANE_PROJECT_DB` | `'0' / 'false' / 'off' / 'no'` → off; `'1' / 'true' / 'on' / 'yes'` → on. Sits between `options.projectDb` and the user-config file. |
205
211
  | `ZIDANE_CREDENTIALS_PATH` | Set by `resolveConfig` itself; the harness providers read it. |
206
212
  | `ZIDANE_DEBUG` | Enables stderr logging for swallowed errors (teardown, save, MCP bootstrap). |
207
213
 
208
214
  ### Project-DB precedence
209
215
 
210
- Project mode resolves through: `options.projectDb` > env var > `~/.{prefix}/config.json` `projectDb` flag > default (off). It activates only when the resolution lands on `true` **and** a git repo is found above `cwd`; otherwise everything stays at the user dir.
216
+ Project mode resolves through: `options.projectDb` > env var > `<configDir>/config.json` `projectDb` flag > default (off). It activates only when the resolution lands on `true` **and** a git repo is found above `cwd`; otherwise everything stays at the user-scoped slots.
217
+
218
+ ### Storage-slot layout
219
+
220
+ `zidane` writes to four logical slots. The XDG resolver (`resolveStorageDirs`) picks between four resolution modes:
221
+
222
+ | Mode | Trigger | Layout |
223
+ |---|---|---|
224
+ | `legacy-explicit` | `options.storageDir` set OR `ZIDANE_STORAGE_DIR` set | All four slots collapse to `<storageDir>/<prefix>`. |
225
+ | `legacy-existing` | `~/<prefix>/` exists on disk | All four slots collapse to `~/<prefix>/`. Existing users keep their setup unchanged. |
226
+ | `xdg` | Linux, OR any `XDG_*_HOME` / `ZIDANE_*_DIR` set | Slots fan out per spec (see below). |
227
+ | `default` | Otherwise (mac/windows fresh) | All four slots collapse to `~/<prefix>/`. |
228
+
229
+ In XDG mode the four slots map to:
230
+
231
+ | Slot | Default | Holds |
232
+ |---|---|---|
233
+ | `configDir` | `$XDG_CONFIG_HOME/zidane` (`~/.config/zidane`) | `credentials.json`, `mcps.json`, `mcp-credentials.json`, `keybindings.json`, `config.json`, `projects.json` (safelist), `skills/`. |
234
+ | `dataDir` | `$XDG_DATA_HOME/zidane` (`~/.local/share/zidane`) | `sessions.db`. |
235
+ | `stateDir` | `$XDG_STATE_HOME/zidane` (`~/.local/state/zidane`) | `state.json`. |
236
+ | `cacheDir` | `$XDG_CACHE_HOME/zidane` (`~/.cache/zidane`) | Persisted tool-result blobs, background-task logs, auto-update registry cache. |
211
237
 
212
238
  ### `ResolvedPaths`
213
239
 
214
240
  ```ts
215
241
  interface ResolvedPaths {
216
- dir: string // effective root (userDir or projectDir)
217
- userDir: string // always `<storageDir>/<prefix>` — credentials + safelist live here
242
+ dir: string // effective root (configDir or projectDir)
243
+ userDir: string // legacy alias for `configDir` — credentials + safelist live here
218
244
  projectDir: string | null // `<git-root>/<prefix>` when project mode is on
219
- db: string // `<dir>/sessions.db`
220
- state: string // `<dir>/state.json`
245
+ db: string // `<dataDir>/sessions.db` (or projectDir/sessions.db in project mode)
246
+ state: string // `<stateDir>/state.json` (or projectDir/state.json in project mode)
247
+ configDir: string // see Storage-slot layout
248
+ dataDir: string
249
+ stateDir: string
250
+ cacheDir: string
251
+ storageMode: 'legacy-explicit' | 'legacy-existing' | 'xdg' | 'default'
221
252
  }
222
253
  ```
223
254
 
@@ -371,10 +402,11 @@ type ToolCallDisplay = 'hidden' | 'formatted' | 'full'
371
402
 
372
403
  `useSettings()` returns `{ settings, toggle, setSetting }`. `toggle` is restricted at the type level to `BooleanSettingKey` (`[K in keyof Settings]-?: Settings[K] extends boolean ? K : never`); `setSetting` is the general writer.
373
404
 
374
- Two tables drive the picker UI use them as the source of truth so new settings land automatically:
405
+ Three tables drive any settings UI (TUI tabs today, GUI panels tomorrow) — they're the source of truth so new settings land automatically:
375
406
 
376
- - `SETTINGS_TOGGLES: SettingsToggle[]` — boolean rows. `key` is the narrowed `BooleanSettingKey`.
377
- - `SETTINGS_CHOICES: SettingsChoice[]` — value-from-options rows. Currently: `toolCallDisplay`, `autoCompactThreshold`, `theme`, `targetFps`.
407
+ - `SETTINGS_CATEGORIES: SettingsCategoryDescriptor[]` — display order + labels for the high-level buckets (`agent`, `ui`). Each toggle / choice declares which bucket it belongs to via its `category` field.
408
+ - `SETTINGS_TOGGLES: SettingsToggle[]` — boolean rows. `key` is the narrowed `BooleanSettingKey`; `category: SettingsCategory` routes the row to the right tab.
409
+ - `SETTINGS_CHOICES: SettingsChoice[]` — value-from-options rows. `category` field on every entry. Currently spans both buckets: `autoCompactThreshold`, `userInstructionsScope` (agent); `toolCallDisplay`, `editDiffDisplay`, `theme`, `uiMode`, `targetFps` (ui).
378
410
 
379
411
  ## Theme
380
412
 
@@ -1137,15 +1169,15 @@ Both autoload from a fixed search order — project beats user, first-found wins
1137
1169
  ```
1138
1170
 
1139
1171
  ```
1140
- {cwd}/.agents/mcps.json
1141
- {cwd}/.{prefix}/mcps.json
1142
- ~/.agents/mcps.json
1143
- ~/.{prefix}/mcps.json
1172
+ {cwd}/.agents/mcps.json {cwd}/.agents/mcp.json
1173
+ {cwd}/.{prefix}/mcps.json {cwd}/.{prefix}/mcp.json
1174
+ ~/.agents/mcps.json ~/.agents/mcp.json
1175
+ ~/.{prefix}/mcps.json ~/.{prefix}/mcp.json
1144
1176
  ```
1145
1177
 
1146
- `projectUserPaths({ subPath, cwd, home, prefix })` is the shared builder — extend any new discovery surface with the same convention.
1178
+ Both filenames are picked up from every search root. `mcps.json` is zidane's canonical name; `mcp.json` is the Cursor / common ecosystem alias and gets merged alongside (`mcps.json` wins on same-name collisions within a directory; non-overlapping entries from `mcp.json` are kept). `projectUserPaths({ subPath, cwd, home, prefix })` is the shared builder — extend any new discovery surface with the same convention.
1147
1179
 
1148
- `mcps.json` accepts three shapes:
1180
+ `mcps.json` / `mcp.json` accepts three shapes:
1149
1181
 
1150
1182
  ```json
1151
1183
  [
@@ -1386,7 +1418,7 @@ const text = turnAsText(turn)
1386
1418
 
1387
1419
  **Read the active theme from a component** — `const { brand, model } = useColors()`. Component renders against the current palette and re-renders on theme switch automatically.
1388
1420
 
1389
- **Add a settings row** — append to `SETTINGS_TOGGLES` (boolean) or `SETTINGS_CHOICES` (string/number-valued). Renderers built off the live tables pick it up without code changes.
1421
+ **Add a settings row** — append to `SETTINGS_TOGGLES` (boolean) or `SETTINGS_CHOICES` (string/number-valued) and set `category: 'agent' | 'ui'`. Renderers built off the live tables pick it up without code changes.
1390
1422
 
1391
1423
  **Add a completion provider** — implement `CompletionProvider<TItem>`, pass the provider list to `useCompletion(state, providers)`. The popup picks it up automatically. Extend `theme.surfaces.chips[providerId]` for a per-kind pill color; otherwise the provider inherits `chips.default`.
1392
1424
 
package/docs/TUI.md CHANGED
@@ -23,7 +23,7 @@ For embedding, mount `<App config={resolveConfig(...)} />` against your own `cre
23
23
 
24
24
  Env-var overrides: `ZIDANE_STORAGE_DIR`, `ZIDANE_PREFIX`, `ZIDANE_PROJECT_DB`, `ZIDANE_NO_UPDATE` (silences the auto-update check), `ZIDANE_DEBUG` (enables renderer `gatherStats`; dumps fps / frametime to stderr on exit).
25
25
 
26
- Renderer fps is a regular user setting (`Settings → Renderer fps`, `30 / 60 / 120`). The on-disk value seeds the renderer at boot; subsequent flips apply live via `renderer.targetFps` / `renderer.maxFps`. `clampFps` (in `zidane/chat`) guards bounds.
26
+ Renderer fps is a regular user setting (`Settings → Renderer FPS`, `30 / 60 / 120`). The on-disk value seeds the renderer at boot; subsequent flips apply live via `renderer.targetFps` / `renderer.maxFps`. `clampFps` (in `zidane/chat`) guards bounds.
27
27
 
28
28
  ## Composition
29
29
 
@@ -99,7 +99,7 @@ import {
99
99
  | `Modal`, `ModalRoot`, `useModal`, `useModalAwareFocus` | Overlay layer. `Modal` owns its own esc-to-close handler. `useModalAwareFocus(preferred)` returns `false` while a modal is open so background inputs blur. **Single-slot:** `modal.open(node)` replaces the active node; modals do not stack. |
100
100
  | `ModelPickerModal` | Cross-provider searchable model picker. Returns `{ providerKey, modelId }` on commit; cross-provider picks trigger a provider swap + session re-activation in the host. |
101
101
  | `EffortPickerModal` | Reasoning-effort picker. Lists `'off' / 'minimal' / 'low' / 'medium' / 'high'` plus `'adaptive'` when `supportsAdaptive` is true (Anthropic only). Surfaced via `ctrl+l` when `modelSupportsReasoning(descriptor, model)`. |
102
- | `SettingsModal` | Tabbed: **General** (toggles + choices + auth/keybindings actions), **Skills**, **MCP servers**. One shared search input filters the active tab; `←/→` cycle tabs (preventDefault keeps the input cursor put), `↑/↓` navigate, `↵` toggle/cycle/pick. MCP tab adds `ctrl+L` login, `ctrl+O` logout, and `esc` cancel-authorizing (Modal's esc-close still fires alongside). Rows sourced from `SETTINGS_TOGGLES` / `SETTINGS_CHOICES` in `zidane/chat`; Skills + MCPs from discovered catalogs passed by the host. Auth/keybindings rows render only when their callbacks are wired. |
102
+ | `SettingsModal` | Tabbed: **Agent** (behaviour, persistence), **UI** (display, theming, animations), **Keybindings** (read-only catalog · `↵` opens `keybindings.json`), **Authentication** (current provider + detected providers · `↵` pops the AuthScreen), **Skills**, **MCP servers**. Category tab order is data-driven by `SETTINGS_CATEGORIES` from `zidane/chat`. Keybindings + Authentication tabs only appear when the host wires the `keybindings` / `authentication` data props; otherwise the legacy "open keybindings file" / "re-authenticate" rows render in the UI / Agent tabs as a fallback. One shared search input filters the active tab; `←/→` cycle tabs (preventDefault keeps the input cursor put), `↑/↓` navigate, `↵` toggle/cycle/pick/edit. MCP tab adds `ctrl+L` login, `ctrl+O` logout, and `esc` cancel-authorizing (Modal's esc-close still fires alongside). Sized at `maxWidth: 160, maxHeight: 50` wider than the legacy modal so the Keybindings catalog + Authentication status block sit comfortably. |
103
103
  | `AgentPickerModal` | Multi-agent profile picker. Hidden when only one profile is registered. |
104
104
  | `SkillsSettingsModal`, `McpsSettingsModal` | Standalone surfaces re-exported for embedders. The main `SettingsModal` integrates the same lists as tabs — prefer that for the in-app flow. `McpsSettingsModal` uses single-letter shortcuts (`l` / `o`); the integrated tab uses `ctrl+L` / `ctrl+O`. |
105
105
  | `ToggleListModal` | Generic checkbox-list modal for `settings.enabledX` allowlists. Powers both the Skills + MCP server pickers; reuse with `keyOf` + `settingKey` + `renderDetail` to add a third toggle surface. |
@@ -364,7 +364,7 @@ Because top-level runs share `session.metadata.todos.session`, a list written in
364
364
 
365
365
  ## Settings rows
366
366
 
367
- The Settings modal is tabbed. The **General** tab renders three row kinds from the chat-level tables; **Skills** and **MCP servers** render the discovered catalogs as enable/disable checklists.
367
+ The Settings modal is tabbed. The **Agent** and **UI** tabs each render three row kinds (toggle / choice / action) sourced from the chat-level tables, filtered by their `category` field. The **Keybindings** tab embeds the action catalog from `chat/keybindings.ts` (shared with the standalone `KeybindingsModal` via `groupBindings` + `KEYBINDING_KEY_COL_WIDTH`); `↵` opens the JSON file. The **Authentication** tab shows the active provider + a list of detected ones (from `detectAuth`); `↵` pops the full-screen `AuthScreen` (the multi-step wizard doesn't embed cleanly inside a modal). **Skills** and **MCP servers** render the discovered catalogs as enable/disable checklists.
368
368
 
369
369
  | Kind | Source | Activation |
370
370
  |---|---|---|
@@ -467,7 +467,7 @@ The `'compact-summary'` `StreamEvent` (carrying `compact: { replacedCount, model
467
467
 
468
468
  ## MCP servers + OAuth login
469
469
 
470
- Discovered MCP servers (from `.{prefix}/mcps.json` / `.agents/mcps.json`) live as `DiscoveredMcp[]` in `App`'s state. Non-fatal parse errors surface as `DiscoveryError[]` in a warn-colored preamble on the Settings → MCP tab.
470
+ Discovered MCP servers (from `mcps.json` AND `mcp.json` under `.{prefix}/` or `.agents/` in both project + user dirs) live as `DiscoveredMcp[]` in `App`'s state. The two filenames merge per-name, with `mcps.json` winning collisions. Non-fatal parse errors surface as `DiscoveryError[]` in a warn-colored preamble on the Settings → MCP tab.
471
471
 
472
472
  Each row carries an OAuth status badge driven by the `mcp-auth-state` reducer:
473
473
 
@@ -609,7 +609,7 @@ src/tui/
609
609
  modal.tsx ModalRoot + Modal + useModalAwareFocus
610
610
  model-picker.tsx Cross-provider searchable model list modal
611
611
  effort-picker.tsx Reasoning-effort modal
612
- settings-modal.tsx Tabbed settings panel (General / Skills / MCPs)
612
+ settings-modal.tsx Tabbed settings panel (Agent / UI / Keybindings / Authentication / Skills / MCPs)
613
613
  agent-picker.tsx Multi-agent profile modal (accentColor re-exported from zidane/chat)
614
614
  skills-settings.tsx Skills list + toggle modal (standalone for embedders)
615
615
  mcps-settings.tsx MCP servers list + toggle modal (standalone for embedders)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zidane",
3
- "version": "5.6.3",
3
+ "version": "5.6.7",
4
4
  "description": "an agent that goes straight to the goal",
5
5
  "type": "module",
6
6
  "private": false,