indusagi-coding-agent 0.1.23 → 0.1.25

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 (236) hide show
  1. package/CHANGELOG.md +101 -0
  2. package/README.md +2 -0
  3. package/dist/cli/args.d.ts +117 -1
  4. package/dist/cli/args.d.ts.map +1 -1
  5. package/dist/cli/args.js +221 -52
  6. package/dist/cli/args.js.map +1 -1
  7. package/dist/cli/config-selector.d.ts +58 -2
  8. package/dist/cli/config-selector.d.ts.map +1 -1
  9. package/dist/cli/config-selector.js +130 -12
  10. package/dist/cli/config-selector.js.map +1 -1
  11. package/dist/cli/file-processor.d.ts +70 -2
  12. package/dist/cli/file-processor.d.ts.map +1 -1
  13. package/dist/cli/file-processor.js +240 -15
  14. package/dist/cli/file-processor.js.map +1 -1
  15. package/dist/cli/list-models.d.ts +63 -3
  16. package/dist/cli/list-models.d.ts.map +1 -1
  17. package/dist/cli/list-models.js +202 -27
  18. package/dist/cli/list-models.js.map +1 -1
  19. package/dist/cli/login-handler.d.ts +82 -8
  20. package/dist/cli/login-handler.d.ts.map +1 -1
  21. package/dist/cli/login-handler.js +410 -77
  22. package/dist/cli/login-handler.js.map +1 -1
  23. package/dist/cli/session-picker.d.ts +74 -2
  24. package/dist/cli/session-picker.d.ts.map +1 -1
  25. package/dist/cli/session-picker.js +236 -12
  26. package/dist/cli/session-picker.js.map +1 -1
  27. package/dist/core/agent-session.d.ts +214 -9
  28. package/dist/core/agent-session.d.ts.map +1 -1
  29. package/dist/core/agent-session.js +214 -9
  30. package/dist/core/agent-session.js.map +1 -1
  31. package/dist/core/bash-executor.d.ts +302 -12
  32. package/dist/core/bash-executor.d.ts.map +1 -1
  33. package/dist/core/bash-executor.js +302 -12
  34. package/dist/core/bash-executor.js.map +1 -1
  35. package/dist/core/diagnostics.d.ts +191 -0
  36. package/dist/core/diagnostics.d.ts.map +1 -1
  37. package/dist/core/diagnostics.js +142 -0
  38. package/dist/core/diagnostics.js.map +1 -1
  39. package/dist/core/discover-packages.d.ts +6 -0
  40. package/dist/core/discover-packages.d.ts.map +1 -0
  41. package/dist/core/discover-packages.js +62 -0
  42. package/dist/core/discover-packages.js.map +1 -0
  43. package/dist/core/event-bus.d.ts +146 -0
  44. package/dist/core/event-bus.d.ts.map +1 -1
  45. package/dist/core/event-bus.js +93 -0
  46. package/dist/core/event-bus.js.map +1 -1
  47. package/dist/core/export-html/ansi-to-html.d.ts +4 -0
  48. package/dist/core/export-html/ansi-to-html.d.ts.map +1 -1
  49. package/dist/core/export-html/ansi-to-html.js +4 -0
  50. package/dist/core/export-html/ansi-to-html.js.map +1 -1
  51. package/dist/core/export-html/index.d.ts +128 -0
  52. package/dist/core/export-html/index.d.ts.map +1 -1
  53. package/dist/core/export-html/index.js +128 -0
  54. package/dist/core/export-html/index.js.map +1 -1
  55. package/dist/core/export-html/tool-renderer.d.ts +4 -0
  56. package/dist/core/export-html/tool-renderer.d.ts.map +1 -1
  57. package/dist/core/export-html/tool-renderer.js +4 -0
  58. package/dist/core/export-html/tool-renderer.js.map +1 -1
  59. package/dist/core/keybindings.d.ts +142 -0
  60. package/dist/core/keybindings.d.ts.map +1 -1
  61. package/dist/core/keybindings.js +142 -0
  62. package/dist/core/keybindings.js.map +1 -1
  63. package/dist/core/model-registry.d.ts +98 -1
  64. package/dist/core/model-registry.d.ts.map +1 -1
  65. package/dist/core/model-registry.js +98 -1
  66. package/dist/core/model-registry.js.map +1 -1
  67. package/dist/core/model-resolver.d.ts +99 -1
  68. package/dist/core/model-resolver.d.ts.map +1 -1
  69. package/dist/core/model-resolver.js +99 -1
  70. package/dist/core/model-resolver.js.map +1 -1
  71. package/dist/core/prompt-templates.js.map +1 -1
  72. package/dist/core/sdk.d.ts.map +1 -1
  73. package/dist/core/sdk.js +2 -0
  74. package/dist/core/sdk.js.map +1 -1
  75. package/dist/core/session-manager.d.ts +127 -0
  76. package/dist/core/session-manager.d.ts.map +1 -1
  77. package/dist/core/session-manager.js +125 -0
  78. package/dist/core/session-manager.js.map +1 -1
  79. package/dist/core/skills.js.map +1 -1
  80. package/dist/core/subagents.js.map +1 -1
  81. package/dist/core/tools/bash.d.ts +391 -11
  82. package/dist/core/tools/bash.d.ts.map +1 -1
  83. package/dist/core/tools/bash.js +269 -2
  84. package/dist/core/tools/bash.js.map +1 -1
  85. package/dist/core/tools/bg-process.d.ts +49 -0
  86. package/dist/core/tools/bg-process.d.ts.map +1 -0
  87. package/dist/core/tools/bg-process.js +69 -0
  88. package/dist/core/tools/bg-process.js.map +1 -0
  89. package/dist/core/tools/edit.d.ts +284 -6
  90. package/dist/core/tools/edit.d.ts.map +1 -1
  91. package/dist/core/tools/edit.js +238 -0
  92. package/dist/core/tools/edit.js.map +1 -1
  93. package/dist/core/tools/find.d.ts +169 -5
  94. package/dist/core/tools/find.d.ts.map +1 -1
  95. package/dist/core/tools/find.js +136 -0
  96. package/dist/core/tools/find.js.map +1 -1
  97. package/dist/core/tools/grep.d.ts +285 -5
  98. package/dist/core/tools/grep.d.ts.map +1 -1
  99. package/dist/core/tools/grep.js +247 -0
  100. package/dist/core/tools/grep.js.map +1 -1
  101. package/dist/core/tools/index.d.ts +45 -0
  102. package/dist/core/tools/index.d.ts.map +1 -1
  103. package/dist/core/tools/index.js +15 -0
  104. package/dist/core/tools/index.js.map +1 -1
  105. package/dist/core/tools/ls.d.ts +6 -0
  106. package/dist/core/tools/ls.d.ts.map +1 -1
  107. package/dist/core/tools/ls.js +6 -0
  108. package/dist/core/tools/ls.js.map +1 -1
  109. package/dist/core/tools/read.d.ts +308 -7
  110. package/dist/core/tools/read.d.ts.map +1 -1
  111. package/dist/core/tools/read.js +231 -0
  112. package/dist/core/tools/read.js.map +1 -1
  113. package/dist/core/tools/registry.d.ts +17 -0
  114. package/dist/core/tools/registry.d.ts.map +1 -0
  115. package/dist/core/tools/registry.js +108 -0
  116. package/dist/core/tools/registry.js.map +1 -0
  117. package/dist/core/tools/webfetch.d.ts +118 -3
  118. package/dist/core/tools/webfetch.d.ts.map +1 -1
  119. package/dist/core/tools/webfetch.js +118 -3
  120. package/dist/core/tools/webfetch.js.map +1 -1
  121. package/dist/core/tools/websearch.d.ts +130 -3
  122. package/dist/core/tools/websearch.d.ts.map +1 -1
  123. package/dist/core/tools/websearch.js +130 -3
  124. package/dist/core/tools/websearch.js.map +1 -1
  125. package/dist/core/tools/write.d.ts +251 -5
  126. package/dist/core/tools/write.d.ts.map +1 -1
  127. package/dist/core/tools/write.js +210 -0
  128. package/dist/core/tools/write.js.map +1 -1
  129. package/dist/main.d.ts.map +1 -1
  130. package/dist/main.js +12 -1
  131. package/dist/main.js.map +1 -1
  132. package/dist/modes/interactive/components/assistant-message.d.ts +164 -1
  133. package/dist/modes/interactive/components/assistant-message.d.ts.map +1 -1
  134. package/dist/modes/interactive/components/assistant-message.js +164 -1
  135. package/dist/modes/interactive/components/assistant-message.js.map +1 -1
  136. package/dist/modes/interactive/components/bash-execution.d.ts +297 -1
  137. package/dist/modes/interactive/components/bash-execution.d.ts.map +1 -1
  138. package/dist/modes/interactive/components/bash-execution.js +297 -1
  139. package/dist/modes/interactive/components/bash-execution.js.map +1 -1
  140. package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
  141. package/dist/modes/interactive/components/tool-execution.js +251 -1
  142. package/dist/modes/interactive/components/tool-execution.js.map +1 -1
  143. package/dist/modes/interactive/components/user-message.d.ts +186 -1
  144. package/dist/modes/interactive/components/user-message.d.ts.map +1 -1
  145. package/dist/modes/interactive/components/user-message.js +186 -1
  146. package/dist/modes/interactive/components/user-message.js.map +1 -1
  147. package/dist/modes/interactive/interactive-mode.d.ts +1567 -13
  148. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  149. package/dist/modes/interactive/interactive-mode.js +1567 -13
  150. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  151. package/dist/modes/interactive/theme/theme.d.ts +422 -0
  152. package/dist/modes/interactive/theme/theme.d.ts.map +1 -1
  153. package/dist/modes/interactive/theme/theme.js +422 -0
  154. package/dist/modes/interactive/theme/theme.js.map +1 -1
  155. package/dist/modes/print-mode.d.ts +538 -5
  156. package/dist/modes/print-mode.d.ts.map +1 -1
  157. package/dist/modes/print-mode.js +538 -5
  158. package/dist/modes/print-mode.js.map +1 -1
  159. package/dist/modes/rpc/rpc-client.d.ts +921 -8
  160. package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
  161. package/dist/modes/rpc/rpc-client.js +921 -8
  162. package/dist/modes/rpc/rpc-client.js.map +1 -1
  163. package/dist/modes/rpc/rpc-mode.d.ts +802 -9
  164. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  165. package/dist/modes/rpc/rpc-mode.js +802 -9
  166. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  167. package/dist/modes/rpc/rpc-types.d.ts +356 -3
  168. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  169. package/dist/modes/rpc/rpc-types.js +356 -3
  170. package/dist/modes/rpc/rpc-types.js.map +1 -1
  171. package/dist/modes/shared.d.ts +386 -0
  172. package/dist/modes/shared.d.ts.map +1 -0
  173. package/dist/modes/shared.js +543 -0
  174. package/dist/modes/shared.js.map +1 -0
  175. package/dist/utils/array.d.ts +389 -0
  176. package/dist/utils/array.d.ts.map +1 -0
  177. package/dist/utils/array.js +585 -0
  178. package/dist/utils/array.js.map +1 -0
  179. package/dist/utils/color-formatter.d.ts +318 -0
  180. package/dist/utils/color-formatter.d.ts.map +1 -0
  181. package/dist/utils/color-formatter.js +442 -0
  182. package/dist/utils/color-formatter.js.map +1 -0
  183. package/dist/utils/data-transformer.d.ts +326 -0
  184. package/dist/utils/data-transformer.d.ts.map +1 -0
  185. package/dist/utils/data-transformer.js +512 -0
  186. package/dist/utils/data-transformer.js.map +1 -0
  187. package/dist/utils/date-formatter.d.ts +281 -0
  188. package/dist/utils/date-formatter.d.ts.map +1 -0
  189. package/dist/utils/date-formatter.js +503 -0
  190. package/dist/utils/date-formatter.js.map +1 -0
  191. package/dist/utils/error-handler.d.ts +541 -0
  192. package/dist/utils/error-handler.d.ts.map +1 -0
  193. package/dist/utils/error-handler.js +726 -0
  194. package/dist/utils/error-handler.js.map +1 -0
  195. package/dist/utils/file-operations.d.ts +297 -0
  196. package/dist/utils/file-operations.d.ts.map +1 -0
  197. package/dist/utils/file-operations.js +505 -0
  198. package/dist/utils/file-operations.js.map +1 -0
  199. package/dist/utils/frontmatter.d.ts +268 -6
  200. package/dist/utils/frontmatter.d.ts.map +1 -1
  201. package/dist/utils/frontmatter.js +500 -21
  202. package/dist/utils/frontmatter.js.map +1 -1
  203. package/dist/utils/json-formatter.d.ts +259 -0
  204. package/dist/utils/json-formatter.d.ts.map +1 -0
  205. package/dist/utils/json-formatter.js +517 -0
  206. package/dist/utils/json-formatter.js.map +1 -0
  207. package/dist/utils/logger.d.ts +176 -0
  208. package/dist/utils/logger.d.ts.map +1 -0
  209. package/dist/utils/logger.js +346 -0
  210. package/dist/utils/logger.js.map +1 -0
  211. package/dist/utils/markdown-formatter.d.ts +211 -0
  212. package/dist/utils/markdown-formatter.d.ts.map +1 -0
  213. package/dist/utils/markdown-formatter.js +482 -0
  214. package/dist/utils/markdown-formatter.js.map +1 -0
  215. package/dist/utils/path-validator.d.ts +603 -0
  216. package/dist/utils/path-validator.d.ts.map +1 -0
  217. package/dist/utils/path-validator.js +870 -0
  218. package/dist/utils/path-validator.js.map +1 -0
  219. package/dist/utils/string-formatter.d.ts +609 -0
  220. package/dist/utils/string-formatter.d.ts.map +1 -0
  221. package/dist/utils/string-formatter.js +806 -0
  222. package/dist/utils/string-formatter.js.map +1 -0
  223. package/dist/utils/type-guards.d.ts +629 -0
  224. package/dist/utils/type-guards.d.ts.map +1 -0
  225. package/dist/utils/type-guards.js +662 -0
  226. package/dist/utils/type-guards.js.map +1 -0
  227. package/docs/COMPLETE-GUIDE.md +300 -0
  228. package/docs/COMPREHENSIVE-CLI-SUMMARY.md +900 -0
  229. package/docs/MODES-ARCHITECTURE.md +565 -0
  230. package/docs/PRINT-MODE-GUIDE.md +456 -0
  231. package/docs/RPC-GUIDE.md +705 -0
  232. package/docs/UTILS-IMPLEMENTATION-SUMMARY.md +647 -0
  233. package/docs/UTILS-MODULE-OVERVIEW.md +1480 -0
  234. package/docs/UTILS-QA-CHECKLIST.md +1061 -0
  235. package/docs/UTILS-USAGE-GUIDE.md +1419 -0
  236. package/package.json +7 -3
