@dreb/coding-agent 2.34.3 → 2.36.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 (80) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +1 -1
  3. package/dist/cli/args.d.ts +3 -0
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +3 -0
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/core/agent-session.d.ts +30 -2
  8. package/dist/core/agent-session.d.ts.map +1 -1
  9. package/dist/core/agent-session.js +172 -130
  10. package/dist/core/agent-session.js.map +1 -1
  11. package/dist/core/export-html/template.js +1 -1
  12. package/dist/core/footer-data-provider.d.ts.map +1 -1
  13. package/dist/core/footer-data-provider.js +5 -102
  14. package/dist/core/footer-data-provider.js.map +1 -1
  15. package/dist/core/git-branch.d.ts +19 -0
  16. package/dist/core/git-branch.d.ts.map +1 -0
  17. package/dist/core/git-branch.js +109 -0
  18. package/dist/core/git-branch.js.map +1 -0
  19. package/dist/core/sdk.d.ts.map +1 -1
  20. package/dist/core/sdk.js +1 -1
  21. package/dist/core/sdk.js.map +1 -1
  22. package/dist/core/session-manager.d.ts +21 -0
  23. package/dist/core/session-manager.d.ts.map +1 -1
  24. package/dist/core/session-manager.js +117 -42
  25. package/dist/core/session-manager.js.map +1 -1
  26. package/dist/core/settings-manager.d.ts +6 -0
  27. package/dist/core/settings-manager.d.ts.map +1 -1
  28. package/dist/core/settings-manager.js +8 -0
  29. package/dist/core/settings-manager.js.map +1 -1
  30. package/dist/{modes/interactive → core}/tab-title.d.ts +12 -3
  31. package/dist/core/tab-title.d.ts.map +1 -0
  32. package/dist/{modes/interactive → core}/tab-title.js +58 -16
  33. package/dist/core/tab-title.js.map +1 -0
  34. package/dist/core/tools/search.d.ts.map +1 -1
  35. package/dist/core/tools/search.js +4 -1
  36. package/dist/core/tools/search.js.map +1 -1
  37. package/dist/core/tools/subagent.d.ts +63 -2
  38. package/dist/core/tools/subagent.d.ts.map +1 -1
  39. package/dist/core/tools/subagent.js +459 -73
  40. package/dist/core/tools/subagent.js.map +1 -1
  41. package/dist/core/tools/web.d.ts +1 -1
  42. package/dist/core/tools/web.d.ts.map +1 -1
  43. package/dist/core/tools/web.js +60 -16
  44. package/dist/core/tools/web.js.map +1 -1
  45. package/dist/main.d.ts +10 -0
  46. package/dist/main.d.ts.map +1 -1
  47. package/dist/main.js +54 -4
  48. package/dist/main.js.map +1 -1
  49. package/dist/modes/index.d.ts +2 -2
  50. package/dist/modes/index.d.ts.map +1 -1
  51. package/dist/modes/index.js +1 -1
  52. package/dist/modes/index.js.map +1 -1
  53. package/dist/modes/interactive/components/session-selector.d.ts +1 -1
  54. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  55. package/dist/modes/interactive/components/session-selector.js +4 -40
  56. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  57. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  58. package/dist/modes/interactive/interactive-mode.js +2 -2
  59. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  60. package/dist/modes/rpc/index.d.ts +2 -2
  61. package/dist/modes/rpc/index.d.ts.map +1 -1
  62. package/dist/modes/rpc/index.js.map +1 -1
  63. package/dist/modes/rpc/rpc-client.d.ts +114 -6
  64. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  65. package/dist/modes/rpc/rpc-client.js +140 -2
  66. package/dist/modes/rpc/rpc-client.js.map +1 -1
  67. package/dist/modes/rpc/rpc-mode.d.ts +97 -0
  68. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  69. package/dist/modes/rpc/rpc-mode.js +656 -27
  70. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  71. package/dist/modes/rpc/rpc-types.d.ts +312 -1
  72. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  73. package/dist/modes/rpc/rpc-types.js.map +1 -1
  74. package/docs/dashboard.md +254 -0
  75. package/docs/development.md +8 -5
  76. package/docs/rpc.md +652 -5
  77. package/examples/sdk/12-full-control.ts +1 -1
  78. package/package.json +1 -1
  79. package/dist/modes/interactive/tab-title.d.ts.map +0 -1
  80. package/dist/modes/interactive/tab-title.js.map +0 -1
package/docs/rpc.md CHANGED
@@ -6,10 +6,10 @@ RPC mode enables headless operation of the coding agent via a JSON protocol over
6
6
 
7
7
  ### Running the agent child as a specific OS user
8
8
 
