@knightcodeai/cli-win32-x64 0.6.0 → 0.6.2

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/bin/CHANGELOG.md CHANGED
@@ -1,5 +1,99 @@
1
1
  # @knightcodeai/cli
2
2
 
3
+ ## 0.6.2
4
+
5
+ ### Added
6
+
7
+ - Added the Environment Variables reference to the documentation navigation, which previously only reached that page through inline links.
8
+
9
+ - Added `ctx.modelRegistry.stream()` and `streamSimple()` so extensions can make model calls through configured providers with resolved authentication, including providers registered by extensions.
10
+
11
+ - Added Ctrl+D as a reliable alternative to Ctrl+S for saving the default model and thinking level. Many terminals (including Windows Terminal) swallow Ctrl+S as XON/XOFF flow control, so the keystroke never reached the app and the default was never saved. Ctrl+S still works where the terminal delivers it.
12
+
13
+ - Added `compaction.modelOverrides`, per-model `reserveTokens` and `keepRecentTokens` budgets keyed by exact `"provider/modelId"`, so a million-token model can hold a large response reserve without inflating it for every other model. Each field falls back independently to the ordinary setting and then the built-in default, and the resolved values drive manual compaction, threshold checks, overflow recovery, and the `session_before_compact` payload.
14
+
15
+ ### Changed
16
+
17
+ - Changed the DeepSeek catalog to advertise `deepseek-flash` for DeepSeek V4.1 Flash, which accepts images and reasoning levels, in place of the retired `deepseek-v4-flash` and `deepseek-v4-flash-vision-exp` aliases, and refreshed DeepSeek input, output, and cache-read pricing.
18
+
19
+ - Changed OpenRouter requests to send the `x-session-id` affinity header by default on both Chat Completions and Anthropic-compatible models, so cached prompts keep hitting the same upstream replica; setting `sendSessionAffinityHeaders: false` or disabling prompt caching still opts out.
20
+
21
+ - Changed the compaction, branch summarization, and retry spinners to render in the editor border alongside the working indicator; custom editors opt in for all four with the same `embedWorkingStatus` flag.
22
+
23
+ - Changed the runtime dependencies to current releases, including the Anthropic, Bedrock and Google GenAI SDKs, the proxy agents, TypeBox, undici, chalk, marked, ignore, minimatch, semver, esbuild and grok-mermaid. Google's new `TOO_MANY_TOOL_CALLS` finish reason now maps to an error stop reason.
24
+
25
+ ### Removed
26
+
27
+ - Removed GPT-5.4 and GPT-5.4 mini from the OpenAI Codex catalog after ChatGPT accounts lost access to them; selecting either now fails at model resolution instead of at the first request.
28
+
29
+ ### Fixed
30
+
31
+ - Fixed agent-level retry backoff doubling without a ceiling, which left the agent asleep for hours after a long provider outage. Assistant and summarization retries now cap each delay at the new `retry.maxAgentDelayMs` setting, defaulting to 60 seconds.
32
+
33
+ - Fixed OpenAI Codex requests omitting the reasoning effort when thinking is off, so models that need an explicit Off level fell back to the provider default; the model's mapped Off effort is now sent, and models that map Off to `null` still send nothing.
34
+
35
+ - Fixed GitHub Copilot GPT models other than GPT-5 being routed to the completions endpoint, which Copilot does not serve them from.
36
+
37
+ - Fixed the event stream draining its buffered events with `Array.shift()`, which made delivery quadratic on long streams; both the event queue and the waiting-consumer queue now use an amortized O(1) FIFO.
38
+
39
+ - Fixed Fireworks Messages models losing their thinking blocks on replay and collapsing native reasoning effort to a budget-based fallback; the catalog now takes effort levels from provider metadata, allows unsigned thinking, and stops advertising GLM 5.2 and Kimi K3 aliases that map onto the same level.
40
+
41
+ - Fixed Mistral-hosted GLM-5.2 reasoning requests sending `prompt_mode`, which that model ignores, so thinking never turned on; they now send `reasoning_effort`.
42
+
43
+ - Fixed Mistral Medium reasoning requests sending the unsupported `prompt_mode` instead of `reasoning_effort` for reasoning-capable `mistral-medium-*` model IDs such as `mistral-medium-latest`.
44
+
45
+ - Fixed OpenCode and OpenCode Go requests dropping the `x-opencode-session` routing header; every API adapter now maps `sessionId` onto it while leaving an explicit caller override alone.
46
+
47
+ - Fixed extension tools registered without an object parameter schema being accepted, which broke provider request serialization later; registration now rejects them with an error naming the tool and the extension.
48
+
49
+ - Fixed steering and follow-up messages bypassing extension `input` handlers, so extensions could neither transform nor intercept a message queued while the agent was already streaming; both paths now run the handlers and carry their real input source.
50
+
51
+ - Fixed session tree navigation starting while a compaction or another navigation was still running; it now rejects instead of moving the active leaf.
52
+
53
+ - Fixed a rejected `/tree` navigation replacing the running operation's escape handler and status spinner; the compaction or summarization it collided with now keeps its own UI.
54
+
55
+ - Fixed the compiled Windows executable inheriting Bun's own PE resources, so `knightcode.exe` shipped with no icon and a `FileDescription` of "Bun" — the string Windows shows as the process name in Task Manager and the taskbar. The win32 build now embeds KnightCode's own title, publisher, copyright, version, and icon.
56
+
57
+ - Fixed fullscreen mode reserving a blank row for a custom footer that renders nothing.
58
+
59
+ ## 0.6.1
60
+
61
+ ### Added
62
+
63
+ - Added GPT-6 Astra support across tool search, additional tools, long-context pricing, xhigh and max thinking levels, and its explicit thinking-level map.
64
+
65
+ - Added five-times-faster mouse wheel scrolling while holding Alt in fullscreen mode.
66
+
67
+ ### Changed
68
+
69
+ - Changed the generated image model catalog to the current OpenRouter listing.
70
+
71
+ - Changed the built-in read, write, edit, and bash tools to request strict JSON-schema sampling by default instead of only under `KNIGHTCODE_EXPERIMENTAL`.
72
+
73
+ - Changed fullscreen scrollbars to render muted thin tracks with contrasting proportional two-cell-minimum thumbs, reserve an unstyled column in `always` mode, reveal hidden `auto` tracks on pointer entry, expand the same-colored thumb on hover, and support track-click jumping in addition to thumb dragging, with optional `scrollbarTrack` and `scrollbarThumb` theme colors falling back to muted and text.
74
+
75
+ - Changed fullscreen transcript search to cache unchanged results, index ASCII runs, and highlight only visible matches, so latency no longer grows with transcript size.
76
+
77
+ - Changed clipboard handling to use small built-in macOS, Windows, and X11 native helpers instead of an external dependency, running native reads on worker threads and making the command-line fallbacks (`pbcopy`, `clip.exe`, `wl-copy`, `xclip`) asynchronous. Incremental X11 transfers, legacy text encodings, and native image formats are preserved.
78
+
79
+ ### Removed
80
+
81
+ - Removed Grok Build 0.1 from the built-in xAI model catalog.
82
+
83
+ ### Fixed
84
+
85
+ - Fixed processes killed by a signal reporting success; they now map to a 128 + signal exit code.
86
+
87
+ - Fixed compiled binaries shipping without the TUI's native helpers, which left clipboard reads on the command-line fallbacks and dropped Shift+Tab on Windows. Each target's prebuilds are now copied next to the executable.
88
+
89
+ - Fixed `fd` failing to start on musl-based Linux distributions by downloading the statically linked musl builds of both `fd` and `ripgrep`.
90
+
91
+ - Fixed post-login model selection for Radius, whose per-account catalog is empty until the first authenticated refresh; selection now waits for that refresh, defaults to `balanced`, and falls back to catalog order.
92
+
93
+ - Fixed the model, scoped-model, and thinking selectors hardcoding Ctrl+S to save; the shortcut is now the `app.models.save` and `app.thinking.save` keybindings and the on-screen hint follows a rebind.
94
+
95
+ - Fixed mouse hover changing selection and recentering autocomplete and settings lists, causing clicks to target a different item.
96
+
3
97
  ## 0.6.0
