@nexus-ai-nexoralabs/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (411) hide show
  1. package/.env.example +16 -0
  2. package/LICENSE +21 -0
  3. package/README.md +106 -0
  4. package/dist/api/index.d.ts +81 -0
  5. package/dist/api/index.d.ts.map +1 -0
  6. package/dist/api/index.js +224 -0
  7. package/dist/api/index.js.map +1 -0
  8. package/dist/chat/chatService.d.ts +49 -0
  9. package/dist/chat/chatService.d.ts.map +1 -0
  10. package/dist/chat/chatService.js +163 -0
  11. package/dist/chat/chatService.js.map +1 -0
  12. package/dist/chat/contextBuilder.d.ts +19 -0
  13. package/dist/chat/contextBuilder.d.ts.map +1 -0
  14. package/dist/chat/contextBuilder.js +43 -0
  15. package/dist/chat/contextBuilder.js.map +1 -0
  16. package/dist/chat/conversationService.d.ts +25 -0
  17. package/dist/chat/conversationService.d.ts.map +1 -0
  18. package/dist/chat/conversationService.js +55 -0
  19. package/dist/chat/conversationService.js.map +1 -0
  20. package/dist/chat/index.d.ts +6 -0
  21. package/dist/chat/index.d.ts.map +1 -0
  22. package/dist/chat/index.js +6 -0
  23. package/dist/chat/index.js.map +1 -0
  24. package/dist/chat/messageService.d.ts +18 -0
  25. package/dist/chat/messageService.d.ts.map +1 -0
  26. package/dist/chat/messageService.js +26 -0
  27. package/dist/chat/messageService.js.map +1 -0
  28. package/dist/chat/promptTemplates.d.ts +19 -0
  29. package/dist/chat/promptTemplates.d.ts.map +1 -0
  30. package/dist/chat/promptTemplates.js +32 -0
  31. package/dist/chat/promptTemplates.js.map +1 -0
  32. package/dist/cli/agentRunner.d.ts +126 -0
  33. package/dist/cli/agentRunner.d.ts.map +1 -0
  34. package/dist/cli/agentRunner.js +892 -0
  35. package/dist/cli/agentRunner.js.map +1 -0
  36. package/dist/cli/bin.d.ts +14 -0
  37. package/dist/cli/bin.d.ts.map +1 -0
  38. package/dist/cli/bin.js +20 -0
  39. package/dist/cli/bin.js.map +1 -0
  40. package/dist/cli/index.d.ts +3 -0
  41. package/dist/cli/index.d.ts.map +1 -0
  42. package/dist/cli/index.js +2 -0
  43. package/dist/cli/index.js.map +1 -0
  44. package/dist/cli/inputEngine.d.ts +76 -0
  45. package/dist/cli/inputEngine.d.ts.map +1 -0
  46. package/dist/cli/inputEngine.js +281 -0
  47. package/dist/cli/inputEngine.js.map +1 -0
  48. package/dist/cli/main.d.ts +9 -0
  49. package/dist/cli/main.d.ts.map +1 -0
  50. package/dist/cli/main.js +144 -0
  51. package/dist/cli/main.js.map +1 -0
  52. package/dist/cli/uiFormatters.d.ts +108 -0
  53. package/dist/cli/uiFormatters.d.ts.map +1 -0
  54. package/dist/cli/uiFormatters.js +925 -0
  55. package/dist/cli/uiFormatters.js.map +1 -0
  56. package/dist/common/logger.d.ts +13 -0
  57. package/dist/common/logger.d.ts.map +1 -0
  58. package/dist/common/logger.js +43 -0
  59. package/dist/common/logger.js.map +1 -0
  60. package/dist/config/firstRunHealthCheck.d.ts +50 -0
  61. package/dist/config/firstRunHealthCheck.d.ts.map +1 -0
  62. package/dist/config/firstRunHealthCheck.js +196 -0
  63. package/dist/config/firstRunHealthCheck.js.map +1 -0
  64. package/dist/config/firstRunService.d.ts +53 -0
  65. package/dist/config/firstRunService.d.ts.map +1 -0
  66. package/dist/config/firstRunService.js +93 -0
  67. package/dist/config/firstRunService.js.map +1 -0
  68. package/dist/config/index.d.ts +30 -0
  69. package/dist/config/index.d.ts.map +1 -0
  70. package/dist/config/index.js +65 -0
  71. package/dist/config/index.js.map +1 -0
  72. package/dist/config/productionPaths.d.ts +34 -0
  73. package/dist/config/productionPaths.d.ts.map +1 -0
  74. package/dist/config/productionPaths.js +95 -0
  75. package/dist/config/productionPaths.js.map +1 -0
  76. package/dist/config/workspaceService.d.ts +42 -0
  77. package/dist/config/workspaceService.d.ts.map +1 -0
  78. package/dist/config/workspaceService.js +218 -0
  79. package/dist/config/workspaceService.js.map +1 -0
  80. package/dist/desktop/appWindow.d.ts +21 -0
  81. package/dist/desktop/appWindow.d.ts.map +1 -0
  82. package/dist/desktop/appWindow.js +77 -0
  83. package/dist/desktop/appWindow.js.map +1 -0
  84. package/dist/desktop/main.d.ts +14 -0
  85. package/dist/desktop/main.d.ts.map +1 -0
  86. package/dist/desktop/main.js +90 -0
  87. package/dist/desktop/main.js.map +1 -0
  88. package/dist/desktop/preload.d.ts +14 -0
  89. package/dist/desktop/preload.d.ts.map +1 -0
  90. package/dist/desktop/preload.js +20 -0
  91. package/dist/desktop/preload.js.map +1 -0
  92. package/dist/intelligence/index.d.ts +33 -0
  93. package/dist/intelligence/index.d.ts.map +1 -0
  94. package/dist/intelligence/index.js +82 -0
  95. package/dist/intelligence/index.js.map +1 -0
  96. package/dist/intelligence/modelGateway.d.ts +35 -0
  97. package/dist/intelligence/modelGateway.d.ts.map +1 -0
  98. package/dist/intelligence/modelGateway.js +123 -0
  99. package/dist/intelligence/modelGateway.js.map +1 -0
  100. package/dist/intelligence/modelRegistry.d.ts +17 -0
  101. package/dist/intelligence/modelRegistry.d.ts.map +1 -0
  102. package/dist/intelligence/modelRegistry.js +87 -0
  103. package/dist/intelligence/modelRegistry.js.map +1 -0
  104. package/dist/intelligence/modelRouter.d.ts +76 -0
  105. package/dist/intelligence/modelRouter.d.ts.map +1 -0
  106. package/dist/intelligence/modelRouter.js +256 -0
  107. package/dist/intelligence/modelRouter.js.map +1 -0
  108. package/dist/intelligence/ollamaAdapter.d.ts +49 -0
  109. package/dist/intelligence/ollamaAdapter.d.ts.map +1 -0
  110. package/dist/intelligence/ollamaAdapter.js +197 -0
  111. package/dist/intelligence/ollamaAdapter.js.map +1 -0
  112. package/dist/intelligence/prototype/runPrototype.d.ts +14 -0
  113. package/dist/intelligence/prototype/runPrototype.d.ts.map +1 -0
  114. package/dist/intelligence/prototype/runPrototype.js +87 -0
  115. package/dist/intelligence/prototype/runPrototype.js.map +1 -0
  116. package/dist/intelligence/providers/embeddedInferenceProvider.d.ts +29 -0
  117. package/dist/intelligence/providers/embeddedInferenceProvider.d.ts.map +1 -0
  118. package/dist/intelligence/providers/embeddedInferenceProvider.js +162 -0
  119. package/dist/intelligence/providers/embeddedInferenceProvider.js.map +1 -0
  120. package/dist/intelligence/providers/index.d.ts +4 -0
  121. package/dist/intelligence/providers/index.d.ts.map +1 -0
  122. package/dist/intelligence/providers/index.js +4 -0
  123. package/dist/intelligence/providers/index.js.map +1 -0
  124. package/dist/intelligence/providers/inferenceProvider.d.ts +98 -0
  125. package/dist/intelligence/providers/inferenceProvider.d.ts.map +1 -0
  126. package/dist/intelligence/providers/inferenceProvider.js +9 -0
  127. package/dist/intelligence/providers/inferenceProvider.js.map +1 -0
  128. package/dist/intelligence/providers/ollamaInferenceProvider.d.ts +17 -0
  129. package/dist/intelligence/providers/ollamaInferenceProvider.d.ts.map +1 -0
  130. package/dist/intelligence/providers/ollamaInferenceProvider.js +103 -0
  131. package/dist/intelligence/providers/ollamaInferenceProvider.js.map +1 -0
  132. package/dist/intelligence/provisioning/hardwareDetector.d.ts +5 -0
  133. package/dist/intelligence/provisioning/hardwareDetector.d.ts.map +1 -0
  134. package/dist/intelligence/provisioning/hardwareDetector.js +48 -0
  135. package/dist/intelligence/provisioning/hardwareDetector.js.map +1 -0
  136. package/dist/intelligence/provisioning/index.d.ts +12 -0
  137. package/dist/intelligence/provisioning/index.d.ts.map +1 -0
  138. package/dist/intelligence/provisioning/index.js +12 -0
  139. package/dist/intelligence/provisioning/index.js.map +1 -0
  140. package/dist/intelligence/provisioning/modelDownloader.d.ts +22 -0
  141. package/dist/intelligence/provisioning/modelDownloader.d.ts.map +1 -0
  142. package/dist/intelligence/provisioning/modelDownloader.js +134 -0
  143. package/dist/intelligence/provisioning/modelDownloader.js.map +1 -0
  144. package/dist/intelligence/provisioning/modelManifest.d.ts +10 -0
  145. package/dist/intelligence/provisioning/modelManifest.d.ts.map +1 -0
  146. package/dist/intelligence/provisioning/modelManifest.js +72 -0
  147. package/dist/intelligence/provisioning/modelManifest.js.map +1 -0
  148. package/dist/intelligence/provisioning/modelSelector.d.ts +14 -0
  149. package/dist/intelligence/provisioning/modelSelector.d.ts.map +1 -0
  150. package/dist/intelligence/provisioning/modelSelector.js +40 -0
  151. package/dist/intelligence/provisioning/modelSelector.js.map +1 -0
  152. package/dist/intelligence/provisioning/modelStorage.d.ts +12 -0
  153. package/dist/intelligence/provisioning/modelStorage.d.ts.map +1 -0
  154. package/dist/intelligence/provisioning/modelStorage.js +66 -0
  155. package/dist/intelligence/provisioning/modelStorage.js.map +1 -0
  156. package/dist/intelligence/provisioning/modelUpdater.d.ts +29 -0
  157. package/dist/intelligence/provisioning/modelUpdater.d.ts.map +1 -0
  158. package/dist/intelligence/provisioning/modelUpdater.js +89 -0
  159. package/dist/intelligence/provisioning/modelUpdater.js.map +1 -0
  160. package/dist/intelligence/provisioning/modelVerifier.d.ts +16 -0
  161. package/dist/intelligence/provisioning/modelVerifier.d.ts.map +1 -0
  162. package/dist/intelligence/provisioning/modelVerifier.js +108 -0
  163. package/dist/intelligence/provisioning/modelVerifier.js.map +1 -0
  164. package/dist/intelligence/provisioning/nativeRuntime.d.ts +18 -0
  165. package/dist/intelligence/provisioning/nativeRuntime.d.ts.map +1 -0
  166. package/dist/intelligence/provisioning/nativeRuntime.js +78 -0
  167. package/dist/intelligence/provisioning/nativeRuntime.js.map +1 -0
  168. package/dist/intelligence/provisioning/platformDetector.d.ts +15 -0
  169. package/dist/intelligence/provisioning/platformDetector.d.ts.map +1 -0
  170. package/dist/intelligence/provisioning/platformDetector.js +40 -0
  171. package/dist/intelligence/provisioning/platformDetector.js.map +1 -0
  172. package/dist/intelligence/provisioning/setupState.d.ts +10 -0
  173. package/dist/intelligence/provisioning/setupState.d.ts.map +1 -0
  174. package/dist/intelligence/provisioning/setupState.js +59 -0
  175. package/dist/intelligence/provisioning/setupState.js.map +1 -0
  176. package/dist/intelligence/provisioning/types.d.ts +51 -0
  177. package/dist/intelligence/provisioning/types.d.ts.map +1 -0
  178. package/dist/intelligence/provisioning/types.js +2 -0
  179. package/dist/intelligence/provisioning/types.js.map +1 -0
  180. package/dist/intelligence/runtime/embeddedRuntimeAdapter.d.ts +26 -0
  181. package/dist/intelligence/runtime/embeddedRuntimeAdapter.d.ts.map +1 -0
  182. package/dist/intelligence/runtime/embeddedRuntimeAdapter.js +119 -0
  183. package/dist/intelligence/runtime/embeddedRuntimeAdapter.js.map +1 -0
  184. package/dist/intelligence/runtime/ollamaRuntimeAdapter.d.ts +28 -0
  185. package/dist/intelligence/runtime/ollamaRuntimeAdapter.d.ts.map +1 -0
  186. package/dist/intelligence/runtime/ollamaRuntimeAdapter.js +131 -0
  187. package/dist/intelligence/runtime/ollamaRuntimeAdapter.js.map +1 -0
  188. package/dist/intelligence/runtime/runtimeManager.d.ts +37 -0
  189. package/dist/intelligence/runtime/runtimeManager.d.ts.map +1 -0
  190. package/dist/intelligence/runtime/runtimeManager.js +168 -0
  191. package/dist/intelligence/runtime/runtimeManager.js.map +1 -0
  192. package/dist/intelligence/runtime/types.d.ts +56 -0
  193. package/dist/intelligence/runtime/types.d.ts.map +1 -0
  194. package/dist/intelligence/runtime/types.js +7 -0
  195. package/dist/intelligence/runtime/types.js.map +1 -0
  196. package/dist/knowledge/chunker.d.ts +18 -0
  197. package/dist/knowledge/chunker.d.ts.map +1 -0
  198. package/dist/knowledge/chunker.js +55 -0
  199. package/dist/knowledge/chunker.js.map +1 -0
  200. package/dist/knowledge/citationService.d.ts +26 -0
  201. package/dist/knowledge/citationService.d.ts.map +1 -0
  202. package/dist/knowledge/citationService.js +47 -0
  203. package/dist/knowledge/citationService.js.map +1 -0
  204. package/dist/knowledge/embeddings.d.ts +11 -0
  205. package/dist/knowledge/embeddings.d.ts.map +1 -0
  206. package/dist/knowledge/embeddings.js +28 -0
  207. package/dist/knowledge/embeddings.js.map +1 -0
  208. package/dist/knowledge/hybridSearch.d.ts +13 -0
  209. package/dist/knowledge/hybridSearch.d.ts.map +1 -0
  210. package/dist/knowledge/hybridSearch.js +38 -0
  211. package/dist/knowledge/hybridSearch.js.map +1 -0
  212. package/dist/knowledge/index.d.ts +25 -0
  213. package/dist/knowledge/index.d.ts.map +1 -0
  214. package/dist/knowledge/index.js +37 -0
  215. package/dist/knowledge/index.js.map +1 -0
  216. package/dist/knowledge/parsers.d.ts +20 -0
  217. package/dist/knowledge/parsers.d.ts.map +1 -0
  218. package/dist/knowledge/parsers.js +94 -0
  219. package/dist/knowledge/parsers.js.map +1 -0
  220. package/dist/knowledge/ragEngine.d.ts +24 -0
  221. package/dist/knowledge/ragEngine.d.ts.map +1 -0
  222. package/dist/knowledge/ragEngine.js +121 -0
  223. package/dist/knowledge/ragEngine.js.map +1 -0
  224. package/dist/knowledge/reranker.d.ts +10 -0
  225. package/dist/knowledge/reranker.d.ts.map +1 -0
  226. package/dist/knowledge/reranker.js +11 -0
  227. package/dist/knowledge/reranker.js.map +1 -0
  228. package/dist/knowledge/vectorStore.d.ts +22 -0
  229. package/dist/knowledge/vectorStore.d.ts.map +1 -0
  230. package/dist/knowledge/vectorStore.js +74 -0
  231. package/dist/knowledge/vectorStore.js.map +1 -0
  232. package/dist/main.d.ts +2 -0
  233. package/dist/main.d.ts.map +1 -0
  234. package/dist/main.js +113 -0
  235. package/dist/main.js.map +1 -0
  236. package/dist/orchestration/agentExecutionService.d.ts +29 -0
  237. package/dist/orchestration/agentExecutionService.d.ts.map +1 -0
  238. package/dist/orchestration/agentExecutionService.js +306 -0
  239. package/dist/orchestration/agentExecutionService.js.map +1 -0
  240. package/dist/orchestration/agentStateMachine.d.ts +29 -0
  241. package/dist/orchestration/agentStateMachine.d.ts.map +1 -0
  242. package/dist/orchestration/agentStateMachine.js +153 -0
  243. package/dist/orchestration/agentStateMachine.js.map +1 -0
  244. package/dist/orchestration/agentTaskService.d.ts +44 -0
  245. package/dist/orchestration/agentTaskService.d.ts.map +1 -0
  246. package/dist/orchestration/agentTaskService.js +168 -0
  247. package/dist/orchestration/agentTaskService.js.map +1 -0
  248. package/dist/orchestration/codingAgentDiscovery.d.ts +32 -0
  249. package/dist/orchestration/codingAgentDiscovery.d.ts.map +1 -0
  250. package/dist/orchestration/codingAgentDiscovery.js +148 -0
  251. package/dist/orchestration/codingAgentDiscovery.js.map +1 -0
  252. package/dist/orchestration/codingAgentService.d.ts +40 -0
  253. package/dist/orchestration/codingAgentService.d.ts.map +1 -0
  254. package/dist/orchestration/codingAgentService.js +319 -0
  255. package/dist/orchestration/codingAgentService.js.map +1 -0
  256. package/dist/orchestration/codingAgentTypes.d.ts +111 -0
  257. package/dist/orchestration/codingAgentTypes.d.ts.map +1 -0
  258. package/dist/orchestration/codingAgentTypes.js +32 -0
  259. package/dist/orchestration/codingAgentTypes.js.map +1 -0
  260. package/dist/orchestration/codingAgentVerifier.d.ts +34 -0
  261. package/dist/orchestration/codingAgentVerifier.d.ts.map +1 -0
  262. package/dist/orchestration/codingAgentVerifier.js +109 -0
  263. package/dist/orchestration/codingAgentVerifier.js.map +1 -0
  264. package/dist/orchestration/codingRepairService.d.ts +34 -0
  265. package/dist/orchestration/codingRepairService.d.ts.map +1 -0
  266. package/dist/orchestration/codingRepairService.js +120 -0
  267. package/dist/orchestration/codingRepairService.js.map +1 -0
  268. package/dist/orchestration/goalCompletionVerifier.d.ts +36 -0
  269. package/dist/orchestration/goalCompletionVerifier.d.ts.map +1 -0
  270. package/dist/orchestration/goalCompletionVerifier.js +165 -0
  271. package/dist/orchestration/goalCompletionVerifier.js.map +1 -0
  272. package/dist/orchestration/humanApprovalService.d.ts +89 -0
  273. package/dist/orchestration/humanApprovalService.d.ts.map +1 -0
  274. package/dist/orchestration/humanApprovalService.js +346 -0
  275. package/dist/orchestration/humanApprovalService.js.map +1 -0
  276. package/dist/orchestration/index.d.ts +47 -0
  277. package/dist/orchestration/index.d.ts.map +1 -0
  278. package/dist/orchestration/index.js +67 -0
  279. package/dist/orchestration/index.js.map +1 -0
  280. package/dist/orchestration/planner.d.ts +105 -0
  281. package/dist/orchestration/planner.d.ts.map +1 -0
  282. package/dist/orchestration/planner.js +692 -0
  283. package/dist/orchestration/planner.js.map +1 -0
  284. package/dist/orchestration/types.d.ts +109 -0
  285. package/dist/orchestration/types.d.ts.map +1 -0
  286. package/dist/orchestration/types.js +20 -0
  287. package/dist/orchestration/types.js.map +1 -0
  288. package/dist/preview/previewServer.d.ts +39 -0
  289. package/dist/preview/previewServer.d.ts.map +1 -0
  290. package/dist/preview/previewServer.js +228 -0
  291. package/dist/preview/previewServer.js.map +1 -0
  292. package/dist/preview/previewService.d.ts +43 -0
  293. package/dist/preview/previewService.d.ts.map +1 -0
  294. package/dist/preview/previewService.js +289 -0
  295. package/dist/preview/previewService.js.map +1 -0
  296. package/dist/preview/previewTypes.d.ts +35 -0
  297. package/dist/preview/previewTypes.d.ts.map +1 -0
  298. package/dist/preview/previewTypes.js +5 -0
  299. package/dist/preview/previewTypes.js.map +1 -0
  300. package/dist/storage/database.d.ts +12 -0
  301. package/dist/storage/database.d.ts.map +1 -0
  302. package/dist/storage/database.js +46 -0
  303. package/dist/storage/database.js.map +1 -0
  304. package/dist/storage/health.d.ts +17 -0
  305. package/dist/storage/health.d.ts.map +1 -0
  306. package/dist/storage/health.js +48 -0
  307. package/dist/storage/health.js.map +1 -0
  308. package/dist/storage/index.d.ts +45 -0
  309. package/dist/storage/index.d.ts.map +1 -0
  310. package/dist/storage/index.js +96 -0
  311. package/dist/storage/index.js.map +1 -0
  312. package/dist/storage/migration.d.ts +17 -0
  313. package/dist/storage/migration.d.ts.map +1 -0
  314. package/dist/storage/migration.js +354 -0
  315. package/dist/storage/migration.js.map +1 -0
  316. package/dist/storage/projectService.d.ts +19 -0
  317. package/dist/storage/projectService.d.ts.map +1 -0
  318. package/dist/storage/projectService.js +29 -0
  319. package/dist/storage/projectService.js.map +1 -0
  320. package/dist/storage/repositories/agentTaskRepository.d.ts +34 -0
  321. package/dist/storage/repositories/agentTaskRepository.d.ts.map +1 -0
  322. package/dist/storage/repositories/agentTaskRepository.js +128 -0
  323. package/dist/storage/repositories/agentTaskRepository.js.map +1 -0
  324. package/dist/storage/repositories/approvalRepository.d.ts +20 -0
  325. package/dist/storage/repositories/approvalRepository.d.ts.map +1 -0
  326. package/dist/storage/repositories/approvalRepository.js +116 -0
  327. package/dist/storage/repositories/approvalRepository.js.map +1 -0
  328. package/dist/storage/repositories/conversationRepository.d.ts +16 -0
  329. package/dist/storage/repositories/conversationRepository.d.ts.map +1 -0
  330. package/dist/storage/repositories/conversationRepository.js +50 -0
  331. package/dist/storage/repositories/conversationRepository.js.map +1 -0
  332. package/dist/storage/repositories/knowledgeRepository.d.ts +109 -0
  333. package/dist/storage/repositories/knowledgeRepository.d.ts.map +1 -0
  334. package/dist/storage/repositories/knowledgeRepository.js +177 -0
  335. package/dist/storage/repositories/knowledgeRepository.js.map +1 -0
  336. package/dist/storage/repositories/messageRepository.d.ts +13 -0
  337. package/dist/storage/repositories/messageRepository.d.ts.map +1 -0
  338. package/dist/storage/repositories/messageRepository.js +39 -0
  339. package/dist/storage/repositories/messageRepository.js.map +1 -0
  340. package/dist/storage/repositories/modelsRepository.d.ts +39 -0
  341. package/dist/storage/repositories/modelsRepository.d.ts.map +1 -0
  342. package/dist/storage/repositories/modelsRepository.js +92 -0
  343. package/dist/storage/repositories/modelsRepository.js.map +1 -0
  344. package/dist/storage/repositories/projectRepository.d.ts +14 -0
  345. package/dist/storage/repositories/projectRepository.d.ts.map +1 -0
  346. package/dist/storage/repositories/projectRepository.js +44 -0
  347. package/dist/storage/repositories/projectRepository.js.map +1 -0
  348. package/dist/storage/repositories/settingsRepository.d.ts +10 -0
  349. package/dist/storage/repositories/settingsRepository.d.ts.map +1 -0
  350. package/dist/storage/repositories/settingsRepository.js +27 -0
  351. package/dist/storage/repositories/settingsRepository.js.map +1 -0
  352. package/dist/storage/repositories/types.d.ts +56 -0
  353. package/dist/storage/repositories/types.d.ts.map +1 -0
  354. package/dist/storage/repositories/types.js +2 -0
  355. package/dist/storage/repositories/types.js.map +1 -0
  356. package/dist/tools/adapters/filesystemAdapter.d.ts +121 -0
  357. package/dist/tools/adapters/filesystemAdapter.d.ts.map +1 -0
  358. package/dist/tools/adapters/filesystemAdapter.js +808 -0
  359. package/dist/tools/adapters/filesystemAdapter.js.map +1 -0
  360. package/dist/tools/adapters/terminalAdapter.d.ts +67 -0
  361. package/dist/tools/adapters/terminalAdapter.d.ts.map +1 -0
  362. package/dist/tools/adapters/terminalAdapter.js +487 -0
  363. package/dist/tools/adapters/terminalAdapter.js.map +1 -0
  364. package/dist/tools/adapters/terminalCommandPolicy.d.ts +44 -0
  365. package/dist/tools/adapters/terminalCommandPolicy.d.ts.map +1 -0
  366. package/dist/tools/adapters/terminalCommandPolicy.js +422 -0
  367. package/dist/tools/adapters/terminalCommandPolicy.js.map +1 -0
  368. package/dist/tools/adapters/terminalTypes.d.ts +111 -0
  369. package/dist/tools/adapters/terminalTypes.d.ts.map +1 -0
  370. package/dist/tools/adapters/terminalTypes.js +26 -0
  371. package/dist/tools/adapters/terminalTypes.js.map +1 -0
  372. package/dist/tools/approvalGate.d.ts +24 -0
  373. package/dist/tools/approvalGate.d.ts.map +1 -0
  374. package/dist/tools/approvalGate.js +137 -0
  375. package/dist/tools/approvalGate.js.map +1 -0
  376. package/dist/tools/approvalPolicyEngine.d.ts +32 -0
  377. package/dist/tools/approvalPolicyEngine.d.ts.map +1 -0
  378. package/dist/tools/approvalPolicyEngine.js +141 -0
  379. package/dist/tools/approvalPolicyEngine.js.map +1 -0
  380. package/dist/tools/approvalTypes.d.ts +67 -0
  381. package/dist/tools/approvalTypes.d.ts.map +1 -0
  382. package/dist/tools/approvalTypes.js +23 -0
  383. package/dist/tools/approvalTypes.js.map +1 -0
  384. package/dist/tools/index.d.ts +72 -0
  385. package/dist/tools/index.d.ts.map +1 -0
  386. package/dist/tools/index.js +353 -0
  387. package/dist/tools/index.js.map +1 -0
  388. package/dist/tools/permissionEngine.d.ts +27 -0
  389. package/dist/tools/permissionEngine.d.ts.map +1 -0
  390. package/dist/tools/permissionEngine.js +130 -0
  391. package/dist/tools/permissionEngine.js.map +1 -0
  392. package/dist/tools/toolExecutor.d.ts +37 -0
  393. package/dist/tools/toolExecutor.d.ts.map +1 -0
  394. package/dist/tools/toolExecutor.js +440 -0
  395. package/dist/tools/toolExecutor.js.map +1 -0
  396. package/dist/tools/toolRegistry.d.ts +34 -0
  397. package/dist/tools/toolRegistry.d.ts.map +1 -0
  398. package/dist/tools/toolRegistry.js +92 -0
  399. package/dist/tools/toolRegistry.js.map +1 -0
  400. package/dist/tools/types.d.ts +82 -0
  401. package/dist/tools/types.d.ts.map +1 -0
  402. package/dist/tools/types.js +33 -0
  403. package/dist/tools/types.js.map +1 -0
  404. package/dist/ui/public/app.js +777 -0
  405. package/dist/ui/public/index.html +117 -0
  406. package/dist/ui/public/styles.css +413 -0
  407. package/dist/ui/server.d.ts +27 -0
  408. package/dist/ui/server.d.ts.map +1 -0
  409. package/dist/ui/server.js +373 -0
  410. package/dist/ui/server.js.map +1 -0
  411. package/package.json +63 -0
