@trenchwork/erosolar 1.1.28 → 1.1.30

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.

Potentially problematic release.


This version of @trenchwork/erosolar might be problematic. Click here for more details.

Files changed (728) hide show
  1. package/README.md +1 -1
  2. package/SECURITY.md +35 -0
  3. package/dist/contracts/agent-schemas.json +1 -1
  4. package/package.json +1 -1
  5. package/dist/bin/cliMode.d.ts +0 -8
  6. package/dist/bin/cliMode.d.ts.map +0 -1
  7. package/dist/bin/cliMode.js +0 -20
  8. package/dist/bin/cliMode.js.map +0 -1
  9. package/dist/bin/deepseek.d.ts +0 -3
  10. package/dist/bin/deepseek.d.ts.map +0 -1
  11. package/dist/bin/deepseek.js +0 -307
  12. package/dist/bin/deepseek.js.map +0 -1
  13. package/dist/bin/erosolar.d.ts +0 -7
  14. package/dist/bin/erosolar.d.ts.map +0 -1
  15. package/dist/bin/erosolar.js +0 -7
  16. package/dist/bin/erosolar.js.map +0 -1
  17. package/dist/bin/selfTest.d.ts +0 -14
  18. package/dist/bin/selfTest.d.ts.map +0 -1
  19. package/dist/bin/selfTest.js +0 -298
  20. package/dist/bin/selfTest.js.map +0 -1
  21. package/dist/capabilities/_processRunner.d.ts +0 -17
  22. package/dist/capabilities/_processRunner.d.ts.map +0 -1
  23. package/dist/capabilities/_processRunner.js +0 -74
  24. package/dist/capabilities/_processRunner.js.map +0 -1
  25. package/dist/capabilities/aflppCapability.d.ts +0 -7
  26. package/dist/capabilities/aflppCapability.d.ts.map +0 -1
  27. package/dist/capabilities/aflppCapability.js +0 -301
  28. package/dist/capabilities/aflppCapability.js.map +0 -1
  29. package/dist/capabilities/baseCapability.d.ts +0 -72
  30. package/dist/capabilities/baseCapability.d.ts.map +0 -1
  31. package/dist/capabilities/baseCapability.js +0 -183
  32. package/dist/capabilities/baseCapability.js.map +0 -1
  33. package/dist/capabilities/bashCapability.d.ts +0 -13
  34. package/dist/capabilities/bashCapability.d.ts.map +0 -1
  35. package/dist/capabilities/bashCapability.js +0 -24
  36. package/dist/capabilities/bashCapability.js.map +0 -1
  37. package/dist/capabilities/binaryAnalysisCapability.d.ts +0 -7
  38. package/dist/capabilities/binaryAnalysisCapability.d.ts.map +0 -1
  39. package/dist/capabilities/binaryAnalysisCapability.js +0 -201
  40. package/dist/capabilities/binaryAnalysisCapability.js.map +0 -1
  41. package/dist/capabilities/editCapability.d.ts +0 -17
  42. package/dist/capabilities/editCapability.d.ts.map +0 -1
  43. package/dist/capabilities/editCapability.js +0 -27
  44. package/dist/capabilities/editCapability.js.map +0 -1
  45. package/dist/capabilities/enhancedGitCapability.d.ts +0 -7
  46. package/dist/capabilities/enhancedGitCapability.d.ts.map +0 -1
  47. package/dist/capabilities/enhancedGitCapability.js +0 -220
  48. package/dist/capabilities/enhancedGitCapability.js.map +0 -1
  49. package/dist/capabilities/filesystemCapability.d.ts +0 -13
  50. package/dist/capabilities/filesystemCapability.d.ts.map +0 -1
  51. package/dist/capabilities/filesystemCapability.js +0 -24
  52. package/dist/capabilities/filesystemCapability.js.map +0 -1
  53. package/dist/capabilities/gdbCapability.d.ts +0 -7
  54. package/dist/capabilities/gdbCapability.d.ts.map +0 -1
  55. package/dist/capabilities/gdbCapability.js +0 -125
  56. package/dist/capabilities/gdbCapability.js.map +0 -1
  57. package/dist/capabilities/ghidraHeadlessCapability.d.ts +0 -25
  58. package/dist/capabilities/ghidraHeadlessCapability.d.ts.map +0 -1
  59. package/dist/capabilities/ghidraHeadlessCapability.js +0 -593
  60. package/dist/capabilities/ghidraHeadlessCapability.js.map +0 -1
  61. package/dist/capabilities/gitHistoryCapability.d.ts +0 -6
  62. package/dist/capabilities/gitHistoryCapability.d.ts.map +0 -1
  63. package/dist/capabilities/gitHistoryCapability.js +0 -184
  64. package/dist/capabilities/gitHistoryCapability.js.map +0 -1
  65. package/dist/capabilities/hitlCapability.d.ts +0 -18
  66. package/dist/capabilities/hitlCapability.d.ts.map +0 -1
  67. package/dist/capabilities/hitlCapability.js +0 -29
  68. package/dist/capabilities/hitlCapability.js.map +0 -1
  69. package/dist/capabilities/index.d.ts +0 -18
  70. package/dist/capabilities/index.d.ts.map +0 -1
  71. package/dist/capabilities/index.js +0 -23
  72. package/dist/capabilities/index.js.map +0 -1
  73. package/dist/capabilities/kaliCapability.d.ts +0 -14
  74. package/dist/capabilities/kaliCapability.d.ts.map +0 -1
  75. package/dist/capabilities/kaliCapability.js +0 -478
  76. package/dist/capabilities/kaliCapability.js.map +0 -1
  77. package/dist/capabilities/mcpCapability.d.ts +0 -7
  78. package/dist/capabilities/mcpCapability.d.ts.map +0 -1
  79. package/dist/capabilities/mcpCapability.js +0 -80
  80. package/dist/capabilities/mcpCapability.js.map +0 -1
  81. package/dist/capabilities/memoryCapability.d.ts +0 -10
  82. package/dist/capabilities/memoryCapability.d.ts.map +0 -1
  83. package/dist/capabilities/memoryCapability.js +0 -22
  84. package/dist/capabilities/memoryCapability.js.map +0 -1
  85. package/dist/capabilities/notebookCapability.d.ts +0 -6
  86. package/dist/capabilities/notebookCapability.d.ts.map +0 -1
  87. package/dist/capabilities/notebookCapability.js +0 -17
  88. package/dist/capabilities/notebookCapability.js.map +0 -1
  89. package/dist/capabilities/pwntoolsCapability.d.ts +0 -7
  90. package/dist/capabilities/pwntoolsCapability.d.ts.map +0 -1
  91. package/dist/capabilities/pwntoolsCapability.js +0 -109
  92. package/dist/capabilities/pwntoolsCapability.js.map +0 -1
  93. package/dist/capabilities/searchCapability.d.ts +0 -19
  94. package/dist/capabilities/searchCapability.d.ts.map +0 -1
  95. package/dist/capabilities/searchCapability.js +0 -29
  96. package/dist/capabilities/searchCapability.js.map +0 -1
  97. package/dist/capabilities/skillCapability.d.ts +0 -6
  98. package/dist/capabilities/skillCapability.d.ts.map +0 -1
  99. package/dist/capabilities/skillCapability.js +0 -17
  100. package/dist/capabilities/skillCapability.js.map +0 -1
  101. package/dist/capabilities/todoCapability.d.ts +0 -11
  102. package/dist/capabilities/todoCapability.d.ts.map +0 -1
  103. package/dist/capabilities/todoCapability.js +0 -22
  104. package/dist/capabilities/todoCapability.js.map +0 -1
  105. package/dist/capabilities/toolManifest.d.ts +0 -3
  106. package/dist/capabilities/toolManifest.d.ts.map +0 -1
  107. package/dist/capabilities/toolManifest.js +0 -163
  108. package/dist/capabilities/toolManifest.js.map +0 -1
  109. package/dist/capabilities/toolRegistry.d.ts +0 -25
  110. package/dist/capabilities/toolRegistry.d.ts.map +0 -1
  111. package/dist/capabilities/toolRegistry.js +0 -150
  112. package/dist/capabilities/toolRegistry.js.map +0 -1
  113. package/dist/capabilities/unifiedCodingCapability.d.ts +0 -62
  114. package/dist/capabilities/unifiedCodingCapability.d.ts.map +0 -1
  115. package/dist/capabilities/unifiedCodingCapability.js +0 -788
  116. package/dist/capabilities/unifiedCodingCapability.js.map +0 -1
  117. package/dist/capabilities/webCapability.d.ts +0 -23
  118. package/dist/capabilities/webCapability.d.ts.map +0 -1
  119. package/dist/capabilities/webCapability.js +0 -33
  120. package/dist/capabilities/webCapability.js.map +0 -1
  121. package/dist/config.d.ts +0 -25
  122. package/dist/config.d.ts.map +0 -1
  123. package/dist/config.js +0 -155
  124. package/dist/config.js.map +0 -1
  125. package/dist/contracts/v1/agent.d.ts +0 -179
  126. package/dist/contracts/v1/agent.d.ts.map +0 -1
  127. package/dist/contracts/v1/agent.js +0 -8
  128. package/dist/contracts/v1/agent.js.map +0 -1
  129. package/dist/contracts/v1/agentProfileManifest.d.ts +0 -60
  130. package/dist/contracts/v1/agentProfileManifest.d.ts.map +0 -1
  131. package/dist/contracts/v1/agentProfileManifest.js +0 -9
  132. package/dist/contracts/v1/agentProfileManifest.js.map +0 -1
  133. package/dist/contracts/v1/agentRules.d.ts +0 -60
  134. package/dist/contracts/v1/agentRules.d.ts.map +0 -1
  135. package/dist/contracts/v1/agentRules.js +0 -10
  136. package/dist/contracts/v1/agentRules.js.map +0 -1
  137. package/dist/contracts/v1/provider.d.ts +0 -149
  138. package/dist/contracts/v1/provider.d.ts.map +0 -1
  139. package/dist/contracts/v1/provider.js +0 -7
  140. package/dist/contracts/v1/provider.js.map +0 -1
  141. package/dist/contracts/v1/tool.d.ts +0 -136
  142. package/dist/contracts/v1/tool.d.ts.map +0 -1
  143. package/dist/contracts/v1/tool.js +0 -7
  144. package/dist/contracts/v1/tool.js.map +0 -1
  145. package/dist/contracts/v1/toolAccess.d.ts +0 -43
  146. package/dist/contracts/v1/toolAccess.d.ts.map +0 -1
  147. package/dist/contracts/v1/toolAccess.js +0 -9
  148. package/dist/contracts/v1/toolAccess.js.map +0 -1
  149. package/dist/core/agent.d.ts +0 -320
  150. package/dist/core/agent.d.ts.map +0 -1
  151. package/dist/core/agent.js +0 -1627
  152. package/dist/core/agent.js.map +0 -1
  153. package/dist/core/agentProfileManifest.d.ts +0 -3
  154. package/dist/core/agentProfileManifest.d.ts.map +0 -1
  155. package/dist/core/agentProfileManifest.js +0 -188
  156. package/dist/core/agentProfileManifest.js.map +0 -1
  157. package/dist/core/agentProfiles.d.ts +0 -22
  158. package/dist/core/agentProfiles.d.ts.map +0 -1
  159. package/dist/core/agentProfiles.js +0 -35
  160. package/dist/core/agentProfiles.js.map +0 -1
  161. package/dist/core/agentRegistry.d.ts +0 -111
  162. package/dist/core/agentRegistry.d.ts.map +0 -1
  163. package/dist/core/agentRegistry.js +0 -229
  164. package/dist/core/agentRegistry.js.map +0 -1
  165. package/dist/core/agentRulebook.d.ts +0 -11
  166. package/dist/core/agentRulebook.d.ts.map +0 -1
  167. package/dist/core/agentRulebook.js +0 -136
  168. package/dist/core/agentRulebook.js.map +0 -1
  169. package/dist/core/agentSchemaLoader.d.ts +0 -131
  170. package/dist/core/agentSchemaLoader.d.ts.map +0 -1
  171. package/dist/core/agentSchemaLoader.js +0 -235
  172. package/dist/core/agentSchemaLoader.js.map +0 -1
  173. package/dist/core/aiErrorFixer.d.ts +0 -57
  174. package/dist/core/aiErrorFixer.d.ts.map +0 -1
  175. package/dist/core/aiErrorFixer.js +0 -214
  176. package/dist/core/aiErrorFixer.js.map +0 -1
  177. package/dist/core/artifactStore.d.ts +0 -35
  178. package/dist/core/artifactStore.d.ts.map +0 -1
  179. package/dist/core/artifactStore.js +0 -105
  180. package/dist/core/artifactStore.js.map +0 -1
  181. package/dist/core/auth.d.ts +0 -15
  182. package/dist/core/auth.d.ts.map +0 -1
  183. package/dist/core/auth.js +0 -291
  184. package/dist/core/auth.js.map +0 -1
  185. package/dist/core/bashCommandGuidance.d.ts +0 -16
  186. package/dist/core/bashCommandGuidance.d.ts.map +0 -1
  187. package/dist/core/bashCommandGuidance.js +0 -40
  188. package/dist/core/bashCommandGuidance.js.map +0 -1
  189. package/dist/core/constants.d.ts +0 -31
  190. package/dist/core/constants.d.ts.map +0 -1
  191. package/dist/core/constants.js +0 -62
  192. package/dist/core/constants.js.map +0 -1
  193. package/dist/core/contextManager.d.ts +0 -271
  194. package/dist/core/contextManager.d.ts.map +0 -1
  195. package/dist/core/contextManager.js +0 -1073
  196. package/dist/core/contextManager.js.map +0 -1
  197. package/dist/core/contextWindow.d.ts +0 -42
  198. package/dist/core/contextWindow.d.ts.map +0 -1
  199. package/dist/core/contextWindow.js +0 -123
  200. package/dist/core/contextWindow.js.map +0 -1
  201. package/dist/core/customCommands.d.ts +0 -19
  202. package/dist/core/customCommands.d.ts.map +0 -1
  203. package/dist/core/customCommands.js +0 -85
  204. package/dist/core/customCommands.js.map +0 -1
  205. package/dist/core/errors/apiKeyErrors.d.ts +0 -11
  206. package/dist/core/errors/apiKeyErrors.d.ts.map +0 -1
  207. package/dist/core/errors/apiKeyErrors.js +0 -159
  208. package/dist/core/errors/apiKeyErrors.js.map +0 -1
  209. package/dist/core/errors/errorTypes.d.ts +0 -111
  210. package/dist/core/errors/errorTypes.d.ts.map +0 -1
  211. package/dist/core/errors/errorTypes.js +0 -345
  212. package/dist/core/errors/errorTypes.js.map +0 -1
  213. package/dist/core/errors/index.d.ts +0 -50
  214. package/dist/core/errors/index.d.ts.map +0 -1
  215. package/dist/core/errors/index.js +0 -156
  216. package/dist/core/errors/index.js.map +0 -1
  217. package/dist/core/errors/networkErrors.d.ts +0 -14
  218. package/dist/core/errors/networkErrors.d.ts.map +0 -1
  219. package/dist/core/errors/networkErrors.js +0 -53
  220. package/dist/core/errors/networkErrors.js.map +0 -1
  221. package/dist/core/errors/safetyValidator.d.ts +0 -109
  222. package/dist/core/errors/safetyValidator.d.ts.map +0 -1
  223. package/dist/core/errors/safetyValidator.js +0 -271
  224. package/dist/core/errors/safetyValidator.js.map +0 -1
  225. package/dist/core/errors.d.ts +0 -4
  226. package/dist/core/errors.d.ts.map +0 -1
  227. package/dist/core/errors.js +0 -33
  228. package/dist/core/errors.js.map +0 -1
  229. package/dist/core/finalResponseFormatter.d.ts +0 -10
  230. package/dist/core/finalResponseFormatter.d.ts.map +0 -1
  231. package/dist/core/finalResponseFormatter.js +0 -14
  232. package/dist/core/finalResponseFormatter.js.map +0 -1
  233. package/dist/core/guardrails.d.ts +0 -146
  234. package/dist/core/guardrails.d.ts.map +0 -1
  235. package/dist/core/guardrails.js +0 -361
  236. package/dist/core/guardrails.js.map +0 -1
  237. package/dist/core/hitl.d.ts +0 -119
  238. package/dist/core/hitl.d.ts.map +0 -1
  239. package/dist/core/hitl.js +0 -387
  240. package/dist/core/hitl.js.map +0 -1
  241. package/dist/core/hooks.d.ts +0 -95
  242. package/dist/core/hooks.d.ts.map +0 -1
  243. package/dist/core/hooks.js +0 -239
  244. package/dist/core/hooks.js.map +0 -1
  245. package/dist/core/index.d.ts +0 -7
  246. package/dist/core/index.d.ts.map +0 -1
  247. package/dist/core/index.js +0 -7
  248. package/dist/core/index.js.map +0 -1
  249. package/dist/core/inputProtection.d.ts +0 -122
  250. package/dist/core/inputProtection.d.ts.map +0 -1
  251. package/dist/core/inputProtection.js +0 -422
  252. package/dist/core/inputProtection.js.map +0 -1
  253. package/dist/core/modelDiscovery.d.ts +0 -105
  254. package/dist/core/modelDiscovery.d.ts.map +0 -1
  255. package/dist/core/modelDiscovery.js +0 -768
  256. package/dist/core/modelDiscovery.js.map +0 -1
  257. package/dist/core/multilinePasteHandler.d.ts +0 -35
  258. package/dist/core/multilinePasteHandler.d.ts.map +0 -1
  259. package/dist/core/multilinePasteHandler.js +0 -81
  260. package/dist/core/multilinePasteHandler.js.map +0 -1
  261. package/dist/core/preferences.d.ts +0 -65
  262. package/dist/core/preferences.d.ts.map +0 -1
  263. package/dist/core/preferences.js +0 -305
  264. package/dist/core/preferences.js.map +0 -1
  265. package/dist/core/providerKeys.d.ts +0 -20
  266. package/dist/core/providerKeys.d.ts.map +0 -1
  267. package/dist/core/providerKeys.js +0 -40
  268. package/dist/core/providerKeys.js.map +0 -1
  269. package/dist/core/refusalDetection.d.ts +0 -2
  270. package/dist/core/refusalDetection.d.ts.map +0 -1
  271. package/dist/core/refusalDetection.js +0 -51
  272. package/dist/core/refusalDetection.js.map +0 -1
  273. package/dist/core/resultVerification.d.ts +0 -47
  274. package/dist/core/resultVerification.d.ts.map +0 -1
  275. package/dist/core/resultVerification.js +0 -126
  276. package/dist/core/resultVerification.js.map +0 -1
  277. package/dist/core/reviewerGuard.d.ts +0 -37
  278. package/dist/core/reviewerGuard.d.ts.map +0 -1
  279. package/dist/core/reviewerGuard.js +0 -188
  280. package/dist/core/reviewerGuard.js.map +0 -1
  281. package/dist/core/schemaValidator.d.ts +0 -49
  282. package/dist/core/schemaValidator.d.ts.map +0 -1
  283. package/dist/core/schemaValidator.js +0 -234
  284. package/dist/core/schemaValidator.js.map +0 -1
  285. package/dist/core/secretStore.d.ts +0 -48
  286. package/dist/core/secretStore.d.ts.map +0 -1
  287. package/dist/core/secretStore.js +0 -259
  288. package/dist/core/secretStore.js.map +0 -1
  289. package/dist/core/sessionStorage.d.ts +0 -10
  290. package/dist/core/sessionStorage.d.ts.map +0 -1
  291. package/dist/core/sessionStorage.js +0 -46
  292. package/dist/core/sessionStorage.js.map +0 -1
  293. package/dist/core/sessionStore.d.ts +0 -35
  294. package/dist/core/sessionStore.d.ts.map +0 -1
  295. package/dist/core/sessionStore.js +0 -191
  296. package/dist/core/sessionStore.js.map +0 -1
  297. package/dist/core/sharedSecrets.d.ts +0 -60
  298. package/dist/core/sharedSecrets.d.ts.map +0 -1
  299. package/dist/core/sharedSecrets.js +0 -111
  300. package/dist/core/sharedSecrets.js.map +0 -1
  301. package/dist/core/shutdown.d.ts +0 -34
  302. package/dist/core/shutdown.d.ts.map +0 -1
  303. package/dist/core/shutdown.js +0 -186
  304. package/dist/core/shutdown.js.map +0 -1
  305. package/dist/core/sudoPasswordManager.d.ts +0 -52
  306. package/dist/core/sudoPasswordManager.d.ts.map +0 -1
  307. package/dist/core/sudoPasswordManager.js +0 -115
  308. package/dist/core/sudoPasswordManager.js.map +0 -1
  309. package/dist/core/taskCompletionDetector.d.ts +0 -117
  310. package/dist/core/taskCompletionDetector.d.ts.map +0 -1
  311. package/dist/core/taskCompletionDetector.js +0 -532
  312. package/dist/core/taskCompletionDetector.js.map +0 -1
  313. package/dist/core/testFailureMonitor.d.ts +0 -67
  314. package/dist/core/testFailureMonitor.d.ts.map +0 -1
  315. package/dist/core/testFailureMonitor.js +0 -262
  316. package/dist/core/testFailureMonitor.js.map +0 -1
  317. package/dist/core/toolPreconditions.d.ts +0 -34
  318. package/dist/core/toolPreconditions.d.ts.map +0 -1
  319. package/dist/core/toolPreconditions.js +0 -242
  320. package/dist/core/toolPreconditions.js.map +0 -1
  321. package/dist/core/toolRuntime.d.ts +0 -192
  322. package/dist/core/toolRuntime.d.ts.map +0 -1
  323. package/dist/core/toolRuntime.js +0 -511
  324. package/dist/core/toolRuntime.js.map +0 -1
  325. package/dist/core/types/utilityTypes.d.ts +0 -183
  326. package/dist/core/types/utilityTypes.d.ts.map +0 -1
  327. package/dist/core/types/utilityTypes.js +0 -273
  328. package/dist/core/types/utilityTypes.js.map +0 -1
  329. package/dist/core/types.d.ts +0 -334
  330. package/dist/core/types.d.ts.map +0 -1
  331. package/dist/core/types.js +0 -76
  332. package/dist/core/types.js.map +0 -1
  333. package/dist/core/updateChecker.d.ts +0 -148
  334. package/dist/core/updateChecker.d.ts.map +0 -1
  335. package/dist/core/updateChecker.js +0 -599
  336. package/dist/core/updateChecker.js.map +0 -1
  337. package/dist/core/usageTracker.d.ts +0 -11
  338. package/dist/core/usageTracker.d.ts.map +0 -1
  339. package/dist/core/usageTracker.js +0 -128
  340. package/dist/core/usageTracker.js.map +0 -1
  341. package/dist/core/userApproval.d.ts +0 -95
  342. package/dist/core/userApproval.d.ts.map +0 -1
  343. package/dist/core/userApproval.js +0 -239
  344. package/dist/core/userApproval.js.map +0 -1
  345. package/dist/headless/interactiveShell.d.ts +0 -22
  346. package/dist/headless/interactiveShell.d.ts.map +0 -1
  347. package/dist/headless/interactiveShell.js +0 -2121
  348. package/dist/headless/interactiveShell.js.map +0 -1
  349. package/dist/leanAgent.d.ts +0 -73
  350. package/dist/leanAgent.d.ts.map +0 -1
  351. package/dist/leanAgent.js +0 -177
  352. package/dist/leanAgent.js.map +0 -1
  353. package/dist/plugins/index.d.ts +0 -49
  354. package/dist/plugins/index.d.ts.map +0 -1
  355. package/dist/plugins/index.js +0 -104
  356. package/dist/plugins/index.js.map +0 -1
  357. package/dist/plugins/providers/anthropic/index.d.ts +0 -9
  358. package/dist/plugins/providers/anthropic/index.d.ts.map +0 -1
  359. package/dist/plugins/providers/anthropic/index.js +0 -48
  360. package/dist/plugins/providers/anthropic/index.js.map +0 -1
  361. package/dist/plugins/providers/deepseek/index.d.ts +0 -11
  362. package/dist/plugins/providers/deepseek/index.d.ts.map +0 -1
  363. package/dist/plugins/providers/deepseek/index.js +0 -54
  364. package/dist/plugins/providers/deepseek/index.js.map +0 -1
  365. package/dist/plugins/providers/index.d.ts +0 -2
  366. package/dist/plugins/providers/index.d.ts.map +0 -1
  367. package/dist/plugins/providers/index.js +0 -17
  368. package/dist/plugins/providers/index.js.map +0 -1
  369. package/dist/plugins/providers/openai/index.d.ts +0 -10
  370. package/dist/plugins/providers/openai/index.d.ts.map +0 -1
  371. package/dist/plugins/providers/openai/index.js +0 -47
  372. package/dist/plugins/providers/openai/index.js.map +0 -1
  373. package/dist/plugins/providers/xai/index.d.ts +0 -10
  374. package/dist/plugins/providers/xai/index.d.ts.map +0 -1
  375. package/dist/plugins/providers/xai/index.js +0 -47
  376. package/dist/plugins/providers/xai/index.js.map +0 -1
  377. package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.d.ts +0 -10
  378. package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.d.ts.map +0 -1
  379. package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.js +0 -110
  380. package/dist/plugins/tools/agentSpawning/agentSpawningPlugin.js.map +0 -1
  381. package/dist/plugins/tools/bash/localBashPlugin.d.ts +0 -3
  382. package/dist/plugins/tools/bash/localBashPlugin.d.ts.map +0 -1
  383. package/dist/plugins/tools/bash/localBashPlugin.js +0 -14
  384. package/dist/plugins/tools/bash/localBashPlugin.js.map +0 -1
  385. package/dist/plugins/tools/edit/editPlugin.d.ts +0 -9
  386. package/dist/plugins/tools/edit/editPlugin.d.ts.map +0 -1
  387. package/dist/plugins/tools/edit/editPlugin.js +0 -15
  388. package/dist/plugins/tools/edit/editPlugin.js.map +0 -1
  389. package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.d.ts +0 -3
  390. package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.d.ts.map +0 -1
  391. package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.js +0 -9
  392. package/dist/plugins/tools/enhancedGit/enhancedGitPlugin.js.map +0 -1
  393. package/dist/plugins/tools/filesystem/localFilesystemPlugin.d.ts +0 -3
  394. package/dist/plugins/tools/filesystem/localFilesystemPlugin.d.ts.map +0 -1
  395. package/dist/plugins/tools/filesystem/localFilesystemPlugin.js +0 -14
  396. package/dist/plugins/tools/filesystem/localFilesystemPlugin.js.map +0 -1
  397. package/dist/plugins/tools/gitHistory/gitHistoryPlugin.d.ts +0 -3
  398. package/dist/plugins/tools/gitHistory/gitHistoryPlugin.d.ts.map +0 -1
  399. package/dist/plugins/tools/gitHistory/gitHistoryPlugin.js +0 -9
  400. package/dist/plugins/tools/gitHistory/gitHistoryPlugin.js.map +0 -1
  401. package/dist/plugins/tools/index.d.ts +0 -3
  402. package/dist/plugins/tools/index.d.ts.map +0 -1
  403. package/dist/plugins/tools/index.js +0 -3
  404. package/dist/plugins/tools/index.js.map +0 -1
  405. package/dist/plugins/tools/integrity/integrityPlugin.d.ts +0 -3
  406. package/dist/plugins/tools/integrity/integrityPlugin.d.ts.map +0 -1
  407. package/dist/plugins/tools/integrity/integrityPlugin.js +0 -31
  408. package/dist/plugins/tools/integrity/integrityPlugin.js.map +0 -1
  409. package/dist/plugins/tools/kali/kaliPlugin.d.ts +0 -3
  410. package/dist/plugins/tools/kali/kaliPlugin.d.ts.map +0 -1
  411. package/dist/plugins/tools/kali/kaliPlugin.js +0 -10
  412. package/dist/plugins/tools/kali/kaliPlugin.js.map +0 -1
  413. package/dist/plugins/tools/mcp/mcpClient.d.ts +0 -49
  414. package/dist/plugins/tools/mcp/mcpClient.d.ts.map +0 -1
  415. package/dist/plugins/tools/mcp/mcpClient.js +0 -112
  416. package/dist/plugins/tools/mcp/mcpClient.js.map +0 -1
  417. package/dist/plugins/tools/mcp/mcpPlugin.d.ts +0 -3
  418. package/dist/plugins/tools/mcp/mcpPlugin.d.ts.map +0 -1
  419. package/dist/plugins/tools/mcp/mcpPlugin.js +0 -10
  420. package/dist/plugins/tools/mcp/mcpPlugin.js.map +0 -1
  421. package/dist/plugins/tools/nodeDefaults.d.ts +0 -13
  422. package/dist/plugins/tools/nodeDefaults.d.ts.map +0 -1
  423. package/dist/plugins/tools/nodeDefaults.js +0 -37
  424. package/dist/plugins/tools/nodeDefaults.js.map +0 -1
  425. package/dist/plugins/tools/orchestration/orchestrationPlugin.d.ts +0 -3
  426. package/dist/plugins/tools/orchestration/orchestrationPlugin.d.ts.map +0 -1
  427. package/dist/plugins/tools/orchestration/orchestrationPlugin.js +0 -340
  428. package/dist/plugins/tools/orchestration/orchestrationPlugin.js.map +0 -1
  429. package/dist/plugins/tools/registry.d.ts +0 -22
  430. package/dist/plugins/tools/registry.d.ts.map +0 -1
  431. package/dist/plugins/tools/registry.js +0 -58
  432. package/dist/plugins/tools/registry.js.map +0 -1
  433. package/dist/plugins/tools/search/localSearchPlugin.d.ts +0 -3
  434. package/dist/plugins/tools/search/localSearchPlugin.d.ts.map +0 -1
  435. package/dist/plugins/tools/search/localSearchPlugin.js +0 -14
  436. package/dist/plugins/tools/search/localSearchPlugin.js.map +0 -1
  437. package/dist/plugins/tools/skills/skillPlugin.d.ts +0 -3
  438. package/dist/plugins/tools/skills/skillPlugin.d.ts.map +0 -1
  439. package/dist/plugins/tools/skills/skillPlugin.js +0 -27
  440. package/dist/plugins/tools/skills/skillPlugin.js.map +0 -1
  441. package/dist/plugins/tools/todo/todoPlugin.d.ts +0 -3
  442. package/dist/plugins/tools/todo/todoPlugin.d.ts.map +0 -1
  443. package/dist/plugins/tools/todo/todoPlugin.js +0 -10
  444. package/dist/plugins/tools/todo/todoPlugin.js.map +0 -1
  445. package/dist/providers/baseProvider.d.ts +0 -148
  446. package/dist/providers/baseProvider.d.ts.map +0 -1
  447. package/dist/providers/baseProvider.js +0 -284
  448. package/dist/providers/baseProvider.js.map +0 -1
  449. package/dist/providers/openaiChatCompletionsProvider.d.ts +0 -64
  450. package/dist/providers/openaiChatCompletionsProvider.d.ts.map +0 -1
  451. package/dist/providers/openaiChatCompletionsProvider.js +0 -1018
  452. package/dist/providers/openaiChatCompletionsProvider.js.map +0 -1
  453. package/dist/providers/providerFactory.d.ts +0 -22
  454. package/dist/providers/providerFactory.d.ts.map +0 -1
  455. package/dist/providers/providerFactory.js +0 -25
  456. package/dist/providers/providerFactory.js.map +0 -1
  457. package/dist/providers/resilientProvider.d.ts +0 -103
  458. package/dist/providers/resilientProvider.d.ts.map +0 -1
  459. package/dist/providers/resilientProvider.js +0 -468
  460. package/dist/providers/resilientProvider.js.map +0 -1
  461. package/dist/runtime/agentController.d.ts +0 -121
  462. package/dist/runtime/agentController.d.ts.map +0 -1
  463. package/dist/runtime/agentController.js +0 -739
  464. package/dist/runtime/agentController.js.map +0 -1
  465. package/dist/runtime/agentHost.d.ts +0 -61
  466. package/dist/runtime/agentHost.d.ts.map +0 -1
  467. package/dist/runtime/agentHost.js +0 -158
  468. package/dist/runtime/agentHost.js.map +0 -1
  469. package/dist/runtime/agentSession.d.ts +0 -49
  470. package/dist/runtime/agentSession.d.ts.map +0 -1
  471. package/dist/runtime/agentSession.js +0 -218
  472. package/dist/runtime/agentSession.js.map +0 -1
  473. package/dist/runtime/agentSpawningWiring.d.ts +0 -23
  474. package/dist/runtime/agentSpawningWiring.d.ts.map +0 -1
  475. package/dist/runtime/agentSpawningWiring.js +0 -119
  476. package/dist/runtime/agentSpawningWiring.js.map +0 -1
  477. package/dist/runtime/agentWorkerPool.d.ts +0 -167
  478. package/dist/runtime/agentWorkerPool.d.ts.map +0 -1
  479. package/dist/runtime/agentWorkerPool.js +0 -435
  480. package/dist/runtime/agentWorkerPool.js.map +0 -1
  481. package/dist/runtime/node.d.ts +0 -7
  482. package/dist/runtime/node.d.ts.map +0 -1
  483. package/dist/runtime/node.js +0 -56
  484. package/dist/runtime/node.js.map +0 -1
  485. package/dist/runtime/universal.d.ts +0 -18
  486. package/dist/runtime/universal.d.ts.map +0 -1
  487. package/dist/runtime/universal.js +0 -21
  488. package/dist/runtime/universal.js.map +0 -1
  489. package/dist/shell/autoExecutor.d.ts +0 -70
  490. package/dist/shell/autoExecutor.d.ts.map +0 -1
  491. package/dist/shell/autoExecutor.js +0 -320
  492. package/dist/shell/autoExecutor.js.map +0 -1
  493. package/dist/shell/commandRegistry.d.ts +0 -122
  494. package/dist/shell/commandRegistry.d.ts.map +0 -1
  495. package/dist/shell/commandRegistry.js +0 -355
  496. package/dist/shell/commandRegistry.js.map +0 -1
  497. package/dist/shell/composableMessage.d.ts +0 -178
  498. package/dist/shell/composableMessage.d.ts.map +0 -1
  499. package/dist/shell/composableMessage.js +0 -384
  500. package/dist/shell/composableMessage.js.map +0 -1
  501. package/dist/shell/liveStatus.d.ts +0 -27
  502. package/dist/shell/liveStatus.d.ts.map +0 -1
  503. package/dist/shell/liveStatus.js +0 -53
  504. package/dist/shell/liveStatus.js.map +0 -1
  505. package/dist/shell/systemPrompt.d.ts +0 -12
  506. package/dist/shell/systemPrompt.d.ts.map +0 -1
  507. package/dist/shell/systemPrompt.js +0 -16
  508. package/dist/shell/systemPrompt.js.map +0 -1
  509. package/dist/shell/vimMode.d.ts +0 -66
  510. package/dist/shell/vimMode.d.ts.map +0 -1
  511. package/dist/shell/vimMode.js +0 -435
  512. package/dist/shell/vimMode.js.map +0 -1
  513. package/dist/tools/bashTools.d.ts +0 -11
  514. package/dist/tools/bashTools.d.ts.map +0 -1
  515. package/dist/tools/bashTools.js +0 -779
  516. package/dist/tools/bashTools.js.map +0 -1
  517. package/dist/tools/diffUtils.d.ts +0 -43
  518. package/dist/tools/diffUtils.d.ts.map +0 -1
  519. package/dist/tools/diffUtils.js +0 -607
  520. package/dist/tools/diffUtils.js.map +0 -1
  521. package/dist/tools/editTools.d.ts +0 -29
  522. package/dist/tools/editTools.d.ts.map +0 -1
  523. package/dist/tools/editTools.js +0 -792
  524. package/dist/tools/editTools.js.map +0 -1
  525. package/dist/tools/fileChangeTracker.d.ts +0 -47
  526. package/dist/tools/fileChangeTracker.d.ts.map +0 -1
  527. package/dist/tools/fileChangeTracker.js +0 -154
  528. package/dist/tools/fileChangeTracker.js.map +0 -1
  529. package/dist/tools/fileReadTracker.d.ts +0 -69
  530. package/dist/tools/fileReadTracker.d.ts.map +0 -1
  531. package/dist/tools/fileReadTracker.js +0 -213
  532. package/dist/tools/fileReadTracker.js.map +0 -1
  533. package/dist/tools/fileTools.d.ts +0 -3
  534. package/dist/tools/fileTools.d.ts.map +0 -1
  535. package/dist/tools/fileTools.js +0 -389
  536. package/dist/tools/fileTools.js.map +0 -1
  537. package/dist/tools/grepTools.d.ts +0 -3
  538. package/dist/tools/grepTools.d.ts.map +0 -1
  539. package/dist/tools/grepTools.js +0 -128
  540. package/dist/tools/grepTools.js.map +0 -1
  541. package/dist/tools/heliaControl.d.ts +0 -51
  542. package/dist/tools/heliaControl.d.ts.map +0 -1
  543. package/dist/tools/heliaControl.js +0 -93
  544. package/dist/tools/heliaControl.js.map +0 -1
  545. package/dist/tools/hitlTools.d.ts +0 -7
  546. package/dist/tools/hitlTools.d.ts.map +0 -1
  547. package/dist/tools/hitlTools.js +0 -185
  548. package/dist/tools/hitlTools.js.map +0 -1
  549. package/dist/tools/localExplore.d.ts +0 -38
  550. package/dist/tools/localExplore.d.ts.map +0 -1
  551. package/dist/tools/localExplore.js +0 -30
  552. package/dist/tools/localExplore.js.map +0 -1
  553. package/dist/tools/memoryTools.d.ts +0 -20
  554. package/dist/tools/memoryTools.d.ts.map +0 -1
  555. package/dist/tools/memoryTools.js +0 -180
  556. package/dist/tools/memoryTools.js.map +0 -1
  557. package/dist/tools/notebookTools.d.ts +0 -20
  558. package/dist/tools/notebookTools.d.ts.map +0 -1
  559. package/dist/tools/notebookTools.js +0 -140
  560. package/dist/tools/notebookTools.js.map +0 -1
  561. package/dist/tools/searchTools.d.ts +0 -12
  562. package/dist/tools/searchTools.d.ts.map +0 -1
  563. package/dist/tools/searchTools.js +0 -413
  564. package/dist/tools/searchTools.js.map +0 -1
  565. package/dist/tools/skillTools.d.ts +0 -24
  566. package/dist/tools/skillTools.d.ts.map +0 -1
  567. package/dist/tools/skillTools.js +0 -140
  568. package/dist/tools/skillTools.js.map +0 -1
  569. package/dist/tools/todoTools.d.ts +0 -24
  570. package/dist/tools/todoTools.d.ts.map +0 -1
  571. package/dist/tools/todoTools.js +0 -101
  572. package/dist/tools/todoTools.js.map +0 -1
  573. package/dist/tools/webTools.d.ts +0 -26
  574. package/dist/tools/webTools.d.ts.map +0 -1
  575. package/dist/tools/webTools.js +0 -332
  576. package/dist/tools/webTools.js.map +0 -1
  577. package/dist/ui/RenderGate.d.ts +0 -83
  578. package/dist/ui/RenderGate.d.ts.map +0 -1
  579. package/dist/ui/RenderGate.js +0 -138
  580. package/dist/ui/RenderGate.js.map +0 -1
  581. package/dist/ui/animatedStatus.d.ts +0 -140
  582. package/dist/ui/animatedStatus.d.ts.map +0 -1
  583. package/dist/ui/animatedStatus.js +0 -480
  584. package/dist/ui/animatedStatus.js.map +0 -1
  585. package/dist/ui/animation/AnimationScheduler.d.ts +0 -197
  586. package/dist/ui/animation/AnimationScheduler.d.ts.map +0 -1
  587. package/dist/ui/animation/AnimationScheduler.js +0 -440
  588. package/dist/ui/animation/AnimationScheduler.js.map +0 -1
  589. package/dist/ui/codeHighlighter.d.ts +0 -6
  590. package/dist/ui/codeHighlighter.d.ts.map +0 -1
  591. package/dist/ui/codeHighlighter.js +0 -855
  592. package/dist/ui/codeHighlighter.js.map +0 -1
  593. package/dist/ui/designSystem.d.ts +0 -26
  594. package/dist/ui/designSystem.d.ts.map +0 -1
  595. package/dist/ui/designSystem.js +0 -114
  596. package/dist/ui/designSystem.js.map +0 -1
  597. package/dist/ui/errorFormatter.d.ts +0 -64
  598. package/dist/ui/errorFormatter.d.ts.map +0 -1
  599. package/dist/ui/errorFormatter.js +0 -316
  600. package/dist/ui/errorFormatter.js.map +0 -1
  601. package/dist/ui/globalWriteLock.d.ts +0 -63
  602. package/dist/ui/globalWriteLock.d.ts.map +0 -1
  603. package/dist/ui/globalWriteLock.js +0 -173
  604. package/dist/ui/globalWriteLock.js.map +0 -1
  605. package/dist/ui/index.d.ts +0 -31
  606. package/dist/ui/index.d.ts.map +0 -1
  607. package/dist/ui/index.js +0 -49
  608. package/dist/ui/index.js.map +0 -1
  609. package/dist/ui/ink/App.d.ts +0 -39
  610. package/dist/ui/ink/App.d.ts.map +0 -1
  611. package/dist/ui/ink/App.js +0 -18
  612. package/dist/ui/ink/App.js.map +0 -1
  613. package/dist/ui/ink/ChatStatic.d.ts +0 -29
  614. package/dist/ui/ink/ChatStatic.d.ts.map +0 -1
  615. package/dist/ui/ink/ChatStatic.js +0 -30
  616. package/dist/ui/ink/ChatStatic.js.map +0 -1
  617. package/dist/ui/ink/InkPromptController.d.ts +0 -286
  618. package/dist/ui/ink/InkPromptController.d.ts.map +0 -1
  619. package/dist/ui/ink/InkPromptController.js +0 -558
  620. package/dist/ui/ink/InkPromptController.js.map +0 -1
  621. package/dist/ui/ink/Prompt.d.ts +0 -36
  622. package/dist/ui/ink/Prompt.d.ts.map +0 -1
  623. package/dist/ui/ink/Prompt.js +0 -296
  624. package/dist/ui/ink/Prompt.js.map +0 -1
  625. package/dist/ui/ink/StatusLine.d.ts +0 -25
  626. package/dist/ui/ink/StatusLine.d.ts.map +0 -1
  627. package/dist/ui/ink/StatusLine.js +0 -11
  628. package/dist/ui/ink/StatusLine.js.map +0 -1
  629. package/dist/ui/ink/adapter.d.ts +0 -58
  630. package/dist/ui/ink/adapter.d.ts.map +0 -1
  631. package/dist/ui/ink/adapter.js +0 -113
  632. package/dist/ui/ink/adapter.js.map +0 -1
  633. package/dist/ui/interrupts/InterruptManager.d.ts +0 -157
  634. package/dist/ui/interrupts/InterruptManager.d.ts.map +0 -1
  635. package/dist/ui/interrupts/InterruptManager.js +0 -501
  636. package/dist/ui/interrupts/InterruptManager.js.map +0 -1
  637. package/dist/ui/layout.d.ts +0 -27
  638. package/dist/ui/layout.d.ts.map +0 -1
  639. package/dist/ui/layout.js +0 -184
  640. package/dist/ui/layout.js.map +0 -1
  641. package/dist/ui/outputMode.d.ts +0 -58
  642. package/dist/ui/outputMode.d.ts.map +0 -1
  643. package/dist/ui/outputMode.js +0 -179
  644. package/dist/ui/outputMode.js.map +0 -1
  645. package/dist/ui/overlay/OverlayManager.d.ts +0 -105
  646. package/dist/ui/overlay/OverlayManager.d.ts.map +0 -1
  647. package/dist/ui/overlay/OverlayManager.js +0 -304
  648. package/dist/ui/overlay/OverlayManager.js.map +0 -1
  649. package/dist/ui/premiumComponents.d.ts +0 -54
  650. package/dist/ui/premiumComponents.d.ts.map +0 -1
  651. package/dist/ui/premiumComponents.js +0 -241
  652. package/dist/ui/premiumComponents.js.map +0 -1
  653. package/dist/ui/richText.d.ts +0 -13
  654. package/dist/ui/richText.d.ts.map +0 -1
  655. package/dist/ui/richText.js +0 -444
  656. package/dist/ui/richText.js.map +0 -1
  657. package/dist/ui/telemetry/ResponseTracker.d.ts +0 -22
  658. package/dist/ui/telemetry/ResponseTracker.d.ts.map +0 -1
  659. package/dist/ui/telemetry/ResponseTracker.js +0 -60
  660. package/dist/ui/telemetry/ResponseTracker.js.map +0 -1
  661. package/dist/ui/telemetry/UITelemetry.d.ts +0 -181
  662. package/dist/ui/telemetry/UITelemetry.d.ts.map +0 -1
  663. package/dist/ui/telemetry/UITelemetry.js +0 -446
  664. package/dist/ui/telemetry/UITelemetry.js.map +0 -1
  665. package/dist/ui/textHighlighter.d.ts +0 -83
  666. package/dist/ui/textHighlighter.d.ts.map +0 -1
  667. package/dist/ui/textHighlighter.js +0 -267
  668. package/dist/ui/textHighlighter.js.map +0 -1
  669. package/dist/ui/theme.d.ts +0 -351
  670. package/dist/ui/theme.d.ts.map +0 -1
  671. package/dist/ui/theme.js +0 -434
  672. package/dist/ui/theme.js.map +0 -1
  673. package/dist/ui/toolDisplay.d.ts +0 -221
  674. package/dist/ui/toolDisplay.d.ts.map +0 -1
  675. package/dist/ui/toolDisplay.js +0 -1654
  676. package/dist/ui/toolDisplay.js.map +0 -1
  677. package/dist/ui/uiConstants.d.ts +0 -253
  678. package/dist/ui/uiConstants.d.ts.map +0 -1
  679. package/dist/ui/uiConstants.js +0 -437
  680. package/dist/ui/uiConstants.js.map +0 -1
  681. package/dist/utils/analytics.d.ts +0 -2
  682. package/dist/utils/analytics.d.ts.map +0 -1
  683. package/dist/utils/analytics.js +0 -51
  684. package/dist/utils/analytics.js.map +0 -1
  685. package/dist/utils/askUserPrompt.d.ts +0 -21
  686. package/dist/utils/askUserPrompt.d.ts.map +0 -1
  687. package/dist/utils/askUserPrompt.js +0 -87
  688. package/dist/utils/askUserPrompt.js.map +0 -1
  689. package/dist/utils/asyncUtils.d.ts +0 -95
  690. package/dist/utils/asyncUtils.d.ts.map +0 -1
  691. package/dist/utils/asyncUtils.js +0 -286
  692. package/dist/utils/asyncUtils.js.map +0 -1
  693. package/dist/utils/debugLogger.d.ts +0 -6
  694. package/dist/utils/debugLogger.d.ts.map +0 -1
  695. package/dist/utils/debugLogger.js +0 -39
  696. package/dist/utils/debugLogger.js.map +0 -1
  697. package/dist/utils/errorUtils.d.ts +0 -12
  698. package/dist/utils/errorUtils.d.ts.map +0 -1
  699. package/dist/utils/errorUtils.js +0 -83
  700. package/dist/utils/errorUtils.js.map +0 -1
  701. package/dist/utils/frontmatter.d.ts +0 -10
  702. package/dist/utils/frontmatter.d.ts.map +0 -1
  703. package/dist/utils/frontmatter.js +0 -78
  704. package/dist/utils/frontmatter.js.map +0 -1
  705. package/dist/utils/packageInfo.d.ts +0 -14
  706. package/dist/utils/packageInfo.d.ts.map +0 -1
  707. package/dist/utils/packageInfo.js +0 -45
  708. package/dist/utils/packageInfo.js.map +0 -1
  709. package/dist/utils/planFormatter.d.ts +0 -34
  710. package/dist/utils/planFormatter.d.ts.map +0 -1
  711. package/dist/utils/planFormatter.js +0 -141
  712. package/dist/utils/planFormatter.js.map +0 -1
  713. package/dist/utils/securityUtils.d.ts +0 -145
  714. package/dist/utils/securityUtils.d.ts.map +0 -1
  715. package/dist/utils/securityUtils.js +0 -507
  716. package/dist/utils/securityUtils.js.map +0 -1
  717. package/dist/utils/statusReporter.d.ts +0 -6
  718. package/dist/utils/statusReporter.d.ts.map +0 -1
  719. package/dist/utils/statusReporter.js +0 -26
  720. package/dist/utils/statusReporter.js.map +0 -1
  721. package/dist/workspace.d.ts +0 -8
  722. package/dist/workspace.d.ts.map +0 -1
  723. package/dist/workspace.js +0 -135
  724. package/dist/workspace.js.map +0 -1
  725. package/dist/workspace.validator.d.ts +0 -49
  726. package/dist/workspace.validator.d.ts.map +0 -1
  727. package/dist/workspace.validator.js +0 -215
  728. package/dist/workspace.validator.js.map +0 -1