4
98
 
5
99
  ### Added
@@ -288,7 +288,7 @@ knightcode.on("session_before_compact", async (event, ctx) => {
288
288
  // preparation.fileOps - extracted file operations
289
289
  // preparation.tokensBefore - context tokens before compaction
290
290
  // preparation.firstKeptEntryId - where kept messages start
291
- // preparation.settings - compaction settings
291
+ // preparation.settings - effective settings after applying model overrides
292
292
 
293
293
  // branchEntries - all entries on current branch (for custom state)
294
294
  // reason - "manual" (/compact), "threshold", or "overflow"
@@ -416,3 +416,29 @@ Configure compaction in `~/.knightcode/agent/settings.json` or `<project-dir>/.k
416
416
  | `keepRecentTokens` | `20000` | Recent tokens to keep (not summarized) |
417
417
 
418
418
  Disable auto-compaction with `"enabled": false`. You can still compact manually with `/compact`.
419
+
420
+ ### Per-model overrides
421
+
422
+ Use `compaction.modelOverrides` to tune token budgets for different models:
423
+
424
+ ```json
425
+ {
426
+ "compaction": {
427
+ "reserveTokens": 16384,
428
+ "keepRecentTokens": 20000,
429
+ "modelOverrides": {
430
+ "some-provider/big-model": {
431
+ "reserveTokens": 400000
432
+ }
433
+ }
434
+ }
435
+ }
436
+ ```
437
+
438
+ For a model with a 1M context window, this override triggers compaction above 600K tokens and keeps the ordinary 20000 recent tokens. Other models retain the ordinary 16384-token reserve. `reserveTokens` also influences summarization output limits, capped by the model's maximum output tokens; it is not solely a trigger threshold.
439
+
440
+ Keys are exact, case-sensitive `provider/modelId` values, including any slashes within the model ID. Each `reserveTokens` and `keepRecentTokens` value falls back independently from the model override to the ordinary setting to the built-in default. Values must be non-negative safe integers. Invalid values in the matching model override produce an error when read; only omitted fields fall back to the ordinary setting. Model override entries must be objects. Invalid ordinary token settings produce an error when read, even if the active model has a valid override. Only omitted ordinary values use built-in defaults. `enabled` remains global, not model-specific.
441
+
442
+ These resolved values are used for manual compaction, all automatic threshold checks, overflow recovery, and extension-visible `preparation.settings`. Model switches affect subsequent checks and compactions without changing ordinary settings. Compaction already in progress uses the model and settings captured for that operation. Branch summarization settings are unaffected.
443
+
444
+ Overrides work in both global and project settings. The files merge recursively before lookup, so a global model-specific value beats a project-wide fallback; a project must override that model entry to change it. See [settings.md](settings.md#per-model-compaction-overrides) for details.
@@ -764,6 +764,7 @@ interface ProviderModelConfig {
764
764
  supportsEagerToolInputStreaming?: boolean;
765
765
  supportsLongCacheRetention?: boolean;
766
766
  sendSessionAffinityHeaders?: boolean;
767
+ sessionAffinityFormat?: "openrouter";
767
768
  supportsCacheControlOnTools?: boolean;
768
769
  forceAdaptiveThinking?: boolean;
769
770
  allowEmptySignature?: boolean;
@@ -81,6 +81,10 @@
81
81
  {
82
82
  "title": "Reference",
83
83
  "items": [
84
+ {
85
+ "title": "Environment Variables",
86
+ "path": "environment-variables.md"
87
+ },
84
88
  {
85
89
  "title": "Session Format",
86
90
  "path": "session-format.md"
@@ -1016,6 +1016,12 @@ Access to models, providers, and resolved authentication. `ctx.modelRegistry.get
1016
1016
 
1017
1017
  `ctx.scopedModels` is the read-only list of models scoped to the current session — the same set the `/scoped-models` command shows. It is resolved at session start from the `--models` CLI flag and the `enabledModels` setting (matched against the available catalogue with minimatch on `provider/modelId` or a bare `modelId`). It is empty when no scoping is configured, meaning every available model is usable. Each entry is `{ model, thinkingLevel? }`, where `thinkingLevel` is set only when a pattern pinned it (e.g. `anthropic/*:high`). Use it to populate a model picker that mirrors the built-in one instead of enumerating the whole catalogue via `ctx.modelRegistry.getAvailable()`.
1018
1018
 
1019
+ #### Streaming model calls
1020
+
1021
+ Use `ctx.modelRegistry.streamSimple(model, context, options)` for provider-neutral options such as `reasoning`, or `stream()` for API-specific options. Both use configured providers and resolve authentication, including for providers registered with `knightcode.registerProvider()`. Use these instead of `@knightcode/ai/compat` streaming functions, which cannot see extension provider registrations.
1022
+
1023
+ Both return an `AssistantMessageEventStream`. Iterate it for response events and await `.result()` for the final message. Setup failures produce error events and error results.
1024
+
1019
1025
  ### ctx.signal
1020
1026
 
1021
1027
  The current agent abort signal, or `undefined` when no agent turn is active.
@@ -1197,7 +1203,7 @@ Options:
1197
1203
 
1198
1204
  ### ctx.navigateTree(targetId, options?)
1199
1205
 
1200
- Navigate to a different point in the session tree:
1206
+ Navigate to a different point in the session tree. Rejects while an agent response, manual or automatic compaction, or another tree navigation is active, even with `summarize: false`. These conflicts leave the active branch unchanged and reject the promise rather than returning `{ cancelled: true }`. Wait for the active operation to finish (for example, with `await ctx.waitForIdle()` in a command handler) and retry:
1201
1207
 
1202
1208
  ```typescript
1203
1209
  const result = await ctx.navigateTree("entry-id-456", {
package/bin/docs/index.md CHANGED
@@ -15,7 +15,7 @@ npm install -g --ignore-scripts @knightcodeai/cli
15
15
  On Linux or macOS, you can also use the installer:
16
16
 
17
17
  ```bash
18
- curl -fsSL https://knightcode.raghavseth.in/install.sh | sh
18
+ curl -fsSL https://knightcode.dev/install.sh | sh
19
19
  ```
20
20
 
21
21
  To uninstall knightcode itself, use npm for curl and npm installs:
@@ -151,7 +151,9 @@ This routing remains configurable through the ordinary action bindings. For exam
151
151
  | `app.model.select` | `ctrl+l` | Open model selector |
152
152
  | `app.model.cycleForward` | `ctrl+p` | Cycle to next model |
153
153
  | `app.model.cycleBackward` | `shift+ctrl+p` (`alt+p` on Windows and WSL) | Cycle to previous model |
154
+ | `app.models.save` | `ctrl+s`, `ctrl+d` | Save the selected default model or scoped model configuration to settings (`ctrl+d` because many terminals swallow `ctrl+s`) |
154
155
  | `app.thinking.cycle` | `shift+tab` | Cycle thinking level |
156
+ | `app.thinking.save` | `ctrl+s`, `ctrl+d` | Save current thinking level to settings (`ctrl+d` because many terminals swallow `ctrl+s`) |
155
157
  | `app.thinking.toggle` | `ctrl+t` | Collapse or expand thinking blocks |
156
158
 
157
159
  ### Display and Message Queue
@@ -185,7 +187,6 @@ Used inside the scoped models selector (opened via `/scoped-models`).
185
187
 
186
188
  | Keybinding id | Default | Description |
187
189
  |--------|---------|-------------|
188
- | `app.models.save` | `ctrl+s` | Save current model selection to settings |
189
190
  | `app.models.enableAll` | `ctrl+a` | Enable all models (or all matching the current search) |
190
191
  | `app.models.clearAll` | `ctrl+x` | Clear all models (or all matching the current search) |
191
192
  | `app.models.toggleProvider` | `ctrl+p` | Toggle all models for the current provider |
@@ -429,7 +429,8 @@ Built-in Anthropic models enable `supportsStrictTools` in their model metadata.
429
429
  |-------|-------------|
430
430
  | `supportsEagerToolInputStreaming` | Whether the provider accepts per-tool `eager_input_streaming`. Default: `true`. Set to `false` to omit that field and use the legacy fine-grained tool streaming beta header on tool-enabled requests. |
431
431
  | `supportsLongCacheRetention` | Whether the provider accepts Anthropic long cache retention (`cache_control.ttl: "1h"`) when cache retention is `long`. Default: `true`. |
432
- | `sendSessionAffinityHeaders` | Whether to send `x-session-affinity` from the session id when caching is enabled. Default: auto-detected for known providers. |
432
+ | `sendSessionAffinityHeaders` | Whether to send a session-affinity header from the session id when caching is enabled. Default: `true` for OpenRouter endpoints, auto-detected for other known providers. |
433
+ | `sessionAffinityFormat` | Session-affinity header name: `openrouter` sends `x-session-id`. When unset, `x-session-affinity` is sent. Default: `openrouter` for OpenRouter endpoints. |
433
434
  | `supportsCacheControlOnTools` | Whether the provider accepts Anthropic-style `cache_control` markers on tool definitions. Default: `true`. |
434
435
  | `forceAdaptiveThinking` | Whether to send adaptive thinking (`thinking.type: "adaptive"` plus `output_config.effort`) for this model. Built-in adaptive models set this automatically. Default: `false`. |
435
436
  | `supportsMidConvoEffort` | Whether the exact Claude model transport supports per-turn effort system messages and thinking binding controls. KnightCode persists native effort levels and always sends `drop_block` when enabled. Default: `false`. |
@@ -477,12 +478,12 @@ For providers with partial OpenAI compatibility, use the `compat` field.
477
478
  | `thinkingTokenBudgetField` | Top-level request field used to cap reasoning tokens from `thinkingBudgets`, clamped so at least 1024 tokens remain for the answer. `"thinking_token_budget"` (vLLM), `"thinking_budget"` (Qwen/DashScope/SGLang), `"thinking_budget_tokens"` (llama.cpp). Off by default; not set on the generated catalog. |
478
479
  | `supportsThinkingTokenBudget` | Alias for `thinkingTokenBudgetField: "thinking_token_budget"` (vLLM). Prefer `thinkingTokenBudgetField`. Default: `false`. |
479
480
  | `cacheControlFormat` | Use Anthropic-style `cache_control` markers on the system prompt, last tool definition, and last user, assistant, or tool-result text content. Currently only `anthropic` is supported. |
480
- | `sendSessionAffinityHeaders` | For `openai-completions`, send session-affinity headers from the session id when caching is enabled. Default: `false`. |
481
+ | `sendSessionAffinityHeaders` | For `openai-completions`, send session-affinity headers from the session id when caching is enabled. Default: `true` for OpenRouter endpoints, `false` otherwise. |
481
482
  | `sessionAffinityFormat` | For `openai-completions` and `openai-responses`, the session-affinity header format: `openai` sends `session_id`/`x-client-request-id` (completions also `x-session-affinity`), `openai-nosession` omits the underscore-containing `session_id` header, `openrouter` sends `x-session-id`. Does not affect the `prompt_cache_key` body param. Default: auto-detected. |
482
483
  | `supportsStrictMode` | Whether the provider accepts strict JSON-schema function tool definitions. Defaults depend on the API; built-in OpenAI models carry explicit capability metadata. |
483
484
  | `supportsOpenAIGrammarTools` | Whether OpenAI-compatible APIs emit custom Lark/regex grammar tools. When `false`, grammar-constrained tools fall back to normal function tools. Default: `false`; the built-in model catalog enables it for GPT-5+ models on OpenAI, OpenAI Codex, Azure OpenAI, GitHub Copilot, opencode, and Cloudflare AI Gateway. |
484
485
  | `deferredToolsMode` | Use provider-specific deferred tool serialization. Currently only `"kimi"` is supported for Kimi's OpenAI-compatible Chat Completions format. |
485
- | `supportsLongCacheRetention` | Whether the provider accepts long cache retention when cache retention is `long`: `prompt_cache_retention: "24h"` for OpenAI prompt caching, or `cache_control.ttl: "1h"` when `cacheControlFormat` is `anthropic`. Default: `true`. |
486
+ | `supportsLongCacheRetention` | Whether the provider accepts long cache retention when cache retention is `long`: `prompt_cache_options.ttl: "30m"` for GPT-5.6+ Responses models, `prompt_cache_retention: "24h"` for earlier OpenAI models, or `cache_control.ttl: "1h"` when `cacheControlFormat` is `anthropic`. Default: `true`. |
486
487
  | `openRouterRouting` | OpenRouter provider routing preferences. This object is sent as-is in the `provider` field of the [OpenRouter API request](https://openrouter.ai/docs/guides/routing/provider-selection). |
487
488
  | `vercelGatewayRouting` | Vercel AI Gateway routing config for provider selection (`only`, `order`) |
488
489
 
@@ -134,7 +134,7 @@ Paths are relative to the package root. Arrays support glob patterns and `!exclu
134
134
 
135
135
  ### Gallery Metadata
136
136
 
137
- The [package gallery](https://knightcode.raghavseth.in/packages) displays packages tagged with `knightcode-package`. Add `video` or `image` fields to show a preview:
137
+ The [package gallery](https://knightcode.dev/packages) displays packages tagged with `knightcode-package`. Add `video` or `image` fields to show a preview:
138
138
 
139
139
  ```json
140
140
  {
@@ -129,7 +129,7 @@ The command output is sent to the model. Use `!!command` to run a command withou
129
129
 
130
130
  ### Switch models
131
131
 
132
- Use `/model` or Ctrl+L to choose a model for the current session. Press Ctrl+S in the model picker to save the highlighted model as the startup default. Use `/thinking` to choose a thinking level for the current session, or Ctrl+S in that picker to save the startup default thinking level. Use Shift+Tab to cycle thinking level. Use Ctrl+P / Shift+Ctrl+P to cycle through scoped models.
132
+ Use `/model` or Ctrl+L to choose a model for the current session. Press Ctrl+S (or Ctrl+D, if your terminal swallows Ctrl+S) in the model picker to save the highlighted model as the startup default. Use `/thinking` to choose a thinking level for the current session, or Ctrl+S / Ctrl+D in that picker to save the startup default thinking level. Use Shift+Tab to cycle thinking level. Use Ctrl+P / Shift+Ctrl+P to cycle through scoped models.
133
133
 
134
134
  ### Continue later
135
135
 
package/bin/docs/sdk.md CHANGED
@@ -111,6 +111,8 @@ interface AgentSession {
111
111
  }
112
112
  ```
113
113
 
114
+ `session.navigateTree()` rejects while an agent response, manual or automatic compaction, or another tree navigation is active, even with `summarize: false`. It does not queue navigation or return `{ cancelled: true }` for these conflicts. Wait for the active operation to finish (for example, with `await session.waitForIdle()`) and retry. Rejection leaves the active branch unchanged.
115
+
114
116
  Session replacement APIs such as new-session, resume, fork, and import live on `AgentSessionRuntime`, not on `AgentSession`.
115
117
 
116
118
  ### createAgentSessionRuntime() and AgentSessionRuntime
@@ -5,10 +5,10 @@ Sessions are stored as JSONL (JSON Lines) files. Each line is a JSON object with
5
5
  ## File Location
6
6
 
7
7
  ```
8
- ~/.knightcode/agent/sessions/--<path>--/<timestamp>_<uuid>.jsonl
8
+ ~/.knightcode/agent/sessions/--<path>--/<timestamp>_<session-id>.jsonl
9
9
  ```
10
10
 
11
- Where `<path>` is the working directory with `/` replaced by `-`.
11
+ By default, `<session-id>` is a UUID. Callers can supply a custom ID through the SDK or `--session-id`. For `<path>`, KnightCode removes the leading path separator and replaces `/`, `\\`, and `:` with `-`.
12
12
 
13
13
  ## Deleting Sessions
14
14
 
@@ -29,8 +29,8 @@ Existing sessions are automatically migrated to the current version (v3) when lo
29
29
  ## Source Files
30
30
 
31
31
  Source on GitHub ([knightcode](https://github.com/KnightCodeAI/knightcode)):
32
- - [`packages/coding-agent/src/core/session-manager.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/session-manager.ts) - Session entry types and SessionManager
33
- - [`packages/coding-agent/src/core/messages.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/coding-agent/src/core/messages.ts) - Extended message types (BashExecutionMessage, CustomMessage, etc.)
32
+ - [`packages/cli/src/core/session-manager.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/cli/src/core/session-manager.ts) - Session entry types and SessionManager
33
+ - [`packages/cli/src/core/messages.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/cli/src/core/messages.ts) - Extended message types (BashExecutionMessage, CustomMessage, etc.)
34
34
  - [`packages/ai/src/types.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/ai/src/types.ts) - Base message types (UserMessage, AssistantMessage, ToolResultMessage)
35
35
  - [`packages/agent/src/types.ts`](https://github.com/KnightCodeAI/knightcode/blob/main/packages/agent/src/types.ts) - AgentMessage union type
36
36
 
@@ -48,6 +48,7 @@ Messages contain arrays of typed content blocks:
48
48
  interface TextContent {
49
49
  type: "text";
50
50
  text: string;
51
+ textSignature?: string;
51
52
  }
52
53
 
53
54
  interface ImageContent {
@@ -59,6 +60,8 @@ interface ImageContent {
59
60
  interface ThinkingContent {
60
61
  type: "thinking";
61
62
  thinking: string;
63
+ thinkingSignature?: string;
64
+ redacted?: boolean;
62
65
  }
63
66
 
64
67
  interface ToolCall {
@@ -66,6 +69,8 @@ interface ToolCall {
66
69
  id: string;
67
70
  name: string;
68
71
  arguments: Record<string, any>;
72
+ thoughtSignature?: string;
73
+ namespace?: string;
69
74
  }
70
75
  ```
71
76
 
@@ -84,9 +89,16 @@ interface AssistantMessage {
84
89
  api: string;
85
90
  provider: string;
86
91
  model: string;
92
+ responseModel?: string;
93
+ responseId?: string;
94
+ providerThinkingLevel?: string;
95
+ diagnostics?: AssistantMessageDiagnostic[];
87
96
  usage: Usage;
88
- stopReason: "stop" | "length" | "toolUse" | "error" | "aborted";
97
+ stopReason: "pending" | "stop" | "length" | "toolUse" | "error" | "aborted" | "deferred";
98
+ deferred?: DeferredHandle;
89
99
  errorMessage?: string;
100
+ rawStopReason?: string;
101
+ endTurn?: boolean;
90
102
  timestamp: number;
91
103
  }
92
104
 
@@ -97,6 +109,7 @@ interface ToolResultMessage {
97
109
  content: (TextContent | ImageContent)[];
98
110
  details?: any; // Tool-specific metadata
99
111
  usage?: Usage; // Nested LLM work performed by the tool
112
+ addedToolNames?: string[];
100
113
  isError: boolean;
101
114
  timestamp: number;
102
115
  }
@@ -106,6 +119,8 @@ interface Usage {
106
119
  output: number;
107
120
  cacheRead: number;
108
121
  cacheWrite: number;
122
+ cacheWrite1h?: number;
123
+ reasoning?: number;
109
124
  totalTokens: number;
110
125
  cost: {
111
126
  input: number;
@@ -117,7 +132,7 @@ interface Usage {
117
132
  }
118
133
  ```
119
134
 
120
- The exported @knightcode/ai `StopReason` type also includes `"pending"`, but that value is reserved for partial messages in streaming events. Terminal `done`/`error` messages replace it with a completion reason before knightcode persists the assistant message, so `"pending"` should never appear in session JSONL.
135
+ `"pending"` is reserved for partial messages in streaming events. Terminal events replace it with a completion reason before knightcode persists the assistant message, so `"pending"` should never appear in session JSONL. `"deferred"` is a terminal reason for a provider response that will complete later; its `deferred` handle contains the provider data needed to retrieve that response.
121
136
 
122
137
  ### Extended Message Types (from @knightcodeai/cli)
123
138
 
@@ -146,7 +161,7 @@ interface CustomMessage {
146
161
  interface BranchSummaryMessage {
147
162
  role: "branchSummary";
148
163
  summary: string;
149
- fromId: string; // Entry we branched from
164
+ fromId: string | null; // Previous leaf whose abandoned path was summarized
150
165
  timestamp: number;
151
166
  }
152
167
 
@@ -178,8 +193,8 @@ All entries (except `SessionHeader`) extend `SessionEntryBase`:
178
193
  ```typescript
179
194
  interface SessionEntryBase {
180
195
  type: string;
181
- id: string; // 8-char hex ID
182
- parentId: string | null; // Parent entry ID (null for first entry)
196
+ id: string; // Usually an 8-char hex ID; may fall back to a full UUID
197
+ parentId: string | null; // Parent entry ID (null for a root entry)
183
198
  timestamp: string; // ISO timestamp
184
199
  }
185
200
  ```
@@ -205,9 +220,9 @@ For sessions with a parent (created via `/fork`, `/clone`, or `newSession({ pare
205
220
  A message in the conversation. The `message` field contains an `AgentMessage`.
206
221
 
207
222
  ```json
208
- {"type":"message","id":"a1b2c3d4","parentId":"prev1234","timestamp":"2024-12-03T14:00:01.000Z","message":{"role":"user","content":"Hello"}}
209
- {"type":"message","id":"b2c3d4e5","parentId":"a1b2c3d4","timestamp":"2024-12-03T14:00:02.000Z","message":{"role":"assistant","content":[{"type":"text","text":"Hi!"}],"provider":"anthropic","model":"claude-sonnet-4-5","usage":{...},"stopReason":"stop"}}
210
- {"type":"message","id":"c3d4e5f6","parentId":"b2c3d4e5","timestamp":"2024-12-03T14:00:03.000Z","message":{"role":"toolResult","toolCallId":"call_123","toolName":"bash","content":[{"type":"text","text":"output"}],"isError":false}}
223
+ {"type":"message","id":"a1b2c3d4","parentId":"prev1234","timestamp":"2024-12-03T14:00:01.000Z","message":{"role":"user","content":"Hello","timestamp":1733234401000}}
224
+ {"type":"message","id":"b2c3d4e5","parentId":"a1b2c3d4","timestamp":"2024-12-03T14:00:02.000Z","message":{"role":"assistant","content":[{"type":"text","text":"Hi!"}],"api":"anthropic-messages","provider":"anthropic","model":"claude-sonnet-4-5","usage":{...},"stopReason":"stop","timestamp":1733234402000}}
225
+ {"type":"message","id":"c3d4e5f6","parentId":"b2c3d4e5","timestamp":"2024-12-03T14:00:03.000Z","message":{"role":"toolResult","toolCallId":"call_123","toolName":"bash","content":[{"type":"text","text":"output"}],"isError":false,"timestamp":1733234403000}}
211
226
  ```
212
227
 
213
228
  ### ModelChangeEntry
@@ -234,18 +249,12 @@ Created when context is compacted. Stores a summary of earlier messages.
234
249
  {"type":"compaction","id":"f6g7h8i9","parentId":"e5f6g7h8","timestamp":"2024-12-03T14:10:00.000Z","summary":"User discussed X, Y, Z...","firstKeptEntryId":"c3d4e5f6","tokensBefore":50000}
235
250
  ```
236
251
 
237
- Newer harness-generated compactions embed the retained post-compaction context directly on the entry, instead of `firstKeptEntryId`:
238
-
239
- ```json
240
- {"type":"compaction","id":"f6g7h8i9","parentId":"e5f6g7h8","timestamp":"2024-12-03T14:10:00.000Z","summary":"User discussed X, Y, Z...","tokensBefore":50000,"retainedTail":[{"role":"user","content":"latest request"},{"role":"assistant","content":[{"type":"text","text":"latest reply"}],"provider":"anthropic","model":"claude-sonnet-4-5","usage":{...},"stopReason":"stop"}]}
241
- ```
252
+ `firstKeptEntryId` is required. It identifies the first entry retained from before the compaction entry. When rebuilding context, KnightCode replaces older summarized entries with the compaction summary and keeps the range beginning at this entry.
242
253
 
243
254
  Optional fields:
244
255
  - `usage`: LLM usage from generating the summary; included in session token and cost totals
245
- - `retainedTail`: Materialized `AgentMessage[]` kept after compaction. This is optional only for backward compatibility with older sessions. Newer harness-generated compactions include it so we can rebuild context from this checkpoint without walking older entries before the compaction entry.
246
256
  - `details`: Implementation-specific data (e.g., `{ readFiles: string[], modifiedFiles: string[] }` for default, or custom data for extensions)
247
257
  - `fromHook`: `true` if generated by an extension, `false`/`undefined` if knightcode-generated (legacy field name)
248
- - `firstKeptEntryId`: for compatibility with old entry format.
249
258
 
250
259
  ### BranchSummaryEntry
251
260
 
@@ -255,6 +264,8 @@ Created when switching branches via `/tree` with an LLM generated summary of the
255
264
  {"type":"branch_summary","id":"g7h8i9j0","parentId":"a1b2c3d4","timestamp":"2024-12-03T14:15:00.000Z","fromId":"f6g7h8i9","summary":"Branch explored approach A..."}
256
265
  ```
257
266
 
267
+ `parentId` is the entry from which the new branch continues. `fromId` is the previous leaf whose abandoned path was summarized.
268
+
258
269
  Optional fields:
259
270
  - `usage`: LLM usage from generating the summary; included in session token and cost totals
260
271
  - `details`: File tracking data (`{ readFiles: string[], modifiedFiles: string[] }`) for default, or custom data for extensions
@@ -305,11 +316,12 @@ The session name is displayed in the session selector (`/resume`) instead of the
305
316
 
306
317
  ## Tree Structure
307
318
 
308
- Entries form a tree:
309
- - First entry has `parentId: null`
310
- - Each subsequent entry points to its parent via `parentId`
319
+ Entries normally form one tree, but navigation APIs can create multiple roots:
320
+ - A root entry has `parentId: null`; the first entry is initially the root
321
+ - Each non-root entry points to its parent via `parentId`
311
322
  - Branching creates new children from an earlier entry
312
323
  - The "leaf" is the current position in the tree
324
+ - Calling `resetLeaf()` or `branchWithSummary(null, ...)` allows a later entry to become another root
313
325
 
314
326
  ```
315
327
  [user msg] ─── [assistant] ─── [user msg] ─── [assistant] ─┬─ [user msg] ← current leaf
@@ -322,11 +334,10 @@ Entries form a tree:
322
334
  `buildContextEntries()` walks from the current leaf to the root, producing the active entry list while honoring compaction:
323
335
 
324
336
  1. Collects all entries on the path
325
- 2. If a `CompactionEntry` is on the path:
337
+ 2. If one or more `CompactionEntry` values are on the path, uses the latest one:
326
338
  - Includes the compaction entry first
327
- - If `retainedTail` is present, it acts as a self-contained checkpoint and entries after the compaction are included
328
- - Otherwise entries from `firstKeptEntryId` to the compaction are included
329
- - Then entries after compaction are included
339
+ - Includes entries from `firstKeptEntryId` up to, but not including, the compaction entry
340
+ - Includes entries after the compaction entry
330
341
  3. Preserves non-message entries in the selected range so interactive mode can render them
331
342
 
332
343
  `buildSessionContext()` builds on that entry list to produce the message list for the LLM:
@@ -334,12 +345,12 @@ Entries form a tree:
334
345
  1. Extracts current model and thinking level settings from the full path
335
346
  2. Converts selected entries to messages:
336
347
  - `message` -> stored `AgentMessage`
337
- - `compaction` -> `compactionSummary` plus `retainedTail` when present
348
+ - `compaction` -> `compactionSummary`
338
349
  - `branch_summary` -> `branchSummary`
339
350
  - `custom_message` -> `CustomMessage`
340
351
  - `custom` -> no context message
341
352
 
342
- This makes newer compactions act like self-contained checkpoints. `retainedTail` is optional only so older sessions that only store `firstKeptEntryId` continue to load correctly.
353
+ The compaction summary replaces entries before `firstKeptEntryId`. The retained entries and all entries after the compaction remain available to the LLM.
343
354
 
344
355
  ## Parsing Example
345
356
 
@@ -388,18 +399,19 @@ for (const line of lines) {
388
399
  Key methods for working with sessions programmatically.
389
400
 
390
401
  ### Static Creation Methods
391
- - `SessionManager.create(cwd, sessionDir?)` - New session
392
- - `SessionManager.open(path, sessionDir?)` - Open existing session file
402
+ - `SessionManager.create(cwd, sessionDir?, options?)` - New session; `options` can set `id` and `parentSession`
403
+ - `SessionManager.open(path, sessionDir?, cwdOverride?)` - Open existing session file
393
404
  - `SessionManager.continueRecent(cwd, sessionDir?)` - Continue most recent or create new
394
- - `SessionManager.inMemory(cwd?)` - No file persistence
395
- - `SessionManager.forkFrom(sourcePath, targetCwd, sessionDir?)` - Fork session from another project
405
+ - `SessionManager.inMemory(cwd?, options?, entries?)` - No file persistence, optionally initialized from entries
406
+ - `SessionManager.forkFrom(sourcePath, targetCwd, sessionDir?, options?)` - Fork session from another project
396
407
 
397
408
  ### Static Listing Methods
398
409
  - `SessionManager.list(cwd, sessionDir?, onProgress?)` - List sessions for a directory
399
410
  - `SessionManager.listAll(onProgress?)` - List all sessions across all projects
411
+ - `SessionManager.listAll(sessionDir?, onProgress?)` - List sessions from a custom session root
400
412
 
401
413
  ### Instance Methods - Session Management
402
- - `newSession(options?)` - Start a new session (options: `{ parentSession?: string }`)
414
+ - `newSession(options?)` - Start a new session (options: `{ id?: string, parentSession?: string }`)
403
415
  - `setSessionFile(path)` - Switch to a different session file
404
416
  - `createBranchedSession(leafId)` - Extract branch to new session file
405
417
 
@@ -407,7 +419,7 @@ Key methods for working with sessions programmatically.
407
419
  - `appendMessage(message)` - Add message
408
420
  - `appendThinkingLevelChange(level)` - Record thinking change
409
421
  - `appendModelChange(provider, modelId)` - Record model change
410
- - `appendCompaction(summary, firstKeptEntryId, tokensBefore, details?, fromHook?)` - Add compaction
422
+ - `appendCompaction(summary, firstKeptEntryId, tokensBefore, details?, fromHook?, usage?)` - Add compaction
411
423
  - `appendCustomEntry(customType, data?)` - Extension state (not in context)
412
424
  - `appendSessionInfo(name)` - Set session display name
413
425
  - `appendCustomMessageEntry(customType, content, display, details?)` - Extension message (in context)
@@ -423,7 +435,7 @@ Key methods for working with sessions programmatically.
423
435
  - `getLabel(id)` - Get label for entry
424
436
  - `branch(entryId)` - Move leaf to earlier entry
425
437
  - `resetLeaf()` - Reset leaf to null (before any entries)
426
- - `branchWithSummary(entryId, summary, details?, fromHook?)` - Branch with context summary
438
+ - `branchWithSummary(entryId, summary, details?, fromHook?, usage?)` - Branch with context summary; `entryId` may be `null` to branch from the root
427
439
 
428
440
  ### Instance Methods - Context & Info
429
441
  - `buildContextEntries()` - Get active branch entries with compaction applied
@@ -70,6 +70,8 @@ Named sessions are easier to find in `/resume` and `knightcode -r`.
70
70
 
71
71
  Sessions are stored as trees. Every entry has an `id` and `parentId`, and the current position is the active leaf. `/tree` lets you jump to any previous point and continue from there without creating a new file.
72
72
 
73
+ Selecting a point while the model is responding cancels that response. Navigation cannot proceed while compaction or another tree navigation is still running; wait for it to finish and retry.
74
+
73
75
  <p align="center"><img src="images/tree-view.png" alt="Tree View" width="600"></p>
74
76
 
75
77
  Example shape:
@@ -66,9 +66,9 @@ Use `/trust` in interactive mode to save a project trust decision for future ses
66
66
  | `outputPad` | number | `1` | Horizontal padding for user messages, assistant messages, and thinking (0 or 1) |
67
67
  | `autocompleteMaxVisible` | number | `5` | Max visible items in autocomplete dropdown (3-20) |
68
68
  | `showHardwareCursor` | boolean | `false` | Show the terminal cursor while TUI positions it for IME support |
69
- | `tuiMode` | string | `"regular"` | Interactive TUI mode: `"regular"` or experimental `"fullscreen"`. Changes from `/settings` apply immediately; `--tui-mode` overrides this setting at startup |
69
+ | `tuiMode` | string | `"regular"` | Interactive TUI mode: `"regular"` or experimental `"fullscreen"`. Fullscreen captures the mouse and owns text selection, so dragging copies to the clipboard; regular leaves selection and copying to the terminal emulator (see [Text selection and copy](terminal-setup.md#text-selection-and-copy)). Changes from `/settings` apply immediately; `--tui-mode` overrides this setting at startup |
70
70
  | `fullscreenExitOutput` | string | `"transcript"` | Fullscreen exit output: `"transcript"` prints the final transcript and resume hint, while `"resume-hint"` restores the previous screen and prints only the resume hint. Has no effect in regular TUI mode |
71
- | `fullscreenScrollbar` | string | `"auto"` | Fullscreen transcript scrollbar: `"auto"` shows it temporarily while scrolling, `"always"` reserves the rightmost column and keeps it visible, and `"hidden"` hides it. Has no effect in regular TUI mode |
71
+ | `fullscreenScrollbar` | string | `"auto"` | Fullscreen transcript scrollbar: `"auto"` shows it temporarily while scrolling or while the pointer is over its rightmost-column track, `"always"` reserves that column and keeps it visible, and `"hidden"` hides it. Has no effect in regular TUI mode |
72
72
  | `fullscreenCopyOnSelect` | boolean | `true` | Automatically copy selected text in fullscreen mode. When disabled, selections stay highlighted and `Ctrl+X` copies the active selection. Has no effect in regular TUI mode |
73
73
 
74
74
  For VS Code, include `--wait` so knightcode resumes after the editor exits:
@@ -81,7 +81,7 @@ For VS Code, include `--wait` so knightcode resumes after the editor exits:
81
81
 
82
82
  ### Telemetry and update checks
83
83
 
84
- `enableInstallTelemetry` controls the anonymous install/update ping to `https://knightcode.raghavseth.in/api/report-install` and KnightCode attribution headers for OpenRouter, NVIDIA NIM, and Cloudflare provider requests. Opting out disables both. It does not disable update checks; KnightCode can still fetch `https://knightcode.raghavseth.in/api/latest-version` to look for the latest version.
84
+ `enableInstallTelemetry` controls the anonymous install/update ping to `https://knightcode.dev/api/report-install` and KnightCode attribution headers for OpenRouter, NVIDIA NIM, and Cloudflare provider requests. Opting out disables both. It does not disable update checks; KnightCode can still fetch `https://knightcode.dev/api/latest-version` to look for the latest version.
85
85
 
86
86
  Set `KNIGHTCODE_SKIP_VERSION_CHECK=1` to disable the KnightCode version update check. Use `--offline` or `KNIGHTCODE_OFFLINE=1` to disable all startup network operations described here, including update checks, package update checks, and install/update telemetry.
87
87
 
@@ -118,6 +118,7 @@ Set `KNIGHTCODE_SKIP_VERSION_CHECK=1` to disable the KnightCode version update c
118
118
  | `compaction.enabled` | boolean | `true` | Enable auto-compaction |
119
119
  | `compaction.reserveTokens` | number | `16384` | Tokens reserved for LLM response |
120
120
  | `compaction.keepRecentTokens` | number | `20000` | Recent tokens to keep (not summarized) |
121
+ | `compaction.modelOverrides` | object | - | Per-model `reserveTokens` and `keepRecentTokens` overrides keyed by exact `"provider/modelId"` |
121
122
 
122
123
  ```json
123
124
  {
@@ -129,6 +130,37 @@ Set `KNIGHTCODE_SKIP_VERSION_CHECK=1` to disable the KnightCode version update c
129
130
  }
130
131
  ```
131
132
 
133
+ #### Per-model compaction overrides
134
+
135
+ ```json
136
+ {
137
+ "compaction": {
138
+ "enabled": true,
139
+ "reserveTokens": 16384,
140
+ "keepRecentTokens": 20000,
141
+ "modelOverrides": {
142
+ "some-provider/big-model": {
143
+ "reserveTokens": 400000
144
+ },
145
+ "local/small-model": {
146
+ "reserveTokens": 2048,
147
+ "keepRecentTokens": 4096
148
+ }
149
+ }
150
+ }
151
+ }
152
+ ```
153
+
154
+ Keys match exact, case-sensitive `provider/modelId` values, not names or glob patterns. Model IDs may contain slashes (for example, `openrouter/anthropic/claude-sonnet-4`).
155
+
156
+ Each token setting resolves independently: matching model override → ordinary `compaction` setting → built-in default. In the example, `some-provider/big-model` keeps the ordinary 20000 recent tokens. Token values must be non-negative safe integers. Invalid values in the matching model override produce an error when read; only omitted fields fall back to the ordinary setting. Model override entries must be objects. Invalid ordinary token settings produce an error when read, even if the active model has a valid override. Only omitted ordinary values use built-in defaults. Zero is accepted, but `reserveTokens: 0` leaves no response margin and also sets the summarization output budget to zero.
157
+
158
+ Global and project settings merge recursively **before** model lookup. A project can override one field for a model without replacing its other fields or other models. A global model-specific value takes precedence over a project-wide fallback; override the same model entry in the project to change it.
159
+
160
+ `enabled` is not model-specific. The active model's token settings apply to manual compaction, automatic threshold checks (including between assistant turns), and overflow recovery. Switching models takes effect on the next check or compaction. Configure overrides in JSON; `/settings` retains the ordinary auto-compaction toggle.
161
+
162
+ See [compaction.md](compaction.md) for trigger and summarization behavior.
163
+
132
164
  ### Branch Summary
133
165
 
134
166
  | Setting | Type | Default | Description |
@@ -143,10 +175,13 @@ Set `KNIGHTCODE_SKIP_VERSION_CHECK=1` to disable the KnightCode version update c
143
175
  | `retry.enabled` | boolean | `true` | Enable automatic agent-level retry on transient errors |
144
176
  | `retry.maxRetries` | number | `3` | Maximum agent-level retry attempts |
145
177
  | `retry.baseDelayMs` | number | `2000` | Base delay for agent-level exponential backoff (2s, 4s, 8s) |
178
+ | `retry.maxAgentDelayMs` | number | `60000` | Max agent-level retry delay (60s) |
146
179
  | `retry.provider.timeoutMs` | number | SDK default | Provider/SDK request timeout in milliseconds |
147
180
  | `retry.provider.maxRetries` | number | `0` | Provider/SDK retry attempts |
148
181
  | `retry.provider.maxRetryDelayMs` | number | `60000` | Max server-requested delay before failing (60s) |
149
182
 
183
+ Agent-level retries use exponential backoff capped by `retry.maxAgentDelayMs`, so long retry runs stay responsive after prolonged outages.
184
+
150
185
  When a provider requests a retry delay longer than `retry.provider.maxRetryDelayMs`, the request fails immediately with an informative error instead of waiting silently. Set it to `0` to disable the limit.
151
186
 
152
187
  Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explicitly needed. Setting it above `0` can make SDK/provider retries handle out-of-usage-limit errors before KnightCode sees them, which may block the agent until the provider quota resets in some circumstances.
@@ -157,6 +192,7 @@ Keep `retry.provider.maxRetries` at `0` unless provider-level retries are explic
157
192
  "enabled": true,
158
193
  "maxRetries": 3,
159
194
  "baseDelayMs": 2000,
195
+ "maxAgentDelayMs": 60000,
160
196
  "provider": {
161
197
  "timeoutMs": 3600000,
162
198
  "maxRetries": 0,
@@ -14,6 +14,14 @@ KnightCode auto-detects OSC 8 hyperlinks, inline image protocols, and truecolor.
14
14
 
15
15
  Settings take precedence over environment variables; unset or `auto` preserves detection. Only force capabilities supported by the complete terminal path, since unsupported escape sequences can corrupt rendering.
16
16
 
17
+ ## Text Selection and Copy
18
+
19
+ Which side owns a mouse drag depends on the [TUI mode](usage.md#other-options).
20
+
21
+ In `fullscreen` mode, knightcode enables mouse reporting and owns text selection itself. Dragging with the primary button selects, and the selection is copied to the clipboard on release. Set `fullscreenCopyOnSelect` to `false` to keep the selection highlighted and copy it with `Ctrl+X` instead. To reach the terminal's own selection while knightcode captures the mouse, hold the terminal's bypass modifier — usually `Shift`, `Option` in iTerm2, and `Shift+Command`/`Shift+Ctrl` in Ghostty.
22
+
23
+ In `regular` mode, knightcode never enables mouse reporting, so a drag is the terminal emulator's own selection and knightcode is not involved in copying it. Use the terminal's copy shortcut — `Ctrl+Shift+C` on most Linux and Windows terminals, `Command+C` on macOS — or enable the terminal's copy-on-select option. Dragging alone does not reach the clipboard in terminals where that option is off by default, which includes Windows Terminal (`copyOnSelect` defaults to `false`) and Apple Terminal, which has no such option. Switch to `fullscreen` if you want drag-to-copy without depending on the terminal.
24
+
17
25
  ## Kitty
18
26
 
19
27
  Works out of the box.
@@ -96,7 +96,6 @@ termux-camera-photo out.jpg # Take photo
96
96
  ## Limitations
97
97
 
98
98
  - **No image clipboard**: Termux clipboard API only supports text
99
- - **No native binaries**: Some optional native dependencies (like the clipboard module) are unavailable on Android ARM64 and are skipped during installation
100
99
  - **Storage access**: To access files in `/storage/emulated/0` (Downloads, etc.), run `termux-setup-storage` once to grant permissions
101
100
 
102
101
  ## Troubleshooting
@@ -88,7 +88,8 @@ vim ~/.knightcode/agent/themes/my-theme.json
88
88
  "text": "",
89
89
  "thinkingText": "secondary",
90
90
  "selectedBg": "#2d2d30",
91
- "scrollbarThumb": "#555566",
91
+ "scrollbarTrack": "secondary",
92
+ "scrollbarThumb": "",
92
93
  "searchMatchBg": "#2d2d30",
93
94
  "searchMatchText": "",
94
95
  "userMessageBg": "#2d2d30",
@@ -160,15 +161,15 @@ vim ~/.knightcode/agent/themes/my-theme.json
160
161
 
161
162
  - `name` is required, must be unique, and must not contain `/`.
162
163
  - `vars` is optional. Define reusable colors here, then reference them in `colors`.
163
- - `colors` must define all 51 required tokens. `thinkingMax`, `scrollbarThumb`, and the two search highlight tokens are optional and use the fallbacks listed below.
164
+ - `colors` must define all 53 required tokens. `thinkingMax` and the two search highlight tokens are optional and use the fallbacks listed below.
164
165
 
165
166
  The `$schema` field enables editor auto-completion and validation.
166
167
 
167
168
  ## Color Tokens
168
169
 
169
- Every theme must define all 51 required color tokens. The optional tokens preserve compatibility with existing themes: `thinkingMax` falls back to `thinkingXhigh`, `scrollbarThumb` and `searchMatchBg` fall back to `selectedBg`, and `searchMatchText` falls back to `text`. Other search matches use `searchMatchText` on `searchMatchBg` with an underline; the current match reverses that foreground/background pair and uses bold text.
170
+ Every theme must define all 53 required color tokens. The optional tokens preserve compatibility with existing themes: `thinkingMax` falls back to `thinkingXhigh`, `searchMatchBg` falls back to `selectedBg`, and `searchMatchText` falls back to `text`. Other search matches use `searchMatchText` on `searchMatchBg` with an underline; the current match reverses that foreground/background pair and uses bold text.
170
171
 
171
- ### Core UI (11 colors)
172
+ ### Core UI (13 colors)
172
173
 
173
174
  | Token | Purpose |
174
175
  |-------|---------|
@@ -183,13 +184,14 @@ Every theme must define all 51 required color tokens. The optional tokens preser
183
184
  | `dim` | Tertiary text |
184
185
  | `text` | Default text (usually `""`) |
185
186
  | `thinkingText` | Thinking block text |
187
+ | `scrollbarTrack` | Fullscreen scrollbar track foreground |
188
+ | `scrollbarThumb` | Fullscreen scrollbar thumb foreground, shared by normal and expanded states |
186
189
 
187
- ### Backgrounds & Content (11 required, 3 optional)
190
+ ### Backgrounds & Content (11 required, 2 optional)
188
191
 
189
192
  | Token | Purpose |
190
193
  |-------|---------|
191
194
  | `selectedBg` | Selected line background |
192
- | `scrollbarThumb` | Fullscreen scrollbar thumb background; optional, falls back to `selectedBg` |
193
195
  | `searchMatchBg` | Transcript search match background and current-match text; optional, falls back to `selectedBg` |
194
196
  | `searchMatchText` | Transcript search match text and current-match background; optional, falls back to `text` |
195
197
  | `userMessageBg` | User message background |
package/bin/docs/tui.md CHANGED
@@ -930,7 +930,7 @@ export default function (knightcode: ExtensionAPI) {
930
930
 
931
931
  - **Extend `CustomEditor`** (not base `Editor`) to get app keybindings (escape to abort, ctrl+d to exit, model switching, etc.)
932
932
  - **Call `super.handleInput(data)`** for keys you don't handle
933
- - **Working status**: custom editors keep the standalone working row by default. Pass `{ embedWorkingStatus: true }` as the fourth `CustomEditor` constructor argument to use the built-in editor-border spinner instead.
933
+ - **Status spinners**: custom editors keep standalone status rows by default. Pass `{ embedWorkingStatus: true }` as the fourth `CustomEditor` constructor argument to embed working, compaction, branch summarization, and retry spinners in the editor border instead.
934
934
  - **Factory pattern**: `setEditorComponent` receives a factory function that gets `tui`, `theme`, and `keybindings`
935
935
  - **Pass `undefined`** to restore the default editor: `ctx.ui.setEditorComponent(undefined)`
936
936
 
package/bin/docs/usage.md CHANGED
@@ -38,8 +38,8 @@ Type `/` in the editor to open command completion. Extensions can register custo
38
38
  |---------|-------------|
39
39
  | `/login`, `/logout` | Manage OAuth or API-key credentials |
40
40
  | [`/llama`](llama-cpp.md) | Download, load, and unload llama.cpp router models |
41
- | `/model` | Switch models; Ctrl+S in the picker saves the startup default |
42
- | `/thinking` | Switch thinking level; Ctrl+S in the picker saves the startup default |
41
+ | `/model` | Switch models; Ctrl+S or Ctrl+D in the picker saves the startup default |
42
+ | `/thinking` | Switch thinking level; Ctrl+S or Ctrl+D in the picker saves the startup default |
43
43
  | `/scoped-models` | Enable/disable models for Ctrl+P cycling |
44
44
  | `/settings` | Theme, message delivery, transport, and other preferences |
45
45
  | `/resume` | Pick from previous sessions |
@@ -249,7 +249,7 @@ knightcode --no-extensions -e ./my-extension.ts
249
249
  | `-h`, `--help` | Show help |
250
250
  | `-v`, `--version` | Show version |
251
251
 
252
- In `fullscreen` mode, the transcript scrolls inside the terminal viewport while queued messages, working status, extension widgets, editor, and footer remain fixed at the bottom. Mouse/trackpad input scrolls the region under the pointer; keyboard viewport actions always remain available. Inline images work in terminals that support the Kitty graphics protocol, including Kitty and Ghostty. In iTerm2 they render as text placeholders because its inline-image protocol cannot delete or crop placements during application-owned scrolling. In `regular` mode, knightcode uses the main screen and terminal-owned scrollback, and iTerm2 inline images continue to render normally. See [Terminal setup](terminal-setup.md) for terminal-specific settings and workarounds.
252
+ In `fullscreen` mode, the transcript scrolls inside the terminal viewport while queued messages, working status, extension widgets, editor, and footer remain fixed at the bottom. Mouse/trackpad input scrolls the region under the pointer; keyboard viewport actions always remain available. Inline images work in terminals that support the Kitty graphics protocol, including Kitty and Ghostty. In iTerm2 they render as text placeholders because its inline-image protocol cannot delete or crop placements during application-owned scrolling. In `regular` mode, knightcode uses the main screen and terminal-owned scrollback, and iTerm2 inline images continue to render normally. Text selection differs between the two modes: fullscreen captures the mouse and owns selection, so dragging copies to the clipboard on release, while regular mode never captures the mouse and leaves both selecting and copying to the terminal emulator. See [Text selection and copy](terminal-setup.md#text-selection-and-copy) for the per-terminal shortcuts, and [Terminal setup](terminal-setup.md) for other terminal-specific settings and workarounds.
253
253
 
254
254
  Set **TUI mode** in `/settings` to switch between `regular` and `fullscreen` immediately and choose the default for future sessions. **Fullscreen exit output** controls whether exiting fullscreen prints the final transcript or restores the previous screen and prints only the session resume hint.
255
255
 
Binary file
package/bin/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@knightcodeai/cli",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "description": "KnightCode — a local, BYOK terminal coding agent powered by OpenRouter.",
5
5
  "type": "module",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/KnightCodeAI/knightcode.git"
9
9
  },
10
- "homepage": "https://knightcode.raghavseth.in",
10
+ "homepage": "https://knightcode.dev",
11
11
  "license": "MIT",
12
12
  "knightcodeConfig": {
13
13
  "configDir": ".knightcode"
@@ -37,12 +37,11 @@
37
37
  "test": "vitest --run"
38
38
  },
39
39
  "optionalDependencies": {
40
- "@knightcodeai/cli-linux-x64": "0.6.0",
41
- "@knightcodeai/cli-linux-arm64": "0.6.0",
42
- "@knightcodeai/cli-darwin-x64": "0.6.0",
43
- "@knightcodeai/cli-darwin-arm64": "0.6.0",
44
- "@knightcodeai/cli-win32-x64": "0.6.0",
45
- "@mariozechner/clipboard": "0.3.9"
40
+ "@knightcodeai/cli-linux-x64": "0.6.2",
41
+ "@knightcodeai/cli-linux-arm64": "0.6.2",
42
+ "@knightcodeai/cli-darwin-x64": "0.6.2",
43
+ "@knightcodeai/cli-darwin-arm64": "0.6.2",
44
+ "@knightcodeai/cli-win32-x64": "0.6.2"
46
45
  },
47
46
  "devDependencies": {
48
47
  "@knightcode/agent": "workspace:*",
@@ -57,19 +56,20 @@
57
56
  "@types/hosted-git-info": "3.0.5",
58
57
  "@types/proper-lockfile": "4.1.4",
59
58
  "@types/semver": "7.7.1",
60
- "chalk": "5.6.2",
59
+ "chalk": "6.0.0",
61
60
  "cross-spawn": "7.0.6",
62
61
  "diff": "8.0.4",
63
- "grok-mermaid": "0.2.2",
62
+ "grok-mermaid": "0.2.3",
64
63
  "highlight.js": "10.7.3",
65
64
  "hosted-git-info": "9.0.3",
66
- "ignore": "7.0.5",
65
+ "ignore": "7.0.8",
67
66
  "jiti": "2.7.0",
68
- "minimatch": "10.2.5",
67
+ "marked": "18.0.11",
68
+ "minimatch": "10.2.6",
69
69
  "proper-lockfile": "4.1.2",
70
- "semver": "7.8.0",
71
- "typebox": "1.3.7",
72
- "undici": "8.9.0",
70
+ "semver": "7.8.5",
71
+ "typebox": "1.3.27",
72
+ "undici": "8.10.2",
73
73
  "yaml": "2.9.0"
74
74
  }
75
75
  }
@@ -33,7 +33,8 @@
33
33
  "thinkingText": "gray",
34
34
 
35
35
  "selectedBg": "selectedBg",
36
- "scrollbarThumb": "selectedBg",
36
+ "scrollbarTrack": "darkGray",
37
+ "scrollbarThumb": "text",
37
38
  "searchMatchBg": "selectedBg",
38
39
  "searchMatchText": "text",
39
40
  "userMessageBg": "userMsgBg",
@@ -32,7 +32,8 @@
32
32
  "thinkingText": "mediumGray",
33
33
 
34
34
  "selectedBg": "selectedBg",
35
- "scrollbarThumb": "selectedBg",
35
+ "scrollbarTrack": "lightGray",
36
+ "scrollbarThumb": "text",
36
37
  "searchMatchBg": "selectedBg",
37
38
  "searchMatchText": "text",
38
39
  "userMessageBg": "userMsgBg",
@@ -34,7 +34,7 @@
34
34
  },
35
35
  "colors": {
36
36
  "type": "object",
37
- "description": "Theme color definitions (thinkingMax, scrollbarThumb, and search highlight colors are optional and use compatible fallbacks)",
37
+ "description": "Theme color definitions (scrollbar, thinkingMax, and search highlight colors are optional and use compatible fallbacks)",
38
38
  "required": [
39
39
  "accent",
40
40
  "border",
@@ -137,9 +137,13 @@
137
137
  "$ref": "#/$defs/colorValue",
138
138
  "description": "Selected item background"
139
139
  },
140
+ "scrollbarTrack": {
141
+ "$ref": "#/$defs/colorValue",
142
+ "description": "Fullscreen scrollbar track foreground (falls back to muted when omitted)"
143
+ },
140
144
  "scrollbarThumb": {
141
145
  "$ref": "#/$defs/colorValue",
142
- "description": "Fullscreen scrollbar thumb background (falls back to selectedBg when omitted)"
146
+ "description": "Fullscreen scrollbar thumb foreground (falls back to text when omitted)"
143
147
  },
144
148
  "searchMatchBg": {
145
149
  "$ref": "#/$defs/colorValue",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@knightcodeai/cli-win32-x64",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",