@knightcodeai/cli 0.18.2 → 0.19.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.
Files changed (67) hide show
  1. package/CHANGELOG.md +92 -0
  2. package/dist/bundle/chunks/anthropic-messages-34POCEPV.js +6 -0
  3. package/dist/bundle/chunks/azure-openai-responses-ZZQJJY7B.js +2 -0
  4. package/dist/bundle/chunks/bedrock-converse-stream.js +2 -2
  5. package/dist/bundle/chunks/{chunk-IGNYWP4P.js → chunk-2QXUEOVY.js} +1 -1
  6. package/dist/bundle/chunks/{chunk-HNZSETB2.js → chunk-3QKQRXCZ.js} +4 -4
  7. package/dist/bundle/chunks/chunk-AA6MLWWY.js +2 -0
  8. package/dist/bundle/chunks/{chunk-NGWSYXD5.js → chunk-BTRAS32C.js} +2 -2
  9. package/dist/bundle/chunks/{chunk-LA7DDYYM.js → chunk-C62RVFZT.js} +9 -8
  10. package/dist/bundle/chunks/{chunk-MXIWLMNT.js → chunk-CCP7VAJU.js} +1 -1
  11. package/dist/bundle/chunks/{chunk-55AAX2FB.js → chunk-GPHSXYPT.js} +1 -1
  12. package/dist/bundle/chunks/{chunk-7CWBI3GL.js → chunk-IIS4JDFO.js} +153 -119
  13. package/dist/bundle/chunks/{chunk-3B66IKOZ.js → chunk-JSLSFYBX.js} +1 -1
  14. package/dist/bundle/chunks/{chunk-ZB5LGRB5.js → chunk-KRDGPCZM.js} +1 -1
  15. package/dist/bundle/chunks/chunk-OQHO44L6.js +16 -0
  16. package/dist/bundle/chunks/chunk-R7X2RAGR.js +30 -0
  17. package/dist/bundle/chunks/{chunk-R2XYMDTS.js → chunk-RZDCZFG7.js} +1 -1
  18. package/dist/bundle/chunks/chunk-T47GKPON.js +11 -0
  19. package/dist/bundle/chunks/chunk-UU4A4NV5.js +2 -0
  20. package/dist/bundle/chunks/{cli-66ZLURJW.js → cli-SIPOI5P3.js} +1 -1
  21. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-QHP5M5HC.js +2 -0
  22. package/dist/bundle/chunks/{easter-egg-3d-DQYQIGP2.js → easter-egg-3d-BVWLABZN.js} +1 -1
  23. package/dist/bundle/chunks/{execute-KJDH5JWX.js → execute-6UIHV2DR.js} +9 -3
  24. package/dist/bundle/chunks/github-copilot.js +1 -1
  25. package/dist/bundle/chunks/google-generative-ai-RFCCCXK6.js +2 -0
  26. package/dist/bundle/chunks/google-vertex-WN3JAZCD.js +2 -0
  27. package/dist/bundle/chunks/knightcode-messages-57CV36UV.js +8 -0
  28. package/dist/bundle/chunks/{llama-cpp-classify-HRPRKOZA.js → llama-cpp-classify-FEWC5ZIH.js} +2 -2
  29. package/dist/bundle/chunks/{mistral-conversations-FKYKJV7R.js → mistral-conversations-GIGX6BW6.js} +1 -1
  30. package/dist/bundle/chunks/openai-codex-responses-3Y7R752C.js +10 -0
  31. package/dist/bundle/chunks/openai-completions-HBXENZUJ.js +7 -0
  32. package/dist/bundle/chunks/{openai-decisions-OBTJNBTE.js → openai-decisions-MLI3SMFN.js} +1 -1
  33. package/dist/bundle/chunks/openai-responses-BNRA5YTD.js +4 -0
  34. package/dist/bundle/chunks/openrouter-images-JWVDFQJ4.js +2 -0
  35. package/dist/bundle/chunks/{runtime-IU2Z5WWF.js → runtime-AROIXIAV.js} +1 -1
  36. package/dist/bundle/chunks/typesafe-system-one-5LELZY2F.js +2 -0
  37. package/dist/bundle/chunks/virtual-modules-IYKQM2DL.js +2 -0
  38. package/dist/bundle/cli-runtime.js +1 -1
  39. package/dist/core/export-html/template.html +1 -0
  40. package/dist/core/export-html/template.js +2 -1
  41. package/dist/core/export-html/vendor/marked-cjk-friendly.min.js +6 -0
  42. package/dist/core/export-html/vendor/marked.min.js +30 -29
  43. package/docs/app-server.md +288 -8
  44. package/docs/app-server.schema.json +5414 -1636
  45. package/docs/codemode.md +2 -2
  46. package/docs/desktop.md +19 -4
  47. package/docs/environment-variables.md +1 -0
  48. package/docs/extensions.md +38 -21
  49. package/docs/settings.md +53 -0
  50. package/package.json +1 -1
  51. package/dist/bundle/chunks/anthropic-messages-QIZAJBTA.js +0 -6
  52. package/dist/bundle/chunks/azure-openai-responses-7R44RRTC.js +0 -2
  53. package/dist/bundle/chunks/chunk-76TARFPL.js +0 -11
  54. package/dist/bundle/chunks/chunk-HHWP56PR.js +0 -2
  55. package/dist/bundle/chunks/chunk-T7XWBYOA.js +0 -11
  56. package/dist/bundle/chunks/chunk-XZJICKQ6.js +0 -30
  57. package/dist/bundle/chunks/chunk-YQ26QP2R.js +0 -2
  58. package/dist/bundle/chunks/cloudflare-workers-ai-system-one-LA7TF5LV.js +0 -2
  59. package/dist/bundle/chunks/google-generative-ai-GEBPSQBJ.js +0 -2
  60. package/dist/bundle/chunks/google-vertex-BRMU44TN.js +0 -2
  61. package/dist/bundle/chunks/knightcode-messages-3GNOTMSI.js +0 -8
  62. package/dist/bundle/chunks/openai-codex-responses-DAZKF6IV.js +0 -10
  63. package/dist/bundle/chunks/openai-completions-A6RD26ED.js +0 -7
  64. package/dist/bundle/chunks/openai-responses-L3QPK3MQ.js +0 -3
  65. package/dist/bundle/chunks/openrouter-images-ZI7LLZ4Y.js +0 -2
  66. package/dist/bundle/chunks/typesafe-system-one-FZHRNG67.js +0 -2
  67. package/dist/bundle/chunks/virtual-modules-IKIDAUHO.js +0 -2