9
- When using the `RpcClient` from `@dreb/coding-agent`, `RpcClientOptions` accepts optional `uid` and `gid` fields. When set, they are forwarded directly to `child_process.spawn`, so the agent child (and every subprocess it spawns, including `bash`) runs under that OS user/group. When unset they are omitted entirely, leaving spawn behavior unchanged.
9
+ When using the `RpcClient` from `@dreb/coding-agent/rpc`, `RpcClientOptions` accepts optional `uid` and `gid` fields. When set, they are forwarded directly to `child_process.spawn`, so the agent child (and every subprocess it spawns, including `bash`) runs under that OS user/group. When unset they are omitted entirely, leaving spawn behavior unchanged.
10
10
 
11
11
  ```ts
12
- import { RpcClient } from "@dreb/coding-agent";
12
+ import { RpcClient } from "@dreb/coding-agent/rpc";
13
13
 
14
14
  // Parent must hold CAP_SETUID / CAP_SETGID (e.g. run as root) for this to succeed.
15
15
  const client = new RpcClient({ cwd: "/srv/users/alice", uid: 4001, gid: 4001 });
@@ -187,6 +187,10 @@ Response:
187
187
  "success": true,
188
188
  "data": {
189
189
  "model": {...},
190
+ "scopedModels": [
191
+ {"provider": "anthropic", "id": "claude-sonnet-4-5", "name": "Claude Sonnet 4.5", "reasoning": true, "thinkingLevel": "high"}
192
+ ],
193
+ "usingSubscription": false,
190
194
  "thinkingLevel": "medium",
191
195
  "isStreaming": false,
192
196
  "isCompacting": false,
@@ -197,12 +201,79 @@ Response:
197
201
  "sessionName": "my-feature-work",
198
202
  "autoCompactionEnabled": true,
199
203
  "messageCount": 5,
200
- "pendingMessageCount": 0
204
+ "pendingMessageCount": 0,
205
+ "contextUsage": {
206
+ "tokens": 60000,
207
+ "contextWindow": 200000,
208
+ "percent": 30
209
+ }
201
210
  }
202
211
  }
203
212
  ```
204
213
 
