erosolar-cli 1.5.2 → 1.5.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (346) hide show
  1. package/config/security-deployment.json +54 -0
  2. package/dist/bin/adapters/node/index.js +33 -0
  3. package/dist/bin/adapters/types.js +1 -0
  4. package/dist/bin/alpha-zero/agentWrapper.js +165 -0
  5. package/dist/bin/alpha-zero/codeEvaluator.js +272 -0
  6. package/dist/bin/alpha-zero/competitiveRunner.js +219 -0
  7. package/dist/bin/alpha-zero/index.js +98 -0
  8. package/dist/bin/alpha-zero/introspection.js +298 -0
  9. package/dist/bin/alpha-zero/metricsTracker.js +207 -0
  10. package/dist/bin/alpha-zero/security/core.js +269 -0
  11. package/dist/bin/alpha-zero/security/google.js +308 -0
  12. package/dist/bin/alpha-zero/security/googleLoader.js +40 -0
  13. package/dist/bin/alpha-zero/security/index.js +31 -0
  14. package/dist/bin/alpha-zero/security/simulation.js +274 -0
  15. package/dist/bin/alpha-zero/selfModification.js +231 -0
  16. package/dist/bin/alpha-zero/types.js +30 -0
  17. package/dist/bin/bin/erosolar-optimized.js +205 -0
  18. package/dist/bin/capabilities/agentSpawningCapability.js +116 -0
  19. package/dist/bin/capabilities/bashCapability.js +22 -0
  20. package/dist/bin/capabilities/cloudCapability.js +36 -0
  21. package/dist/bin/capabilities/codeAnalysisCapability.js +22 -0
  22. package/dist/bin/capabilities/codeQualityCapability.js +23 -0
  23. package/dist/bin/capabilities/dependencySecurityCapability.js +22 -0
  24. package/dist/bin/capabilities/devCapability.js +22 -0
  25. package/dist/bin/capabilities/editCapability.js +28 -0
  26. package/dist/bin/capabilities/emailCapability.js +20 -0
  27. package/dist/bin/capabilities/enhancedGitCapability.js +221 -0
  28. package/dist/bin/capabilities/filesystemCapability.js +22 -0
  29. package/dist/bin/capabilities/globCapability.js +28 -0
  30. package/dist/bin/capabilities/interactionCapability.js +20 -0
  31. package/dist/bin/capabilities/learnCapability.js +22 -0
  32. package/dist/bin/capabilities/mcpCapability.js +20 -0
  33. package/dist/bin/capabilities/notebookCapability.js +28 -0
  34. package/dist/bin/capabilities/planningCapability.js +27 -0
  35. package/dist/bin/capabilities/refactoringCapability.js +23 -0
  36. package/dist/bin/capabilities/repoChecksCapability.js +22 -0
  37. package/dist/bin/capabilities/searchCapability.js +22 -0
  38. package/dist/bin/capabilities/skillCapability.js +76 -0
  39. package/dist/bin/capabilities/taskManagementCapability.js +20 -0
  40. package/dist/bin/capabilities/testingCapability.js +23 -0
  41. package/dist/bin/capabilities/toolManifest.js +159 -0
  42. package/dist/bin/capabilities/toolRegistry.js +114 -0
  43. package/dist/bin/capabilities/webCapability.js +20 -0
  44. package/dist/bin/config.js +139 -0
  45. package/dist/bin/contracts/v1/agent.js +7 -0
  46. package/dist/bin/contracts/v1/agentProfileManifest.js +8 -0
  47. package/dist/bin/contracts/v1/agentRules.js +9 -0
  48. package/dist/bin/contracts/v1/toolAccess.js +8 -0
  49. package/dist/bin/core/agent.js +362 -0
  50. package/dist/bin/core/agentProfileManifest.js +187 -0
  51. package/dist/bin/core/agentProfiles.js +34 -0
  52. package/dist/bin/core/agentRulebook.js +135 -0
  53. package/dist/bin/core/agentSchemaLoader.js +233 -0
  54. package/dist/bin/core/contextManager.js +412 -0
  55. package/dist/bin/core/contextWindow.js +122 -0
  56. package/dist/bin/core/customCommands.js +80 -0
  57. package/dist/bin/core/errors/apiKeyErrors.js +114 -0
  58. package/dist/bin/core/errors/errorTypes.js +340 -0
  59. package/dist/bin/core/errors/safetyValidator.js +304 -0
  60. package/dist/bin/core/errors.js +32 -0
  61. package/dist/bin/core/modelDiscovery.js +755 -0
  62. package/dist/bin/core/preferences.js +224 -0
  63. package/dist/bin/core/schemaValidator.js +92 -0
  64. package/dist/bin/core/secretStore.js +199 -0
  65. package/dist/bin/core/sessionStore.js +187 -0
  66. package/dist/bin/core/toolRuntime.js +290 -0
  67. package/dist/bin/core/types.js +1 -0
  68. package/dist/bin/erosolar-optimized.d.ts +12 -0
  69. package/dist/bin/erosolar-optimized.d.ts.map +1 -0
  70. package/dist/bin/erosolar-optimized.js +239 -0
  71. package/dist/bin/erosolar-optimized.js.map +1 -0
  72. package/dist/bin/erosolar.js +14 -0
  73. package/dist/bin/erosolar.js.map +1 -1
  74. package/dist/bin/headless/headlessApp.js +172 -0
  75. package/dist/bin/mcp/config.js +202 -0
  76. package/dist/bin/mcp/stdioClient.js +172 -0
  77. package/dist/bin/mcp/toolBridge.js +104 -0
  78. package/dist/bin/mcp/types.js +1 -0
  79. package/dist/bin/plugins/index.js +113 -0
  80. package/dist/bin/plugins/providers/anthropic/index.js +25 -0
  81. package/dist/bin/plugins/providers/deepseek/index.js +24 -0
  82. package/dist/bin/plugins/providers/google/index.js +26 -0
  83. package/dist/bin/plugins/providers/index.js +19 -0
  84. package/dist/bin/plugins/providers/ollama/index.js +59 -0
  85. package/dist/bin/plugins/providers/openai/index.js +26 -0
  86. package/dist/bin/plugins/providers/xai/index.js +24 -0
  87. package/dist/bin/plugins/tools/agentSpawning/agentSpawningPlugin.js +8 -0
  88. package/dist/bin/plugins/tools/bash/localBashPlugin.js +13 -0
  89. package/dist/bin/plugins/tools/checks/localRepoChecksPlugin.js +13 -0
  90. package/dist/bin/plugins/tools/cloud/cloudPlugin.js +13 -0
  91. package/dist/bin/plugins/tools/codeAnalysis/codeAnalysisPlugin.js +13 -0
  92. package/dist/bin/plugins/tools/codeQuality/codeQualityPlugin.js +13 -0
  93. package/dist/bin/plugins/tools/dependency/dependencyPlugin.js +11 -0
  94. package/dist/bin/plugins/tools/development/devPlugin.js +13 -0
  95. package/dist/bin/plugins/tools/edit/editPlugin.js +14 -0
  96. package/dist/bin/plugins/tools/email/emailPlugin.js +11 -0
  97. package/dist/bin/plugins/tools/enhancedGit/enhancedGitPlugin.js +8 -0
  98. package/dist/bin/plugins/tools/filesystem/localFilesystemPlugin.js +13 -0
  99. package/dist/bin/plugins/tools/glob/globPlugin.js +14 -0
  100. package/dist/bin/plugins/tools/index.js +2 -0
  101. package/dist/bin/plugins/tools/interaction/interactionPlugin.js +11 -0
  102. package/dist/bin/plugins/tools/learn/learnPlugin.js +13 -0
  103. package/dist/bin/plugins/tools/mcp/mcpPlugin.js +8 -0
  104. package/dist/bin/plugins/tools/nodeDefaults.js +56 -0
  105. package/dist/bin/plugins/tools/notebook/notebookPlugin.js +14 -0
  106. package/dist/bin/plugins/tools/planning/planningPlugin.js +14 -0
  107. package/dist/bin/plugins/tools/refactoring/refactoringPlugin.js +11 -0
  108. package/dist/bin/plugins/tools/registry.js +57 -0
  109. package/dist/bin/plugins/tools/search/localSearchPlugin.js +13 -0
  110. package/dist/bin/plugins/tools/skills/skillPlugin.js +8 -0
  111. package/dist/bin/plugins/tools/taskManagement/taskManagementPlugin.js +11 -0
  112. package/dist/bin/plugins/tools/testing/testingPlugin.js +11 -0
  113. package/dist/bin/plugins/tools/web/webPlugin.js +11 -0
  114. package/dist/bin/providers/anthropicProvider.js +329 -0
  115. package/dist/bin/providers/googleProvider.js +203 -0
  116. package/dist/bin/providers/openaiChatCompletionsProvider.js +208 -0
  117. package/dist/bin/providers/openaiResponsesProvider.js +249 -0
  118. package/dist/bin/providers/providerFactory.js +24 -0
  119. package/dist/bin/runtime/agentController.js +321 -0
  120. package/dist/bin/runtime/agentHost.js +153 -0
  121. package/dist/bin/runtime/agentSession.js +195 -0
  122. package/dist/bin/runtime/node.js +10 -0
  123. package/dist/bin/runtime/universal.js +28 -0
  124. package/dist/bin/shell/bracketedPasteManager.js +350 -0
  125. package/dist/bin/shell/fileChangeTracker.js +65 -0
  126. package/dist/bin/shell/interactiveShell.js +2908 -0
  127. package/dist/bin/shell/liveStatus.js +78 -0
  128. package/dist/bin/shell/shellApp.js +290 -0
  129. package/dist/bin/shell/systemPrompt.js +60 -0
  130. package/dist/bin/shell/updateManager.js +108 -0
  131. package/dist/bin/skills/skillRepository.js +236 -0
  132. package/dist/bin/skills/types.js +1 -0
  133. package/dist/bin/subagents/taskRunner.js +269 -0
  134. package/dist/bin/tools/backgroundBashTools.js +211 -0
  135. package/dist/bin/tools/bashTools.js +159 -0
  136. package/dist/bin/tools/cloudTools.js +864 -0
  137. package/dist/bin/tools/codeAnalysisTools.js +641 -0
  138. package/dist/bin/tools/codeQualityTools.js +294 -0
  139. package/dist/bin/tools/dependencyTools.js +282 -0
  140. package/dist/bin/tools/devTools.js +238 -0
  141. package/dist/bin/tools/diffUtils.js +137 -0
  142. package/dist/bin/tools/editTools.js +134 -0
  143. package/dist/bin/tools/emailTools.js +448 -0
  144. package/dist/bin/tools/fileTools.js +282 -0
  145. package/dist/bin/tools/globTools.js +173 -0
  146. package/dist/bin/tools/grepTools.js +332 -0
  147. package/dist/bin/tools/interactionTools.js +170 -0
  148. package/dist/bin/tools/learnTools.js +1818 -0
  149. package/dist/bin/tools/notebookEditTools.js +196 -0
  150. package/dist/bin/tools/planningTools.js +46 -0
  151. package/dist/bin/tools/refactoringTools.js +293 -0
  152. package/dist/bin/tools/repoChecksTools.js +160 -0
  153. package/dist/bin/tools/searchTools.js +206 -0
  154. package/dist/bin/tools/skillTools.js +177 -0
  155. package/dist/bin/tools/taskManagementTools.js +156 -0
  156. package/dist/bin/tools/testingTools.js +232 -0
  157. package/dist/bin/tools/webTools.js +480 -0
  158. package/dist/bin/ui/ShellUIAdapter.js +459 -0
  159. package/dist/bin/ui/UnifiedUIController.js +183 -0
  160. package/dist/bin/ui/animation/AnimationScheduler.js +430 -0
  161. package/dist/bin/ui/codeHighlighter.js +854 -0
  162. package/dist/bin/ui/designSystem.js +121 -0
  163. package/dist/bin/ui/display.js +1222 -0
  164. package/dist/bin/ui/interrupts/InterruptManager.js +437 -0
  165. package/dist/bin/ui/layout.js +139 -0
  166. package/dist/bin/ui/orchestration/StatusOrchestrator.js +403 -0
  167. package/dist/bin/ui/outputMode.js +38 -0
  168. package/dist/bin/ui/persistentPrompt.js +183 -0
  169. package/dist/bin/ui/richText.js +338 -0
  170. package/dist/bin/ui/shortcutsHelp.js +87 -0
  171. package/dist/bin/ui/telemetry/UITelemetry.js +443 -0
  172. package/dist/bin/ui/textHighlighter.js +210 -0
  173. package/dist/bin/ui/theme.js +116 -0
  174. package/dist/bin/ui/toolDisplay.js +423 -0
  175. package/dist/bin/ui/toolDisplayAdapter.js +357 -0
  176. package/dist/bin/workspace.js +106 -0
  177. package/dist/bin/workspace.validator.js +213 -0
  178. package/dist/capabilities/cloudCapability.d.ts +13 -0
  179. package/dist/capabilities/cloudCapability.d.ts.map +1 -0
  180. package/dist/capabilities/cloudCapability.js +38 -0
  181. package/dist/capabilities/cloudCapability.js.map +1 -0
  182. package/dist/capabilities/index.d.ts +1 -0
  183. package/dist/capabilities/index.d.ts.map +1 -1
  184. package/dist/capabilities/index.js +1 -0
  185. package/dist/capabilities/index.js.map +1 -1
  186. package/dist/capabilities/offensiveSecurityCapability.d.ts +26 -0
  187. package/dist/capabilities/offensiveSecurityCapability.d.ts.map +1 -0
  188. package/dist/capabilities/offensiveSecurityCapability.js +58 -0
  189. package/dist/capabilities/offensiveSecurityCapability.js.map +1 -0
  190. package/dist/capabilities/realSecurityCapability.d.ts +26 -0
  191. package/dist/capabilities/realSecurityCapability.d.ts.map +1 -0
  192. package/dist/capabilities/realSecurityCapability.js +53 -0
  193. package/dist/capabilities/realSecurityCapability.js.map +1 -0
  194. package/dist/capabilities/securityCapability.d.ts +32 -0
  195. package/dist/capabilities/securityCapability.d.ts.map +1 -0
  196. package/dist/capabilities/securityCapability.js +57 -0
  197. package/dist/capabilities/securityCapability.js.map +1 -0
  198. package/dist/capabilities/ultimateSecurityCapability.d.ts +42 -0
  199. package/dist/capabilities/ultimateSecurityCapability.d.ts.map +1 -0
  200. package/dist/capabilities/ultimateSecurityCapability.js +96 -0
  201. package/dist/capabilities/ultimateSecurityCapability.js.map +1 -0
  202. package/dist/core/LazyLoader.d.ts +129 -0
  203. package/dist/core/LazyLoader.d.ts.map +1 -0
  204. package/dist/core/LazyLoader.js +240 -0
  205. package/dist/core/LazyLoader.js.map +1 -0
  206. package/dist/core/intelligenceTools.d.ts +19 -0
  207. package/dist/core/intelligenceTools.d.ts.map +1 -0
  208. package/dist/core/intelligenceTools.js +453 -0
  209. package/dist/core/intelligenceTools.js.map +1 -0
  210. package/dist/core/operationalTools.d.ts +19 -0
  211. package/dist/core/operationalTools.d.ts.map +1 -0
  212. package/dist/core/operationalTools.js +467 -0
  213. package/dist/core/operationalTools.js.map +1 -0
  214. package/dist/offensive/core/offensive-engine.d.ts +171 -0
  215. package/dist/offensive/core/offensive-engine.d.ts.map +1 -0
  216. package/dist/offensive/core/offensive-engine.js +345 -0
  217. package/dist/offensive/core/offensive-engine.js.map +1 -0
  218. package/dist/offensive/core/offensive-integration.d.ts +129 -0
  219. package/dist/offensive/core/offensive-integration.d.ts.map +1 -0
  220. package/dist/offensive/core/offensive-integration.js +364 -0
  221. package/dist/offensive/core/offensive-integration.js.map +1 -0
  222. package/dist/offensive/core/offensive-tools.d.ts +55 -0
  223. package/dist/offensive/core/offensive-tools.d.ts.map +1 -0
  224. package/dist/offensive/core/offensive-tools.js +438 -0
  225. package/dist/offensive/core/offensive-tools.js.map +1 -0
  226. package/dist/offensive/offensive-cli.d.ts +48 -0
  227. package/dist/offensive/offensive-cli.d.ts.map +1 -0
  228. package/dist/offensive/offensive-cli.js +233 -0
  229. package/dist/offensive/offensive-cli.js.map +1 -0
  230. package/dist/plugins/index.d.ts +1 -1
  231. package/dist/plugins/index.d.ts.map +1 -1
  232. package/dist/plugins/index.js +2 -0
  233. package/dist/plugins/index.js.map +1 -1
  234. package/dist/plugins/tools/cloud/cloudPlugin.d.ts +3 -0
  235. package/dist/plugins/tools/cloud/cloudPlugin.d.ts.map +1 -0
  236. package/dist/plugins/tools/cloud/cloudPlugin.js +14 -0
  237. package/dist/plugins/tools/cloud/cloudPlugin.js.map +1 -0
  238. package/dist/plugins/tools/nodeDefaults.d.ts.map +1 -1
  239. package/dist/plugins/tools/nodeDefaults.js +2 -0
  240. package/dist/plugins/tools/nodeDefaults.js.map +1 -1
  241. package/dist/security/advanced-persistence-research.d.ts +92 -0
  242. package/dist/security/advanced-persistence-research.d.ts.map +1 -0
  243. package/dist/security/advanced-persistence-research.js +195 -0
  244. package/dist/security/advanced-persistence-research.js.map +1 -0
  245. package/dist/security/apt-simulation-cli.d.ts +57 -0
  246. package/dist/security/apt-simulation-cli.d.ts.map +1 -0
  247. package/dist/security/apt-simulation-cli.js +278 -0
  248. package/dist/security/apt-simulation-cli.js.map +1 -0
  249. package/dist/security/apt-simulation-engine-complete.d.ts +97 -0
  250. package/dist/security/apt-simulation-engine-complete.d.ts.map +1 -0
  251. package/dist/security/apt-simulation-engine-complete.js +441 -0
  252. package/dist/security/apt-simulation-engine-complete.js.map +1 -0
  253. package/dist/security/apt-simulation-engine.d.ts +97 -0
  254. package/dist/security/apt-simulation-engine.d.ts.map +1 -0
  255. package/dist/security/apt-simulation-engine.js +441 -0
  256. package/dist/security/apt-simulation-engine.js.map +1 -0
  257. package/dist/security/assessment/vulnerabilityAssessment.d.ts +104 -0
  258. package/dist/security/assessment/vulnerabilityAssessment.d.ts.map +1 -0
  259. package/dist/security/assessment/vulnerabilityAssessment.js +315 -0
  260. package/dist/security/assessment/vulnerabilityAssessment.js.map +1 -0
  261. package/dist/security/authorization/securityAuthorization.d.ts +88 -0
  262. package/dist/security/authorization/securityAuthorization.d.ts.map +1 -0
  263. package/dist/security/authorization/securityAuthorization.js +172 -0
  264. package/dist/security/authorization/securityAuthorization.js.map +1 -0
  265. package/dist/security/authorization.d.ts +45 -0
  266. package/dist/security/authorization.d.ts.map +1 -0
  267. package/dist/security/authorization.js +128 -0
  268. package/dist/security/authorization.js.map +1 -0
  269. package/dist/security/comprehensive-security-research.d.ts +84 -0
  270. package/dist/security/comprehensive-security-research.d.ts.map +1 -0
  271. package/dist/security/comprehensive-security-research.js +211 -0
  272. package/dist/security/comprehensive-security-research.js.map +1 -0
  273. package/dist/security/offensive/exploitationEngine.d.ts +54 -0
  274. package/dist/security/offensive/exploitationEngine.d.ts.map +1 -0
  275. package/dist/security/offensive/exploitationEngine.js +263 -0
  276. package/dist/security/offensive/exploitationEngine.js.map +1 -0
  277. package/dist/security/persistence-analyzer.d.ts +56 -0
  278. package/dist/security/persistence-analyzer.d.ts.map +1 -0
  279. package/dist/security/persistence-analyzer.js +187 -0
  280. package/dist/security/persistence-analyzer.js.map +1 -0
  281. package/dist/security/persistence-cli.d.ts +36 -0
  282. package/dist/security/persistence-cli.d.ts.map +1 -0
  283. package/dist/security/persistence-cli.js +160 -0
  284. package/dist/security/persistence-cli.js.map +1 -0
  285. package/dist/security/persistence-research.d.ts +100 -0
  286. package/dist/security/persistence-research.d.ts.map +1 -0
  287. package/dist/security/persistence-research.js +372 -0
  288. package/dist/security/persistence-research.js.map +1 -0
  289. package/dist/security/real/networkExploitation.d.ts +92 -0
  290. package/dist/security/real/networkExploitation.d.ts.map +1 -0
  291. package/dist/security/real/networkExploitation.js +316 -0
  292. package/dist/security/real/networkExploitation.js.map +1 -0
  293. package/dist/security/real/persistenceImplementation.d.ts +62 -0
  294. package/dist/security/real/persistenceImplementation.d.ts.map +1 -0
  295. package/dist/security/real/persistenceImplementation.js +323 -0
  296. package/dist/security/real/persistenceImplementation.js.map +1 -0
  297. package/dist/security/real/vulnerabilityScanner.d.ts +73 -0
  298. package/dist/security/real/vulnerabilityScanner.d.ts.map +1 -0
  299. package/dist/security/real/vulnerabilityScanner.js +341 -0
  300. package/dist/security/real/vulnerabilityScanner.js.map +1 -0
  301. package/dist/security/research/persistenceResearch.d.ts +97 -0
  302. package/dist/security/research/persistenceResearch.d.ts.map +1 -0
  303. package/dist/security/research/persistenceResearch.js +282 -0
  304. package/dist/security/research/persistenceResearch.js.map +1 -0
  305. package/dist/security/security-testing-framework.d.ts +120 -0
  306. package/dist/security/security-testing-framework.d.ts.map +1 -0
  307. package/dist/security/security-testing-framework.js +372 -0
  308. package/dist/security/security-testing-framework.js.map +1 -0
  309. package/dist/security/simulation/attackSimulation.d.ts +93 -0
  310. package/dist/security/simulation/attackSimulation.d.ts.map +1 -0
  311. package/dist/security/simulation/attackSimulation.js +341 -0
  312. package/dist/security/simulation/attackSimulation.js.map +1 -0
  313. package/dist/shell/bracketedPasteManager.d.ts +76 -0
  314. package/dist/shell/bracketedPasteManager.d.ts.map +1 -1
  315. package/dist/shell/bracketedPasteManager.js +267 -9
  316. package/dist/shell/bracketedPasteManager.js.map +1 -1
  317. package/dist/shell/interactiveShell.d.ts +34 -1
  318. package/dist/shell/interactiveShell.d.ts.map +1 -1
  319. package/dist/shell/interactiveShell.js +304 -24
  320. package/dist/shell/interactiveShell.js.map +1 -1
  321. package/dist/shell/taskCompletionDetector.d.ts +101 -0
  322. package/dist/shell/taskCompletionDetector.d.ts.map +1 -0
  323. package/dist/shell/taskCompletionDetector.js +343 -0
  324. package/dist/shell/taskCompletionDetector.js.map +1 -0
  325. package/dist/tools/cloudTools.d.ts +57 -0
  326. package/dist/tools/cloudTools.d.ts.map +1 -0
  327. package/dist/tools/cloudTools.js +865 -0
  328. package/dist/tools/cloudTools.js.map +1 -0
  329. package/dist/tools/enhancedSecurityTools.d.ts +19 -0
  330. package/dist/tools/enhancedSecurityTools.d.ts.map +1 -0
  331. package/dist/tools/enhancedSecurityTools.js +215 -0
  332. package/dist/tools/enhancedSecurityTools.js.map +1 -0
  333. package/dist/tools/offensiveSecurityTools.d.ts +16 -0
  334. package/dist/tools/offensiveSecurityTools.d.ts.map +1 -0
  335. package/dist/tools/offensiveSecurityTools.js +285 -0
  336. package/dist/tools/offensiveSecurityTools.js.map +1 -0
  337. package/dist/tools/realSecurityTools.d.ts +18 -0
  338. package/dist/tools/realSecurityTools.d.ts.map +1 -0
  339. package/dist/tools/realSecurityTools.js +468 -0
  340. package/dist/tools/realSecurityTools.js.map +1 -0
  341. package/dist/tools/securityTools.d.ts +20 -0
  342. package/dist/tools/securityTools.d.ts.map +1 -0
  343. package/dist/tools/securityTools.js +449 -0
  344. package/dist/tools/securityTools.js.map +1 -0
  345. package/package.json +27 -12
  346. package/scripts/deploy-security-capabilities.js +178 -0