@@ -72,9 +72,10 @@ send a subscriber-only `warning` with `threadId`.
72
72
 
73
73
  Threads and list summaries include `createdAt` (header creation time) and
74
74
  optional `forkedFromId` (the parent's header ID, not a UUID inferred from its
75
- filename). List summaries use file modification time for `updatedAt`; loaded
76
- threads use the latest entry time, falling back to the header. Their `status`
77
- is one of:
75
+ filename). A loaded thread also carries `sessionFile`, the session file's path,
76
+ once it has been saved. List summaries use file modification time for
77
+ `updatedAt`; loaded threads use the latest entry time, falling back to the
78
+ header. Their `status` is one of:
78
79
 
79
80
  - `{type: "notLoaded"}`
80
81
  - `{type: "idle"}`
@@ -159,9 +160,12 @@ lands in a later turn. A steer cannot be taken back once accepted.
159
160
  input starts a turn of its own once the thread is idle, oldest first; on an idle
160
161
  thread it starts at once. Until it starts it is removable with
161
162
  `turn/queue/remove`. A queued input that fails to start (no model, signed out) is
162
- dropped with an `error` notification. `turn/queue/updated` sends
163
- `{threadId, steering: [text], followUp: [{id, text}]}`: steers the agent has not
164
- delivered yet, and the queued inputs.
163
+ dropped with an `error` notification carrying its `clientMessageId`, if it had
164
+ one. `turn/queue/updated` sends
165
+ `{threadId, steering: [text], followUp: [{id, text, attachments?}]}`: steers the
166
+ agent has not delivered yet, and the queued inputs. `text` is the user's own (not
167
+ a prompt composed with review comments); `attachments` counts the images and
168
+ review comments an input carries that its text alone does not.
165
169
 
