@knightcodeai/cli 0.19.0 → 0.21.1

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.
Files changed (88) hide show
  1. package/CHANGELOG.md +106 -0
  2. package/dist/bundle/chunks/anthropic-messages-EY2CGNFR.js +6 -0
  3. package/dist/bundle/chunks/azure-openai-responses-KGI5F27P.js +2 -0
  4. package/dist/bundle/chunks/bedrock-converse-stream.js +8 -5
  5. package/dist/bundle/chunks/chunk-424HQSAU.js +10 -0
  6. package/dist/bundle/chunks/{chunk-3QKQRXCZ.js → chunk-5O4LFJS7.js} +4 -4
  7. package/dist/bundle/chunks/chunk-5ZES34QN.js +2 -0
  8. package/dist/bundle/chunks/chunk-BLHRVYHG.js +9 -0
  9. package/dist/bundle/chunks/{chunk-RZDCZFG7.js → chunk-EJS73Z3L.js} +1 -1
  10. package/dist/bundle/chunks/chunk-F22TYE3W.js +7 -0
  11. package/dist/bundle/chunks/{chunk-C62RVFZT.js → chunk-FSAHEI7P.js} +6 -6
  12. package/dist/bundle/chunks/chunk-K6AEXKBA.js +30 -0
  13. package/dist/bundle/chunks/chunk-O2HKRIDR.js +16 -0
  14. package/dist/bundle/chunks/{chunk-KRDGPCZM.js → chunk-OLW2IS5G.js} +2 -2
  15. package/dist/bundle/chunks/chunk-QEVQ7EIS.js +2 -0
  16. package/dist/bundle/chunks/chunk-RRNUW65U.js +4 -0
  17. package/dist/bundle/chunks/{chunk-AA6MLWWY.js → chunk-TOEFTX4C.js} +1 -1
  18. package/dist/bundle/chunks/{chunk-IIS4JDFO.js → chunk-TOGJI36I.js} +147 -134
  19. package/dist/bundle/chunks/chunk-VLP4ZJF6.js +2 -0
  20. package/dist/bundle/chunks/{chunk-2QXPCKUQ.js → chunk-VQBEVSZH.js} +1 -1
  21. package/dist/bundle/chunks/chunk-XDEOVQPJ.js +108 -0
  22. package/dist/bundle/chunks/chunk-YDO6TXKD.js +2 -0
  23. package/dist/bundle/chunks/{cli-SIPOI5P3.js → cli-CIRIEG66.js} +1 -1
  24. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-H3D4RYQQ.js +2 -0
  25. package/dist/bundle/chunks/{easter-egg-3d-BVWLABZN.js → easter-egg-3d-YLN6ACWS.js} +1 -1
  26. package/dist/bundle/chunks/{execute-6UIHV2DR.js → execute-P6HIB6ET.js} +1 -1
  27. package/dist/bundle/chunks/{google-generative-ai-RFCCCXK6.js → google-generative-ai-C3FLXY47.js} +1 -1
  28. package/dist/bundle/chunks/{google-vertex-WN3JAZCD.js → google-vertex-AXIPR47C.js} +1 -1
  29. package/dist/bundle/chunks/knightcode-messages-LTLKDRGW.js +8 -0
  30. package/dist/bundle/chunks/{llama-cpp-classify-FEWC5ZIH.js → llama-cpp-classify-J2EJVDIZ.js} +1 -1
  31. package/dist/bundle/chunks/mistral-conversations-N2UBIKKR.js +5 -0
  32. package/dist/bundle/chunks/{openai-codex-responses-3Y7R752C.js → openai-codex-responses-REOHLPAA.js} +1 -1
  33. package/dist/bundle/chunks/openai-completions-XONAGXPC.js +7 -0
  34. package/dist/bundle/chunks/{openai-decisions-MLI3SMFN.js → openai-decisions-ACB7F6SS.js} +1 -1
  35. package/dist/bundle/chunks/{openai-responses-BNRA5YTD.js → openai-responses-OHJS7C73.js} +1 -1
  36. package/dist/bundle/chunks/{openrouter-images-JWVDFQJ4.js → openrouter-images-SMNBEOPV.js} +1 -1
  37. package/dist/bundle/chunks/{runtime-AROIXIAV.js → runtime-WNZGA67H.js} +1 -1
  38. package/dist/bundle/chunks/typesafe-system-one-KB2F2YGV.js +2 -0
  39. package/dist/bundle/chunks/{virtual-modules-IYKQM2DL.js → virtual-modules-EU3BUTGN.js} +1 -1
  40. package/dist/bundle/cli-runtime.js +1 -1
  41. package/dist/core/export-html/template.css +9 -0
  42. package/dist/core/export-html/template.js +165 -45
  43. package/docs/app-server.md +168 -14
  44. package/docs/app-server.schema.json +7505 -1860
  45. package/docs/cli.md +3 -3
  46. package/docs/containerization.md +2 -2
  47. package/docs/custom-provider.md +2 -0
  48. package/docs/declarative-views.md +118 -0
  49. package/docs/desktop.md +109 -4
  50. package/docs/docs.json +4 -0
  51. package/docs/environment-variables.md +1 -0
  52. package/docs/extensions.md +7 -3
  53. package/docs/keybindings.md +1 -0
  54. package/docs/mcp.md +16 -2
  55. package/docs/message-types.md +1 -1
  56. package/docs/models-configuration.md +9 -0
  57. package/docs/models.md +8 -4
  58. package/docs/packages.md +2 -0
  59. package/docs/plan-mode.md +4 -0
  60. package/docs/settings.md +3 -3
  61. package/docs/slash-commands.md +2 -0
  62. package/docs/usage.md +23 -0
  63. package/examples/extensions/README.md +1 -0
  64. package/examples/extensions/custom-provider-anthropic/index.ts +27 -31
  65. package/examples/extensions/desktop-view.ts +72 -0
  66. package/examples/extensions/gondolin/index.ts +8 -10
  67. package/examples/extensions/gondolin/package-lock.json +20 -30
  68. package/examples/extensions/gondolin/package.json +1 -1
  69. package/examples/extensions/todo.ts +3 -0
  70. package/examples/mcp-app/server.mjs +177 -0
  71. package/package.json +1 -1
  72. package/dist/bundle/chunks/anthropic-messages-34POCEPV.js +0 -6
  73. package/dist/bundle/chunks/azure-openai-responses-ZZQJJY7B.js +0 -2
  74. package/dist/bundle/chunks/chunk-2QXUEOVY.js +0 -2
  75. package/dist/bundle/chunks/chunk-4CRI7BMY.js +0 -2
  76. package/dist/bundle/chunks/chunk-BTRAS32C.js +0 -7
  77. package/dist/bundle/chunks/chunk-FA32X2UJ.js +0 -7
  78. package/dist/bundle/chunks/chunk-GPHSXYPT.js +0 -2
  79. package/dist/bundle/chunks/chunk-JSLSFYBX.js +0 -108
  80. package/dist/bundle/chunks/chunk-OQHO44L6.js +0 -16
  81. package/dist/bundle/chunks/chunk-R7X2RAGR.js +0 -30
  82. package/dist/bundle/chunks/chunk-T47GKPON.js +0 -11
  83. package/dist/bundle/chunks/chunk-UU4A4NV5.js +0 -2
  84. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-QHP5M5HC.js +0 -2
  85. package/dist/bundle/chunks/knightcode-messages-57CV36UV.js +0 -8
  86. package/dist/bundle/chunks/mistral-conversations-GIGX6BW6.js +0 -5
  87. package/dist/bundle/chunks/openai-completions-HBXENZUJ.js +0 -7
  88. package/dist/bundle/chunks/typesafe-system-one-5LELZY2F.js +0 -2
