byterover-cli 0.4.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (474) hide show
  1. package/README.md +1 -9
  2. package/dist/commands/curate.d.ts +1 -3
  3. package/dist/commands/curate.js +14 -51
  4. package/dist/commands/main.d.ts +8 -0
  5. package/dist/commands/main.js +29 -8
  6. package/dist/commands/query.d.ts +1 -3
  7. package/dist/commands/query.js +8 -35
  8. package/dist/config/context-tree-domains.d.ts +5 -0
  9. package/dist/config/context-tree-domains.js +6 -1
  10. package/dist/config/environment.js +9 -9
  11. package/dist/constants.d.ts +14 -0
  12. package/dist/constants.js +18 -0
  13. package/dist/core/domain/cipher/agent/agent-info.d.ts +199 -0
  14. package/dist/core/domain/cipher/agent/agent-info.js +143 -0
  15. package/dist/core/domain/cipher/agent/agent-registry.d.ts +96 -0
  16. package/dist/core/domain/cipher/agent/agent-registry.js +254 -0
  17. package/dist/core/domain/cipher/agent/index.d.ts +4 -1
  18. package/dist/core/domain/cipher/agent/index.js +7 -1
  19. package/dist/core/domain/cipher/agent-events/types.d.ts +355 -2
  20. package/dist/core/domain/cipher/agent-events/types.js +11 -0
  21. package/dist/core/domain/cipher/errors/error-normalizer.d.ts +156 -0
  22. package/dist/core/domain/cipher/errors/error-normalizer.js +379 -0
  23. package/dist/core/domain/cipher/errors/file-system-error.d.ts +2 -1
  24. package/dist/core/domain/cipher/errors/file-system-error.js +3 -2
  25. package/dist/core/domain/cipher/errors/system-prompt-error-codes.d.ts +79 -0
  26. package/dist/core/domain/cipher/errors/system-prompt-error-codes.js +80 -0
  27. package/dist/core/domain/cipher/errors/system-prompt-error.d.ts +114 -0
  28. package/dist/core/domain/cipher/errors/system-prompt-error.js +144 -0
  29. package/dist/core/domain/cipher/file-system/types.d.ts +57 -0
  30. package/dist/core/domain/cipher/llm/error-codes.d.ts +51 -0
  31. package/dist/core/domain/cipher/llm/error-codes.js +51 -0
  32. package/dist/core/domain/cipher/llm/index.d.ts +9 -0
  33. package/dist/core/domain/cipher/llm/index.js +13 -0
  34. package/dist/core/domain/cipher/llm/registry.d.ts +113 -0
  35. package/dist/core/domain/cipher/llm/registry.js +244 -0
  36. package/dist/core/domain/cipher/llm/schemas.d.ts +155 -0
  37. package/dist/core/domain/cipher/llm/schemas.js +151 -0
  38. package/dist/core/domain/cipher/llm/types.d.ts +121 -0
  39. package/dist/core/domain/cipher/llm/types.js +60 -0
  40. package/dist/core/domain/cipher/storage/message-storage-types.d.ts +114 -5
  41. package/dist/core/domain/cipher/streaming/types.d.ts +119 -0
  42. package/dist/core/domain/cipher/streaming/types.js +16 -0
  43. package/dist/core/domain/cipher/system-prompt/types.d.ts +44 -0
  44. package/dist/core/domain/cipher/todos/types.d.ts +34 -0
  45. package/dist/core/domain/cipher/tools/constants.d.ts +5 -2
  46. package/dist/core/domain/cipher/tools/constants.js +5 -2
  47. package/dist/core/domain/cipher/tools/types.d.ts +31 -0
  48. package/dist/core/domain/errors/connection-error.d.ts +33 -0
  49. package/dist/core/domain/errors/connection-error.js +54 -0
  50. package/dist/core/domain/errors/core-process-error.d.ts +27 -0
  51. package/dist/core/domain/errors/core-process-error.js +43 -0
  52. package/dist/core/domain/errors/task-error.d.ts +64 -0
  53. package/dist/core/domain/errors/task-error.js +116 -0
  54. package/dist/core/domain/errors/transport-error.d.ts +72 -0
  55. package/dist/core/domain/errors/transport-error.js +114 -0
  56. package/dist/core/domain/instance/index.d.ts +1 -0
  57. package/dist/core/domain/instance/index.js +1 -0
  58. package/dist/core/domain/instance/types.d.ts +57 -0
  59. package/dist/core/domain/instance/types.js +72 -0
  60. package/dist/core/domain/knowledge/directory-manager.d.ts +16 -0
  61. package/dist/core/domain/knowledge/directory-manager.js +31 -0
  62. package/dist/core/domain/transport/index.d.ts +2 -0
  63. package/dist/core/domain/transport/index.js +2 -0
  64. package/dist/core/domain/transport/schemas.d.ts +1149 -0
  65. package/dist/core/domain/transport/schemas.js +554 -0
  66. package/dist/core/domain/transport/types.d.ts +67 -0
  67. package/dist/core/domain/transport/types.js +7 -0
  68. package/dist/core/interfaces/cipher/cipher-services.d.ts +15 -3
  69. package/dist/core/interfaces/cipher/i-chat-session.d.ts +47 -5
  70. package/dist/core/interfaces/cipher/i-cipher-agent.d.ts +39 -4
  71. package/dist/core/interfaces/cipher/i-content-generator.d.ts +3 -5
  72. package/dist/core/interfaces/cipher/i-file-system.d.ts +12 -1
  73. package/dist/core/interfaces/cipher/i-llm-service.d.ts +4 -5
  74. package/dist/core/interfaces/cipher/i-todo-storage.d.ts +24 -0
  75. package/dist/core/interfaces/cipher/i-todo-storage.js +1 -0
  76. package/dist/core/interfaces/cipher/i-tool-plugin.d.ts +90 -0
  77. package/dist/core/interfaces/cipher/i-tool-plugin.js +1 -0
  78. package/dist/core/interfaces/cipher/i-tool-provider.d.ts +3 -2
  79. package/dist/core/interfaces/cipher/i-tool-scheduler.d.ts +4 -0
  80. package/dist/core/interfaces/cipher/index.d.ts +35 -0
  81. package/dist/core/interfaces/cipher/index.js +11 -0
  82. package/dist/core/interfaces/cipher/message-factory.d.ts +155 -0
  83. package/dist/core/interfaces/cipher/message-factory.js +252 -0
  84. package/dist/core/interfaces/cipher/message-type-guards.d.ts +139 -0
  85. package/dist/core/interfaces/cipher/message-type-guards.js +173 -0
  86. package/dist/core/interfaces/cipher/message-types.d.ts +279 -5
  87. package/dist/core/interfaces/cipher/message-types.js +6 -0
  88. package/dist/core/interfaces/cipher/sanitization-types.d.ts +147 -0
  89. package/dist/core/interfaces/cipher/sanitization-types.js +46 -0
  90. package/dist/core/interfaces/executor/i-curate-executor.d.ts +34 -0
  91. package/dist/core/interfaces/executor/i-curate-executor.js +1 -0
  92. package/dist/core/interfaces/executor/i-query-executor.d.ts +32 -0
  93. package/dist/core/interfaces/executor/i-query-executor.js +1 -0
  94. package/dist/core/interfaces/executor/index.d.ts +2 -0
  95. package/dist/core/interfaces/executor/index.js +2 -0
  96. package/dist/core/interfaces/instance/i-instance-discovery.d.ts +45 -0
  97. package/dist/core/interfaces/instance/i-instance-discovery.js +1 -0
  98. package/dist/core/interfaces/instance/i-instance-manager.d.ts +58 -0
  99. package/dist/core/interfaces/instance/i-instance-manager.js +1 -0
  100. package/dist/core/interfaces/instance/index.d.ts +2 -0
  101. package/dist/core/interfaces/instance/index.js +2 -0
  102. package/dist/core/interfaces/noop-implementations.d.ts +53 -0
  103. package/dist/core/interfaces/noop-implementations.js +62 -0
  104. package/dist/core/interfaces/transport/i-transport-client.d.ts +97 -0
  105. package/dist/core/interfaces/transport/i-transport-client.js +1 -0
  106. package/dist/core/interfaces/transport/i-transport-server.d.ts +93 -0
  107. package/dist/core/interfaces/transport/i-transport-server.js +1 -0
  108. package/dist/core/interfaces/transport/index.d.ts +2 -0
  109. package/dist/core/interfaces/transport/index.js +2 -0
  110. package/dist/infra/cipher/agent/agent-error-codes.d.ts +16 -0
  111. package/dist/infra/cipher/agent/agent-error-codes.js +17 -0
  112. package/dist/infra/cipher/agent/agent-error.d.ts +54 -0
  113. package/dist/infra/cipher/agent/agent-error.js +79 -0
  114. package/dist/infra/cipher/agent/agent-schemas.d.ts +264 -0
  115. package/dist/infra/cipher/agent/agent-schemas.js +97 -0
  116. package/dist/infra/cipher/agent/agent-state-manager.d.ts +140 -0
  117. package/dist/infra/cipher/agent/agent-state-manager.js +275 -0
  118. package/dist/infra/cipher/agent/base-agent.d.ts +118 -0
  119. package/dist/infra/cipher/agent/base-agent.js +240 -0
  120. package/dist/infra/cipher/agent/cipher-agent.d.ts +165 -0
  121. package/dist/infra/cipher/agent/cipher-agent.js +546 -0
  122. package/dist/infra/cipher/agent/index.d.ts +22 -0
  123. package/dist/infra/cipher/agent/index.js +24 -0
  124. package/dist/infra/cipher/agent/service-initializer.d.ts +79 -0
  125. package/dist/infra/cipher/{agent-service-factory.js → agent/service-initializer.js} +117 -68
  126. package/dist/infra/cipher/agent/types.d.ts +35 -0
  127. package/dist/infra/cipher/agent/types.js +1 -0
  128. package/dist/infra/cipher/blob/blob-reference-resolver.d.ts +107 -0
  129. package/dist/infra/cipher/blob/blob-reference-resolver.js +228 -0
  130. package/dist/infra/cipher/blob/blob-reference-utils.d.ts +117 -0
  131. package/dist/infra/cipher/blob/blob-reference-utils.js +230 -0
  132. package/dist/infra/cipher/consumer/consumer-lock.js +1 -0
  133. package/dist/infra/cipher/consumer/consumer-service.js +1 -0
  134. package/dist/infra/cipher/consumer/execution-consumer.d.ts +6 -1
  135. package/dist/infra/cipher/consumer/execution-consumer.js +54 -16
  136. package/dist/infra/cipher/consumer/index.d.ts +1 -1
  137. package/dist/infra/cipher/consumer/index.js +2 -1
  138. package/dist/infra/cipher/consumer/queue-polling-service.js +1 -0
  139. package/dist/infra/cipher/file-system/binary-utils.d.ts +43 -0
  140. package/dist/infra/cipher/file-system/binary-utils.js +164 -0
  141. package/dist/infra/cipher/file-system/context-tree-file-system-factory.d.ts +9 -0
  142. package/dist/infra/cipher/file-system/context-tree-file-system-factory.js +24 -0
  143. package/dist/infra/cipher/file-system/file-system-service.d.ts +17 -1
  144. package/dist/infra/cipher/file-system/file-system-service.js +327 -36
  145. package/dist/infra/cipher/file-system/path-validator.d.ts +32 -0
  146. package/dist/infra/cipher/file-system/path-validator.js +111 -6
  147. package/dist/infra/cipher/interactive-loop.js +41 -33
  148. package/dist/infra/cipher/llm/capability-cache.d.ts +87 -0
  149. package/dist/infra/cipher/llm/capability-cache.js +125 -0
  150. package/dist/infra/cipher/llm/context/compaction/compaction-service.d.ts +32 -0
  151. package/dist/infra/cipher/llm/context/compaction/compaction-service.js +44 -3
  152. package/dist/infra/cipher/llm/context/compression/enhanced-compaction.d.ts +112 -0
  153. package/dist/infra/cipher/llm/context/compression/enhanced-compaction.js +175 -0
  154. package/dist/infra/cipher/llm/context/compression/filter-compacted.d.ts +83 -0
  155. package/dist/infra/cipher/llm/context/compression/filter-compacted.js +150 -0
  156. package/dist/infra/cipher/llm/context/compression/index.d.ts +5 -0
  157. package/dist/infra/cipher/llm/context/compression/index.js +6 -0
  158. package/dist/infra/cipher/llm/context/compression/reactive-overflow.d.ts +107 -0
  159. package/dist/infra/cipher/llm/context/compression/reactive-overflow.js +272 -0
  160. package/dist/infra/cipher/llm/context/context-manager.d.ts +47 -1
  161. package/dist/infra/cipher/llm/context/context-manager.js +129 -0
  162. package/dist/infra/cipher/llm/context/utils.js +17 -4
  163. package/dist/infra/cipher/llm/generators/byterover-content-generator.js +4 -2
  164. package/dist/infra/cipher/llm/internal-llm-service.d.ts +50 -17
  165. package/dist/infra/cipher/llm/internal-llm-service.js +273 -50
  166. package/dist/infra/cipher/llm/openrouter-llm-service.d.ts +6 -8
  167. package/dist/infra/cipher/llm/openrouter-llm-service.js +14 -16
  168. package/dist/infra/cipher/llm/retry/retry-policy.d.ts +1 -0
  169. package/dist/infra/cipher/llm/retry/retry-policy.js +11 -0
  170. package/dist/infra/cipher/llm/retry/retry-with-backoff.js +3 -2
  171. package/dist/infra/cipher/llm/sanitization/base64-utils.d.ts +102 -0
  172. package/dist/infra/cipher/llm/sanitization/base64-utils.js +182 -0
  173. package/dist/infra/cipher/llm/sanitization/index.d.ts +12 -0
  174. package/dist/infra/cipher/llm/sanitization/index.js +13 -0
  175. package/dist/infra/cipher/llm/sanitization/tool-sanitizer.d.ts +74 -0
  176. package/dist/infra/cipher/llm/sanitization/tool-sanitizer.js +398 -0
  177. package/dist/infra/cipher/llm/stream-processor.d.ts +158 -0
  178. package/dist/infra/cipher/llm/stream-processor.js +276 -0
  179. package/dist/infra/cipher/llm/tokenizers/claude-tokenizer.d.ts +13 -20
  180. package/dist/infra/cipher/llm/tokenizers/claude-tokenizer.js +17 -24
  181. package/dist/infra/cipher/llm/tokenizers/gemini-tokenizer.d.ts +12 -11
  182. package/dist/infra/cipher/llm/tokenizers/gemini-tokenizer.js +16 -15
  183. package/dist/infra/cipher/llm/tokenizers/openrouter-tokenizer.d.ts +15 -7
  184. package/dist/infra/cipher/llm/tokenizers/openrouter-tokenizer.js +22 -10
  185. package/dist/infra/cipher/llm/tool-output-processor.d.ts +51 -0
  186. package/dist/infra/cipher/llm/tool-output-processor.js +139 -0
  187. package/dist/infra/cipher/process/command-validator.d.ts +23 -0
  188. package/dist/infra/cipher/process/command-validator.js +75 -0
  189. package/dist/infra/cipher/process/path-utils.d.ts +66 -0
  190. package/dist/infra/cipher/process/path-utils.js +94 -0
  191. package/dist/infra/cipher/process/process-service.d.ts +32 -0
  192. package/dist/infra/cipher/process/process-service.js +98 -17
  193. package/dist/infra/cipher/session/chat-session.d.ts +56 -7
  194. package/dist/infra/cipher/session/chat-session.js +163 -13
  195. package/dist/infra/cipher/session/index.d.ts +1 -0
  196. package/dist/infra/cipher/session/index.js +2 -0
  197. package/dist/infra/cipher/session/message-queue.d.ts +65 -0
  198. package/dist/infra/cipher/session/message-queue.js +90 -0
  199. package/dist/infra/cipher/session/session-manager.d.ts +106 -5
  200. package/dist/infra/cipher/session/session-manager.js +254 -7
  201. package/dist/infra/cipher/session/session-status.d.ts +137 -0
  202. package/dist/infra/cipher/session/session-status.js +184 -0
  203. package/dist/infra/cipher/session/title-generator.d.ts +8 -0
  204. package/dist/infra/cipher/session/title-generator.js +31 -0
  205. package/dist/infra/cipher/storage/message-storage-service.d.ts +65 -2
  206. package/dist/infra/cipher/storage/message-storage-service.js +300 -54
  207. package/dist/infra/cipher/storage/tool-part-factory.d.ts +116 -0
  208. package/dist/infra/cipher/storage/tool-part-factory.js +197 -0
  209. package/dist/infra/cipher/system-prompt/contributor-schemas.d.ts +516 -0
  210. package/dist/infra/cipher/system-prompt/contributor-schemas.js +85 -0
  211. package/dist/infra/cipher/system-prompt/contributors/agent-prompt-contributor.d.ts +59 -0
  212. package/dist/infra/cipher/system-prompt/contributors/agent-prompt-contributor.js +131 -0
  213. package/dist/infra/cipher/system-prompt/contributors/companion-contributor.d.ts +54 -0
  214. package/dist/infra/cipher/system-prompt/contributors/companion-contributor.js +107 -0
  215. package/dist/infra/cipher/system-prompt/contributors/context-tree-structure-contributor.d.ts +68 -0
  216. package/dist/infra/cipher/system-prompt/contributors/context-tree-structure-contributor.js +179 -0
  217. package/dist/infra/cipher/system-prompt/contributors/datetime-contributor.d.ts +25 -0
  218. package/dist/infra/cipher/system-prompt/contributors/datetime-contributor.js +29 -0
  219. package/dist/infra/cipher/system-prompt/contributors/environment-contributor.d.ts +25 -0
  220. package/dist/infra/cipher/system-prompt/contributors/environment-contributor.js +54 -0
  221. package/dist/infra/cipher/system-prompt/contributors/file-contributor.d.ts +60 -0
  222. package/dist/infra/cipher/system-prompt/contributors/file-contributor.js +128 -0
  223. package/dist/infra/cipher/system-prompt/contributors/index.d.ts +13 -0
  224. package/dist/infra/cipher/system-prompt/contributors/index.js +8 -0
  225. package/dist/infra/cipher/system-prompt/contributors/memory-contributor.d.ts +40 -0
  226. package/dist/infra/cipher/system-prompt/contributors/memory-contributor.js +56 -0
  227. package/dist/infra/cipher/system-prompt/contributors/static-contributor.d.ts +26 -0
  228. package/dist/infra/cipher/system-prompt/contributors/static-contributor.js +31 -0
  229. package/dist/infra/cipher/system-prompt/environment-context-builder.d.ts +112 -0
  230. package/dist/infra/cipher/system-prompt/environment-context-builder.js +256 -0
  231. package/dist/infra/cipher/system-prompt/prompt-cache.d.ts +102 -0
  232. package/dist/infra/cipher/system-prompt/prompt-cache.js +156 -0
  233. package/dist/infra/cipher/system-prompt/schemas.d.ts +151 -0
  234. package/dist/infra/cipher/system-prompt/schemas.js +94 -0
  235. package/dist/infra/cipher/system-prompt/system-prompt-manager.d.ts +136 -0
  236. package/dist/infra/cipher/system-prompt/system-prompt-manager.js +307 -0
  237. package/dist/infra/cipher/todos/todo-storage-service.d.ts +26 -0
  238. package/dist/infra/cipher/todos/todo-storage-service.js +28 -0
  239. package/dist/infra/cipher/tools/core-tool-scheduler.js +5 -1
  240. package/dist/infra/cipher/tools/default-policy-rules.js +1 -1
  241. package/dist/infra/cipher/tools/implementations/bash-exec-tool.d.ts +1 -0
  242. package/dist/infra/cipher/tools/implementations/bash-exec-tool.js +27 -10
  243. package/dist/infra/cipher/tools/implementations/bash-output-tool.js +1 -5
  244. package/dist/infra/cipher/tools/implementations/batch-tool.d.ts +12 -0
  245. package/dist/infra/cipher/tools/implementations/batch-tool.js +142 -0
  246. package/dist/infra/cipher/tools/implementations/curate-tool.js +195 -68
  247. package/dist/infra/cipher/tools/implementations/list-directory-tool.d.ts +12 -0
  248. package/dist/infra/cipher/tools/implementations/list-directory-tool.js +52 -0
  249. package/dist/infra/cipher/tools/implementations/read-file-tool.d.ts +8 -1
  250. package/dist/infra/cipher/tools/implementations/read-file-tool.js +17 -7
  251. package/dist/infra/cipher/tools/implementations/read-todos-tool.d.ts +11 -0
  252. package/dist/infra/cipher/tools/implementations/read-todos-tool.js +39 -0
  253. package/dist/infra/cipher/tools/implementations/{detect-domains-tool.d.ts → spec-analyze-tool.d.ts} +1 -1
  254. package/dist/infra/cipher/tools/implementations/{detect-domains-tool.js → spec-analyze-tool.js} +9 -7
  255. package/dist/infra/cipher/tools/implementations/task-tool.d.ts +34 -0
  256. package/dist/infra/cipher/tools/implementations/task-tool.js +207 -0
  257. package/dist/infra/cipher/tools/implementations/write-todos-tool.d.ts +4 -1
  258. package/dist/infra/cipher/tools/implementations/write-todos-tool.js +19 -63
  259. package/dist/infra/cipher/tools/index.d.ts +1 -1
  260. package/dist/infra/cipher/tools/index.js +1 -1
  261. package/dist/infra/cipher/tools/plugins/index.d.ts +3 -0
  262. package/dist/infra/cipher/tools/plugins/index.js +2 -0
  263. package/dist/infra/cipher/tools/plugins/logging-plugin.d.ts +28 -0
  264. package/dist/infra/cipher/tools/plugins/logging-plugin.js +66 -0
  265. package/dist/infra/cipher/tools/plugins/plugin-manager.d.ts +81 -0
  266. package/dist/infra/cipher/tools/plugins/plugin-manager.js +122 -0
  267. package/dist/infra/cipher/tools/streaming/index.d.ts +1 -0
  268. package/dist/infra/cipher/tools/streaming/index.js +1 -0
  269. package/dist/infra/cipher/tools/streaming/metadata-handler.d.ts +31 -0
  270. package/dist/infra/cipher/tools/streaming/metadata-handler.js +39 -0
  271. package/dist/infra/cipher/tools/tool-description-loader.d.ts +57 -0
  272. package/dist/infra/cipher/tools/tool-description-loader.js +108 -0
  273. package/dist/infra/cipher/tools/tool-manager.d.ts +38 -4
  274. package/dist/infra/cipher/tools/tool-manager.js +107 -11
  275. package/dist/infra/cipher/tools/tool-provider-getter.d.ts +6 -0
  276. package/dist/infra/cipher/tools/tool-provider-getter.js +1 -0
  277. package/dist/infra/cipher/tools/tool-provider.d.ts +32 -7
  278. package/dist/infra/cipher/tools/tool-provider.js +81 -25
  279. package/dist/infra/cipher/tools/tool-registry.d.ts +23 -0
  280. package/dist/infra/cipher/tools/tool-registry.js +58 -16
  281. package/dist/infra/context-tree/file-context-tree-snapshot-service.js +10 -4
  282. package/dist/infra/context-tree/file-context-tree-writer-service.d.ts +4 -3
  283. package/dist/infra/context-tree/file-context-tree-writer-service.js +6 -4
  284. package/dist/infra/context-tree/path-utils.d.ts +7 -0
  285. package/dist/infra/context-tree/path-utils.js +7 -0
  286. package/dist/infra/core/executors/curate-executor.d.ts +35 -0
  287. package/dist/infra/core/executors/curate-executor.js +123 -0
  288. package/dist/infra/core/executors/index.d.ts +2 -0
  289. package/dist/infra/core/executors/index.js +2 -0
  290. package/dist/infra/core/executors/query-executor.d.ts +23 -0
  291. package/dist/infra/core/executors/query-executor.js +51 -0
  292. package/dist/infra/core/task-processor.d.ts +81 -0
  293. package/dist/infra/core/task-processor.js +115 -0
  294. package/dist/infra/instance/file-instance-discovery.d.ts +31 -0
  295. package/dist/infra/instance/file-instance-discovery.js +84 -0
  296. package/dist/infra/instance/file-instance-manager.d.ts +46 -0
  297. package/dist/infra/instance/file-instance-manager.js +123 -0
  298. package/dist/infra/instance/index.d.ts +3 -0
  299. package/dist/infra/instance/index.js +3 -0
  300. package/dist/infra/instance/process-utils.d.ts +14 -0
  301. package/dist/infra/instance/process-utils.js +39 -0
  302. package/dist/infra/process/agent-worker.d.ts +20 -0
  303. package/dist/infra/process/agent-worker.js +602 -0
  304. package/dist/infra/process/index.d.ts +12 -0
  305. package/dist/infra/process/index.js +11 -0
  306. package/dist/infra/process/ipc-types.d.ts +55 -0
  307. package/dist/infra/process/ipc-types.js +12 -0
  308. package/dist/infra/process/process-manager.d.ts +154 -0
  309. package/dist/infra/process/process-manager.js +471 -0
  310. package/dist/infra/process/task-queue-manager.d.ts +123 -0
  311. package/dist/infra/process/task-queue-manager.js +226 -0
  312. package/dist/infra/process/transport-handlers.d.ts +124 -0
  313. package/dist/infra/process/transport-handlers.js +348 -0
  314. package/dist/infra/process/transport-worker.d.ts +20 -0
  315. package/dist/infra/process/transport-worker.js +168 -0
  316. package/dist/infra/repl/commands/curate-command.js +0 -5
  317. package/dist/infra/repl/commands/query-command.js +0 -3
  318. package/dist/infra/repl/repl-startup.d.ts +4 -0
  319. package/dist/infra/repl/repl-startup.js +8 -1
  320. package/dist/infra/repl/transport-client-helper.d.ts +9 -0
  321. package/dist/infra/repl/transport-client-helper.js +96 -0
  322. package/dist/infra/transport/index.d.ts +4 -0
  323. package/dist/infra/transport/index.js +4 -0
  324. package/dist/infra/transport/port-utils.d.ts +42 -0
  325. package/dist/infra/transport/port-utils.js +84 -0
  326. package/dist/infra/transport/socket-io-transport-client.d.ts +45 -0
  327. package/dist/infra/transport/socket-io-transport-client.js +270 -0
  328. package/dist/infra/transport/socket-io-transport-server.d.ts +35 -0
  329. package/dist/infra/transport/socket-io-transport-server.js +207 -0
  330. package/dist/infra/transport/transport-client-factory.d.ts +76 -0
  331. package/dist/infra/transport/transport-client-factory.js +168 -0
  332. package/dist/infra/transport/transport-factory.d.ts +33 -0
  333. package/dist/infra/transport/transport-factory.js +59 -0
  334. package/dist/infra/usecase/curate-use-case.d.ts +8 -55
  335. package/dist/infra/usecase/curate-use-case.js +71 -262
  336. package/dist/infra/usecase/init-use-case.js +3 -2
  337. package/dist/infra/usecase/query-use-case.d.ts +18 -45
  338. package/dist/infra/usecase/query-use-case.js +250 -326
  339. package/dist/infra/usecase/status-use-case.js +1 -1
  340. package/dist/resources/prompts/{curate-context-tree-curation.yml → curate.yml} +25 -22
  341. package/dist/resources/prompts/explore.yml +78 -0
  342. package/dist/resources/prompts/plan.yml +114 -0
  343. package/dist/resources/prompts/reflection.yml +1 -1
  344. package/dist/resources/prompts/system-prompt.yml +15 -8
  345. package/dist/resources/prompts/tool-outputs.yml +0 -5
  346. package/dist/resources/tools/bash_exec.txt +98 -0
  347. package/dist/resources/tools/bash_output.txt +40 -0
  348. package/dist/resources/tools/batch.txt +28 -0
  349. package/dist/resources/tools/create_knowledge_topic.txt +23 -0
  350. package/dist/resources/tools/curate.txt +22 -0
  351. package/dist/resources/tools/delete_memory.txt +1 -0
  352. package/dist/resources/tools/detect_domains.txt +11 -0
  353. package/dist/resources/tools/edit_file.txt +1 -0
  354. package/dist/resources/tools/edit_memory.txt +1 -0
  355. package/dist/resources/tools/glob_files.txt +20 -0
  356. package/dist/resources/tools/grep_content.txt +18 -0
  357. package/dist/resources/tools/kill_process.txt +16 -0
  358. package/dist/resources/tools/list_directory.txt +16 -0
  359. package/dist/resources/tools/list_memories.txt +1 -0
  360. package/dist/resources/tools/read_file.txt +31 -0
  361. package/dist/resources/tools/read_memory.txt +1 -0
  362. package/dist/resources/tools/read_todos.txt +17 -0
  363. package/dist/resources/tools/search_history.txt +1 -0
  364. package/dist/resources/tools/task.txt +23 -0
  365. package/dist/resources/tools/write_file.txt +1 -0
  366. package/dist/resources/tools/write_memory.txt +1 -0
  367. package/dist/resources/tools/write_todos.txt +29 -0
  368. package/dist/tui/app.js +9 -13
  369. package/dist/tui/components/command-details.d.ts +14 -0
  370. package/dist/tui/components/command-details.js +35 -0
  371. package/dist/tui/components/execution/execution-changes.d.ts +5 -0
  372. package/dist/tui/components/execution/execution-changes.js +19 -4
  373. package/dist/tui/components/execution/execution-content.d.ts +4 -2
  374. package/dist/tui/components/execution/execution-content.js +26 -13
  375. package/dist/tui/components/execution/execution-input.js +3 -3
  376. package/dist/tui/components/execution/execution-progress.d.ts +2 -2
  377. package/dist/tui/components/execution/execution-progress.js +8 -6
  378. package/dist/tui/components/execution/log-item.d.ts +3 -4
  379. package/dist/tui/components/execution/log-item.js +2 -5
  380. package/dist/tui/components/footer.js +9 -4
  381. package/dist/tui/components/header.d.ts +3 -3
  382. package/dist/tui/components/header.js +5 -3
  383. package/dist/tui/components/index.d.ts +1 -0
  384. package/dist/tui/components/index.js +1 -0
  385. package/dist/tui/components/onboarding/copyable-prompt.d.ts +5 -3
  386. package/dist/tui/components/onboarding/copyable-prompt.js +7 -8
  387. package/dist/tui/components/onboarding/onboarding-flow.js +35 -25
  388. package/dist/tui/components/scrollable-list.js +12 -10
  389. package/dist/tui/components/suggestions.js +39 -41
  390. package/dist/tui/components/tab-bar.d.ts +2 -1
  391. package/dist/tui/components/tab-bar.js +3 -4
  392. package/dist/tui/constants.d.ts +0 -5
  393. package/dist/tui/constants.js +0 -5
  394. package/dist/tui/contexts/auth-context.js +9 -2
  395. package/dist/tui/contexts/{use-commands.js → commands-context.js} +3 -3
  396. package/dist/tui/contexts/index.d.ts +6 -1
  397. package/dist/tui/contexts/index.js +6 -1
  398. package/dist/tui/contexts/onboarding-context.d.ts +1 -1
  399. package/dist/tui/contexts/onboarding-context.js +9 -9
  400. package/dist/tui/contexts/tasks-context.d.ts +84 -0
  401. package/dist/tui/contexts/tasks-context.js +218 -0
  402. package/dist/tui/contexts/transport-context.d.ts +29 -0
  403. package/dist/tui/contexts/transport-context.js +82 -0
  404. package/dist/tui/hooks/index.d.ts +10 -6
  405. package/dist/tui/hooks/index.js +7 -6
  406. package/dist/tui/hooks/use-activity-logs.d.ts +3 -11
  407. package/dist/tui/hooks/use-activity-logs.js +87 -34
  408. package/dist/tui/hooks/use-auth-polling.d.ts +24 -0
  409. package/dist/tui/hooks/use-auth-polling.js +104 -0
  410. package/dist/tui/hooks/use-slash-command-processor.js +0 -1
  411. package/dist/tui/hooks/use-slash-completion.js +1 -1
  412. package/dist/tui/hooks/use-tab-navigation.d.ts +2 -1
  413. package/dist/tui/hooks/use-tab-navigation.js +16 -7
  414. package/dist/tui/hooks/use-terminal-breakpoint.d.ts +21 -0
  415. package/dist/tui/hooks/use-terminal-breakpoint.js +38 -0
  416. package/dist/tui/hooks/use-ui-heights.d.ts +120 -0
  417. package/dist/tui/hooks/use-ui-heights.js +88 -0
  418. package/dist/tui/providers/app-providers.js +2 -6
  419. package/dist/tui/types/commands.d.ts +0 -26
  420. package/dist/tui/types/index.d.ts +1 -1
  421. package/dist/tui/types/ui.d.ts +9 -4
  422. package/dist/tui/utils/line.d.ts +11 -0
  423. package/dist/tui/utils/line.js +16 -0
  424. package/dist/tui/utils/log.d.ts +27 -0
  425. package/dist/tui/utils/log.js +114 -0
  426. package/dist/tui/views/command-view.d.ts +7 -0
  427. package/dist/tui/views/command-view.js +103 -80
  428. package/dist/tui/views/login-view.js +7 -4
  429. package/dist/tui/views/logs-view.d.ts +13 -0
  430. package/dist/tui/views/logs-view.js +27 -52
  431. package/dist/utils/connection-error-handler.d.ts +16 -0
  432. package/dist/utils/connection-error-handler.js +49 -0
  433. package/dist/utils/crash-log.d.ts +14 -0
  434. package/dist/utils/crash-log.js +19 -0
  435. package/dist/utils/file-helpers.d.ts +14 -0
  436. package/dist/utils/file-helpers.js +21 -0
  437. package/dist/utils/global-logs-path.d.ts +11 -0
  438. package/dist/utils/global-logs-path.js +37 -0
  439. package/dist/utils/process-logger.d.ts +53 -0
  440. package/dist/utils/process-logger.js +253 -0
  441. package/dist/utils/sandbox-detector.d.ts +31 -0
  442. package/dist/utils/sandbox-detector.js +122 -0
  443. package/oclif.manifest.json +10 -198
  444. package/package.json +5 -1
  445. package/dist/commands/cipher-agent/run.d.ts +0 -142
  446. package/dist/commands/cipher-agent/run.js +0 -555
  447. package/dist/commands/cipher-agent/set-prompt.d.ts +0 -16
  448. package/dist/commands/cipher-agent/set-prompt.js +0 -58
  449. package/dist/commands/cipher-agent/show-prompt.d.ts +0 -13
  450. package/dist/commands/cipher-agent/show-prompt.js +0 -53
  451. package/dist/commands/foo.d.ts +0 -14
  452. package/dist/commands/foo.js +0 -66
  453. package/dist/infra/cipher/agent-service-factory.d.ts +0 -93
  454. package/dist/infra/cipher/cipher-agent-state-manager.d.ts +0 -63
  455. package/dist/infra/cipher/cipher-agent-state-manager.js +0 -108
  456. package/dist/infra/cipher/cipher-agent.d.ts +0 -182
  457. package/dist/infra/cipher/cipher-agent.js +0 -317
  458. package/dist/infra/cipher/system-prompt/simple-prompt-factory.d.ts +0 -106
  459. package/dist/infra/cipher/system-prompt/simple-prompt-factory.js +0 -297
  460. package/dist/infra/cipher/tools/implementations/find-knowledge-topics-tool.d.ts +0 -7
  461. package/dist/infra/cipher/tools/implementations/find-knowledge-topics-tool.js +0 -424
  462. package/dist/resources/prompts/modes/autonomous.yml +0 -9
  463. package/dist/resources/prompts/query-context-tree-retrieval.yml +0 -48
  464. package/dist/tui/contexts/consumer.d.ts +0 -31
  465. package/dist/tui/contexts/consumer.js +0 -56
  466. package/dist/tui/hooks/use-consumer.d.ts +0 -12
  467. package/dist/tui/hooks/use-consumer.js +0 -50
  468. package/dist/tui/hooks/use-queue-polling.d.ts +0 -31
  469. package/dist/tui/hooks/use-queue-polling.js +0 -90
  470. /package/dist/tui/contexts/{use-commands.d.ts → commands-context.d.ts} +0 -0
  471. /package/dist/tui/contexts/{use-mode.d.ts → mode-context.d.ts} +0 -0
  472. /package/dist/tui/contexts/{use-mode.js → mode-context.js} +0 -0
  473. /package/dist/tui/contexts/{use-theme.d.ts → theme-context.d.ts} +0 -0
  474. /package/dist/tui/contexts/{use-theme.js → theme-context.js} +0 -0