205
- The `model` field is a full [Model](#model) object or `null`. The `sessionName` field is the display name set via `set_session_name`, or omitted if not set.
214
+ The `model` field is a full [Model](#model) object or `null`. `scopedModels` is the runtime model scope (from settings `enabledModels` / CLI `--models`) in the same order used by model cycling; it is an empty array when no scope is active. `usingSubscription` is true when the active model is using OAuth subscription credentials, matching the TUI footer's `(sub)` cost indicator. The `sessionName` field is the display name set via `set_session_name` or auto-naming, or omitted if not set.
215
+
216
+ `contextUsage` carries the same numbers the TUI footer shows, computed by the session itself — clients must render these rather than deriving their own estimate. `tokens` and `percent` are `null` when usage is unknown (right after compaction, before the next LLM response). The whole field is omitted when no model is set or the model has no context window.
217
+
218
+ #### get_resources
219
+
220
+ Get loaded resource metadata for the current session. This returns paths/names/descriptions only — it does not include context file contents, prompt bodies, skill bodies, or system prompt text.
221
+
222
+ ```json
223
+ {"type": "get_resources"}
224
+ ```
225
+
226
+ Response:
227
+ ```json
228
+ {
229
+ "type": "response",
230
+ "command": "get_resources",
231
+ "success": true,
232
+ "data": {
233
+ "contextFiles": [{"path": "/repo/AGENTS.md"}],
234
+ "skills": [{"name": "review-code", "description": "Review code"}],
235
+ "extensions": [{"name": "my-extension", "path": "/repo/.dreb/extensions/my-extension.ts"}],
236
+ "promptTemplates": [{"name": "plan", "description": "Create an implementation plan"}],
237
+ "systemPromptPresent": true
238
+ }
239
+ }
240
+ ```
241
+
242
+ #### get_git_branch
243
+
244
+ Get the current git branch for the session cwd. Returns `null` outside a git repository and `"detached"` for detached HEAD.
245
+
246
+ ```json
247
+ {"type": "get_git_branch"}
248
+ ```
249
+
250
+ Response:
251
+ ```json
252
+ {
253
+ "type": "response",
254
+ "command": "get_git_branch",
255
+ "success": true,
256
+ "data": {"branch": "feature/dashboard"}
257
+ }
258
+ ```
259
+
260
+ #### get_daily_cost
261
+
262
+ Get the same-day aggregate cost across all session files. The RPC process scans once on first call so the first response is current, then returns the cached value (refreshed periodically by the tracker).
263
+
264
+ ```json
265
+ {"type": "get_daily_cost"}
266
+ ```
267
+
268
+ Response:
269
+ ```json
270
+ {
271
+ "type": "response",
272
+ "command": "get_daily_cost",
273
+ "success": true,
274
+ "data": {"cost": 1.23}
275
+ }
276
+ ```
206
277
 
207
278
  #### get_messages
208
279
 
@@ -244,6 +315,29 @@ Response contains the full [Model](#model) object:
244
315
  }
245
316
  ```
246
317
 
318
+ #### resolve_model
319
+
320
+ Resolve a model pattern using the same matching rules as the interactive `/model` command, without switching the current session. Returns `null` if no model matches; a warning may be included when the match required fallback behavior.
321
+
322
+ ```json
323
+ {"type": "resolve_model", "pattern": "sonnet"}
324
+ ```
325
+
326
+ Response:
327
+ ```json
328
+ {
329
+ "type": "response",
330
+ "command": "resolve_model",
331
+ "success": true,
332
+ "data": {"model": {...}, "warning": "matched provider/model-id"}
333
+ }
334
+ ```
335
+
336
+ If no model matches:
337
+ ```json
338
+ {"type": "response", "command": "resolve_model", "success": true, "data": null}
339
+ ```
340
+
247
341
  #### cycle_model
248
342
 
249
343
  Cycle to the next available model. Returns `null` data if only one model available.
@@ -288,6 +382,46 @@ Response contains an array of full [Model](#model) objects:
288
382
  }
289
383
  ```
290
384
 
385
+ ### Buddy
386
+
387
+ Buddy commands run inside the agent process so provider credentials never leave the RPC child. They are exposed for clients that choose to render the terminal companion; most non-terminal clients can ignore them.
388
+
389
+ #### buddy_hatch
390
+
391
+ Create or load the current buddy state.
392
+
393
+ ```json
394
+ {"type": "buddy_hatch"}
395
+ ```
396
+
397
+ Response:
398
+ ```json
399
+ {
400
+ "type": "response",
401
+ "command": "buddy_hatch",
402
+ "success": true,
403
+ "data": {"state": {...}}
404
+ }
405
+ ```
406
+
407
+ #### buddy_reroll
408
+
409
+ Reroll buddy appearance/state.
410
+
411
+ ```json
412
+ {"type": "buddy_reroll"}
413
+ ```
414
+
415
+ Response:
416
+ ```json
417
+ {
418
+ "type": "response",
419
+ "command": "buddy_reroll",
420
+ "success": true,
421
+ "data": {"state": {...}}
422
+ }
423
+ ```
424
+
291
425
  ### Thinking
292
426
 
293
427
  #### set_thinking_level
@@ -361,6 +495,32 @@ Response:
361
495
  {"type": "response", "command": "set_follow_up_mode", "success": true}
362
496
  ```
363
497
 
498
+ #### get_pending_messages
499
+
500
+ Return queued steering and follow-up messages without clearing them. `steering` and `followUp` are the text-only compatibility view; `steeringMessages` and `followUpMessages` include inline image attachments for clients that need to restore queued multimodal turns.
501
+
502
+ ```json
503
+ {"type": "get_pending_messages"}
504
+ ```
505
+
506
+ Response:
507
+ ```json
508
+ {"type": "response", "command": "get_pending_messages", "success": true, "data": {"steering": ["steer text"], "followUp": ["follow-up text"], "steeringMessages": [{"text": "steer text", "images": [{"type": "image", "data": "...", "mimeType": "image/png"}]}], "followUpMessages": [{"text": "follow-up text"}]}}
509
+ ```
510
+
511
+ #### clear_pending_messages
512
+
513
+ Clear queued steering and follow-up messages, returning the cleared payloads. This mirrors the TUI restore-to-editor flow; multimodal clients should use `steeringMessages`/`followUpMessages` so inline images are not lost.
514
+
515
+ ```json
516
+ {"type": "clear_pending_messages"}
517
+ ```
518
+
519
+ Response:
520
+ ```json
521
+ {"type": "response", "command": "clear_pending_messages", "success": true, "data": {"steering": ["steer text"], "followUp": ["follow-up text"], "steeringMessages": [{"text": "steer text", "images": [{"type": "image", "data": "...", "mimeType": "image/png"}]}], "followUpMessages": [{"text": "follow-up text"}]}}
522
+ ```
523
+
364
524
  ### Compaction
365
525
 
366
526
  #### compact
@@ -404,6 +564,19 @@ Response:
404
564
  {"type": "response", "command": "set_auto_compaction", "success": true}
405
565
  ```
406
566
 
567
+ #### abort_compaction
568
+
569
+ Abort an in-progress manual or automatic compaction.
570
+
571
+ ```json
572
+ {"type": "abort_compaction"}
573
+ ```
574
+
575
+ Response:
576
+ ```json
577
+ {"type": "response", "command": "abort_compaction", "success": true}
578
+ ```
579
+
407
580
  ### Retry
408
581
 
409
582
  #### set_auto_retry
@@ -621,6 +794,39 @@ If an extension cancelled the switch:
621
794
  {"type": "response", "command": "switch_session", "success": true, "data": {"cancelled": true}}
622
795
  ```
623
796
 
797
+ #### delete_session
798
+
799
+ Delete a session file. Deletion tries trash first and falls back to unlink. The currently active session cannot be deleted.
800
+
801
+ ```json
802
+ {"type": "delete_session", "sessionPath": "/path/to/session.jsonl"}
803
+ ```
804
+
805
+ Response:
806
+ ```json
807
+ {"type": "response", "command": "delete_session", "success": true, "data": {"method": "trash"}}
808
+ ```
809
+
810
+ If attempting to delete the currently active session:
811
+ ```json
812
+ {
813
+ "type": "response",
814
+ "command": "delete_session",
815
+ "success": false,
816
+ "error": "Cannot delete the currently active session"
817
+ }
818
+ ```
819
+
820
+ The path uses the same unrestricted, cross-project addressing as [`switch_session`](#switch_session): it is `resolve()`d (collapsing `.`/`..`/relative segments) and then checked against the active session. There is **no** sessions-directory containment guard — this is a trusted local channel, and any frontend exposing it (e.g. the web dashboard) is expected to enforce its own authorization. Deletion is refused only for the currently active session, non-`.jsonl` paths, and nonexistent files:
821
+ ```json
822
+ {
823
+ "type": "response",
824
+ "command": "delete_session",
825
+ "success": false,
826
+ "error": "Not a session file (expected .jsonl): /tmp/evil.txt"
827
+ }
828
+ ```
829
+
624
830
  #### fork
625
831
 
626
832
  Create a new fork from a previous user message. Can be cancelled by a `session_before_fork` extension event handler. Returns the text of the message being forked from.
@@ -709,7 +915,7 @@ Response:
709
915
  }
710
916
  ```
711
917
 
712
- The current session name is available via `get_state` in the `sessionName` field.
918
+ The current session name is available via `get_state` in the `sessionName` field. Successful renames also emit a `session_name_changed` event.
713
919
 
714
920
  ### Commands
715
921
 
@@ -795,6 +1001,386 @@ Each session has:
795
1001
  - `messageCount`: Number of messages in the session
796
1002
  - `firstMessage`: First user message text (for preview)
797
1003
 
1004
+ #### list_all_sessions
1005
+
1006
+ List sessions across all projects. Returns sessions sorted by most recently modified first. May be slow with many sessions. If the underlying listing fails (an I/O error reading the sessions store), the command responds `success: false` rather than a silently-empty list — so a client can distinguish "no sessions" from "listing failed."
1007
+
1008
+ ```json
1009
+ {"type": "list_all_sessions"}
1010
+ ```
1011
+
1012
+ Response:
1013
+ ```json
1014
+ {
1015
+ "type": "response",
1016
+ "command": "list_all_sessions",
1017
+ "success": true,
1018
+ "data": {
1019
+ "sessions": [
1020
+ {
1021
+ "path": "/home/user/.dreb/agent/sessions/--home-user-project--/2024-01-15T10-30-00_abc123.jsonl",
1022
+ "id": "abc123-def456-...",
1023
+ "cwd": "/home/user/project",
1024
+ "name": "feature-work",
1025
+ "created": "2024-01-15T10:30:00.000Z",
1026
+ "modified": "2024-01-15T11:45:00.000Z",
1027
+ "messageCount": 12,
1028
+ "firstMessage": "Help me refactor the auth module"
1029
+ }
1030
+ ]
1031
+ }
1032
+ }
1033
+ ```
1034
+
1035
+ Each session has the same fields as `list_sessions`.
1036
+
1037
+ ### Background Agents
1038
+
1039
+ #### list_background_agents
1040
+
1041
+ List background subagents tracked by this process's registry — running and recently completed (finished entries are pruned after ~5 minutes). `sessionDir` is known from launch; `sessionFile` appears once the child process exits. Live transcripts are delivered via `background_agent_event` events (see Events), not by reading these paths.
1042
+
1043
+ ```json
1044
+ {"type": "list_background_agents"}
1045
+ ```
1046
+
1047
+ Response:
1048
+ ```json
1049
+ {
1050
+ "type": "response",
1051
+ "command": "list_background_agents",
1052
+ "success": true,
1053
+ "data": {
1054
+ "agents": [
1055
+ {
1056
+ "agentId": "a1b2c3d4e5f6",
1057
+ "agentType": "Explore",
1058
+ "taskSummary": "Explore task 1/2",
1059
+ "startedAt": "2026-07-07T12:00:00.000Z",
1060
+ "status": "running",
1061
+ "sessionDir": "/home/user/.dreb/agent/subagent-sessions/a1b2c3d4e5f6",
1062
+ "cwd": "/home/user/project"
1063
+ }
1064
+ ]
1065
+ }
1066
+ }
1067
+ ```
1068
+
1069
+ #### list_agent_types
1070
+
1071
+ List discoverable subagent types for the current session working directory. This includes package-bundled agents, user-level agents, and project-level agents in `.dreb/agents/*.md`. Results are sorted by `name`.
1072
+
1073
+ ```json
1074
+ {"type": "list_agent_types"}
1075
+ ```
1076
+
1077
+ Response:
1078
+ ```json
1079
+ {
1080
+ "type": "response",
1081
+ "command": "list_agent_types",
1082
+ "success": true,
1083
+ "data": {
1084
+ "agentTypes": [
1085
+ {
1086
+ "name": "code-reviewer",
1087
+ "description": "Reviews code changes for correctness, idiomatic patterns, and maintainability"
1088
+ },
1089
+ {
1090
+ "name": "Explore",
1091
+ "description": "Codebase and web exploration — find files, search code, search the web, answer questions. Read-only."
1092
+ }
1093
+ ]
1094
+ }
1095
+ }
1096
+ ```
1097
+
1098
+ Each agent type has:
1099
+ - `name`: Agent type name to use as an `agentModels` key.
1100
+ - `description`: Human-readable description from the agent frontmatter.
1101
+
1102
+ ### Session Tree
1103
+
1104
+ Sessions are append-only trees: editing/retrying a message or navigating back creates a branch rather than discarding entries. These commands expose tree inspection and navigation — the scriptable equivalent of the TUI's `/tree` selector.
1105
+
1106
+ #### get_tree
1107
+
1108
+ Get the session tree as a serializable DTO, plus the current leaf position.
1109
+
1110
+ ```json
1111
+ {"type": "get_tree"}
1112
+ ```
1113
+
1114
+ Response:
1115
+ ```json
1116
+ {
1117
+ "type": "response",
1118
+ "command": "get_tree",
1119
+ "success": true,
1120
+ "data": {
1121
+ "roots": [
1122
+ {
1123
+ "id": "a1b2c3d4",
1124
+ "parentId": null,
1125
+ "type": "message",
1126
+ "role": "user",
1127
+ "preview": "Help me refactor the auth module",
1128
+ "timestamp": "2024-01-15T10:30:00.000Z",
1129
+ "label": "start",
1130
+ "children": [
1131
+ {
1132
+ "id": "e5f6a7b8",
1133
+ "parentId": "a1b2c3d4",
1134
+ "type": "message",
1135
+ "role": "assistant",
1136
+ "preview": "Sure — let's look at the middleware first.",
1137
+ "timestamp": "2024-01-15T10:30:05.000Z",
1138
+ "children": []
1139
+ }
1140
+ ]
1141
+ }
1142
+ ],
1143
+ "leafId": "e5f6a7b8"
1144
+ }
1145
+ }
1146
+ ```
1147
+
1148
+ Each node has:
1149
+ - `id`: Entry id (use with `navigate_tree`, `fork`)
1150
+ - `parentId`: Parent entry id, or `null` for a root. Orphaned roots keep their original non-null `parentId` (referencing an entry not in the tree) — prefer `children` for hierarchy
1151
+ - `type`: Entry type (`message`, `compaction`, `branch_summary`, `model_change`, `thinking_level_change`, `custom`, `custom_message`, `label`, `session_info`)
1152
+ - `role`: Message role, present only for `type: "message"` entries (`user`, `assistant`, `toolResult`, `bashExecution`)
1153
+ - `preview`: Short single-line content preview (whitespace-collapsed, max 200 chars). Non-text entries use bracketed forms like `[compaction: 50k tokens]`, `[branch summary]: ...`, `[model: claude-sonnet-4]`, `[bash]: npm test`
1154
+ - `timestamp`: ISO timestamp of the entry
1155
+ - `label`: Resolved user label, if any
1156
+ - `children`: Child nodes, oldest first
1157
+
1158
+ `leafId` is the id of the current leaf entry (`null` for an empty session) — the "you are here" marker for a tree UI. The DTO is stable and deliberately does **not** include full message payloads; use `get_messages` for content after navigation.
1159
+
1160
+ A well-formed session has exactly one root; orphaned entries (broken parent chains) also surface as roots.
1161
+
1162
+ #### navigate_tree
1163
+
1164
+ Navigate the current session to a different tree node, optionally summarizing the abandoned branch. Unlike `fork` (which creates a new session file), navigation stays within the same session file.
1165
+
1166
+ ```json
1167
+ {"type": "navigate_tree", "targetId": "a1b2c3d4"}
1168
+ ```
1169
+
1170
+ With branch summarization:
1171
+ ```json
1172
+ {
1173
+ "type": "navigate_tree",
1174
+ "targetId": "a1b2c3d4",
1175
+ "summarize": true,
1176
+ "customInstructions": "Focus on decisions made",
1177
+ "replaceInstructions": false,
1178
+ "label": "before-refactor"
1179
+ }
1180
+ ```
1181
+
1182
+ Options (all optional, passed through verbatim to the core navigation — the TUI's interactive summarize prompt is not replicated):
1183
+ - `summarize`: Generate an LLM summary of the branch being abandoned and attach it at the navigation target. Requires a model and API key.
1184
+ - `customInstructions`: Extra instructions for the summarizer.
1185
+ - `replaceInstructions`: If `true`, `customInstructions` replaces the default summarizer prompt instead of augmenting it.
1186
+ - `label`: Label to attach to the branch summary entry (or to the target entry when not summarizing).
1187
+
1188
+ Response:
1189
+ ```json
1190
+ {
1191
+ "type": "response",
1192
+ "command": "navigate_tree",
1193
+ "success": true,
1194
+ "data": {"cancelled": false, "editorText": "Help me refactor the auth module"}
1195
+ }
1196
+ ```
1197
+
1198
+ - `cancelled`: `true` if an extension (`session_before_tree`) cancelled the navigation or summarization was aborted.
1199
+ - `editorText`: Present when navigating to a `user` (or `custom_message`) entry — the text of that message. The leaf moves to the entry's *parent* so the message can be re-edited and resubmitted; a client should pre-fill its input with this text (this is what the TUI does). Navigating to any other entry type moves the leaf to the entry itself and returns no `editorText`.
1200
+
1201
+ After a successful `navigate_tree`, `get_state` and `get_messages` reflect the post-navigation session state.
1202
+
1203
+ Errors are explicit `success: false` responses:
1204
+ ```json
1205
+ {
1206
+ "type": "response",
1207
+ "command": "navigate_tree",
1208
+ "success": false,
1209
+ "error": "Entry zzz not found"
1210
+ }
1211
+ ```
1212
+
1213
+ - Unknown `targetId`: `Entry <id> not found`
1214
+ - Agent currently streaming: `Cannot navigate the session tree while the agent is streaming. Abort or wait for idle first.`
1215
+ - Branch summarization or compaction in progress: `Cannot navigate the session tree while summarization or compaction is in progress. Wait for idle first.`
1216
+ - `summarize: true` with no model available: `No model available for summarization`
1217
+
1218
+ Note: with `summarize: true` the command is LLM-bound and can take a while. `RpcClient.navigateTree` uses a 5-minute client timeout (overridable via its client-side `timeoutMs` option, which is not sent over the wire); raw-protocol clients should budget accordingly. There is no scriptable abort for an in-flight branch summarization over RPC. A client-side timeout does not stop the server: a timed-out `navigate_tree` may still complete server-side and move the leaf — after a timeout, resync with `get_tree`/`get_state` instead of assuming the navigation failed.
1219
+
1220
+ ### Settings
1221
+
1222
+ Persistent default settings, backed by the settings file (see [settings.md](settings.md)). These are distinct from live session state:
1223
+
1224
+ - **Persistent defaults** (`get_settings` / `set_settings`): the values stored in `settings.json` that seed fresh runtimes — default provider/model, default thinking level, queue modes, compaction/retry/image/context/skill/thinking-display/transport toggles, and per-agent model fallback lists. Writing them does **not** change the running session.
1225
+ - **Runtime state** (`get_state` / `set_model` / `set_thinking_level` / `set_steering_mode` / `set_follow_up_mode` / `set_auto_compaction` / `set_auto_retry`): the state of the live session. Note that the runtime setters also persist their values as new defaults as a side effect.
1226
+
1227
+ A dashboard settings tab typically reads both: `get_state` for what's active now, `get_settings` for what the next startup will use.
1228
+
1229
+ #### get_settings
1230
+
1231
+ Get the persistent default settings (merged global + project view).
1232
+
1233
+ ```json
1234
+ {"type": "get_settings"}
1235
+ ```
1236
+
1237
+ Response:
1238
+ ```json
1239
+ {
1240
+ "type": "response",
1241
+ "command": "get_settings",
1242
+ "success": true,
1243
+ "data": {
1244
+ "defaultProvider": "anthropic",
1245
+ "defaultModel": "claude-sonnet-4-5",
1246
+ "defaultThinkingLevel": "high",
1247
+ "steeringMode": "one-at-a-time",
1248
+ "followUpMode": "one-at-a-time",
1249
+ "compactionEnabled": true,
1250
+ "retryEnabled": true,
1251
+ "imageAutoResize": true,
1252
+ "blockImages": false,
1253
+ "enableSkillCommands": true,
1254
+ "autoLoadNestedContext": true,
1255
+ "transport": "sse",
1256
+ "hideThinkingBlock": false,
1257
+ "agentModels": {
1258
+ "Explore": ["anthropic/sonnet", "openai/gpt-5"]
1259
+ }
1260
+ }
1261
+ }
1262
+ ```
1263
+
1264
+ `defaultProvider`, `defaultModel`, and `defaultThinkingLevel` are absent if never set. `agentModels` is the merged global + project view; project entries win per agent name.
1265
+
1266
+ #### set_settings
1267
+
1268
+ Update persistent default settings. Takes a partial payload — only the supplied keys change. The whole payload is validated before anything is applied: on any invalid field, nothing changes and the response is an explicit error. Writes target the global settings file (same scope as every runtime setter).
1269
+
1270
+ ```json
1271
+ {"type": "set_settings", "settings": {"defaultThinkingLevel": "low", "retryEnabled": false}}
1272
+ ```
1273
+
1274
+ Setting the default model (both keys required together, validated against available models — the provider must have credentials configured, same rule as `set_model`):
1275
+
1276
+ ```json
1277
+ {"type": "set_settings", "settings": {"defaultProvider": "anthropic", "defaultModel": "claude-sonnet-4-5"}}
1278
+ ```
1279
+
1280
+ Setting per-agent model fallback lists:
1281
+
1282
+ ```json
1283
+ {
1284
+ "type": "set_settings",
1285
+ "settings": {
1286
+ "agentModels": {
1287
+ "Explore": ["anthropic/sonnet", "openai/gpt-5"],
1288
+ "code-reviewer": []
1289
+ }
1290
+ }
1291
+ }
1292
+ ```
1293
+
1294
+ For `agentModels`, a non-empty array writes the global fallback list for that agent. An empty array removes the global entry, so that agent uses its agent-definition default unless a project-level override exists.
1295
+
1296
+ Response is the full settings snapshot after the write (same shape as `get_settings`), plus `warnings` when the write was accepted but a project-level override shadows part of it:
1297
+
1298
+ ```json
1299
+ {
1300
+ "type": "response",
1301
+ "command": "set_settings",
1302
+ "success": true,
1303
+ "data": {
1304
+ "defaultProvider": "anthropic",
1305
+ "defaultModel": "claude-sonnet-4-5",
1306
+ "defaultThinkingLevel": "low",
1307
+ "steeringMode": "one-at-a-time",
1308
+ "followUpMode": "one-at-a-time",
1309
+ "compactionEnabled": true,
1310
+ "retryEnabled": false,
1311
+ "imageAutoResize": true,
1312
+ "blockImages": false,
1313
+ "enableSkillCommands": true,
1314
+ "autoLoadNestedContext": true,
1315
+ "transport": "sse",
1316
+ "hideThinkingBlock": false,
1317
+ "agentModels": {}
1318
+ }
1319
+ }
1320
+ ```
1321
+
1322
+ Project-shadow warning example (the global write still lands, but the returned merged `agentModels.Explore` remains the project value until `.dreb/settings.json` is edited):
1323
+
1324
+ ```json
1325
+ {
1326
+ "type": "response",
1327
+ "command": "set_settings",
1328
+ "success": true,
1329
+ "data": {
1330
+ "steeringMode": "one-at-a-time",
1331
+ "followUpMode": "one-at-a-time",
1332
+ "compactionEnabled": true,
1333
+ "retryEnabled": true,
1334
+ "imageAutoResize": true,
1335
+ "blockImages": false,
1336
+ "enableSkillCommands": true,
1337
+ "autoLoadNestedContext": true,
1338
+ "transport": "sse",
1339
+ "hideThinkingBlock": false,
1340
+ "agentModels": {
1341
+ "Explore": ["project/model"]
1342
+ },
1343
+ "warnings": [
1344
+ "A project-level agentModels override for \"Explore\" (.dreb/settings.json) takes precedence — this change to global settings will have no effect. Edit the project settings file to change it."
1345
+ ]
1346
+ }
1347
+ }
1348
+ ```
1349
+
1350
+ Valid keys and values:
1351
+
1352
+ | Key | Values |
1353
+ |-----|--------|
1354
+ | `defaultProvider` + `defaultModel` | Must be supplied together; must match a model from `get_available_models` |
1355
+ | `defaultThinkingLevel` | `"off"`, `"minimal"`, `"low"`, `"medium"`, `"high"`, `"xhigh"` (validated against the full set — a stored default is not tied to the current model's capabilities) |
1356
+ | `steeringMode` | `"all"`, `"one-at-a-time"` |
1357
+ | `followUpMode` | `"all"`, `"one-at-a-time"` |
1358
+ | `compactionEnabled` | boolean |
1359
+ | `retryEnabled` | boolean |
1360
+ | `imageAutoResize` | boolean |
1361
+ | `blockImages` | boolean |
1362
+ | `enableSkillCommands` | boolean |
1363
+ | `autoLoadNestedContext` | boolean |
1364
+ | `transport` | `"sse"`, `"websocket"`, `"auto"` |
1365
+ | `hideThinkingBlock` | boolean |
1366
+ | `agentModels` | Plain object mapping agent names to arrays of non-empty model id strings; empty arrays remove the global entry for that agent |
1367
+
1368
+ Errors are explicit `success: false` responses (nothing is applied on any of them):
1369
+
1370
+ - Missing/empty payload: `set_settings requires at least one setting to change`
1371
+ - Unknown key: `Unknown settings key(s): ...`
1372
+ - Invalid enum value: `Invalid defaultThinkingLevel: "extreme". Valid values: off, minimal, low, medium, high, xhigh`
1373
+ - Invalid transport: `Invalid transport: "http". Valid values: sse, websocket, auto`
1374
+ - Non-boolean toggle: `Invalid retryEnabled: "yes". Must be a boolean`
1375
+ - Invalid `agentModels` object: `Invalid agentModels: must be a plain object mapping agent names to model fallback arrays`
1376
+ - Invalid `agentModels` entry (the offending agent key is named): `Invalid agentModels["Explore"]: expected an array of non-empty strings`
1377
+ - Provider without model (or vice versa): `defaultProvider and defaultModel must be set together`
1378
+ - Unavailable model: `Model not found: provider/model-id`
1379
+ - Corrupt settings file: `Cannot write settings: the global settings file failed to load (fix or remove the corrupt settings.json first)` — without this guard the write would silently no-op
1380
+ - Write failure (I/O error): `Failed to persist settings: ...`
1381
+
1382
+ Unlike `set_thinking_level` (which silently clamps to the current model's capabilities), `set_settings` rejects invalid values loudly — a dashboard needs the error, not a silent correction.
1383
+
798
1384
  ### Version
799
1385
 
800
1386
  #### get_version
@@ -833,12 +1419,24 @@ Events are streamed to stdout as JSON lines during agent operation. Events do NO
833
1419
  | `tool_execution_start` | Tool begins execution |
834
1420
  | `tool_execution_update` | Tool execution progress (streaming output) |
835
1421
  | `tool_execution_end` | Tool completes |
1422
+ | `stream_retry` | Stream dropped mid-turn; retrying (partial output discarded) |
1423
+ | `length_retry` | Response hit the token limit; retrying with a larger budget |
836
1424
  | `auto_compaction_start` | Auto-compaction begins |
837
1425
  | `auto_compaction_end` | Auto-compaction completes |
838
1426
  | `auto_retry_start` | Auto-retry begins (after transient error) |
839
1427
  | `auto_retry_end` | Auto-retry completes (success or final failure) |
1428
+ | `background_agent_start` | Background subagent launched (includes `sessionDir`) |
1429
+ | `background_agent_end` | Background subagent finished (includes `sessionFile` when known) |
1430
+ | `background_agent_event` | Relayed event from a background subagent's own stream |
1431
+ | `parent_paused_for_background_agents` | Parent paused waiting on background agents |
1432
+ | `session_name_changed` | Session display name changed (manual rename, extension rename, or auto-title) |
1433
+ | `tasks_update` | Session task list replaced (see the `tasks_update` tool) |
1434
+ | `suggest_next` | Agent suggested a next command |
840
1435
  | `extension_error` | Extension threw an error |
841
1436
 
1437
+ Treat the event union as open — dispatch on `type` and ignore unknown values
1438
+ rather than validating against a closed list; new event types may be added.
1439
+
842
1440
  ### agent_start
843
1441
 
844
1442
  Emitted when the agent begins processing a prompt. Includes the resolved model.
@@ -1032,6 +1630,55 @@ On final failure (max retries exceeded):
1032
1630
  }
1033
1631
  ```
1034
1632
 
1633
+ ### background_agent_start / background_agent_end / background_agent_event
1634
+
1635
+ Lifecycle and live-observability events for background subagents (the `subagent` tool's background mode).
1636
+
1637
+ `background_agent_start` fires at launch. `sessionDir` is the directory the child will write its session JSONL into (per-launch, known before spawn):
1638
+
1639
+ ```json
1640
+ {
1641
+ "type": "background_agent_start",
1642
+ "agentId": "a1b2c3d4e5f6",
1643
+ "agentType": "Explore",
1644
+ "taskSummary": "Explore task 1/2",
1645
+ "sessionDir": "/home/user/.dreb/agent/subagent-sessions/a1b2c3d4e5f6"
1646
+ }
1647
+ ```
1648
+
1649
+ `background_agent_end` fires after the result is delivered to the parent agent. `sessionFile` is the child's session JSONL path when one was written:
1650
+
1651
+ ```json
1652
+ {
1653
+ "type": "background_agent_end",
1654
+ "agentId": "a1b2c3d4e5f6",
1655
+ "agentType": "Explore",
1656
+ "success": true,
1657
+ "sessionFile": "/home/user/.dreb/agent/subagent-sessions/a1b2c3d4e5f6/2026-07-07T12-00-00-000Z_uuid.jsonl"
1658
+ }
1659
+ ```
1660
+
1661
+ `background_agent_event` relays every JSONL event the child process emits (the same event union documented here, plus the initial session header), verbatim, tagged with the child's `agentId`. This is the live-transcript transport for observers like the dashboard — no session-file tailing needed. Streaming children emit `message_update` deltas at high frequency; consumers that fan events out further (e.g. over a network) should batch or throttle:
1662
+
1663
+ ```json
1664
+ {
1665
+ "type": "background_agent_event",
1666
+ "agentId": "a1b2c3d4e5f6",
1667
+ "event": {"type": "tool_execution_start", "toolName": "read", "args": {"path": "src/index.ts"}}
1668
+ }
1669
+ ```
1670
+
1671
+ `parent_paused_for_background_agents` fires when the parent agent pauses because its background-agent turn guardrail was hit while agents are still running:
1672
+
1673
+ ```json
1674
+ {
1675
+ "type": "parent_paused_for_background_agents",
1676
+ "runningAgentCount": 2,
1677
+ "turnsUsed": 10,
1678
+ "turnLimit": 10
1679
+ }
1680
+ ```
1681
+
1035
1682
  ### extension_error
1036
1683
 
1037
1684
  Emitted when an extension throws an error.