@@ -0,0 +1,925 @@
1
+ /**
2
+ * NEXUS AI — P7-F.2: CLI Visual Formatting & Theme Engine
3
+ *
4
+ * Provides premium dark-terminal styling, ANSI color utilities, box-drawing
5
+ * primitives, state machine symbols, and structured card renderers for the
6
+ * NEXUS AI CLI, matching the P7-F.2 reference design specification.
7
+ *
8
+ * Design language: electric blue / violet / cyan on near-black background.
9
+ * Visual hierarchy: NEXUS wordmark → info cards → welcome panel → input hint → footer.
10
+ *
11
+ * Zero external dependencies — uses Node.js standard ANSI escape codes only.
12
+ */
13
+ // ---------------------------------------------------------------------------
14
+ // ANSI Color Palette & Typography Tokens
15
+ // ---------------------------------------------------------------------------
16
+ export const colors = {
17
+ reset: '\x1b[0m',
18
+ bold: '\x1b[1m',
19
+ dim: '\x1b[2m',
20
+ italic: '\x1b[3m',
21
+ underline: '\x1b[4m',
22
+ // Primary Theme — Cyan / Blue / Violet
23
+ cyan: '\x1b[36m',
24
+ brightCyan: '\x1b[96m',
25
+ blue: '\x1b[34m',
26
+ brightBlue: '\x1b[94m',
27
+ magenta: '\x1b[35m',
28
+ brightMagenta: '\x1b[95m',
29
+ // Semantic Status Colors
30
+ green: '\x1b[32m',
31
+ brightGreen: '\x1b[92m',
32
+ yellow: '\x1b[33m',
33
+ brightYellow: '\x1b[93m',
34
+ red: '\x1b[31m',
35
+ brightRed: '\x1b[91m',
36
+ white: '\x1b[97m',
37
+ gray: '\x1b[90m',
38
+ };
39
+ // ---------------------------------------------------------------------------
40
+ // State Machine Symbols (with & without ANSI colors)
41
+ // ---------------------------------------------------------------------------
42
+ export const stateSymbols = {
43
+ completed: `${colors.brightGreen}✓${colors.reset}`,
44
+ executing: `${colors.brightCyan}●${colors.reset}`,
45
+ planning: `${colors.dim}◌${colors.reset}`,
46
+ awaitingApproval: `${colors.brightYellow}!${colors.reset}`,
47
+ failed: `${colors.brightRed}✕${colors.reset}`,
48
+ cancelled: `${colors.gray}○${colors.reset}`,
49
+ plain: {
50
+ completed: '✓',
51
+ executing: '●',
52
+ planning: '◌',
53
+ awaitingApproval: '!',
54
+ failed: '✕',
55
+ cancelled: '○',
56
+ },
57
+ };
58
+ export function getSymbolForState(state, useColor = true) {
59
+ const normalized = state.toLowerCase();
60
+ if (normalized === 'completed')
61
+ return useColor ? stateSymbols.completed : stateSymbols.plain.completed;
62
+ if (normalized === 'executing' || normalized === 'observing' || normalized === 'verifying')
63
+ return useColor ? stateSymbols.executing : stateSymbols.plain.executing;
64
+ if (normalized === 'planning' || normalized === 'plan_ready' || normalized === 'created')
65
+ return useColor ? stateSymbols.planning : stateSymbols.plain.planning;
66
+ if (normalized === 'awaiting_approval')
67
+ return useColor ? stateSymbols.awaitingApproval : stateSymbols.plain.awaitingApproval;
68
+ if (normalized === 'failed')
69
+ return useColor ? stateSymbols.failed : stateSymbols.plain.failed;
70
+ if (normalized === 'cancelled')
71
+ return useColor ? stateSymbols.cancelled : stateSymbols.plain.cancelled;
72
+ return useColor ? `${colors.dim}•${colors.reset}` : '•';
73
+ }
74
+ // ---------------------------------------------------------------------------
75
+ // Secret & Sensitive Parameter Sanitization
76
+ // ---------------------------------------------------------------------------
77
+ export function sanitizeText(text) {
78
+ if (!text)
79
+ return text;
80
+ return text
81
+ .replace(/(api[_-]?key|secret|password|token)\s*[:=]\s*['"]?[^'"\s\n]+['"]?/gi, '$1=***REDACTED***')
82
+ .replace(/bearer\s+[a-zA-Z0-9_\-.]+/gi, 'Bearer ***REDACTED***');
83
+ }
84
+ // ---------------------------------------------------------------------------
85
+ // Internal Layout Utilities
86
+ // ---------------------------------------------------------------------------
87
+ /** Strip ANSI escape sequences from a string */
88
+ function stripAnsi(str) {
89
+ return str.replace(/\x1b\[[0-9;]*m/g, '');
90
+ }
91
+ /** Visible character width of a string (ignoring ANSI codes) */
92
+ function visibleWidth(str) {
93
+ return stripAnsi(str).length;
94
+ }
95
+ /**
96
+ * Pad a string (which may contain ANSI codes) to a target visible width.
97
+ * If the string is longer than `width`, it is truncated with a trailing ellipsis.
98
+ */
99
+ function padAnsi(str, width, align = 'left') {
100
+ const vw = visibleWidth(str);
101
+ if (vw > width) {
102
+ const stripped = stripAnsi(str);
103
+ return width > 1 ? stripped.slice(0, width - 1) + '\u2026' : stripped.slice(0, width);
104
+ }
105
+ const pad = width - vw;
106
+ if (align === 'right')
107
+ return ' '.repeat(pad) + str;
108
+ if (align === 'center') {
109
+ const left = Math.floor(pad / 2);
110
+ return ' '.repeat(left) + str + ' '.repeat(pad - left);
111
+ }
112
+ return str + ' '.repeat(pad);
113
+ }
114
+ /** Effective terminal width, clamped to a usable range */
115
+ function termWidth() {
116
+ return Math.min(Math.max(process.stdout.columns || 100, 80), 130);
117
+ }
118
+ /** Horizontal divider (public export — used by agentRunner.ts) */
119
+ export function drawDivider(char = '─', width = 74) {
120
+ return `${colors.dim}${char.repeat(width)}${colors.reset}`;
121
+ }
122
+ /** Full terminal-width divider */
123
+ function fullDivider(char = '─', ansiColor = colors.dim) {
124
+ return `${ansiColor}${char.repeat(termWidth())}${colors.reset}`;
125
+ }
126
+ /**
127
+ * Merge multiple column arrays side by side with a separator.
128
+ * Each column's strings are padded to their specified width.
129
+ */
130
+ function mergeColumns(cols, widths, separator = ' ') {
131
+ const maxRows = Math.max(...cols.map((c) => c.length), 0);
132
+ const result = [];
133
+ for (let i = 0; i < maxRows; i++) {
134
+ const parts = cols.map((col, ci) => padAnsi(col[i] ?? '', widths[ci]));
135
+ result.push(parts.join(separator));
136
+ }
137
+ return result;
138
+ }
139
+ /**
140
+ * Wrap content lines in a bordered box.
141
+ * The box is exactly `outerWidth` visible characters wide (including the two border chars).
142
+ * Content lines are padded to fill the inner width.
143
+ */
144
+ function drawBox(lines, outerWidth, borderColor = colors.brightBlue) {
145
+ const innerWidth = Math.max(0, outerWidth - 2);
146
+ const out = [];
147
+ out.push(`${borderColor}\u250c${'─'.repeat(innerWidth)}\u2510${colors.reset}`);
148
+ for (const line of lines) {
149
+ out.push(`${borderColor}\u2502${colors.reset}${padAnsi(line, innerWidth)}${borderColor}\u2502${colors.reset}`);
150
+ }
151
+ out.push(`${borderColor}\u2514${'─'.repeat(innerWidth)}\u2518${colors.reset}`);
152
+ return out;
153
+ }
154
+ // ---------------------------------------------------------------------------
155
+ // NEXUS ASCII Wordmark
156
+ // ---------------------------------------------------------------------------
157
+ /**
158
+ * Returns the multi-line NEXUS block-art wordmark.
159
+ * Uses blue → cyan → violet gradient across letters N-E-X-U-S.
160
+ * Visible width of each line is ~47 characters.
161
+ */
162
+ function nexusWordmark() {
163
+ const C1 = colors.brightCyan;
164
+ const C2 = colors.brightBlue;
165
+ const C3 = colors.brightMagenta;
166
+ const R = colors.reset;
167
+ return [
168
+ `${C1} \u2588\u2588\u2588\u2557 \u2588\u2588\u2557${C2}\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557${C1}\u2588\u2588\u2557 \u2588\u2588\u2557${C2}\u2588\u2588\u2557 \u2588\u2588\u2557${C3}\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557${R}`,
169
+ `${C1} \u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551${C2}\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255d${C1}\u255a\u2588\u2588\u2557\u2588\u2588\u2554\u255d${C2}\u2588\u2588\u2551 \u2588\u2588\u2551${C3}\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255d${R}`,
170
+ `${C1} \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551${C2}\u2588\u2588\u2588\u2588\u2588\u2557 ${C1} \u255a\u2588\u2588\u2588\u2554\u255d ${C2}\u2588\u2588\u2551 \u2588\u2588\u2551${C3}\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557${R}`,
171
+ `${C1} \u2588\u2588\u2551\u255a\u2588\u2588\u2557\u2588\u2588\u2551${C2}\u2588\u2588\u2554\u2550\u2550\u255d ${C1} \u2588\u2588\u2554\u2588\u2588\u2557 ${C2}\u2588\u2588\u2551 \u2588\u2588\u2551${C3}\u255a\u2550\u2550\u2550\u2550\u2588\u2588\u2551${R}`,
172
+ `${C1} \u2588\u2588\u2551 \u255a\u2588\u2588\u2588\u2588\u2551${C2}\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557${C1}\u2588\u2588\u2554\u255d \u2588\u2588\u2557${C2}\u255a\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255d${C3}\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551${R}`,
173
+ `${C1} \u255a\u2550\u255d \u255a\u2550\u2550\u2550\u255d${C2}\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u255d${C1}\u255a\u2550\u255d \u255a\u2550\u255d${C2} \u255a\u2550\u2550\u2550\u2550\u2550\u255d ${C3}\u255a\u2550\u2550\u2550\u2550\u2550\u2550\u255d${R}`,
174
+ ];
175
+ }
176
+ /** Small N glyph + tagline for the welcome panel visual mark */
177
+ function nMark() {
178
+ const C = colors.brightBlue;
179
+ const D = colors.dim;
180
+ const R = colors.reset;
181
+ return [
182
+ '',
183
+ `${C} \u2588\u2557 \u2588\u2557${R}`,
184
+ `${C} \u2588\u2588\u2557 \u2588\u2588\u2551${R}`,
185
+ `${C} \u2588\u2554\u2588\u2588\u2554\u2588\u2551${R}`,
186
+ `${C} \u2588\u2551\u255a\u2588\u2588\u2554\u2588\u2551${R}`,
187
+ `${C} \u2588\u2551 \u255a\u2588\u2554\u2588\u2551${R}`,
188
+ `${C} \u255a\u2550\u255d \u255a\u2550\u255d${R}`,
189
+ '',
190
+ `${D} IDEAS TO${R}`,
191
+ `${D} IMPACT${R}`,
192
+ '',
193
+ ];
194
+ }
195
+ // ---------------------------------------------------------------------------
196
+ // Header Banner (drawHeaderBanner)
197
+ // ---------------------------------------------------------------------------
198
+ export function drawHeaderBanner() {
199
+ const W = termWidth();
200
+ const lines = [];
201
+ lines.push(fullDivider('\u2550', colors.brightBlue));
202
+ // Wordmark rows + right-side branding aligned to right edge
203
+ const wm = nexusWordmark();
204
+ const wmVW = visibleWidth(wm[0]); // e.g. ~49 chars
205
+ const rightLines = [
206
+ `${colors.dim}THINK ${colors.brightCyan}\u203a${colors.dim} PLAN ${colors.brightCyan}\u203a${colors.dim} APPROVE${colors.reset}`,
207
+ `${colors.dim}EXECUTE ${colors.brightCyan}\u203a${colors.dim} ACHIEVE${colors.reset}`,
208
+ '',
209
+ `${colors.gray}LOCAL \u00b7 PRIVATE \u00b7 POWERFUL \u00b7 YOURS${colors.reset}`,
210
+ '',
211
+ `${colors.dim}v0.1.0${colors.reset}`,
212
+ ];
213
+ const rightColW = Math.max(0, W - wmVW - 4); // 2 leading spaces + 2 spacing
214
+ const maxRows = Math.max(wm.length, rightLines.length);
215
+ for (let i = 0; i < maxRows; i++) {
216
+ const leftPart = wm[i] ? ` ${wm[i]}` : ` ${' '.repeat(wmVW)}`;
217
+ const rightPart = rightLines[i]
218
+ ? padAnsi(rightLines[i], rightColW, 'right')
219
+ : ' '.repeat(rightColW);
220
+ lines.push(leftPart + ' ' + rightPart);
221
+ }
222
+ lines.push('');
223
+ lines.push(` ${colors.bold}${colors.brightCyan}NEXUS AI — YOUR LOCAL AI WORKSTATION${colors.reset}`);
224
+ lines.push('');
225
+ lines.push(fullDivider('─', colors.brightBlue));
226
+ return lines.join('\n');
227
+ }
228
+ // ---------------------------------------------------------------------------
229
+ // Workstation Dashboard (renderDashboard) — Startup View
230
+ // ---------------------------------------------------------------------------
231
+ export function renderDashboard(report, workspaceRoot) {
232
+ const lines = [];
233
+ const W = termWidth();
234
+ // ── HEADER ──────────────────────────────────────────────────────────────
235
+ lines.push(drawHeaderBanner());
236
+ lines.push('');
237
+ // ── THREE-COLUMN CARDS ───────────────────────────────────────────────────
238
+ // Column outer widths must sum to W with two 2-char separators:
239
+ // col1Outer + 2 + col2Outer + 2 + col3Outer = W
240
+ const col1Outer = Math.floor(W * 0.33);
241
+ const col2Outer = Math.floor(W * 0.34);
242
+ const col3Outer = W - col1Outer - col2Outer - 4;
243
+ const col1Inner = col1Outer - 2;
244
+ const col2Inner = col2Outer - 2;
245
+ const col3Inner = col3Outer - 2;
246
+ // -- SYSTEM CARD --
247
+ const ollamaSub = report.subsystems.find((s) => s.name === 'IntelligenceService');
248
+ const ollamaVersion = String(ollamaSub?.details?.ollamaVersion ?? 'Connected');
249
+ const modelCount = ollamaSub?.details?.modelsCount ?? 0;
250
+ const primaryModel = String(ollamaSub?.details?.primaryModel ?? 'Auto');
251
+ const isReady = ollamaSub?.status === 'ok';
252
+ const statusLabel = isReady
253
+ ? `${colors.brightGreen}\u25cf READY${colors.reset}`
254
+ : `${colors.brightYellow}\u25cf DEGRADED${colors.reset}`;
255
+ const maxWsLen = col1Inner - 4;
256
+ const wsShort = workspaceRoot.length > maxWsLen
257
+ ? '\u2026' + workspaceRoot.slice(-(maxWsLen - 1))
258
+ : workspaceRoot;
259
+ const maxModelLen = col1Inner - 4;
260
+ const modelShort = primaryModel.length > maxModelLen
261
+ ? primaryModel.slice(0, maxModelLen - 1) + '\u2026'
262
+ : primaryModel;
263
+ const col1Lines = [
264
+ ` ${colors.brightGreen}\u25cf SYSTEM STATUS${colors.reset}`,
265
+ ` ${colors.bold}System Health${colors.reset} ${statusLabel}`,
266
+ '',
267
+ ` ${colors.dim}AI Runtime${colors.reset}`,
268
+ ` ${colors.white}Ollama ${ollamaVersion}${colors.reset}`,
269
+ '',
270
+ ` ${colors.dim}Primary Model${colors.reset}`,
271
+ ` ${colors.brightCyan}${modelShort}${colors.reset}`,
272
+ '',
273
+ ` ${colors.dim}Workspace${colors.reset}`,
274
+ ` ${colors.gray}${wsShort}${colors.reset}`,
275
+ '',
276
+ ` ${colors.dim}Database${colors.reset} ${colors.green}Connected${colors.reset}`,
277
+ ` ${colors.dim}Models${colors.reset} ${colors.white}${String(modelCount)} available${colors.reset}`,
278
+ '',
279
+ ];
280
+ // -- CENTER QUOTE CARD --
281
+ const col2Lines = [
282
+ '',
283
+ '',
284
+ ` ${colors.dim}\u275d${colors.reset}`,
285
+ '',
286
+ ` ${colors.bold}${colors.white}Turn your ideas${colors.reset}`,
287
+ ` ${colors.bold}${colors.white}into real results.${colors.reset}`,
288
+ '',
289
+ ` ${colors.dim}\u2014 NEXUS AI${colors.reset}`,
290
+ '',
291
+ '',
292
+ '',
293
+ '',
294
+ '',
295
+ '',
296
+ '',
297
+ '',
298
+ ];
299
+ // -- QUICK COMMANDS CARD --
300
+ const col3Lines = [
301
+ ` ${colors.brightMagenta}\u2736 QUICK COMMANDS${colors.reset}`,
302
+ '',
303
+ ` ${colors.brightCyan}/help${colors.reset} ${colors.gray}Show all commands${colors.reset}`,
304
+ ` ${colors.brightCyan}/models${colors.reset} ${colors.gray}List AI models${colors.reset}`,
305
+ ` ${colors.brightCyan}/workspace${colors.reset} ${colors.gray}Workspace info${colors.reset}`,
306
+ ` ${colors.brightCyan}/agents${colors.reset} ${colors.gray}Agent status${colors.reset}`,
307
+ ` ${colors.brightCyan}/clear${colors.reset} ${colors.gray}Clear screen${colors.reset}`,
308
+ ` ${colors.brightCyan}/exit${colors.reset} ${colors.gray}Exit NEXUS${colors.reset}`,
309
+ '',
310
+ ` ${colors.dim}Type /help for full list${colors.reset}`,
311
+ '',
312
+ '',
313
+ '',
314
+ '',
315
+ '',
316
+ '',
317
+ ];
318
+ // Ensure all columns have the same number of rows (pad shorter ones)
319
+ const maxColRows = Math.max(col1Lines.length, col2Lines.length, col3Lines.length);
320
+ while (col1Lines.length < maxColRows)
321
+ col1Lines.push('');
322
+ while (col2Lines.length < maxColRows)
323
+ col2Lines.push('');
324
+ while (col3Lines.length < maxColRows)
325
+ col3Lines.push('');
326
+ // Pre-pad content to inner column width before boxing
327
+ const padCol1 = col1Lines.map((l) => padAnsi(l, col1Inner));
328
+ const padCol2 = col2Lines.map((l) => padAnsi(l, col2Inner));
329
+ const padCol3 = col3Lines.map((l) => padAnsi(l, col3Inner));
330
+ const box1 = drawBox(padCol1, col1Outer, colors.brightBlue);
331
+ const box2 = drawBox(padCol2, col2Outer, `${colors.dim}`);
332
+ const box3 = drawBox(padCol3, col3Outer, colors.brightMagenta);
333
+ const merged = mergeColumns([box1, box2, box3], [col1Outer, col2Outer, col3Outer], ' ');
334
+ lines.push(...merged);
335
+ lines.push('');
336
+ if (report.overall === 'degraded') {
337
+ lines.push(`${colors.brightYellow}⚠ NOTICE: AI Runtime is operating in DEGRADED mode. Local Ollama instance may be offline.${colors.reset}`);
338
+ lines.push('');
339
+ }
340
+ // ── WELCOME PANEL ────────────────────────────────────────────────────────
341
+ const welcomeOuter = W;
342
+ const welcomeInner = welcomeOuter - 2;
343
+ // Right visual mark (N + IDEAS TO IMPACT)
344
+ const mark = nMark();
345
+ const markVW = 12; // fixed width for the N mark column
346
+ const contentW = welcomeInner - markVW;
347
+ // Examples separator line
348
+ const exSepLen = Math.max(0, contentW - 10);
349
+ const examplesSep = ` ${colors.dim}EXAMPLES ${colors.gray}${'─'.repeat(exSepLen)}${colors.reset}`;
350
+ const contentLines = [
351
+ ` ${colors.brightCyan}\u25c8${colors.reset} ${colors.bold}${colors.white}NEXUS${colors.reset}`,
352
+ '',
353
+ ` ${colors.bold}${colors.white}Welcome to NEXUS AI!${colors.reset}`,
354
+ ` ${colors.gray}I'm your local AI agent, ready to help you build,${colors.reset}`,
355
+ ` ${colors.gray}automate, research, and create. Just describe what${colors.reset}`,
356
+ ` ${colors.gray}you want to do, and I'll take care of the rest.${colors.reset}`,
357
+ '',
358
+ examplesSep,
359
+ '',
360
+ ` ${colors.dim}"Create a calculator with HTML, CSS and JS"${colors.reset}`,
361
+ ` ${colors.dim}"Summarize the files in my workspace"${colors.reset}`,
362
+ ` ${colors.dim}"Build a to-do app"${colors.reset}`,
363
+ ` ${colors.dim}"Write a research report on quantum computing"${colors.reset}`,
364
+ '',
365
+ ];
366
+ const maxWelcomeRows = Math.max(contentLines.length, mark.length);
367
+ const welcomeRows = [];
368
+ for (let i = 0; i < maxWelcomeRows; i++) {
369
+ const leftPart = padAnsi(contentLines[i] ?? '', contentW);
370
+ const rightPart = padAnsi(mark[i] ?? '', markVW);
371
+ welcomeRows.push(leftPart + rightPart);
372
+ }
373
+ const welcomeBox = drawBox(welcomeRows, welcomeOuter, colors.brightBlue);
374
+ lines.push(...welcomeBox);
375
+ lines.push('');
376
+ // ── INPUT AREA HINT ──────────────────────────────────────────────────────
377
+ const inputOuter = W;
378
+ const inputInner = inputOuter - 2;
379
+ const inputLeft = ` ${colors.brightCyan}\u203a${colors.reset} ${colors.dim}Ask NEXUS anything...${colors.reset}`;
380
+ const inputRight = `${colors.dim}Ctrl+Enter to send${colors.reset} `;
381
+ const inputLeftVW = visibleWidth(inputLeft);
382
+ const inputRightVW = visibleWidth(inputRight);
383
+ const inputGap = Math.max(0, inputInner - inputLeftVW - inputRightVW);
384
+ const inputRow = inputLeft + ' '.repeat(inputGap) + inputRight;
385
+ lines.push(`${colors.brightBlue}\u250c${'─'.repeat(inputInner)}\u2510${colors.reset}`);
386
+ lines.push(`${colors.brightBlue}\u2502${colors.reset}${padAnsi(inputRow, inputInner)}${colors.brightBlue}\u2502${colors.reset}`);
387
+ lines.push(`${colors.brightBlue}\u2514${'─'.repeat(inputInner)}\u2518${colors.reset}`);
388
+ lines.push('');
389
+ // ── FOOTER ───────────────────────────────────────────────────────────────
390
+ lines.push(fullDivider('─', colors.dim));
391
+ const now = new Date();
392
+ const timeStr = now.toLocaleTimeString('en-US', {
393
+ hour: '2-digit',
394
+ minute: '2-digit',
395
+ hour12: false,
396
+ });
397
+ const dateStr = now.toLocaleDateString('en-US', {
398
+ month: 'short',
399
+ day: 'numeric',
400
+ year: 'numeric',
401
+ });
402
+ const footerLeft = ` ${colors.brightCyan}N${colors.reset} ${colors.bold}NEXUS AI CLI${colors.reset}`;
403
+ const footerCenter = `${colors.dim}BUILT FOR CREATORS, DEVELOPERS, THINKERS.${colors.reset}`;
404
+ const footerRight = `${colors.gray}${dateStr} ${timeStr}${colors.reset} `;
405
+ const fLeftVW = visibleWidth(footerLeft);
406
+ const fCenterVW = visibleWidth(footerCenter);
407
+ const fRightVW = visibleWidth(footerRight);
408
+ const totalAvail = W;
409
+ const centerPos = Math.floor((totalAvail - fCenterVW) / 2);
410
+ const leftGap = Math.max(1, centerPos - fLeftVW);
411
+ const rightGap = Math.max(1, totalAvail - fLeftVW - leftGap - fCenterVW - fRightVW);
412
+ lines.push(footerLeft +
413
+ ' '.repeat(leftGap) +
414
+ footerCenter +
415
+ ' '.repeat(rightGap) +
416
+ footerRight);
417
+ lines.push('');
418
+ return lines.join('\n');
419
+ }
420
+ // ---------------------------------------------------------------------------
421
+ // Help Command Renderer
422
+ // ---------------------------------------------------------------------------
423
+ export function renderHelpMenu() {
424
+ const lines = [
425
+ `${colors.bold}${colors.brightCyan}NEXUS AI Agent Runner \u2014 Help & Command Reference${colors.reset}`,
426
+ drawDivider('─', 64),
427
+ `${colors.dim}TASK COMMANDS${colors.reset}`,
428
+ ` ${colors.brightCyan}<task description>${colors.reset} Submit a natural language goal`,
429
+ ` ${colors.brightCyan}/task <goal>${colors.reset} Explicitly submit a task (alias: /t)`,
430
+ ` ${colors.brightCyan}/code <goal>${colors.reset} Run automated coding task (P6-D)`,
431
+ ` ${colors.brightCyan}/prompt${colors.reset} Enter compose (multi-line) mode`,
432
+ ` ${colors.brightCyan}/send${colors.reset} Submit compose buffer`,
433
+ ` ${colors.brightCyan}/status${colors.reset} Show current task status`,
434
+ ` ${colors.brightCyan}/plan${colors.reset} View synthesized plan`,
435
+ ` ${colors.brightCyan}/result${colors.reset} Show execution result`,
436
+ ` ${colors.brightCyan}/cancel${colors.reset} Cancel active task`,
437
+ '',
438
+ `${colors.dim}WORKSTATION & SYSTEM${colors.reset}`,
439
+ ` ${colors.brightCyan}/preview${colors.reset} Preview latest completed web task`,
440
+ ` ${colors.brightCyan}/preview stop${colors.reset} Stop active preview server`,
441
+ ` ${colors.brightCyan}/preview status${colors.reset} Show active preview status`,
442
+ ` ${colors.brightCyan}/tasks${colors.reset} List recent task history`,
443
+ ` ${colors.brightCyan}/models${colors.reset} List installed Ollama models`,
444
+ ` ${colors.brightCyan}/model <role> <n>${colors.reset} Set role model override`,
445
+ ` ${colors.brightCyan}/model reset${colors.reset} Reset all model overrides`,
446
+ ` ${colors.brightCyan}/workspace${colors.reset} Workspace root & security info`,
447
+ ` ${colors.brightCyan}/agents${colors.reset} Subsystem status`,
448
+ ` ${colors.brightCyan}/approvals${colors.reset} Pending approval requests`,
449
+ ` ${colors.brightCyan}/approve <id>${colors.reset} Approve a request`,
450
+ ` ${colors.brightCyan}/reject <id>${colors.reset} Reject a request`,
451
+ ` ${colors.brightCyan}/clear${colors.reset} Clear terminal screen`,
452
+ ` ${colors.brightCyan}/exit${colors.reset} Exit NEXUS CLI`,
453
+ drawDivider('─', 64),
454
+ `${colors.dim}TIP: Paste multi-line prompts directly \u2014 NEXUS batches them safely.${colors.reset}`,
455
+ `${colors.dim} Use /prompt for deliberate multi-line task authoring.${colors.reset}`,
456
+ ];
457
+ return lines.join('\n');
458
+ }
459
+ // ---------------------------------------------------------------------------
460
+ // Task History Renderer (/tasks)
461
+ // ---------------------------------------------------------------------------
462
+ export function renderTasksList(tasks) {
463
+ if (tasks.length === 0) {
464
+ return `${colors.dim}No task history recorded yet. Submit a task using: /task <goal>${colors.reset}`;
465
+ }
466
+ const lines = [
467
+ `${colors.bold}${colors.brightCyan}RECENT TASKS${colors.reset}`,
468
+ drawDivider('─', 74),
469
+ ];
470
+ tasks.slice(0, 15).forEach((t) => {
471
+ const symbol = getSymbolForState(t.state);
472
+ const idPad = t.id.padEnd(26, ' ');
473
+ const titleTrunc = t.title.length > 30 ? `${t.title.slice(0, 27)}...` : t.title.padEnd(30, ' ');
474
+ const stateColor = t.state === 'completed'
475
+ ? colors.brightGreen
476
+ : t.state === 'failed'
477
+ ? colors.brightRed
478
+ : t.state === 'awaiting_approval'
479
+ ? colors.brightYellow
480
+ : colors.dim;
481
+ lines.push(`${symbol} ${colors.brightCyan}${idPad}${colors.reset} ${titleTrunc} ${stateColor}${t.state.toUpperCase()}${colors.reset}`);
482
+ });
483
+ lines.push(drawDivider('─', 74));
484
+ lines.push(`${colors.dim}Use /task <id> to inspect detailed plan and steps for a specific task.${colors.reset}`);
485
+ return lines.join('\n');
486
+ }
487
+ // ---------------------------------------------------------------------------
488
+ // Interactive Approval Card Generator
489
+ // ---------------------------------------------------------------------------
490
+ export function renderApprovalCard(approval, taskTitle) {
491
+ const lines = [
492
+ drawDivider('─', 64),
493
+ `${colors.bold}${colors.brightYellow}\u26a0 APPROVAL REQUIRED${colors.reset}`,
494
+ '',
495
+ ` ${colors.bold}Task:${colors.reset} ${taskTitle || approval.taskId}`,
496
+ ` ${colors.bold}Approval ID:${colors.reset} ${colors.brightCyan}${approval.approvalId}${colors.reset}`,
497
+ ` ${colors.bold}Step ID:${colors.reset} ${approval.stepId}`,
498
+ ` ${colors.bold}Tool:${colors.reset} ${colors.bold}${colors.white}${approval.toolId}${colors.reset}`,
499
+ ` ${colors.bold}Risk Level:${colors.reset} ${colors.bold}${colors.brightRed}${approval.riskLevel.toUpperCase()}${colors.reset}`,
500
+ ` ${colors.bold}Capability:${colors.reset} ${approval.requestedCapability}`,
501
+ ` ${colors.bold}Reason:${colors.reset} ${approval.decisionReason || 'Action requires explicit human approval'}`,
502
+ '',
503
+ `${colors.bold}Options:${colors.reset}`,
504
+ ` ${colors.brightGreen}[Y] Approve${colors.reset} Allow and resume task (/approve ${approval.approvalId})`,
505
+ ` ${colors.brightRed}[N] Reject${colors.reset} Reject and cancel task (/reject ${approval.approvalId})`,
506
+ ` ${colors.brightCyan}[V] View${colors.reset} View approval parameters`,
507
+ drawDivider('─', 64),
508
+ ];
509
+ return lines.join('\n');
510
+ }
511
+ // ---------------------------------------------------------------------------
512
+ // Task Completion Card Generator
513
+ // ---------------------------------------------------------------------------
514
+ export function renderCompletionCard(task, plan, durationMs) {
515
+ const durationSec = durationMs ? (durationMs / 1000).toFixed(1) : 'N/A';
516
+ const lines = [
517
+ drawDivider('─', 64),
518
+ `${colors.bold}${colors.brightGreen}FINAL RESULT \u2014 TASK COMPLETED${colors.reset}`,
519
+ '',
520
+ ` ${colors.bold}Goal:${colors.reset} ${task.title}`,
521
+ ` ${colors.bold}Status:${colors.reset} ${colors.brightGreen}\u2713 COMPLETED${colors.reset}`,
522
+ ` ${colors.bold}Task ID:${colors.reset} ${task.id}`,
523
+ ` ${colors.bold}Duration:${colors.reset} ${durationSec}s`,
524
+ ];
525
+ if (plan) {
526
+ const total = plan.steps.length;
527
+ const comp = plan.steps.filter((s) => s.status === 'completed').length;
528
+ lines.push(` ${colors.bold}Steps:${colors.reset} ${comp}/${total} completed successfully`);
529
+ }
530
+ lines.push('');
531
+ lines.push(`${colors.bold}Verification:${colors.reset}`);
532
+ lines.push(` ${colors.brightGreen}\u2713 All plan steps executed cleanly${colors.reset}`);
533
+ lines.push(` ${colors.brightGreen}\u2713 Task state verified as COMPLETED in SQLite${colors.reset}`);
534
+ lines.push(drawDivider('─', 64));
535
+ return lines.join('\n');
536
+ }
537
+ // ---------------------------------------------------------------------------
538
+ // Task Failure Card Generator
539
+ // ---------------------------------------------------------------------------
540
+ export function renderFailureCard(task, errorMessage) {
541
+ const category = task.errorCategory || 'UNKNOWN_ERROR';
542
+ const lines = [
543
+ drawDivider('─', 64),
544
+ `${colors.bold}${colors.brightRed}\u2716 TASK FAILED${colors.reset}`,
545
+ '',
546
+ ` ${colors.bold}Goal:${colors.reset} ${task.title}`,
547
+ ` ${colors.bold}Task ID:${colors.reset} ${task.id}`,
548
+ ` ${colors.bold}Error Category:${colors.reset} ${colors.bold}${colors.brightRed}${category}${colors.reset}`,
549
+ ` ${colors.bold}Failed Step:${colors.reset} ${task.currentStep || 'Initialization / Planning'}`,
550
+ ` ${colors.bold}Details:${colors.reset} ${sanitizeText(errorMessage || 'Execution encountered a non-retryable error.')}`,
551
+ '',
552
+ `${colors.bold}Suggested Action:${colors.reset}`,
553
+ ];
554
+ if (category === 'FILE_NOT_FOUND') {
555
+ lines.push(' \u2022 Check if the specified relative path is correct.');
556
+ lines.push(' \u2022 If you meant to author a new file, request to "create" or "build" it.');
557
+ }
558
+ else if (category === 'PERMISSION_DENIED') {
559
+ lines.push(' \u2022 The action was blocked by the Security PermissionEngine policy.');
560
+ lines.push(' \u2022 Check workspace boundary or allowed capabilities.');
561
+ }
562
+ else if (category === 'APPROVAL_REJECTED') {
563
+ lines.push(' \u2022 Action was cancelled because approval was rejected.');
564
+ }
565
+ else {
566
+ lines.push(' \u2022 Inspect plan steps with /plan or submit a simplified goal.');
567
+ }
568
+ lines.push(drawDivider('─', 64));
569
+ return lines.join('\n');
570
+ }
571
+ // ---------------------------------------------------------------------------
572
+ // P7-F.1: Prompt Preview Card
573
+ // ---------------------------------------------------------------------------
574
+ const MAX_PREVIEW_LINES = 5;
575
+ const PREVIEW_WIDTH = 65;
576
+ export function renderPromptPreview(text) {
577
+ const allLines = text.split('\n');
578
+ const lineCount = allLines.length;
579
+ const charCount = text.length;
580
+ const previewLines = allLines.slice(0, MAX_PREVIEW_LINES);
581
+ const overflow = lineCount - MAX_PREVIEW_LINES;
582
+ const innerWidth = PREVIEW_WIDTH - 4;
583
+ const top = `${colors.dim}\u250c\u2500 TASK ${'─'.repeat(Math.max(0, PREVIEW_WIDTH - 8))}\u2510${colors.reset}`;
584
+ const bottom = `${colors.dim}\u2514${'─'.repeat(PREVIEW_WIDTH - 2)}\u2518${colors.reset}`;
585
+ const rows = [top];
586
+ for (const line of previewLines) {
587
+ const truncated = line.length > innerWidth ? line.slice(0, innerWidth - 1) + '\u2026' : line;
588
+ rows.push(`${colors.dim}\u2502${colors.reset} ${padAnsi(truncated, innerWidth)} ${colors.dim}\u2502${colors.reset}`);
589
+ }
590
+ if (overflow > 0) {
591
+ const overflowStr = `${colors.dim}+ ${overflow} more line${overflow === 1 ? '' : 's'}${colors.reset}`;
592
+ rows.push(`${colors.dim}\u2502${colors.reset} ${padAnsi(overflowStr, innerWidth)} ${colors.dim}\u2502${colors.reset}`);
593
+ }
594
+ rows.push(`${colors.dim}\u2502${colors.reset} ${' '.repeat(innerWidth)} ${colors.dim}\u2502${colors.reset}`);
595
+ const stats = `${colors.dim}${lineCount} line${lineCount === 1 ? '' : 's'} \u2022 ${charCount} character${charCount === 1 ? '' : 's'}${colors.reset}`;
596
+ rows.push(`${colors.dim}\u2502${colors.reset} ${padAnsi(stats, innerWidth)} ${colors.dim}\u2502${colors.reset}`);
597
+ rows.push(bottom);
598
+ return rows.join('\n');
599
+ }
600
+ // ---------------------------------------------------------------------------
601
+ // P7-F.1: Compose Mode Header
602
+ // ---------------------------------------------------------------------------
603
+ export function renderComposeHeader() {
604
+ const lines = [
605
+ `${colors.brightBlue}\u250c\u2500 NEXUS COMPOSE ${'─'.repeat(47)}\u2510${colors.reset}`,
606
+ `${colors.brightBlue}\u2502${colors.reset}${' '.repeat(63)}${colors.brightBlue}\u2502${colors.reset}`,
607
+ `${colors.brightBlue}\u2502${colors.reset} ${colors.bold}${colors.brightCyan}COMPOSE MODE${colors.reset} \u2014 Type or paste your complete task. ${colors.brightBlue}\u2502${colors.reset}`,
608
+ `${colors.brightBlue}\u2502${colors.reset}${' '.repeat(63)}${colors.brightBlue}\u2502${colors.reset}`,
609
+ `${colors.brightBlue}\u2502${colors.reset} Lines accumulate until you finish with one of: ${colors.brightBlue}\u2502${colors.reset}`,
610
+ `${colors.brightBlue}\u2502${colors.reset} ${colors.brightCyan}/send${colors.reset} \u2014 Submit the prompt ${colors.brightBlue}\u2502${colors.reset}`,
611
+ `${colors.brightBlue}\u2502${colors.reset} ${colors.brightYellow}/cancel${colors.reset} \u2014 Discard and return to normal mode ${colors.brightBlue}\u2502${colors.reset}`,
612
+ `${colors.brightBlue}\u2502${colors.reset} ${colors.dim}Ctrl+D${colors.reset} \u2014 Submit (EOF signal) ${colors.brightBlue}\u2502${colors.reset}`,
613
+ `${colors.brightBlue}\u2502${colors.reset}${' '.repeat(63)}${colors.brightBlue}\u2502${colors.reset}`,
614
+ `${colors.brightBlue}\u2514${'─'.repeat(63)}\u2518${colors.reset}`,
615
+ ];
616
+ return lines.join('\n');
617
+ }
618
+ // ---------------------------------------------------------------------------
619
+ // P7-G: Model Control & Status Screen Renderers
620
+ // ---------------------------------------------------------------------------
621
+ export function renderModelControlScreen(models, roleStatus, providerName = 'Embedded (Local)') {
622
+ const lines = [];
623
+ lines.push(drawDivider('─', 60));
624
+ lines.push(` ${colors.bold}${colors.brightCyan}NEXUS MODEL CONTROL${colors.reset}`);
625
+ lines.push(drawDivider('─', 60));
626
+ lines.push('');
627
+ lines.push(` ${colors.dim}Provider:${colors.reset} ${colors.bold}${colors.brightGreen}${providerName}${colors.reset} • ${colors.dim}Status:${colors.reset} ${colors.bold}${colors.brightGreen}READY${colors.reset}`);
628
+ lines.push('');
629
+ lines.push(`${colors.bold}AVAILABLE MODELS${colors.reset}`);
630
+ lines.push('');
631
+ if (models.length === 0) {
632
+ lines.push(` ${colors.brightYellow}No local models discovered.${colors.reset}`);
633
+ }
634
+ else {
635
+ models.forEach((m, idx) => {
636
+ lines.push(` ${colors.brightCyan}[${idx + 1}]${colors.reset} ${colors.bold}${m.name}${colors.reset}`);
637
+ lines.push(` ${colors.dim}${m.capabilities.join(' \u2022 ')}${colors.reset}`);
638
+ lines.push('');
639
+ });
640
+ }
641
+ lines.push(`${colors.bold}MODEL ROLES${colors.reset}`);
642
+ lines.push('');
643
+ const roles = [
644
+ { key: 'planner', label: 'Planner ' },
645
+ { key: 'coder', label: 'Coder ' },
646
+ { key: 'reasoning', label: 'Reasoning ' },
647
+ { key: 'chat', label: 'Chat ' },
648
+ ];
649
+ roles.forEach(({ key, label }) => {
650
+ const st = roleStatus[key];
651
+ const sourceBadge = st && st.source === 'USER'
652
+ ? ` ${colors.brightYellow}[USER]${colors.reset}`
653
+ : ` ${colors.dim}[AUTO]${colors.reset}`;
654
+ const modelDisplay = st
655
+ ? st.source === 'USER'
656
+ ? colors.bold + st.modelId + colors.reset
657
+ : colors.dim + st.modelId + colors.reset
658
+ : colors.dim + 'AUTO' + colors.reset;
659
+ lines.push(` ${label} \u2192 ${modelDisplay}${sourceBadge}`);
660
+ });
661
+ lines.push('');
662
+ lines.push(drawDivider('─', 60));
663
+ lines.push(`${colors.dim}Usage: /model <index|id> | /model <role> <index|id> | /model reset${colors.reset}`);
664
+ return lines.join('\n');
665
+ }
666
+ export function renderModelStatusScreen(roleStatus, globalOverride, runtimeVersion, modelCount = 0, providerName = 'Embedded (Local)') {
667
+ const lines = [];
668
+ lines.push(drawDivider('─', 60));
669
+ lines.push(` ${colors.bold}${colors.brightCyan}NEXUS MODEL CONFIGURATION${colors.reset}`);
670
+ lines.push(drawDivider('─', 60));
671
+ lines.push('');
672
+ lines.push(` Provider \u2192 ${colors.bold}${colors.brightGreen}${providerName}${colors.reset}`);
673
+ lines.push(` Global \u2192 ${globalOverride
674
+ ? colors.bold + colors.brightYellow + globalOverride + ' [USER]'
675
+ : colors.dim + 'AUTO'}${colors.reset}`);
676
+ lines.push('');
677
+ const roles = [
678
+ { key: 'planner', label: 'Planner ' },
679
+ { key: 'coder', label: 'Coder ' },
680
+ { key: 'reasoning', label: 'Reasoning ' },
681
+ { key: 'chat', label: 'Chat ' },
682
+ ];
683
+ roles.forEach(({ key, label }) => {
684
+ const st = roleStatus[key];
685
+ const sourceBadge = st && st.source === 'USER'
686
+ ? ` ${colors.brightYellow}[USER]${colors.reset}`
687
+ : ` ${colors.dim}[AUTO]${colors.reset}`;
688
+ const modelDisplay = st
689
+ ? st.source === 'USER'
690
+ ? colors.bold + st.modelId + colors.reset
691
+ : colors.dim + st.modelId + colors.reset
692
+ : colors.dim + 'AUTO' + colors.reset;
693
+ lines.push(` ${label} \u2192 ${modelDisplay}${sourceBadge}`);
694
+ });
695
+ lines.push('');
696
+ lines.push(` Runtime \u2192 ${providerName} (v${runtimeVersion || '0.1.0'})`);
697
+ lines.push(` Models \u2192 ${modelCount} available`);
698
+ lines.push('');
699
+ lines.push(drawDivider('─', 60));
700
+ return lines.join('\n');
701
+ }
702
+ // ---------------------------------------------------------------------------
703
+ // P7-H: Local Web Project Preview Renderers (/preview)
704
+ // ---------------------------------------------------------------------------
705
+ export function renderPreviewCard(result) {
706
+ const lines = [];
707
+ lines.push(drawDivider('─', 56));
708
+ lines.push(` ${colors.bold}${colors.brightCyan}NEXUS PREVIEW${colors.reset}`);
709
+ lines.push(drawDivider('─', 56));
710
+ lines.push('');
711
+ if (result.status === 'NO_COMPLETED_TASK') {
712
+ lines.push(` ${colors.brightRed}\u2716 No completed task is available to preview.${colors.reset}`);
713
+ lines.push('');
714
+ lines.push(` ${colors.dim}Complete a task that creates a supported previewable project first.${colors.reset}`);
715
+ lines.push(drawDivider('─', 56));
716
+ return lines.join('\n');
717
+ }
718
+ if (result.status === 'NOT_WEB_PROJECT') {
719
+ lines.push(` ${colors.brightYellow}\u26a0 Latest task does not contain a previewable web project.${colors.reset}`);
720
+ lines.push('');
721
+ if (result.task) {
722
+ lines.push(` ${colors.bold}Task:${colors.reset}`);
723
+ lines.push(` ${result.task.title}`);
724
+ lines.push('');
725
+ }
726
+ if (result.artifactsSummary && result.artifactsSummary.length > 0) {
727
+ lines.push(` ${colors.bold}Detected artifacts:${colors.reset}`);
728
+ result.artifactsSummary.forEach((art) => {
729
+ lines.push(` \u2022 ${art}`);
730
+ });
731
+ lines.push('');
732
+ }
733
+ lines.push(` ${colors.bold}Supported preview types currently include:${colors.reset}`);
734
+ lines.push(` HTML/CSS/JavaScript websites.`);
735
+ lines.push(drawDivider('─', 56));
736
+ return lines.join('\n');
737
+ }
738
+ if (result.status === 'MISSING_INDEX') {
739
+ lines.push(` ${colors.brightYellow}\u26a0 Cannot preview this project.${colors.reset}`);
740
+ lines.push('');
741
+ if (result.task) {
742
+ lines.push(` ${colors.bold}Task:${colors.reset}`);
743
+ lines.push(` ${result.task.title}`);
744
+ lines.push('');
745
+ }
746
+ lines.push(` ${colors.bold}Reason:${colors.reset}`);
747
+ lines.push(` No index.html entry point was found.`);
748
+ lines.push('');
749
+ if (result.detectedFiles && result.detectedFiles.length > 0) {
750
+ lines.push(` ${colors.bold}Detected files:${colors.reset}`);
751
+ result.detectedFiles.forEach((f) => {
752
+ lines.push(` \u2022 ${f}`);
753
+ });
754
+ lines.push('');
755
+ }
756
+ lines.push(` ${colors.dim}Add an index.html entry point to preview this project.${colors.reset}`);
757
+ lines.push(drawDivider('─', 56));
758
+ return lines.join('\n');
759
+ }
760
+ if (result.status === 'ERROR' || !result.success || !result.serverInfo) {
761
+ lines.push(` ${colors.brightRed}\u2716 Preview Launch Failed${colors.reset}`);
762
+ lines.push(` ${result.error || result.message || 'Unknown preview error'}`);
763
+ lines.push(drawDivider('─', 56));
764
+ return lines.join('\n');
765
+ }
766
+ // Status LAUNCHED
767
+ const taskTitle = result.task?.title || 'Web Project Task';
768
+ const projectFolder = result.serverInfo.projectDir.replace(/\\/g, '/').split('/').pop() || 'project';
769
+ const entry = result.serverInfo.entryFile || 'index.html';
770
+ lines.push(` ${colors.bold}Current Task${colors.reset}`);
771
+ lines.push(` ${taskTitle}`);
772
+ lines.push('');
773
+ lines.push(` ${colors.bold}Project${colors.reset}`);
774
+ lines.push(` ${projectFolder}`);
775
+ lines.push('');
776
+ lines.push(` ${colors.bold}Entry Point${colors.reset}`);
777
+ lines.push(` ${entry}`);
778
+ lines.push('');
779
+ if (result.detectedFiles && result.detectedFiles.length > 0) {
780
+ lines.push(` ${colors.bold}Files${colors.reset}`);
781
+ result.detectedFiles.forEach((f) => {
782
+ lines.push(` ${colors.brightGreen}\u2713${colors.reset} ${f}`);
783
+ });
784
+ lines.push('');
785
+ }
786
+ lines.push(` ${colors.bold}Preview Server${colors.reset}`);
787
+ lines.push(` ${colors.brightCyan}\u25cf Starting...${colors.reset}`);
788
+ lines.push('');
789
+ lines.push(` ${colors.bold}URL${colors.reset}`);
790
+ lines.push(` ${colors.brightGreen}${result.serverInfo.url}${colors.reset}`);
791
+ lines.push('');
792
+ lines.push(` ${colors.dim}Opening browser...${colors.reset}`);
793
+ lines.push('');
794
+ lines.push(` ${colors.brightGreen}\u2713 Preview launched successfully.${colors.reset}`);
795
+ lines.push(drawDivider('─', 56));
796
+ return lines.join('\n');
797
+ }
798
+ export function renderPreviewStatusCard(status) {
799
+ const lines = [];
800
+ lines.push(drawDivider('─', 56));
801
+ lines.push(` ${colors.bold}${colors.brightCyan}NEXUS PREVIEW STATUS${colors.reset}`);
802
+ lines.push(drawDivider('─', 56));
803
+ lines.push('');
804
+ if (!status.active || !status.serverInfo) {
805
+ lines.push(` ${colors.dim}No active preview server is currently running.${colors.reset}`);
806
+ lines.push(` ${colors.dim}Use /preview to launch preview for the latest completed task.${colors.reset}`);
807
+ lines.push(drawDivider('─', 56));
808
+ return lines.join('\n');
809
+ }
810
+ lines.push(` ${colors.bold}Status:${colors.reset} ${colors.brightGreen}\u25cf ACTIVE${colors.reset}`);
811
+ lines.push(` ${colors.bold}Task ID:${colors.reset} ${status.taskId || 'N/A'}`);
812
+ lines.push(` ${colors.bold}Task:${colors.reset} ${status.taskTitle || 'N/A'}`);
813
+ lines.push(` ${colors.bold}Port:${colors.reset} ${status.serverInfo.port}`);
814
+ lines.push(` ${colors.bold}URL:${colors.reset} ${colors.brightGreen}${status.serverInfo.url}${colors.reset}`);
815
+ lines.push(` ${colors.bold}Directory:${colors.reset} ${status.serverInfo.projectDir}`);
816
+ lines.push(` ${colors.bold}Entry File:${colors.reset} ${status.serverInfo.entryFile}`);
817
+ lines.push('');
818
+ lines.push(` ${colors.dim}Use /preview stop to terminate the preview server.${colors.reset}`);
819
+ lines.push(drawDivider('─', 56));
820
+ return lines.join('\n');
821
+ }
822
+ export function renderPreviewStoppedCard() {
823
+ const lines = [];
824
+ lines.push(drawDivider('─', 56));
825
+ lines.push(` ${colors.bold}${colors.brightCyan}NEXUS PREVIEW${colors.reset}`);
826
+ lines.push(drawDivider('─', 56));
827
+ lines.push(` ${colors.dim}\u2713 Preview server stopped successfully.${colors.reset}`);
828
+ lines.push(drawDivider('─', 56));
829
+ return lines.join('\n');
830
+ }
831
+ // ---------------------------------------------------------------------------
832
+ // Ollama Missing Banner — First-Run Actionable Error Screen (P7-J)
833
+ // ---------------------------------------------------------------------------
834
+ /**
835
+ * Renders a prominent, professional banner displayed on CLI startup
836
+ * when the Ollama AI runtime is not detected or not running.
837
+ *
838
+ * Designed for new users who have not yet installed Ollama.
839
+ * The CLI remains fully operational (help, commands etc.) — this is a
840
+ * non-blocking informational screen, not a crash.
841
+ */
842
+ export function renderOllamaMissingBanner(ollamaHost = 'http://127.0.0.1:11434') {
843
+ const lines = [];
844
+ const W = Math.min(termWidth(), 74);
845
+ lines.push('');
846
+ lines.push(`${colors.brightYellow}${'─'.repeat(W)}${colors.reset}`);
847
+ lines.push('');
848
+ lines.push(` ${colors.bold}${colors.brightYellow}\u26a0 NEXUS AI — ACTION REQUIRED${colors.reset}`);
849
+ lines.push('');
850
+ lines.push(`${colors.brightYellow}${'─'.repeat(W)}${colors.reset}`);
851
+ lines.push('');
852
+ lines.push(` ${colors.white}Ollama was not detected at:${colors.reset} ${colors.dim}${ollamaHost}${colors.reset}`);
853
+ lines.push('');
854
+ lines.push(` ${colors.white}NEXUS requires ${colors.brightCyan}Ollama${colors.reset}${colors.white} for local AI inference.${colors.reset}`);
855
+ lines.push(` ${colors.dim}Without it, tasks and AI commands will not work.${colors.reset}`);
856
+ lines.push('');
857
+ lines.push(` ${colors.bold}${colors.brightCyan}SETUP STEPS${colors.reset}`);
858
+ lines.push('');
859
+ lines.push(` ${colors.brightGreen}1.${colors.reset} Install Ollama:`);
860
+ lines.push(` ${colors.dim}https://ollama.com/download${colors.reset}`);
861
+ lines.push('');
862
+ lines.push(` ${colors.brightGreen}2.${colors.reset} Start Ollama:`);
863
+ lines.push(` ${colors.dim}ollama serve${colors.reset}`);
864
+ lines.push('');
865
+ lines.push(` ${colors.brightGreen}3.${colors.reset} Install a model:`);
866
+ lines.push(` ${colors.dim}ollama pull qwen2.5:3b${colors.reset}`);
867
+ lines.push('');
868
+ lines.push(` ${colors.brightGreen}4.${colors.reset} Restart NEXUS:`);
869
+ lines.push(` ${colors.dim}nexus${colors.reset}`);
870
+ lines.push('');
871
+ lines.push(`${colors.dim}${'─'.repeat(W)}${colors.reset}`);
872
+ lines.push(` ${colors.dim}You can still use /help, /models, /settings while Ollama is offline.${colors.reset}`);
873
+ lines.push(`${colors.dim}${'─'.repeat(W)}${colors.reset}`);
874
+ return lines.join('\n');
875
+ }
876
+ /**
877
+ * Phase 4: Renders First-Run Model Setup Screen for NEXUS CLI startup.
878
+ */
879
+ export function renderFirstRunSetupScreen(manifestName, sizeMb, reqStorageMb, warning) {
880
+ const lines = [];
881
+ const W = 60;
882
+ lines.push('');
883
+ lines.push(drawDivider('─', W));
884
+ lines.push(` ${colors.bold}${colors.brightCyan}NEXUS AI — FIRST TIME SETUP${colors.reset}`);
885
+ lines.push(drawDivider('─', W));
886
+ lines.push('');
887
+ lines.push(` ${colors.brightGreen}✓${colors.reset} NEXUS Workstation Installed`);
888
+ lines.push(` ${colors.brightGreen}✓${colors.reset} Embedded AI Runtime Ready`);
889
+ lines.push('');
890
+ lines.push(`${colors.bold}AI MODEL PROVISIONING${colors.reset}`);
891
+ lines.push(` ${colors.brightYellow}→ Production model is not installed.${colors.reset}`);
892
+ lines.push('');
893
+ lines.push(` ${colors.dim}Recommended Model:${colors.reset} ${colors.bold}${colors.brightCyan}${manifestName}${colors.reset}`);
894
+ lines.push(` ${colors.dim}Download Size:${colors.reset} ${colors.bold}${sizeMb} MB${colors.reset}`);
895
+ lines.push(` ${colors.dim}Required Storage:${colors.reset} ${colors.bold}${reqStorageMb} MB free disk space${colors.reset}`);
896
+ if (warning) {
897
+ lines.push('');
898
+ lines.push(` ${colors.brightYellow}\u26a0 ${warning}${colors.reset}`);
899
+ }
900
+ lines.push('');
901
+ lines.push(` ${colors.dim}Run ${colors.brightCyan}/model install${colors.reset} ${colors.dim}to download and provision local model files.${colors.reset}`);
902
+ lines.push(drawDivider('─', W));
903
+ return lines.join('\n');
904
+ }
905
+ /**
906
+ * Phase 4: Renders detailed model info card for /model info <id> command.
907
+ */
908
+ export function renderModelInfoCard(manifest, isInstalled) {
909
+ const lines = [];
910
+ const W = 60;
911
+ const sizeMb = Math.round(manifest.sizeBytes / (1024 * 1024));
912
+ lines.push(drawDivider('─', W));
913
+ lines.push(` ${colors.bold}${colors.brightCyan}MODEL DETAILS: ${manifest.id}${colors.reset}`);
914
+ lines.push(drawDivider('─', W));
915
+ lines.push(` Name → ${manifest.displayName}`);
916
+ lines.push(` Tier → ${manifest.tier.toUpperCase()}`);
917
+ lines.push(` Format → ${manifest.format.toUpperCase()} (Binary GGUF)`);
918
+ lines.push(` Size → ${sizeMb} MB`);
919
+ lines.push(` License → ${manifest.license}`);
920
+ lines.push(` Installed → ${isInstalled ? colors.brightGreen + 'YES (READY)' : colors.brightYellow + 'NO'}${colors.reset}`);
921
+ lines.push(` Description → ${manifest.description}`);
922
+ lines.push(drawDivider('─', W));
923
+ return lines.join('\n');
924
+ }
925
+ //# sourceMappingURL=uiFormatters.js.map