@@ -3,6 +3,7 @@ import { randomBytes } from 'node:crypto';
3
3
  import { isAbsolute, relative, resolve } from 'node:path';
4
4
  import { ProcessError } from '../../../core/domain/cipher/errors/process-error.js';
5
5
  import { CommandValidator } from './command-validator.js';
6
+ import { normalizePath } from './path-utils.js';
6
7
  /**
7
8
  * Default timeout for foreground commands (milliseconds).
8
9
  */
@@ -97,6 +98,8 @@ export class ProcessService {
97
98
  }
98
99
  // Resolve working directory
99
100
  const cwd = this.resolveSafeCwd(options.cwd);
101
+ // Validate path arguments in the command
102
+ this.validatePathArguments(normalizedCommand, cwd);
100
103
  // Merge environment variables
101
104
  const env = {};
102
105
  for (const [key, value] of Object.entries({
@@ -168,6 +171,8 @@ export class ProcessService {
168
171
  /**
169
172
  * Terminate a background process.
170
173
  *
174
+ * Uses process tree killing to ensure all child processes are terminated.
175
+ *
171
176
  * @param processId - Unique process identifier
172
177
  */
173
178
  async killProcess(processId) {
@@ -180,14 +185,8 @@ export class ProcessService {
180
185
  return;
181
186
  }
182
187
  try {
183
- // Send SIGTERM
184
- bgProcess.child.kill('SIGTERM');
185
- // Wait 5 seconds, then escalate to SIGKILL
186
- setTimeout(() => {
187
- if (bgProcess.child.exitCode === null) {
188
- bgProcess.child.kill('SIGKILL');
189
- }
190
- }, 5000);
188
+ // Kill the entire process tree
189
+ await this.killProcessTree(bgProcess.child, bgProcess.child.pid);
191
190
  }
192
191
  catch (error) {
193
192
  throw ProcessError.killFailed(processId, error instanceof Error ? error.message : String(error));
@@ -320,12 +319,17 @@ export class ProcessService {
320
319
  truncated: false,
321
320
  };
322
321
  // Spawn process
322
+ // Use detached: true on Unix to create a process group for tree killing
323
323
  const child = spawn(command, {
324
324
  cwd: options.cwd,
325
- detached: false, // Process dies with parent
325
+ detached: process.platform !== 'win32',
326
326
  env: options.env,
327
327
  shell: true,
328
328
  });
329
+ // Prevent child from keeping parent alive on Unix
330
+ if (process.platform !== 'win32') {
331
+ child.unref();
332
+ }
329
333
  const startedAt = new Date();
330
334
  // Create background process entry
331
335
  const bgProcess = {
@@ -389,13 +393,10 @@ export class ProcessService {
389
393
  // Set timeout handler
390
394
  const killTimer = setTimeout(() => {
391
395
  if (bgProcess.status === 'running') {
392
- child.kill('SIGTERM');
393
- // Escalate to SIGKILL after 5 seconds
394
- setTimeout(() => {
395
- if (bgProcess.status === 'running') {
396
- child.kill('SIGKILL');
397
- }
398
- }, 5000);
396
+ // Use process tree killing for timeout
397
+ this.killProcessTree(child, child.pid).catch(() => {
398
+ // Ignore errors during timeout kill - process may already be dead
399
+ });
399
400
  }
400
401
  }, options.timeout);
401
402
  // Clear timeout when process completes
@@ -411,6 +412,50 @@ export class ProcessService {
411
412
  startedAt,
412
413
  };
413
414
  }
415
+ /**
416
+ * Kill a process and all its children (process tree).
417
+ *
418
+ * On Unix, uses process groups (-pid) to kill all descendants.
419
+ * On Windows, uses taskkill with /t flag for tree kill.
420
+ * Falls back to direct kill if process group kill fails.
421
+ *
422
+ * @param child - Child process to kill
423
+ * @param pid - Process ID (optional, extracted from child if not provided)
424
+ * @returns Promise that resolves when kill attempt completes
425
+ */
426
+ async killProcessTree(child, pid) {
427
+ const targetPid = pid ?? child.pid;
428
+ if (!targetPid)
429
+ return;
430
+ if (process.platform === 'win32') {
431
+ // Use taskkill with /t flag for tree kill on Windows
432
+ return new Promise((resolve) => {
433
+ const killer = spawn('taskkill', ['/pid', String(targetPid), '/f', '/t'], { stdio: 'ignore' });
434
+ killer.once('exit', () => resolve());
435
+ killer.once('error', () => resolve());
436
+ });
437
+ }
438
+ // Unix: kill process group using negative PID
439
+ try {
440
+ process.kill(-targetPid, 'SIGTERM');
441
+ await this.sleep(5000);
442
+ try {
443
+ process.kill(-targetPid, 'SIGKILL');
444
+ }
445
+ catch {
446
+ // Process already dead, ignore
447
+ }
448
+ }
449
+ catch {
450
+ // Fallback to direct kill if process group kill fails
451
+ // (e.g., process wasn't started with detached: true)
452
+ child.kill('SIGTERM');
453
+ await this.sleep(5000);
454
+ if (child.exitCode === null) {
455
+ child.kill('SIGKILL');
456
+ }
457
+ }
458
+ }
414
459
  /**
415
460
  * Resolve and validate working directory.
416
461
  *
@@ -426,8 +471,10 @@ export class ProcessService {
426
471
  if (!cwd) {
427
472
  return baseDir;
428
473
  }
474
+ // Normalize for Git Bash on Windows
475
+ const normalizedCwd = normalizePath(cwd);
429
476
  // Resolve to absolute path
430
- const candidatePath = isAbsolute(cwd) ? resolve(cwd) : resolve(baseDir, cwd);
477
+ const candidatePath = isAbsolute(normalizedCwd) ? resolve(normalizedCwd) : resolve(baseDir, normalizedCwd);
431
478
  // Check if path is within base directory
432
479
  const relativePath = relative(baseDir, candidatePath);
433
480
  const isOutsideBase = relativePath.startsWith('..') || isAbsolute(relativePath);
@@ -436,4 +483,38 @@ export class ProcessService {
436
483
  }
437
484
  return candidatePath;
438
485
  }
486
+ /**
487
+ * Sleep for specified milliseconds.
488
+ *
489
+ * @param ms - Milliseconds to sleep
490
+ * @returns Promise that resolves after the delay
491
+ */
492
+ sleep(ms) {
493
+ return new Promise((resolve) => {
494
+ setTimeout(resolve, ms);
495
+ });
496
+ }
497
+ /**
498
+ * Validate file path arguments in a command.
499
+ *
500
+ * Extracts path arguments from path-sensitive commands and validates
501
+ * that they are within the configured base directory.
502
+ *
503
+ * @param command - Command string to validate
504
+ * @param baseDir - Base directory for confinement
505
+ * @throws ProcessError if any path argument is outside the base directory
506
+ */
507
+ validatePathArguments(command, baseDir) {
508
+ const paths = this.commandValidator.extractPathArguments(command);
509
+ for (const pathArg of paths) {
510
+ // Resolve to absolute path
511
+ const resolved = isAbsolute(pathArg) ? resolve(pathArg) : resolve(baseDir, pathArg);
512
+ // Check if path is within base directory
513
+ const relativePath = relative(baseDir, resolved);
514
+ const isOutsideBase = relativePath.startsWith('..') || isAbsolute(relativePath);
515
+ if (isOutsideBase) {
516
+ throw ProcessError.invalidWorkingDirectory(pathArg, `Path argument "${pathArg}" references location outside ${baseDir}`);
517
+ }
518
+ }
519
+ }
439
520
  }
@@ -3,11 +3,10 @@ import type { CipherAgentServices, SessionServices } from '../../../core/interfa
3
3
  import type { IChatSession } from '../../../core/interfaces/cipher/i-chat-session.js';
4
4
  import type { ExecutionContext } from '../../../core/interfaces/cipher/i-cipher-agent.js';
5
5
  import type { ILLMService } from '../../../core/interfaces/cipher/i-llm-service.js';
6
+ import type { FileData, ImageData } from '../llm/context/context-manager.js';
6
7
  import { SessionEventBus } from '../events/event-emitter.js';
7
8
  /**
8
9
  * Chat session implementation.
9
- *
10
- * Following Dexto's pattern: ChatSession owns session-specific services
11
10
  * (LLM, EventBus) and receives shared services (ToolManager, SystemPromptManager).
12
11
  *
13
12
  * The LLM service handles:
@@ -25,8 +24,11 @@ export declare class ChatSession implements IChatSession {
25
24
  readonly eventBus: SessionEventBus;
26
25
  readonly id: string;
27
26
  private currentController?;
27
+ private currentTaskId?;
28
28
  private readonly forwarders;
29
+ private isExecuting;
29
30
  private readonly llmService;
31
+ private readonly messageQueue;
30
32
  private readonly sharedServices;
31
33
  /**
32
34
  * Creates a new chat session
@@ -41,7 +43,14 @@ export declare class ChatSession implements IChatSession {
41
43
  */
42
44
  cancel(): void;
43
45
  /**
44
- * Dispose of the session and clean up resources.
46
+ * Cleanup session resources but preserve history for later restoration.
47
+ * Call this when ending a session temporarily (e.g., user navigates away).
48
+ * History remains in ContextManager for persistence; event listeners stay for potential reactivation.
49
+ */
50
+ cleanup(): void;
51
+ /**
52
+ * Dispose of the session completely - remove all event listeners.
53
+ * Call this when permanently destroying a session.
45
54
  * Removes event listeners to prevent memory leaks.
46
55
  */
47
56
  dispose(): void;
@@ -65,16 +74,56 @@ export declare class ChatSession implements IChatSession {
65
74
  /**
66
75
  * Send a message and get a response.
67
76
  * Delegates to the LLM service which handles the agentic loop.
77
+ * Processes any queued messages first if present.
78
+ *
79
+ * @param input - User message
80
+ * @param options - Execution options
81
+ * @param options.executionContext - Optional execution context
82
+ * @param options.taskId - Optional task ID for concurrent task isolation
68
83
  */
69
84
  run(input: string, options?: {
70
85
  executionContext?: ExecutionContext;
71
- mode?: 'autonomous' | 'default' | 'query';
86
+ taskId?: string;
72
87
  }): Promise<string>;
73
88
  /**
74
- * Setup automatic event forwarding from SessionEventBus to AgentEventBus.
75
- * All session events are forwarded with sessionId added to the payload.
89
+ * Send a message, queuing if the session is busy executing.
90
+ * If the session is idle, executes immediately via run().
91
+ * If the session is busy, queues the message and returns the queue position.
76
92
  *
77
- * Following Dexto's pattern: event forwarding is built into the session.
93
+ * @param input - User message content
94
+ * @param options - Optional execution options and attachments
95
+ * @param options.executionContext - Optional execution context for the LLM
96
+ * @param options.fileData - Optional file attachment
97
+ * @param options.imageData - Optional image attachment
98
+ * @returns Response string if executed, or queue info if queued
99
+ */
100
+ sendMessage(input: string, options?: {
101
+ executionContext?: ExecutionContext;
102
+ fileData?: FileData;
103
+ imageData?: ImageData;
104
+ }): Promise<string | {
105
+ position: number;
106
+ queued: true;
107
+ }>;
108
+ /**
109
+ * Stream execution with real-time event emission.
110
+ * Unlike run(), this does not return a response directly - events are yielded via the agent's stream().
111
+ * Emits run:complete event when finished.
112
+ *
113
+ * @param input - User message
114
+ * @param options - Execution options with optional signal for cancellation
115
+ * @param options.executionContext - Optional execution context for the LLM
116
+ * @param options.signal - Optional AbortSignal for cancellation
117
+ * @param options.taskId - Optional task ID for concurrent task isolation
118
+ */
119
+ streamRun(input: string, options?: {
120
+ executionContext?: ExecutionContext;
121
+ signal?: AbortSignal;
122
+ taskId?: string;
123
+ }): Promise<void>;
124
+ /**
125
+ * Setup automatic event forwarding from SessionEventBus to AgentEventBus.
126
+ * All session events are forwarded with sessionId and taskId added to the payload.
78
127
  */
79
128
  private setupEventForwarding;
80
129
  }
@@ -1,4 +1,6 @@
1
1
  import { LLMError, SessionCancelledError } from '../../../core/domain/cipher/errors/session-error.js';
2
+ import { MessageQueueService } from './message-queue.js';
3
+ import { sessionStatusManager } from './session-status.js';
2
4
  // List of all session events that should be forwarded to agent bus
3
5
  const SESSION_EVENT_NAMES = [
4
6
  'llmservice:thinking',
@@ -6,13 +8,18 @@ const SESSION_EVENT_NAMES = [
6
8
  'llmservice:response',
7
9
  'llmservice:toolCall',
8
10
  'llmservice:toolResult',
11
+ 'llmservice:doomLoopDetected',
9
12
  'llmservice:error',
10
13
  'llmservice:unsupportedInput',
14
+ 'message:queued',
15
+ 'message:dequeued',
16
+ 'run:complete',
17
+ 'session:statusChanged',
18
+ 'step:started',
19
+ 'step:finished',
11
20
  ];
12
21
  /**
13
22
  * Chat session implementation.
14
- *
15
- * Following Dexto's pattern: ChatSession owns session-specific services
16
23
  * (LLM, EventBus) and receives shared services (ToolManager, SystemPromptManager).
17
24
  *
18
25
  * The LLM service handles:
@@ -30,8 +37,11 @@ export class ChatSession {
30
37
  eventBus;
31
38
  id;
32
39
  currentController;
40
+ currentTaskId;
33
41
  forwarders = new Map();
42
+ isExecuting = false;
34
43
  llmService;
44
+ messageQueue;
35
45
  sharedServices;
36
46
  /**
37
47
  * Creates a new chat session
@@ -45,6 +55,7 @@ export class ChatSession {
45
55
  this.sharedServices = sharedServices;
46
56
  this.eventBus = sessionServices.sessionEventBus;
47
57
  this.llmService = sessionServices.llmService;
58
+ this.messageQueue = new MessageQueueService(sessionServices.sessionEventBus);
48
59
  // Setup event forwarding from session bus to agent bus
49
60
  this.setupEventForwarding();
50
61
  }
@@ -57,15 +68,34 @@ export class ChatSession {
57
68
  }
58
69
  }
59
70
  /**
60
- * Dispose of the session and clean up resources.
71
+ * Cleanup session resources but preserve history for later restoration.
72
+ * Call this when ending a session temporarily (e.g., user navigates away).
73
+ * History remains in ContextManager for persistence; event listeners stay for potential reactivation.
74
+ */
75
+ cleanup() {
76
+ // Cancel any in-flight operation
77
+ if (this.currentController) {
78
+ this.currentController.abort();
79
+ this.currentController = undefined;
80
+ }
81
+ // Note: History remains in LLMService's ContextManager for persistence
82
+ // Event listeners remain for potential reactivation
83
+ }
84
+ /**
85
+ * Dispose of the session completely - remove all event listeners.
86
+ * Call this when permanently destroying a session.
61
87
  * Removes event listeners to prevent memory leaks.
62
88
  */
63
89
  dispose() {
90
+ // First cleanup any in-flight operations
91
+ this.cleanup();
64
92
  // Remove all event forwarders
65
93
  for (const [eventName, forwarder] of this.forwarders.entries()) {
66
94
  this.eventBus.off(eventName, forwarder);
67
95
  }
68
96
  this.forwarders.clear();
97
+ // Clean up session status
98
+ sessionStatusManager.remove(this.id);
69
99
  }
70
100
  /**
71
101
  * Get the conversation history.
@@ -116,22 +146,40 @@ export class ChatSession {
116
146
  /**
117
147
  * Send a message and get a response.
118
148
  * Delegates to the LLM service which handles the agentic loop.
149
+ * Processes any queued messages first if present.
150
+ *
151
+ * @param input - User message
152
+ * @param options - Execution options
153
+ * @param options.executionContext - Optional execution context
154
+ * @param options.taskId - Optional task ID for concurrent task isolation
119
155
  */
120
156
  async run(input, options) {
121
157
  // Create abort controller for cancellation
122
158
  this.currentController = new AbortController();
159
+ this.isExecuting = true;
160
+ // Store taskId for event forwarding
161
+ this.currentTaskId = options?.taskId;
162
+ // Update session status to busy
163
+ sessionStatusManager.setBusy(this.id, this.eventBus);
164
+ // Store reference to controller for use in catch/finally blocks
165
+ // This prevents race conditions where currentController might be undefined
166
+ const controller = this.currentController;
123
167
  try {
168
+ // Process any queued messages first, coalescing with current input
169
+ const queued = this.messageQueue.dequeueAll();
170
+ const finalInput = queued ? `${queued.content}\n\nAlso: ${input}` : input;
124
171
  // Delegate to service - it handles everything
125
- const response = await this.llmService.completeTask(input, this.id, {
172
+ // Pass taskId for billing tracking
173
+ const response = await this.llmService.completeTask(finalInput, {
126
174
  executionContext: options?.executionContext,
127
- mode: options?.mode,
128
- signal: this.currentController.signal,
175
+ signal: controller.signal,
176
+ taskId: options?.taskId,
129
177
  });
130
178
  return response;
131
179
  }
132
180
  catch (error) {
133
- // Check if cancelled
134
- if (this.currentController.signal.aborted) {
181
+ // Check if cancelled - use stored controller reference to avoid undefined access
182
+ if (controller.signal.aborted) {
135
183
  throw new SessionCancelledError(this.id);
136
184
  }
137
185
  // Wrap other errors - pass message as-is since it's already formatted
@@ -139,20 +187,122 @@ export class ChatSession {
139
187
  throw new LLMError(errorMessage, this.id);
140
188
  }
141
189
  finally {
190
+ this.isExecuting = false;
142
191
  this.currentController = undefined;
192
+ this.currentTaskId = undefined;
193
+ // Update session status back to idle
194
+ sessionStatusManager.setIdle(this.id, this.eventBus);
143
195
  }
144
196
  }
145
197
  /**
146
- * Setup automatic event forwarding from SessionEventBus to AgentEventBus.
147
- * All session events are forwarded with sessionId added to the payload.
198
+ * Send a message, queuing if the session is busy executing.
199
+ * If the session is idle, executes immediately via run().
200
+ * If the session is busy, queues the message and returns the queue position.
201
+ *
202
+ * @param input - User message content
203
+ * @param options - Optional execution options and attachments
204
+ * @param options.executionContext - Optional execution context for the LLM
205
+ * @param options.fileData - Optional file attachment
206
+ * @param options.imageData - Optional image attachment
207
+ * @returns Response string if executed, or queue info if queued
208
+ */
209
+ async sendMessage(input, options) {
210
+ if (this.isExecuting) {
211
+ // Queue the message for later processing
212
+ const position = this.messageQueue.enqueue({
213
+ content: input,
214
+ fileData: options?.fileData,
215
+ imageData: options?.imageData,
216
+ });
217
+ return { position, queued: true };
218
+ }
219
+ // Execute immediately
220
+ return this.run(input, { executionContext: options?.executionContext });
221
+ }
222
+ /**
223
+ * Stream execution with real-time event emission.
224
+ * Unlike run(), this does not return a response directly - events are yielded via the agent's stream().
225
+ * Emits run:complete event when finished.
148
226
  *
149
- * Following Dexto's pattern: event forwarding is built into the session.
227
+ * @param input - User message
228
+ * @param options - Execution options with optional signal for cancellation
229
+ * @param options.executionContext - Optional execution context for the LLM
230
+ * @param options.signal - Optional AbortSignal for cancellation
231
+ * @param options.taskId - Optional task ID for concurrent task isolation
232
+ */
233
+ async streamRun(input, options) {
234
+ const startTime = Date.now();
235
+ let finishReason = 'stop';
236
+ let error;
237
+ // Create abort controller for cancellation
238
+ this.currentController = new AbortController();
239
+ this.isExecuting = true;
240
+ // Store taskId for event forwarding
241
+ this.currentTaskId = options?.taskId;
242
+ // Update session status to busy
243
+ sessionStatusManager.setBusy(this.id, this.eventBus);
244
+ // Store reference to controller for use in catch/finally blocks
245
+ // This prevents race conditions where currentController might be undefined
246
+ const controller = this.currentController;
247
+ // Link external signal if provided (use {once: true} to prevent listener accumulation)
248
+ if (options?.signal) {
249
+ options.signal.addEventListener('abort', () => controller?.abort(), { once: true });
250
+ }
251
+ try {
252
+ // Process any queued messages first, coalescing with current input
253
+ const queued = this.messageQueue.dequeueAll();
254
+ const finalInput = queued ? `${queued.content}\n\nAlso: ${input}` : input;
255
+ // Delegate to service - it handles everything and emits events
256
+ // Pass taskId for billing tracking
257
+ await this.llmService.completeTask(finalInput, {
258
+ executionContext: options?.executionContext,
259
+ signal: controller.signal,
260
+ taskId: options?.taskId,
261
+ });
262
+ }
263
+ catch (error_) {
264
+ // Check if cancelled - use stored controller reference to avoid undefined access
265
+ if (controller.signal.aborted) {
266
+ finishReason = 'cancelled';
267
+ }
268
+ else {
269
+ finishReason = 'error';
270
+ error = error_ instanceof Error ? error_ : new Error(String(error_));
271
+ }
272
+ }
273
+ finally {
274
+ this.isExecuting = false;
275
+ this.currentController = undefined;
276
+ // Save taskId before clearing for run:complete event
277
+ const completedTaskId = this.currentTaskId;
278
+ this.currentTaskId = undefined;
279
+ // Update session status back to idle
280
+ sessionStatusManager.setIdle(this.id, this.eventBus);
281
+ // Emit run:complete event with taskId for billing tracking
282
+ const durationMs = Date.now() - startTime;
283
+ this.eventBus.emit('run:complete', {
284
+ durationMs,
285
+ error,
286
+ finishReason,
287
+ stepCount: 0, // Can be enhanced later to track actual step count
288
+ ...(completedTaskId && { taskId: completedTaskId }),
289
+ });
290
+ }
291
+ }
292
+ /**
293
+ * Setup automatic event forwarding from SessionEventBus to AgentEventBus.
294
+ * All session events are forwarded with sessionId and taskId added to the payload.
150
295
  */
151
296
  setupEventForwarding() {
152
297
  for (const eventName of SESSION_EVENT_NAMES) {
153
298
  const forwarder = (payload) => {
154
- // Add sessionId to payload
155
- const payloadWithSession = payload && typeof payload === 'object' ? { ...payload, sessionId: this.id } : { sessionId: this.id };
299
+ // Add sessionId and taskId to payload
300
+ const basePayload = payload && typeof payload === 'object' ? payload : {};
301
+ const payloadWithSession = {
302
+ ...basePayload,
303
+ sessionId: this.id,
304
+ ...(this.currentTaskId && { taskId: this.currentTaskId }),
305
+ };
156
306
  // Forward to agent bus - eventName is properly typed from SESSION_EVENT_NAMES
157
307
  this.sharedServices.agentEventBus.emit(eventName, payloadWithSession);
158
308
  };
@@ -4,3 +4,4 @@ export type { IChatSession } from '../../../core/interfaces/cipher/i-chat-sessio
4
4
  export type { ILLMService } from '../../../core/interfaces/cipher/i-llm-service.js';
5
5
  export { ChatSession } from './chat-session.js';
6
6
  export { SessionManager } from './session-manager.js';
7
+ export { SessionStatusManager, sessionStatusManager } from './session-status.js';
@@ -3,3 +3,5 @@ export { LLMError, MaxIterationsExceededError, SessionCancelledError, SessionErr
3
3
  export { ChatSession } from './chat-session.js';
4
4
  // Session manager
5
5
  export { SessionManager } from './session-manager.js';
6
+ // Session status
7
+ export { SessionStatusManager, sessionStatusManager } from './session-status.js';
@@ -0,0 +1,65 @@
1
+ import type { SessionEventBus } from '../events/event-emitter.js';
2
+ import type { FileData, ImageData } from '../llm/context/context-manager.js';
3
+ /**
4
+ * A message that has been queued for later processing.
5
+ */
6
+ export interface QueuedMessage {
7
+ /** Message text content */
8
+ content: string;
9
+ /** Optional file attachment */
10
+ fileData?: FileData;
11
+ /** Unique identifier for this queued message */
12
+ id: string;
13
+ /** Optional image attachment */
14
+ imageData?: ImageData;
15
+ /** Timestamp when the message was queued */
16
+ queuedAt: number;
17
+ }
18
+ /**
19
+ * Service for buffering user messages when a session is busy executing.
20
+ *
21
+ * When the LLM is processing a request, new messages from the user are
22
+ * queued and coalesced into a single input when the session becomes available.
23
+ *
24
+ * This improves UX by allowing users to add context while waiting for responses.
25
+ */
26
+ export declare class MessageQueueService {
27
+ private readonly eventBus?;
28
+ private readonly queue;
29
+ /**
30
+ * Creates a new message queue service.
31
+ *
32
+ * @param eventBus - Optional session event bus for queue events
33
+ */
34
+ constructor(eventBus?: SessionEventBus);
35
+ /**
36
+ * Clear all queued messages without processing.
37
+ */
38
+ clear(): void;
39
+ /**
40
+ * Dequeue all messages and coalesce into single input.
41
+ * Messages are combined intelligently based on count.
42
+ *
43
+ * @returns Coalesced content with images/files, or null if queue is empty
44
+ */
45
+ dequeueAll(): null | {
46
+ content: string;
47
+ files: FileData[];
48
+ images: ImageData[];
49
+ };
50
+ /**
51
+ * Queue a message for later processing.
52
+ *
53
+ * @param message - Message to queue (without id and queuedAt)
54
+ * @returns Queue position (1-based)
55
+ */
56
+ enqueue(message: Omit<QueuedMessage, 'id' | 'queuedAt'>): number;
57
+ /**
58
+ * Check if there are pending messages in the queue.
59
+ */
60
+ hasPending(): boolean;
61
+ /**
62
+ * Get the number of pending messages.
63
+ */
64
+ pendingCount(): number;
65
+ }