package/docs/cli.md CHANGED
@@ -13,7 +13,7 @@ knightcode update [target] [options]
13
13
  knightcode list
14
14
  knightcode config [options]
15
15
  knightcode auth <check|print-api-key|print-bearer-token> [options]
16
- knightcode mcp <list|login|logout> [options]
16
+ knightcode mcp <add|remove|list|login|logout> [options]
17
17
  knightcode app-server [-e <extension>]... [--session-dir <dir>]
18
18
  ```
19
19
 
@@ -167,7 +167,7 @@ The MCP resource tools (`list_mcp_resources`, `list_mcp_resource_templates`, `re
167
167
 
168
168
  The [web tools](usage.md#web-tools) `webfetch` and `websearch` and the [question tool](usage.md#questions) `ask_user` are off until enabled with `/tools` or named here. A tool excluded here stays off whatever `/tools` says, and one turned off with `/tools` stays off even when named here.
169
169
 
170
- Built-in extensions add two more tools. They are off by default; the MCP extension turns them on when an MCP server needs them (see [MCP](mcp.md#exposure)). To enable them yourself, name them in `--tools` or `defaultTools`.
170
+ Built-in extensions add two more tools. They are off by default; the MCP extension turns them on when an MCP server needs them (see [MCP](mcp.md#control-tool-exposure)). To enable them yourself, name them in `--tools` or `defaultTools`.
171
171
 
172
172
  | Built-in extension | Purpose |
173
173
  |---|---|
@@ -388,6 +388,6 @@ These commands work outside a session, so agents can run them through `bash`. Se
388
388
  | `knightcode mcp login <server> [--timeout <seconds>]` | Sign in to an OAuth server: open the authorization page and wait for the browser; a terminal also accepts the pasted redirect URL. `--timeout` limits the whole sign-in, including requests to the authorization server (default 300 seconds) |
389
389
  | `knightcode mcp logout <server>` | Delete the stored OAuth credentials of a server |
390
390
 
391
- `add` and `remove` change `~/.knightcode/agent/mcp.json`, or `.knightcode/mcp.json` in the current directory with `--local` (`-l`). `add` also takes `--exposure <mode>` (see [Exposure](mcp.md#exposure)) and `--description <text>` and does not connect; run `knightcode mcp list` to check the server.
391
+ `add` and `remove` change `~/.knightcode/agent/mcp.json`, or `.knightcode/mcp.json` in the current directory with `--local` (`-l`). `add` also takes `--exposure <mode>` (see [Exposure](mcp.md#control-tool-exposure)) and `--description <text>` and does not connect; run `knightcode mcp list` to check the server.
392
392
 
393
393
  Project `.knightcode/mcp.json` files are only read for projects that are already trusted.
@@ -112,11 +112,11 @@ OpenShell inference routing can keep raw model credentials outside the sandbox.
112
112
 
113
113
  ## Route tools through Gondolin
114
114
 
115
- [Gondolin](https://github.com/KnightCodeAI/gondolin) is a local Linux micro-VM. Its example extension keeps the KnightCode process and file-based provider credentials on the host while routing the built-in tools and user `!` commands into the VM.
115
+ [Gondolin](https://github.com/earendil-works/gondolin) is a local Linux micro-VM. Its example extension keeps the KnightCode process and file-based provider credentials on the host while routing the built-in tools and user `!` commands into the VM.
116
116
 
117
117
  Commands inside the VM inherit the host process environment. Provider keys supplied through environment variables can therefore be visible inside the VM. Do not use this pattern as a credential boundary unless you remove sensitive variables or change the extension's environment handling.
118
118
 
119
- Gondolin requires Node.js 23.6 or newer and QEMU installed through your operating-system package manager.
119
+ Gondolin requires Node.js 22.19 or newer and QEMU installed through your operating-system package manager.
120
120
 
121
121
  ### Install the extension
122
122
 
@@ -138,6 +138,8 @@ An OAuth provider supplies a display name, login flow, token refresh, and access
138
138
 
139
139
  OAuth callbacks are UI-neutral. They can open an authorization URL, show a device code, report progress, request input, or ask the user to choose a login method. Honor cancellation and the supplied abort signal during network requests.
140
140
 
141
+ Press Enter (`tui.select.confirm`) to open the device-login URL and copy the code, or log in manually. Providers can disable either action with `openBrowserOnConfirm: false` or `copyCodeOnConfirm: false` in `onDeviceCode` or native `AuthEvent` notifications.
142
+
141
143
  Never write access tokens, refresh tokens, authorization headers, or complete provider responses to ordinary logs.
142
144
 
143
145
  ## Supply and refresh models
@@ -0,0 +1,118 @@
1
+ # Declarative Views
2
+
3
+ A view is a small tree of data that describes what to draw: text, markdown, a
4
+ table, a progress bar, a button. An extension hands one to a widget, a tool
5
+ result or an extension message, and every client draws it with its own
6
+ components: the terminal with TUI components, the [desktop app](desktop.md) with
7
+ its own. A view is data only. It never holds HTML, scripts or URLs that load.
8
+
9
+ ```ts
10
+ import type { View } from "@knightcodeai/cli";
11
+
12
+ const view: View = {
13
+ type: "stack",
14
+ children: [
15
+ { type: "text", text: "2 checks failed", tone: "error" },
16
+ { type: "table", columns: ["check", "result"], rows: [["parser", "failed"], ["lexer", "failed"]] },
17
+ { type: "button", id: "rerun", label: "Run again" },
18
+ ],
19
+ };
20
+ ```
21
+
22
+ ## Nodes
23
+
24
+ | Node | Fields | Example |
25
+ | --- | --- | --- |
26
+ | `text` | `text`, optional `tone`: `muted`, `accent`, `success`, `warning`, `error` | `{type: "text", text: "Saved", tone: "success"}` |
27
+ | `markdown` | `markdown`; raw HTML shows as text, images do not load | `{type: "markdown", markdown: "**3** files"}` |
28
+ | `stack` | `children`, optional `direction`: `vertical` (default) or `horizontal` | `{type: "stack", direction: "horizontal", children: [...]}` |
29
+ | `list` | `items`, each a view, drawn as bullets | `{type: "list", items: [{type: "text", text: "one"}]}` |
30
+ | `table` | `columns` (at least one), `rows` of strings, each row as wide as `columns` | `{type: "table", columns: ["a"], rows: [["1"]]}` |
31
+ | `progress` | `value` (0 or more), `max` (over 0), optional `label`; a value over `max` draws full | `{type: "progress", value: 3, max: 10, label: "tests"}` |
32
+ | `button` | `id` (1 to 128 characters), `label` | `{type: "button", id: "reset", label: "Reset"}` |
33
+ | `field` | `id`, `kind`: `text`, `toggle` or `select`, `label`, `value`, and `options` for a select | `{type: "field", id: "mode", kind: "select", label: "Mode", value: "fast", options: ["fast", "slow"]}` |
34
+
35
+ ## Rules and limits
36
+
37
+ A view that breaks a rule is refused as a whole:
38
+
39
+ - No members other than those above, and no other node types.
40
+ - Stacks and lists nest at most 8 levels.
41
+ - Control ids (`button` and `field`) are unique within the view.
42
+ - A toggle's `value` is a boolean; a text or select field's is a string. A
43
+ select has `options` and its `value` is one of them; a text field or toggle
44
+ has no `options`.
45
+ - Its JSON is at most 64 KiB in a tool result or an extension message, and at
46
+ most 16 KiB in a widget.
47
+
48
+ The view is copied through JSON when it is used, so a getter, a `toJSON` or a
49
+ change you make to the object later does not change what was drawn. Call
50
+ `setWidget` again to change a widget.
51
+
52
+ Terminal escape sequences and control characters other than tab and newline
53
+ are removed from every string of the copy, so colour a view with `tone`, not
54
+ ANSI codes.
55
+
56
+ A thread shows at most 16 widgets and 50 statuses, with keys of 1 to 128
57
+ characters. Status text, the title and the working message are cut to 200
58
+ characters and kept on one line.
59
+
60
+ ## Widgets
61
+
62
+ ```ts
63
+ ctx.ui.setWidget("checks:summary", view, { placement: "aboveEditor" });
64
+ ctx.ui.setWidget("checks:summary", undefined); // remove it
65
+ ```
66
+
67
+ `placement` is `aboveEditor` (the default) or `belowEditor`. Widget and status
68
+ keys are shared by every extension of a thread, so prefix them with your
69
+ extension's name. In the terminal, an invalid view draws one warning line in
70
+ its place; the app server sends nothing and reports it once per key as a
71
+ warning.
72
+
73
+ ## Tool results and extension messages
74
+
75
+ Put a view in `details.view` and clients draw it in place of the text output:
76
+
77
+ ```ts
78
+ return { content: [{ type: "text", text: "parser: failed" }], details: { view } };
79
+
80
+ knightcode.sendMessage({ customType: "checks", content: "2 failed", display: true, details: { view } });
81
+ ```
82
+
83
+ Keep the text content meaningful: the model reads it, not the view, and a client
84
+ that cannot draw the view shows the text. An invalid view is ignored and the
85
+ text shows. In the terminal a tool's own `renderResult`, or a registered message
86
+ renderer, still wins over the view.
87
+
88
+ ## Buttons and fields
89
+
90
+ In a widget on the desktop app, buttons and fields are live. A press or a
91
+ change reaches every handler the thread's extensions registered:
92
+
93
+ ```ts
94
+ ctx.ui.onViewEvent?.((event) => {
95
+ if (event.widgetKey !== "checks:summary") return;
96
+ if (event.id === "rerun") runChecks();
97
+ if (event.id === "verbose" && typeof event.value === "boolean") verbose = event.value;
98
+ ctx.ui.setWidget("checks:summary", render());
99
+ });
100
+ ```
101
+
102
+ `event` is `{widgetKey, id, value?}`: `value` is a string for a text or select
103
+ field, a boolean for a toggle, absent for a button. A field shows the value in
104
+ the view, so answer a change by setting the widget again. `onViewEvent` is
105
+ present only where widgets are interactive; the `?.` keeps the code working
106
+ elsewhere. A handler that throws becomes a warning in the app.
107
+
108
+ ## Where views draw
109
+
110
+ | Client | Widgets | Tool results and messages | Controls |
111
+ | --- | --- | --- | --- |
112
+ | Terminal | yes | yes | drawn as text |
113
+ | Desktop app | yes | yes | live in widgets, disabled elsewhere |
114
+ | RPC, JSON and print modes | no | no | no |
115
+
116
+ [`examples/extensions/desktop-view.ts`](../examples/extensions/desktop-view.ts)
117
+ puts all of it together. For the protocol side see
118
+ [app-server.md](app-server.md#dialogs-and-extension-ui).
package/docs/desktop.md CHANGED
@@ -7,8 +7,40 @@ configuration lives in the files the terminal reads (`settings.json`, `mcp.json`
7
7
  `tools.json`); the app's Settings edit those same files, so a change made in either place
8
8
  shows in both.
9
9
 
10
- The app is in development and not yet published. Phase S1 (threads, transcript, composer,
11
- approvals) is usable from a source checkout.
10
+ Installers come from the GitHub releases tagged `desktop-v<version>`; none is published yet,
11
+ so for now the app runs from a source checkout.
12
+
13
+ ## Installing
14
+
15
+ Each installer carries its own `knightcode` binary as the app server, so nothing needs to be
16
+ on `PATH`. None is signed by a recognised publisher yet:
17
+
18
+ - Windows: run `KnightCode-<version>.Setup.exe`. It installs for your user only, into
19
+ `%LOCALAPPDATA%\KnightCodeDesktop`, with Start menu and desktop shortcuts; remove it from
20
+ Settings › Apps. SmartScreen says "Windows protected your PC" the first time: choose
21
+ More info, then Run anyway.
22
+ - macOS: open the `.dmg` for your Mac (`arm64` for Apple silicon, `x64` for Intel) and drag
23
+ KnightCode to Applications. The app is signed ad hoc, not notarized, so the first launch
24
+ is refused: open System Settings › Privacy & Security and choose Open Anyway, or run
25
+ `xattr -dr com.apple.quarantine /Applications/KnightCode.app` once.
26
+ - Linux: install the `.deb` (`sudo apt install ./knightcode-desktop_<version>_amd64.deb`) or
27
+ the `.rpm` (`sudo dnf install ./knightcode-desktop-<version>-1.x86_64.rpm`).
28
+
29
+ Check a download against the release's `SHA256SUMS`.
30
+
31
+ ## Updates
32
+
33
+ - Windows: the app checks at launch and every 4 hours, and downloads a newer version in
34
+ the background. An Update button then shows at the right of the title bar, and Settings ›
35
+ About offers Restart to update; if threads are running it asks first, since quitting
36
+ interrupts them. Help › Check for Updates… checks now.
37
+ - macOS: the app checks the same way and shows Update when a newer version exists, which
38
+ opens the release page to download it (it cannot install itself while it is signed ad
39
+ hoc). KnightCode › Check for Updates… checks now.
40
+ - Linux: install the newer `.deb` or `.rpm` over the old one.
41
+
42
+ Settings › About shows the app's and the app server's versions and when the app last
43
+ checked.
12
44
 
13
45
  ## Running from source
14
46
 
@@ -25,7 +57,22 @@ quoting, so a path containing spaces (`C:\Program Files\...`) cannot be named; p
25
57
  on `PATH` and give the bare name. A packaged build ignores it and runs only its bundled binary.
26
58
 
27
59
  Server output goes to `app-server.log` in the app's logs folder (`%APPDATA%\KnightCode\logs`
28
- on Windows, `~/Library/Logs/KnightCode` on macOS, `~/.config/KnightCode/logs` on Linux).
60
+ on Windows, `~/Library/Logs/KnightCode` on macOS, `~/.config/KnightCode/logs` on Linux). At
61
+ 5 MiB it moves to `app-server.log.1`, the older ones to `.2` up to `.4`, so at most five files
62
+ are kept. Settings › About › Show logs opens the folder.
63
+
64
+ To build the installers for this machine, stage the app server and make them; the
65
+ installers land in `apps/desktop/out/make/`:
66
+
67
+ ```sh
68
+ bun run apps/desktop/scripts/stage-server.ts # builds knightcode for this platform
69
+ cd apps/desktop && bun run make
70
+ ```
71
+
72
+ The end-to-end tests launch the production build that packaging leaves in
73
+ `apps/desktop/.vite/`, against an app server whose model is scripted
74
+ (`packages/cli/test/fixtures/faux-app-server.ts`): run `bun run package`, then
75
+ `bun run test:e2e`.
29
76
 
30
77
  ## What works
31
78
 
@@ -64,10 +111,62 @@ on Windows, `~/Library/Logs/KnightCode` on macOS, `~/.config/KnightCode/logs` on
64
111
  added, as `knightcode config` does. Built-in extensions are always on and not listed.
65
112
 
66
113
  Changes apply to threads that start or resume afterwards.
114
+ - Side panel: Changes shows the thread's diff; the separators between hunks expand to
115
+ the unchanged lines around them. A file named in a tool row or in Changes opens in a
116
+ read-only tab beside it, at the line the tool read or changed. A tab opened in passing
117
+ is italic and the next one replaces it; double-click it to keep it. Each thread keeps
118
+ its own tabs, at most 12 files.
119
+ - Open in: a file tab's Open button sends the file, at its line, to an editor, terminal
120
+ or IDE found on your machine, or to the system's default app or file manager. The app
121
+ remembers the last choice, per project and overall.
122
+ - Terminal: Ctrl+\` opens a terminal in the thread's folder, in a region under the chat and
123
+ the side panel; Ctrl+J shows or hides it, and its top edge resizes it. The + menu offers
124
+ the shells found (PowerShell, Windows PowerShell, Command Prompt, Git Bash and WSL on
125
+ Windows; your login shell elsewhere), and the last one picked is the default. Terminals
126
+ belong to their thread: they keep running when the window reloads or another thread
127
+ opens, and end when you close them, archive or delete the thread, or quit. Copy needs a
128
+ selection (Ctrl+C, Ctrl+Shift+C or Ctrl+Insert); paste with Ctrl+V, Ctrl+Shift+V or
129
+ Shift+Insert (on macOS, Cmd+C and Cmd+V). Links in the output open in your browser.
130
+ - Preview: the side panel's + (Ctrl+T) opens a page in a preview tab, http and https only
131
+ (`localhost:3000` is enough). A link to a local server in a message opens there too.
132
+ Each thread keeps its own cookies and storage, cleared when the thread is deleted; pages
133
+ get no permissions, and downloads ask where to save. Annotate (Ctrl+Shift+.) lets you
134
+ drag over part of the page to attach it to the message you are writing, with the page's
135
+ address.
136
+ - MCP Apps: a tool from an [MCP server](mcp.md#mcp-apps) that has an app shows it in the
137
+ thread, under the turn's work. The app can call its own server's tools (asking you
138
+ first for one that may change things), send a follow-up message once you confirm it,
139
+ and open full screen in the side panel.
67
140
  - Archived threads: search, unarchive, or delete for good.
68
141
  - Command palette (Ctrl+K): actions and threads in one search.
69
142
  - Quitting while threads run asks first.
70
143
 
144
+ ## Extensions
145
+
146
+ Extensions load in desktop threads as they do in the terminal (`ctx.mode` is
147
+ `"desktop"`). What they show appears in the app:
148
+
149
+ - Dialogs (`select`, `confirm`, `input`, `editor`) and `ask_user`'s questions take
150
+ the composer's place; notices (`notify`) show as toasts.
151
+ - Statuses (`setStatus`) are chips in the thread's header, with the full text on
152
+ hover.
153
+ - `setTitle` names the window while the thread is open; the thread's own name stays.
154
+ - `setWorkingMessage` replaces the "Thinking" text while a turn waits on the model,
155
+ and `setWorkingVisible(false)` hides it.
156
+ - Widgets (`setWidget`) show in a panel above the composer, lines in a monospace
157
+ font, at most 10 per widget. A widget can be a
158
+ [declarative view](declarative-views.md) whose buttons and fields work: a press
159
+ reaches the extension's `ctx.ui.onViewEvent` handler.
160
+ - A tool result or an extension message with a view in `details.view` shows the view
161
+ in its row.
162
+
163
+ Terminal-only UI does not draw: widget factories, `custom()` components, header
164
+ and footer components, raw terminal input, the working indicator and editor access
165
+ (`setEditorText`, `getEditorText`, `pasteToEditor`, custom editors and autocomplete).
166
+ The app server notes each such call once per thread in `app-server.log`. A widget or
167
+ status the server refuses (an invalid view, too large, too many) shows a warning
168
+ once. The protocol side is in [app-server.md](app-server.md#dialogs-and-extension-ui).
169
+
71
170
  ## Keyboard shortcuts
72
171
 
73
172
  | Action | Default |
@@ -79,10 +178,16 @@ on Windows, `~/Library/Logs/KnightCode` on macOS, `~/.config/KnightCode/logs` on
79
178
  | Toggle the sidebar | Ctrl+B |
80
179
  | Back / forward | Alt+Left / Alt+Right |
81
180
  | Archive the thread | Ctrl+Shift+A |
181
+ | Close the side panel's file tab | Ctrl+Shift+W |
182
+ | Open a terminal / show or hide them | Ctrl+\` / Ctrl+J |
183
+ | Next / previous terminal | Ctrl+PageDown / Ctrl+PageUp |
184
+ | Open a preview / focus its address bar | Ctrl+T / Ctrl+L |
185
+ | Annotate the preview | Ctrl+Shift+. |
82
186
  | Send | Enter |
83
187
  | New line | Shift+Enter |
84
188
  | Steer the running turn | Ctrl+Enter |
85
189
  | Stop the running turn | Escape (empty composer) |
86
190
  | Allow / deny an approval | Enter / Escape (card focused) |
87
191
 
88
- On macOS, Ctrl is Cmd. Settings › Keyboard shortcuts lists every binding.
192
+ On macOS, Ctrl is Cmd, except in Ctrl+\` and Ctrl+PageDown/PageUp, which stay Control.
193
+ Settings › Keyboard shortcuts lists every binding.
package/docs/docs.json CHANGED
@@ -121,6 +121,10 @@
121
121
  "title": "Build Extensions",
122
122
  "path": "extensions.md"
123
123
  },
124
+ {
125
+ "title": "Draw Declarative Views",
126
+ "path": "declarative-views.md"
127
+ },
124
128
  {
125
129
  "title": "Add Custom Providers",
126
130
  "path": "custom-provider.md"
@@ -90,6 +90,7 @@ These variables are read by KnightCode itself:
90
90
  | `KNIGHTCODE_CACHE_RETENTION` | Set to `long` for extended provider prompt caching where supported |
91
91
  | `KNIGHTCODE_SHARE_VIEWER_URL` | Override the base URL used by `/share` |
92
92
  | `KNIGHTCODE_BUG_ENDPOINT` | Override the origin `/bug` uploads go to; default is `https://remote.knightcode.dev` |
93
+ | `KNIGHTCODE_CLEAR_ON_SHRINK` | Set to `1` to clear empty rows when rendered content shrinks; the `terminal.clearOnShrink` setting takes precedence. See [Settings](settings.md) |
93
94
  | `KNIGHTCODE_HARDWARE_CURSOR` | Set to `1` to show the hardware cursor; see [Terminal setup](terminal-setup.md) |
94
95
  | `KNIGHTCODE_CLIPBOARD_OSC52` | Set to `1` to also send copied text to the terminal with OSC 52 after the local clipboard write, as KnightCode does over SSH. Use it when a remote client reaches KnightCode without SSH variables, such as a multiplexer attached from another machine or a remote IDE daemon |
95
96
  | `KNIGHTCODE_HYPERLINKS` | Override OSC 8 hyperlink detection with `1`, `0`, or `auto` |
@@ -262,6 +262,8 @@ A tool can run other tools with `ctx.executeTool(name, args, { signal, onUpdate
262
262
 
263
263
  See [`hello.ts`](../examples/extensions/hello.ts), [`todo.ts`](../examples/extensions/todo.ts), [`dynamic-tools.ts`](../examples/extensions/dynamic-tools.ts), and [`truncated-tool.ts`](../examples/extensions/truncated-tool.ts).
264
264
 
265
+ A tool registered under a built-in name replaces the built-in tool. Re-registering a copy of `createBashToolDefinition(cwd)` or `createPowerShellToolDefinition(cwd)` with object spread, for example to change its rendering, keeps [background commands](usage.md#background-commands): the session runs them with its own background manager as long as the copy keeps the built-in `execute` and `parameters`. A copy that replaces `execute`, such as one that routes commands to a sandbox or a remote host, runs commands in the foreground only, and `task_stop` is not declared for it.
266
+
265
267
  ### Tool exposure
266
268
 
267
269
  `exposure` controls how the model reaches a tool. "Callable" means callable from other tools through `ctx.executeTool()` (`ctx.tools`), as the `codemode` tool's scripts do:
@@ -315,7 +317,7 @@ knightcode.unregisterMcpServer("jira");
315
317
 
316
318
  Servers registered while the extension loads connect when the session starts, together with the `mcp.json` servers; servers registered later connect right away, and `knightcode.unregisterMcpServer()` closes the connection and makes the server's tools unreachable. Registrations are not saved: register again on every load, for example based on the extension's own settings. A server in `mcp.json` with the same name takes precedence, and `/mcp` shows the override. Registering the same name again replaces the extension's earlier registration; names registered by another extension, invalid names, and invalid configs throw.
317
319
 
318
- The built-in MCP support connects registered servers. When nothing does, because another extension replaced it (see [MCP](mcp.md#other-mcp-extensions)), each registration is reported as an extension error. Other MCP extensions can connect registered servers too: read them with `knightcode.getMcpServers()` on `session_start` and handle the `mcp_servers_change` event for later changes.
320
+ The built-in MCP support connects registered servers. When nothing does, because another extension replaced it (see [MCP](mcp.md#replace-the-built-in-mcp-support)), each registration is reported as an extension error. Other MCP extensions can connect registered servers too: read them with `knightcode.getMcpServers()` on `session_start` and handle the `mcp_servers_change` event for later changes.
319
321
 
320
322
  <a id="extensioncontext"></a>
321
323
  <a id="extensioncommandcontext"></a>
@@ -387,8 +389,10 @@ Use `ctx.ui.custom()` only when the interaction needs its own rendering and inpu
387
389
  See [Terminal UI](tui.md) for component, focus, overlay, theme, and performance guidance.
388
390
 
389
391
  Extensions load in interactive, RPC, JSON, print, and desktop modes.
390
- Desktop mode currently has no extension UI (`hasUI` is false); terminal
391
- components remain unavailable even when desktop dialogs are added.
392
+ Desktop mode draws dialogs, notices, statuses, titles, working text and widgets,
393
+ including [declarative views](declarative-views.md) with live buttons and
394
+ fields; terminal components (widget factories, `custom()`, header, footer) do not
395
+ draw there. See [Desktop App](desktop.md#extensions).
392
396
  Interactive mode provides the complete terminal UI. The [DOOM overlay example](../examples/extensions/doom-overlay/) uses a custom overlay component to render a game frame by frame:
393
397
 
394
398
  <p align="center"><img src="images/doom-extension.png" alt="The DOOM overlay example running over a KnightCode session" width="750"></p>
@@ -164,6 +164,7 @@ On native Windows, `app.suspend` has no default because Windows terminals do not
164
164
  | Keybinding id | Default | Description |
165
165
  |--------|---------|-------------|
166
166
  | `app.tools.expand` | `ctrl+o` | Collapse or expand tool output |
167
+ | `app.tools.background` | `ctrl+b` | Move running shell commands to the [background](usage.md#background-commands). Only while a command runs; otherwise the key reaches the editor, where `ctrl+b` moves the cursor left |
167
168
  | `app.message.copy` | `ctrl+x` | Copy the selected message in `/tree`; otherwise copy the active fullscreen text selection when `fullscreenCopyOnSelect` is disabled, falling back to the last assistant message. On OAuth sign-in screens, copy the sign-in URL |
168
169
  | `app.message.followUp` | `alt+enter` (`ctrl+q` on Windows and WSL) | Queue follow-up message |
169
170
  | `app.message.dequeue` | `alt+up` (`alt+q` on Windows and WSL) | Restore queued messages to editor |
package/docs/mcp.md CHANGED
@@ -243,13 +243,27 @@ When a connected server offers [resources](https://modelcontextprotocol.io/speci
243
243
 
244
244
  These tools reach every enabled, non-hidden server with resources. Their exposure is the widest exposure among those servers: `direct`, then `codemode` or `deferred`. Resource links in tool results identify `read_mcp_resource` and the server.
245
245
 
246
- Resources for MCP Apps, identified by `ui://` URIs or `text/html;profile=mcp-app`, are omitted because KnightCode does not render them. Resource icons are also omitted.
246
+ Resources for MCP Apps, identified by `ui://` URIs or `text/html;profile=mcp-app`, are omitted from these tools: the desktop app draws them (see [MCP Apps](#mcp-apps)). Resource icons are also omitted.
247
247
 
248
248
  Reading and listing resources is retried once after a transient HTTP error (408, 429, or 5xx). Tool calls are not retried because the server may already have performed them.
249
249
 
250
+ ## MCP Apps
251
+
252
+ A server can give a tool an interactive view with the MCP Apps extension (`io.modelcontextprotocol/ui`, Stable 2026-01-26): the tool names a `ui://` resource in `_meta.ui.resourceUri`, and the resource is an HTML document of type `text/html;profile=mcp-app`. The [desktop app](desktop.md) draws it in the tool's row. The terminal draws no apps, so KnightCode tells servers it supports them only in the desktop, and elsewhere servers answer with their text fallback.
253
+
254
+ In the desktop:
255
+
256
+ - A tool with an app is declared to the model whatever the server's exposure, and it cannot be called from codemode scripts: a call drawn as an app must be the model's own, which the session keeps. A tool you configured as `hidden` stays hidden and draws no app.
257
+ - A tool whose `_meta.ui.visibility` leaves out `"model"` is not declared to the model, whatever its exposure and whether or not it has an app of its own. An app can still call it.
258
+ - An app calls only tools of its own server whose visibility includes `"app"`. In Full access its calls run. In Ask and Auto-edit, a call to a tool not annotated `readOnlyHint` asks you first, naming the server and the tool. An app's calls do not go through the session's tool pipeline, so extension `tool_call` and `tool_result` handlers, permission gates included, do not see them.
259
+ - An app can send a follow-up message to the thread after you confirm it, open http and https links in your browser, and ask to be shown full screen in the side panel. It cannot update the model's context.
260
+ - The app runs in a sandboxed frame on its own origin, with no permissions (no camera, microphone, location or clipboard). It reaches the network only through the domains its resource declares in `_meta.ui.csp`; a declaration that is not a list of host sources is refused and the app does not load.
261
+
262
+ [`examples/mcp-app/server.mjs`](../examples/mcp-app/server.mjs) is a small stdio server with a counter app: one tool that shows the app, one only the app may call, and one read-only tool.
263
+
250
264
  ## Permissions
251
265
 
252
- Every MCP call passes through KnightCode's tool pipeline. Extension `tool_call` and `tool_result` handlers, including permission gates, therefore apply to MCP tools. Calls made from codemode scripts carry the codemode call ID as `parentToolCallId`.
266
+ Every MCP call the model makes passes through KnightCode's tool pipeline. Extension `tool_call` and `tool_result` handlers, including permission gates, therefore apply to MCP tools; an [MCP App](#mcp-apps)'s own calls are the exception. Calls made from codemode scripts carry the codemode call ID as `parentToolCallId`.
253
267
 
254
268
  `knightcode.getAllTools()` reports the annotations declared by each server: `readOnlyHint`, `destructiveHint`, `idempotentHint`, and `openWorldHint`. Permission extensions can use these hints to decide which calls require confirmation (see [Tool exposure](extensions.md#tool-exposure)). Resource tools are marked read-only.
255
269
 
@@ -140,7 +140,7 @@ interface AssistantMessage {
140
140
  }
141
141
  ```
142
142
 
143
- `responseModel` records a concrete provider response model when it differs from the requested model. `responseId`, `providerThinkingLevel`, `thinkingLevel`, `diagnostics`, and `rawStopReason` preserve provider or runtime details.
143
+ `responseModel` records the concrete model reported by the provider, when the provider reports one. It may equal the requested model. `responseId`, `providerThinkingLevel`, `thinkingLevel`, `diagnostics`, and `rawStopReason` preserve provider or runtime details.
144
144
 
145
145
  `"pending"` is used for a partial assistant message while it streams. The completed message in `message_end` has a terminal stop reason, and KnightCode does not persist `"pending"` assistant messages in session JSONL.
146
146
 
@@ -185,3 +185,12 @@ Also applies to `azure-openai-responses` and `openai-codex-responses`.
185
185
  | Field | Type | Default | Description |
186
186
  |---|---|---|---|
187
187
  | `supportsMidConvoSystemMessages` | boolean | `false` | Whether the exact model accepts system messages after the conversation has started. When false, later system messages are folded into the leading system message. |
188
+
189
+ ### `typesafe-system-one`
190
+
191
+ Also applies to `cloudflare-workers-ai-system-one`.
192
+
193
+ | Field | Type | Default | Description |
194
+ |---|---|---|---|
195
+ | `imageInput` | `"assets" \| "images" \| "state-image-urls"` | | How the service takes classifier images. "assets" sends TypeSafe's assets map (PNG and JPEG) and references the images from the state, as TypeSafe and Jev on Workers AI expect. "images" sends Clef's images list of data URLs (PNG, JPEG, and WebP, at most four), as Clef on Workers AI expects. "state-image-urls" places image_url parts before the state, as OpenRouter expects; OpenRouter drops assets without an error. Auto-detected from the provider, baseUrl, and model ID. Classifier models read it from the provider-level compat; models and modelOverrides entries apply to chat models only. |
196
+ | `sendImageOptInHeader` | boolean | | Whether requests with images send the TypeSafe-Danger-Zone-Images: true header, which TypeSafe's own API requires for its experimental image input. Defaults to true for the typesafe-system-one API unless the model is detected as OpenRouter. |
package/docs/models.md CHANGED
@@ -141,20 +141,20 @@ Compatibility settings should describe verified differences in the endpoint's re
141
141
 
142
142
  ## Use classifier models
143
143
 
144
- Classifier models do not chat. They answer typed questions about JSON state: pick one of several choices, answer yes or no, or give a score, each with probabilities. KnightCode includes TypeSafe's Jev model from these providers, Cloudflare's Clef and Clef Flash models from Workers AI, and OpenAI's GPT-6 Luna through the [Decisions API](https://developers.openai.com/api/docs/guides/decisions):
144
+ Classifier models do not chat. They answer typed questions about JSON state: pick one of several choices, answer yes or no, or give a score, each with probabilities. KnightCode includes TypeSafe's Jev model from these providers, Cloudflare's Clef, Clef Flash, and Clef Omni models from Workers AI and OpenRouter, and OpenAI's GPT-6 Luna through the [Decisions API](https://developers.openai.com/api/docs/guides/decisions):
145
145
 
146
146
  | Provider | Model IDs | Authentication |
147
147
  |---|---|---|
148
148
  | `typesafe` | `jev-latest` | `TYPESAFE_API_KEY` |
149
- | `openrouter` | `typesafe/jev-1.13`, `~typesafe/jev-latest` | `OPENROUTER_API_KEY` or `/login` |
150
- | `cloudflare-workers-ai` | `typesafe/jev`, `@cf/cloudflare/clef`, `@cf/cloudflare/clef-flash` | `CLOUDFLARE_API_KEY` and `CLOUDFLARE_ACCOUNT_ID` |
149
+ | `openrouter` | `typesafe/jev-1.13`, `typesafe/jev-1.14`, `~typesafe/jev-latest`, `cloudflare/clef`, `cloudflare/clef-flash`, `cloudflare/clef-omni` | `OPENROUTER_API_KEY` or `/login` |
150
+ | `cloudflare-workers-ai` | `typesafe/jev`, `typesafe/jev-1.14.0`, `@cf/cloudflare/clef`, `@cf/cloudflare/clef-flash`, `@cf/cloudflare/clef-omni` | `CLOUDFLARE_API_KEY` and `CLOUDFLARE_ACCOUNT_ID` |
151
151
  | `vercel-ai-gateway` | `typesafe-ai/jev` | `AI_GATEWAY_API_KEY` |
152
152
  | `opencode` | `jev-1.13`, `jev-1.13-free` | `OPENCODE_API_KEY` |
153
153
  | `openai` | `gpt-6-luna` | `OPENAI_API_KEY` |
154
154
 
155
155
  A [llama.cpp router](llama-cpp.md#classification) lists decision models as native classifiers, and also lists each chat model as a classifier.
156
156
 
157
- OpenAI's Decisions API needs an API key. ChatGPT sign-in does not work with it, so `gpt-6-luna` is not listed as available while `openai` is logged in through `/login`, even when `OPENAI_API_KEY` is set; log out of `openai` to use the key. GPT-6 Luna also judges images passed in `images` (see [Codemode](codemode.md#classify)); other classifier models return an error for them. The API rejects inputs above 922K tokens, but requests that run longer than about five seconds, currently above roughly 600K input tokens, fail with a gateway timeout.
157
+ OpenAI's Decisions API needs an API key. ChatGPT sign-in does not work with it, so `gpt-6-luna` is not listed as available while `openai` is logged in through `/login`, even when `OPENAI_API_KEY` is set; log out of `openai` to use the key. The API rejects inputs above 922K tokens, but requests that run longer than about five seconds, currently above roughly 600K input tokens, fail with a gateway timeout.
158
158
 
159
159
  Classifier models do not appear in `/model`. The [classifier gate](usage.md#classifier-gate) uses one to screen risky tool calls. The model reaches them through the [`codemode`](cli.md#enable-codemode) tool, which is off unless an MCP server turned it on. Enable it with `"defaultTools": ["+codemode"]` in [settings](settings.md#tools). Scripts then list classifier models with `models.getAvailableOfType("classifier")` and call `models.classify(model, { state, questions })`:
160
160
 
@@ -175,6 +175,10 @@ return result.answers;
175
175
 
176
176
  [Codemode](codemode.md#classify) describes the question and answer types.
177
177
 
178
+ Classifier models whose `input` includes `"image"` also judge images passed in `images`; other classifier models return an error for them. Image input works with GPT-6 Luna, with Jev from `typesafe` and `cloudflare-workers-ai`, with Clef from `cloudflare-workers-ai`, and with the OpenRouter models whose catalog lists image input. Jev takes PNG and JPEG images, and image input is experimental on TypeSafe's own API. Clef takes PNG, JPEG, and WebP images, at most four per request. Jev from `vercel-ai-gateway` and `opencode` takes text only.
179
+
180
+ Each System One service takes images in its own request format, set by the model's `compat.imageInput`. Built-in models set it, so overriding a provider's `baseUrl` keeps it. A custom provider that proxies another service's classifiers sets it in its provider-level `compat` in `models.json` (see [System One compatibility](models-configuration.md#typesafe-system-one)). OpenRouter in particular answers requests in TypeSafe's format without an error but drops the images.
181
+
178
182
  When the service reports token counts, as all System One services do, `result.usage` carries them with their cost. KnightCode adds the usage of a script's classifier calls to the `codemode` tool result, so it counts toward the session cost in the footer and `/session`. The cost uses the model's catalog price; models without one, such as TypeSafe's direct `jev-latest`, report tokens at no cost.
179
183
 
180
184
  Extensions call classifiers through `ctx.modelRegistry.classify()`, without codemode. [Virtual models](virtual-models.md#route-requests) can use them to route requests; see the `jev-router.ts` example.
package/docs/packages.md CHANGED
@@ -16,6 +16,8 @@ knightcode install ./local-package
16
16
 
17
17
  `knightcode list` shows configured packages. Use `knightcode remove <source>` to remove one and `knightcode update --extensions` to reconcile package installations. See [Command Line](cli.md#package-commands) for every package command and option.
18
18
 
19
+ If a configured package fails to install at startup, for example because npm cannot reach the registry, KnightCode warns about it, skips that package's resources, and keeps running. KnightCode tries to install it again on the next start or `/reload`. `knightcode install` and `knightcode update --extensions` still report the failure and exit non-zero.
20
+
19
21
  Personal installs are written to `~/.knightcode/agent/settings.json`. Add `--local` or `-l` to write the package declaration to `.knightcode/settings.json`. KnightCode reads declarations from that file only after project trust is granted.
20
22
 
21
23
  Project packages are installed and loaded only after project trust is resolved. Packages can execute extension code and can include skills that instruct the model to run programs. Review third-party package source before installing it. Review project package declarations before granting project trust.
package/docs/plan-mode.md CHANGED
@@ -69,6 +69,10 @@ to the highlighted choice; on an implement choice it is sent with the
69
69
  approval, and on Keep planning it is sent as feedback. Escape keeps planning. Review does not open automatically on resume. Session replacement, tree navigation, or a new run cancels an open
70
70
  picker. An action rechecks the shown revision before changing state.
71
71
 
72
+ The desktop app opens review by itself too, asking "Implement this plan?":
73
+ Yes, implement this plan; Implement in a new thread; or Exit planning.
74
+ A fresh session is named after the plan's first line of prose.
75
+
72
76
  RPC reports a submission notification; `/plan` opens its review selection.
73
77
  JSON mode adds no extra output:
74
78
  the submission tool-call events contain the Markdown.
package/docs/settings.md CHANGED
@@ -107,7 +107,7 @@ See [Compaction Reference](compaction.md) for trigger, summarization, and valida
107
107
  | `showHardwareCursor` | boolean | `false` | Use the terminal cursor instead of KnightCode's drawn cursor. KnightCode still positions it for input methods. |
108
108
  | `terminal.showImages` | boolean | `true` | Display inline images when supported. |
109
109
  | `terminal.imageWidthCells` | number | `60` | Preferred inline image width in terminal cells. |
110
- | `terminal.clearOnShrink` | boolean | `false` | Clear empty rows when rendered content shrinks. |
110
+ | `terminal.clearOnShrink` | boolean | `false` | Clear empty rows when rendered content shrinks. When unset, `KNIGHTCODE_CLEAR_ON_SHRINK=1` enables it. |
111
111
  | `terminal.showTerminalProgress` | boolean | `false` | Show OSC 9;4 progress in the terminal tab. |
112
112
  | `terminal.hyperlinks` | `boolean \| "auto"` | `"auto"` | Override OSC 8 hyperlink detection. |
113
113
  | `terminal.images` | `"kitty" \| "iterm2" \| "auto" \| false` | `"auto"` | Override inline-image protocol detection. |
@@ -178,8 +178,8 @@ handed off by accident, and nothing is created through a symlink or junction.
178
178
  |---|---|---|---|
179
179
  | `transport` | `"auto" \| "sse" \| "websocket" \| "websocket-cached"` | `"auto"` | Preferred transport for AI providers that support multiple transports. |
180
180
  | `httpProxy` | string | None | Proxy URL applied as `HTTP_PROXY` and `HTTPS_PROXY` for KnightCode-managed HTTP clients. **Can only be set in agent-directory settings.** |
181
- | `httpIdleTimeoutMs` | number | `300000` | HTTP header and body idle timeout in milliseconds. Set to `0` to disable. |
182
- | `websocketConnectTimeoutMs` | number | `15000` | WebSocket connection timeout in milliseconds. Set to `0` to disable. |
181
+ | `httpIdleTimeoutMs` | number \| `"disabled"` | `300000` | HTTP header and body idle timeout in milliseconds. Set to `0` or `"disabled"` to disable. |
182
+ | `websocketConnectTimeoutMs` | number \| `"disabled"` | `15000` | WebSocket connection timeout in milliseconds. Set to `0` or `"disabled"` to disable. |
183
183
  | `retry.enabled` | boolean | `true` | Enable automatic agent-level retry for transient failures. |
184
184
  | `retry.maxRetries` | number | `3` | Maximum agent-level retry attempts. |
185
185
  | `retry.baseDelayMs` | number | `2000` | Initial exponential-backoff delay in milliseconds. |
@@ -64,8 +64,10 @@ Review a session before exporting or sharing it. Sessions can contain prompts, t
64
64
  | Command | Description |
65
65
  |---|---|
66
66
  | `/trust` | Save a project trust decision for future KnightCode processes |
67
+ | `/mcp` | Manage MCP servers: sign in, reconnect, enable or disable, and change exposure |
67
68
  | `/reload` | Reload keybindings, extensions, skills, templates, themes, and context files |
68
69
  | `/hotkeys` | Show active keyboard shortcuts |
70
+ | `/tasks` | List [background commands](usage.md#background-commands), show their output, and stop them |
69
71
  | `/changelog` | Show changelog entries |
70
72
  | `/quit` | Quit KnightCode |
71
73
 
package/docs/usage.md CHANGED
@@ -41,6 +41,7 @@ You can send more input while KnightCode is working:
41
41
  | Adjust the current task | Type a message and press `Enter` |
42
42
  | Add work after the current task | Type a message and press `Alt+Enter` |
43
43
  | Return queued messages to the editor | Press `Alt+Up` |
44
+ | Let a long command run on while KnightCode continues | Press `Ctrl+B` (see [Background commands](#background-commands)) |
44
45
  | Stop the current task | Press `Escape` |
45
46
 
46
47
  A message sent with `Enter` waits until the current response and its tool calls finish, then guides the next response. A follow-up sent with `Alt+Enter` waits until KnightCode finishes the current task. Aborting returns queued messages to the editor.
@@ -83,6 +84,28 @@ Prefix a command with `!` to run it and include its output in the conversation:
83
84
 
84
85
  Use `!!` when you want to run a command without sending its output to the model.
85
86
 
87
+ ## Background commands
88
+
89
+ KnightCode can start a command in the background, and decides per command whether to. It does so for work that takes long or never exits, such as a dev server, a file watcher, or a long build or test run. The tool call returns at once and the command keeps running while KnightCode works, across turns. When the command exits, KnightCode is told how it ended, with the last lines of its output, and carries on from there; you see the same notice in the transcript.
90
+
91
+ Press `Ctrl+B` while a command runs in the foreground to move it to the background. The same process keeps running; nothing starts again. The key works only while a command runs; otherwise `Ctrl+B` moves the cursor as usual.
92
+
93
+ While commands run, a pill above the footer counts them: `1 shell`, `3 shells`. Press `Down` in an empty editor to select it and `Enter` to open the **Background tasks** list, or click it; `Esc` or `Up` returns to the editor. `/tasks` opens the same list. With a single command it opens on that command's details.
94
+
95
+ | Key | In the list | In a command's details |
96
+ |-----|-------------|------------------------|
97
+ | `Up`/`Down` | Choose a command | |
98
+ | `Enter` | Show its details | Close |
99
+ | `x` | Stop the chosen command | Stop it |
100
+ | `Left` | Close | Back to the list |
101
+ | `Esc` | Close | Close |
102
+
103
+ A command's details show its status and exit code, runtime, command, and the last 10 lines of its output as it arrives. Its output is also written to a file, and KnightCode reads that file when it needs the output sooner. If writing that file fails, for example on a full disk, the file is incomplete and KnightCode is told so. KnightCode stops a command with the `task_stop` tool, which is on whenever `bash` or `powershell` is.
104
+
105
+ A background command ends when it exits, when KnightCode or you stop it, or when the session ends: quitting, `/new`, `/resume`, and `/fork` stop it, while `/reload` keeps it. Resuming or forking a session does not start its commands again; with your next message KnightCode is told that they were stopped. A `timeout` given with the command still stops it in the background. A command that writes more than 1 GiB of output is stopped, and at most 32 run at once.
106
+
107
+ A background command has no input: one that asks a question reads end-of-file. If you press `Escape` to stop the current task, a command that ends afterwards is recorded in the conversation without starting KnightCode again; the next message you send re-arms that. In print and JSON modes KnightCode does not exit while a command it started in the background is running, so it can act on how the command ended.
108
+
86
109
  ## Web Tools
87
110
 
88
111
  Two tools give the agent read access to the web. Both ship disabled; turn them on with `/tools`.
@@ -32,6 +32,7 @@ cp permission-gate.ts ~/.knightcode/agent/extensions/
32
32
  |-----------|-------------|
33
33
  | `todo.ts` | Todo list tool + `/todos` command with custom rendering and state persistence |
34
34
  | `hello.ts` | Minimal custom tool example |
35
+ | `desktop-view.ts` | Declarative views: a widget with a live toggle and button (`ctx.ui.onViewEvent`), and a tool result drawn as a table |
35
36
  | `question.ts` | Demonstrates `ctx.ui.select()` for asking the user questions with custom UI |
36
37
  | `questionnaire.ts` | Multi-question input with tab bar navigation between questions |
37
38
  | `tool-override.ts` | Override built-in tools (e.g., add logging/access control to `read`) |