166
170
  `turn/interrupt` accepts optional `turnId`; a supplied stale ID returns
167
171
  `turnMismatch`, while omitting it retains interrupt-current behavior. It drops
@@ -281,6 +285,86 @@ The most recent initiating subscriber is asked first. Disconnect or unsubscribe
281
285
  cancels that attempt and migrates it to another subscriber; no subscribers means
282
286
  cancel. `serverRequest/cancelled` withdraws an outstanding request.
283
287
 
288
+ ## Dialogs
289
+
290
+ What KnightCode asks the user mid-turn reaches a desktop connection as a server
291
+ request, asked the way approvals are; the thread reports `waitingOn: ["dialog"]`
292
+ meanwhile.
293
+
294
+ `item/toolCall/requestUserInput` carries `ask_user`'s questions, all at once,
295
+ with the `itemId` of the call asking, so a client can move back and forth
296
+ between them before answering. Each question has an `id`, its text and its
297
+ options (`label`, `description`); a label ending in `(Recommended)` is the
298
+ recommended one. Reply `{"answers": {"<id>": {"label": "..."}}}` with the
299
+ chosen option's exact label and an optional `note`, or `{"other": "..."}` for
300
+ the user's own answer; leave out a skipped question. `{}` dismisses the
301
+ questions and stops the turn.
302
+
303
+ `ui/dialog` carries the rest, such as the classifier gate's confirmation of a
304
+ risky call and plan mode's review. `kind` says which: a select carries
305
+ `options`, a confirm its `message`, an input its `placeholder`, an editor its
306
+ `prefill`. Reply with `{"value": "..."}` for a select, input or editor,
307
+ `{"confirmed": true}` for a confirm, or `{}` to cancel.
308
+
309
+ Notices such as "Downloaded model" arrive as the notification `ui/notify` with
310
+ a `level` of `info`, `warning` or `error`. Widgets, status, header, footer
311
+ and custom components draw only in the terminal and do nothing here. Threads a
312
+ terminal-mode connection loads have no dialogs yet.
313
+
314
+ ## Workspaces, diffs and git
315
+
316
+ A thread runs in a workspace: the user's checkout (`{mode: "local"}`), or a git
317
+ worktree of its own (`{mode: "worktree"}`), as in the Codex desktop app.
318
+
319
+ `thread/start {cwd, workspace: {mode: "worktree", baseRef?, carryLocalChanges?, environment?}}`
320
+ creates a worktree on a **detached `HEAD`** at `baseRef` (default:
321
+ the checkout's `HEAD`) under `<worktrees.root>/<4 hex digits>/<repository name>`
322
+ and runs the thread there, in the same subdirectory the `cwd` had. No branch is
323
+ created until `git/branch/create` or a handoff makes one. `carryLocalChanges`
324
+ brings the checkout's uncommitted changes (untracked files included, ignored
325
+ files not) along as uncommitted edits. Creation runs no hook, filter or user
326
+ code, so a failed creation leaves nothing behind. A start whose `cwd` is inside
327
+ a managed worktree is a new thread in that worktree.
328
+
329
+ `thread/workspace/progress {threadId, phase, output}` streams the output of an
330
+ environment's setup or cleanup script to the connection that asked. Every
331
+ `Thread` carries `workspace`; `ThreadSummary.workspaceMode` marks worktree
332
+ threads in listings.
333
+
334
+ Diffs come in Codex's Changes scopes: `lastTurn`, `uncommitted` (the default),
335
+ `unstaged`, `staged`, `committed` and `branch`. Each hunk has a content-hash id;
336
+ an action naming a hunk that changed since it was read answers `gitConflict`
337
+ with `data.reason: "diffChanged"`. Files changed while a turn ran are reported
338
+ by `turn/diff/updated {threadId, turnId, files}` after `turn/completed`, each
339
+ file as `{path, additions, deletions}`: the net line totals between the working
340
+ tree before and after the turn. A read-back turn carries the same list as
341
+ `Turn.files`. This
342
+ means "changed while the turn ran", not "changed by the turn": an edit another
343
+ local thread or an editor made meanwhile is in the list too. A worktree thread
344
+ is the only writer in its worktree, so its list is its own.
345
+
346
+ Review comments are drafts the client keeps. They travel with the next
347
+ `turn/start` or `turn/queue/add` as `comments`; the server quotes the commented
348
+ lines from the diff the user reviewed, and the user item shows the comments
349
+ next to the typed text.
350
+
351
+ **Reverting an added file deletes it**, an untracked one included. Clients
352
+ confirm with the user before a revert that removes files.
353
+
354
+ `thread/handoff` moves a chat and its uncommitted changes between its worktree
355
+ and the main checkout. The destination must be clean: "Stash or commit your
356
+ local changes to hand off." Archiving a thread deletes its worktree after a
357
+ snapshot, kept as `refs/knightcode/snapshots/<bucket>/<time>`, and
358
+ `thread/worktree/restore` rebuilds it. Past `worktrees.keep` worktrees, the
359
+ least recently used are pruned the same way. Outside a git repository, diff and
360
+ git methods answer `notGitRepo`.
361
+
362
+ `gitConflict` errors carry `data.reason`: `diffChanged`, `patchFailed`,
363
+ `concurrentChange`, `pushRejected`, `localChanges`, `operationInProgress`,
364
+ `branchExists`, `recoveryRequired`, `worktreeDeleted`, `worktreeMissing`,
365
+ `worktreeInUse` or `submodules`, with `paths`, `output` or
366
+ `recoveryInstructions` where they apply.
367
+
284
368
  ## Method reference