@@ -1,2121 +0,0 @@
1
- /**
2
- * Interactive Shell - Full interactive CLI experience with rich UI.
3
- *
4
- * Usage:
5
- * agi # Start interactive shell
6
- * agi "initial prompt" # Start with initial prompt
7
- *
8
- * Features:
9
- * - Rich terminal UI with status bar
10
- * - Command history
11
- * - Streaming responses
12
- * - Tool execution display
13
- * - Ctrl+C to interrupt
14
- */
15
- import { stdin, stdout, exit } from 'node:process';
16
- import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'node:fs';
17
- import { resolve, dirname, join } from 'node:path';
18
- import { homedir } from 'node:os';
19
- import { fileURLToPath } from 'node:url';
20
- import { exec as childExec } from 'node:child_process';
21
- import { promisify } from 'node:util';
22
- import chalk from 'chalk';
23
- import gradientString from 'gradient-string';
24
- import { getHITL, hitlEvents } from '../core/hitl.js';
25
- import { reportUsageToFirebase, fetchUserBalanceMicrodollars } from '../core/usageTracker.js';
26
- import { getAuthStatus } from '../core/auth.js';
27
- // Connector imports removed — CLI is local-only, no GitHub gate.
28
- // Stub functions (antiTermination removed)
29
- const initializeProtection = (_config) => { };
30
- const enterCriticalSection = (_name) => { };
31
- const exitCriticalSection = (_name) => { };
32
- // Import real shutdown handler for reliable Ctrl+C handling
33
- import { authorizedShutdown, installSignalHandlers, onShutdown } from '../core/shutdown.js';
34
- import { resolveProfileConfig } from '../config.js';
35
- import { hasAgentProfile } from '../core/agentProfiles.js';
36
- import { createAgentController } from '../runtime/agentController.js';
37
- import { resolveWorkspaceCaptureOptions, buildWorkspaceContext } from '../workspace.js';
38
- import { loadAllSecrets, listSecretDefinitions, setSecretValue, getSecretValue } from '../core/secretStore.js';
39
- import { getConfiguredProviders, getProvidersStatus, quickCheckProviders, getCachedDiscoveredModels, sortModelsByPriority } from '../core/modelDiscovery.js';
40
- import { saveModelPreference } from '../core/preferences.js';
41
- import { setDebugMode, debugSnippet } from '../utils/debugLogger.js';
42
- const exec = promisify(childExec);
43
- import { ensureNextSteps } from '../core/finalResponseFormatter.js';
44
- import { getTaskCompletionDetector, detectFailingTestOrBuild } from '../core/taskCompletionDetector.js';
45
- import { checkForUpdates, performBackgroundUpdate } from '../core/updateChecker.js';
46
- import { startNewRun } from '../tools/fileChangeTracker.js';
47
- import { onSudoPasswordNeeded, offSudoPasswordNeeded, provideSudoPassword } from '../core/sudoPasswordManager.js';
48
- import { reportStatus, setStatusSink } from '../utils/statusReporter.js';
49
- import { isSafetyRefusal } from '../core/refusalDetection.js';
50
- import { getSharedMcpManager } from '../plugins/tools/mcp/mcpClient.js';
51
- // Timeout constants for regular prompt processing (reasoning models like DeepSeek)
52
- const PROMPT_REASONING_TIMEOUT_MS = 60 * 1000; // 60 seconds max for reasoning-only without action
53
- // Per-step timeout: how long we'll wait for the *next* event before
54
- // declaring the stream stuck and bailing out. Set generously (10 min) so
55
- // long-running tool calls (a build, a slow `npm install`, etc.) don't
56
- // trip it, but short enough that a dead provider / network drop doesn't
57
- // leave the user staring at a forever-spinner with Ctrl+C as their only
58
- // escape. iterateWithTimeout resets this per-event, so it only fires on
59
- // genuine inactivity. Override with EROSOLAR_STEP_TIMEOUT_MS for tests.
60
- const PROMPT_STEP_TIMEOUT_MS = (() => {
61
- const env = process.env['EROSOLAR_STEP_TIMEOUT_MS'];
62
- const parsed = env ? Number(env) : NaN;
63
- if (Number.isFinite(parsed) && parsed > 0)
64
- return parsed;
65
- return 10 * 60 * 1000;
66
- })();
67
- const HITL_TOOL_PREFIX = 'HITL_';
68
- const isHitlToolName = (toolName) => toolName.startsWith(HITL_TOOL_PREFIX);
69
- /**
70
- * Iterate over an async iterator with a timeout per iteration.
71
- * If no event is received within the timeout, yields a special timeout marker.
72
- * Emits timeout markers without aborting the underlying iterator.
73
- * Pass Infinity to disable timeouts entirely.
74
- */
75
- async function* iterateWithTimeout(iterator, timeoutMs, onTimeout) {
76
- const asyncIterator = iterator[Symbol.asyncIterator]();
77
- let pending = null;
78
- let done = false;
79
- // If timeout is Infinity or not a positive finite number, disable timeout entirely
80
- const timeoutDisabled = !Number.isFinite(timeoutMs) || timeoutMs <= 0;
81
- try {
82
- while (true) {
83
- if (!pending) {
84
- pending = asyncIterator.next();
85
- }
86
- let result;
87
- if (timeoutDisabled) {
88
- // No timeout - just wait for the next value
89
- result = await pending;
90
- }
91
- else {
92
- // Race between pending result and timeout
93
- const timeoutPromise = new Promise((resolve) => setTimeout(() => resolve({ __timeout: true }), timeoutMs));
94
- result = await Promise.race([pending, timeoutPromise]);
95
- }
96
- if ('__timeout' in result) {
97
- onTimeout?.();
98
- yield result;
99
- continue;
100
- }
101
- pending = null;
102
- if (result.done) {
103
- done = true;
104
- return;
105
- }
106
- yield result.value;
107
- }
108
- }
109
- finally {
110
- if (!done && typeof asyncIterator.return === 'function') {
111
- try {
112
- await asyncIterator.return(undefined);
113
- }
114
- catch {
115
- // Ignore return errors
116
- }
117
- }
118
- }
119
- }
120
- let cachedVersion = null;
121
- // Get version from package.json
122
- function getVersion() {
123
- if (cachedVersion)
124
- return cachedVersion;
125
- try {
126
- const __filename = fileURLToPath(import.meta.url);
127
- const pkgPath = resolve(dirname(__filename), '../../package.json');
128
- const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
129
- cachedVersion = pkg.version || '0.0.0';
130
- return cachedVersion;
131
- }
132
- catch {
133
- return '0.0.0';
134
- }
135
- }
136
- // Clean minimal banner
137
- const BANNER_GRADIENT = gradientString(['#0EA5E9', '#6366F1', '#EC4899']);
138
- const EROSOLAR_BANNER_RENDERED = BANNER_GRADIENT(' ◈ Erosolar Coder — a freedom coding CLI powered by DeepSeek');
139
- /**
140
- * Run the fully interactive shell with rich UI.
141
- */
142
- export async function runInteractiveShell(options) {
143
- // Install signal handlers FIRST for reliable Ctrl+C handling
144
- installSignalHandlers();
145
- // Initialize protection systems
146
- initializeProtection({
147
- interceptSignals: true,
148
- monitorResources: true,
149
- armorExceptions: true,
150
- enableWatchdog: true,
151
- verbose: process.env['EROSOLAR_DEBUG'] === '1',
152
- });
153
- // The CLI is interactive-only. There is no piped / one-shot / headless
154
- // mode — every session runs through the Ink renderer against a live
155
- // terminal. If stdin or stdout isn't a TTY, fail fast with a clear
156
- // message rather than emitting unrenderable escape sequences into a
157
- // pipe.
158
- if (!stdin.isTTY || !stdout.isTTY) {
159
- reportStatus('erosolar requires an interactive terminal. Run it directly in a TTY (no pipes, no shell redirection).');
160
- exit(1);
161
- }
162
- loadAllSecrets();
163
- const parsed = parseArgs(options.argv);
164
- const profile = resolveProfile();
165
- const workingDir = process.cwd();
166
- const workspaceOptions = resolveWorkspaceCaptureOptions(process.env);
167
- const workspaceContext = buildWorkspaceContext(workingDir, workspaceOptions);
168
- // Resolve profile config for model info
169
- const profileConfig = resolveProfileConfig(profile, workspaceContext);
170
- // Create agent controller
171
- const controller = await createAgentController({
172
- profile,
173
- workingDir,
174
- workspaceContext,
175
- env: process.env,
176
- });
177
- // Create the interactive shell instance
178
- const shell = new InteractiveShell(controller, profile, profileConfig, workingDir);
179
- // Handle initial prompt if provided
180
- if (parsed.initialPrompt) {
181
- shell.queuePrompt(parsed.initialPrompt);
182
- }
183
- await shell.run();
184
- }
185
- class InteractiveShell {
186
- controller;
187
- profile;
188
- profileConfig;
189
- workingDir;
190
- // The shell holds an `IPromptController`-shaped value so the same
191
- // call sites work whether we picked the legacy renderer or the Ink
192
- // adapter (selected by EROSOLAR_INK=1, see createPromptController).
193
- // Using `any` here keeps existing call signatures unchanged — the
194
- // interface declares the same surface but TS would otherwise insist
195
- // we touch every call site to declare nullability.
196
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
197
- promptController = null;
198
- isProcessing = false;
199
- shouldExit = false;
200
- pendingPrompts = [];
201
- debugEnabled = false;
202
- ctrlCCount = 0;
203
- lastCtrlCTime = 0;
204
- // Set when the user Ctrl+C interrupts a run; suppresses the auto-continue
205
- // re-launch in the finally block of processPrompt so the agent doesn't
206
- // immediately resume the work the user just cancelled. Cleared when the
207
- // user submits a fresh prompt.
208
- userInterruptedRun = false;
209
- cachedProviders = null;
210
- secretInputMode = {
211
- active: false,
212
- secretId: null,
213
- queue: [],
214
- };
215
- pendingModelSwitch = null;
216
- currentResponseBuffer = '';
217
- // Store original prompt for auto-continuation
218
- originalPromptForAutoContinue = null;
219
- // (Pinned prompt removed per request — field intentionally absent.)
220
- constructor(controller, profile, profileConfig, workingDir) {
221
- this.controller = controller;
222
- this.profile = profile;
223
- this.profileConfig = profileConfig;
224
- this.workingDir = workingDir;
225
- // Pre-fetch provider status in background
226
- void this.fetchProviders();
227
- }
228
- async fetchProviders() {
229
- try {
230
- this.cachedProviders = await quickCheckProviders();
231
- }
232
- catch {
233
- this.cachedProviders = [];
234
- }
235
- }
236
- validateRequiredApiKeys() {
237
- const missingKeys = [];
238
- // Check DeepSeek API key (required)
239
- if (!getSecretValue('DEEPSEEK_API_KEY')) {
240
- missingKeys.push('DEEPSEEK_API_KEY');
241
- }
242
- // Prompt for missing keys directly without showing warning
243
- if (missingKeys.length > 0 && this.promptController) {
244
- // Queue all missing keys for input
245
- this.secretInputMode.queue = missingKeys.slice(1); // Rest of the keys
246
- const first = missingKeys[0];
247
- if (first) {
248
- // Set secret mode immediately to mask input
249
- this.secretInputMode.active = true;
250
- this.secretInputMode.secretId = first;
251
- this.promptController.setSecretMode(true);
252
- // Show the inline panel with instructions
253
- const secrets = listSecretDefinitions();
254
- const secret = secrets.find(s => s.id === first);
255
- if (secret && this.promptController.supportsInlinePanel()) {
256
- const lines = [
257
- chalk.bold.hex('#6366F1')(`Set ${secret.label}`),
258
- chalk.dim(secret.description),
259
- '',
260
- chalk.dim('Enter value (or press Enter to skip)'),
261
- ];
262
- this.promptController.setInlinePanel(lines);
263
- this.promptController.setStatusMessage(`Enter ${secret.label}...`);
264
- }
265
- }
266
- }
267
- }
268
- queuePrompt(prompt) {
269
- this.pendingPrompts.push(prompt);
270
- }
271
- async run() {
272
- // Factory-driven construction: `EROSOLAR_INK=1` picks the Ink-backed
273
- // controller (src/ui/ink/InkPromptController.ts), otherwise the
274
- // legacy PromptController. Both implement the same surface so
275
- // every call site below is unchanged. Dynamic import keeps the
276
- // legacy path's cold-start free of the React/Ink parse cost when
277
- // the env flag is unset.
278
- const { createPromptController } = await import('../ui/ink/InkPromptController.js');
279
- this.promptController = await createPromptController(stdin, stdout, {
280
- onSubmit: (text) => this.handleSubmit(text),
281
- onQueue: (text) => this.queuePrompt(text),
282
- onInterrupt: () => this.handleInterrupt(),
283
- onExit: () => this.handleExit(),
284
- onCtrlC: (info) => this.handleCtrlC(info),
285
- onToggleAutoContinue: () => this.handleAutoContinueToggle(),
286
- onToggleHITL: () => this.handleHITLToggle(),
287
- });
288
- // Register cleanup callback for graceful shutdown
289
- onShutdown(() => {
290
- this.shouldExit = true;
291
- this.promptController?.stop();
292
- setStatusSink(null);
293
- });
294
- setStatusSink((message) => this.promptController?.setStatusMessage(message));
295
- // Hand the terminal off to the HITL prompt while it's open: suspend
296
- // prompt rendering and detach our keypress handler so arrow keys aren't
297
- // double-consumed. Restore both when the prompt closes so the next turn's
298
- // input works correctly.
299
- const onHitlOpen = () => {
300
- const r = this.promptController?.getRenderer();
301
- if (!r)
302
- return;
303
- try {
304
- r.suspendPromptRendering();
305
- }
306
- catch { /* ignore */ }
307
- try {
308
- r.suspendInputCapture();
309
- }
310
- catch { /* ignore */ }
311
- };
312
- const onHitlClose = () => {
313
- const r = this.promptController?.getRenderer();
314
- if (!r)
315
- return;
316
- try {
317
- r.resumeInputCapture();
318
- }
319
- catch { /* ignore */ }
320
- try {
321
- r.resumePromptRendering(true);
322
- }
323
- catch { /* ignore */ }
324
- };
325
- hitlEvents.on('prompt-open', onHitlOpen);
326
- hitlEvents.on('prompt-close', onHitlClose);
327
- onShutdown(() => {
328
- hitlEvents.removeListener('prompt-open', onHitlOpen);
329
- hitlEvents.removeListener('prompt-close', onHitlClose);
330
- });
331
- // Start the UI
332
- this.promptController.start();
333
- this.applyDebugState(this.debugEnabled);
334
- // Set up sudo password prompt handler
335
- this.setupSudoPasswordHandler();
336
- // Set initial status
337
- this.promptController.setChromeMeta({
338
- directory: this.workingDir,
339
- });
340
- // Show welcome message
341
- await this.showWelcome();
342
- // Pinned prompt loading removed — feature stripped per request.
343
- // Process any queued prompts
344
- if (this.pendingPrompts.length > 0) {
345
- const prompts = this.pendingPrompts.splice(0);
346
- for (const prompt of prompts) {
347
- await this.processPrompt(prompt);
348
- }
349
- }
350
- // Keep running until exit
351
- await this.waitForExit();
352
- }
353
- async showWelcome() {
354
- const renderer = this.promptController?.getRenderer();
355
- if (!renderer)
356
- return;
357
- const version = getVersion();
358
- // Append to existing terminal history — do not clear scrollback.
359
- // Check if DeepSeek API key is set
360
- const apiKey = process.env.DEEPSEEK_API_KEY?.trim() || '';
361
- const hasApiKey = apiKey.length > 0;
362
- // Mask API key: show first 4 and last 4 chars
363
- const maskApiKey = (key) => {
364
- if (key.length <= 12)
365
- return key.slice(0, 3) + '...' + key.slice(-3);
366
- return key.slice(0, 6) + '...' + key.slice(-4);
367
- };
368
- // Account state for the welcome banner
369
- const auth = getAuthStatus();
370
- const accountLine = auth.authenticated && auth.email
371
- ? chalk.dim(' Signed in as ') + chalk.green(auth.email) + chalk.dim(' · /logout')
372
- : chalk.dim(' ') + chalk.yellow('Not signed in') + chalk.dim(' · /login to sync usage & credits');
373
- // Pull account balance + connector status for signed-in users. Tight
374
- // timeouts so slow networks can't hang launch — skip lines on miss.
375
- // Update check runs in parallel for everyone (no auth required), with a
376
- // hard race-timeout so a slow registry never delays the banner.
377
- let balanceLine = null;
378
- const updateLines = [];
379
- const updatePromise = Promise.race([
380
- checkForUpdates(version).catch(() => null),
381
- new Promise((resolve) => setTimeout(() => resolve(null), 2000)),
382
- ]);
383
- if (auth.authenticated) {
384
- // CLI is local-only — no GitHub connector required. Skip the
385
- // connector lookup entirely (was a wasted Firestore round-trip
386
- // on every launch, plus a nag prompting users to set up an
387
- // unused connection).
388
- const micro = await fetchUserBalanceMicrodollars(800);
389
- if (typeof micro === 'number') {
390
- const dollars = Math.max(0, micro) / 1_000_000;
391
- const fmt = '$' + dollars.toFixed(4);
392
- const exhausted = micro <= 0;
393
- const lowish = !exhausted && micro < 100_000; // < $0.10
394
- const colored = exhausted ? chalk.red(fmt) : (lowish ? chalk.yellow(fmt) : chalk.green(fmt));
395
- const topup = chalk.cyan('https://ero.solar/portal');
396
- balanceLine = chalk.dim(' Balance: ') + colored + chalk.dim(' · Top up at ') + topup;
397
- }
398
- }
399
- // Resolve the update check BEFORE composing the welcome lines — the
400
- // previous order built welcomeLines with `...updateLines` (the array
401
- // was empty at that point) and only populated updateLines afterwards,
402
- // so the upgrade banner literally never rendered. Bug shipped before
403
- // the scoped-package rename made the check return wrong data anyway.
404
- const updateInfo = await updatePromise;
405
- if (updateInfo?.updateAvailable) {
406
- updateLines.push(chalk.cyan(' ⬆ ') +
407
- chalk.dim('Update available: ') +
408
- chalk.yellow(`v${updateInfo.current}`) +
409
- chalk.dim(' → ') +
410
- chalk.green(`v${updateInfo.latest}`) +
411
- chalk.dim(' · installing in background…'));
412
- this.runBackgroundUpdate(updateInfo);
413
- }
414
- // Clean, minimal welcome - just the essentials
415
- const welcomeLines = [
416
- '',
417
- EROSOLAR_BANNER_RENDERED + chalk.dim(` v${version}`),
418
- chalk.dim(' ') + chalk.cyan('https://ero.solar') + chalk.dim(' · ') + chalk.cyan('https://www.npmjs.com/package/@trenchwork/erosolar'),
419
- accountLine,
420
- ...(balanceLine ? [balanceLine] : []),
421
- ...updateLines,
422
- '',
423
- ];
424
- if (!hasApiKey) {
425
- // Show API key setup instructions
426
- welcomeLines.push(chalk.yellow(' ⚠ No API key configured'), '', chalk.dim(' Get your key: ') + chalk.cyan('https://platform.deepseek.com/'), chalk.dim(' Set your key: ') + chalk.hex('#FBBF24')('/key YOUR_API_KEY'), '');
427
- }
428
- else {
429
- const maskedKey = maskApiKey(apiKey);
430
- welcomeLines.push(chalk.dim(` ${this.profileConfig.model} · ${this.profileConfig.provider}`), chalk.dim(' Key: ') + chalk.green(maskedKey) + chalk.dim(' · /help for commands'), '');
431
- }
432
- const welcomeContent = welcomeLines.join('\n');
433
- // Use renderer event system instead of direct stdout writes
434
- renderer.addEvent('banner', welcomeContent);
435
- // Update renderer meta with model info
436
- this.promptController?.setModelContext({
437
- model: this.profileConfig.model,
438
- provider: this.profileConfig.provider,
439
- });
440
- }
441
- /**
442
- * Kick off `npm install -g <pkg>@latest` in a background process. When it
443
- * completes, surface a renderer event so the user sees the result without
444
- * any blocking. The running CLI keeps the old code — the new version is
445
- * picked up on next launch.
446
- */
447
- runBackgroundUpdate(info) {
448
- const renderer = this.promptController?.getRenderer();
449
- void performBackgroundUpdate(info, (msg) => {
450
- try {
451
- renderer?.addEvent('system', msg);
452
- }
453
- catch { /* ignore */ }
454
- }).then((res) => {
455
- if (!res.started)
456
- return;
457
- try {
458
- renderer?.addEvent('system', chalk.green(`✓ Update installer launched for v${info.latest}. `) +
459
- chalk.dim('Exit and reopen the CLI to use the new version.'));
460
- }
461
- catch { /* ignore */ }
462
- }).catch(() => { });
463
- }
464
- /**
465
- * Set up handler for sudo password prompts from bash tool execution.
466
- * When a sudo command needs a password, this prompts the user securely.
467
- */
468
- sudoPasswordHandler = null;
469
- setupSudoPasswordHandler() {
470
- this.sudoPasswordHandler = async () => {
471
- const renderer = this.promptController?.getRenderer();
472
- if (!renderer) {
473
- provideSudoPassword(null);
474
- return;
475
- }
476
- try {
477
- // Show password prompt
478
- renderer.addEvent('system', chalk.yellow('🔐 Sudo password required'));
479
- renderer.setSecretMode(true);
480
- renderer.clearBuffer();
481
- // Capture password input
482
- const password = await renderer.captureInput({ allowEmpty: false, trim: true, resetBuffer: true });
483
- // Hide password mode
484
- renderer.setSecretMode(false);
485
- if (password) {
486
- provideSudoPassword(password);
487
- renderer.addEvent('system', chalk.green('✓ Password provided'));
488
- }
489
- else {
490
- provideSudoPassword(null);
491
- renderer.addEvent('system', chalk.yellow('Sudo cancelled'));
492
- }
493
- }
494
- catch (error) {
495
- renderer.setSecretMode(false);
496
- provideSudoPassword(null);
497
- reportStatus('Password prompt cancelled');
498
- }
499
- };
500
- onSudoPasswordNeeded(this.sudoPasswordHandler);
501
- }
502
- cleanupSudoPasswordHandler() {
503
- if (this.sudoPasswordHandler) {
504
- offSudoPasswordNeeded(this.sudoPasswordHandler);
505
- this.sudoPasswordHandler = null;
506
- }
507
- }
508
- applyDebugState(enabled, statusMessage) {
509
- this.debugEnabled = enabled;
510
- setDebugMode(enabled);
511
- this.promptController?.setDebugMode(enabled);
512
- // Show transient status message instead of chat banner
513
- if (statusMessage) {
514
- this.promptController?.setStatusMessage(statusMessage);
515
- setTimeout(() => this.promptController?.setStatusMessage(null), 2000);
516
- }
517
- }
518
- describeEventForDebug(event) {
519
- switch (event.type) {
520
- case 'message.start':
521
- return 'message.start';
522
- case 'message.delta': {
523
- const snippet = debugSnippet(event.content);
524
- return snippet ? `message.delta → ${snippet}` : 'message.delta (empty)';
525
- }
526
- case 'message.complete': {
527
- const snippet = debugSnippet(event.content);
528
- return snippet
529
- ? `message.complete → ${snippet} (${event.elapsedMs}ms)`
530
- : `message.complete (${event.elapsedMs}ms)`;
531
- }
532
- case 'tool.start':
533
- return `tool.start ${event.toolName}`;
534
- case 'tool.complete': {
535
- const snippet = debugSnippet(event.result);
536
- return snippet
537
- ? `tool.complete ${event.toolName} → ${snippet}`
538
- : `tool.complete ${event.toolName}`;
539
- }
540
- case 'tool.error':
541
- return `tool.error ${event.toolName} → ${event.error}`;
542
- case 'edit.explanation': {
543
- const snippet = debugSnippet(event.content);
544
- return snippet ? `edit.explanation → ${snippet}` : 'edit.explanation';
545
- }
546
- case 'error':
547
- return `error → ${event.error}`;
548
- case 'usage': {
549
- const parts = [];
550
- if (event.inputTokens != null)
551
- parts.push(`in:${event.inputTokens}`);
552
- if (event.outputTokens != null)
553
- parts.push(`out:${event.outputTokens}`);
554
- if (event.totalTokens != null)
555
- parts.push(`total:${event.totalTokens}`);
556
- return `usage ${parts.length ? parts.join(', ') : '(no tokens)'}`;
557
- }
558
- default:
559
- return event.type;
560
- }
561
- }
562
- handleDebugCommand(arg) {
563
- const normalized = arg?.toLowerCase();
564
- // /debug alone - toggle
565
- if (!normalized) {
566
- const targetState = !this.debugEnabled;
567
- this.applyDebugState(targetState, `Debug ${targetState ? 'on' : 'off'}`);
568
- return true;
569
- }
570
- // /debug status - show current state
571
- if (normalized === 'status') {
572
- this.promptController?.setStatusMessage(`Debug is ${this.debugEnabled ? 'on' : 'off'}`);
573
- setTimeout(() => this.promptController?.setStatusMessage(null), 2000);
574
- return true;
575
- }
576
- // /debug on|enable
577
- if (normalized === 'on' || normalized === 'enable') {
578
- if (this.debugEnabled) {
579
- this.promptController?.setStatusMessage('Debug already on');
580
- setTimeout(() => this.promptController?.setStatusMessage(null), 2000);
581
- return true;
582
- }
583
- this.applyDebugState(true, 'Debug on');
584
- return true;
585
- }
586
- // /debug off|disable
587
- if (normalized === 'off' || normalized === 'disable') {
588
- if (!this.debugEnabled) {
589
- this.promptController?.setStatusMessage('Debug already off');
590
- setTimeout(() => this.promptController?.setStatusMessage(null), 2000);
591
- return true;
592
- }
593
- this.applyDebugState(false, 'Debug off');
594
- return true;
595
- }
596
- // Invalid argument
597
- this.promptController?.setStatusMessage(`Invalid: /debug ${arg}. Use on|off|status`);
598
- setTimeout(() => this.promptController?.setStatusMessage(null), 2500);
599
- return true;
600
- }
601
- /**
602
- * Synthesize a user-facing response from reasoning content when the model
603
- * provides reasoning but no actual response (common with deepseek-v4-pro).
604
- * Extracts key conclusions and formats them as a concise response.
605
- */
606
- synthesizeFromReasoning(reasoning) {
607
- if (!reasoning || reasoning.trim().length < 50) {
608
- return null;
609
- }
610
- // Filter out internal meta-reasoning patterns that shouldn't be shown to user
611
- const metaPatterns = [
612
- /according to the rules?:?/gi,
613
- /let me (?:use|search|look|check|find|think|analyze)/gi,
614
- /I (?:should|need to|will|can|must) (?:use|search|look|check|find)/gi,
615
- /⚡\s*Executing\.*/gi,
616
- /use web\s?search/gi,
617
- /for (?:non-)?coding (?:questions|tasks)/gi,
618
- /answer (?:directly )?from knowledge/gi,
619
- /this is a (?:general knowledge|coding|security)/gi,
620
- /the user (?:is asking|wants|might be)/gi,
621
- /however,? (?:the user|I|we)/gi,
622
- /(?:first|next),? (?:I should|let me|I need)/gi,
623
- ];
624
- let filtered = reasoning;
625
- for (const pattern of metaPatterns) {
626
- filtered = filtered.replace(pattern, '');
627
- }
628
- // Split into sentences
629
- const sentences = filtered
630
- .split(/[.!?\n]+/)
631
- .map(s => s.trim())
632
- .filter(s => s.length > 20 && !/^[•\-–—*]/.test(s)); // Skip bullets and short fragments
633
- if (sentences.length === 0) {
634
- return null;
635
- }
636
- // Look for actual content (not process descriptions)
637
- const contentPatterns = [
638
- /(?:refers? to|involves?|relates? to|is about|concerns?)/i,
639
- /(?:scandal|deal|agreement|proposal|plan|policy)/i,
640
- /(?:Trump|Biden|Ukraine|Russia|president|congress)/i,
641
- /(?:the (?:main|key|primary)|importantly)/i,
642
- ];
643
- const contentSentences = [];
644
- for (const sentence of sentences) {
645
- // Skip sentences that are clearly meta-reasoning
646
- if (/^(?:so|therefore|thus|hence|accordingly)/i.test(sentence))
647
- continue;
648
- if (/(?:I should|let me|I will|I need|I can)/i.test(sentence))
649
- continue;
650
- for (const pattern of contentPatterns) {
651
- if (pattern.test(sentence)) {
652
- contentSentences.push(sentence);
653
- break;
654
- }
655
- }
656
- }
657
- // Use content sentences if found, otherwise take last few sentences (often conclusions)
658
- const useSentences = contentSentences.length > 0
659
- ? contentSentences.slice(0, 3)
660
- : sentences.slice(-3);
661
- if (useSentences.length === 0) {
662
- return null;
663
- }
664
- const response = useSentences.join('. ').replace(/\.{2,}/g, '.').trim();
665
- // Don't prefix with "Based on my analysis" - just return clean content
666
- return response.endsWith('.') ? response : response + '.';
667
- }
668
- async runLocalCommand(command) {
669
- const renderer = this.promptController?.getRenderer();
670
- if (!command) {
671
- this.promptController?.setStatusMessage('Usage: /bash <command>');
672
- setTimeout(() => this.promptController?.setStatusMessage(null), 2500);
673
- return;
674
- }
675
- this.promptController?.setStatusMessage(`bash: ${command}`);
676
- try {
677
- const { stdout: out, stderr } = await exec(command, {
678
- cwd: this.workingDir,
679
- maxBuffer: 4 * 1024 * 1024,
680
- });
681
- const output = [out, stderr].filter(Boolean).join('').trim() || '(no output)';
682
- renderer?.addEvent('tool', `$ ${command}\n${output}`);
683
- }
684
- catch (error) {
685
- const err = error;
686
- const output = [err.stdout, err.stderr, err.message].filter(Boolean).join('\n').trim();
687
- renderer?.addEvent('error', `$ ${command}\n${output || 'command failed'}`);
688
- }
689
- finally {
690
- this.promptController?.setStatusMessage(null);
691
- }
692
- }
693
- handleSlashCommand(command) {
694
- const trimmed = command.trim();
695
- const lower = trimmed.toLowerCase();
696
- // Handle /model with arguments - silent model switch
697
- if (lower.startsWith('/model ') || lower.startsWith('/m ')) {
698
- const arg = trimmed.slice(trimmed.indexOf(' ') + 1).trim();
699
- if (arg) {
700
- void this.switchModel(arg);
701
- return true;
702
- }
703
- }
704
- // Handle /model or /m alone - show interactive model picker menu
705
- if (lower === '/model' || lower === '/m') {
706
- this.showModelMenu();
707
- return true;
708
- }
709
- // Handle /secrets with subcommands
710
- if (lower.startsWith('/secrets') || lower.startsWith('/s ') || lower === '/s') {
711
- const parts = trimmed.split(/\s+/);
712
- const subCmd = parts[1]?.toLowerCase();
713
- if (subCmd === 'set') {
714
- const secretArg = parts[2];
715
- void this.startSecretInput(secretArg);
716
- return true;
717
- }
718
- // /secrets or /s alone - show status
719
- this.showSecrets();
720
- return true;
721
- }
722
- // Handle /key - shortcut to set DEEPSEEK_API_KEY
723
- if (lower === '/key' || lower.startsWith('/key ')) {
724
- const parts = trimmed.split(/\s+/);
725
- const keyValue = parts[1];
726
- const renderer = this.promptController?.getRenderer();
727
- if (keyValue) {
728
- // Direct file write - most reliable method
729
- try {
730
- const secretDir = join(homedir(), '.erosolar');
731
- const secretFile = join(secretDir, 'secrets.json');
732
- mkdirSync(secretDir, { recursive: true });
733
- const existing = existsSync(secretFile)
734
- ? JSON.parse(readFileSync(secretFile, 'utf-8'))
735
- : {};
736
- existing['DEEPSEEK_API_KEY'] = keyValue;
737
- writeFileSync(secretFile, JSON.stringify(existing, null, 2) + '\n');
738
- // Also set in process.env for immediate use
739
- process.env['DEEPSEEK_API_KEY'] = keyValue;
740
- // Show confirmation via renderer
741
- renderer?.addEvent('system', chalk.green('✓ DEEPSEEK_API_KEY saved'));
742
- }
743
- catch (error) {
744
- const msg = error instanceof Error ? error.message : String(error);
745
- renderer?.addEvent('system', chalk.red(`✗ Failed: ${msg}`));
746
- }
747
- }
748
- else {
749
- // Show usage hint
750
- renderer?.addEvent('system', chalk.yellow('Usage: /key YOUR_API_KEY'));
751
- }
752
- return true;
753
- }
754
- if (lower === '/help' || lower === '/h' || lower === '/?') {
755
- this.showHelp();
756
- return true;
757
- }
758
- if (lower === '/clear' || lower === '/c') {
759
- stdout.write('\x1b[2J\x1b[H');
760
- void this.showWelcome();
761
- return true;
762
- }
763
- if (lower.startsWith('/bash') || lower.startsWith('/sh ')) {
764
- const cmd = trimmed.replace(/^\/(bash|sh)\s*/i, '').trim();
765
- void this.runLocalCommand(cmd);
766
- return true;
767
- }
768
- // Pin/unpin slash commands removed. The pinned prompt UI was
769
- // pulled per request; commands now silently no-op so existing
770
- // bindings don't error.
771
- if (lower.startsWith('/pin ') || lower === '/unpin' || lower === '/clearpin') {
772
- return true;
773
- }
774
- // Toggle auto mode: off → on → dual → off
775
- if (lower === '/auto' || lower === '/continue' || lower === '/loop' || lower === '/dual') {
776
- this.promptController?.toggleAutoContinue();
777
- const mode = this.promptController?.getAutoMode() ?? 'off';
778
- this.promptController?.setStatusMessage(`Auto: ${mode}`);
779
- setTimeout(() => this.promptController?.setStatusMessage(null), 1500);
780
- return true;
781
- }
782
- if (lower === '/exit' || lower === '/quit' || lower === '/q') {
783
- this.handleExit();
784
- return true;
785
- }
786
- if (lower.startsWith('/debug')) {
787
- const parts = trimmed.split(/\s+/);
788
- this.handleDebugCommand(parts[1]);
789
- return true;
790
- }
791
- // Keyboard shortcuts help
792
- if (lower === '/keys' || lower === '/shortcuts' || lower === '/kb') {
793
- this.showKeyboardShortcuts();
794
- return true;
795
- }
796
- // /email and /mail are intentionally unimplemented in the CLI.
797
- // All transactional email is handled by Cloud Functions (site/functions/index.js).
798
- if (lower.startsWith('/email') || lower.startsWith('/mail')) {
799
- const renderer = this.promptController?.getRenderer();
800
- const msg = 'Email sending is handled by the Cloud Functions backend, not the CLI. See site/functions/index.js (sendProtonEmail, requestHuman, onUserCreate, maybeNotifyBalance).';
801
- if (renderer) {
802
- renderer.addEvent('response', msg);
803
- }
804
- else {
805
- console.log(msg);
806
- }
807
- return true;
808
- }
809
- // Session stats
810
- if (lower === '/stats' || lower === '/status') {
811
- this.showSessionStats();
812
- return true;
813
- }
814
- return false;
815
- }
816
- /**
817
- * Switch model silently without writing to chat.
818
- * Accepts formats: "provider", "provider model", "provider/model", or "model"
819
- * Updates status bar to show new model.
820
- */
821
- async switchModel(arg) {
822
- // Ensure we have provider info
823
- if (!this.cachedProviders) {
824
- await this.fetchProviders();
825
- }
826
- const providers = this.cachedProviders || [];
827
- const configuredProviders = getConfiguredProviders();
828
- let targetProvider = null;
829
- let targetModel = null;
830
- // Parse argument: could be "provider model", "provider/model", "provider", or just "model"
831
- // Check for space-separated format first: "openai o1-pro"
832
- const parts = arg.split(/[\s/]+/);
833
- if (parts.length >= 2) {
834
- // Try first part as provider
835
- const providerMatch = this.matchProvider(parts[0] || '');
836
- if (providerMatch) {
837
- targetProvider = providerMatch;
838
- targetModel = parts.slice(1).join('/'); // Rest is model (handle models with slashes)
839
- }
840
- else {
841
- // First part isn't a provider, treat whole arg as model name
842
- const inferredProvider = this.inferProviderFromModel(arg.replace(/\s+/g, '-'));
843
- if (inferredProvider) {
844
- targetProvider = inferredProvider;
845
- targetModel = arg.replace(/\s+/g, '-');
846
- }
847
- }
848
- }
849
- else {
850
- // Single token - could be provider or model
851
- const matched = this.matchProvider(arg);
852
- if (matched) {
853
- targetProvider = matched;
854
- // Use provider's best model
855
- const providerStatus = providers.find(p => p.provider === targetProvider);
856
- targetModel = providerStatus?.latestModel || null;
857
- }
858
- else {
859
- // Assume it's a model name - try to infer provider from model prefix
860
- const inferredProvider = this.inferProviderFromModel(arg);
861
- if (inferredProvider) {
862
- targetProvider = inferredProvider;
863
- targetModel = arg;
864
- }
865
- }
866
- }
867
- // Validate we have a valid provider
868
- if (!targetProvider) {
869
- // Silent error - just flash status briefly
870
- this.promptController?.setStatusMessage(`Unknown: ${arg}`);
871
- setTimeout(() => this.promptController?.setStatusMessage(null), 2000);
872
- return;
873
- }
874
- // Check provider is configured
875
- const providerInfo = configuredProviders.find(p => p.id === targetProvider);
876
- if (!providerInfo) {
877
- // Provider not configured - offer to set up API key
878
- const secretMap = {
879
- 'deepseek': 'DEEPSEEK_API_KEY',
880
- };
881
- const secretId = secretMap[targetProvider];
882
- if (secretId) {
883
- this.promptController?.setStatusMessage(`${targetProvider} needs API key - setting up...`);
884
- // Store the pending model switch to complete after secret is set
885
- this.pendingModelSwitch = { provider: targetProvider, model: targetModel };
886
- setTimeout(() => this.promptForSecret(secretId), 500);
887
- return;
888
- }
889
- // Provider not supported
890
- this.promptController?.setStatusMessage(`${targetProvider} not available - only DeepSeek is supported`);
891
- setTimeout(() => this.promptController?.setStatusMessage(null), 2000);
892
- return;
893
- }
894
- // Get model if not specified
895
- if (!targetModel) {
896
- const providerStatus = providers.find(p => p.provider === targetProvider);
897
- targetModel = providerStatus?.latestModel || providerInfo.latestModel;
898
- }
899
- // Save preference and update config
900
- saveModelPreference(this.profile, {
901
- provider: targetProvider,
902
- model: targetModel,
903
- });
904
- // Update local config
905
- this.profileConfig = {
906
- ...this.profileConfig,
907
- provider: targetProvider,
908
- model: targetModel,
909
- };
910
- // Update controller's model
911
- await this.controller.switchModel({
912
- provider: targetProvider,
913
- model: targetModel,
914
- });
915
- // Update status bar - this displays the model below the chat box
916
- this.promptController?.setModelContext({
917
- model: targetModel,
918
- provider: targetProvider,
919
- });
920
- // Silent success - no chat output, just status bar update
921
- }
922
- /**
923
- * Match user input to a provider ID (fuzzy matching)
924
- */
925
- matchProvider(input) {
926
- const lower = input.toLowerCase();
927
- const providers = getConfiguredProviders();
928
- // Exact match
929
- const exact = providers.find(p => p.id === lower || p.name.toLowerCase() === lower);
930
- if (exact)
931
- return exact.id;
932
- // Prefix match
933
- const prefix = providers.find(p => p.id.startsWith(lower) || p.name.toLowerCase().startsWith(lower));
934
- if (prefix)
935
- return prefix.id;
936
- // Alias matching
937
- const aliases = {
938
- 'claude': 'anthropic',
939
- 'ant': 'anthropic',
940
- 'gpt': 'openai',
941
- 'oai': 'openai',
942
- 'gemini': 'google',
943
- 'gem': 'google',
944
- 'ds': 'deepseek',
945
- 'deep': 'deepseek',
946
- 'grok': 'xai',
947
- 'x': 'xai',
948
- 'local': 'ollama',
949
- 'llama': 'ollama',
950
- };
951
- if (aliases[lower]) {
952
- const aliased = providers.find(p => p.id === aliases[lower]);
953
- if (aliased)
954
- return aliased.id;
955
- }
956
- return null;
957
- }
958
- /**
959
- * Infer provider from model name
960
- */
961
- inferProviderFromModel(model) {
962
- const lower = model.toLowerCase();
963
- if (lower.startsWith('claude') || lower.startsWith('opus') || lower.startsWith('sonnet') || lower.startsWith('haiku')) {
964
- return 'anthropic';
965
- }
966
- if (lower.startsWith('gpt') || lower.startsWith('o1') || lower.startsWith('o3') || lower.startsWith('codex')) {
967
- return 'openai';
968
- }
969
- if (lower.startsWith('gemini')) {
970
- return 'google';
971
- }
972
- if (lower.startsWith('deepseek')) {
973
- return 'deepseek';
974
- }
975
- if (lower.startsWith('grok')) {
976
- return 'xai';
977
- }
978
- if (lower.startsWith('llama') || lower.startsWith('mistral') || lower.startsWith('qwen')) {
979
- return 'ollama';
980
- }
981
- return null;
982
- }
983
- /**
984
- * Show interactive model picker menu (Claude Code style).
985
- * Auto-discovers latest models from each provider's API.
986
- * Uses arrow key navigation with inline panel display.
987
- */
988
- showModelMenu() {
989
- if (!this.promptController?.supportsInlinePanel()) {
990
- this.promptController?.setStatusMessage('Use /model <provider> <model> to switch');
991
- setTimeout(() => this.promptController?.setStatusMessage(null), 3000);
992
- return;
993
- }
994
- // Show loading indicator
995
- this.promptController?.setStatusMessage('Discovering models...');
996
- // Fetch latest models from APIs
997
- void this.fetchAndShowModelMenu();
998
- }
999
- /**
1000
- * Fetch models from provider APIs and show the interactive menu.
1001
- */
1002
- async fetchAndShowModelMenu() {
1003
- try {
1004
- // Get provider status and cached models
1005
- const allProviders = getProvidersStatus();
1006
- const cachedModels = getCachedDiscoveredModels();
1007
- const currentModel = this.profileConfig.model;
1008
- const currentProvider = this.profileConfig.provider;
1009
- // Try to get fresh models from configured providers (with short timeout)
1010
- let freshStatus = [];
1011
- try {
1012
- freshStatus = await Promise.race([
1013
- quickCheckProviders(),
1014
- new Promise((resolve) => setTimeout(() => resolve([]), 3000))
1015
- ]);
1016
- }
1017
- catch {
1018
- // Use cached data on error
1019
- }
1020
- // Build menu items - group by provider, show models
1021
- const menuItems = [];
1022
- for (const provider of allProviders) {
1023
- // Get models for this provider
1024
- const providerCachedModels = cachedModels.filter(m => m.provider === provider.id);
1025
- const freshProvider = freshStatus.find(s => s.provider === provider.id);
1026
- // Collect model IDs
1027
- let modelIds = [];
1028
- // Add fresh latest model if available
1029
- if (freshProvider?.available && freshProvider.latestModel) {
1030
- modelIds.push(freshProvider.latestModel);
1031
- }
1032
- // Add cached models
1033
- modelIds.push(...providerCachedModels.map(m => m.id));
1034
- // Add provider's default model
1035
- if (provider.latestModel && !modelIds.includes(provider.latestModel)) {
1036
- modelIds.push(provider.latestModel);
1037
- }
1038
- // Remove duplicates and sort by priority (best first)
1039
- modelIds = [...new Set(modelIds)];
1040
- modelIds = sortModelsByPriority(provider.id, modelIds);
1041
- // Limit to top 3 models per provider
1042
- const topModels = modelIds.slice(0, 3);
1043
- if (!provider.configured) {
1044
- // Show unconfigured provider as single disabled item
1045
- menuItems.push({
1046
- id: `${provider.id}:setup`,
1047
- label: `${provider.name}`,
1048
- description: `(${provider.envVar} not set - select to configure)`,
1049
- category: provider.id,
1050
- isActive: false,
1051
- disabled: false, // Allow selection to configure
1052
- });
1053
- }
1054
- else if (topModels.length === 0) {
1055
- // No models found - show provider with default
1056
- menuItems.push({
1057
- id: `${provider.id}:${provider.latestModel}`,
1058
- label: `${provider.name} › ${provider.latestModel}`,
1059
- description: 'default',
1060
- category: provider.id,
1061
- isActive: provider.id === currentProvider && provider.latestModel === currentModel,
1062
- disabled: false,
1063
- });
1064
- }
1065
- else {
1066
- // Show each model as selectable item
1067
- for (const modelId of topModels) {
1068
- const isCurrentModel = provider.id === currentProvider && modelId === currentModel;
1069
- const modelLabel = this.formatModelLabel(modelId);
1070
- menuItems.push({
1071
- id: `${provider.id}:${modelId}`,
1072
- label: `${provider.name} › ${modelLabel}`,
1073
- description: isCurrentModel ? '(current)' : '',
1074
- category: provider.id,
1075
- isActive: isCurrentModel,
1076
- disabled: false,
1077
- });
1078
- }
1079
- }
1080
- }
1081
- // Clear loading message
1082
- this.promptController?.setStatusMessage(null);
1083
- // Show the interactive menu
1084
- this.promptController?.setMenu(menuItems, { title: '🤖 Select Model' }, (selected) => {
1085
- if (selected) {
1086
- // Parse provider:model format
1087
- const [providerId, ...modelParts] = selected.id.split(':');
1088
- const modelId = modelParts.join(':');
1089
- if (modelId === 'setup') {
1090
- // Configure provider API key
1091
- const secretMap = {
1092
- 'deepseek': 'DEEPSEEK_API_KEY',
1093
- };
1094
- const secretId = secretMap[providerId ?? ''];
1095
- if (secretId) {
1096
- this.promptForSecret(secretId);
1097
- }
1098
- }
1099
- else {
1100
- // Switch to selected model
1101
- void this.switchModel(`${providerId} ${modelId}`);
1102
- }
1103
- }
1104
- });
1105
- }
1106
- catch (error) {
1107
- this.promptController?.setStatusMessage('Failed to load models');
1108
- setTimeout(() => this.promptController?.setStatusMessage(null), 2000);
1109
- }
1110
- }
1111
- /**
1112
- * Format model ID for display (shorten long IDs).
1113
- */
1114
- formatModelLabel(modelId) {
1115
- // Shorten common prefixes
1116
- let label = modelId
1117
- .replace(/^claude-/, '')
1118
- .replace(/^gpt-/, 'GPT-')
1119
- .replace(/^gemini-/, 'Gemini ')
1120
- .replace(/^deepseek-/, 'DeepSeek ')
1121
- .replace(/^grok-/, 'Grok ')
1122
- .replace(/^llama/, 'Llama ')
1123
- .replace(/^qwen-/, 'Qwen ');
1124
- // Truncate if too long
1125
- if (label.length > 30) {
1126
- label = label.slice(0, 27) + '...';
1127
- }
1128
- return label;
1129
- }
1130
- showSecrets() {
1131
- const secrets = listSecretDefinitions();
1132
- if (!this.promptController?.supportsInlinePanel()) {
1133
- // Fallback for non-TTY - use status message
1134
- const setCount = secrets.filter(s => !!process.env[s.envVar]).length;
1135
- this.promptController?.setStatusMessage(`API Keys: ${setCount}/${secrets.length} configured`);
1136
- setTimeout(() => this.promptController?.setStatusMessage(null), 3000);
1137
- return;
1138
- }
1139
- // Build interactive menu items
1140
- const menuItems = secrets.map(secret => {
1141
- const isSet = !!process.env[secret.envVar];
1142
- const statusIcon = isSet ? '✓' : '✗';
1143
- const providers = secret.providers?.length ? ` (${secret.providers.join(', ')})` : '';
1144
- return {
1145
- id: secret.id,
1146
- label: `${statusIcon} ${secret.envVar}`,
1147
- description: isSet ? 'configured' + providers : 'not set' + providers,
1148
- isActive: isSet,
1149
- disabled: false,
1150
- };
1151
- });
1152
- // Show the interactive menu
1153
- this.promptController.setMenu(menuItems, { title: '🔑 API Keys - Select to Configure' }, (selected) => {
1154
- if (selected) {
1155
- // Start secret input for selected key
1156
- this.promptForSecret(selected.id);
1157
- }
1158
- });
1159
- }
1160
- /**
1161
- * Start interactive secret input flow.
1162
- * If secretArg is provided, set only that secret.
1163
- * Otherwise, prompt for all unset secrets.
1164
- */
1165
- async startSecretInput(secretArg) {
1166
- const secrets = listSecretDefinitions();
1167
- if (secretArg) {
1168
- // Set a specific secret
1169
- const upper = secretArg.toUpperCase();
1170
- const secret = secrets.find(s => s.id === upper || s.envVar === upper);
1171
- if (!secret) {
1172
- this.promptController?.setStatusMessage(`Unknown secret: ${secretArg}`);
1173
- setTimeout(() => this.promptController?.setStatusMessage(null), 2000);
1174
- return;
1175
- }
1176
- this.promptForSecret(secret.id);
1177
- return;
1178
- }
1179
- // Queue all unset secrets for input
1180
- const unsetSecrets = secrets.filter(s => !getSecretValue(s.id));
1181
- if (unsetSecrets.length === 0) {
1182
- this.promptController?.setStatusMessage('All secrets configured');
1183
- setTimeout(() => this.promptController?.setStatusMessage(null), 2000);
1184
- return;
1185
- }
1186
- // Queue all unset secrets and start with the first one
1187
- this.secretInputMode.queue = unsetSecrets.map(s => s.id);
1188
- const first = this.secretInputMode.queue.shift();
1189
- if (first) {
1190
- this.promptForSecret(first);
1191
- }
1192
- }
1193
- /**
1194
- * Show prompt for a specific secret and enable secret input mode.
1195
- */
1196
- promptForSecret(secretId) {
1197
- const secrets = listSecretDefinitions();
1198
- const secret = secrets.find(s => s.id === secretId);
1199
- if (!secret)
1200
- return;
1201
- // Show in inline panel (no chat output)
1202
- if (this.promptController?.supportsInlinePanel()) {
1203
- const lines = [
1204
- chalk.bold.hex('#6366F1')(`Set ${secret.label}`),
1205
- chalk.dim(secret.description),
1206
- '',
1207
- chalk.dim('Enter value (or press Enter to skip)'),
1208
- ];
1209
- this.promptController.setInlinePanel(lines);
1210
- }
1211
- // Enable secret input mode
1212
- this.secretInputMode.active = true;
1213
- this.secretInputMode.secretId = secretId;
1214
- this.promptController?.setSecretMode(true);
1215
- this.promptController?.setStatusMessage(`Enter ${secret.label}...`);
1216
- }
1217
- /**
1218
- * Handle secret value submission.
1219
- */
1220
- handleSecretValue(value) {
1221
- const secretId = this.secretInputMode.secretId;
1222
- if (!secretId)
1223
- return;
1224
- // Disable secret mode and clear inline panel
1225
- this.promptController?.setSecretMode(false);
1226
- this.promptController?.clearInlinePanel();
1227
- this.secretInputMode.active = false;
1228
- this.secretInputMode.secretId = null;
1229
- let savedSuccessfully = false;
1230
- if (value.trim()) {
1231
- try {
1232
- setSecretValue(secretId, value.trim());
1233
- this.promptController?.setStatusMessage(`${secretId} saved`);
1234
- savedSuccessfully = true;
1235
- }
1236
- catch (error) {
1237
- const msg = error instanceof Error ? error.message : 'Failed to save';
1238
- this.promptController?.setStatusMessage(msg);
1239
- }
1240
- }
1241
- else {
1242
- this.promptController?.setStatusMessage(`Skipped ${secretId}`);
1243
- }
1244
- // Clear status after a moment
1245
- setTimeout(() => this.promptController?.setStatusMessage(null), 1500);
1246
- // Process next secret in queue if any
1247
- if (this.secretInputMode.queue.length > 0) {
1248
- const next = this.secretInputMode.queue.shift();
1249
- if (next) {
1250
- setTimeout(() => this.promptForSecret(next), 500);
1251
- }
1252
- return;
1253
- }
1254
- // Complete pending model switch if secret was saved successfully
1255
- if (savedSuccessfully && this.pendingModelSwitch) {
1256
- const { provider, model } = this.pendingModelSwitch;
1257
- this.pendingModelSwitch = null;
1258
- // Refresh provider cache and complete the switch
1259
- setTimeout(async () => {
1260
- await this.fetchProviders();
1261
- await this.switchModel(model ? `${provider} ${model}` : provider);
1262
- }, 500);
1263
- }
1264
- }
1265
- showHelp() {
1266
- if (!this.promptController?.supportsInlinePanel()) {
1267
- this.promptController?.setStatusMessage('Help: /model /secrets /auto /stats /keys /clear /exit');
1268
- setTimeout(() => this.promptController?.setStatusMessage(null), 3000);
1269
- return;
1270
- }
1271
- const heading = (s) => chalk.bold.hex('#8B5CF6')(s);
1272
- const cmd = (s) => chalk.hex('#FBBF24')(s);
1273
- const dim = (s) => chalk.dim(s);
1274
- const lines = [
1275
- chalk.bold.hex('#6366F1')('Erosolar Coder Help') + dim(' (press any key to dismiss)'),
1276
- '',
1277
- heading('Slash commands'),
1278
- cmd('/model') + dim(' Cycle provider, or /model <name> to switch'),
1279
- cmd('/key') + dim(' Set DeepSeek API key for this machine'),
1280
- cmd('/secrets') + dim(' Show or set provider keys'),
1281
- cmd('/auto') + dim(' Toggle auto-continue (off → on → dual → off)'),
1282
- cmd('/bash <cmd>') + dim(' Run a one-shot local shell command'),
1283
- cmd('/debug') + dim(' Toggle debug mode'),
1284
- cmd('/stats') + dim(' Show session token + cost stats'),
1285
- cmd('/keys') + dim(' Show keyboard shortcuts'),
1286
- cmd('/clear') + dim(' Clear the screen'),
1287
- cmd('/exit') + dim(' Quit'),
1288
- '',
1289
- heading('Quick start'),
1290
- dim(' 1. /key sk-… (or set ANTHROPIC_API_KEY / OPENAI_API_KEY)'),
1291
- dim(' 2. Type any prompt; the agent reads files, edits, runs commands'),
1292
- dim(' 3. Ctrl+C interrupts an in-flight run'),
1293
- '',
1294
- heading('Companion surface'),
1295
- dim(' Helia — Electron browser at https://ero.solar/helia'),
1296
- dim(' Same Firebase account, same balance, browser-side agent.'),
1297
- '',
1298
- dim('Launch: erosolar (interactive)'),
1299
- dim(' erosolar "task" (interactive, pre-filled with the prompt)'),
1300
- dim('Docs: https://ero.solar/docs | README.md'),
1301
- ];
1302
- this.promptController.setInlinePanel(lines);
1303
- this.scheduleInlinePanelDismiss();
1304
- }
1305
- showKeyboardShortcuts() {
1306
- if (!this.promptController?.supportsInlinePanel()) {
1307
- this.promptController?.setStatusMessage('Use /keys in interactive mode');
1308
- setTimeout(() => this.promptController?.setStatusMessage(null), 3000);
1309
- return;
1310
- }
1311
- const kb = (key) => chalk.hex('#FBBF24')(key);
1312
- const desc = (text) => chalk.dim(text);
1313
- const lines = [
1314
- chalk.bold.hex('#6366F1')('Keyboard Shortcuts') + chalk.dim(' (press any key to dismiss)'),
1315
- '',
1316
- chalk.hex('#22D3EE')('Navigation'),
1317
- ` ${kb('Ctrl+A')} / ${kb('Home')} ${desc('Move to start of line')}`,
1318
- ` ${kb('Ctrl+E')} / ${kb('End')} ${desc('Move to end of line')}`,
1319
- ` ${kb('Alt+←')} / ${kb('Alt+→')} ${desc('Move word by word')}`,
1320
- '',
1321
- chalk.hex('#22D3EE')('Editing'),
1322
- ` ${kb('Ctrl+U')} ${desc('Clear entire line')}`,
1323
- ` ${kb('Ctrl+W')} / ${kb('Alt+⌫')} ${desc('Delete word backward')}`,
1324
- ` ${kb('Ctrl+K')} ${desc('Delete to end of line')}`,
1325
- '',
1326
- chalk.hex('#22D3EE')('Display'),
1327
- ` ${kb('Ctrl+L')} ${desc('Clear screen')}`,
1328
- ` ${kb('Ctrl+O')} ${desc('Expand last tool result')}`,
1329
- '',
1330
- chalk.hex('#22D3EE')('Control'),
1331
- ` ${kb('Ctrl+C')} ${desc('Cancel input / interrupt')}`,
1332
- ` ${kb('Ctrl+D')} ${desc('Exit (when empty)')}`,
1333
- ` ${kb('Esc')} ${desc('Interrupt AI response')}`,
1334
- ];
1335
- this.promptController.setInlinePanel(lines);
1336
- this.scheduleInlinePanelDismiss();
1337
- }
1338
- showSessionStats() {
1339
- if (!this.promptController?.supportsInlinePanel()) {
1340
- this.promptController?.setStatusMessage('Use /stats in interactive mode');
1341
- setTimeout(() => this.promptController?.setStatusMessage(null), 3000);
1342
- return;
1343
- }
1344
- const history = this.controller.getHistory();
1345
- const messageCount = history.length;
1346
- const userMessages = history.filter(m => m.role === 'user').length;
1347
- const assistantMessages = history.filter(m => m.role === 'assistant').length;
1348
- // Calculate approximate token usage from history
1349
- let totalChars = 0;
1350
- for (const msg of history) {
1351
- if (typeof msg.content === 'string') {
1352
- totalChars += msg.content.length;
1353
- }
1354
- }
1355
- const approxTokens = Math.round(totalChars / 4); // Rough estimate
1356
- const collapsedCount = this.promptController?.getRenderer?.()?.getCollapsedResultCount?.() ?? 0;
1357
- const lines = [
1358
- chalk.bold.hex('#6366F1')('Session Stats') + chalk.dim(' (press any key to dismiss)'),
1359
- '',
1360
- chalk.hex('#22D3EE')('Conversation'),
1361
- ` ${chalk.white(messageCount.toString())} messages (${userMessages} user, ${assistantMessages} assistant)`,
1362
- ` ${chalk.dim('~')}${chalk.white(approxTokens.toLocaleString())} ${chalk.dim('tokens (estimate)')}`,
1363
- '',
1364
- chalk.hex('#22D3EE')('Model'),
1365
- ` ${chalk.white(this.profileConfig.model)} ${chalk.dim('on')} ${chalk.hex('#A855F7')(this.profileConfig.provider)}`,
1366
- collapsedCount > 0 ? ` ${chalk.white(collapsedCount.toString())} collapsed results` : '',
1367
- '',
1368
- chalk.hex('#22D3EE')('Settings'),
1369
- ` Debug: ${this.debugEnabled ? chalk.green('on') : chalk.dim('off')}`,
1370
- ].filter(line => line !== '');
1371
- this.promptController.setInlinePanel(lines);
1372
- this.scheduleInlinePanelDismiss();
1373
- }
1374
- async showMcpStatus() {
1375
- const manager = getSharedMcpManager(this.workingDir);
1376
- await manager.init();
1377
- const entries = manager.getEntries();
1378
- if (!this.promptController?.supportsInlinePanel()) {
1379
- const summary = entries.length === 0
1380
- ? 'No MCP servers configured (.erosolar/mcp.json)'
1381
- : entries.map(e => e.status === 'connected'
1382
- ? `${e.name}: ${e.tools.length} tools`
1383
- : `${e.name}: ERROR (${e.error})`).join(' · ');
1384
- this.promptController?.setStatusMessage(summary);
1385
- setTimeout(() => this.promptController?.setStatusMessage(null), 4000);
1386
- return;
1387
- }
1388
- const lines = [
1389
- chalk.bold.hex('#6366F1')('MCP Servers') + chalk.dim(' (.erosolar/mcp.json)'),
1390
- '',
1391
- ];
1392
- if (entries.length === 0) {
1393
- lines.push(chalk.dim(' No servers configured.'));
1394
- lines.push(chalk.dim(' Add entries to ~/.erosolar/mcp.json or <project>/.erosolar/mcp.json.'));
1395
- }
1396
- else {
1397
- for (const entry of entries) {
1398
- if (entry.status === 'connected') {
1399
- lines.push(` ${chalk.green('●')} ${chalk.white(entry.name)} ` +
1400
- chalk.dim(`${entry.spec.command}${entry.spec.args?.length ? ' ' + entry.spec.args.join(' ') : ''}`));
1401
- lines.push(` ${chalk.dim('tools: ')}${chalk.hex('#22D3EE')(String(entry.tools.length))}`);
1402
- for (const t of entry.tools.slice(0, 8)) {
1403
- lines.push(` ${chalk.dim('·')} ${chalk.white(t.name)}`);
1404
- }
1405
- if (entry.tools.length > 8) {
1406
- lines.push(` ${chalk.dim(`… +${entry.tools.length - 8} more`)}`);
1407
- }
1408
- }
1409
- else {
1410
- lines.push(` ${chalk.red('●')} ${chalk.white(entry.name)} ${chalk.red('error')}`);
1411
- lines.push(` ${chalk.dim(entry.error)}`);
1412
- }
1413
- }
1414
- }
1415
- this.promptController.setInlinePanel(lines);
1416
- this.scheduleInlinePanelDismiss();
1417
- }
1418
- /**
1419
- * Auto-dismiss inline panel after timeout or on next input.
1420
- */
1421
- inlinePanelDismissTimer = null;
1422
- scheduleInlinePanelDismiss() {
1423
- // Clear any existing timer
1424
- if (this.inlinePanelDismissTimer) {
1425
- clearTimeout(this.inlinePanelDismissTimer);
1426
- }
1427
- // Auto-dismiss after 8 seconds
1428
- this.inlinePanelDismissTimer = setTimeout(() => {
1429
- this.promptController?.clearInlinePanel();
1430
- this.inlinePanelDismissTimer = null;
1431
- }, 8000);
1432
- }
1433
- dismissInlinePanel() {
1434
- if (this.inlinePanelDismissTimer) {
1435
- clearTimeout(this.inlinePanelDismissTimer);
1436
- this.inlinePanelDismissTimer = null;
1437
- }
1438
- this.promptController?.clearInlinePanel();
1439
- }
1440
- handleSubmit(text) {
1441
- const trimmed = text.trim();
1442
- // Handle secret input mode - capture the API key value
1443
- if (this.secretInputMode.active && this.secretInputMode.secretId) {
1444
- this.handleSecretValue(trimmed);
1445
- return;
1446
- }
1447
- if (!trimmed) {
1448
- return;
1449
- }
1450
- // Handle slash commands first - these don't go to the AI
1451
- if (trimmed.startsWith('/')) {
1452
- if (this.handleSlashCommand(trimmed)) {
1453
- return;
1454
- }
1455
- // Unknown slash command - silent status flash, dismiss inline panel
1456
- this.dismissInlinePanel();
1457
- this.promptController?.setStatusMessage(`Unknown: ${trimmed.slice(0, 30)}`);
1458
- setTimeout(() => this.promptController?.setStatusMessage(null), 2000);
1459
- return;
1460
- }
1461
- // Dismiss inline panel for regular user prompts
1462
- this.dismissInlinePanel();
1463
- if (this.isProcessing) {
1464
- this.pendingPrompts.push(trimmed);
1465
- return;
1466
- }
1467
- void this.processPrompt(trimmed);
1468
- }
1469
- async processPrompt(prompt) {
1470
- if (this.isProcessing) {
1471
- return;
1472
- }
1473
- // Start new run for file change tracking (enables /revert)
1474
- startNewRun();
1475
- const sanitizedPrompt = prompt;
1476
- // Store original prompt for auto-continuation (if not a continuation or auto-generated prompt)
1477
- if (prompt !== 'continue' && !prompt.startsWith('IMPORTANT:')) {
1478
- this.originalPromptForAutoContinue = prompt;
1479
- // A fresh user prompt clears any prior interrupt state — this is new
1480
- // work the user actually wants done.
1481
- this.userInterruptedRun = false;
1482
- // Pinned-prompt persistence removed per request — no longer
1483
- // displayed above the chat box.
1484
- }
1485
- enterCriticalSection();
1486
- this.isProcessing = true;
1487
- this.currentResponseBuffer = '';
1488
- this.promptController?.setStreaming(true);
1489
- this.promptController?.setStatusMessage('🔄 Analyzing request...');
1490
- const renderer = this.promptController?.getRenderer();
1491
- let episodeSuccess = false;
1492
- const toolsUsed = [];
1493
- const filesModified = [];
1494
- // Track reasoning content for fallback when response is empty
1495
- let reasoningBuffer = '';
1496
- // Track reasoning-only time to prevent models from reasoning forever without action
1497
- let reasoningOnlyStartTime = null;
1498
- let reasoningTimedOut = false;
1499
- let stepTimedOut = false;
1500
- let hitlDepth = 0;
1501
- // Track total prompt processing time to prevent infinite loops
1502
- const promptStartTime = Date.now();
1503
- const TOTAL_PROMPT_TIMEOUT_MS = 24 * 60 * 60 * 1000; // 24 hours max for entire prompt without meaningful content
1504
- let hasReceivedMeaningfulContent = false;
1505
- // Track response content separately - tool calls don't count for reasoning timeout
1506
- let hasReceivedResponseContent = false;
1507
- try {
1508
- // Use timeout-wrapped iterator to prevent hanging on slow/stuck models
1509
- for await (const eventOrTimeout of iterateWithTimeout(this.controller.send(sanitizedPrompt), PROMPT_STEP_TIMEOUT_MS)) {
1510
- // Check for timeout marker
1511
- if (eventOrTimeout && typeof eventOrTimeout === 'object' && '__timeout' in eventOrTimeout) {
1512
- if (hitlDepth > 0) {
1513
- this.promptController?.setStatusMessage('⏱ Waiting for human decision...');
1514
- continue;
1515
- }
1516
- stepTimedOut = true;
1517
- this.promptController?.setStatusMessage(`⏱ Step timeout (${PROMPT_STEP_TIMEOUT_MS / 1000}s) - completing response`);
1518
- // Cancel the controller so the underlying agent stops generating
1519
- // events that would never be consumed. Without this the spinner
1520
- // can keep ticking against a "ghost" run after the for-await
1521
- // loop exits, and any in-flight tool keeps doing work the user
1522
- // can't see or stop.
1523
- try {
1524
- this.controller.cancel('step timeout');
1525
- }
1526
- catch { /* best-effort */ }
1527
- break;
1528
- }
1529
- // Check total elapsed time - bail out if too long without meaningful content
1530
- const totalElapsed = Date.now() - promptStartTime;
1531
- if (!hasReceivedMeaningfulContent && totalElapsed > TOTAL_PROMPT_TIMEOUT_MS) {
1532
- if (renderer) {
1533
- renderer.addEvent('response', chalk.yellow(`\n⏱ Response timeout (${Math.round(totalElapsed / 1000)}s) - completing\n`));
1534
- }
1535
- reasoningTimedOut = true;
1536
- try {
1537
- this.controller.cancel('response timeout');
1538
- }
1539
- catch { /* best-effort */ }
1540
- break;
1541
- }
1542
- const event = eventOrTimeout;
1543
- if (this.shouldExit) {
1544
- break;
1545
- }
1546
- switch (event.type) {
1547
- case 'message.start':
1548
- // AI has started processing - update status to show activity
1549
- this.currentResponseBuffer = '';
1550
- reasoningBuffer = '';
1551
- reasoningOnlyStartTime = null; // Reset on new message
1552
- this.promptController?.setStatusMessage('Thinking...');
1553
- break;
1554
- case 'message.delta':
1555
- // Stream content as it arrives
1556
- this.currentResponseBuffer += event.content ?? '';
1557
- if (renderer) {
1558
- renderer.addEvent('stream', event.content);
1559
- }
1560
- // Reset reasoning timer only when we get actual non-empty content
1561
- if (event.content && event.content.trim()) {
1562
- reasoningOnlyStartTime = null;
1563
- hasReceivedMeaningfulContent = true;
1564
- hasReceivedResponseContent = true; // Track actual response content
1565
- }
1566
- break;
1567
- case 'reasoning':
1568
- // Accumulate reasoning for potential fallback synthesis
1569
- reasoningBuffer += event.content ?? '';
1570
- // Update status to show reasoning is actively streaming
1571
- this.promptController?.setActivityMessage('Thinking');
1572
- // Start the reasoning timer on first reasoning event
1573
- if (!reasoningOnlyStartTime) {
1574
- reasoningOnlyStartTime = Date.now();
1575
- }
1576
- // Display useful reasoning as 'thought' events BEFORE the response
1577
- // The renderer's curateReasoningContent and shouldRenderThought will filter
1578
- // to show only actionable/structured thoughts
1579
- if (renderer && event.content?.trim()) {
1580
- renderer.addEvent('thought', event.content);
1581
- }
1582
- break;
1583
- case 'message.complete':
1584
- // Response complete — clear thinking AND reasoning indicators
1585
- // both. statusMessage clears 'Thinking...' (set on message.start
1586
- // and after each tool); activityMessage clears the reasoning
1587
- // chip (set on every 'reasoning' event but never reset until
1588
- // the post-loop finally). Without clearing activityMessage
1589
- // here, the spinner kept ticking between message-end and the
1590
- // next event because composedStatus falls through to the still-
1591
- // set 'Thinking' activity label.
1592
- this.promptController?.setStatusMessage(null);
1593
- this.promptController?.setActivityMessage(null);
1594
- // Response complete - ensure final output includes required "Next steps"
1595
- if (renderer) {
1596
- // Use the appended field from ensureNextSteps to avoid re-rendering the entire response
1597
- const base = (event.content ?? '').trimEnd();
1598
- let sourceText = base || this.currentResponseBuffer;
1599
- // If content came via message.complete but NOT via deltas, render it now as a proper response
1600
- // This handles models that don't stream deltas (e.g., deepseek-v4-pro)
1601
- // IMPORTANT: Do NOT re-emit content that was already streamed via 'message.delta' events
1602
- // to prevent duplicate display of the same response
1603
- if (base && !this.currentResponseBuffer.trim()) {
1604
- renderer.addEvent('response', base);
1605
- }
1606
- // Note: We intentionally DO NOT re-emit currentResponseBuffer as a 'response' event
1607
- // because it was already displayed via 'stream' events during message.delta handling
1608
- // Fallback: If response is empty but we have reasoning, synthesize a response
1609
- if (!sourceText.trim() && reasoningBuffer.trim()) {
1610
- // Extract key conclusions from reasoning for display
1611
- const synthesized = this.synthesizeFromReasoning(reasoningBuffer);
1612
- if (synthesized) {
1613
- renderer.addEvent('response', synthesized);
1614
- sourceText = synthesized;
1615
- }
1616
- }
1617
- episodeSuccess = true; // Mark episode as successful only after we have content
1618
- // Only add "Next steps" if tools were actually used (real work done)
1619
- // This prevents showing "Next steps" after reasoning-only responses
1620
- if (toolsUsed.length > 0) {
1621
- const { appended } = ensureNextSteps(sourceText);
1622
- // Only stream the newly appended content (e.g., "Next steps:")
1623
- // The main response was already added as a response event above
1624
- if (appended && appended.trim()) {
1625
- renderer.addEvent('response', appended);
1626
- }
1627
- }
1628
- renderer.addEvent('response', '\n');
1629
- }
1630
- this.currentResponseBuffer = '';
1631
- break;
1632
- case 'tool.start': {
1633
- const toolName = event.toolName;
1634
- const args = event.parameters;
1635
- // Default format: `ToolName(arg)` — Claude Code's idiom.
1636
- // ChatStatic prefixes a `⏺ ` glyph for kind='tool', so this
1637
- // string is what reads after the bullet. Shorter and more
1638
- // scannable than `[ToolName] arg`.
1639
- let toolDisplay = toolName;
1640
- if (isHitlToolName(toolName)) {
1641
- hitlDepth += 1;
1642
- }
1643
- // Reset reasoning timer when tools are being called (model is taking action)
1644
- reasoningOnlyStartTime = null;
1645
- hasReceivedMeaningfulContent = true;
1646
- if (!toolsUsed.includes(toolName)) {
1647
- toolsUsed.push(toolName);
1648
- }
1649
- const filePath = args?.['file_path'];
1650
- if (filePath && (toolName === 'Write' || toolName === 'Edit')) {
1651
- if (!filesModified.includes(filePath)) {
1652
- filesModified.push(filePath);
1653
- }
1654
- }
1655
- if (toolName === 'Bash' && args?.['command']) {
1656
- toolDisplay = `Bash(${String(args['command']).slice(0, 120)})`;
1657
- }
1658
- else if (toolName === 'Read' && args?.['file_path']) {
1659
- toolDisplay = `Read(${args['file_path']})`;
1660
- }
1661
- else if (toolName === 'Write' && args?.['file_path']) {
1662
- toolDisplay = `Write(${args['file_path']})`;
1663
- }
1664
- else if (toolName === 'Edit' && args?.['file_path']) {
1665
- toolDisplay = `Edit(${args['file_path']})`;
1666
- }
1667
- else if (toolName === 'Search' && args?.['pattern']) {
1668
- toolDisplay = `Search(${args['pattern']})`;
1669
- }
1670
- else if (toolName === 'Grep' && args?.['pattern']) {
1671
- toolDisplay = `Grep(${args['pattern']})`;
1672
- }
1673
- else if (toolName === 'WebSearch' && args?.['query']) {
1674
- toolDisplay = `WebSearch("${String(args['query']).slice(0, 80)}")`;
1675
- }
1676
- else if (toolName === 'WebExtract') {
1677
- const urlsArg = args?.['urls'];
1678
- const urls = Array.isArray(urlsArg)
1679
- ? urlsArg.filter((u) => typeof u === 'string')
1680
- : typeof args?.['url'] === 'string'
1681
- ? [args['url']]
1682
- : [];
1683
- const display = urls.length > 0
1684
- ? urls.length === 1 ? urls[0] : `${urls[0]} (+${urls.length - 1} more)`
1685
- : '...';
1686
- toolDisplay = `WebExtract(${display})`;
1687
- }
1688
- if (renderer) {
1689
- renderer.addEvent('tool', toolDisplay);
1690
- }
1691
- // Provide explanatory status messages for different tool types
1692
- let statusMsg = '';
1693
- if (toolName === 'Bash') {
1694
- statusMsg = `Running: ${args?.['command'] ? String(args['command']).slice(0, 40) : '...'}`;
1695
- }
1696
- else if (toolName === 'Edit' || toolName === 'Write') {
1697
- statusMsg = `📝 Editing file: ${args?.['file_path'] || '...'}`;
1698
- }
1699
- else if (toolName === 'Read') {
1700
- statusMsg = `📖 Reading file: ${args?.['file_path'] || '...'}`;
1701
- }
1702
- else if (toolName === 'Search' || toolName === 'Grep') {
1703
- statusMsg = `🔍 Searching: ${args?.['pattern'] ? String(args['pattern']).slice(0, 30) : '...'}`;
1704
- }
1705
- else if (toolName === 'WebSearch') {
1706
- statusMsg = `🌐 Searching web: ${args?.['query'] ? String(args['query']).slice(0, 40) : '...'}`;
1707
- }
1708
- else if (toolName === 'WebExtract') {
1709
- const urlsArg = args?.['urls'];
1710
- const firstUrl = Array.isArray(urlsArg)
1711
- ? urlsArg.find((u) => typeof u === 'string')
1712
- : typeof args?.['url'] === 'string' ? args['url'] : '...';
1713
- statusMsg = `🌐 Extracting: ${String(firstUrl ?? '...').slice(0, 50)}`;
1714
- }
1715
- else {
1716
- statusMsg = `🔧 Running ${toolName}...`;
1717
- }
1718
- this.promptController?.setStatusMessage(statusMsg);
1719
- break;
1720
- }
1721
- case 'tool.complete': {
1722
- if (isHitlToolName(event.toolName)) {
1723
- hitlDepth = Math.max(0, hitlDepth - 1);
1724
- }
1725
- // Clear the "Running X..." status since tool is complete
1726
- this.promptController?.setStatusMessage('Thinking...');
1727
- // Reset reasoning timer after tool completes
1728
- reasoningOnlyStartTime = null;
1729
- // The legacy "Done:" header for Bash was redundant — the
1730
- // tool-result item now renders with its own ` ↳ ` indent
1731
- // so the call→result pairing is visually obvious without
1732
- // a separate header line.
1733
- // Pass full result to renderer - it handles display truncation
1734
- // and stores full content for Ctrl+O expansion
1735
- if (event.result && typeof event.result === 'string' && event.result.trim() && renderer) {
1736
- renderer.addEvent('tool-result', event.result);
1737
- }
1738
- break;
1739
- }
1740
- case 'tool.error':
1741
- if (isHitlToolName(event.toolName)) {
1742
- hitlDepth = Math.max(0, hitlDepth - 1);
1743
- }
1744
- // Clear the "Running X..." status since tool errored
1745
- this.promptController?.setStatusMessage('Thinking...');
1746
- if (renderer) {
1747
- renderer.addEvent('error', event.error);
1748
- }
1749
- break;
1750
- case 'error':
1751
- if (renderer) {
1752
- renderer.addEvent('error', event.error);
1753
- }
1754
- break;
1755
- case 'usage':
1756
- reportUsageToFirebase(event.inputTokens || 0, event.outputTokens || 0).catch(() => { });
1757
- this.promptController?.setMetaStatus({
1758
- tokensUsed: event.totalTokens,
1759
- tokenLimit: 200000, // Approximate limit
1760
- });
1761
- break;
1762
- case 'provider.fallback': {
1763
- // Display fallback notification
1764
- if (renderer) {
1765
- const fallbackMsg = chalk.yellow('⚠ ') +
1766
- chalk.dim(`${event.fromProvider}/${event.fromModel} failed: `) +
1767
- chalk.hex('#EF4444')(event.reason) +
1768
- chalk.dim(' → switching to ') +
1769
- chalk.hex('#34D399')(`${event.toProvider}/${event.toModel}`);
1770
- renderer.addEvent('banner', fallbackMsg);
1771
- }
1772
- // Update the model context to reflect the new provider/model
1773
- this.profileConfig = {
1774
- ...this.profileConfig,
1775
- provider: event.toProvider,
1776
- model: event.toModel,
1777
- };
1778
- this.promptController?.setModelContext({
1779
- model: event.toModel,
1780
- provider: event.toProvider,
1781
- });
1782
- break;
1783
- }
1784
- case 'edit.explanation':
1785
- // Show explanation for edits made
1786
- if (event.content && renderer) {
1787
- const filesInfo = event.files?.length ? ` (${event.files.join(', ')})` : '';
1788
- renderer.addEvent('response', `${event.content}${filesInfo}`);
1789
- }
1790
- break;
1791
- }
1792
- // Check reasoning timeout on EVERY iteration (not just when reasoning events arrive)
1793
- // This ensures we bail out even if events are sparse
1794
- // Use hasReceivedResponseContent (not hasReceivedMeaningfulContent) so timeout
1795
- // still triggers after tool calls if model just reasons without responding
1796
- if (reasoningOnlyStartTime && !hasReceivedResponseContent) {
1797
- const reasoningElapsed = Date.now() - reasoningOnlyStartTime;
1798
- if (reasoningElapsed > PROMPT_REASONING_TIMEOUT_MS) {
1799
- if (renderer) {
1800
- renderer.addEvent('response', chalk.yellow(`\n⏱ Reasoning timeout (${Math.round(reasoningElapsed / 1000)}s)\n`));
1801
- }
1802
- reasoningTimedOut = true;
1803
- }
1804
- }
1805
- // Check if reasoning timeout was triggered - break out of event loop
1806
- if (reasoningTimedOut) {
1807
- // Cancel the controller too; otherwise the for-await drain
1808
- // exits but the agent keeps producing events and side-effects
1809
- // for the next 30+ seconds with no UI to consume them.
1810
- try {
1811
- this.controller.cancel('reasoning timeout');
1812
- }
1813
- catch { /* best-effort */ }
1814
- break;
1815
- }
1816
- }
1817
- // After loop: synthesize from reasoning if no response was generated or timed out
1818
- // This handles models like deepseek-v4-pro that output thinking but empty response
1819
- // Also handles step timeouts where the model was stuck
1820
- // IMPORTANT: Don't add "Next steps" when only reasoning occurred - only after real work
1821
- if ((!episodeSuccess || reasoningTimedOut || stepTimedOut) && reasoningBuffer.trim() && !this.currentResponseBuffer.trim()) {
1822
- const synthesized = this.synthesizeFromReasoning(reasoningBuffer);
1823
- if (synthesized && renderer) {
1824
- renderer.addEvent('stream', '\n' + synthesized);
1825
- // Only add "Next steps" if tools were actually used (real work done)
1826
- if (toolsUsed.length > 0) {
1827
- const { appended } = ensureNextSteps(synthesized);
1828
- if (appended?.trim()) {
1829
- renderer.addEvent('stream', appended);
1830
- }
1831
- }
1832
- renderer.addEvent('response', '\n');
1833
- episodeSuccess = true;
1834
- }
1835
- }
1836
- }
1837
- catch (error) {
1838
- const message = error instanceof Error ? error.message : String(error);
1839
- if (renderer) {
1840
- renderer.addEvent('error', message);
1841
- }
1842
- // Fallback: If we have reasoning content but no response was generated, synthesize one
1843
- if (!episodeSuccess && reasoningBuffer.trim() && !this.currentResponseBuffer.trim()) {
1844
- const synthesized = this.synthesizeFromReasoning(reasoningBuffer);
1845
- if (synthesized && renderer) {
1846
- renderer.addEvent('stream', '\n' + synthesized);
1847
- renderer.addEvent('response', '\n');
1848
- episodeSuccess = true; // Mark as partial success
1849
- }
1850
- }
1851
- }
1852
- finally {
1853
- // Exit critical section - allow termination again
1854
- exitCriticalSection();
1855
- // Final fallback: If stream ended without message.complete but we have reasoning
1856
- if (!episodeSuccess && reasoningBuffer.trim() && !this.currentResponseBuffer.trim()) {
1857
- const synthesized = this.synthesizeFromReasoning(reasoningBuffer);
1858
- if (synthesized && renderer) {
1859
- renderer.addEvent('stream', '\n' + synthesized);
1860
- // Only add "Next steps" if tools were actually used (real work done)
1861
- if (toolsUsed.length > 0) {
1862
- const { appended } = ensureNextSteps(synthesized);
1863
- if (appended?.trim()) {
1864
- renderer.addEvent('stream', appended);
1865
- }
1866
- }
1867
- renderer.addEvent('response', '\n');
1868
- episodeSuccess = true;
1869
- }
1870
- }
1871
- // Detect a model safety refusal in the just-finished turn. When the
1872
- // model declines the request, the request is *done* — auto-continue
1873
- // would just resubmit "continue" and start a new spinner cycle, which
1874
- // is what produced the stuck "Thinking… (4m N s)" timer the user saw.
1875
- const refusedTurn = isSafetyRefusal(this.currentResponseBuffer);
1876
- this.isProcessing = false;
1877
- this.promptController?.setStreaming(false);
1878
- this.promptController?.setStatusMessage(null);
1879
- // Belt-and-suspenders: explicitly clear the activity message so the
1880
- // "Thinking… (esc to interrupt · Ns)" line doesn't linger after the
1881
- // final reply if setMode→stopSpinnerAnimation races with another
1882
- // renderPrompt tick.
1883
- this.promptController?.setActivityMessage(null);
1884
- // Force an idle re-render so the spinner area is repainted without
1885
- // the streaming activity line. setStreaming(false) → setMode('idle')
1886
- // already calls renderPrompt(), but a coalesced spinner tick that
1887
- // races with the transition can leave the last "Thinking… (Ns)"
1888
- // frame on screen until the next event. forceRender squashes it.
1889
- this.promptController?.forceRender();
1890
- this.currentResponseBuffer = '';
1891
- // Process any queued prompts
1892
- if (this.pendingPrompts.length > 0 && !this.shouldExit) {
1893
- const next = this.pendingPrompts.shift();
1894
- if (next) {
1895
- await this.processPrompt(next);
1896
- }
1897
- }
1898
- else if (refusedTurn) {
1899
- // Refusal terminates the turn. Don't re-prompt the model — the
1900
- // user's request is finished from the agent's side. Clear the
1901
- // stored "original prompt" so a stray Alt+G later doesn't pick
1902
- // up where this turn left off.
1903
- this.originalPromptForAutoContinue = null;
1904
- }
1905
- else if (!this.shouldExit && !this.userInterruptedRun) {
1906
- // Auto mode: keep running until user's prompt is fully completed.
1907
- // Skipped after a Ctrl+C interrupt so we don't immediately resume
1908
- // the work the user just cancelled.
1909
- const autoMode = this.promptController?.getAutoMode() ?? 'off';
1910
- if (autoMode !== 'off') {
1911
- // Check if original user prompt is fully completed
1912
- const detector = getTaskCompletionDetector();
1913
- const analysis = detector.analyzeCompletion(this.currentResponseBuffer, toolsUsed);
1914
- // Continue until task is complete
1915
- if (!analysis.isComplete) {
1916
- this.promptController?.setStatusMessage('Continuing...');
1917
- await new Promise(resolve => setTimeout(resolve, 500));
1918
- // Generate auto-continue prompt using stored original prompt
1919
- const autoPrompt = this.generateAutoContinuePrompt(this.originalPromptForAutoContinue || '', this.currentResponseBuffer, toolsUsed);
1920
- if (autoPrompt) {
1921
- await this.processPrompt(autoPrompt);
1922
- }
1923
- else {
1924
- // Default continue if no specific auto-prompt generated
1925
- await this.processPrompt('continue');
1926
- }
1927
- }
1928
- else {
1929
- this.promptController?.setStatusMessage('Task complete');
1930
- setTimeout(() => this.promptController?.setStatusMessage(null), 2000);
1931
- }
1932
- }
1933
- else if (episodeSuccess && !stepTimedOut && !reasoningTimedOut) {
1934
- // Manual mode (autoMode === 'off') — show a brief end-of-turn
1935
- // signal so the user knows the agent is idle again. Without
1936
- // this the spinner just vanishes silently, which on slow
1937
- // terminals reads as "still thinking" or "hung". Skipped on
1938
- // errors / timeouts because those already render their own
1939
- // explanatory bubble.
1940
- this.promptController?.setStatusMessage('✓ Done');
1941
- setTimeout(() => this.promptController?.setStatusMessage(null), 2000);
1942
- }
1943
- }
1944
- }
1945
- }
1946
- generateAutoContinuePrompt(originalPrompt, response, toolsUsed) {
1947
- // Highest-priority signal: a test or build is currently failing
1948
- // in the visible output. Override every other heuristic and force
1949
- // a sharp, focused next-action prompt — the agent must drill into
1950
- // the FIRST failure rather than declaring victory.
1951
- const failingSignal = detectFailingTestOrBuild(response);
1952
- if (failingSignal) {
1953
- const noDocsInstruction = `IMPORTANT: Do NOT create markdown files, documentation, summaries, or reports.`;
1954
- return `${noDocsInstruction} The output above shows a failing test/build (${failingSignal}). Read the FIRST failure carefully, identify the root cause, edit exactly the file(s) needed, then re-run the same test/build command to confirm. Do not stop until that command exits cleanly.`;
1955
- }
1956
- // Only auto-continue for certain types of work
1957
- const hasFileOperations = toolsUsed.some(t => ['Read', 'Write', 'Edit', 'Search', 'Grep'].includes(t));
1958
- const hasBashOperations = toolsUsed.includes('Bash');
1959
- if (!hasFileOperations && !hasBashOperations) {
1960
- return null; // No meaningful work to continue
1961
- }
1962
- // Analyze response to determine what to do next
1963
- const lowercaseResponse = response.toLowerCase();
1964
- // Check for common patterns that indicate more work is needed
1965
- if (lowercaseResponse.includes('next steps') ||
1966
- lowercaseResponse.includes('further') ||
1967
- lowercaseResponse.includes('additional') ||
1968
- lowercaseResponse.includes('implement') ||
1969
- lowercaseResponse.includes('complete') ||
1970
- lowercaseResponse.includes('finish')) {
1971
- // Core instruction to prevent documentation spam
1972
- const noDocsInstruction = `IMPORTANT: Do NOT create markdown files, documentation, summaries, or reports. Focus only on the actual code/implementation work. Perform the next concrete action in the codebase.`;
1973
- // Generate a follow-up prompt based on the original task
1974
- if (originalPrompt.includes('fix') || originalPrompt.includes('bug')) {
1975
- return `${noDocsInstruction} Continue fixing - edit the next file that needs changes.`;
1976
- }
1977
- else if (originalPrompt.includes('implement') || originalPrompt.includes('add')) {
1978
- return `${noDocsInstruction} Continue implementing - write or edit the next piece of code.`;
1979
- }
1980
- else if (originalPrompt.includes('refactor') || originalPrompt.includes('clean')) {
1981
- return `${noDocsInstruction} Continue refactoring - apply changes to the next file.`;
1982
- }
1983
- else if (originalPrompt.includes('test')) {
1984
- return `${noDocsInstruction} Continue with tests - run or fix the next test.`;
1985
- }
1986
- else if (originalPrompt.includes('build') || originalPrompt.includes('deploy') || originalPrompt.includes('publish')) {
1987
- return `${noDocsInstruction} Continue the build/deploy process - execute the next command.`;
1988
- }
1989
- else {
1990
- return `${noDocsInstruction} Continue with the original task "${originalPrompt.slice(0, 100)}..." - perform the next action.`;
1991
- }
1992
- }
1993
- return null;
1994
- }
1995
- handleInterrupt() {
1996
- if (!this.isProcessing) {
1997
- return;
1998
- }
1999
- const renderer = this.promptController?.getRenderer();
2000
- if (renderer) {
2001
- renderer.addEvent('banner', chalk.yellow('Interrupted'));
2002
- }
2003
- // Actually cancel the in-flight controller run. Without this the
2004
- // for-await loop in processPrompt keeps consuming events, the spinner
2005
- // stays up, and the agent grinds through the rest of its tool loop
2006
- // while the user sees only a "Interrupted" banner. cancel() is a no-op
2007
- // when there's no active sink, so this is safe to call unconditionally.
2008
- try {
2009
- this.controller.cancel('user interrupt via Ctrl+C');
2010
- }
2011
- catch {
2012
- // Best-effort; if the controller is already torn down the next
2013
- // Ctrl+C will fall through to authorizedShutdown.
2014
- }
2015
- // Suppress the auto-continue re-launch in processPrompt's finally
2016
- // block. Otherwise the agent immediately starts a fresh "continue"
2017
- // cycle 500ms later and the user has to keep mashing Ctrl+C to keep
2018
- // up. Cleared when the user submits a new prompt.
2019
- this.userInterruptedRun = true;
2020
- }
2021
- handleAutoContinueToggle() {
2022
- const autoMode = this.promptController?.getAutoMode() ?? 'off';
2023
- this.promptController?.setStatusMessage(`Auto: ${autoMode}`);
2024
- setTimeout(() => this.promptController?.setStatusMessage(null), 1500);
2025
- // Reset task completion detector when entering any auto mode
2026
- if (autoMode !== 'off') {
2027
- const detector = getTaskCompletionDetector();
2028
- detector.reset();
2029
- // Clear any stored original prompt
2030
- this.originalPromptForAutoContinue = null;
2031
- }
2032
- }
2033
- handleHITLToggle() {
2034
- const mode = this.promptController?.getModeToggleState().hitlMode ?? 'off';
2035
- getHITL().updateConfig({ autoPause: mode === 'on' });
2036
- this.promptController?.setStatusMessage(`HITL: ${mode}`);
2037
- setTimeout(() => this.promptController?.setStatusMessage(null), 1500);
2038
- }
2039
- handleCtrlC(info) {
2040
- const now = Date.now();
2041
- // Reset count if more than 2 seconds since last Ctrl+C
2042
- if (now - this.lastCtrlCTime > 2000) {
2043
- this.ctrlCCount = 0;
2044
- }
2045
- this.lastCtrlCTime = now;
2046
- this.ctrlCCount++;
2047
- if (info.hadBuffer) {
2048
- // Clear buffer, reset count
2049
- this.ctrlCCount = 0;
2050
- return;
2051
- }
2052
- // Always allow double Ctrl+C to exit, even while processing
2053
- if (this.ctrlCCount >= 2) {
2054
- // Use authorized shutdown to bypass anti-termination guard
2055
- void authorizedShutdown(0);
2056
- this.shouldExit = true;
2057
- this.ctrlCCount = 0;
2058
- return;
2059
- }
2060
- if (this.isProcessing) {
2061
- // Interrupt processing on first Ctrl+C, then allow next Ctrl+C to exit
2062
- this.handleInterrupt();
2063
- const renderer = this.promptController?.getRenderer();
2064
- if (renderer) {
2065
- renderer.addEvent('banner', chalk.dim('Press Ctrl+C again to exit'));
2066
- }
2067
- return;
2068
- }
2069
- // First Ctrl+C when idle: show hint
2070
- const renderer = this.promptController?.getRenderer();
2071
- if (renderer) {
2072
- renderer.addEvent('banner', chalk.dim('Press Ctrl+C again to exit'));
2073
- }
2074
- }
2075
- handleExit() {
2076
- this.shouldExit = true;
2077
- this.cleanupSudoPasswordHandler();
2078
- this.promptController?.stop();
2079
- void authorizedShutdown(0);
2080
- }
2081
- waitForExit() {
2082
- return new Promise((resolve) => {
2083
- const check = () => {
2084
- if (this.shouldExit) {
2085
- resolve();
2086
- }
2087
- else {
2088
- setTimeout(check, 100);
2089
- }
2090
- };
2091
- check();
2092
- });
2093
- }
2094
- }
2095
- function parseArgs(argv) {
2096
- const promptTokens = [];
2097
- for (let index = 0; index < argv.length; index += 1) {
2098
- const token = argv[index];
2099
- if (!token) {
2100
- continue;
2101
- }
2102
- // Skip known flags
2103
- if (token.startsWith('--') || token.startsWith('-')) {
2104
- continue;
2105
- }
2106
- promptTokens.push(token);
2107
- }
2108
- return {
2109
- initialPrompt: promptTokens.length ? promptTokens.join(' ').trim() : null,
2110
- };
2111
- }
2112
- // Default profile is erosolar-code; opt-in offsec / engagement profiles
2113
- // activate via EROSOLAR_PROFILE env var so the default tool inventory
2114
- // stays clean for ordinary coding sessions.
2115
- function resolveProfile() {
2116
- const env = process.env.EROSOLAR_PROFILE?.trim();
2117
- if (env && hasAgentProfile(env))
2118
- return env;
2119
- return 'erosolar-code';
2120
- }
2121
- //# sourceMappingURL=interactiveShell.js.map