@@ -0,0 +1,224 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { join } from 'node:path';
4
+ const CONFIG_DIR = join(homedir(), '.erosolar');
5
+ const SETTINGS_PATH = join(CONFIG_DIR, 'settings.json');
6
+ const CURRENT_VERSION = 2;
7
+ export function loadActiveProfilePreference() {
8
+ const payload = readSettingsFile();
9
+ if (!payload?.activeProfile) {
10
+ return null;
11
+ }
12
+ return normalizeProfileNameValue(payload.activeProfile);
13
+ }
14
+ export function saveActiveProfilePreference(profile) {
15
+ const normalized = normalizeProfileNameValue(profile);
16
+ if (!normalized) {
17
+ return;
18
+ }
19
+ const payload = readSettingsFile() ?? { version: CURRENT_VERSION, profiles: {} };
20
+ payload.version = CURRENT_VERSION;
21
+ payload.profiles = payload.profiles ?? {};
22
+ payload.activeProfile = normalized;
23
+ writeSettingsFile(payload);
24
+ }
25
+ export function clearActiveProfilePreference() {
26
+ const payload = readSettingsFile();
27
+ if (!payload?.activeProfile) {
28
+ return;
29
+ }
30
+ payload.version = CURRENT_VERSION;
31
+ payload.profiles = payload.profiles ?? {};
32
+ delete payload.activeProfile;
33
+ writeSettingsFile(payload);
34
+ }
35
+ export function loadModelPreference(profile) {
36
+ const payload = readSettingsFile();
37
+ if (!payload) {
38
+ return null;
39
+ }
40
+ const entry = payload.profiles?.[profile];
41
+ if (!entry || typeof entry !== 'object') {
42
+ return null;
43
+ }
44
+ if (typeof entry.provider !== 'string' || typeof entry.model !== 'string') {
45
+ return null;
46
+ }
47
+ return { ...entry };
48
+ }
49
+ export function saveModelPreference(profile, preference) {
50
+ const payload = readSettingsFile() ?? { version: CURRENT_VERSION, profiles: {} };
51
+ payload.version = CURRENT_VERSION;
52
+ payload.profiles = payload.profiles ?? {};
53
+ payload.profiles[profile] = { ...preference };
54
+ writeSettingsFile(payload);
55
+ }
56
+ export function loadToolSettings() {
57
+ const payload = readSettingsFile();
58
+ if (!payload?.tools) {
59
+ return null;
60
+ }
61
+ const enabledTools = normalizeToolIds(payload.tools.enabledTools);
62
+ return { enabledTools };
63
+ }
64
+ export function saveToolSettings(settings) {
65
+ const payload = readSettingsFile() ?? { version: CURRENT_VERSION, profiles: {} };
66
+ payload.version = CURRENT_VERSION;
67
+ payload.profiles = payload.profiles ?? {};
68
+ payload.tools = {
69
+ enabledTools: normalizeToolIds(settings.enabledTools),
70
+ };
71
+ writeSettingsFile(payload);
72
+ }
73
+ export function clearToolSettings() {
74
+ const payload = readSettingsFile();
75
+ if (!payload) {
76
+ return;
77
+ }
78
+ payload.version = CURRENT_VERSION;
79
+ payload.profiles = payload.profiles ?? {};
80
+ if (payload.tools) {
81
+ delete payload.tools;
82
+ }
83
+ writeSettingsFile(payload);
84
+ }
85
+ export function loadSessionPreferences() {
86
+ const payload = readSettingsFile();
87
+ const section = payload?.session;
88
+ return {
89
+ autosave: typeof section?.autosave === 'boolean' ? section.autosave : true,
90
+ autoResume: typeof section?.autoResume === 'boolean' ? section.autoResume : true,
91
+ lastSessionId: typeof section?.lastSessionId === 'string' && section.lastSessionId.trim()
92
+ ? section.lastSessionId.trim()
93
+ : null,
94
+ thinkingMode: parseThinkingMode(section?.thinkingMode),
95
+ };
96
+ }
97
+ export function saveSessionPreferences(preferences) {
98
+ const payload = readSettingsFile() ?? { version: CURRENT_VERSION, profiles: {} };
99
+ payload.version = CURRENT_VERSION;
100
+ payload.profiles = payload.profiles ?? {};
101
+ const section = payload.session ?? {};
102
+ if (typeof preferences.autosave === 'boolean') {
103
+ section.autosave = preferences.autosave;
104
+ }
105
+ if (typeof preferences.autoResume === 'boolean') {
106
+ section.autoResume = preferences.autoResume;
107
+ }
108
+ if ('lastSessionId' in preferences) {
109
+ section.lastSessionId = preferences.lastSessionId ?? undefined;
110
+ }
111
+ if (preferences.thinkingMode) {
112
+ section.thinkingMode = preferences.thinkingMode;
113
+ }
114
+ payload.session = section;
115
+ writeSettingsFile(payload);
116
+ }
117
+ function readSettingsFile() {
118
+ try {
119
+ if (!existsSync(SETTINGS_PATH)) {
120
+ return null;
121
+ }
122
+ const raw = readFileSync(SETTINGS_PATH, 'utf8');
123
+ const parsed = JSON.parse(raw);
124
+ if (!parsed || typeof parsed !== 'object') {
125
+ return null;
126
+ }
127
+ const profiles = typeof parsed.profiles === 'object' && parsed.profiles !== null ? parsed.profiles : {};
128
+ const payload = {
129
+ version: typeof parsed.version === 'number' ? parsed.version : CURRENT_VERSION,
130
+ profiles,
131
+ };
132
+ const tools = parseToolSettings(parsed.tools);
133
+ if (tools) {
134
+ payload.tools = tools;
135
+ }
136
+ const session = parseSessionPreferences(parsed.session);
137
+ if (session) {
138
+ payload.session = session;
139
+ }
140
+ const rawProfile = typeof parsed.activeProfile === 'string' && parsed.activeProfile.trim()
141
+ ? parsed.activeProfile.trim()
142
+ : undefined;
143
+ if (rawProfile) {
144
+ payload.activeProfile = rawProfile;
145
+ }
146
+ return payload;
147
+ }
148
+ catch {
149
+ return null;
150
+ }
151
+ }
152
+ function writeSettingsFile(payload) {
153
+ try {
154
+ mkdirSync(CONFIG_DIR, { recursive: true });
155
+ writeFileSync(SETTINGS_PATH, JSON.stringify(payload, null, 2));
156
+ }
157
+ catch {
158
+ }
159
+ }
160
+ function parseToolSettings(value) {
161
+ if (!value || typeof value !== 'object') {
162
+ return undefined;
163
+ }
164
+ const record = value;
165
+ if (!Array.isArray(record.enabledTools)) {
166
+ return { enabledTools: [] };
167
+ }
168
+ return { enabledTools: normalizeToolIds(record.enabledTools) };
169
+ }
170
+ function parseSessionPreferences(value) {
171
+ if (!value || typeof value !== 'object') {
172
+ return undefined;
173
+ }
174
+ const record = value;
175
+ const section = {};
176
+ if (typeof record.autosave === 'boolean') {
177
+ section.autosave = record.autosave;
178
+ }
179
+ if (typeof record.autoResume === 'boolean') {
180
+ section.autoResume = record.autoResume;
181
+ }
182
+ if (typeof record.lastSessionId === 'string' && record.lastSessionId.trim()) {
183
+ section.lastSessionId = record.lastSessionId.trim();
184
+ }
185
+ if (record.thinkingMode) {
186
+ section.thinkingMode = parseThinkingMode(record.thinkingMode);
187
+ }
188
+ return section;
189
+ }
190
+ function parseThinkingMode(value) {
191
+ if (value === 'concise' || value === 'extended' || value === 'balanced') {
192
+ return value;
193
+ }
194
+ return 'balanced';
195
+ }
196
+ function normalizeToolIds(ids) {
197
+ if (!Array.isArray(ids)) {
198
+ return [];
199
+ }
200
+ const seen = new Set();
201
+ const result = [];
202
+ for (const entry of ids) {
203
+ if (typeof entry !== 'string') {
204
+ continue;
205
+ }
206
+ const id = entry.trim();
207
+ if (!id || seen.has(id)) {
208
+ continue;
209
+ }
210
+ seen.add(id);
211
+ result.push(id);
212
+ }
213
+ return result;
214
+ }
215
+ function normalizeProfileNameValue(value) {
216
+ if (typeof value !== 'string') {
217
+ return null;
218
+ }
219
+ const trimmed = value.trim();
220
+ if (!trimmed) {
221
+ return null;
222
+ }
223
+ return trimmed;
224
+ }
@@ -0,0 +1,92 @@
1
+ export class ToolArgumentValidationError extends Error {
2
+ constructor(toolName, issues) {
3
+ super(formatMessage(toolName, issues));
4
+ this.name = 'ToolArgumentValidationError';
5
+ }
6
+ }
7
+ export function validateToolArguments(toolName, schema, args) {
8
+ if (!schema || schema.type !== 'object') {
9
+ return;
10
+ }
11
+ const errors = [];
12
+ const properties = schema.properties ?? {};
13
+ const required = Array.isArray(schema.required) ? schema.required : [];
14
+ for (const property of required) {
15
+ if (!hasArgument(args, property)) {
16
+ errors.push(`Missing required property "${property}".`);
17
+ }
18
+ }
19
+ for (const [key, value] of Object.entries(args)) {
20
+ const definition = properties[key];
21
+ if (!definition) {
22
+ if (schema.additionalProperties === false) {
23
+ errors.push(`Property "${key}" is not allowed.`);
24
+ }
25
+ continue;
26
+ }
27
+ validateSchemaProperty(definition, value, key, errors);
28
+ }
29
+ if (errors.length) {
30
+ throw new ToolArgumentValidationError(toolName, errors);
31
+ }
32
+ }
33
+ function validateSchemaProperty(definition, value, path, errors) {
34
+ switch (definition.type) {
35
+ case 'string': {
36
+ if (typeof value !== 'string') {
37
+ errors.push(`Argument "${path}" must be a string.`);
38
+ return;
39
+ }
40
+ if (definition.enum && !definition.enum.includes(value)) {
41
+ errors.push(`Argument "${path}" must be one of: ${definition.enum.map((entry) => `"${entry}"`).join(', ')}.`);
42
+ }
43
+ if (typeof definition.minLength === 'number' && value.length < definition.minLength) {
44
+ errors.push(`Argument "${path}" must be at least ${definition.minLength} character${definition.minLength === 1 ? '' : 's'} long.`);
45
+ }
46
+ return;
47
+ }
48
+ case 'number': {
49
+ if (typeof value !== 'number' || Number.isNaN(value)) {
50
+ errors.push(`Argument "${path}" must be a number.`);
51
+ }
52
+ return;
53
+ }
54
+ case 'boolean': {
55
+ if (typeof value !== 'boolean') {
56
+ errors.push(`Argument "${path}" must be a boolean.`);
57
+ }
58
+ return;
59
+ }
60
+ case 'array': {
61
+ if (!Array.isArray(value)) {
62
+ errors.push(`Argument "${path}" must be an array.`);
63
+ return;
64
+ }
65
+ validateArrayItems(definition, value, path, errors);
66
+ return;
67
+ }
68
+ default:
69
+ return;
70
+ }
71
+ }
72
+ function validateArrayItems(definition, value, path, errors) {
73
+ const itemSchema = definition.items;
74
+ if (!itemSchema) {
75
+ return;
76
+ }
77
+ for (let index = 0; index < value.length; index += 1) {
78
+ const entry = value[index];
79
+ validateSchemaProperty(itemSchema, entry, `${path}[${index}]`, errors);
80
+ }
81
+ }
82
+ function hasArgument(args, key) {
83
+ if (!Object.hasOwn(args, key)) {
84
+ return false;
85
+ }
86
+ const value = args[key];
87
+ return value !== undefined && value !== null;
88
+ }
89
+ function formatMessage(toolName, issues) {
90
+ const detail = issues.join(' ');
91
+ return `Invalid arguments for "${toolName}": ${detail}`;
92
+ }
@@ -0,0 +1,199 @@
1
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { homedir } from 'node:os';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ const SECRET_DEFINITIONS = [
5
+ {
6
+ id: 'OPENAI_API_KEY',
7
+ label: 'OpenAI API Key',
8
+ description: 'Required to run OpenAI GPT and Erosolar Code models.',
9
+ envVar: 'OPENAI_API_KEY',
10
+ providers: ['openai'],
11
+ },
12
+ {
13
+ id: 'ANTHROPIC_API_KEY',
14
+ label: 'Anthropic API Key',
15
+ description: 'Required to run Anthropic Sonnet, Opus, or Haiku models.',
16
+ envVar: 'ANTHROPIC_API_KEY',
17
+ providers: ['anthropic'],
18
+ },
19
+ {
20
+ id: 'DEEPSEEK_API_KEY',
21
+ label: 'DeepSeek API Key',
22
+ description: 'Required to run DeepSeek Reasoner or Chat models.',
23
+ envVar: 'DEEPSEEK_API_KEY',
24
+ providers: ['deepseek'],
25
+ },
26
+ {
27
+ id: 'XAI_API_KEY',
28
+ label: 'xAI API Key',
29
+ description: 'Required to run Grok models from xAI.',
30
+ envVar: 'XAI_API_KEY',
31
+ providers: ['xai'],
32
+ },
33
+ {
34
+ id: 'GEMINI_API_KEY',
35
+ label: 'Google Gemini API Key',
36
+ description: 'Required to run Gemini 2.5 Pro or Flash models.',
37
+ envVar: 'GEMINI_API_KEY',
38
+ providers: ['google'],
39
+ },
40
+ {
41
+ id: 'BRAVE_SEARCH_API_KEY',
42
+ label: 'Brave Search API Key',
43
+ description: 'Optional: unlock WebSearch using the Brave Search API.',
44
+ envVar: 'BRAVE_SEARCH_API_KEY',
45
+ providers: [],
46
+ },
47
+ {
48
+ id: 'SERPAPI_API_KEY',
49
+ label: 'SerpAPI Key',
50
+ description: 'Optional: fallback WebSearch provider via SerpAPI.',
51
+ envVar: 'SERPAPI_API_KEY',
52
+ providers: [],
53
+ },
54
+ {
55
+ id: 'TAVILY_API_KEY',
56
+ label: 'Tavily API Key',
57
+ description: 'Recommended: Primary WebSearch and WebExtract provider. Get yours at https://tavily.com',
58
+ envVar: 'TAVILY_API_KEY',
59
+ providers: [],
60
+ },
61
+ {
62
+ id: 'SMTP_USER',
63
+ label: 'Email Address',
64
+ description: 'Your email address for sending emails (e.g., you@gmail.com).',
65
+ envVar: 'SMTP_USER',
66
+ providers: [],
67
+ },
68
+ {
69
+ id: 'SMTP_PASSWORD',
70
+ label: 'Email App Password',
71
+ description: 'App password for your email (NOT your regular password). For Gmail: https://myaccount.google.com/apppasswords',
72
+ envVar: 'SMTP_PASSWORD',
73
+ providers: [],
74
+ },
75
+ {
76
+ id: 'SMTP_PROVIDER',
77
+ label: 'Email Provider',
78
+ description: 'Email provider: gmail, outlook, yahoo, icloud, zoho (default: gmail).',
79
+ envVar: 'SMTP_PROVIDER',
80
+ providers: [],
81
+ },
82
+ {
83
+ id: 'SMTP_FROM_NAME',
84
+ label: 'Email Display Name',
85
+ description: 'Optional: Display name shown in sent emails (e.g., "John Doe").',
86
+ envVar: 'SMTP_FROM_NAME',
87
+ providers: [],
88
+ },
89
+ {
90
+ id: 'SMTP_HOST',
91
+ label: 'Custom SMTP Host',
92
+ description: 'Optional: Custom SMTP server hostname (only for non-standard providers).',
93
+ envVar: 'SMTP_HOST',
94
+ providers: [],
95
+ },
96
+ {
97
+ id: 'SMTP_PORT',
98
+ label: 'Custom SMTP Port',
99
+ description: 'Optional: Custom SMTP port (only for non-standard providers, default: 587).',
100
+ envVar: 'SMTP_PORT',
101
+ providers: [],
102
+ },
103
+ ];
104
+ const envCodexHome = process.env['CODEX_HOME'];
105
+ const SECRET_DIR = envCodexHome ? resolve(envCodexHome) : join(homedir(), '.codex');
106
+ const SECRET_FILE = join(SECRET_DIR, 'secrets.json');
107
+ export class MissingSecretError extends Error {
108
+ constructor(secret) {
109
+ super(`${secret.label} is not configured.`);
110
+ this.secret = secret;
111
+ this.name = 'MissingSecretError';
112
+ }
113
+ }
114
+ export function listSecretDefinitions() {
115
+ return [...SECRET_DEFINITIONS];
116
+ }
117
+ export function getSecretValue(id) {
118
+ const envValue = sanitize(process.env[id]);
119
+ if (envValue) {
120
+ return envValue;
121
+ }
122
+ const store = readSecretStore();
123
+ const storedValue = sanitize(store[id]);
124
+ if (!storedValue) {
125
+ return null;
126
+ }
127
+ process.env[id] = storedValue;
128
+ return storedValue;
129
+ }
130
+ export function setSecretValue(id, rawValue) {
131
+ const value = sanitize(rawValue);
132
+ if (!value) {
133
+ throw new Error('Secret value cannot be blank.');
134
+ }
135
+ const store = readSecretStore();
136
+ store[id] = value;
137
+ writeSecretStore(store);
138
+ process.env[id] = value;
139
+ }
140
+ export function maskSecret(value) {
141
+ if (!value) {
142
+ return '';
143
+ }
144
+ if (value.length <= 4) {
145
+ return '*'.repeat(value.length);
146
+ }
147
+ const suffix = value.slice(-4);
148
+ const prefix = '*'.repeat(Math.max(0, value.length - 4));
149
+ return `${prefix}${suffix}`;
150
+ }
151
+ export function ensureSecretForProvider(provider) {
152
+ const definition = findDefinitionForProvider(provider);
153
+ const value = getSecretValue(definition.id);
154
+ if (!value) {
155
+ throw new MissingSecretError(definition);
156
+ }
157
+ process.env[definition.envVar] = value;
158
+ return value;
159
+ }
160
+ export function getSecretDefinitionForProvider(provider) {
161
+ return SECRET_DEFINITIONS.find((entry) => entry.providers.includes(provider)) ?? null;
162
+ }
163
+ function readSecretStore() {
164
+ if (!existsSync(SECRET_FILE)) {
165
+ return {};
166
+ }
167
+ try {
168
+ const content = readFileSync(SECRET_FILE, 'utf8');
169
+ const parsed = JSON.parse(content);
170
+ if (parsed && typeof parsed === 'object') {
171
+ return parsed;
172
+ }
173
+ }
174
+ catch {
175
+ return {};
176
+ }
177
+ return {};
178
+ }
179
+ function writeSecretStore(store) {
180
+ const directory = dirname(SECRET_FILE);
181
+ mkdirSync(directory, { recursive: true });
182
+ const payload = JSON.stringify(store, null, 2);
183
+ writeFileSync(SECRET_FILE, `${payload}
184
+ `);
185
+ }
186
+ function findDefinitionForProvider(provider) {
187
+ const definition = getSecretDefinitionForProvider(provider);
188
+ if (!definition) {
189
+ throw new Error(`No secret configuration for provider "${provider}".`);
190
+ }
191
+ return definition;
192
+ }
193
+ function sanitize(value) {
194
+ if (typeof value !== 'string') {
195
+ return null;
196
+ }
197
+ const trimmed = value.trim();
198
+ return trimmed.length ? trimmed : null;
199
+ }
@@ -0,0 +1,187 @@
1
+ import { randomUUID } from 'node:crypto';
2
+ import { mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync } from 'node:fs';
3
+ import { join } from 'node:path';
4
+ import { homedir } from 'node:os';
5
+ const dataRoot = process.env['EROSOLAR_DATA_DIR']?.trim() || join(homedir(), '.erosolar');
6
+ const sessionsDir = join(dataRoot, 'sessions');
7
+ const indexPath = join(sessionsDir, 'index.json');
8
+ export function listSessions(profile) {
9
+ const index = readIndex();
10
+ const entries = Object.values(index.entries);
11
+ const filtered = profile ? entries.filter((entry) => entry.profile === profile) : entries;
12
+ return filtered.sort((a, b) => {
13
+ const aTime = Date.parse(a.updatedAt ?? '') || 0;
14
+ const bTime = Date.parse(b.updatedAt ?? '') || 0;
15
+ return bTime - aTime;
16
+ });
17
+ }
18
+ export function saveSessionSnapshot(options) {
19
+ ensureDirectory();
20
+ if (!Array.isArray(options.messages)) {
21
+ throw new Error('Session snapshots must include the entire message history array.');
22
+ }
23
+ const index = readIndex();
24
+ const now = new Date().toISOString();
25
+ const existingId = options.id ?? null;
26
+ const summaryId = existingId && index.entries[existingId] ? existingId : randomUUID();
27
+ const previous = index.entries[summaryId];
28
+ const summary = {
29
+ id: summaryId,
30
+ title: sanitizeTitle(options.title) ?? previous?.title ?? buildDefaultTitle(options.messages),
31
+ profile: options.profile,
32
+ provider: options.provider,
33
+ model: options.model,
34
+ workspaceRoot: options.workspaceRoot ?? previous?.workspaceRoot ?? undefined,
35
+ createdAt: previous?.createdAt ?? now,
36
+ updatedAt: now,
37
+ messageCount: options.messages.length,
38
+ };
39
+ const payload = {
40
+ ...summary,
41
+ messages: options.messages,
42
+ };
43
+ writeFileSync(getSessionPath(summaryId), JSON.stringify(payload, null, 2), 'utf8');
44
+ index.entries[summaryId] = summary;
45
+ writeIndex(index);
46
+ return summary;
47
+ }
48
+ export function loadSessionById(id) {
49
+ if (!id) {
50
+ return null;
51
+ }
52
+ try {
53
+ const raw = readFileSync(getSessionPath(id), 'utf8');
54
+ const parsed = JSON.parse(raw);
55
+ return parsed;
56
+ }
57
+ catch {
58
+ return null;
59
+ }
60
+ }
61
+ export function deleteSession(id) {
62
+ if (!id) {
63
+ return false;
64
+ }
65
+ const index = readIndex();
66
+ if (!index.entries[id]) {
67
+ return false;
68
+ }
69
+ try {
70
+ rmSync(getSessionPath(id), { force: true });
71
+ }
72
+ catch {
73
+ // ignore
74
+ }
75
+ delete index.entries[id];
76
+ writeIndex(index);
77
+ return true;
78
+ }
79
+ export function saveAutosaveSnapshot(profile, options) {
80
+ ensureDirectory();
81
+ const payload = {
82
+ id: `autosave-${profile}`,
83
+ profile,
84
+ provider: options.provider,
85
+ model: options.model,
86
+ workspaceRoot: options.workspaceRoot ?? undefined,
87
+ createdAt: new Date().toISOString(),
88
+ updatedAt: new Date().toISOString(),
89
+ title: sanitizeTitle(options.title) ?? buildDefaultTitle(options.messages),
90
+ messageCount: options.messages.length,
91
+ messages: options.messages,
92
+ };
93
+ writeFileSync(getAutosavePath(profile), JSON.stringify(payload, null, 2), 'utf8');
94
+ }
95
+ export function loadAutosaveSnapshot(profile) {
96
+ try {
97
+ const raw = readFileSync(getAutosavePath(profile), 'utf8');
98
+ return JSON.parse(raw);
99
+ }
100
+ catch {
101
+ return null;
102
+ }
103
+ }
104
+ export function clearAutosaveSnapshot(profile) {
105
+ try {
106
+ rmSync(getAutosavePath(profile), { force: true });
107
+ }
108
+ catch {
109
+ // ignore
110
+ }
111
+ }
112
+ function readIndex() {
113
+ ensureDirectory();
114
+ try {
115
+ const raw = readFileSync(indexPath, 'utf8');
116
+ const parsed = JSON.parse(raw);
117
+ if (!parsed || typeof parsed !== 'object' || typeof parsed.entries !== 'object') {
118
+ return { entries: {} };
119
+ }
120
+ return { entries: { ...parsed.entries } };
121
+ }
122
+ catch {
123
+ return { entries: {} };
124
+ }
125
+ }
126
+ function writeIndex(index) {
127
+ ensureDirectory();
128
+ writeFileSync(indexPath, JSON.stringify(index, null, 2), 'utf8');
129
+ }
130
+ function ensureDirectory() {
131
+ mkdirSync(sessionsDir, { recursive: true });
132
+ }
133
+ function getSessionPath(id) {
134
+ return join(sessionsDir, `${id}.json`);
135
+ }
136
+ function getAutosavePath(profile) {
137
+ return join(sessionsDir, `${profile}-autosave.json`);
138
+ }
139
+ function sanitizeTitle(value) {
140
+ if (typeof value !== 'string') {
141
+ return null;
142
+ }
143
+ const trimmed = value.trim();
144
+ if (!trimmed) {
145
+ return null;
146
+ }
147
+ return trimmed.slice(0, 160);
148
+ }
149
+ function buildDefaultTitle(messages) {
150
+ for (const message of messages) {
151
+ if (message.role !== 'user') {
152
+ continue;
153
+ }
154
+ const condensed = message.content.trim().replace(/\s+/g, ' ');
155
+ if (condensed) {
156
+ return condensed.slice(0, 160);
157
+ }
158
+ }
159
+ return `Session ${new Date().toLocaleString()}`;
160
+ }
161
+ function pruneOrphans() {
162
+ try {
163
+ ensureDirectory();
164
+ const index = readIndex();
165
+ const known = new Set(Object.keys(index.entries));
166
+ for (const file of readdirSync(sessionsDir)) {
167
+ if (!file.endsWith('.json')) {
168
+ continue;
169
+ }
170
+ if (file === 'index.json' || file.includes('-autosave')) {
171
+ continue;
172
+ }
173
+ const id = file.slice(0, -5);
174
+ if (!known.has(id)) {
175
+ const candidate = join(sessionsDir, file);
176
+ const stats = statSync(candidate);
177
+ if (stats.isFile()) {
178
+ rmSync(candidate, { force: true });
179
+ }
180
+ }
181
+ }
182
+ }
183
+ catch {
184
+ // best-effort cleanup
185
+ }
186
+ }
187
+ pruneOrphans();