285
369
 
286
370
  All methods require the handshake. Common errors are `notInitialized`,
@@ -300,12 +384,13 @@ Errors: `threadNotFound`.
300
384
 
301
385
  ### `config/read`
302
386
 
303
- Params: optional `{cwd}`. Result: `{settings, origins, versions, errors}`.
387
+ Params: optional `{cwd}`. Result: `{settings, defaults, origins, versions, paths, errors}`.
304
388
  Without cwd, only global settings are read. With cwd, trusted project settings
305
389
  merge over global settings; untrusted project files are not read. `origins`
306
390
  maps dotted leaf keys to `global` or `project`. `versions.global` and optional
307
391
  `versions.project` are SHA-256 hashes of raw file contents, or `"none"` for an
308
- absent or unread untrusted scope. Settings, origins, versions, and parse errors
392
+ absent or unread untrusted scope. `defaults` is what an unset key means, in the
393
+ shape of `settings`; `paths` names the global and, with cwd, the project file. Settings, origins, versions, and parse errors
309
394
  come from the same scope reads, not cached settings paired with fresh versions.
310
395
  Parse errors appear as structured `source: "settings"` warnings with an
311
396
  optional path and available one-based line/column; unaffected scopes still read.
@@ -336,6 +421,71 @@ malformed keys, and prototype-pollution segments (`__proto__`, `constructor`,
336
421
  {"id":12,"method":"config/write","params":{"scope":"global","key":"theme","value":"dark","expectedVersion":"none"}}
337
422
  ```
338
423
 
424
+ ### `tool/list`
425
+
426
+ Params: optional `{cwd}`. Result: `{tools: [{name, description, source}], defaultTools}`.
427
+ The tools a new thread in `cwd` would register (without cwd, a
428
+ project-less one), from an in-memory session like `command/list`'s; hidden tools
429
+ are left out, and MCP tools appear only once a thread connects. `defaultTools` is
430
+ the global `defaultTools` setting resolved (`+name` and `-name` applied), or the
431
+ built-in default `read`, `bash`, `edit`, `write`. Change it with `config/write`.
432
+
433
+ ```json
434
+ {"id":26,"method":"tool/list","params":{}}
435
+ ```
436
+
437
+ ### `tool/settings/read` and `tool/settings/write`
438
+
439
+ The KnightCode tools `/tools` manages, stored in `tools.json` in the agent
440
+ directory. `tool/settings/read {}` returns
441
+ `{tools: [{name, enabled, settings}], classifiers: [{provider, id, name}]}`: each tool's state (its default when the
442
+ file does not set it) and its own settings, with values of keys ending in `Key`
443
+ masked to their last four characters; `classifiers` are the classifier models
444
+ with credentials, for the classifier gate's `model`.
445
+ `tool/settings/write {name, key, value}` sets one setting; `enabled` takes a boolean, other keys a string,
446
+ and `null` deletes the key. An unknown tool or a malformed key is
447
+ `invalidParams`.
448
+
449
+ ```json
450
+ {"id":27,"method":"tool/settings/write","params":{"name":"websearch","key":"provider","value":"brave"}}
451
+ ```
452
+
453
+ ### `mcp/list`, `mcp/update`, `mcp/add` and `mcp/remove`
454
+
455
+ The servers of the global `mcp.json` and, for an explicitly trusted project, its
456
+ `.knightcode/mcp.json` ([MCP](mcp.md)). `mcp/list {cwd?}` returns
457
+ `{servers, errors, paths}`: each server's `name`, `scope`, defining file (`source`), the
458
+ project file that overrides it (`override`), `transport` (`stdio` or `http`),
459
+ `target` (command line or URL), `description`, `enabled` and `exposure`.
460
+ `mcp/update {cwd?, name, enabled?, exposure?}` saves the change where `/mcp`
461
+ would: in the project override when there is one, else in the defining file.
462
+ `mcp/add {scope, cwd?, name, config}` validates `config` as an `mcpServers` entry
463
+ and adds or replaces it (result `{replaced}`); `auth` is refused in a project
464
+ file. `mcp/remove {scope, cwd?, name}` returns `{removed}`. Project writes need
465
+ cwd and a trusted project (`invalidParams`, `data.reason: "untrusted"`).
466
+ Connections, sign-in and status belong to the MCP extension in each thread
467
+ (`/mcp`); loaded threads pick up file changes when they next load.
468
+
469
+ ```json
470
+ {"id":28,"method":"mcp/add","params":{"scope":"global","name":"docs","config":{"url":"https://example.com/mcp"}}}
471
+ ```
472
+
473
+ ### `resource/list` and `resource/set`
474
+
475
+ Extensions, skills, prompt templates and themes as `knightcode config` lists them.
476
+ `resource/list {cwd?}` returns
477
+ `{resources: [{type, path, name, enabled, scope, origin, source}]}` for what a thread in `cwd` (or with no project) would find,
478
+ installing nothing. Built-in extensions are left out: they are always on, so
479
+ `resource/set` refuses them like any unknown path. `resource/set {cwd?, type, path, enabled}` loads or
480
+ skips one resource with a `+` or `-` pattern in the settings of the scope that
481
+ defines it: a top-level resource in that scope's `extensions`, `skills`,
482
+ `prompts` or `themes`, a package's in that package's filter. Project resources
483
+ need a trusted project; an unknown path is `invalidParams`.
484
+
485
+ ```json
486
+ {"id":29,"method":"resource/set","params":{"type":"skills","path":"/home/u/.knightcode/agent/skills/review/SKILL.md","enabled":false}}
487
+ ```
488
+
339
489
  ### `project/trust/read`
340
490
 
341
491
  Params: `{cwd}`. Result: `{trusted, needsTrust}`. `trusted` is true, false, or
@@ -425,6 +575,136 @@ Diagnostics observe the shared server, not only this connection.
425
575
  {"id":18,"method":"server/diagnostics","params":{}}
426
576
  ```
427
577
 
578
+ ### `thread/diff/read`
579
+
580
+ Params: `{threadId, scope?, against?, commit?, context?, ignoreWhitespace?}`.
581
+ Result: `{scope, root, files, filesOmitted?, untrackedSkipped?, turnId?, stale?, against?}`.
582
+ `files` are `{path, oldPath?, status, binary, additions, deletions, tooLarge?, hunks}`,
583
+ their paths relative to the repository's `root` (not the thread's cwd, which can
584
+ be a subdirectory of it); each hunk keeps its lines with their `" "`, `"+"`, `"-"` or
585
+ `"\"` prefix. `committed` needs `commit`; `branch` compares with `against`,
586
+ else the worktree's base, the upstream or the default branch, and echoes it.
587
+ More than 500 untracked files are counted in `untrackedSkipped` and left out.
588
+ Files past the response budget come without hunks (`tooLarge`) or are only
589
+ counted (`filesOmitted`). A hunk id hashes the file's header (its blob ids) and
590
+ the hunk at the read's `context`: an action must pass the same `context` (a
591
+ `context: 0` id matches no action), and after an action changes a file, read it
592
+ again, as its other hunks' ids change too. A hunk id from an `ignoreWhitespace` read matches no
593
+ action. Reads take no lock and never write the user's index.
594
+ Errors: `threadNotFound`, `notGitRepo`; `invalidParams` for a missing `commit`
595
+ or no branch to compare with.
596
+
597
+ ```json
598
+ {"id":20,"method":"thread/diff/read","params":{"threadId":"THREAD_ID","scope":"uncommitted","context":3}}
599
+ ```
600
+
601
+ ### `thread/diff/revert`
602
+
603
+ Params: `{threadId, scope?, against?, commit?, path?, hunkId?, context?, reapply?, turnId?}`.
604
+ With `turnId` (`lastTurn` only), a last turn other than that one answers
605
+ `gitConflict` `diffChanged`, so an Undo shown on one turn never reverts a newer one.
606
+ Result: `{paths}`. Reverse-applies one hunk, one file, or the whole scope to the
607
+ working tree; `lastTurn` without a path undoes the turn, and only while every
608
+ affected file is exactly as the turn left it. With `reapply` (`lastTurn` only,
609
+ no hunk), the turn's changes apply again instead, and only while every affected
610
+ file is exactly as the turn found it. Hunks of renamed, added, deleted,
611
+ binary or mode-changed files revert as whole files only. Refused while a turn
612
+ runs in the checkout; no turn starts and no tool runs there until it ends.
613
+ Errors: `turnInProgress`; `invalidParams` for `staged` and `committed` or a
614
+ path outside the diff; `gitConflict` with `diffChanged` or `patchFailed`.
615
+
616
+ ```json
617
+ {"id":21,"method":"thread/diff/revert","params":{"threadId":"THREAD_ID","path":"src/a.ts","hunkId":"HUNK_ID"}}
618
+ ```
619
+
620
+ ### `thread/handoff`
621
+
622
+ Params: `{threadId, to: "local" | "worktree", branch?, environment?}`. Result:
623
+ `{thread, branch?, warnings}`. To the main checkout: the worktree's `HEAD`
624
+ becomes a branch checked out there (the worktree's own branch, else `branch`,
625
+ else the previous handoff's branch fast-forwarded, else
626
+ `<worktrees.branchPrefix><title>`), the uncommitted changes move, and the
627
+ worktree stays, detached and clean. Back: the worktree is detached at the main
628
+ checkout's `HEAD` and the changes move into it; a thread born in the main
629
+ checkout gets a worktree. The changes are saved under `<agentDir>/handoff/`
630
+ before anything moves and leave the source only after they landed. The thread
631
+ is reloaded where it now runs: subscribers receive `thread/replaced` with the
632
+ same id, and queued inputs follow it.
633
+ Errors: `turnInProgress`; `invalidParams` for a thread with no message yet or
634
+ already on that side; `gitConflict` with `localChanges`,
635
+ `operationInProgress`, `branchExists`, `recoveryRequired` (with `data.patch`)
636
+ or `worktreeDeleted`.
637
+
638
+ ```json
639
+ {"id":22,"method":"thread/handoff","params":{"threadId":"THREAD_ID","to":"local"}}
640
+ ```
641
+
642
+ ### `thread/worktree/restore`
643
+
644
+ Params: `{threadId}`. Result: `{thread}`. Rebuilds a deleted worktree at its
645
+ old path from its snapshot: detached at the old `HEAD`, with the working files
646
+ and the staged state as they were (ignored files were not kept). Then the
647
+ thread loads there.
648
+ Errors: `threadNotFound`; `invalidParams` when the worktree is not deleted;
649
+ `gitConflict` with `worktreeMissing` (deleted without a snapshot: fork the chat
650
+ into a new worktree instead) or `submodules`.
651
+
652
+ ```json
653
+ {"id":23,"method":"thread/worktree/restore","params":{"threadId":"THREAD_ID"}}
654
+ ```
655
+
656
+ ### `worktree/list` and `worktree/delete`
657
+
658
+ `worktree/list {cwd?}` →
659
+ `{worktrees: [{path, projectCwd, head?, branch?, threadIds, lastUsedAt, deleted}]}`,
660
+ the managed worktrees (of `cwd`'s project
661
+ when given). `worktree/delete {path}` → `{snapshot?}` deletes one after its
662
+ snapshot. A worktree a thread is loaded in, or one holding a nested repository
663
+ (an initialized submodule or a repository inside it), is never deleted: archive
664
+ and pruning skip it, and `worktree/delete` answers `gitConflict` with
665
+ `worktreeInUse` or `submodules`. Only registrations in the managed layout are
666
+ removed; the user's own worktrees are never touched.
667
+
668
+ ```json
669
+ {"id":24,"method":"worktree/delete","params":{"path":"/home/u/.knightcode/agent/worktrees/ab12/project"}}
670
+ ```
671
+
672
+ ### `environment/list` and `environment/save`
673
+
674
+ `environment/list {cwd}` → `{environments, trusted}` reads the project's
675
+ `.knightcode/environments.json`; `environment/save {cwd, environments}` writes
676
+ it (names unique, at most 50). An untrusted project's scripts never run. See
677
+ [Settings](settings.md#worktrees).
678
+
679
+ ```json
680
+ {"id":25,"method":"environment/save","params":{"cwd":"/p","environments":[{"name":"node","setup":{"default":"cd \"$KNIGHTCODE_WORKTREE_PATH\" && npm ci"}}]}}
681
+ ```
682
+
683
+ ### `git/*`
684
+
685
+ Each acts on the thread's own checkout: its worktree, or the user's checkout.
686
+ `git/status` → branch, upstream, ahead/behind, staged/unstaged/untracked/
687
+ conflicted counts and an operation in progress. `git/stage` and `git/unstage`
688
+ take `{threadId, path?, hunkId?, context?}`: no path is everything; paths are
689
+ literal. `git/commit {threadId, message?, includeUnstaged?}` stages everything
690
+ first unless `includeUnstaged: false`; an empty message is written by the
691
+ thread's model from the staged diff, outside the conversation, and the commit
692
+ answers `concurrentChange` when the checkout changed meanwhile. The user's
693
+ hooks run. `git/push` pushes the current branch with one explicit,
694
+ non-forcing refspec and sets the upstream the first time.
695
+ `git/pr/create {threadId, title?, body?, draft?}` runs `gh pr create` (`toolMissing` without
696
+ `gh`). `git/branches`, `git/branch/create {name}` ("Create branch here"),
697
+ `git/branch/switch {name}` (refused when it would overwrite local changes or an
698
+ ignored file the branch tracks) and `git/log {limit?}` (the commits since the
699
+ base, for the `committed` scope) complete the set.
700
+ Errors: `notGitRepo`, `invalidParams`, `authRequired`, `toolMissing`;
701
+ `gitConflict` with `diffChanged`, `patchFailed`, `concurrentChange`,
702
+ `pushRejected`, `branchExists` or `localChanges`.
703
+
704
+ ```json
705
+ {"id":26,"method":"git/commit","params":{"threadId":"THREAD_ID","includeUnstaged":true}}
706
+ ```
707
+
428
708
  ## Ownership, unloading, and shutdown
429
709
 
430
710
  Only one process may own a persisted session file. Symlink/junction aliases share