@knightcodeai/cli 0.18.4 → 0.20.0
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/CHANGELOG.md +90 -0
- package/dist/bundle/chunks/anthropic-messages-5ZM7Z2XQ.js +6 -0
- package/dist/bundle/chunks/azure-openai-responses-OUS4VJNA.js +2 -0
- package/dist/bundle/chunks/bedrock-converse-stream.js +3 -3
- package/dist/bundle/chunks/chunk-5ZES34QN.js +2 -0
- package/dist/bundle/chunks/{chunk-3VVG5HD5.js → chunk-6GRVIFTN.js} +2 -2
- package/dist/bundle/chunks/{chunk-FG6M5B3F.js → chunk-6KWPS3LA.js} +159 -124
- package/dist/bundle/chunks/chunk-6X7IXVQH.js +30 -0
- package/dist/bundle/chunks/{chunk-T6M3FJYR.js → chunk-B7A4GIBK.js} +1 -1
- package/dist/bundle/chunks/{chunk-3B66IKOZ.js → chunk-BWGDAXFH.js} +1 -1
- package/dist/bundle/chunks/{chunk-MXIWLMNT.js → chunk-CCP7VAJU.js} +1 -1
- package/dist/bundle/chunks/{chunk-L2XRQUGK.js → chunk-DFRYMT3C.js} +4 -4
- package/dist/bundle/chunks/{chunk-NGWSYXD5.js → chunk-IIWY7U5S.js} +3 -3
- package/dist/bundle/chunks/{chunk-SLWTIEJK.js → chunk-J63X3FRT.js} +1 -1
- package/dist/bundle/chunks/{chunk-HRZGVTRM.js → chunk-JMJS643J.js} +1 -1
- package/dist/bundle/chunks/{chunk-GCXF7ZNR.js → chunk-L6QGGIZG.js} +4 -4
- package/dist/bundle/chunks/chunk-MZ5UVOTP.js +2 -0
- package/dist/bundle/chunks/chunk-N5M3XNPN.js +2 -0
- package/dist/bundle/chunks/{chunk-XILUO467.js → chunk-RKNFSQUG.js} +1 -1
- package/dist/bundle/chunks/chunk-UU4A4NV5.js +2 -0
- package/dist/bundle/chunks/{chunk-2QXPCKUQ.js → chunk-VQBEVSZH.js} +1 -1
- package/dist/bundle/chunks/{cli-AMSWLH7A.js → cli-72YA573P.js} +1 -1
- package/dist/bundle/chunks/cloudflare-workers-ai-system-one-AWHNPEAT.js +2 -0
- package/dist/bundle/chunks/{easter-egg-3d-VH6SGOZS.js → easter-egg-3d-XXPCDCZV.js} +1 -1
- package/dist/bundle/chunks/{execute-4UQWU4SD.js → execute-KWIUMPDE.js} +1 -1
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/google-generative-ai-HPLZ2ABU.js +2 -0
- package/dist/bundle/chunks/google-vertex-E3UTTTIG.js +2 -0
- package/dist/bundle/chunks/knightcode-messages-57CV36UV.js +8 -0
- package/dist/bundle/chunks/{llama-cpp-classify-HRPRKOZA.js → llama-cpp-classify-FEWC5ZIH.js} +2 -2
- package/dist/bundle/chunks/{mistral-conversations-NUSSE6NX.js → mistral-conversations-KT4C4XTZ.js} +1 -1
- package/dist/bundle/chunks/openai-codex-responses-BCLSSOJ6.js +10 -0
- package/dist/bundle/chunks/openai-completions-GTNAEXX6.js +7 -0
- package/dist/bundle/chunks/{openai-decisions-ENPSYANO.js → openai-decisions-CSQTW3S4.js} +1 -1
- package/dist/bundle/chunks/openai-responses-ILFXLMJW.js +4 -0
- package/dist/bundle/chunks/openrouter-images-J66HXAMB.js +2 -0
- package/dist/bundle/chunks/{runtime-IU2Z5WWF.js → runtime-OW5JKWBE.js} +1 -1
- package/dist/bundle/chunks/typesafe-system-one-QA5VXBEZ.js +2 -0
- package/dist/bundle/chunks/{virtual-modules-AK4BYDR6.js → virtual-modules-5DLTLPP7.js} +1 -1
- package/dist/bundle/cli-runtime.js +1 -1
- package/dist/core/export-html/template.css +9 -0
- package/dist/core/export-html/template.js +165 -45
- package/docs/app-server.md +350 -12
- package/docs/app-server.schema.json +11493 -2563
- package/docs/containerization.md +2 -2
- package/docs/declarative-views.md +118 -0
- package/docs/desktop.md +45 -4
- package/docs/docs.json +4 -0
- package/docs/extensions.md +4 -2
- package/docs/models-configuration.md +9 -0
- package/docs/models.md +8 -4
- package/docs/settings.md +53 -0
- package/examples/extensions/README.md +1 -0
- package/examples/extensions/desktop-view.ts +72 -0
- package/examples/extensions/gondolin/index.ts +8 -10
- package/examples/extensions/gondolin/package-lock.json +20 -30
- package/examples/extensions/gondolin/package.json +1 -1
- package/package.json +1 -1
- package/dist/bundle/chunks/anthropic-messages-VD2GN7C4.js +0 -6
- package/dist/bundle/chunks/azure-openai-responses-6IJ5JZ3Y.js +0 -2
- package/dist/bundle/chunks/chunk-3PSTVJEH.js +0 -2
- package/dist/bundle/chunks/chunk-4DOSUUX3.js +0 -30
- package/dist/bundle/chunks/chunk-CRLO4X52.js +0 -2
- package/dist/bundle/chunks/chunk-HHWP56PR.js +0 -2
- package/dist/bundle/chunks/cloudflare-workers-ai-system-one-JBMTTHVI.js +0 -2
- package/dist/bundle/chunks/google-generative-ai-QBWYWMCA.js +0 -2
- package/dist/bundle/chunks/google-vertex-4KVZWEAI.js +0 -2
- package/dist/bundle/chunks/knightcode-messages-3GNOTMSI.js +0 -8
- package/dist/bundle/chunks/openai-codex-responses-66UQNGWB.js +0 -10
- package/dist/bundle/chunks/openai-completions-QTYKORY2.js +0 -7
- package/dist/bundle/chunks/openai-responses-JSX72BKV.js +0 -3
- package/dist/bundle/chunks/openrouter-images-ZI7LLZ4Y.js +0 -2
- package/dist/bundle/chunks/typesafe-system-one-ETHWOYKC.js +0 -2
package/docs/app-server.md
CHANGED
|
@@ -63,7 +63,8 @@ Start a thread with its project directory:
|
|
|
63
63
|
```
|
|
64
64
|
|
|
65
65
|
Wait for each response. `thread/start` and `thread/fork` return
|
|
66
|
-
`{thread, warnings}
|
|
66
|
+
`{thread, warnings, ui}` (`ui` is the thread's extension UI, see
|
|
67
|
+
[Dialogs and extension UI](#dialogs-and-extension-ui)). A fork is named after its source with ` (fork)` appended. `thread/resume` also returns warnings; render them from the
|
|
67
68
|
response, because they can occur before subscription. A warning has
|
|
68
69
|
`{message, source, path?, line?, column?}`, where `source` is `settings`,
|
|
69
70
|
`extension`, `trust`, or `server`. Malformed settings, refused extension loads,
|
|
@@ -72,9 +73,10 @@ send a subscriber-only `warning` with `threadId`.
|
|
|
72
73
|
|
|
73
74
|
Threads and list summaries include `createdAt` (header creation time) and
|
|
74
75
|
optional `forkedFromId` (the parent's header ID, not a UUID inferred from its
|
|
75
|
-
filename).
|
|
76
|
-
|
|
77
|
-
|
|
76
|
+
filename). A loaded thread also carries `sessionFile`, the session file's path,
|
|
77
|
+
once it has been saved. List summaries use file modification time for
|
|
78
|
+
`updatedAt`; loaded threads use the latest entry time, falling back to the
|
|
79
|
+
header. Their `status` is one of:
|
|
78
80
|
|
|
79
81
|
- `{type: "notLoaded"}`
|
|
80
82
|
- `{type: "idle"}`
|
|
@@ -159,9 +161,12 @@ lands in a later turn. A steer cannot be taken back once accepted.
|
|
|
159
161
|
input starts a turn of its own once the thread is idle, oldest first; on an idle
|
|
160
162
|
thread it starts at once. Until it starts it is removable with
|
|
161
163
|
`turn/queue/remove`. A queued input that fails to start (no model, signed out) is
|
|
162
|
-
dropped with an `error` notification
|
|
163
|
-
`
|
|
164
|
-
|
|
164
|
+
dropped with an `error` notification carrying its `clientMessageId`, if it had
|
|
165
|
+
one. `turn/queue/updated` sends
|
|
166
|
+
`{threadId, steering: [text], followUp: [{id, text, attachments?}]}`: steers the
|
|
167
|
+
agent has not delivered yet, and the queued inputs. `text` is the user's own (not
|
|
168
|
+
a prompt composed with review comments); `attachments` counts the images and
|
|
169
|
+
review comments an input carries that its text alone does not.
|
|
165
170
|
|
|
166
171
|
`turn/interrupt` accepts optional `turnId`; a supplied stale ID returns
|
|
167
172
|
`turnMismatch`, while omitting it retains interrupt-current behavior. It drops
|
|
@@ -201,9 +206,9 @@ Desktop OS notifications are for live outcomes, not initial history.
|
|
|
201
206
|
`thread/resume` returns history and subscribes in the same synchronous send step.
|
|
202
207
|
Its separate `runningTurn` is a current snapshot, even when an old history cursor
|
|
203
208
|
is supplied. Its required `queue` and `usage` are also live send-time snapshots,
|
|
204
|
-
not values from handler entry or the history cursor
|
|
205
|
-
while awaiting the response, install the snapshots (an
|
|
206
|
-
state), then replay the buffered events. Invalid cursors subscribe nobody.
|
|
209
|
+
not values from handler entry or the history cursor; so is `ui`. Buffer
|
|
210
|
+
queue/usage/`ui/*` events while awaiting the response, install the snapshots (an
|
|
211
|
+
empty queue clears stale state), then replay the buffered events. Invalid cursors subscribe nobody.
|
|
207
212
|
Install `runningTurn` before applying buffered deltas. `thread/replaced` moves
|
|
208
213
|
subscriptions to the new thread; captured old extension contexts become stale.
|
|
209
214
|
`thread/unsubscribe` returns `{status: "unsubscribed" | "notSubscribed"}`.
|
|
@@ -281,6 +286,117 @@ The most recent initiating subscriber is asked first. Disconnect or unsubscribe
|
|
|
281
286
|
cancels that attempt and migrates it to another subscriber; no subscribers means
|
|
282
287
|
cancel. `serverRequest/cancelled` withdraws an outstanding request.
|
|
283
288
|
|
|
289
|
+
## Dialogs and extension UI
|
|
290
|
+
|
|
291
|
+
What KnightCode asks the user mid-turn reaches a desktop connection as a server
|
|
292
|
+
request, asked the way approvals are; the thread reports `waitingOn: ["dialog"]`
|
|
293
|
+
meanwhile.
|
|
294
|
+
|
|
295
|
+
`item/toolCall/requestUserInput` carries `ask_user`'s questions, all at once,
|
|
296
|
+
with the `itemId` of the call asking, so a client can move back and forth
|
|
297
|
+
between them before answering. Each question has an `id`, its text and its
|
|
298
|
+
options (`label`, `description`); a label ending in `(Recommended)` is the
|
|
299
|
+
recommended one. Reply `{"answers": {"<id>": {"label": "..."}}}` with the
|
|
300
|
+
chosen option's exact label and an optional `note`, or `{"other": "..."}` for
|
|
301
|
+
the user's own answer; leave out a skipped question. `{}` dismisses the
|
|
302
|
+
questions and stops the turn.
|
|
303
|
+
|
|
304
|
+
`ui/dialog` carries the rest, such as the classifier gate's confirmation of a
|
|
305
|
+
risky call and plan mode's review. `kind` says which: a select carries
|
|
306
|
+
`options`, a confirm its `message`, an input its `placeholder`, an editor its
|
|
307
|
+
`prefill`. Reply with `{"value": "..."}` for a select, input or editor,
|
|
308
|
+
`{"confirmed": true}` for a confirm, or `{}` to cancel.
|
|
309
|
+
|
|
310
|
+
Notices such as "Downloaded model" arrive as the notification `ui/notify` with
|
|
311
|
+
a `level` of `info`, `warning` or `error`.
|
|
312
|
+
|
|
313
|
+
What an extension shows beside the transcript is the thread's extension UI:
|
|
314
|
+
|
|
315
|
+
- The `ui` of the `thread/start`, `thread/resume` and `thread/fork` results is
|
|
316
|
+
all of it as it stands when the response is written:
|
|
317
|
+
`{statuses: [{key, text}], title?, workingMessage?, workingVisible, widgets}`.
|
|
318
|
+
Statuses are sorted by key. Each widget is `{key, placement, lines}` or
|
|
319
|
+
`{key, placement, view}`, `placement` being `aboveEditor` or `belowEditor`;
|
|
320
|
+
those above come first, each group in the order they were last set.
|
|
321
|
+
- `ui/state` carries every field but the widgets, whole, whenever one changes.
|
|
322
|
+
An absent `title` or `workingMessage` is a cleared one.
|
|
323
|
+
`workingVisible: false` asks the client to hide its waiting indicator, and
|
|
324
|
+
`workingMessage` replaces its text.
|
|
325
|
+
- `ui/widget` carries one widget set or replaced (it moves to the end of its
|
|
326
|
+
placement), or `{threadId, key}` alone when it is removed.
|
|
327
|
+
|
|
328
|
+
Install `ui` from the result, then apply the notifications, buffered across a
|
|
329
|
+
resume as `queue` is. A `/reload` clears everything the old extensions showed,
|
|
330
|
+
with one `ui/state` and a removal per widget, before the new ones start. The
|
|
331
|
+
server strips ANSI escapes and keeps text on one line, at most 200 code points;
|
|
332
|
+
widget lines keep their spacing. A [view](declarative-views.md) is data, never
|
|
333
|
+
HTML; the server checked it before sending.
|
|
334
|
+
|
|
335
|
+
A button or field in a widget's view answers with the request `ui/event`
|
|
336
|
+
(below), which reaches every handler the thread's extensions registered with
|
|
337
|
+
`ctx.ui.onViewEvent`. Views on `toolCall` and `extensionMessage` items (their
|
|
338
|
+
optional `view`) are for display only.
|
|
339
|
+
|
|
340
|
+
Widget factories, `custom()` components, header and footer components, raw
|
|
341
|
+
terminal input and the working indicator draw only in the terminal: the server
|
|
342
|
+
writes one line to its log per method per thread load and draws nothing. Editor
|
|
343
|
+
access (`setEditorText`, `getEditorText`, `pasteToEditor`) does nothing.
|
|
344
|
+
Threads a terminal-mode connection loads have no dialogs or extension UI yet.
|
|
345
|
+
|
|
346
|
+
## Workspaces, diffs and git
|
|
347
|
+
|
|
348
|
+
A thread runs in a workspace: the user's checkout (`{mode: "local"}`), or a git
|
|
349
|
+
worktree of its own (`{mode: "worktree"}`), as in the Codex desktop app.
|
|
350
|
+
|
|
351
|
+
`thread/start {cwd, workspace: {mode: "worktree", baseRef?, carryLocalChanges?, environment?}}`
|
|
352
|
+
creates a worktree on a **detached `HEAD`** at `baseRef` (default:
|
|
353
|
+
the checkout's `HEAD`) under `<worktrees.root>/<4 hex digits>/<repository name>`
|
|
354
|
+
and runs the thread there, in the same subdirectory the `cwd` had. No branch is
|
|
355
|
+
created until `git/branch/create` or a handoff makes one. `carryLocalChanges`
|
|
356
|
+
brings the checkout's uncommitted changes (untracked files included, ignored
|
|
357
|
+
files not) along as uncommitted edits. Creation runs no hook, filter or user
|
|
358
|
+
code, so a failed creation leaves nothing behind. A start whose `cwd` is inside
|
|
359
|
+
a managed worktree is a new thread in that worktree.
|
|
360
|
+
|
|
361
|
+
`thread/workspace/progress {threadId, phase, output}` streams the output of an
|
|
362
|
+
environment's setup or cleanup script to the connection that asked. Every
|
|
363
|
+
`Thread` carries `workspace`; `ThreadSummary.workspaceMode` marks worktree
|
|
364
|
+
threads in listings.
|
|
365
|
+
|
|
366
|
+
Diffs come in Codex's Changes scopes: `lastTurn`, `uncommitted` (the default),
|
|
367
|
+
`unstaged`, `staged`, `committed` and `branch`. Each hunk has a content-hash id;
|
|
368
|
+
an action naming a hunk that changed since it was read answers `gitConflict`
|
|
369
|
+
with `data.reason: "diffChanged"`. Files changed while a turn ran are reported
|
|
370
|
+
by `turn/diff/updated {threadId, turnId, files}` after `turn/completed`, each
|
|
371
|
+
file as `{path, additions, deletions}`: the net line totals between the working
|
|
372
|
+
tree before and after the turn. A read-back turn carries the same list as
|
|
373
|
+
`Turn.files`. This
|
|
374
|
+
means "changed while the turn ran", not "changed by the turn": an edit another
|
|
375
|
+
local thread or an editor made meanwhile is in the list too. A worktree thread
|
|
376
|
+
is the only writer in its worktree, so its list is its own.
|
|
377
|
+
|
|
378
|
+
Review comments are drafts the client keeps. They travel with the next
|
|
379
|
+
`turn/start` or `turn/queue/add` as `comments`; the server quotes the commented
|
|
380
|
+
lines from the diff the user reviewed, and the user item shows the comments
|
|
381
|
+
next to the typed text.
|
|
382
|
+
|
|
383
|
+
**Reverting an added file deletes it**, an untracked one included. Clients
|
|
384
|
+
confirm with the user before a revert that removes files.
|
|
385
|
+
|
|
386
|
+
`thread/handoff` moves a chat and its uncommitted changes between its worktree
|
|
387
|
+
and the main checkout. The destination must be clean: "Stash or commit your
|
|
388
|
+
local changes to hand off." Archiving a thread deletes its worktree after a
|
|
389
|
+
snapshot, kept as `refs/knightcode/snapshots/<bucket>/<time>`, and
|
|
390
|
+
`thread/worktree/restore` rebuilds it. Past `worktrees.keep` worktrees, the
|
|
391
|
+
least recently used are pruned the same way. Outside a git repository, diff and
|
|
392
|
+
git methods answer `notGitRepo`.
|
|
393
|
+
|
|
394
|
+
`gitConflict` errors carry `data.reason`: `diffChanged`, `patchFailed`,
|
|
395
|
+
`concurrentChange`, `pushRejected`, `localChanges`, `operationInProgress`,
|
|
396
|
+
`branchExists`, `recoveryRequired`, `worktreeDeleted`, `worktreeMissing`,
|
|
397
|
+
`worktreeInUse` or `submodules`, with `paths`, `output` or
|
|
398
|
+
`recoveryInstructions` where they apply.
|
|
399
|
+
|
|
284
400
|
## Method reference
|
|
285
401
|
|
|
286
402
|
All methods require the handshake. Common errors are `notInitialized`,
|
|
@@ -300,12 +416,13 @@ Errors: `threadNotFound`.
|
|
|
300
416
|
|
|
301
417
|
### `config/read`
|
|
302
418
|
|
|
303
|
-
Params: optional `{cwd}`. Result: `{settings, origins, versions, errors}`.
|
|
419
|
+
Params: optional `{cwd}`. Result: `{settings, defaults, origins, versions, paths, errors}`.
|
|
304
420
|
Without cwd, only global settings are read. With cwd, trusted project settings
|
|
305
421
|
merge over global settings; untrusted project files are not read. `origins`
|
|
306
422
|
maps dotted leaf keys to `global` or `project`. `versions.global` and optional
|
|
307
423
|
`versions.project` are SHA-256 hashes of raw file contents, or `"none"` for an
|
|
308
|
-
absent or unread untrusted scope.
|
|
424
|
+
absent or unread untrusted scope. `defaults` is what an unset key means, in the
|
|
425
|
+
shape of `settings`; `paths` names the global and, with cwd, the project file. Settings, origins, versions, and parse errors
|
|
309
426
|
come from the same scope reads, not cached settings paired with fresh versions.
|
|
310
427
|
Parse errors appear as structured `source: "settings"` warnings with an
|
|
311
428
|
optional path and available one-based line/column; unaffected scopes still read.
|
|
@@ -336,6 +453,71 @@ malformed keys, and prototype-pollution segments (`__proto__`, `constructor`,
|
|
|
336
453
|
{"id":12,"method":"config/write","params":{"scope":"global","key":"theme","value":"dark","expectedVersion":"none"}}
|
|
337
454
|
```
|
|
338
455
|
|
|
456
|
+
### `tool/list`
|
|
457
|
+
|
|
458
|
+
Params: optional `{cwd}`. Result: `{tools: [{name, description, source}], defaultTools}`.
|
|
459
|
+
The tools a new thread in `cwd` would register (without cwd, a
|
|
460
|
+
project-less one), from an in-memory session like `command/list`'s; hidden tools
|
|
461
|
+
are left out, and MCP tools appear only once a thread connects. `defaultTools` is
|
|
462
|
+
the global `defaultTools` setting resolved (`+name` and `-name` applied), or the
|
|
463
|
+
built-in default `read`, `bash`, `edit`, `write`. Change it with `config/write`.
|
|
464
|
+
|
|
465
|
+
```json
|
|
466
|
+
{"id":26,"method":"tool/list","params":{}}
|
|
467
|
+
```
|
|
468
|
+
|
|
469
|
+
### `tool/settings/read` and `tool/settings/write`
|
|
470
|
+
|
|
471
|
+
The KnightCode tools `/tools` manages, stored in `tools.json` in the agent
|
|
472
|
+
directory. `tool/settings/read {}` returns
|
|
473
|
+
`{tools: [{name, enabled, settings}], classifiers: [{provider, id, name}]}`: each tool's state (its default when the
|
|
474
|
+
file does not set it) and its own settings, with values of keys ending in `Key`
|
|
475
|
+
masked to their last four characters; `classifiers` are the classifier models
|
|
476
|
+
with credentials, for the classifier gate's `model`.
|
|
477
|
+
`tool/settings/write {name, key, value}` sets one setting; `enabled` takes a boolean, other keys a string,
|
|
478
|
+
and `null` deletes the key. An unknown tool or a malformed key is
|
|
479
|
+
`invalidParams`.
|
|
480
|
+
|
|
481
|
+
```json
|
|
482
|
+
{"id":27,"method":"tool/settings/write","params":{"name":"websearch","key":"provider","value":"brave"}}
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
### `mcp/list`, `mcp/update`, `mcp/add` and `mcp/remove`
|
|
486
|
+
|
|
487
|
+
The servers of the global `mcp.json` and, for an explicitly trusted project, its
|
|
488
|
+
`.knightcode/mcp.json` ([MCP](mcp.md)). `mcp/list {cwd?}` returns
|
|
489
|
+
`{servers, errors, paths}`: each server's `name`, `scope`, defining file (`source`), the
|
|
490
|
+
project file that overrides it (`override`), `transport` (`stdio` or `http`),
|
|
491
|
+
`target` (command line or URL), `description`, `enabled` and `exposure`.
|
|
492
|
+
`mcp/update {cwd?, name, enabled?, exposure?}` saves the change where `/mcp`
|
|
493
|
+
would: in the project override when there is one, else in the defining file.
|
|
494
|
+
`mcp/add {scope, cwd?, name, config}` validates `config` as an `mcpServers` entry
|
|
495
|
+
and adds or replaces it (result `{replaced}`); `auth` is refused in a project
|
|
496
|
+
file. `mcp/remove {scope, cwd?, name}` returns `{removed}`. Project writes need
|
|
497
|
+
cwd and a trusted project (`invalidParams`, `data.reason: "untrusted"`).
|
|
498
|
+
Connections, sign-in and status belong to the MCP extension in each thread
|
|
499
|
+
(`/mcp`); loaded threads pick up file changes when they next load.
|
|
500
|
+
|
|
501
|
+
```json
|
|
502
|
+
{"id":28,"method":"mcp/add","params":{"scope":"global","name":"docs","config":{"url":"https://example.com/mcp"}}}
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### `resource/list` and `resource/set`
|
|
506
|
+
|
|
507
|
+
Extensions, skills, prompt templates and themes as `knightcode config` lists them.
|
|
508
|
+
`resource/list {cwd?}` returns
|
|
509
|
+
`{resources: [{type, path, name, enabled, scope, origin, source}]}` for what a thread in `cwd` (or with no project) would find,
|
|
510
|
+
installing nothing. Built-in extensions are left out: they are always on, so
|
|
511
|
+
`resource/set` refuses them like any unknown path. `resource/set {cwd?, type, path, enabled}` loads or
|
|
512
|
+
skips one resource with a `+` or `-` pattern in the settings of the scope that
|
|
513
|
+
defines it: a top-level resource in that scope's `extensions`, `skills`,
|
|
514
|
+
`prompts` or `themes`, a package's in that package's filter. Project resources
|
|
515
|
+
need a trusted project; an unknown path is `invalidParams`.
|
|
516
|
+
|
|
517
|
+
```json
|
|
518
|
+
{"id":29,"method":"resource/set","params":{"type":"skills","path":"/home/u/.knightcode/agent/skills/review/SKILL.md","enabled":false}}
|
|
519
|
+
```
|
|
520
|
+
|
|
339
521
|
### `project/trust/read`
|
|
340
522
|
|
|
341
523
|
Params: `{cwd}`. Result: `{trusted, needsTrust}`. `trusted` is true, false, or
|
|
@@ -394,6 +576,24 @@ and nothing is written. Built-in commands that only work in the terminal
|
|
|
394
576
|
{"id":17,"method":"command/list","params":{"cwd":"/path/to/project"}}
|
|
395
577
|
```
|
|
396
578
|
|
|
579
|
+
### `ui/event`
|
|
580
|
+
|
|
581
|
+
Params: `{threadId, widgetKey, id, value?}`. Result: `{}`. A press of the button
|
|
582
|
+
`id`, or a change of the field `id`, in the widget `widgetKey`'s view: `value` is
|
|
583
|
+
a string for a text or select field, a boolean for a toggle, and absent for a
|
|
584
|
+
button. Every handler of the thread gets `{widgetKey, id, value?}`; a handler
|
|
585
|
+
that fails becomes a `warning`. The extension answers by setting the widget
|
|
586
|
+
again: a field shows the view's value, not what was typed. A press of a widget or
|
|
587
|
+
control that is gone answers `{}` and reaches nobody.
|
|
588
|
+
|
|
589
|
+
Errors: `threadNotFound` when the thread is not loaded, and `invalidParams` when
|
|
590
|
+
the value does not fit the control (a toggle's string, a select value outside its
|
|
591
|
+
options, a button with a value).
|
|
592
|
+
|
|
593
|
+
```json
|
|
594
|
+
{"id":18,"method":"ui/event","params":{"threadId":"THREAD_ID","widgetKey":"checks","id":"verbose","value":true}}
|
|
595
|
+
```
|
|
596
|
+
|
|
397
597
|
### `thread/delete`
|
|
398
598
|
|
|
399
599
|
Params: `{threadId}`. Result: `{}`. Permanently removes an archived transcript;
|
|
@@ -425,6 +625,136 @@ Diagnostics observe the shared server, not only this connection.
|
|
|
425
625
|
{"id":18,"method":"server/diagnostics","params":{}}
|
|
426
626
|
```
|
|
427
627
|
|
|
628
|
+
### `thread/diff/read`
|
|
629
|
+
|
|
630
|
+
Params: `{threadId, scope?, against?, commit?, context?, ignoreWhitespace?}`.
|
|
631
|
+
Result: `{scope, root, files, filesOmitted?, untrackedSkipped?, turnId?, stale?, against?}`.
|
|
632
|
+
`files` are `{path, oldPath?, status, binary, additions, deletions, tooLarge?, hunks}`,
|
|
633
|
+
their paths relative to the repository's `root` (not the thread's cwd, which can
|
|
634
|
+
be a subdirectory of it); each hunk keeps its lines with their `" "`, `"+"`, `"-"` or
|
|
635
|
+
`"\"` prefix. `committed` needs `commit`; `branch` compares with `against`,
|
|
636
|
+
else the worktree's base, the upstream or the default branch, and echoes it.
|
|
637
|
+
More than 500 untracked files are counted in `untrackedSkipped` and left out.
|
|
638
|
+
Files past the response budget come without hunks (`tooLarge`) or are only
|
|
639
|
+
counted (`filesOmitted`). A hunk id hashes the file's header (its blob ids) and
|
|
640
|
+
the hunk at the read's `context`: an action must pass the same `context` (a
|
|
641
|
+
`context: 0` id matches no action), and after an action changes a file, read it
|
|
642
|
+
again, as its other hunks' ids change too. A hunk id from an `ignoreWhitespace` read matches no
|
|
643
|
+
action. Reads take no lock and never write the user's index.
|
|
644
|
+
Errors: `threadNotFound`, `notGitRepo`; `invalidParams` for a missing `commit`
|
|
645
|
+
or no branch to compare with.
|
|
646
|
+
|
|
647
|
+
```json
|
|
648
|
+
{"id":20,"method":"thread/diff/read","params":{"threadId":"THREAD_ID","scope":"uncommitted","context":3}}
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
### `thread/diff/revert`
|
|
652
|
+
|
|
653
|
+
Params: `{threadId, scope?, against?, commit?, path?, hunkId?, context?, reapply?, turnId?}`.
|
|
654
|
+
With `turnId` (`lastTurn` only), a last turn other than that one answers
|
|
655
|
+
`gitConflict` `diffChanged`, so an Undo shown on one turn never reverts a newer one.
|
|
656
|
+
Result: `{paths}`. Reverse-applies one hunk, one file, or the whole scope to the
|
|
657
|
+
working tree; `lastTurn` without a path undoes the turn, and only while every
|
|
658
|
+
affected file is exactly as the turn left it. With `reapply` (`lastTurn` only,
|
|
659
|
+
no hunk), the turn's changes apply again instead, and only while every affected
|
|
660
|
+
file is exactly as the turn found it. Hunks of renamed, added, deleted,
|
|
661
|
+
binary or mode-changed files revert as whole files only. Refused while a turn
|
|
662
|
+
runs in the checkout; no turn starts and no tool runs there until it ends.
|
|
663
|
+
Errors: `turnInProgress`; `invalidParams` for `staged` and `committed` or a
|
|
664
|
+
path outside the diff; `gitConflict` with `diffChanged` or `patchFailed`.
|
|
665
|
+
|
|
666
|
+
```json
|
|
667
|
+
{"id":21,"method":"thread/diff/revert","params":{"threadId":"THREAD_ID","path":"src/a.ts","hunkId":"HUNK_ID"}}
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
### `thread/handoff`
|
|
671
|
+
|
|
672
|
+
Params: `{threadId, to: "local" | "worktree", branch?, environment?}`. Result:
|
|
673
|
+
`{thread, branch?, warnings}`. To the main checkout: the worktree's `HEAD`
|
|
674
|
+
becomes a branch checked out there (the worktree's own branch, else `branch`,
|
|
675
|
+
else the previous handoff's branch fast-forwarded, else
|
|
676
|
+
`<worktrees.branchPrefix><title>`), the uncommitted changes move, and the
|
|
677
|
+
worktree stays, detached and clean. Back: the worktree is detached at the main
|
|
678
|
+
checkout's `HEAD` and the changes move into it; a thread born in the main
|
|
679
|
+
checkout gets a worktree. The changes are saved under `<agentDir>/handoff/`
|
|
680
|
+
before anything moves and leave the source only after they landed. The thread
|
|
681
|
+
is reloaded where it now runs: subscribers receive `thread/replaced` with the
|
|
682
|
+
same id, and queued inputs follow it.
|
|
683
|
+
Errors: `turnInProgress`; `invalidParams` for a thread with no message yet or
|
|
684
|
+
already on that side; `gitConflict` with `localChanges`,
|
|
685
|
+
`operationInProgress`, `branchExists`, `recoveryRequired` (with `data.patch`)
|
|
686
|
+
or `worktreeDeleted`.
|
|
687
|
+
|
|
688
|
+
```json
|
|
689
|
+
{"id":22,"method":"thread/handoff","params":{"threadId":"THREAD_ID","to":"local"}}
|
|
690
|
+
```
|
|
691
|
+
|
|
692
|
+
### `thread/worktree/restore`
|
|
693
|
+
|
|
694
|
+
Params: `{threadId}`. Result: `{thread}`. Rebuilds a deleted worktree at its
|
|
695
|
+
old path from its snapshot: detached at the old `HEAD`, with the working files
|
|
696
|
+
and the staged state as they were (ignored files were not kept). Then the
|
|
697
|
+
thread loads there.
|
|
698
|
+
Errors: `threadNotFound`; `invalidParams` when the worktree is not deleted;
|
|
699
|
+
`gitConflict` with `worktreeMissing` (deleted without a snapshot: fork the chat
|
|
700
|
+
into a new worktree instead) or `submodules`.
|
|
701
|
+
|
|
702
|
+
```json
|
|
703
|
+
{"id":23,"method":"thread/worktree/restore","params":{"threadId":"THREAD_ID"}}
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
### `worktree/list` and `worktree/delete`
|
|
707
|
+
|
|
708
|
+
`worktree/list {cwd?}` →
|
|
709
|
+
`{worktrees: [{path, projectCwd, head?, branch?, threadIds, lastUsedAt, deleted}]}`,
|
|
710
|
+
the managed worktrees (of `cwd`'s project
|
|
711
|
+
when given). `worktree/delete {path}` → `{snapshot?}` deletes one after its
|
|
712
|
+
snapshot. A worktree a thread is loaded in, or one holding a nested repository
|
|
713
|
+
(an initialized submodule or a repository inside it), is never deleted: archive
|
|
714
|
+
and pruning skip it, and `worktree/delete` answers `gitConflict` with
|
|
715
|
+
`worktreeInUse` or `submodules`. Only registrations in the managed layout are
|
|
716
|
+
removed; the user's own worktrees are never touched.
|
|
717
|
+
|
|
718
|
+
```json
|
|
719
|
+
{"id":24,"method":"worktree/delete","params":{"path":"/home/u/.knightcode/agent/worktrees/ab12/project"}}
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
### `environment/list` and `environment/save`
|
|
723
|
+
|
|
724
|
+
`environment/list {cwd}` → `{environments, trusted}` reads the project's
|
|
725
|
+
`.knightcode/environments.json`; `environment/save {cwd, environments}` writes
|
|
726
|
+
it (names unique, at most 50). An untrusted project's scripts never run. See
|
|
727
|
+
[Settings](settings.md#worktrees).
|
|
728
|
+
|
|
729
|
+
```json
|
|
730
|
+
{"id":25,"method":"environment/save","params":{"cwd":"/p","environments":[{"name":"node","setup":{"default":"cd \"$KNIGHTCODE_WORKTREE_PATH\" && npm ci"}}]}}
|
|
731
|
+
```
|
|
732
|
+
|
|
733
|
+
### `git/*`
|
|
734
|
+
|
|
735
|
+
Each acts on the thread's own checkout: its worktree, or the user's checkout.
|
|
736
|
+
`git/status` → branch, upstream, ahead/behind, staged/unstaged/untracked/
|
|
737
|
+
conflicted counts and an operation in progress. `git/stage` and `git/unstage`
|
|
738
|
+
take `{threadId, path?, hunkId?, context?}`: no path is everything; paths are
|
|
739
|
+
literal. `git/commit {threadId, message?, includeUnstaged?}` stages everything
|
|
740
|
+
first unless `includeUnstaged: false`; an empty message is written by the
|
|
741
|
+
thread's model from the staged diff, outside the conversation, and the commit
|
|
742
|
+
answers `concurrentChange` when the checkout changed meanwhile. The user's
|
|
743
|
+
hooks run. `git/push` pushes the current branch with one explicit,
|
|
744
|
+
non-forcing refspec and sets the upstream the first time.
|
|
745
|
+
`git/pr/create {threadId, title?, body?, draft?}` runs `gh pr create` (`toolMissing` without
|
|
746
|
+
`gh`). `git/branches`, `git/branch/create {name}` ("Create branch here"),
|
|
747
|
+
`git/branch/switch {name}` (refused when it would overwrite local changes or an
|
|
748
|
+
ignored file the branch tracks) and `git/log {limit?}` (the commits since the
|
|
749
|
+
base, for the `committed` scope) complete the set.
|
|
750
|
+
Errors: `notGitRepo`, `invalidParams`, `authRequired`, `toolMissing`;
|
|
751
|
+
`gitConflict` with `diffChanged`, `patchFailed`, `concurrentChange`,
|
|
752
|
+
`pushRejected`, `branchExists` or `localChanges`.
|
|
753
|
+
|
|
754
|
+
```json
|
|
755
|
+
{"id":26,"method":"git/commit","params":{"threadId":"THREAD_ID","includeUnstaged":true}}
|
|
756
|
+
```
|
|
757
|
+
|
|
428
758
|
## Ownership, unloading, and shutdown
|
|
429
759
|
|
|
430
760
|
Only one process may own a persisted session file. Symlink/junction aliases share
|
|
@@ -461,6 +791,14 @@ Limits count UTF-8 bytes:
|
|
|
461
791
|
- 1 MiB per history/list response, including envelope reserve.
|
|
462
792
|
- 64 KiB per inline turn/item; larger values use references.
|
|
463
793
|
- 48 KiB per payload chunk before base64 encoding.
|
|
794
|
+
- 64 KiB per view in a tool result or an extension message, as serialized JSON;
|
|
795
|
+
a larger or invalid view is dropped and the raw output or text shows.
|
|
796
|
+
- 16 KiB per widget (its lines or view), 16 widgets and 50 statuses per thread;
|
|
797
|
+
status and widget keys of 1 to 128 characters; status text, title and working
|
|
798
|
+
message cut to 200 code points. A refused widget or status gives one
|
|
799
|
+
`warning` per key per load (a load warning when it happened while the thread
|
|
800
|
+
loaded).
|
|
801
|
+
- Views nest stacks and lists at most 8 levels deep.
|
|
464
802
|
|
|
465
803
|
The in-repository `AppServerClient` supports typed `request`, `onNotification`,
|
|
466
804
|
`onRequest`, `readPayload`, `resolveTurn`, and `resolveItem` calls. Its
|