@nex-ai/nex 0.1.65 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (529) hide show
  1. package/README.md +190 -263
  2. package/bin/nex-mcp.js +50 -0
  3. package/bin/nex.js +53 -0
  4. package/package.json +15 -36
  5. package/dist/agent/adoption.d.ts +0 -23
  6. package/dist/agent/adoption.js +0 -87
  7. package/dist/agent/adoption.js.map +0 -1
  8. package/dist/agent/gossip.d.ts +0 -17
  9. package/dist/agent/gossip.js +0 -48
  10. package/dist/agent/gossip.js.map +0 -1
  11. package/dist/agent/loop.d.ts +0 -59
  12. package/dist/agent/loop.js +0 -389
  13. package/dist/agent/loop.js.map +0 -1
  14. package/dist/agent/queues.d.ts +0 -16
  15. package/dist/agent/queues.js +0 -44
  16. package/dist/agent/queues.js.map +0 -1
  17. package/dist/agent/session-store.d.ts +0 -21
  18. package/dist/agent/session-store.js +0 -96
  19. package/dist/agent/session-store.js.map +0 -1
  20. package/dist/agent/templates.d.ts +0 -5
  21. package/dist/agent/templates.js +0 -55
  22. package/dist/agent/templates.js.map +0 -1
  23. package/dist/agent/tools.d.ts +0 -25
  24. package/dist/agent/tools.js +0 -238
  25. package/dist/agent/tools.js.map +0 -1
  26. package/dist/agent/types.d.ts +0 -59
  27. package/dist/agent/types.js +0 -5
  28. package/dist/agent/types.js.map +0 -1
  29. package/dist/calendar/scheduler.d.ts +0 -32
  30. package/dist/calendar/scheduler.js +0 -178
  31. package/dist/calendar/scheduler.js.map +0 -1
  32. package/dist/calendar/store.d.ts +0 -15
  33. package/dist/calendar/store.js +0 -50
  34. package/dist/calendar/store.js.map +0 -1
  35. package/dist/calendar/types.d.ts +0 -17
  36. package/dist/calendar/types.js +0 -5
  37. package/dist/calendar/types.js.map +0 -1
  38. package/dist/chat/channel.d.ts +0 -20
  39. package/dist/chat/channel.js +0 -84
  40. package/dist/chat/channel.js.map +0 -1
  41. package/dist/chat/message-store.d.ts +0 -18
  42. package/dist/chat/message-store.js +0 -82
  43. package/dist/chat/message-store.js.map +0 -1
  44. package/dist/chat/router.d.ts +0 -17
  45. package/dist/chat/router.js +0 -65
  46. package/dist/chat/router.js.map +0 -1
  47. package/dist/chat/suggested-responses.d.ts +0 -6
  48. package/dist/chat/suggested-responses.js +0 -99
  49. package/dist/chat/suggested-responses.js.map +0 -1
  50. package/dist/chat/types.d.ts +0 -28
  51. package/dist/chat/types.js +0 -5
  52. package/dist/chat/types.js.map +0 -1
  53. package/dist/cli.d.ts +0 -5
  54. package/dist/cli.js +0 -20
  55. package/dist/cli.js.map +0 -1
  56. package/dist/commands/attribute.d.ts +0 -4
  57. package/dist/commands/attribute.js +0 -75
  58. package/dist/commands/attribute.js.map +0 -1
  59. package/dist/commands/config-cmd.d.ts +0 -4
  60. package/dist/commands/config-cmd.js +0 -53
  61. package/dist/commands/config-cmd.js.map +0 -1
  62. package/dist/commands/context.d.ts +0 -4
  63. package/dist/commands/context.js +0 -167
  64. package/dist/commands/context.js.map +0 -1
  65. package/dist/commands/dispatch.d.ts +0 -44
  66. package/dist/commands/dispatch.js +0 -1544
  67. package/dist/commands/dispatch.js.map +0 -1
  68. package/dist/commands/graph.d.ts +0 -5
  69. package/dist/commands/graph.js +0 -77
  70. package/dist/commands/graph.js.map +0 -1
  71. package/dist/commands/init.d.ts +0 -49
  72. package/dist/commands/init.js +0 -319
  73. package/dist/commands/init.js.map +0 -1
  74. package/dist/commands/insight.d.ts +0 -4
  75. package/dist/commands/insight.js +0 -39
  76. package/dist/commands/insight.js.map +0 -1
  77. package/dist/commands/integrate.d.ts +0 -4
  78. package/dist/commands/integrate.js +0 -361
  79. package/dist/commands/integrate.js.map +0 -1
  80. package/dist/commands/list-job.d.ts +0 -4
  81. package/dist/commands/list-job.js +0 -41
  82. package/dist/commands/list-job.js.map +0 -1
  83. package/dist/commands/list.d.ts +0 -4
  84. package/dist/commands/list.js +0 -148
  85. package/dist/commands/list.js.map +0 -1
  86. package/dist/commands/note.d.ts +0 -4
  87. package/dist/commands/note.js +0 -77
  88. package/dist/commands/note.js.map +0 -1
  89. package/dist/commands/object.d.ts +0 -4
  90. package/dist/commands/object.js +0 -78
  91. package/dist/commands/object.js.map +0 -1
  92. package/dist/commands/parse-input.d.ts +0 -5
  93. package/dist/commands/parse-input.js +0 -37
  94. package/dist/commands/parse-input.js.map +0 -1
  95. package/dist/commands/record.d.ts +0 -4
  96. package/dist/commands/record.js +0 -126
  97. package/dist/commands/record.js.map +0 -1
  98. package/dist/commands/register.d.ts +0 -4
  99. package/dist/commands/register.js +0 -23
  100. package/dist/commands/register.js.map +0 -1
  101. package/dist/commands/relationship.d.ts +0 -4
  102. package/dist/commands/relationship.js +0 -80
  103. package/dist/commands/relationship.js.map +0 -1
  104. package/dist/commands/scan.d.ts +0 -4
  105. package/dist/commands/scan.js +0 -111
  106. package/dist/commands/scan.js.map +0 -1
  107. package/dist/commands/search.d.ts +0 -4
  108. package/dist/commands/search.js +0 -62
  109. package/dist/commands/search.js.map +0 -1
  110. package/dist/commands/session.d.ts +0 -4
  111. package/dist/commands/session.js +0 -31
  112. package/dist/commands/session.js.map +0 -1
  113. package/dist/commands/setup.d.ts +0 -25
  114. package/dist/commands/setup.js +0 -584
  115. package/dist/commands/setup.js.map +0 -1
  116. package/dist/commands/task.d.ts +0 -4
  117. package/dist/commands/task.js +0 -140
  118. package/dist/commands/task.js.map +0 -1
  119. package/dist/commands/workspace.d.ts +0 -8
  120. package/dist/commands/workspace.js +0 -251
  121. package/dist/commands/workspace.js.map +0 -1
  122. package/dist/index.d.ts +0 -9
  123. package/dist/index.js +0 -142
  124. package/dist/index.js.map +0 -1
  125. package/dist/lib/capture-filter.d.ts +0 -9
  126. package/dist/lib/capture-filter.js +0 -14
  127. package/dist/lib/capture-filter.js.map +0 -1
  128. package/dist/lib/client.d.ts +0 -20
  129. package/dist/lib/client.js +0 -160
  130. package/dist/lib/client.js.map +0 -1
  131. package/dist/lib/compounding-worker.d.ts +0 -2
  132. package/dist/lib/compounding-worker.js +0 -21
  133. package/dist/lib/compounding-worker.js.map +0 -1
  134. package/dist/lib/compounding.d.ts +0 -20
  135. package/dist/lib/compounding.js +0 -45
  136. package/dist/lib/compounding.js.map +0 -1
  137. package/dist/lib/config.d.ts +0 -35
  138. package/dist/lib/config.js +0 -96
  139. package/dist/lib/config.js.map +0 -1
  140. package/dist/lib/context-format.d.ts +0 -7
  141. package/dist/lib/context-format.js +0 -21
  142. package/dist/lib/context-format.js.map +0 -1
  143. package/dist/lib/errors.d.ts +0 -18
  144. package/dist/lib/errors.js +0 -30
  145. package/dist/lib/errors.js.map +0 -1
  146. package/dist/lib/file-scanner.d.ts +0 -38
  147. package/dist/lib/file-scanner.js +0 -188
  148. package/dist/lib/file-scanner.js.map +0 -1
  149. package/dist/lib/graph-html.d.ts +0 -59
  150. package/dist/lib/graph-html.js +0 -859
  151. package/dist/lib/graph-html.js.map +0 -1
  152. package/dist/lib/installers.d.ts +0 -80
  153. package/dist/lib/installers.js +0 -602
  154. package/dist/lib/installers.js.map +0 -1
  155. package/dist/lib/integrations.d.ts +0 -23
  156. package/dist/lib/integrations.js +0 -25
  157. package/dist/lib/integrations.js.map +0 -1
  158. package/dist/lib/output.d.ts +0 -7
  159. package/dist/lib/output.js +0 -70
  160. package/dist/lib/output.js.map +0 -1
  161. package/dist/lib/platform-detect.d.ts +0 -23
  162. package/dist/lib/platform-detect.js +0 -359
  163. package/dist/lib/platform-detect.js.map +0 -1
  164. package/dist/lib/project-config.d.ts +0 -53
  165. package/dist/lib/project-config.js +0 -151
  166. package/dist/lib/project-config.js.map +0 -1
  167. package/dist/lib/prompt.d.ts +0 -15
  168. package/dist/lib/prompt.js +0 -213
  169. package/dist/lib/prompt.js.map +0 -1
  170. package/dist/lib/rate-limiter.d.ts +0 -13
  171. package/dist/lib/rate-limiter.js +0 -49
  172. package/dist/lib/rate-limiter.js.map +0 -1
  173. package/dist/lib/recall-filter.d.ts +0 -5
  174. package/dist/lib/recall-filter.js +0 -24
  175. package/dist/lib/recall-filter.js.map +0 -1
  176. package/dist/lib/session-store.d.ts +0 -15
  177. package/dist/lib/session-store.js +0 -62
  178. package/dist/lib/session-store.js.map +0 -1
  179. package/dist/lib/tui.d.ts +0 -57
  180. package/dist/lib/tui.js +0 -247
  181. package/dist/lib/tui.js.map +0 -1
  182. package/dist/lib/workspace-registry.d.ts +0 -47
  183. package/dist/lib/workspace-registry.js +0 -240
  184. package/dist/lib/workspace-registry.js.map +0 -1
  185. package/dist/mcp/channel.d.ts +0 -24
  186. package/dist/mcp/channel.js +0 -198
  187. package/dist/mcp/channel.js.map +0 -1
  188. package/dist/mcp/client.d.ts +0 -20
  189. package/dist/mcp/client.js +0 -131
  190. package/dist/mcp/client.js.map +0 -1
  191. package/dist/mcp/config.d.ts +0 -19
  192. package/dist/mcp/config.js +0 -48
  193. package/dist/mcp/config.js.map +0 -1
  194. package/dist/mcp/context-files.d.ts +0 -9
  195. package/dist/mcp/context-files.js +0 -90
  196. package/dist/mcp/context-files.js.map +0 -1
  197. package/dist/mcp/file-manifest.d.ts +0 -27
  198. package/dist/mcp/file-manifest.js +0 -68
  199. package/dist/mcp/file-manifest.js.map +0 -1
  200. package/dist/mcp/file-scanner.d.ts +0 -17
  201. package/dist/mcp/file-scanner.js +0 -77
  202. package/dist/mcp/file-scanner.js.map +0 -1
  203. package/dist/mcp/index.d.ts +0 -2
  204. package/dist/mcp/index.js +0 -51
  205. package/dist/mcp/index.js.map +0 -1
  206. package/dist/mcp/rate-limiter.d.ts +0 -14
  207. package/dist/mcp/rate-limiter.js +0 -60
  208. package/dist/mcp/rate-limiter.js.map +0 -1
  209. package/dist/mcp/server.d.ts +0 -6
  210. package/dist/mcp/server.js +0 -44
  211. package/dist/mcp/server.js.map +0 -1
  212. package/dist/mcp/session-store.d.ts +0 -16
  213. package/dist/mcp/session-store.js +0 -70
  214. package/dist/mcp/session-store.js.map +0 -1
  215. package/dist/mcp/tools/context.d.ts +0 -3
  216. package/dist/mcp/tools/context.js +0 -65
  217. package/dist/mcp/tools/context.js.map +0 -1
  218. package/dist/mcp/tools/insights.d.ts +0 -3
  219. package/dist/mcp/tools/insights.js +0 -24
  220. package/dist/mcp/tools/insights.js.map +0 -1
  221. package/dist/mcp/tools/integrations.d.ts +0 -3
  222. package/dist/mcp/tools/integrations.js +0 -27
  223. package/dist/mcp/tools/integrations.js.map +0 -1
  224. package/dist/mcp/tools/lists.d.ts +0 -3
  225. package/dist/mcp/tools/lists.js +0 -101
  226. package/dist/mcp/tools/lists.js.map +0 -1
  227. package/dist/mcp/tools/notes.d.ts +0 -3
  228. package/dist/mcp/tools/notes.js +0 -52
  229. package/dist/mcp/tools/notes.js.map +0 -1
  230. package/dist/mcp/tools/notifications.d.ts +0 -3
  231. package/dist/mcp/tools/notifications.js +0 -53
  232. package/dist/mcp/tools/notifications.js.map +0 -1
  233. package/dist/mcp/tools/records.d.ts +0 -3
  234. package/dist/mcp/tools/records.js +0 -74
  235. package/dist/mcp/tools/records.js.map +0 -1
  236. package/dist/mcp/tools/register.d.ts +0 -3
  237. package/dist/mcp/tools/register.js +0 -41
  238. package/dist/mcp/tools/register.js.map +0 -1
  239. package/dist/mcp/tools/relationships.d.ts +0 -3
  240. package/dist/mcp/tools/relationships.js +0 -47
  241. package/dist/mcp/tools/relationships.js.map +0 -1
  242. package/dist/mcp/tools/scan.d.ts +0 -3
  243. package/dist/mcp/tools/scan.js +0 -37
  244. package/dist/mcp/tools/scan.js.map +0 -1
  245. package/dist/mcp/tools/schema.d.ts +0 -3
  246. package/dist/mcp/tools/schema.js +0 -108
  247. package/dist/mcp/tools/schema.js.map +0 -1
  248. package/dist/mcp/tools/search.d.ts +0 -3
  249. package/dist/mcp/tools/search.js +0 -8
  250. package/dist/mcp/tools/search.js.map +0 -1
  251. package/dist/mcp/tools/tasks.d.ts +0 -3
  252. package/dist/mcp/tools/tasks.js +0 -88
  253. package/dist/mcp/tools/tasks.js.map +0 -1
  254. package/dist/mcp/workspace-data-dir.d.ts +0 -2
  255. package/dist/mcp/workspace-data-dir.js +0 -28
  256. package/dist/mcp/workspace-data-dir.js.map +0 -1
  257. package/dist/orchestration/budget.d.ts +0 -32
  258. package/dist/orchestration/budget.js +0 -72
  259. package/dist/orchestration/budget.js.map +0 -1
  260. package/dist/orchestration/executor.d.ts +0 -59
  261. package/dist/orchestration/executor.js +0 -197
  262. package/dist/orchestration/executor.js.map +0 -1
  263. package/dist/orchestration/router.d.ts +0 -30
  264. package/dist/orchestration/router.js +0 -98
  265. package/dist/orchestration/router.js.map +0 -1
  266. package/dist/orchestration/templates.d.ts +0 -11
  267. package/dist/orchestration/templates.js +0 -99
  268. package/dist/orchestration/templates.js.map +0 -1
  269. package/dist/orchestration/types.d.ts +0 -58
  270. package/dist/orchestration/types.js +0 -7
  271. package/dist/orchestration/types.js.map +0 -1
  272. package/dist/plugin/auto-capture.d.ts +0 -11
  273. package/dist/plugin/auto-capture.js +0 -135
  274. package/dist/plugin/auto-capture.js.map +0 -1
  275. package/dist/plugin/auto-recall-worker.d.ts +0 -2
  276. package/dist/plugin/auto-recall-worker.js +0 -74
  277. package/dist/plugin/auto-recall-worker.js.map +0 -1
  278. package/dist/plugin/auto-recall.d.ts +0 -11
  279. package/dist/plugin/auto-recall.js +0 -186
  280. package/dist/plugin/auto-recall.js.map +0 -1
  281. package/dist/plugin/auto-register.d.ts +0 -10
  282. package/dist/plugin/auto-register.js +0 -81
  283. package/dist/plugin/auto-register.js.map +0 -1
  284. package/dist/plugin/auto-scan.d.ts +0 -10
  285. package/dist/plugin/auto-scan.js +0 -54
  286. package/dist/plugin/auto-scan.js.map +0 -1
  287. package/dist/plugin/auto-session-start.d.ts +0 -14
  288. package/dist/plugin/auto-session-start.js +0 -156
  289. package/dist/plugin/auto-session-start.js.map +0 -1
  290. package/dist/plugin/capture-filter.d.ts +0 -21
  291. package/dist/plugin/capture-filter.js +0 -32
  292. package/dist/plugin/capture-filter.js.map +0 -1
  293. package/dist/plugin/config.d.ts +0 -61
  294. package/dist/plugin/config.js +0 -182
  295. package/dist/plugin/config.js.map +0 -1
  296. package/dist/plugin/context-files.d.ts +0 -23
  297. package/dist/plugin/context-files.js +0 -103
  298. package/dist/plugin/context-files.js.map +0 -1
  299. package/dist/plugin/context-format.d.ts +0 -18
  300. package/dist/plugin/context-format.js +0 -34
  301. package/dist/plugin/context-format.js.map +0 -1
  302. package/dist/plugin/file-manifest.d.ts +0 -27
  303. package/dist/plugin/file-manifest.js +0 -68
  304. package/dist/plugin/file-manifest.js.map +0 -1
  305. package/dist/plugin/file-scanner.d.ts +0 -19
  306. package/dist/plugin/file-scanner.js +0 -90
  307. package/dist/plugin/file-scanner.js.map +0 -1
  308. package/dist/plugin/nex-client.d.ts +0 -50
  309. package/dist/plugin/nex-client.js +0 -129
  310. package/dist/plugin/nex-client.js.map +0 -1
  311. package/dist/plugin/rate-limiter.d.ts +0 -26
  312. package/dist/plugin/rate-limiter.js +0 -65
  313. package/dist/plugin/rate-limiter.js.map +0 -1
  314. package/dist/plugin/recall-cache.d.ts +0 -41
  315. package/dist/plugin/recall-cache.js +0 -195
  316. package/dist/plugin/recall-cache.js.map +0 -1
  317. package/dist/plugin/recall-filter.d.ts +0 -13
  318. package/dist/plugin/recall-filter.js +0 -39
  319. package/dist/plugin/recall-filter.js.map +0 -1
  320. package/dist/plugin/session-store.d.ts +0 -23
  321. package/dist/plugin/session-store.js +0 -73
  322. package/dist/plugin/session-store.js.map +0 -1
  323. package/dist/plugin/workspace-data-dir.d.ts +0 -2
  324. package/dist/plugin/workspace-data-dir.js +0 -31
  325. package/dist/plugin/workspace-data-dir.js.map +0 -1
  326. package/dist/tui/agent-colors.d.ts +0 -19
  327. package/dist/tui/agent-colors.js +0 -34
  328. package/dist/tui/agent-colors.js.map +0 -1
  329. package/dist/tui/app.d.ts +0 -14
  330. package/dist/tui/app.js +0 -181
  331. package/dist/tui/app.js.map +0 -1
  332. package/dist/tui/channel-colors.d.ts +0 -16
  333. package/dist/tui/channel-colors.js +0 -43
  334. package/dist/tui/channel-colors.js.map +0 -1
  335. package/dist/tui/components/agent-card.d.ts +0 -11
  336. package/dist/tui/components/agent-card.js +0 -40
  337. package/dist/tui/components/agent-card.js.map +0 -1
  338. package/dist/tui/components/banner.d.ts +0 -44
  339. package/dist/tui/components/banner.js +0 -130
  340. package/dist/tui/components/banner.js.map +0 -1
  341. package/dist/tui/components/channel-colors.d.ts +0 -21
  342. package/dist/tui/components/channel-colors.js +0 -53
  343. package/dist/tui/components/channel-colors.js.map +0 -1
  344. package/dist/tui/components/channel-message.d.ts +0 -53
  345. package/dist/tui/components/channel-message.js +0 -66
  346. package/dist/tui/components/channel-message.js.map +0 -1
  347. package/dist/tui/components/chat-input.d.ts +0 -11
  348. package/dist/tui/components/chat-input.js +0 -19
  349. package/dist/tui/components/chat-input.js.map +0 -1
  350. package/dist/tui/components/data-table.d.ts +0 -11
  351. package/dist/tui/components/data-table.js +0 -47
  352. package/dist/tui/components/data-table.js.map +0 -1
  353. package/dist/tui/components/error-box.d.ts +0 -11
  354. package/dist/tui/components/error-box.js +0 -59
  355. package/dist/tui/components/error-box.js.map +0 -1
  356. package/dist/tui/components/help-screen.d.ts +0 -3
  357. package/dist/tui/components/help-screen.js +0 -63
  358. package/dist/tui/components/help-screen.js.map +0 -1
  359. package/dist/tui/components/index.d.ts +0 -17
  360. package/dist/tui/components/index.js +0 -10
  361. package/dist/tui/components/index.js.map +0 -1
  362. package/dist/tui/components/inline-confirm.d.ts +0 -14
  363. package/dist/tui/components/inline-confirm.js +0 -13
  364. package/dist/tui/components/inline-confirm.js.map +0 -1
  365. package/dist/tui/components/inline-select.d.ts +0 -21
  366. package/dist/tui/components/inline-select.js +0 -20
  367. package/dist/tui/components/inline-select.js.map +0 -1
  368. package/dist/tui/components/markdown.d.ts +0 -6
  369. package/dist/tui/components/markdown.js +0 -179
  370. package/dist/tui/components/markdown.js.map +0 -1
  371. package/dist/tui/components/mention-autocomplete.d.ts +0 -79
  372. package/dist/tui/components/mention-autocomplete.js +0 -250
  373. package/dist/tui/components/mention-autocomplete.js.map +0 -1
  374. package/dist/tui/components/message-list.d.ts +0 -18
  375. package/dist/tui/components/message-list.js +0 -29
  376. package/dist/tui/components/message-list.js.map +0 -1
  377. package/dist/tui/components/picker.d.ts +0 -16
  378. package/dist/tui/components/picker.js +0 -32
  379. package/dist/tui/components/picker.js.map +0 -1
  380. package/dist/tui/components/progress-steps.d.ts +0 -13
  381. package/dist/tui/components/progress-steps.js +0 -21
  382. package/dist/tui/components/progress-steps.js.map +0 -1
  383. package/dist/tui/components/slack/compose.d.ts +0 -27
  384. package/dist/tui/components/slack/compose.js +0 -147
  385. package/dist/tui/components/slack/compose.js.map +0 -1
  386. package/dist/tui/components/slack/layout.d.ts +0 -36
  387. package/dist/tui/components/slack/layout.js +0 -96
  388. package/dist/tui/components/slack/layout.js.map +0 -1
  389. package/dist/tui/components/slack/messages.d.ts +0 -72
  390. package/dist/tui/components/slack/messages.js +0 -177
  391. package/dist/tui/components/slack/messages.js.map +0 -1
  392. package/dist/tui/components/slack/quick-switcher.d.ts +0 -33
  393. package/dist/tui/components/slack/quick-switcher.js +0 -98
  394. package/dist/tui/components/slack/quick-switcher.js.map +0 -1
  395. package/dist/tui/components/slack/sidebar-types.d.ts +0 -65
  396. package/dist/tui/components/slack/sidebar-types.js +0 -7
  397. package/dist/tui/components/slack/sidebar-types.js.map +0 -1
  398. package/dist/tui/components/slack/sidebar.d.ts +0 -46
  399. package/dist/tui/components/slack/sidebar.js +0 -52
  400. package/dist/tui/components/slack/sidebar.js.map +0 -1
  401. package/dist/tui/components/slack/thread-panel.d.ts +0 -45
  402. package/dist/tui/components/slack/thread-panel.js +0 -47
  403. package/dist/tui/components/slack/thread-panel.js.map +0 -1
  404. package/dist/tui/components/slash-autocomplete.d.ts +0 -83
  405. package/dist/tui/components/slash-autocomplete.js +0 -233
  406. package/dist/tui/components/slash-autocomplete.js.map +0 -1
  407. package/dist/tui/components/spinner.d.ts +0 -17
  408. package/dist/tui/components/spinner.js +0 -30
  409. package/dist/tui/components/spinner.js.map +0 -1
  410. package/dist/tui/components/status-bar.d.ts +0 -23
  411. package/dist/tui/components/status-bar.js +0 -55
  412. package/dist/tui/components/status-bar.js.map +0 -1
  413. package/dist/tui/components/success-box.d.ts +0 -7
  414. package/dist/tui/components/success-box.js +0 -10
  415. package/dist/tui/components/success-box.js.map +0 -1
  416. package/dist/tui/components/tool-indicator.d.ts +0 -12
  417. package/dist/tui/components/tool-indicator.js +0 -18
  418. package/dist/tui/components/tool-indicator.js.map +0 -1
  419. package/dist/tui/components/viewport.d.ts +0 -9
  420. package/dist/tui/components/viewport.js +0 -24
  421. package/dist/tui/components/viewport.js.map +0 -1
  422. package/dist/tui/generative/bindings.d.ts +0 -27
  423. package/dist/tui/generative/bindings.js +0 -152
  424. package/dist/tui/generative/bindings.js.map +0 -1
  425. package/dist/tui/generative/registry.d.ts +0 -19
  426. package/dist/tui/generative/registry.js +0 -31
  427. package/dist/tui/generative/registry.js.map +0 -1
  428. package/dist/tui/generative/renderer.d.ts +0 -24
  429. package/dist/tui/generative/renderer.js +0 -160
  430. package/dist/tui/generative/renderer.js.map +0 -1
  431. package/dist/tui/generative/types.d.ts +0 -68
  432. package/dist/tui/generative/types.js +0 -7
  433. package/dist/tui/generative/types.js.map +0 -1
  434. package/dist/tui/hooks/use-cancellable.d.ts +0 -28
  435. package/dist/tui/hooks/use-cancellable.js +0 -51
  436. package/dist/tui/hooks/use-cancellable.js.map +0 -1
  437. package/dist/tui/hooks/use-streaming.d.ts +0 -44
  438. package/dist/tui/hooks/use-streaming.js +0 -105
  439. package/dist/tui/hooks/use-streaming.js.map +0 -1
  440. package/dist/tui/index.d.ts +0 -4
  441. package/dist/tui/index.js +0 -7
  442. package/dist/tui/index.js.map +0 -1
  443. package/dist/tui/keybindings.d.ts +0 -25
  444. package/dist/tui/keybindings.js +0 -277
  445. package/dist/tui/keybindings.js.map +0 -1
  446. package/dist/tui/register-views.d.ts +0 -8
  447. package/dist/tui/register-views.js +0 -122
  448. package/dist/tui/register-views.js.map +0 -1
  449. package/dist/tui/router.d.ts +0 -29
  450. package/dist/tui/router.js +0 -87
  451. package/dist/tui/router.js.map +0 -1
  452. package/dist/tui/services/agent-service.d.ts +0 -58
  453. package/dist/tui/services/agent-service.js +0 -197
  454. package/dist/tui/services/agent-service.js.map +0 -1
  455. package/dist/tui/services/calendar-service.d.ts +0 -31
  456. package/dist/tui/services/calendar-service.js +0 -133
  457. package/dist/tui/services/calendar-service.js.map +0 -1
  458. package/dist/tui/services/chat-service.d.ts +0 -28
  459. package/dist/tui/services/chat-service.js +0 -91
  460. package/dist/tui/services/chat-service.js.map +0 -1
  461. package/dist/tui/services/orchestration-service.d.ts +0 -42
  462. package/dist/tui/services/orchestration-service.js +0 -153
  463. package/dist/tui/services/orchestration-service.js.map +0 -1
  464. package/dist/tui/slash-commands.d.ts +0 -106
  465. package/dist/tui/slash-commands.js +0 -1421
  466. package/dist/tui/slash-commands.js.map +0 -1
  467. package/dist/tui/store.d.ts +0 -96
  468. package/dist/tui/store.js +0 -120
  469. package/dist/tui/store.js.map +0 -1
  470. package/dist/tui/theme.d.ts +0 -40
  471. package/dist/tui/theme.js +0 -39
  472. package/dist/tui/theme.js.map +0 -1
  473. package/dist/tui/tui-context.d.ts +0 -22
  474. package/dist/tui/tui-context.js +0 -17
  475. package/dist/tui/tui-context.js.map +0 -1
  476. package/dist/tui/views/agent-list.d.ts +0 -8
  477. package/dist/tui/views/agent-list.js +0 -11
  478. package/dist/tui/views/agent-list.js.map +0 -1
  479. package/dist/tui/views/ask-chat.d.ts +0 -9
  480. package/dist/tui/views/ask-chat.js +0 -40
  481. package/dist/tui/views/ask-chat.js.map +0 -1
  482. package/dist/tui/views/calendar.d.ts +0 -15
  483. package/dist/tui/views/calendar.js +0 -29
  484. package/dist/tui/views/calendar.js.map +0 -1
  485. package/dist/tui/views/chat.d.ts +0 -18
  486. package/dist/tui/views/chat.js +0 -28
  487. package/dist/tui/views/chat.js.map +0 -1
  488. package/dist/tui/views/generative.d.ts +0 -14
  489. package/dist/tui/views/generative.js +0 -37
  490. package/dist/tui/views/generative.js.map +0 -1
  491. package/dist/tui/views/help.d.ts +0 -6
  492. package/dist/tui/views/help.js +0 -9
  493. package/dist/tui/views/help.js.map +0 -1
  494. package/dist/tui/views/home-screen.d.ts +0 -67
  495. package/dist/tui/views/home-screen.js +0 -192
  496. package/dist/tui/views/home-screen.js.map +0 -1
  497. package/dist/tui/views/home.d.ts +0 -33
  498. package/dist/tui/views/home.js +0 -60
  499. package/dist/tui/views/home.js.map +0 -1
  500. package/dist/tui/views/index.d.ts +0 -20
  501. package/dist/tui/views/index.js +0 -11
  502. package/dist/tui/views/index.js.map +0 -1
  503. package/dist/tui/views/insights.d.ts +0 -19
  504. package/dist/tui/views/insights.js +0 -46
  505. package/dist/tui/views/insights.js.map +0 -1
  506. package/dist/tui/views/orchestration.d.ts +0 -18
  507. package/dist/tui/views/orchestration.js +0 -73
  508. package/dist/tui/views/orchestration.js.map +0 -1
  509. package/dist/tui/views/record-detail.d.ts +0 -10
  510. package/dist/tui/views/record-detail.js +0 -22
  511. package/dist/tui/views/record-detail.js.map +0 -1
  512. package/dist/tui/views/record-list.d.ts +0 -15
  513. package/dist/tui/views/record-list.js +0 -22
  514. package/dist/tui/views/record-list.js.map +0 -1
  515. package/dist/tui/views/slack-channel-header.d.ts +0 -15
  516. package/dist/tui/views/slack-channel-header.js +0 -16
  517. package/dist/tui/views/slack-channel-header.js.map +0 -1
  518. package/dist/tui/views/slack-home.d.ts +0 -21
  519. package/dist/tui/views/slack-home.js +0 -572
  520. package/dist/tui/views/slack-home.js.map +0 -1
  521. package/dist/tui/views/stream.d.ts +0 -16
  522. package/dist/tui/views/stream.js +0 -210
  523. package/dist/tui/views/stream.js.map +0 -1
  524. package/dist/tui/views/task-board.d.ts +0 -21
  525. package/dist/tui/views/task-board.js +0 -33
  526. package/dist/tui/views/task-board.js.map +0 -1
  527. package/dist/tui/views/timeline.d.ts +0 -17
  528. package/dist/tui/views/timeline.js +0 -24
  529. package/dist/tui/views/timeline.js.map +0 -1