@@ -1,21 +1,814 @@
1
1
  /**
2
- * RPC mode: Headless operation with JSON stdin/stdout protocol.
2
+ * RPC Mode - Network API for programmatic access to the coding agent
3
3
  *
4
- * Used for embedding the agent in other applications.
5
- * Receives commands as JSON on stdin, outputs events and responses as JSON on stdout.
4
+ * ============================================================================
5
+ * PURPOSE
6
+ * ============================================================================
6
7
  *
7
- * Protocol:
8
- * - Commands: JSON objects with `type` field, optional `id` for correlation
9
- * - Responses: JSON objects with `type: "response"`, `command`, `success`, and optional `data`/`error`
10
- * - Events: AgentSessionEvent objects streamed as they occur
11
- * - Extension UI: Extension UI requests are emitted, client responds with extension_ui_response
8
+ * Provides a headless JSON-RPC 2.0 interface for embedding the agent in
9
+ * other applications or accessing it via network. Enables programmatic
10
+ * control of the agent without terminal UI, suitable for:
11
+ *
12
+ * - IDE plugins and editor extensions
13
+ * - Web applications and dashboards
14
+ * - Automated workflows and orchestration
15
+ * - Mobile or desktop app backends
16
+ * - Testing and development tools
17
+ * - Multi-client session management
18
+ *
19
+ * ============================================================================
20
+ * PROTOCOL: JSON-RPC 2.0 WITH EXTENSIONS
21
+ * ============================================================================
22
+ *
23
+ * Communication Model:
24
+ * - Stdin: JSON lines with RpcCommand objects
25
+ * - Stdout: JSON lines with RpcResponse and AgentSessionEvent objects
26
+ * - Bidirectional: Client sends commands, server sends responses/events
27
+ * - Asynchronous: Events streamed independently of command responses
28
+ *
29
+ * Command Format:
30
+ * {
31
+ * "id": "req-123", // Optional correlation ID (string or number)
32
+ * "type": "prompt", // Command type
33
+ * "message": "What is 2+2?", // Command-specific fields
34
+ * "images": [...] // Optional images
35
+ * }
36
+ *
37
+ * Response Format:
38
+ * {
39
+ * "id": "req-123", // Matches command ID
40
+ * "type": "response",
41
+ * "command": "prompt", // Which command this responds to
42
+ * "success": true,
43
+ * "data": {...} // Optional success data
44
+ * }
45
+ * OR
46
+ * {
47
+ * "id": "req-123",
48
+ * "type": "response",
49
+ * "command": "prompt",
50
+ * "success": false,
51
+ * "error": "Model not found"
52
+ * }
53
+ *
54
+ * Event Format (streamed asynchronously):
55
+ * {
56
+ * "type": "agent_start",
57
+ * "model": {...}
58
+ * }
59
+ * {
60
+ * "type": "message",
61
+ * "role": "assistant",
62
+ * "content": [...]
63
+ * }
64
+ * {
65
+ * "type": "tool_call",
66
+ * "toolName": "bash",
67
+ * "toolInput": {"command": "ls"}
68
+ * }
69
+ * ... More events ...
70
+ *
71
+ * Extension UI Request Format:
72
+ * {
73
+ * "type": "extension_ui_request",
74
+ * "id": "ui-456",
75
+ * "method": "select", // UI method: select, confirm, input, etc.
76
+ * "title": "Select option",
77
+ * "options": ["Option 1", "Option 2"]
78
+ * }
79
+ *
80
+ * Extension UI Response Format (client must send):
81
+ * {
82
+ * "type": "extension_ui_response",
83
+ * "id": "ui-456",
84
+ * "value": "Option 1" // Response depends on method
85
+ * }
86
+ * OR (for cancelled dialogs):
87
+ * {
88
+ * "type": "extension_ui_response",
89
+ * "id": "ui-456",
90
+ * "cancelled": true
91
+ * }
92
+ *
93
+ * ============================================================================
94
+ * SERVER LIFECYCLE
95
+ * ============================================================================
96
+ *
97
+ * Startup Phase:
98
+ * 1. Process starts in RPC mode (via --mode rpc flag)
99
+ * 2. AgentSession initialized (loads model, tools, extensions)
100
+ * 3. Extensions initialized with RPC-based ExtensionUIContext
101
+ * 4. Event subscription set up
102
+ * 5. Readline interface starts listening on stdin
103
+ * 6. Server ready to accept commands
104
+ *
105
+ * Command Processing Loop:
106
+ * 1. Read JSON line from stdin
107
+ * 2. If extension_ui_response: resolve pending extension UI request
108
+ * 3. If RpcCommand: validate, route to handler, send response
109
+ * 4. Continue listening for next command
110
+ *
111
+ * Streaming Events:
112
+ * - As agent processes commands, events streamed to stdout asynchronously
113
+ * - Client receives both responses (for correlation) and events (for updates)
114
+ * - No ordering guarantee between events from different commands (if sent quickly)
115
+ *
116
+ * Shutdown Phase:
117
+ * - Extension sends session_shutdown event (optional)
118
+ * - Extension shutdown handlers run
119
+ * - Process exits with code 0
120
+ * - Client should close readline interface
121
+ *
122
+ * ============================================================================
123
+ * AVAILABLE COMMANDS
124
+ * ============================================================================
125
+ *
126
+ * Prompting Commands:
127
+ * prompt(message, images, streamingBehavior)
128
+ * → Executes agent loop with prompt
129
+ * → Returns success or error
130
+ * → Streams events asynchronously
131
+ *
132
+ * steer(message)
133
+ * → Queue message to steer current agent response
134
+ * → Only valid while agent streaming
135
+ *
136
+ * follow_up(message)
137
+ * → Queue follow-up prompt for after current response
138
+ * → Buffers until current response complete
139
+ *
140
+ * abort()
141
+ * → Cancel current streaming/processing
142
+ * → Cleans up pending operations
143
+ *
144
+ * State Commands:
145
+ * get_state()
146
+ * → Returns current session state
147
+ * → Includes model, messages count, streaming status
148
+ *
149
+ * get_messages()
150
+ * → Returns all messages in session
151
+ *
152
+ * Model Commands:
153
+ * set_model(provider, modelId)
154
+ * → Switch to different model
155
+ *
156
+ * cycle_model()
157
+ * → Switch to next scoped model or available model
158
+ *
159
+ * get_available_models()
160
+ * → List all available models
161
+ *
162
+ * Thinking Commands:
163
+ * set_thinking_level(level)
164
+ * → Set thinking budget: "none", "auto", "max"
165
+ *
166
+ * cycle_thinking_level()
167
+ * → Cycle through thinking levels
168
+ *
169
+ * Queue Mode Commands:
170
+ * set_steering_mode(mode)
171
+ * → Set steering behavior: "immediate", "queued"
172
+ *
173
+ * set_follow_up_mode(mode)
174
+ * → Set follow-up behavior: "immediate", "queued"
175
+ *
176
+ * Compaction Commands:
177
+ * compact(customInstructions)
178
+ * → Manually compact session context
179
+ * → Returns compaction summary
180
+ *
181
+ * set_auto_compaction(enabled)
182
+ * → Enable/disable auto compaction
183
+ *
184
+ * Bash Commands:
185
+ * bash(command)
186
+ * → Execute bash command synchronously
187
+ * → Returns stdout, stderr, exit code
188
+ *
189
+ * abort_bash()
190
+ * → Kill running bash command
191
+ *
192
+ * Session Commands:
193
+ * get_session_stats()
194
+ * → Returns token usage, message count, etc.
195
+ *
196
+ * export_html(outputPath)
197
+ * → Export session to HTML file
198
+ *
199
+ * switch_session(sessionPath)
200
+ * → Load different session file
201
+ *
202
+ * fork(entryId)
203
+ * → Create new session from branch point
204
+ *
205
+ * ============================================================================
206
+ * ERROR HANDLING
207
+ * ============================================================================
208
+ *
209
+ * Response Errors:
210
+ * All errors returned in success: false responses with error field
211
+ * No exceptions thrown (graceful error handling)
212
+ *
213
+ * Error Categories:
214
+ * - Invalid command/arguments → success: false
215
+ * - Model not found → success: false
216
+ * - Session not found → success: false
217
+ * - Tool execution error → returned in event
218
+ * - API error → returned in stop_reason: "error" event
219
+ *
220
+ * Extension UI Errors:
221
+ * - Dialog timeout → default value returned
222
+ * - Signal abort → default value returned
223
+ * - Client disconnect → no response (pending request hangs)
224
+ *
225
+ * ============================================================================
226
+ * EXTENSION SYSTEM IN RPC MODE
227
+ * ============================================================================
228
+ *
229
+ * Extension UI Context:
230
+ * - Dialog methods (select, confirm, input) emit extension_ui_request
231
+ * - Client must respond with extension_ui_response
232
+ * - Supports timeouts and abort signals
233
+ *
234
+ * Supported UI Methods:
235
+ * - select(title, options, opts) → option value or undefined
236
+ * - confirm(title, message, opts) → boolean
237
+ * - input(title, placeholder, opts) → string or undefined
238
+ * - notify(message, type) → fire-and-forget
239
+ * - setStatus(key, text) → fire-and-forget
240
+ * - setWidget(key, content) → fire-and-forget (string arrays only)
241
+ * - setTitle(title) → fire-and-forget
242
+ * - editor(title, prefill) → edited text or undefined
243
+ *
244
+ * Unsupported UI Methods (RPC mode limitations):
245
+ * - setWorkingMessage() → no TUI loader access
246
+ * - setWidget(factory) → factory functions not supported
247
+ * - setFooter(factory) → requires TUI access
248
+ * - setHeader(factory) → requires TUI access
249
+ * - custom() → requires TUI access
250
+ * - setEditorComponent() → requires TUI access
251
+ * - Theme switching → read-only access only
252
+ *
253
+ * Extension Hooks:
254
+ * - before_prompt: Runs before agent execution
255
+ * - after_prompt: Runs after agent execution
256
+ * - session_shutdown: Runs on shutdown signal
257
+ * - on_error: Extension error handler
258
+ *
259
+ * ============================================================================
260
+ * CLIENT IMPLEMENTATION EXAMPLE
261
+ * ============================================================================
262
+ *
263
+ * const { spawn } = require('child_process');
264
+ *
265
+ * const server = spawn('indusagi', ['--mode', 'rpc']);
266
+ * const readline = require('readline').createInterface({
267
+ * input: server.stdout,
268
+ * output: process.stdout,
269
+ * terminal: false
270
+ * });
271
+ *
272
+ * let nextId = 1;
273
+ * const pending = new Map();
274
+ *
275
+ * readline.on('line', (line) => {
276
+ * const obj = JSON.parse(line);
277
+ * if (obj.type === 'response') {
278
+ * const resolve = pending.get(obj.id);
279
+ * if (resolve) {
280
+ * resolve(obj);
281
+ * pending.delete(obj.id);
282
+ * }
283
+ * } else if (obj.type === 'extension_ui_request') {
284
+ * // Handle UI request from extension
285
+ * server.stdin.write(JSON.stringify({
286
+ * type: 'extension_ui_response',
287
+ * id: obj.id,
288
+ * value: 'user selection'
289
+ * }) + '\n');
290
+ * } else {
291
+ * // Handle event (agent_start, message, tool_call, etc.)
292
+ * console.log('Event:', obj.type);
293
+ * }
294
+ * });
295
+ *
296
+ * // Send a prompt
297
+ * const id = String(nextId++);
298
+ * server.stdin.write(JSON.stringify({
299
+ * id,
300
+ * type: 'prompt',
301
+ * message: 'What is 2+2?'
302
+ * }) + '\n');
303
+ *
304
+ * pending.set(id, (response) => {
305
+ * console.log('Response:', response);
306
+ * });
307
+ *
308
+ * ============================================================================
309
+ * BASED ON RPC SERVER IMPLEMENTATION
310
+ * ============================================================================
311
+ *
312
+ * This RPC mode provides a robust, JSON-based interface for programmatic
313
+ * access to the agent. It follows JSON-RPC 2.0 conventions with extensions
314
+ * for streaming events and asynchronous extension UI.
315
+ *
316
+ * Use cases:
317
+ * - Backend API for web applications
318
+ * - IDE plugin integration
319
+ * - Workflow orchestration
320
+ * - Multi-tenant agent service
321
+ * - Development and testing
12
322
  */
13
323
  import * as crypto from "node:crypto";
14
324
  import * as readline from "readline";
15
325
  import { theme } from "../interactive/theme/theme.js";
16
326
  /**
17
- * Run in RPC mode.
327
+ * Run in RPC (Remote Procedure Call) mode.
328
+ * Establishes a JSON-RPC 2.0 based server for programmatic access to the coding agent.
18
329
  * Listens for JSON commands on stdin, outputs events and responses on stdout.
330
+ *
331
+ * ============================================================================
332
+ * FUNCTION SIGNATURE
333
+ * ============================================================================
334
+ *
335
+ * async runRpcMode(session: AgentSession): Promise<never>
336
+ *
337
+ * Note: Never returns - process loop runs indefinitely until stdin closes.
338
+ *
339
+ * ============================================================================
340
+ * COMMAND PROCESSING LOOP
341
+ * ============================================================================
342
+ *
343
+ * Overview:
344
+ * 1. Initialize server and set up event subscriptions
345
+ * 2. Create readline interface on stdin
346
+ * 3. For each line:
347
+ * a. Parse JSON to get command or extension UI response
348
+ * b. If extension_ui_response: resolve pending UI request
349
+ * c. If RpcCommand: route to handler, send response
350
+ * d. Continue listening (no blocking)
351
+ * 4. Events stream continuously as agent processes
352
+ * 5. Check for shutdown signal after each command
353
+ *
354
+ * Processing Model:
355
+ * - Commands are fire-and-forget (response sent, then events stream)
356
+ * - No ordering guarantee between different commands' events
357
+ * - Multiple commands can be queued and processed serially
358
+ * - Events stream asynchronously throughout processing
359
+ *
360
+ * ============================================================================
361
+ * STARTUP INITIALIZATION
362
+ * ============================================================================
363
+ *
364
+ * Extension Setup:
365
+ * 1. Check if extensionRunner exists in session
366
+ * 2. Create RPC-based ExtensionUIContext (emits ui_request events)
367
+ * 3. Bind extensions with:
368
+ * - Custom UI context (no TUI access - dialogs via RPC)
369
+ * - Command context actions (session control)
370
+ * - Error handlers (logged, not fatal)
371
+ * - Shutdown handler (sets shutdownRequested flag)
372
+ *
373
+ * Session Subscription:
374
+ * 1. Subscribe to all session events
375
+ * 2. Forward all events to client via output()
376
+ * 3. Enables client to reconstruct session state
377
+ *
378
+ * Readline Setup:
379
+ * 1. Create interface on process.stdin
380
+ * 2. Set terminal: false (don't read from TTY)
381
+ * 3. Listen for 'line' events
382
+ * 4. Stay alive indefinitely (Promise never resolves)
383
+ *
384
+ * ============================================================================
385
+ * COMMAND HANDLERS (30+ Commands)
386
+ * ============================================================================
387
+ *
388
+ * PROMPTING COMMANDS (4 handlers)
389
+ * ──────────────────────────────────────────────────────────────────────
390
+ *
391
+ * prompt(message: string, images?: ImageContent[], streamingBehavior?: "steer" | "followUp")
392
+ * Purpose: Send a new prompt to the agent
393
+ * Input:
394
+ * - message (required): The prompt text
395
+ * - images (optional): Array of image content (PNG, JPEG, GIF, WebP)
396
+ * - streamingBehavior: "steer" (interrupt), "followUp" (queue after)
397
+ * Response: { success: true } immediately
398
+ * Events: agent_start → messages → tool_calls → agent_end (streamed)
399
+ * Exit Code on Error: 1
400
+ * Example:
401
+ * Client: {"id":"1","type":"prompt","message":"What is 2+2?"}
402
+ * Server: {"id":"1","type":"response","command":"prompt","success":true}
403
+ * Server: {"type":"agent_start",...}
404
+ * Server: {"type":"message","role":"assistant",...}
405
+ * Server: {"type":"agent_end"}
406
+ *
407
+ * steer(message: string)
408
+ * Purpose: Interrupt current streaming response and steer it
409
+ * Input:
410
+ * - message (required): Steering instruction
411
+ * Response: { success: true }
412
+ * Behavior: Only valid while agent streaming (otherwise queued)
413
+ * Use Case: "Stop using bash, use node instead"
414
+ * Example:
415
+ * Client: {"id":"2","type":"steer","message":"Use Python instead"}
416
+ * Server: {"id":"2","type":"response","command":"steer","success":true}
417
+ *
418
+ * follow_up(message: string)
419
+ * Purpose: Queue message to be processed after current response
420
+ * Input:
421
+ * - message (required): Follow-up prompt
422
+ * Response: { success: true }
423
+ * Behavior: Buffered, processed when agent becomes idle
424
+ * Use Case: Pipelining multiple prompts without waiting
425
+ * Example:
426
+ * Client: {"id":"3","type":"follow_up","message":"Now optimize it"}
427
+ * Server: {"id":"3","type":"response","command":"follow_up","success":true}
428
+ *
429
+ * abort()
430
+ * Purpose: Cancel current operation
431
+ * Response: { success: true }
432
+ * Effect: Stops streaming, cleans up pending operations
433
+ * Use Case: User hit Ctrl+C or timeout reached
434
+ * Example:
435
+ * Client: {"id":"4","type":"abort"}
436
+ * Server: {"id":"4","type":"response","command":"abort","success":true}
437
+ *
438
+ * new_session(parentSession?: string)
439
+ * Purpose: Start new session, optionally tracking parent
440
+ * Input:
441
+ * - parentSession (optional): Path to parent session for lineage
442
+ * Response: { success: true, data: { cancelled: boolean } }
443
+ * Effect: Creates new session file, clears message history
444
+ * Use Case: Starting fresh conversation branch
445
+ * Example:
446
+ * Client: {"id":"5","type":"new_session"}
447
+ * Server: {"id":"5","type":"response","command":"new_session","success":true,"data":{"cancelled":false}}
448
+ *
449
+ * STATE COMMANDS (3 handlers)
450
+ * ──────────────────────────────────────────────────────────────────────
451
+ *
452
+ * get_state()
453
+ * Purpose: Query current session state snapshot
454
+ * Response: { success: true, data: RpcSessionState }
455
+ * Returns:
456
+ * - model: Current model info (provider, id, context window)
457
+ * - thinkingLevel: "none" | "auto" | "max"
458
+ * - isStreaming: Agent currently processing
459
+ * - isCompacting: Auto-compaction in progress
460
+ * - steeringMode: "all" | "one-at-a-time"
461
+ * - followUpMode: "all" | "one-at-a-time"
462
+ * - sessionFile: Full path to session JSONL
463
+ * - sessionId: Short session ID
464
+ * - autoCompactionEnabled: Auto-compact setting
465
+ * - messageCount: Total messages in session
466
+ * - pendingMessageCount: Queued but not processed
467
+ * Use Case: Client UI state display, status checks
468
+ * Example:
469
+ * Client: {"id":"6","type":"get_state"}
470
+ * Server: {"id":"6","type":"response","command":"get_state","success":true,"data":{...}}
471
+ *
472
+ * get_messages()
473
+ * Purpose: Retrieve all messages in conversation
474
+ * Response: { success: true, data: { messages: AgentMessage[] } }
475
+ * Returns: Complete message history with content, roles, stop reasons
476
+ * Use Case: Reconstructing session state, exporting conversation
477
+ * Note: Use carefully if session is very large (many tokens)
478
+ * Example:
479
+ * Client: {"id":"7","type":"get_messages"}
480
+ * Server: {"id":"7","type":"response","command":"get_messages","success":true,"data":{...}}
481
+ *
482
+ * get_last_assistant_text()
483
+ * Purpose: Quick access to most recent assistant response
484
+ * Response: { success: true, data: { text: string | null } }
485
+ * Returns: Only text content (ignores images/tool use)
486
+ * Use Case: Getting latest response without full state
487
+ * Example:
488
+ * Client: {"id":"8","type":"get_last_assistant_text"}
489
+ * Server: {"id":"8","type":"response",...,"data":{"text":"The answer is 4"}}
490
+ *
491
+ * MODEL COMMANDS (3 handlers)
492
+ * ──────────────────────────────────────────────────────────────────────
493
+ *
494
+ * set_model(provider: string, modelId: string)
495
+ * Purpose: Switch to specific model
496
+ * Input:
497
+ * - provider: "anthropic", "openai", "google", etc.
498
+ * - modelId: Model identifier ("claude-3-5-sonnet", "gpt-4", etc.)
499
+ * Response: { success: true, data: Model } on success
500
+ * OR { success: false, error: "Model not found" }
501
+ * Effect: Changes active model for subsequent prompts
502
+ * Validation: Checks model exists in registry
503
+ * Use Case: Programmatic model selection based on capability
504
+ * Example:
505
+ * Client: {"id":"9","type":"set_model","provider":"anthropic","modelId":"claude-3-5-sonnet"}
506
+ * Server: {"id":"9","type":"response",...,"success":true,"data":{"provider":"anthropic",...}}
507
+ *
508
+ * cycle_model()
509
+ * Purpose: Switch to next scoped model or available model
510
+ * Response: { success: true, data: Model } if cycled
511
+ * OR { success: true, data: null } if only one model
512
+ * Use Case: User cycles through available options
513
+ * Example:
514
+ * Client: {"id":"10","type":"cycle_model"}
515
+ * Server: {"id":"10","type":"response",...,"data":{"model":{...},"thinkingLevel":"auto"}}
516
+ *
517
+ * get_available_models()
518
+ * Purpose: List all models available to user
519
+ * Response: { success: true, data: { models: Model[] } }
520
+ * Returns: Array of all models from provider registry
521
+ * Use Case: Client UI model selector, capability checking
522
+ * Example:
523
+ * Client: {"id":"11","type":"get_available_models"}
524
+ * Server: {"id":"11","type":"response",...,"data":{"models":[...]}}
525
+ *
526
+ * THINKING COMMANDS (2 handlers)
527
+ * ──────────────────────────────────────────────────────────────────────
528
+ *
529
+ * set_thinking_level(level: ThinkingLevel)
530
+ * Purpose: Control model reasoning/thinking
531
+ * Input:
532
+ * - level: "none" (no thinking) | "auto" (adaptive) | "max" (max budget)
533
+ * Response: { success: true }
534
+ * Effect: Changes thinking for subsequent prompts
535
+ * Supported Models: Only models with reasoning capability
536
+ * Use Case: Trading latency for reasoning quality
537
+ * Example:
538
+ * Client: {"id":"12","type":"set_thinking_level","level":"max"}
539
+ * Server: {"id":"12","type":"response","command":"set_thinking_level","success":true}
540
+ *
541
+ * cycle_thinking_level()
542
+ * Purpose: Rotate through thinking levels
543
+ * Cycle: "none" → "auto" → "max" → "none" ...
544
+ * Response: { success: true, data: { level: ThinkingLevel } } or null if unsupported
545
+ * Example:
546
+ * Client: {"id":"13","type":"cycle_thinking_level"}
547
+ * Server: {"id":"13","type":"response",...,"data":{"level":"auto"}}
548
+ *
549
+ * QUEUE MODE COMMANDS (2 handlers)
550
+ * ──────────────────────────────────────────────────────────────────────
551
+ *
552
+ * set_steering_mode(mode: "all" | "one-at-a-time")
553
+ * Purpose: Configure how steering messages are processed
554
+ * Input:
555
+ * - "all": Process all steering messages as queue
556
+ * - "one-at-a-time": Process steering sequentially
557
+ * Response: { success: true }
558
+ * Example:
559
+ * Client: {"id":"14","type":"set_steering_mode","mode":"all"}
560
+ * Server: {"id":"14","type":"response","command":"set_steering_mode","success":true}
561
+ *
562
+ * set_follow_up_mode(mode: "all" | "one-at-a-time")
563
+ * Purpose: Configure how follow-up messages are processed
564
+ * Input:
565
+ * - "all": Process all follow-ups in sequence
566
+ * - "one-at-a-time": Process one, then wait
567
+ * Response: { success: true }
568
+ * Example:
569
+ * Client: {"id":"15","type":"set_follow_up_mode","mode":"one-at-a-time"}
570
+ * Server: {"id":"15","type":"response","command":"set_follow_up_mode","success":true}
571
+ *
572
+ * COMPACTION COMMANDS (2 handlers)
573
+ * ──────────────────────────────────────────────────────────────────────
574
+ *
575
+ * compact(customInstructions?: string)
576
+ * Purpose: Manually trigger context compaction
577
+ * Input:
578
+ * - customInstructions (optional): Special instructions for compaction
579
+ * Response: { success: true, data: CompactionResult }
580
+ * Returns:
581
+ * - removedMessages: Count of messages removed
582
+ * - summary: Summarized context
583
+ * - tokensRecovered: Token count freed
584
+ * Effect: Summarizes old messages, frees context for new content
585
+ * Use Case: Manual compaction when approaching context limit
586
+ * Example:
587
+ * Client: {"id":"16","type":"compact","customInstructions":"Keep technical details"}
588
+ * Server: {"id":"16","type":"response",...,"data":{"removedMessages":5,"summary":"..."}}
589
+ *
590
+ * set_auto_compaction(enabled: boolean)
591
+ * Purpose: Enable/disable automatic compaction
592
+ * Response: { success: true }
593
+ * Effect: When enabled, auto-compacts when approaching context limit
594
+ * Default: Typically enabled
595
+ * Example:
596
+ * Client: {"id":"17","type":"set_auto_compaction","enabled":true}
597
+ * Server: {"id":"17","type":"response","command":"set_auto_compaction","success":true}
598
+ *
599
+ * RETRY COMMANDS (2 handlers)
600
+ * ──────────────────────────────────────────────────────────────────────
601
+ *
602
+ * set_auto_retry(enabled: boolean)
603
+ * Purpose: Enable/disable automatic retry on error
604
+ * Response: { success: true }
605
+ * Effect: When enabled, automatically retries failed operations
606
+ * Example:
607
+ * Client: {"id":"18","type":"set_auto_retry","enabled":true}
608
+ * Server: {"id":"18","type":"response","command":"set_auto_retry","success":true}
609
+ *
610
+ * abort_retry()
611
+ * Purpose: Cancel in-flight retry operation
612
+ * Response: { success: true }
613
+ * Example:
614
+ * Client: {"id":"19","type":"abort_retry"}
615
+ * Server: {"id":"19","type":"response","command":"abort_retry","success":true}
616
+ *
617
+ * BASH COMMANDS (2 handlers)
618
+ * ──────────────────────────────────────────────────────────────────────
619
+ *
620
+ * bash(command: string)
621
+ * Purpose: Execute shell command directly (outside agent)
622
+ * Input:
623
+ * - command: Shell command to execute
624
+ * Response: { success: true, data: BashResult }
625
+ * Returns:
626
+ * - stdout: Standard output
627
+ * - stderr: Standard error output
628
+ * - exitCode: Exit code (0 = success)
629
+ * - timedOut: Whether execution timed out
630
+ * Execution: Synchronous, waits for completion
631
+ * Use Case: Direct shell access from client, utility operations
632
+ * Example:
633
+ * Client: {"id":"20","type":"bash","command":"ls -la"}
634
+ * Server: {"id":"20","type":"response",...,"data":{"stdout":"...","stderr":"","exitCode":0}}
635
+ *
636
+ * abort_bash()
637
+ * Purpose: Kill running bash command
638
+ * Response: { success: true }
639
+ * Effect: Immediately terminates bash subprocess
640
+ * Example:
641
+ * Client: {"id":"21","type":"abort_bash"}
642
+ * Server: {"id":"21","type":"response","command":"abort_bash","success":true}
643
+ *
644
+ * SESSION MANAGEMENT COMMANDS (7 handlers)
645
+ * ──────────────────────────────────────────────────────────────────────
646
+ *
647
+ * get_session_stats()
648
+ * Purpose: Get detailed session statistics
649
+ * Response: { success: true, data: SessionStats }
650
+ * Returns:
651
+ * - messageCount: Total messages
652
+ * - totalTokensUsed: Cumulative token usage
653
+ * - estimatedCost: Cost estimate
654
+ * - sessionDuration: Time since creation
655
+ * - toolUsageCount: Tool invocations
656
+ * Use Case: Usage tracking, monitoring, billing
657
+ * Example:
658
+ * Client: {"id":"22","type":"get_session_stats"}
659
+ * Server: {"id":"22","type":"response",...,"data":{"messageCount":42,...}}
660
+ *
661
+ * export_html(outputPath?: string)
662
+ * Purpose: Export session to HTML file
663
+ * Input:
664
+ * - outputPath (optional): Where to save HTML (default: auto-generated)
665
+ * Response: { success: true, data: { path: string } }
666
+ * Returns: Path where HTML was written
667
+ * Use Case: Sharing conversations, archiving, documentation
668
+ * Example:
669
+ * Client: {"id":"23","type":"export_html","outputPath":"/tmp/session.html"}
670
+ * Server: {"id":"23","type":"response",...,"data":{"path":"/tmp/session.html"}}
671
+ *
672
+ * switch_session(sessionPath: string)
673
+ * Purpose: Load different session file
674
+ * Input:
675
+ * - sessionPath: Path to .jsonl session file
676
+ * Response: { success: true, data: { cancelled: boolean } }
677
+ * Effect: Closes current session, loads new one
678
+ * Validation: File must exist and be valid session JSONL
679
+ * Example:
680
+ * Client: {"id":"24","type":"switch_session","sessionPath":"~/.indusagi/sessions/old.jsonl"}
681
+ * Server: {"id":"24","type":"response",...,"data":{"cancelled":false}}
682
+ *
683
+ * fork(entryId: string)
684
+ * Purpose: Create new session from branch point
685
+ * Input:
686
+ * - entryId: Message ID to branch from
687
+ * Response: { success: true, data: { text: string, cancelled: boolean } }
688
+ * Returns: Text at branch point
689
+ * Effect: New session created with messages up to branch point
690
+ * Use Case: Exploring alternative conversation paths
691
+ * Example:
692
+ * Client: {"id":"25","type":"fork","entryId":"msg-42"}
693
+ * Server: {"id":"25","type":"response",...,"data":{"text":"...","cancelled":false}}
694
+ *
695
+ * get_fork_messages()
696
+ * Purpose: Get messages available for branching
697
+ * Response: { success: true, data: { messages: Array<{entryId, text}> } }
698
+ * Returns: List of message IDs and summaries
699
+ * Use Case: UI showing available branch points
700
+ * Example:
701
+ * Client: {"id":"26","type":"get_fork_messages"}
702
+ * Server: {"id":"26","type":"response",...,"data":{"messages":[...]}}
703
+ *
704
+ * ============================================================================
705
+ * EXTENSION UI REQUEST/RESPONSE HANDLING
706
+ * ============================================================================
707
+ *
708
+ * When extensions request user input, the protocol uses bidirectional
709
+ * extension_ui_request/response messages:
710
+ *
711
+ * Server sends extension_ui_request when extension needs input:
712
+ * {
713
+ * "type": "extension_ui_request",
714
+ * "id": "ui-uuid",
715
+ * "method": "select" | "confirm" | "input" | "editor" | "notify" | ...
716
+ * ...method-specific fields...
717
+ * }
718
+ *
719
+ * Client responds with extension_ui_response:
720
+ * {
721
+ * "type": "extension_ui_response",
722
+ * "id": "ui-uuid",
723
+ * "value": "..." // or "confirmed": true or "cancelled": true
724
+ * }
725
+ *
726
+ * Supported Methods:
727
+ * - select(title, options): User picks option
728
+ * - confirm(title, message): Yes/no confirmation
729
+ * - input(title, placeholder): Text input
730
+ * - editor(title, prefill): Multi-line editor
731
+ * - notify(message, type): Info/warning/error notification (no response)
732
+ * - setStatus(key, text): Update status line (no response)
733
+ * - setWidget(key, lines): Update widget display (no response)
734
+ * - setTitle(title): Set terminal title (no response)
735
+ * - setEditorText(text): Set editor content (no response)
736
+ *
737
+ * Timeout Handling:
738
+ * - If client doesn't respond within timeout, default value used
739
+ * - Dialog cancelled, handler receives undefined/false
740
+ * - Server continues processing
741
+ *
742
+ * ============================================================================
743
+ * SHUTDOWN PROTOCOL
744
+ * ============================================================================
745
+ *
746
+ * Graceful Shutdown:
747
+ * 1. Extension sends "shutdown_requested" signal (internal)
748
+ * 2. After next idle point (between commands)
749
+ * 3. Server emits session_shutdown event (via extension runner)
750
+ * 4. Readline closed, process exits cleanly with code 0
751
+ *
752
+ * Abnormal Shutdown:
753
+ * - Stdin closes: readline 'close' event triggers process exit
754
+ * - Ctrl+C: SIGINT handler stops server
755
+ * - SIGTERM: Server performs cleanup then exits
756
+ *
757
+ * ============================================================================
758
+ * ERROR HANDLING STRATEGIES
759
+ * ============================================================================
760
+ *
761
+ * Command Errors:
762
+ * - All caught and returned as { success: false, error: "message" }
763
+ * - No exceptions thrown to client
764
+ * - Process continues, ready for next command
765
+ *
766
+ * Extension Errors:
767
+ * - Logged to stderr with format: "Extension error (path): message"
768
+ * - Emitted as hook_error or extension_error event
769
+ * - Don't crash server, handler registered errors
770
+ *
771
+ * Async Event Errors:
772
+ * - Agent events from streaming: included in events
773
+ * - Stop reason "error" in message event
774
+ * - Client can subscribe to events for error details
775
+ *
776
+ * Unrecoverable Errors:
777
+ * - Process exits with code 1
778
+ * - Client should detect process termination
779
+ * - Reconnect and start new session
780
+ *
781
+ * ============================================================================
782
+ * IMPLEMENTATION NOTES
783
+ * ============================================================================
784
+ *
785
+ * Event Emission:
786
+ * - Subscription set up at startup
787
+ * - All events output via output() function
788
+ * - Events stream even during command processing
789
+ * - No backpressure or queuing (stdout assumed fast)
790
+ *
791
+ * Request Correlation:
792
+ * - Each command gets unique ID (optional, generated if missing)
793
+ * - Response includes same ID for correlation
794
+ * - Client can match responses to requests by ID
795
+ * - Extension UI requests also use UUID for correlation
796
+ *
797
+ * State Safety:
798
+ * - Session state is thread-safe (no multi-threading)
799
+ * - Readline ensures single-threaded execution
800
+ * - Events stream after response to ensure ordering
801
+ *
802
+ * ============================================================================
803
+ * BASED ON RPC SERVER IMPLEMENTATION
804
+ * ============================================================================
805
+ *
806
+ * This function implements the complete JSON-RPC 2.0 protocol with
807
+ * extensions for streaming events and asynchronous extension UI.
808
+ * It provides a robust, type-safe interface for programmatic access.
809
+ *
810
+ * Use with RpcClient for type-safe client implementation.
811
+ * Or implement custom client using the protocol specification.
19
812
  */
20
813
  export async function runRpcMode(session) {
21
814
  const output = (obj) => {