@@ -1,1421 +0,0 @@
1
- /**
2
- * Slash command registry for the conversation-first TUI.
3
- *
4
- * Slash commands (/help, /agents, etc.) are the explicit navigation model.
5
- * Natural language input goes to the Pi agent via dispatch("ask ...").
6
- */
7
- // ── Registry ────────────────────────────────────────────────────────
8
- const commands = new Map();
9
- export function registerSlashCommand(cmd) {
10
- commands.set(cmd.name, cmd);
11
- }
12
- export function getSlashCommand(name) {
13
- return commands.get(name);
14
- }
15
- export function listSlashCommands() {
16
- return Array.from(commands.values());
17
- }
18
- /**
19
- * Parse raw input to determine if it is a slash command.
20
- * Returns `{ isSlash: true, command, args }` for "/foo bar baz",
21
- * or `{ isSlash: false }` for everything else.
22
- */
23
- export function parseSlashInput(input) {
24
- const trimmed = input.trim();
25
- if (!trimmed.startsWith("/"))
26
- return { isSlash: false };
27
- const withoutSlash = trimmed.slice(1);
28
- const spaceIdx = withoutSlash.indexOf(" ");
29
- if (spaceIdx === -1) {
30
- return { isSlash: true, command: withoutSlash, args: "" };
31
- }
32
- return {
33
- isSlash: true,
34
- command: withoutSlash.slice(0, spaceIdx),
35
- args: withoutSlash.slice(spaceIdx + 1).trim(),
36
- };
37
- }
38
- let initState = { phase: "idle" };
39
- export function getInitState() {
40
- return initState;
41
- }
42
- export function resetInitState() {
43
- initState = { phase: "idle" };
44
- }
45
- /**
46
- * Run platform detection and installation (non-interactive).
47
- * Called after we have a validated API key.
48
- */
49
- async function runPlatformInstall(apiKey, ctx) {
50
- ctx.setLoading(true, "Detecting platforms...");
51
- const { detectPlatforms, installForPlatform } = await import("../commands/init.js");
52
- const { syncApiKeyToMcpConfig } = await import("../lib/installers.js");
53
- // Sync API key to ~/.nex/config.json
54
- syncApiKeyToMcpConfig(apiKey);
55
- let platforms;
56
- try {
57
- platforms = detectPlatforms().filter((p) => p.detected);
58
- }
59
- catch (err) {
60
- ctx.setLoading(false);
61
- ctx.addMessage({
62
- id: `init-detect-err-${Date.now()}`,
63
- role: "system",
64
- content: `Platform detection failed: ${err instanceof Error ? err.message : String(err)}`,
65
- timestamp: Date.now(),
66
- isError: true,
67
- });
68
- return;
69
- }
70
- ctx.setLoading(false);
71
- if (platforms.length === 0) {
72
- ctx.addMessage({
73
- id: `init-no-platforms-${Date.now()}`,
74
- role: "system",
75
- content: "No supported AI coding platforms detected. API key is saved and ready to use.",
76
- timestamp: Date.now(),
77
- });
78
- promptAgentChoice(ctx);
79
- return;
80
- }
81
- const lines = [`Found ${platforms.length} platform(s):\n`];
82
- for (const platform of platforms) {
83
- ctx.setLoading(true, `Installing for ${platform.name}...`);
84
- const results = [];
85
- try {
86
- installForPlatform(platform, apiKey, (progress) => {
87
- if (progress.detail)
88
- results.push(progress.detail);
89
- });
90
- }
91
- catch {
92
- // Installation errors are reported via the callback
93
- }
94
- const status = results.length > 0
95
- ? results.join(", ")
96
- : platform.nexInstalled
97
- ? "already installed"
98
- : "detected";
99
- lines.push(` - ${platform.name}: ${status}`);
100
- }
101
- ctx.setLoading(false);
102
- ctx.addMessage({
103
- id: `init-platforms-${Date.now()}`,
104
- role: "system",
105
- content: lines.join("\n"),
106
- timestamp: Date.now(),
107
- });
108
- promptAgentChoice(ctx);
109
- }
110
- /**
111
- * Show the agent creation choice picker after platform install.
112
- */
113
- function promptAgentChoice(ctx) {
114
- ctx.addMessage({
115
- id: `init-agent-choice-${Date.now()}`,
116
- role: "system",
117
- content: "Setup complete! Your workspace is ready.\n\n" +
118
- "Pick an AI agent to start with — your first team member.\n" +
119
- "It will work autonomously on your behalf. You can add more agents later.",
120
- timestamp: Date.now(),
121
- });
122
- ctx.showPicker("Which agent should join your team first?", [
123
- { label: "Pick from specialists", value: "templates", description: "SEO, Lead Gen, Research, Customer Success, etc." },
124
- { label: "Describe what you need", value: "custom", description: "Tell us in plain English — AI builds the agent" },
125
- { label: "Founding Agent", value: "founding", description: "A generalist that handles everything until you add specialists" },
126
- { label: "Skip — I'll add agents later", value: "skip" },
127
- ], (choice) => handleAgentChoice(choice, ctx));
128
- }
129
- /**
130
- * Show the template selection picker.
131
- */
132
- function promptTemplateChoice(ctx) {
133
- // Picker handles interaction — no state machine phase needed
134
- const templateOptions = TEMPLATE_MENU.map((t) => {
135
- const tmpl = TEMPLATE_LABELS[t.templateKey];
136
- return {
137
- label: tmpl?.name ?? t.templateKey,
138
- value: t.templateKey,
139
- description: tmpl?.expertise ?? "",
140
- };
141
- });
142
- // Add a back option
143
- templateOptions.push({ label: "Back", value: "back" });
144
- ctx.showPicker("Pick a specialist agent:", templateOptions, (value) => {
145
- if (value === "back") {
146
- promptAgentChoice(ctx);
147
- return;
148
- }
149
- handleTemplateSelect(value, ctx);
150
- });
151
- }
152
- /**
153
- * Show confirmation after creating an agent.
154
- */
155
- function showAgentCreated(ctx, name, slug, expertise, cron) {
156
- ctx.addMessage({
157
- id: `init-agent-created-${Date.now()}`,
158
- role: "system",
159
- content: `Created "${name}" agent (${slug})\n` +
160
- ` Expertise: ${expertise.join(", ")}\n` +
161
- ` Schedule: ${cron} heartbeat\n\n` +
162
- `Your agent is ready! It will start working on its next heartbeat.\n` +
163
- `Use /agents to see your team, or just start chatting.`,
164
- timestamp: Date.now(),
165
- });
166
- initState = { phase: "idle" };
167
- }
168
- /** Template slugs indexed by menu number. */
169
- const TEMPLATE_MENU = [
170
- { slug: "seo-agent", templateKey: "seo-agent" },
171
- { slug: "lead-gen", templateKey: "lead-gen" },
172
- { slug: "enrichment", templateKey: "enrichment" },
173
- { slug: "research", templateKey: "research" },
174
- { slug: "customer-success", templateKey: "customer-success" },
175
- ];
176
- /** Display labels for template picker options. */
177
- const TEMPLATE_LABELS = {
178
- "seo-agent": { name: "SEO Analyst", expertise: "keyword research, content analysis, search visibility" },
179
- "lead-gen": { name: "Lead Generator", expertise: "prospecting, enrichment, outreach" },
180
- "enrichment": { name: "Data Enricher", expertise: "research, validation, missing data" },
181
- "research": { name: "Research Analyst", expertise: "market research, competitive analysis, trends" },
182
- "customer-success": { name: "Customer Success", expertise: "relationship management, health scoring, renewals" },
183
- };
184
- /**
185
- * Handle agent choice picker selection.
186
- */
187
- async function handleAgentChoice(choice, ctx) {
188
- if (choice === "templates") {
189
- promptTemplateChoice(ctx);
190
- return;
191
- }
192
- if (choice === "custom") {
193
- ctx.addMessage({
194
- id: `init-agent-prompt-${Date.now()}`,
195
- role: "system",
196
- content: 'Describe what you want your agent to do:\n(e.g., "Monitor competitor pricing and alert me to changes")',
197
- timestamp: Date.now(),
198
- });
199
- initState = { phase: "awaiting_agent_prompt" };
200
- return;
201
- }
202
- if (choice === "founding") {
203
- ctx.setLoading(true, "Creating Founding Agent...");
204
- try {
205
- const { getAgentService } = await import("./services/agent-service.js");
206
- const service = getAgentService();
207
- const managed = service.createFromTemplate("founding-agent", "founding-agent");
208
- ctx.setLoading(false);
209
- showAgentCreated(ctx, managed.config.name, managed.config.slug, managed.config.expertise, managed.config.heartbeatCron ?? "daily");
210
- }
211
- catch (err) {
212
- ctx.setLoading(false);
213
- ctx.addMessage({
214
- id: `init-agent-err-${Date.now()}`,
215
- role: "system",
216
- content: `Failed to create agent: ${err instanceof Error ? err.message : String(err)}`,
217
- timestamp: Date.now(),
218
- isError: true,
219
- });
220
- initState = { phase: "idle" };
221
- }
222
- return;
223
- }
224
- if (choice === "skip") {
225
- ctx.addMessage({
226
- id: `init-skip-agent-${Date.now()}`,
227
- role: "system",
228
- content: "Skipped agent creation. Use /agents or /agent create <slug> --template <name> anytime.",
229
- timestamp: Date.now(),
230
- });
231
- initState = { phase: "idle" };
232
- return;
233
- }
234
- }
235
- /**
236
- * Handle template picker selection.
237
- */
238
- async function handleTemplateSelect(templateKey, ctx) {
239
- const entry = TEMPLATE_MENU.find((t) => t.templateKey === templateKey);
240
- if (!entry) {
241
- promptTemplateChoice(ctx);
242
- return;
243
- }
244
- ctx.setLoading(true, "Creating agent...");
245
- try {
246
- const { getAgentService } = await import("./services/agent-service.js");
247
- const service = getAgentService();
248
- const managed = service.createFromTemplate(entry.slug, entry.templateKey);
249
- ctx.setLoading(false);
250
- showAgentCreated(ctx, managed.config.name, managed.config.slug, managed.config.expertise, managed.config.heartbeatCron ?? "daily");
251
- }
252
- catch (err) {
253
- ctx.setLoading(false);
254
- ctx.addMessage({
255
- id: `init-template-err-${Date.now()}`,
256
- role: "system",
257
- content: `Failed to create agent: ${err instanceof Error ? err.message : String(err)}`,
258
- timestamp: Date.now(),
259
- isError: true,
260
- });
261
- initState = { phase: "idle" };
262
- }
263
- }
264
- /**
265
- * Handle expired key choice via picker.
266
- */
267
- async function handleRegenChoice(choice, currentEmail, currentKey, ctx) {
268
- if (choice === "regenerate") {
269
- if (!currentEmail) {
270
- ctx.addMessage({
271
- id: `init-no-email-${Date.now()}`,
272
- role: "system",
273
- content: "No email on file. What's your email address?",
274
- timestamp: Date.now(),
275
- });
276
- initState = { phase: "awaiting_email" };
277
- return;
278
- }
279
- ctx.setLoading(true, "Generating new key...");
280
- try {
281
- const { registerUser } = await import("../commands/init.js");
282
- const result = await registerUser(currentEmail);
283
- ctx.setLoading(false);
284
- const maskedKey = `${result.apiKey.slice(0, 6)}...${result.apiKey.slice(-4)}`;
285
- ctx.addMessage({
286
- id: `init-regen-${Date.now()}`,
287
- role: "system",
288
- content: `New key generated: ${maskedKey}`,
289
- timestamp: Date.now(),
290
- });
291
- await runPlatformInstall(result.apiKey, ctx);
292
- }
293
- catch (err) {
294
- ctx.setLoading(false);
295
- ctx.addMessage({
296
- id: `init-regen-err-${Date.now()}`,
297
- role: "system",
298
- content: `Key regeneration failed: ${err instanceof Error ? err.message : String(err)}`,
299
- timestamp: Date.now(),
300
- isError: true,
301
- });
302
- initState = { phase: "idle" };
303
- }
304
- return;
305
- }
306
- if (choice === "new-email") {
307
- ctx.addMessage({
308
- id: `init-new-email-${Date.now()}`,
309
- role: "system",
310
- content: "What's your email address?",
311
- timestamp: Date.now(),
312
- });
313
- initState = { phase: "awaiting_new_email" };
314
- return;
315
- }
316
- // "skip" — keep current key
317
- ctx.addMessage({
318
- id: `init-keep-${Date.now()}`,
319
- role: "system",
320
- content: "Keeping current key.",
321
- timestamp: Date.now(),
322
- });
323
- await runPlatformInstall(currentKey, ctx);
324
- }
325
- /**
326
- * Handle agent confirm via inline confirm.
327
- */
328
- async function handleAgentConfirm(confirmed, config, ctx) {
329
- if (confirmed) {
330
- ctx.setLoading(true, "Creating agent...");
331
- try {
332
- const { getAgentService } = await import("./services/agent-service.js");
333
- const service = getAgentService();
334
- const agentConfig = {
335
- slug: config.slug,
336
- name: config.name,
337
- expertise: config.expertise,
338
- personality: config.personality,
339
- heartbeatCron: config.heartbeatCron,
340
- tools: config.tools,
341
- };
342
- const managed = service.create(agentConfig);
343
- ctx.setLoading(false);
344
- showAgentCreated(ctx, managed.config.name, managed.config.slug, managed.config.expertise, managed.config.heartbeatCron ?? "daily");
345
- }
346
- catch (err) {
347
- ctx.setLoading(false);
348
- ctx.addMessage({
349
- id: `init-agent-create-err-${Date.now()}`,
350
- role: "system",
351
- content: `Failed to create agent: ${err instanceof Error ? err.message : String(err)}`,
352
- timestamp: Date.now(),
353
- isError: true,
354
- });
355
- initState = { phase: "idle" };
356
- }
357
- return;
358
- }
359
- // Declined
360
- ctx.addMessage({
361
- id: `init-agent-declined-${Date.now()}`,
362
- role: "system",
363
- content: "Agent creation cancelled.",
364
- timestamp: Date.now(),
365
- });
366
- promptAgentChoice(ctx);
367
- }
368
- /**
369
- * Build an agent config from a free-text user prompt.
370
- */
371
- function buildAgentFromPrompt(prompt) {
372
- const slug = prompt
373
- .split(/\s+/)
374
- .slice(0, 3)
375
- .join("-")
376
- .toLowerCase()
377
- .replace(/[^a-z0-9-]/g, "");
378
- // Capitalize first letter of each of the first few words for the name
379
- const name = prompt
380
- .split(/\s+/)
381
- .slice(0, 4)
382
- .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
383
- .join(" ");
384
- // Extract expertise keywords: split on common delimiters, take meaningful words
385
- const stopWords = new Set(["and", "the", "a", "an", "to", "for", "of", "in", "on", "my", "me", "i", "is", "it", "that", "this", "with"]);
386
- const expertise = prompt
387
- .toLowerCase()
388
- .split(/[\s,;.]+/)
389
- .filter((w) => w.length > 2 && !stopWords.has(w))
390
- .slice(0, 5);
391
- return {
392
- slug: slug || "custom-agent",
393
- name: name || "Custom Agent",
394
- expertise: expertise.length > 0 ? expertise : ["general"],
395
- personality: `You are an AI agent specialized in: ${prompt}`,
396
- heartbeatCron: "daily",
397
- tools: ["nex_search", "nex_ask", "nex_remember"],
398
- };
399
- }
400
- /**
401
- * Handle user input when the init flow is awaiting a text response.
402
- * Called by the home adapter when `getInitState().phase !== 'idle'`.
403
- *
404
- * Picker-based choices (regen, agent, template) are now handled via
405
- * showPicker callbacks -- only text-input phases remain here.
406
- */
407
- export async function handleInitInput(input, context) {
408
- if (initState.phase === "awaiting_email" || initState.phase === "awaiting_new_email") {
409
- const email = input.trim();
410
- if (!email || !email.includes("@")) {
411
- context.addMessage({
412
- id: `init-email-err-${Date.now()}`,
413
- role: "system",
414
- content: "Please enter a valid email address.",
415
- timestamp: Date.now(),
416
- });
417
- return;
418
- }
419
- context.setLoading(true, "Registering...");
420
- try {
421
- const { registerUser } = await import("../commands/init.js");
422
- const result = await registerUser(email);
423
- context.setLoading(false);
424
- const maskedKey = `${result.apiKey.slice(0, 6)}...${result.apiKey.slice(-4)}`;
425
- const isLoginOnly = initState.loginOnly;
426
- context.addMessage({
427
- id: `init-registered-${Date.now()}`,
428
- role: "system",
429
- content: `Logged in! API key: ${maskedKey}\n` +
430
- `Workspace: ${result.workspaceSlug}\n\n` +
431
- `Saved to ~/.nex/config.json` +
432
- (isLoginOnly ? "\n\nRun /init to install Nex into your AI agents." : ""),
433
- timestamp: Date.now(),
434
- });
435
- // Proceed to platform installation (unless login-only)
436
- if (!isLoginOnly) {
437
- await runPlatformInstall(result.apiKey, context);
438
- // runPlatformInstall may have advanced state to agent onboarding
439
- return;
440
- }
441
- }
442
- catch (err) {
443
- context.setLoading(false);
444
- context.addMessage({
445
- id: `init-reg-err-${Date.now()}`,
446
- role: "system",
447
- content: `Registration failed: ${err instanceof Error ? err.message : String(err)}`,
448
- timestamp: Date.now(),
449
- isError: true,
450
- });
451
- }
452
- initState = { phase: "idle" };
453
- return;
454
- }
455
- if (initState.phase === "awaiting_agent_prompt") {
456
- const prompt = input.trim();
457
- if (!prompt) {
458
- context.addMessage({
459
- id: `init-prompt-empty-${Date.now()}`,
460
- role: "system",
461
- content: "Please describe what you want your agent to do.",
462
- timestamp: Date.now(),
463
- });
464
- return;
465
- }
466
- // Try AI-powered generation via dispatch, fall back to local parsing
467
- context.setLoading(true, "Generating agent profile...");
468
- let config;
469
- try {
470
- const aiResult = await context.dispatch(`ask Generate an agent profile as JSON for this task: "${prompt}". Return ONLY JSON with fields: name (string), expertise (string[]), personality (string), heartbeatCron (string), tools (string[] from: nex_search, nex_ask, nex_remember, nex_record_list, nex_record_get, nex_record_create, nex_record_update)`);
471
- // Try to parse AI result as JSON
472
- let parsed = null;
473
- if (aiResult.output) {
474
- try {
475
- // Extract JSON from the response (may be wrapped in markdown code blocks)
476
- const jsonMatch = aiResult.output.match(/\{[\s\S]*\}/);
477
- if (jsonMatch) {
478
- parsed = JSON.parse(jsonMatch[0]);
479
- }
480
- }
481
- catch {
482
- // JSON parse failed, fall through to local builder
483
- }
484
- }
485
- if (parsed && typeof parsed.name === "string" && Array.isArray(parsed.expertise)) {
486
- const slug = parsed.name
487
- .toLowerCase()
488
- .replace(/[^a-z0-9]+/g, "-")
489
- .replace(/^-|-$/g, "");
490
- config = {
491
- slug: slug || "custom-agent",
492
- name: parsed.name,
493
- expertise: parsed.expertise,
494
- personality: parsed.personality ?? `You are an AI agent specialized in: ${prompt}`,
495
- heartbeatCron: parsed.heartbeatCron ?? "daily",
496
- tools: Array.isArray(parsed.tools) ? parsed.tools : ["nex_search", "nex_ask", "nex_remember"],
497
- };
498
- }
499
- else {
500
- config = buildAgentFromPrompt(prompt);
501
- }
502
- }
503
- catch {
504
- // AI generation failed, use local builder
505
- config = buildAgentFromPrompt(prompt);
506
- }
507
- context.setLoading(false);
508
- // Show generated profile and ask for confirmation via inline confirm
509
- const expertise = config.expertise;
510
- context.addMessage({
511
- id: `init-agent-preview-${Date.now()}`,
512
- role: "system",
513
- content: `Here's the agent I'll create:\n\n` +
514
- ` Name: ${config.name}\n` +
515
- ` Slug: ${config.slug}\n` +
516
- ` Expertise: ${expertise.join(", ")}\n` +
517
- ` Schedule: ${config.heartbeatCron} heartbeat`,
518
- timestamp: Date.now(),
519
- });
520
- // ConfirmInput handles interaction — set idle so text input isn't blocked
521
- initState = { phase: "idle" };
522
- context.showConfirm("Create this agent?", (confirmed) => handleAgentConfirm(confirmed, config, context));
523
- return;
524
- }
525
- }
526
- let agentWizardState = { phase: "idle" };
527
- export function getAgentWizardState() {
528
- return agentWizardState;
529
- }
530
- export function resetAgentWizardState() {
531
- agentWizardState = { phase: "idle" };
532
- }
533
- const SCHEDULE_OPTIONS = [
534
- { label: "Hourly", value: "hourly", description: "every hour" },
535
- { label: "Every 4 hours", value: "0 */4 * * *", description: "6x per day" },
536
- { label: "Every 6 hours", value: "0 */6 * * *", description: "4x per day" },
537
- { label: "Daily", value: "daily", description: "once per day" },
538
- { label: "Weekly (Mon 9am)", value: "0 9 * * 1", description: "every Monday" },
539
- { label: "Manual only", value: "manual", description: "no automatic runs" },
540
- ];
541
- function formatSchedule(cron) {
542
- if (!cron)
543
- return "daily";
544
- const found = SCHEDULE_OPTIONS.find((o) => o.value === cron);
545
- return found ? found.label : cron;
546
- }
547
- function slugify(name) {
548
- return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "agent";
549
- }
550
- async function createAgentFromConfig(config, ctx) {
551
- ctx.setLoading(true, "Creating agent...");
552
- try {
553
- const { getAgentService } = await import("./services/agent-service.js");
554
- const service = getAgentService();
555
- const managed = service.create({
556
- slug: config.slug,
557
- name: config.name,
558
- expertise: config.expertise,
559
- personality: config.personality ??
560
- `You are an AI agent specializing in: ${config.expertise.join(", ")}`,
561
- heartbeatCron: config.heartbeatCron ?? "daily",
562
- tools: Array.isArray(config.tools)
563
- ? config.tools
564
- : ["nex_search", "nex_ask", "nex_remember"],
565
- });
566
- ctx.setLoading(false);
567
- ctx.addMessage({
568
- id: `agent-created-${Date.now()}`,
569
- role: "system",
570
- content: `Created "${managed.config.name}" (${managed.config.slug})\n` +
571
- ` Expertise: ${managed.config.expertise.join(", ")}\n` +
572
- ` Schedule: ${formatSchedule(managed.config.heartbeatCron)}\n\n` +
573
- `Agent is ready and will run on its next heartbeat.`,
574
- timestamp: Date.now(),
575
- });
576
- }
577
- catch (err) {
578
- ctx.setLoading(false);
579
- ctx.addMessage({
580
- id: `agent-create-err-${Date.now()}`,
581
- role: "system",
582
- content: `Failed to create agent: ${err instanceof Error ? err.message : String(err)}`,
583
- timestamp: Date.now(),
584
- isError: true,
585
- });
586
- }
587
- }
588
- async function createFromTemplateKey(templateKey, ctx) {
589
- const { getAgentService } = await import("./services/agent-service.js");
590
- const service = getAgentService();
591
- const template = service.getTemplate(templateKey);
592
- if (!template) {
593
- ctx.addMessage({
594
- id: `agent-tmpl-err-${Date.now()}`,
595
- role: "system",
596
- content: `Unknown template: ${templateKey}`,
597
- timestamp: Date.now(),
598
- isError: true,
599
- });
600
- return;
601
- }
602
- ctx.addMessage({
603
- id: `agent-tmpl-preview-${Date.now()}`,
604
- role: "system",
605
- content: `About to create:\n\n` +
606
- ` Name: ${template.name}\n` +
607
- ` Expertise: ${template.expertise.join(", ")}\n` +
608
- ` Schedule: ${formatSchedule(template.heartbeatCron)}`,
609
- timestamp: Date.now(),
610
- });
611
- ctx.showConfirm(`Create "${template.name}" agent?`, async (confirmed) => {
612
- if (!confirmed) {
613
- showAgentCreatePicker(ctx);
614
- return;
615
- }
616
- const existing = service.get(templateKey);
617
- const slug = existing ? `${templateKey}-${Date.now()}` : templateKey;
618
- await createAgentFromConfig({
619
- slug,
620
- name: template.name,
621
- expertise: template.expertise,
622
- personality: template.personality,
623
- heartbeatCron: template.heartbeatCron,
624
- tools: template.tools,
625
- }, ctx);
626
- });
627
- }
628
- function showAgentCreatePicker(ctx) {
629
- ctx.showPicker("Create an agent:", [
630
- { label: "Founding Agent", value: "tmpl:founding-agent", description: "generalist — handles everything" },
631
- { label: "SEO Analyst", value: "tmpl:seo-agent", description: "keywords, content, search visibility" },
632
- { label: "Lead Generator", value: "tmpl:lead-gen", description: "prospecting, enrichment, outreach" },
633
- { label: "Data Enricher", value: "tmpl:enrichment", description: "research, validation, missing data" },
634
- { label: "Research Analyst", value: "tmpl:research", description: "market research, trends, analysis" },
635
- { label: "Customer Success", value: "tmpl:customer-success", description: "health scoring, renewals" },
636
- { label: "Describe what you need (AI generates)", value: "custom:describe", description: "" },
637
- { label: "Fill in details manually", value: "custom:manual", description: "step-by-step" },
638
- { label: "Back", value: "back" },
639
- ], (value) => { void handleCreatePickerSelect(value, ctx); });
640
- }
641
- async function handleCreatePickerSelect(value, ctx) {
642
- if (value === "back") {
643
- await openAgentsManager(ctx);
644
- return;
645
- }
646
- if (value.startsWith("tmpl:")) {
647
- await createFromTemplateKey(value.slice(5), ctx);
648
- return;
649
- }
650
- if (value === "custom:describe") {
651
- agentWizardState = { phase: "agent_create_describe" };
652
- ctx.addMessage({
653
- id: `agent-wizard-desc-${Date.now()}`,
654
- role: "system",
655
- content: "Describe what you want this agent to do:\n" +
656
- "(e.g., \"Monitor competitor pricing and alert me to changes\")",
657
- timestamp: Date.now(),
658
- });
659
- return;
660
- }
661
- if (value === "custom:manual") {
662
- agentWizardState = { phase: "agent_create_name" };
663
- ctx.addMessage({
664
- id: `agent-wizard-name-${Date.now()}`,
665
- role: "system",
666
- content: "What should this agent be called?\n(e.g., Sales Assistant, Content Writer)",
667
- timestamp: Date.now(),
668
- });
669
- }
670
- }
671
- async function showAgentManagePicker(slug, ctx) {
672
- const { getAgentService } = await import("./services/agent-service.js");
673
- const service = getAgentService();
674
- const managed = service.get(slug);
675
- if (!managed) {
676
- ctx.addMessage({
677
- id: `agent-not-found-${Date.now()}`,
678
- role: "system",
679
- content: `Agent "${slug}" not found.`,
680
- timestamp: Date.now(),
681
- isError: true,
682
- });
683
- await openAgentsManager(ctx);
684
- return;
685
- }
686
- const isRunning = managed.state.phase !== "idle" && managed.state.phase !== "done" && managed.state.phase !== "error";
687
- ctx.showPicker(`Manage "${managed.config.name}":`, [
688
- isRunning
689
- ? { label: "Stop", value: "stop", description: "pause the agent" }
690
- : { label: "Start", value: "start", description: "run a heartbeat tick" },
691
- { label: "Edit name", value: "edit:name", description: `currently: ${managed.config.name}` },
692
- {
693
- label: "Edit expertise",
694
- value: "edit:expertise",
695
- description: managed.config.expertise.slice(0, 3).join(", "),
696
- },
697
- {
698
- label: "Edit schedule",
699
- value: "edit:schedule",
700
- description: formatSchedule(managed.config.heartbeatCron),
701
- },
702
- { label: "Delete agent", value: "delete", description: "remove permanently" },
703
- { label: "Back", value: "back" },
704
- ], (value) => { void handleManageAction(value, slug, ctx); });
705
- }
706
- async function handleManageAction(value, slug, ctx) {
707
- if (value === "back") {
708
- await openAgentsManager(ctx);
709
- return;
710
- }
711
- const { getAgentService } = await import("./services/agent-service.js");
712
- const service = getAgentService();
713
- const managed = service.get(slug);
714
- if (!managed) {
715
- ctx.addMessage({
716
- id: `agent-gone-${Date.now()}`,
717
- role: "system",
718
- content: `Agent "${slug}" no longer exists.`,
719
- timestamp: Date.now(),
720
- isError: true,
721
- });
722
- return;
723
- }
724
- if (value === "start") {
725
- ctx.setLoading(true, `Starting ${managed.config.name}...`);
726
- try {
727
- await service.start(slug);
728
- ctx.setLoading(false);
729
- ctx.addMessage({
730
- id: `agent-start-${Date.now()}`,
731
- role: "system",
732
- content: `${managed.config.name} started.`,
733
- timestamp: Date.now(),
734
- });
735
- }
736
- catch (err) {
737
- ctx.setLoading(false);
738
- ctx.addMessage({
739
- id: `agent-start-err-${Date.now()}`,
740
- role: "system",
741
- content: `Start failed: ${err instanceof Error ? err.message : String(err)}`,
742
- timestamp: Date.now(),
743
- isError: true,
744
- });
745
- }
746
- return;
747
- }
748
- if (value === "stop") {
749
- service.stop(slug);
750
- ctx.addMessage({
751
- id: `agent-stop-${Date.now()}`,
752
- role: "system",
753
- content: `${managed.config.name} stopped.`,
754
- timestamp: Date.now(),
755
- });
756
- return;
757
- }
758
- if (value === "edit:name") {
759
- agentWizardState = { phase: "agent_edit_name", slug };
760
- ctx.addMessage({
761
- id: `agent-edit-name-${Date.now()}`,
762
- role: "system",
763
- content: `New name for "${managed.config.name}":`,
764
- timestamp: Date.now(),
765
- });
766
- return;
767
- }
768
- if (value === "edit:expertise") {
769
- agentWizardState = { phase: "agent_edit_expertise", slug };
770
- ctx.addMessage({
771
- id: `agent-edit-exp-${Date.now()}`,
772
- role: "system",
773
- content: `Current expertise: ${managed.config.expertise.join(", ")}\n\n` +
774
- `Enter new expertise (comma-separated):`,
775
- timestamp: Date.now(),
776
- });
777
- return;
778
- }
779
- if (value === "edit:schedule") {
780
- ctx.showPicker(`Schedule for "${managed.config.name}":`, SCHEDULE_OPTIONS.map((o) => ({
781
- ...o,
782
- label: o.value === managed.config.heartbeatCron ? `${o.label} ✓` : o.label,
783
- })), (scheduleValue) => {
784
- service.updateConfig(slug, { heartbeatCron: scheduleValue });
785
- ctx.addMessage({
786
- id: `agent-schedule-${Date.now()}`,
787
- role: "system",
788
- content: `${managed.config.name} schedule updated to: ${formatSchedule(scheduleValue)}`,
789
- timestamp: Date.now(),
790
- });
791
- });
792
- return;
793
- }
794
- if (value === "delete") {
795
- ctx.showConfirm(`Delete "${managed.config.name}" permanently?`, async (confirmed) => {
796
- if (!confirmed) {
797
- await showAgentManagePicker(slug, ctx);
798
- return;
799
- }
800
- const name = managed.config.name;
801
- service.remove(slug);
802
- ctx.addMessage({
803
- id: `agent-deleted-${Date.now()}`,
804
- role: "system",
805
- content: `${name} has been removed.`,
806
- timestamp: Date.now(),
807
- });
808
- });
809
- }
810
- }
811
- /**
812
- * Main entry point for the /agents interactive manager.
813
- * Exported so SlackHome can call it from the sidebar `[a]` shortcut.
814
- */
815
- export async function openAgentsManager(ctx) {
816
- const { getAgentService } = await import("./services/agent-service.js");
817
- const service = getAgentService();
818
- const agents = service.list();
819
- if (agents.length > 0) {
820
- const lines = agents.map((a) => {
821
- const phase = a.state.phase;
822
- const icon = (phase !== "idle" && phase !== "done" && phase !== "error") ? "●" : phase === "idle" ? "○" : "◐";
823
- const expertise = a.config.expertise.slice(0, 3).join(", ");
824
- return ` ${icon} ${a.config.name} (${a.config.slug}) [${phase}] ${expertise}`;
825
- });
826
- ctx.addMessage({
827
- id: `agents-list-${Date.now()}`,
828
- role: "system",
829
- content: `Your agents (${agents.length}):\n\n${lines.join("\n")}`,
830
- timestamp: Date.now(),
831
- });
832
- }
833
- const agentOptions = agents.map((a) => ({
834
- label: a.config.name,
835
- value: `manage:${a.config.slug}`,
836
- description: `[${a.state.phase}] ${a.config.expertise.slice(0, 2).join(", ")}`,
837
- }));
838
- ctx.showPicker(agents.length === 0 ? "No agents yet. Create your first one:" : "Agent Manager:", [
839
- { label: "+ Create new agent", value: "create" },
840
- ...agentOptions,
841
- { label: "Done", value: "cancel" },
842
- ], (value) => { void handleAgentsPickerSelect(value, ctx); });
843
- }
844
- async function handleAgentsPickerSelect(value, ctx) {
845
- if (value === "create") {
846
- showAgentCreatePicker(ctx);
847
- return;
848
- }
849
- if (value.startsWith("manage:")) {
850
- await showAgentManagePicker(value.slice(7), ctx);
851
- }
852
- // "cancel" → picker closes, no further action
853
- }
854
- /**
855
- * Handle text input when the agent wizard is awaiting user input.
856
- * Called by SlackHome's handleSend when agentWizardState.phase !== "idle".
857
- */
858
- export async function handleAgentWizardInput(input, ctx) {
859
- const state = agentWizardState;
860
- if (state.phase === "agent_create_describe") {
861
- const prompt = input.trim();
862
- if (!prompt) {
863
- ctx.addMessage({
864
- id: `aw-empty-${Date.now()}`,
865
- role: "system",
866
- content: "Please describe what you want the agent to do.",
867
- timestamp: Date.now(),
868
- });
869
- return;
870
- }
871
- agentWizardState = { phase: "idle" };
872
- ctx.setLoading(true, "Generating agent profile...");
873
- let config;
874
- try {
875
- const aiResult = await ctx.dispatch(`ask Generate an agent profile as JSON for: "${prompt}". Return ONLY JSON with: name (string), expertise (string[]), heartbeatCron (string), tools (string[]).`);
876
- const jsonMatch = aiResult.output?.match(/\{[\s\S]*\}/);
877
- const parsed = jsonMatch ? JSON.parse(jsonMatch[0]) : null;
878
- if (parsed && typeof parsed.name === "string" && Array.isArray(parsed.expertise)) {
879
- config = {
880
- slug: slugify(parsed.name) || "custom-agent",
881
- name: parsed.name,
882
- expertise: parsed.expertise,
883
- personality: `You are an AI agent specialized in: ${prompt}`,
884
- heartbeatCron: parsed.heartbeatCron ?? "daily",
885
- tools: Array.isArray(parsed.tools) ? parsed.tools : ["nex_search", "nex_ask", "nex_remember"],
886
- };
887
- }
888
- else {
889
- config = buildAgentFromPrompt(prompt);
890
- }
891
- }
892
- catch {
893
- config = buildAgentFromPrompt(prompt);
894
- }
895
- ctx.setLoading(false);
896
- ctx.addMessage({
897
- id: `aw-preview-${Date.now()}`,
898
- role: "system",
899
- content: `Agent profile:\n\n` +
900
- ` Name: ${config.name}\n` +
901
- ` Expertise: ${config.expertise.join(", ")}\n` +
902
- ` Schedule: ${formatSchedule(config.heartbeatCron)}`,
903
- timestamp: Date.now(),
904
- });
905
- ctx.showConfirm("Create this agent?", async (confirmed) => {
906
- if (!confirmed) {
907
- showAgentCreatePicker(ctx);
908
- return;
909
- }
910
- await createAgentFromConfig(config, ctx);
911
- });
912
- return;
913
- }
914
- if (state.phase === "agent_create_name") {
915
- const name = input.trim();
916
- if (!name) {
917
- ctx.addMessage({
918
- id: `aw-name-empty-${Date.now()}`,
919
- role: "system",
920
- content: "Please enter a name for the agent.",
921
- timestamp: Date.now(),
922
- });
923
- return;
924
- }
925
- agentWizardState = { phase: "agent_create_expertise", slug: slugify(name), name };
926
- ctx.addMessage({
927
- id: `aw-expertise-prompt-${Date.now()}`,
928
- role: "system",
929
- content: "Enter areas of expertise (comma-separated):\n(e.g., sales, outreach, lead-generation)",
930
- timestamp: Date.now(),
931
- });
932
- return;
933
- }
934
- if (state.phase === "agent_create_expertise") {
935
- const expertiseRaw = input.trim();
936
- if (!expertiseRaw) {
937
- ctx.addMessage({
938
- id: `aw-exp-empty-${Date.now()}`,
939
- role: "system",
940
- content: "Please enter at least one area of expertise.",
941
- timestamp: Date.now(),
942
- });
943
- return;
944
- }
945
- const expertise = expertiseRaw.split(",").map((s) => s.trim()).filter(Boolean);
946
- const { slug, name } = state;
947
- agentWizardState = { phase: "idle" };
948
- ctx.showPicker("How often should this agent run?", SCHEDULE_OPTIONS, async (scheduleValue) => {
949
- ctx.addMessage({
950
- id: `aw-preview-manual-${Date.now()}`,
951
- role: "system",
952
- content: `Agent summary:\n\n` +
953
- ` Name: ${name}\n` +
954
- ` Expertise: ${expertise.join(", ")}\n` +
955
- ` Schedule: ${formatSchedule(scheduleValue)}`,
956
- timestamp: Date.now(),
957
- });
958
- ctx.showConfirm("Create this agent?", async (confirmed) => {
959
- if (!confirmed) {
960
- showAgentCreatePicker(ctx);
961
- return;
962
- }
963
- await createAgentFromConfig({
964
- slug,
965
- name,
966
- expertise,
967
- heartbeatCron: scheduleValue,
968
- }, ctx);
969
- });
970
- });
971
- return;
972
- }
973
- if (state.phase === "agent_edit_name") {
974
- const newName = input.trim();
975
- if (!newName) {
976
- ctx.addMessage({
977
- id: `aw-edit-name-empty-${Date.now()}`,
978
- role: "system",
979
- content: "Please enter a new name.",
980
- timestamp: Date.now(),
981
- });
982
- return;
983
- }
984
- agentWizardState = { phase: "idle" };
985
- const { getAgentService } = await import("./services/agent-service.js");
986
- getAgentService().updateConfig(state.slug, { name: newName });
987
- ctx.addMessage({
988
- id: `aw-edit-name-done-${Date.now()}`,
989
- role: "system",
990
- content: `Agent renamed to "${newName}".`,
991
- timestamp: Date.now(),
992
- });
993
- return;
994
- }
995
- if (state.phase === "agent_edit_expertise") {
996
- const expertiseRaw = input.trim();
997
- if (!expertiseRaw) {
998
- ctx.addMessage({
999
- id: `aw-edit-exp-empty-${Date.now()}`,
1000
- role: "system",
1001
- content: "Please enter at least one area of expertise.",
1002
- timestamp: Date.now(),
1003
- });
1004
- return;
1005
- }
1006
- const expertise = expertiseRaw.split(",").map((s) => s.trim()).filter(Boolean);
1007
- agentWizardState = { phase: "idle" };
1008
- const { getAgentService } = await import("./services/agent-service.js");
1009
- getAgentService().updateConfig(state.slug, { expertise });
1010
- ctx.addMessage({
1011
- id: `aw-edit-exp-done-${Date.now()}`,
1012
- role: "system",
1013
- content: `Expertise updated to: ${expertise.join(", ")}.`,
1014
- timestamp: Date.now(),
1015
- });
1016
- }
1017
- }
1018
- // ── Built-in commands ───────────────────────────────────────────────
1019
- registerSlashCommand({
1020
- name: "help",
1021
- description: "Show all slash commands and keybindings",
1022
- execute: async () => {
1023
- const lines = listSlashCommands().map((cmd) => {
1024
- const usage = cmd.usage ? ` ${cmd.usage}` : "";
1025
- return ` /${cmd.name}${usage} — ${cmd.description}`;
1026
- });
1027
- const header = "Available commands:\n";
1028
- const footer = "\nKeybindings: Esc=back Ctrl+C=quit";
1029
- return { output: header + lines.join("\n") + footer };
1030
- },
1031
- });
1032
- registerSlashCommand({
1033
- name: "init",
1034
- description: "Run setup flow to configure API key and install integrations",
1035
- usage: "/init",
1036
- execute: async (_args, ctx) => {
1037
- // Reset any stale init state
1038
- resetInitState();
1039
- ctx.setLoading(true, "Checking configuration...");
1040
- try {
1041
- const { resolveApiKey, loadConfig } = await import("../lib/config.js");
1042
- const apiKey = resolveApiKey();
1043
- if (!apiKey) {
1044
- // No key at all — start registration flow
1045
- ctx.setLoading(false);
1046
- ctx.addMessage({
1047
- id: `init-welcome-${Date.now()}`,
1048
- role: "system",
1049
- content: "Welcome to Nex! Let's get you set up.\n\nWhat's your email address?",
1050
- timestamp: Date.now(),
1051
- });
1052
- initState = { phase: "awaiting_email" };
1053
- return { silent: true };
1054
- }
1055
- // Key exists — validate it with a lightweight API call
1056
- ctx.setLoading(true, "Validating API key...");
1057
- const testResult = await ctx.dispatch("object list");
1058
- if (testResult.exitCode === 2 ||
1059
- (testResult.error && testResult.error.includes("API key"))) {
1060
- // Key is expired/invalid — offer to regenerate via picker
1061
- ctx.setLoading(false);
1062
- const config = loadConfig();
1063
- ctx.addMessage({
1064
- id: `init-expired-${Date.now()}`,
1065
- role: "system",
1066
- content: `Your API key is expired or invalid.${config.email ? ` (${config.email})` : ""}`,
1067
- timestamp: Date.now(),
1068
- });
1069
- const regenOption = config.email
1070
- ? { label: `Generate new key for ${config.email}`, value: "regenerate" }
1071
- : { label: "Generate new key (enter email)", value: "regenerate" };
1072
- ctx.showPicker("What would you like to do?", [
1073
- regenOption,
1074
- { label: "Use a different email", value: "new-email" },
1075
- { label: "Keep current key and skip", value: "skip" },
1076
- ], (choice) => handleRegenChoice(choice, config.email, apiKey, ctx));
1077
- return { silent: true };
1078
- }
1079
- // Key is valid — proceed directly to platform installation
1080
- ctx.setLoading(false);
1081
- ctx.addMessage({
1082
- id: `init-valid-${Date.now()}`,
1083
- role: "system",
1084
- content: "API key is valid. Running platform installation...",
1085
- timestamp: Date.now(),
1086
- });
1087
- await runPlatformInstall(apiKey, ctx);
1088
- return { silent: true };
1089
- }
1090
- catch (err) {
1091
- ctx.setLoading(false);
1092
- return {
1093
- output: `Setup error: ${err instanceof Error ? err.message : String(err)}`,
1094
- };
1095
- }
1096
- },
1097
- });
1098
- // ── /login — auth only, no platform install ───────────────────────
1099
- registerSlashCommand({
1100
- name: "login",
1101
- description: "Log in or sign up (register only, no platform install)",
1102
- usage: "/login [email]",
1103
- execute: async (args, ctx) => {
1104
- resetInitState();
1105
- const email = args.trim();
1106
- // If email provided inline, register immediately
1107
- if (email && email.includes("@")) {
1108
- ctx.setLoading(true, "Registering...");
1109
- try {
1110
- const { registerUser } = await import("../commands/init.js");
1111
- const result = await registerUser(email);
1112
- ctx.setLoading(false);
1113
- const maskedKey = `${result.apiKey.slice(0, 6)}...${result.apiKey.slice(-4)}`;
1114
- return {
1115
- output: `Logged in!\n\n` +
1116
- ` API key: ${maskedKey}\n` +
1117
- ` Workspace: ${result.workspaceSlug}\n` +
1118
- ` Email: ${email}\n\n` +
1119
- `Saved to ~/.nex/config.json\n` +
1120
- `Run /init to install Nex into your AI agents.`,
1121
- };
1122
- }
1123
- catch (err) {
1124
- ctx.setLoading(false);
1125
- return {
1126
- output: `Login failed: ${err instanceof Error ? err.message : String(err)}`,
1127
- };
1128
- }
1129
- }
1130
- // Check if already logged in
1131
- const { resolveApiKey, loadConfig } = await import("../lib/config.js");
1132
- const apiKey = resolveApiKey();
1133
- if (apiKey) {
1134
- // Validate the key
1135
- ctx.setLoading(true, "Checking session...");
1136
- const testResult = await ctx.dispatch("object list");
1137
- ctx.setLoading(false);
1138
- if (testResult.exitCode !== 2) {
1139
- const config = loadConfig();
1140
- const maskedKey = `${apiKey.slice(0, 6)}...${apiKey.slice(-4)}`;
1141
- return {
1142
- output: `Already logged in.\n\n` +
1143
- ` API key: ${maskedKey}\n` +
1144
- ` Email: ${config.email || "unknown"}\n` +
1145
- ` Workspace: ${config.workspace_slug || "unknown"}\n\n` +
1146
- `To switch accounts: /login new@email.com`,
1147
- };
1148
- }
1149
- // Key expired — prompt for email
1150
- const config = loadConfig();
1151
- ctx.addMessage({
1152
- id: `login-expired-${Date.now()}`,
1153
- role: "system",
1154
- content: `Your session has expired.${config.email ? ` (${config.email})` : ""}\n\n` +
1155
- `Enter your email to log in again:`,
1156
- timestamp: Date.now(),
1157
- });
1158
- initState = { phase: "awaiting_email", loginOnly: true };
1159
- return { silent: true };
1160
- }
1161
- // No key — ask for email
1162
- ctx.addMessage({
1163
- id: `login-prompt-${Date.now()}`,
1164
- role: "system",
1165
- content: "Enter your email to log in or sign up:",
1166
- timestamp: Date.now(),
1167
- });
1168
- initState = { phase: "awaiting_email", loginOnly: true };
1169
- return { silent: true };
1170
- },
1171
- });
1172
- registerSlashCommand({
1173
- name: "ask",
1174
- description: "Query the context graph",
1175
- usage: "/ask <query>",
1176
- execute: async (args, ctx) => {
1177
- if (!args.trim()) {
1178
- return { output: "Usage: /ask <question>" };
1179
- }
1180
- ctx.setLoading(true, "thinking...");
1181
- try {
1182
- const result = await ctx.dispatch(`ask ${args}`);
1183
- if (result.error)
1184
- return { output: `Error: ${result.error}` };
1185
- return { output: result.output || "(no response)" };
1186
- }
1187
- finally {
1188
- ctx.setLoading(false);
1189
- }
1190
- },
1191
- });
1192
- registerSlashCommand({
1193
- name: "search",
1194
- description: "Fuzzy search across records",
1195
- usage: "/search <query>",
1196
- execute: async (args, ctx) => {
1197
- if (!args.trim()) {
1198
- return { output: "Usage: /search <query>" };
1199
- }
1200
- ctx.setLoading(true, "searching...");
1201
- try {
1202
- const result = await ctx.dispatch(`search ${args}`);
1203
- if (result.error)
1204
- return { output: `Error: ${result.error}` };
1205
- return { output: result.output || "(no results)" };
1206
- }
1207
- finally {
1208
- ctx.setLoading(false);
1209
- }
1210
- },
1211
- });
1212
- registerSlashCommand({
1213
- name: "agents",
1214
- description: "Manage agents — create, start, stop, edit",
1215
- execute: async (_args, ctx) => {
1216
- await openAgentsManager(ctx);
1217
- return { silent: true };
1218
- },
1219
- });
1220
- registerSlashCommand({
1221
- name: "agent",
1222
- description: "Manage agents",
1223
- usage: "/agent <create|start|stop> <slug> [--template <name>]",
1224
- execute: async (args, ctx) => {
1225
- if (!args.trim()) {
1226
- return { output: "Usage: /agent <create|start|stop> <slug> [options]" };
1227
- }
1228
- ctx.setLoading(true, "running agent command...");
1229
- try {
1230
- const result = await ctx.dispatch(`agent ${args}`);
1231
- if (result.error)
1232
- return { output: `Error: ${result.error}` };
1233
- return { output: result.output || "(done)" };
1234
- }
1235
- finally {
1236
- ctx.setLoading(false);
1237
- }
1238
- },
1239
- });
1240
- registerSlashCommand({
1241
- name: "chat",
1242
- description: "Open chat view",
1243
- execute: async (_args, ctx) => {
1244
- ctx.push({ name: "chat" });
1245
- return { output: "Switched to chat view.", silent: true };
1246
- },
1247
- });
1248
- registerSlashCommand({
1249
- name: "calendar",
1250
- description: "Open full calendar view",
1251
- execute: async (_args, ctx) => {
1252
- ctx.push({ name: "calendar" });
1253
- return { output: "Switched to calendar view.", silent: true };
1254
- },
1255
- });
1256
- registerSlashCommand({
1257
- name: "cal",
1258
- description: "Toggle calendar strip on home screen",
1259
- execute: async () => {
1260
- const toggleFn = globalThis.__nexHomeCalendarToggle;
1261
- if (toggleFn) {
1262
- toggleFn();
1263
- return { output: "Calendar toggled.", silent: true };
1264
- }
1265
- return { output: "Calendar toggle only available on home screen." };
1266
- },
1267
- });
1268
- registerSlashCommand({
1269
- name: "orchestration",
1270
- description: "Open orchestration view",
1271
- execute: async (_args, ctx) => {
1272
- ctx.push({ name: "orchestration" });
1273
- return { output: "Switched to orchestration view.", silent: true };
1274
- },
1275
- });
1276
- registerSlashCommand({
1277
- name: "orch",
1278
- description: "Open orchestration view (alias)",
1279
- execute: async (_args, ctx) => {
1280
- ctx.push({ name: "orchestration" });
1281
- return { output: "Switched to orchestration view.", silent: true };
1282
- },
1283
- });
1284
- registerSlashCommand({
1285
- name: "insights",
1286
- description: "Open insights dashboard",
1287
- usage: "/insights [--last <dur>]",
1288
- execute: async (args, ctx) => {
1289
- ctx.setLoading(true, "fetching insights...");
1290
- try {
1291
- const cmdArgs = args ? `insight list ${args}` : "insight list";
1292
- const result = await ctx.dispatch(cmdArgs);
1293
- if (result.error)
1294
- return { output: `Error: ${result.error}` };
1295
- // Parse API response into view props
1296
- const raw = result.data;
1297
- const insights = (raw?.insights ?? []).map((item) => ({
1298
- id: String(item.id ?? ""),
1299
- title: String(item.title ?? item.content ?? ""),
1300
- body: String(item.body ?? item.summary ?? ""),
1301
- priority: normalizePriority(String(item.priority ?? "medium")),
1302
- category: String(item.category ?? item.type ?? "general"),
1303
- recordIds: Array.isArray(item.record_ids) ? item.record_ids.map(String) : [],
1304
- timestamp: String(item.created_at ?? item.timestamp ?? new Date().toISOString()),
1305
- }));
1306
- ctx.push({ name: "insights", props: { insights } });
1307
- return { output: "Switched to insights view.", silent: true };
1308
- }
1309
- finally {
1310
- ctx.setLoading(false);
1311
- }
1312
- },
1313
- });
1314
- function normalizePriority(p) {
1315
- const lower = p.toLowerCase();
1316
- if (lower === "critical" || lower === "crit")
1317
- return "critical";
1318
- if (lower === "high")
1319
- return "high";
1320
- if (lower === "low")
1321
- return "low";
1322
- return "medium";
1323
- }
1324
- registerSlashCommand({
1325
- name: "graph",
1326
- description: "Open workspace graph in browser",
1327
- execute: async (_args, ctx) => {
1328
- ctx.setLoading(true, "opening graph...");
1329
- try {
1330
- const result = await ctx.dispatch("graph");
1331
- if (result.error)
1332
- return { output: `Error: ${result.error}` };
1333
- return { output: result.output || "Graph opened." };
1334
- }
1335
- finally {
1336
- ctx.setLoading(false);
1337
- }
1338
- },
1339
- });
1340
- registerSlashCommand({
1341
- name: "objects",
1342
- description: "List object types",
1343
- execute: async (_args, ctx) => {
1344
- ctx.setLoading(true, "fetching objects...");
1345
- try {
1346
- const result = await ctx.dispatch("object list");
1347
- if (result.error)
1348
- return { output: `Error: ${result.error}` };
1349
- return { output: result.output || "(no objects)" };
1350
- }
1351
- finally {
1352
- ctx.setLoading(false);
1353
- }
1354
- },
1355
- });
1356
- registerSlashCommand({
1357
- name: "records",
1358
- description: "List records for an object",
1359
- usage: "/records <object-slug>",
1360
- execute: async (args, ctx) => {
1361
- if (!args.trim()) {
1362
- return { output: "Usage: /records <object-slug>" };
1363
- }
1364
- ctx.setLoading(true, "fetching records...");
1365
- try {
1366
- const result = await ctx.dispatch(`record list ${args}`);
1367
- if (result.error)
1368
- return { output: `Error: ${result.error}` };
1369
- return { output: result.output || "(no records)" };
1370
- }
1371
- finally {
1372
- ctx.setLoading(false);
1373
- }
1374
- },
1375
- });
1376
- registerSlashCommand({
1377
- name: "remember",
1378
- description: "Store content in context graph",
1379
- usage: "/remember <content>",
1380
- execute: async (args, ctx) => {
1381
- if (!args.trim()) {
1382
- return { output: "Usage: /remember <content>" };
1383
- }
1384
- ctx.setLoading(true, "storing...");
1385
- try {
1386
- const result = await ctx.dispatch(`remember ${args}`);
1387
- if (result.error)
1388
- return { output: `Error: ${result.error}` };
1389
- return { output: result.output || "Stored." };
1390
- }
1391
- finally {
1392
- ctx.setLoading(false);
1393
- }
1394
- },
1395
- });
1396
- registerSlashCommand({
1397
- name: "clear",
1398
- description: "Clear conversation history",
1399
- execute: async () => {
1400
- // Handled specially by the conversation view — it checks for /clear
1401
- // and resets messages. We return a sentinel here.
1402
- return { output: "__CLEAR__", silent: true };
1403
- },
1404
- });
1405
- registerSlashCommand({
1406
- name: "quit",
1407
- description: "Exit Nex",
1408
- execute: async () => {
1409
- process.exit(0);
1410
- return { output: "" };
1411
- },
1412
- });
1413
- registerSlashCommand({
1414
- name: "q",
1415
- description: "Exit Nex (alias)",
1416
- execute: async () => {
1417
- process.exit(0);
1418
- return { output: "" };
1419
- },
1420
- });
1421
- //# sourceMappingURL=slash-commands.js.map