@namzu/cli 0.0.2 → 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 (365) hide show
  1. package/LICENSE.md +110 -0
  2. package/dist/bin.js +4 -32
  3. package/dist/bin.js.map +1 -1
  4. package/dist/cli.d.ts +14 -0
  5. package/dist/cli.d.ts.map +1 -0
  6. package/dist/cli.js +124 -0
  7. package/dist/cli.js.map +1 -0
  8. package/dist/cli.test.d.ts +2 -0
  9. package/dist/cli.test.d.ts.map +1 -0
  10. package/dist/cli.test.js +94 -0
  11. package/dist/cli.test.js.map +1 -0
  12. package/dist/commands/doctor.d.ts +6 -0
  13. package/dist/commands/doctor.d.ts.map +1 -1
  14. package/dist/commands/doctor.js +10 -0
  15. package/dist/commands/doctor.js.map +1 -1
  16. package/dist/commands/providers.d.ts +17 -0
  17. package/dist/commands/providers.d.ts.map +1 -0
  18. package/dist/commands/providers.js +274 -0
  19. package/dist/commands/providers.js.map +1 -0
  20. package/dist/commands/registry.d.ts +11 -0
  21. package/dist/commands/registry.d.ts.map +1 -0
  22. package/dist/commands/registry.js +28 -0
  23. package/dist/commands/registry.js.map +1 -0
  24. package/dist/commands/run.d.ts +14 -0
  25. package/dist/commands/run.d.ts.map +1 -0
  26. package/dist/commands/run.js +73 -0
  27. package/dist/commands/run.js.map +1 -0
  28. package/dist/commands/stubs.d.ts +12 -0
  29. package/dist/commands/stubs.d.ts.map +1 -0
  30. package/dist/commands/stubs.js +32 -0
  31. package/dist/commands/stubs.js.map +1 -0
  32. package/dist/commands/tools.d.ts +16 -0
  33. package/dist/commands/tools.d.ts.map +1 -0
  34. package/dist/commands/tools.js +161 -0
  35. package/dist/commands/tools.js.map +1 -0
  36. package/dist/commands/types.d.ts +25 -0
  37. package/dist/commands/types.d.ts.map +1 -0
  38. package/dist/commands/types.js +2 -0
  39. package/dist/commands/types.js.map +1 -0
  40. package/dist/config/load.d.ts +25 -0
  41. package/dist/config/load.d.ts.map +1 -0
  42. package/dist/config/load.js +92 -0
  43. package/dist/config/load.js.map +1 -0
  44. package/dist/config/load.test.d.ts +2 -0
  45. package/dist/config/load.test.d.ts.map +1 -0
  46. package/dist/config/load.test.js +57 -0
  47. package/dist/config/load.test.js.map +1 -0
  48. package/dist/config/schema.d.ts +29 -0
  49. package/dist/config/schema.d.ts.map +1 -0
  50. package/dist/config/schema.js +13 -0
  51. package/dist/config/schema.js.map +1 -0
  52. package/dist/doctor/registry.d.ts.map +1 -1
  53. package/dist/doctor/registry.js +3 -1
  54. package/dist/doctor/registry.js.map +1 -1
  55. package/dist/doctor/registry.test.js +4 -1
  56. package/dist/doctor/registry.test.js.map +1 -1
  57. package/dist/index.d.ts +6 -0
  58. package/dist/index.d.ts.map +1 -1
  59. package/dist/index.js +7 -0
  60. package/dist/index.js.map +1 -1
  61. package/dist/integrations/clawtool/agents.d.ts +31 -0
  62. package/dist/integrations/clawtool/agents.d.ts.map +1 -0
  63. package/dist/integrations/clawtool/agents.js +30 -0
  64. package/dist/integrations/clawtool/agents.js.map +1 -0
  65. package/dist/integrations/clawtool/agents.test.d.ts +2 -0
  66. package/dist/integrations/clawtool/agents.test.d.ts.map +1 -0
  67. package/dist/integrations/clawtool/agents.test.js +79 -0
  68. package/dist/integrations/clawtool/agents.test.js.map +1 -0
  69. package/dist/integrations/clawtool/auth.d.ts +26 -0
  70. package/dist/integrations/clawtool/auth.d.ts.map +1 -0
  71. package/dist/integrations/clawtool/auth.js +56 -0
  72. package/dist/integrations/clawtool/auth.js.map +1 -0
  73. package/dist/integrations/clawtool/auth.test.d.ts +2 -0
  74. package/dist/integrations/clawtool/auth.test.d.ts.map +1 -0
  75. package/dist/integrations/clawtool/auth.test.js +40 -0
  76. package/dist/integrations/clawtool/auth.test.js.map +1 -0
  77. package/dist/integrations/clawtool/binary.d.ts +25 -0
  78. package/dist/integrations/clawtool/binary.d.ts.map +1 -0
  79. package/dist/integrations/clawtool/binary.js +50 -0
  80. package/dist/integrations/clawtool/binary.js.map +1 -0
  81. package/dist/integrations/clawtool/binary.test.d.ts +2 -0
  82. package/dist/integrations/clawtool/binary.test.d.ts.map +1 -0
  83. package/dist/integrations/clawtool/binary.test.js +42 -0
  84. package/dist/integrations/clawtool/binary.test.js.map +1 -0
  85. package/dist/integrations/clawtool/daemon.d.ts +37 -0
  86. package/dist/integrations/clawtool/daemon.d.ts.map +1 -0
  87. package/dist/integrations/clawtool/daemon.js +109 -0
  88. package/dist/integrations/clawtool/daemon.js.map +1 -0
  89. package/dist/integrations/clawtool/daemon.test.d.ts +11 -0
  90. package/dist/integrations/clawtool/daemon.test.d.ts.map +1 -0
  91. package/dist/integrations/clawtool/daemon.test.js +118 -0
  92. package/dist/integrations/clawtool/daemon.test.js.map +1 -0
  93. package/dist/integrations/clawtool/dispatch.d.ts +33 -0
  94. package/dist/integrations/clawtool/dispatch.d.ts.map +1 -0
  95. package/dist/integrations/clawtool/dispatch.js +155 -0
  96. package/dist/integrations/clawtool/dispatch.js.map +1 -0
  97. package/dist/integrations/clawtool/dispatch.test.d.ts +2 -0
  98. package/dist/integrations/clawtool/dispatch.test.d.ts.map +1 -0
  99. package/dist/integrations/clawtool/dispatch.test.js +138 -0
  100. package/dist/integrations/clawtool/dispatch.test.js.map +1 -0
  101. package/dist/integrations/clawtool/index.d.ts +11 -0
  102. package/dist/integrations/clawtool/index.d.ts.map +1 -0
  103. package/dist/integrations/clawtool/index.js +10 -0
  104. package/dist/integrations/clawtool/index.js.map +1 -0
  105. package/dist/integrations/clawtool/mcp.d.ts +51 -0
  106. package/dist/integrations/clawtool/mcp.d.ts.map +1 -0
  107. package/dist/integrations/clawtool/mcp.js +156 -0
  108. package/dist/integrations/clawtool/mcp.js.map +1 -0
  109. package/dist/integrations/clawtool/mcp.test.d.ts +2 -0
  110. package/dist/integrations/clawtool/mcp.test.d.ts.map +1 -0
  111. package/dist/integrations/clawtool/mcp.test.js +126 -0
  112. package/dist/integrations/clawtool/mcp.test.js.map +1 -0
  113. package/dist/integrations/clawtool/paths.d.ts +8 -0
  114. package/dist/integrations/clawtool/paths.d.ts.map +1 -0
  115. package/dist/integrations/clawtool/paths.js +19 -0
  116. package/dist/integrations/clawtool/paths.js.map +1 -0
  117. package/dist/integrations/clawtool/peers.d.ts +67 -0
  118. package/dist/integrations/clawtool/peers.d.ts.map +1 -0
  119. package/dist/integrations/clawtool/peers.js +150 -0
  120. package/dist/integrations/clawtool/peers.js.map +1 -0
  121. package/dist/integrations/clawtool/plugin.d.ts +42 -0
  122. package/dist/integrations/clawtool/plugin.d.ts.map +1 -0
  123. package/dist/integrations/clawtool/plugin.js +38 -0
  124. package/dist/integrations/clawtool/plugin.js.map +1 -0
  125. package/dist/integrations/clawtool/state.d.ts +11 -0
  126. package/dist/integrations/clawtool/state.d.ts.map +1 -0
  127. package/dist/integrations/clawtool/state.js +41 -0
  128. package/dist/integrations/clawtool/state.js.map +1 -0
  129. package/dist/integrations/clawtool/state.test.d.ts +2 -0
  130. package/dist/integrations/clawtool/state.test.d.ts.map +1 -0
  131. package/dist/integrations/clawtool/state.test.js +38 -0
  132. package/dist/integrations/clawtool/state.test.js.map +1 -0
  133. package/dist/integrations/clawtool/tooling.d.ts +50 -0
  134. package/dist/integrations/clawtool/tooling.d.ts.map +1 -0
  135. package/dist/integrations/clawtool/tooling.js +89 -0
  136. package/dist/integrations/clawtool/tooling.js.map +1 -0
  137. package/dist/integrations/clawtool/tooling.test.d.ts +2 -0
  138. package/dist/integrations/clawtool/tooling.test.d.ts.map +1 -0
  139. package/dist/integrations/clawtool/tooling.test.js +58 -0
  140. package/dist/integrations/clawtool/tooling.test.js.map +1 -0
  141. package/dist/integrations/clawtool/types.d.ts +41 -0
  142. package/dist/integrations/clawtool/types.d.ts.map +1 -0
  143. package/dist/integrations/clawtool/types.js +9 -0
  144. package/dist/integrations/clawtool/types.js.map +1 -0
  145. package/dist/integrations/clipboard/image.d.ts +18 -0
  146. package/dist/integrations/clipboard/image.d.ts.map +1 -0
  147. package/dist/integrations/clipboard/image.js +88 -0
  148. package/dist/integrations/clipboard/image.js.map +1 -0
  149. package/dist/integrations/providers/discover.d.ts +68 -0
  150. package/dist/integrations/providers/discover.d.ts.map +1 -0
  151. package/dist/integrations/providers/discover.js +108 -0
  152. package/dist/integrations/providers/discover.js.map +1 -0
  153. package/dist/integrations/providers/discover.test.d.ts +2 -0
  154. package/dist/integrations/providers/discover.test.d.ts.map +1 -0
  155. package/dist/integrations/providers/discover.test.js +120 -0
  156. package/dist/integrations/providers/discover.test.js.map +1 -0
  157. package/dist/integrations/providers/index.d.ts +10 -0
  158. package/dist/integrations/providers/index.d.ts.map +1 -0
  159. package/dist/integrations/providers/index.js +12 -0
  160. package/dist/integrations/providers/index.js.map +1 -0
  161. package/dist/integrations/providers/keychain.d.ts +44 -0
  162. package/dist/integrations/providers/keychain.d.ts.map +1 -0
  163. package/dist/integrations/providers/keychain.js +154 -0
  164. package/dist/integrations/providers/keychain.js.map +1 -0
  165. package/dist/integrations/providers/keychain.test.d.ts +2 -0
  166. package/dist/integrations/providers/keychain.test.d.ts.map +1 -0
  167. package/dist/integrations/providers/keychain.test.js +21 -0
  168. package/dist/integrations/providers/keychain.test.js.map +1 -0
  169. package/dist/integrations/providers/mask.d.ts +7 -0
  170. package/dist/integrations/providers/mask.d.ts.map +1 -0
  171. package/dist/integrations/providers/mask.js +14 -0
  172. package/dist/integrations/providers/mask.js.map +1 -0
  173. package/dist/integrations/providers/mask.test.d.ts +2 -0
  174. package/dist/integrations/providers/mask.test.d.ts.map +1 -0
  175. package/dist/integrations/providers/mask.test.js +20 -0
  176. package/dist/integrations/providers/mask.test.js.map +1 -0
  177. package/dist/integrations/providers/oauth.d.ts +28 -0
  178. package/dist/integrations/providers/oauth.d.ts.map +1 -0
  179. package/dist/integrations/providers/oauth.js +65 -0
  180. package/dist/integrations/providers/oauth.js.map +1 -0
  181. package/dist/integrations/providers/oauth.test.d.ts +2 -0
  182. package/dist/integrations/providers/oauth.test.d.ts.map +1 -0
  183. package/dist/integrations/providers/oauth.test.js +86 -0
  184. package/dist/integrations/providers/oauth.test.js.map +1 -0
  185. package/dist/integrations/providers/preferences.d.ts +43 -0
  186. package/dist/integrations/providers/preferences.d.ts.map +1 -0
  187. package/dist/integrations/providers/preferences.js +111 -0
  188. package/dist/integrations/providers/preferences.js.map +1 -0
  189. package/dist/integrations/providers/preferences.test.d.ts +2 -0
  190. package/dist/integrations/providers/preferences.test.d.ts.map +1 -0
  191. package/dist/integrations/providers/preferences.test.js +68 -0
  192. package/dist/integrations/providers/preferences.test.js.map +1 -0
  193. package/dist/integrations/providers/registry.d.ts +31 -0
  194. package/dist/integrations/providers/registry.d.ts.map +1 -0
  195. package/dist/integrations/providers/registry.js +79 -0
  196. package/dist/integrations/providers/registry.js.map +1 -0
  197. package/dist/integrations/providers/schema.d.ts +73 -0
  198. package/dist/integrations/providers/schema.d.ts.map +1 -0
  199. package/dist/integrations/providers/schema.js +70 -0
  200. package/dist/integrations/providers/schema.js.map +1 -0
  201. package/dist/integrations/providers/schema.test.d.ts +2 -0
  202. package/dist/integrations/providers/schema.test.d.ts.map +1 -0
  203. package/dist/integrations/providers/schema.test.js +43 -0
  204. package/dist/integrations/providers/schema.test.js.map +1 -0
  205. package/dist/integrations/providers/secrets.d.ts +37 -0
  206. package/dist/integrations/providers/secrets.d.ts.map +1 -0
  207. package/dist/integrations/providers/secrets.js +69 -0
  208. package/dist/integrations/providers/secrets.js.map +1 -0
  209. package/dist/integrations/providers/store.d.ts +32 -0
  210. package/dist/integrations/providers/store.d.ts.map +1 -0
  211. package/dist/integrations/providers/store.js +133 -0
  212. package/dist/integrations/providers/store.js.map +1 -0
  213. package/dist/integrations/providers/store.test.d.ts +2 -0
  214. package/dist/integrations/providers/store.test.d.ts.map +1 -0
  215. package/dist/integrations/providers/store.test.js +127 -0
  216. package/dist/integrations/providers/store.test.js.map +1 -0
  217. package/dist/integrations/sessions/store.d.ts +40 -0
  218. package/dist/integrations/sessions/store.d.ts.map +1 -0
  219. package/dist/integrations/sessions/store.js +90 -0
  220. package/dist/integrations/sessions/store.js.map +1 -0
  221. package/dist/integrations/subagents/runtime.d.ts +37 -0
  222. package/dist/integrations/subagents/runtime.d.ts.map +1 -0
  223. package/dist/integrations/subagents/runtime.js +183 -0
  224. package/dist/integrations/subagents/runtime.js.map +1 -0
  225. package/dist/integrations/trust/store.d.ts +16 -0
  226. package/dist/integrations/trust/store.d.ts.map +1 -0
  227. package/dist/integrations/trust/store.js +59 -0
  228. package/dist/integrations/trust/store.js.map +1 -0
  229. package/dist/integrations/trust/store.test.d.ts +2 -0
  230. package/dist/integrations/trust/store.test.d.ts.map +1 -0
  231. package/dist/integrations/trust/store.test.js +50 -0
  232. package/dist/integrations/trust/store.test.js.map +1 -0
  233. package/dist/integrations/updates.d.ts +27 -0
  234. package/dist/integrations/updates.d.ts.map +1 -0
  235. package/dist/integrations/updates.js +99 -0
  236. package/dist/integrations/updates.js.map +1 -0
  237. package/dist/memory/store.d.ts +29 -0
  238. package/dist/memory/store.d.ts.map +1 -0
  239. package/dist/memory/store.js +74 -0
  240. package/dist/memory/store.js.map +1 -0
  241. package/dist/memory/store.test.d.ts +2 -0
  242. package/dist/memory/store.test.d.ts.map +1 -0
  243. package/dist/memory/store.test.js +63 -0
  244. package/dist/memory/store.test.js.map +1 -0
  245. package/dist/output/formatter.d.ts +30 -0
  246. package/dist/output/formatter.d.ts.map +1 -0
  247. package/dist/output/formatter.js +16 -0
  248. package/dist/output/formatter.js.map +1 -0
  249. package/dist/output/formatter.test.d.ts +2 -0
  250. package/dist/output/formatter.test.d.ts.map +1 -0
  251. package/dist/output/formatter.test.js +88 -0
  252. package/dist/output/formatter.test.js.map +1 -0
  253. package/dist/output/index.d.ts +5 -0
  254. package/dist/output/index.d.ts.map +1 -0
  255. package/dist/output/index.js +22 -0
  256. package/dist/output/index.js.map +1 -0
  257. package/dist/output/json.d.ts +13 -0
  258. package/dist/output/json.d.ts.map +1 -0
  259. package/dist/output/json.js +51 -0
  260. package/dist/output/json.js.map +1 -0
  261. package/dist/output/text.d.ts +13 -0
  262. package/dist/output/text.d.ts.map +1 -0
  263. package/dist/output/text.js +36 -0
  264. package/dist/output/text.js.map +1 -0
  265. package/dist/output/yaml.d.ts +13 -0
  266. package/dist/output/yaml.d.ts.map +1 -0
  267. package/dist/output/yaml.js +26 -0
  268. package/dist/output/yaml.js.map +1 -0
  269. package/dist/skills/store.d.ts +49 -0
  270. package/dist/skills/store.d.ts.map +1 -0
  271. package/dist/skills/store.js +109 -0
  272. package/dist/skills/store.js.map +1 -0
  273. package/dist/skills/store.test.d.ts +2 -0
  274. package/dist/skills/store.test.d.ts.map +1 -0
  275. package/dist/skills/store.test.js +80 -0
  276. package/dist/skills/store.test.js.map +1 -0
  277. package/dist/tui/App.d.ts +18 -0
  278. package/dist/tui/App.d.ts.map +1 -0
  279. package/dist/tui/App.js +742 -0
  280. package/dist/tui/App.js.map +1 -0
  281. package/dist/tui/Composer.d.ts +17 -0
  282. package/dist/tui/Composer.d.ts.map +1 -0
  283. package/dist/tui/Composer.js +123 -0
  284. package/dist/tui/Composer.js.map +1 -0
  285. package/dist/tui/LiveActivity.d.ts +22 -0
  286. package/dist/tui/LiveActivity.d.ts.map +1 -0
  287. package/dist/tui/LiveActivity.js +46 -0
  288. package/dist/tui/LiveActivity.js.map +1 -0
  289. package/dist/tui/Markdown.d.ts +18 -0
  290. package/dist/tui/Markdown.d.ts.map +1 -0
  291. package/dist/tui/Markdown.js +68 -0
  292. package/dist/tui/Markdown.js.map +1 -0
  293. package/dist/tui/PermissionOverlay.d.ts +14 -0
  294. package/dist/tui/PermissionOverlay.d.ts.map +1 -0
  295. package/dist/tui/PermissionOverlay.js +22 -0
  296. package/dist/tui/PermissionOverlay.js.map +1 -0
  297. package/dist/tui/Picker.d.ts +20 -0
  298. package/dist/tui/Picker.d.ts.map +1 -0
  299. package/dist/tui/Picker.js +72 -0
  300. package/dist/tui/Picker.js.map +1 -0
  301. package/dist/tui/ResumePicker.d.ts +12 -0
  302. package/dist/tui/ResumePicker.d.ts.map +1 -0
  303. package/dist/tui/ResumePicker.js +26 -0
  304. package/dist/tui/ResumePicker.js.map +1 -0
  305. package/dist/tui/StatusBar.d.ts +22 -0
  306. package/dist/tui/StatusBar.d.ts.map +1 -0
  307. package/dist/tui/StatusBar.js +73 -0
  308. package/dist/tui/StatusBar.js.map +1 -0
  309. package/dist/tui/Transcript.d.ts +29 -0
  310. package/dist/tui/Transcript.d.ts.map +1 -0
  311. package/dist/tui/Transcript.js +105 -0
  312. package/dist/tui/Transcript.js.map +1 -0
  313. package/dist/tui/TrustPrompt.d.ts +11 -0
  314. package/dist/tui/TrustPrompt.d.ts.map +1 -0
  315. package/dist/tui/TrustPrompt.js +13 -0
  316. package/dist/tui/TrustPrompt.js.map +1 -0
  317. package/dist/tui/agent.d.ts +163 -0
  318. package/dist/tui/agent.d.ts.map +1 -0
  319. package/dist/tui/agent.js +684 -0
  320. package/dist/tui/agent.js.map +1 -0
  321. package/dist/tui/agent.test.d.ts +2 -0
  322. package/dist/tui/agent.test.d.ts.map +1 -0
  323. package/dist/tui/agent.test.js +225 -0
  324. package/dist/tui/agent.test.js.map +1 -0
  325. package/dist/tui/index.d.ts +7 -0
  326. package/dist/tui/index.d.ts.map +1 -0
  327. package/dist/tui/index.js +29 -0
  328. package/dist/tui/index.js.map +1 -0
  329. package/dist/tui/logo.d.ts +23 -0
  330. package/dist/tui/logo.d.ts.map +1 -0
  331. package/dist/tui/logo.js +35 -0
  332. package/dist/tui/logo.js.map +1 -0
  333. package/dist/tui/markdownParser.d.ts +45 -0
  334. package/dist/tui/markdownParser.d.ts.map +1 -0
  335. package/dist/tui/markdownParser.js +127 -0
  336. package/dist/tui/markdownParser.js.map +1 -0
  337. package/dist/tui/markdownParser.test.d.ts +2 -0
  338. package/dist/tui/markdownParser.test.d.ts.map +1 -0
  339. package/dist/tui/markdownParser.test.js +90 -0
  340. package/dist/tui/markdownParser.test.js.map +1 -0
  341. package/dist/tui/mentions.d.ts +22 -0
  342. package/dist/tui/mentions.d.ts.map +1 -0
  343. package/dist/tui/mentions.js +59 -0
  344. package/dist/tui/mentions.js.map +1 -0
  345. package/dist/tui/mentions.test.d.ts +2 -0
  346. package/dist/tui/mentions.test.d.ts.map +1 -0
  347. package/dist/tui/mentions.test.js +35 -0
  348. package/dist/tui/mentions.test.js.map +1 -0
  349. package/dist/tui/slashCommands.d.ts +64 -0
  350. package/dist/tui/slashCommands.d.ts.map +1 -0
  351. package/dist/tui/slashCommands.js +153 -0
  352. package/dist/tui/slashCommands.js.map +1 -0
  353. package/dist/tui/slashCommands.test.d.ts +2 -0
  354. package/dist/tui/slashCommands.test.d.ts.map +1 -0
  355. package/dist/tui/slashCommands.test.js +114 -0
  356. package/dist/tui/slashCommands.test.js.map +1 -0
  357. package/dist/tui/theme.d.ts +34 -0
  358. package/dist/tui/theme.d.ts.map +1 -0
  359. package/dist/tui/theme.js +32 -0
  360. package/dist/tui/theme.js.map +1 -0
  361. package/dist/tui/types.d.ts +27 -0
  362. package/dist/tui/types.d.ts.map +1 -0
  363. package/dist/tui/types.js +7 -0
  364. package/dist/tui/types.js.map +1 -0
  365. package/package.json +67 -57
@@ -0,0 +1,90 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { parseInline, parseMarkdown } from './markdownParser.js';
3
+ describe('parseMarkdown', () => {
4
+ it('parses a fenced code block with a language', () => {
5
+ const blocks = parseMarkdown('before\n```ts\nconst x = 1\nconst y = 2\n```\nafter');
6
+ expect(blocks).toEqual([
7
+ { type: 'paragraph', text: 'before' },
8
+ { type: 'code', lang: 'ts', lines: ['const x = 1', 'const y = 2'] },
9
+ { type: 'paragraph', text: 'after' },
10
+ ]);
11
+ });
12
+ it('parses headings at varying levels', () => {
13
+ expect(parseMarkdown('# Title')).toEqual([{ type: 'heading', level: 1, text: 'Title' }]);
14
+ expect(parseMarkdown('### Sub')).toEqual([{ type: 'heading', level: 3, text: 'Sub' }]);
15
+ });
16
+ it('parses unordered and ordered list items', () => {
17
+ const blocks = parseMarkdown('- one\n- two\n1. first\n2) second');
18
+ expect(blocks).toEqual([
19
+ { type: 'bullet', ordered: false, marker: '•', text: 'one' },
20
+ { type: 'bullet', ordered: false, marker: '•', text: 'two' },
21
+ { type: 'bullet', ordered: true, marker: '1', text: 'first' },
22
+ { type: 'bullet', ordered: true, marker: '2', text: 'second' },
23
+ ]);
24
+ });
25
+ it('merges consecutive plain lines into one paragraph and splits on blanks', () => {
26
+ const blocks = parseMarkdown('line one\nline two\n\nsecond para');
27
+ expect(blocks).toEqual([
28
+ { type: 'paragraph', text: 'line one line two' },
29
+ { type: 'paragraph', text: 'second para' },
30
+ ]);
31
+ });
32
+ it('keeps code content verbatim (no markdown interpretation inside)', () => {
33
+ const blocks = parseMarkdown('```\n# not a heading\n- not a bullet\n```');
34
+ expect(blocks).toEqual([
35
+ { type: 'code', lang: undefined, lines: ['# not a heading', '- not a bullet'] },
36
+ ]);
37
+ });
38
+ });
39
+ describe('parseInline', () => {
40
+ it('splits bold, italic, and inline code', () => {
41
+ expect(parseInline('a **b** c `d` e *f*')).toEqual([
42
+ { text: 'a ' },
43
+ { text: 'b', bold: true },
44
+ { text: ' c ' },
45
+ { text: 'd', code: true },
46
+ { text: ' e ' },
47
+ { text: 'f', italic: true },
48
+ ]);
49
+ });
50
+ it('treats __x__ as bold and _x_ as italic', () => {
51
+ expect(parseInline('__b__ and _i_')).toEqual([
52
+ { text: 'b', bold: true },
53
+ { text: ' and ' },
54
+ { text: 'i', italic: true },
55
+ ]);
56
+ });
57
+ it('returns a single span for plain text', () => {
58
+ expect(parseInline('just text')).toEqual([{ text: 'just text' }]);
59
+ });
60
+ it('does not parse markers inside inline code', () => {
61
+ expect(parseInline('`a*b*c`')).toEqual([{ text: 'a*b*c', code: true }]);
62
+ });
63
+ it('parses a [text](url) link', () => {
64
+ expect(parseInline('see [the docs](https://x.dev/a) now')).toEqual([
65
+ { text: 'see ' },
66
+ { text: 'the docs', link: 'https://x.dev/a' },
67
+ { text: ' now' },
68
+ ]);
69
+ });
70
+ });
71
+ describe('parseMarkdown tables', () => {
72
+ it('parses a pipe table with header + separator + rows', () => {
73
+ const blocks = parseMarkdown('| A | B |\n|---|---|\n| 1 | 2 |\n| 3 | 4 |');
74
+ expect(blocks).toEqual([
75
+ {
76
+ type: 'table',
77
+ headers: ['A', 'B'],
78
+ rows: [
79
+ ['1', '2'],
80
+ ['3', '4'],
81
+ ],
82
+ },
83
+ ]);
84
+ });
85
+ it('does not treat a lone pipe line without a separator as a table', () => {
86
+ const blocks = parseMarkdown('| not | a table |\njust text');
87
+ expect(blocks[0]?.type).toBe('paragraph');
88
+ });
89
+ });
90
+ //# sourceMappingURL=markdownParser.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"markdownParser.test.js","sourceRoot":"","sources":["../../src/tui/markdownParser.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * `@file` mentions in a composed message. Typing `@src/auth.ts` inlines that
3
+ * file's contents into the text sent to the model (Claude Code / opencode
4
+ * style), while the visible message keeps the readable `@path` token.
5
+ *
6
+ * Safety: only files resolving *inside* the working directory are inlined
7
+ * (so `@/etc/passwd` or `@../secrets` are ignored, not exfiltrated), and each
8
+ * file is capped so a huge file can't blow up the turn. Non-existent or
9
+ * unreadable tokens are left as literal text.
10
+ */
11
+ export interface ExpandedMessage {
12
+ /** Text to send to the model (original + inlined `<file>` blocks). */
13
+ readonly sendText: string;
14
+ /** Relative paths that were inlined (for a UI affordance). */
15
+ readonly attached: readonly string[];
16
+ }
17
+ /**
18
+ * Expand `@path` tokens in `text`. `readFile` is injectable for tests; the
19
+ * default reads from disk, scoped to `cwd` and size-capped.
20
+ */
21
+ export declare function expandFileMentions(text: string, cwd: string, readFile?: (relPath: string) => string | null): ExpandedMessage;
22
+ //# sourceMappingURL=mentions.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mentions.d.ts","sourceRoot":"","sources":["../../src/tui/mentions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAUH,MAAM,WAAW,eAAe;IAC/B,sEAAsE;IACtE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,8DAA8D;IAC9D,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CACpC;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CACjC,IAAI,EAAE,MAAM,EACZ,GAAG,EAAE,MAAM,EACX,QAAQ,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,MAAM,GAAG,IAAuC,GAC7E,eAAe,CAmBjB"}
@@ -0,0 +1,59 @@
1
+ /**
2
+ * `@file` mentions in a composed message. Typing `@src/auth.ts` inlines that
3
+ * file's contents into the text sent to the model (Claude Code / opencode
4
+ * style), while the visible message keeps the readable `@path` token.
5
+ *
6
+ * Safety: only files resolving *inside* the working directory are inlined
7
+ * (so `@/etc/passwd` or `@../secrets` are ignored, not exfiltrated), and each
8
+ * file is capped so a huge file can't blow up the turn. Non-existent or
9
+ * unreadable tokens are left as literal text.
10
+ */
11
+ import { readFileSync, statSync } from 'node:fs';
12
+ import { resolve, sep } from 'node:path';
13
+ /** Path-ish characters only, so `@a.ts,` or `@a.ts)` don't swallow punctuation. */
14
+ const MENTION = /@([\w./~-]+)/g;
15
+ const MAX_FILE_CHARS = 60_000;
16
+ /**
17
+ * Expand `@path` tokens in `text`. `readFile` is injectable for tests; the
18
+ * default reads from disk, scoped to `cwd` and size-capped.
19
+ */
20
+ export function expandFileMentions(text, cwd, readFile = (rel) => safeReadInCwd(cwd, rel)) {
21
+ const tokens = text.match(MENTION);
22
+ if (!tokens)
23
+ return { sendText: text, attached: [] };
24
+ const attached = [];
25
+ const blocks = [];
26
+ const seen = new Set();
27
+ for (const tok of tokens) {
28
+ // Drop trailing sentence punctuation the path-char class still captured
29
+ // (e.g. the final `.` in "see @b.ts.").
30
+ const rel = tok.slice(1).replace(/[.,;:!?]+$/, '');
31
+ if (rel.length === 0 || seen.has(rel))
32
+ continue;
33
+ seen.add(rel);
34
+ const content = readFile(rel);
35
+ if (content === null)
36
+ continue;
37
+ blocks.push(`<file path="${rel}">\n${content}\n</file>`);
38
+ attached.push(rel);
39
+ }
40
+ if (blocks.length === 0)
41
+ return { sendText: text, attached: [] };
42
+ return { sendText: `${text}\n\n${blocks.join('\n\n')}`, attached };
43
+ }
44
+ function safeReadInCwd(cwd, rel) {
45
+ const root = resolve(cwd);
46
+ const abs = resolve(root, rel);
47
+ if (abs !== root && !abs.startsWith(root + sep))
48
+ return null;
49
+ try {
50
+ if (!statSync(abs).isFile())
51
+ return null;
52
+ const raw = readFileSync(abs, 'utf8');
53
+ return raw.length > MAX_FILE_CHARS ? `${raw.slice(0, MAX_FILE_CHARS)}\n… (truncated)` : raw;
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ }
59
+ //# sourceMappingURL=mentions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mentions.js","sourceRoot":"","sources":["../../src/tui/mentions.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;AAChD,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAA;AAExC,mFAAmF;AACnF,MAAM,OAAO,GAAG,eAAe,CAAA;AAE/B,MAAM,cAAc,GAAG,MAAM,CAAA;AAS7B;;;GAGG;AACH,MAAM,UAAU,kBAAkB,CACjC,IAAY,EACZ,GAAW,EACX,WAA+C,CAAC,GAAG,EAAE,EAAE,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC;IAE/E,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IAClC,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAA;IACpD,MAAM,QAAQ,GAAa,EAAE,CAAA;IAC7B,MAAM,MAAM,GAAa,EAAE,CAAA;IAC3B,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9B,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QAC1B,wEAAwE;QACxE,wCAAwC;QACxC,MAAM,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,YAAY,EAAE,EAAE,CAAC,CAAA;QAClD,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAQ;QAC/C,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;QACb,MAAM,OAAO,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAA;QAC7B,IAAI,OAAO,KAAK,IAAI;YAAE,SAAQ;QAC9B,MAAM,CAAC,IAAI,CAAC,eAAe,GAAG,OAAO,OAAO,WAAW,CAAC,CAAA;QACxD,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;IACnB,CAAC;IACD,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAA;IAChE,OAAO,EAAE,QAAQ,EAAE,GAAG,IAAI,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,CAAA;AACnE,CAAC;AAED,SAAS,aAAa,CAAC,GAAW,EAAE,GAAW;IAC9C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;IACzB,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAA;IAC9B,IAAI,GAAG,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,GAAG,GAAG,CAAC;QAAE,OAAO,IAAI,CAAA;IAC5D,IAAI,CAAC;QACJ,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE;YAAE,OAAO,IAAI,CAAA;QACxC,MAAM,GAAG,GAAG,YAAY,CAAC,GAAG,EAAE,MAAM,CAAC,CAAA;QACrC,OAAO,GAAG,CAAC,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,iBAAiB,CAAC,CAAC,CAAC,GAAG,CAAA;IAC5F,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAA;IACZ,CAAC;AACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=mentions.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mentions.test.d.ts","sourceRoot":"","sources":["../../src/tui/mentions.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,35 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { expandFileMentions } from './mentions.js';
3
+ const fake = (files) => (rel) => files[rel] ?? null;
4
+ describe('expandFileMentions', () => {
5
+ it('inlines a mentioned file and reports it', () => {
6
+ const { sendText, attached } = expandFileMentions('fix @src/auth.ts please', '/repo', fake({ 'src/auth.ts': 'export const x = 1' }));
7
+ expect(attached).toEqual(['src/auth.ts']);
8
+ expect(sendText).toContain('fix @src/auth.ts please');
9
+ expect(sendText).toContain('<file path="src/auth.ts">\nexport const x = 1\n</file>');
10
+ });
11
+ it('leaves text untouched when there are no mentions', () => {
12
+ const r = expandFileMentions('no mentions here', '/repo', fake({}));
13
+ expect(r).toEqual({ sendText: 'no mentions here', attached: [] });
14
+ });
15
+ it('ignores tokens that do not resolve to a readable file', () => {
16
+ const r = expandFileMentions('@missing.ts', '/repo', fake({}));
17
+ expect(r.attached).toEqual([]);
18
+ expect(r.sendText).toBe('@missing.ts');
19
+ });
20
+ it('de-duplicates repeated mentions', () => {
21
+ const { attached } = expandFileMentions('@a.ts and again @a.ts', '/repo', fake({ 'a.ts': 'x' }));
22
+ expect(attached).toEqual(['a.ts']);
23
+ });
24
+ it('does not swallow trailing punctuation into the path', () => {
25
+ const { attached } = expandFileMentions('see @a.ts, @b.ts.', '/repo', fake({ 'a.ts': '1', 'b.ts': '2' }));
26
+ expect(attached).toEqual(['a.ts', 'b.ts']);
27
+ });
28
+ it('inlines multiple distinct files', () => {
29
+ const { attached, sendText } = expandFileMentions('@a.ts @b.ts', '/repo', fake({ 'a.ts': 'A', 'b.ts': 'B' }));
30
+ expect(attached).toEqual(['a.ts', 'b.ts']);
31
+ expect(sendText).toContain('<file path="a.ts">');
32
+ expect(sendText).toContain('<file path="b.ts">');
33
+ });
34
+ });
35
+ //# sourceMappingURL=mentions.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mentions.test.js","sourceRoot":"","sources":["../../src/tui/mentions.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Slash command registry + parser. Pure logic — no React. Unit-tested.
3
+ *
4
+ * A command's `action` returns either a `system` message to push onto the
5
+ * transcript, an `exit` signal, or `void` (no transcript change). The
6
+ * caller (App) maps results onto state.
7
+ */
8
+ export type SlashAction = {
9
+ kind: 'message';
10
+ role: 'system';
11
+ content: string;
12
+ } | {
13
+ kind: 'exit';
14
+ } | {
15
+ kind: 'clear';
16
+ } | {
17
+ kind: 'repick';
18
+ } | {
19
+ kind: 'remember';
20
+ text: string;
21
+ } | {
22
+ kind: 'show-memory';
23
+ } | {
24
+ kind: 'list-skills';
25
+ } | {
26
+ kind: 'load-skill';
27
+ name: string;
28
+ } | {
29
+ kind: 'resume';
30
+ } | {
31
+ kind: 'list-agents';
32
+ } | {
33
+ kind: 'send-peer';
34
+ peer: string;
35
+ text: string;
36
+ } | {
37
+ kind: 'none';
38
+ };
39
+ export interface SlashContext {
40
+ readonly availableTools: readonly string[];
41
+ readonly providerSummary: string | null;
42
+ readonly modelSummary: string | null;
43
+ }
44
+ export interface SlashCommand {
45
+ readonly name: string;
46
+ readonly description: string;
47
+ readonly action: (ctx: SlashContext, args: readonly string[]) => SlashAction;
48
+ }
49
+ export interface ParsedSlash {
50
+ readonly name: string;
51
+ readonly args: readonly string[];
52
+ }
53
+ /**
54
+ * Autocomplete matches for a composer value that is a command-in-progress
55
+ * (`/`, `/me`, `/mo…` — slash + a partial name, no space yet). Returns []
56
+ * once a space is typed (the user has moved on to arguments) or the value
57
+ * isn't a slash command, so the dropdown only shows while picking a name.
58
+ */
59
+ export declare function matchSlashCommands(value: string): SlashCommand[];
60
+ /** Returns null when the line is not a slash command. */
61
+ export declare function parseSlash(line: string): ParsedSlash | null;
62
+ export declare const SLASH_COMMANDS: readonly SlashCommand[];
63
+ export declare function runSlash(line: string, ctx: SlashContext): SlashAction | null;
64
+ //# sourceMappingURL=slashCommands.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slashCommands.d.ts","sourceRoot":"","sources":["../../src/tui/slashCommands.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,WAAW,GACpB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,QAAQ,CAAA;CAAE,GAClB;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,CAAA;AAEnB,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;IAC1C,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IACvC,QAAQ,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;CACpC;AAED,MAAM,WAAW,YAAY;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAA;IAC5B,QAAQ,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,KAAK,WAAW,CAAA;CAC5E;AAED,MAAM,WAAW,WAAW;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAA;CAChC;AAED;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,MAAM,GAAG,YAAY,EAAE,CAKhE;AAED,yDAAyD;AACzD,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,IAAI,CAM3D;AAED,eAAO,MAAM,cAAc,EAAE,SAAS,YAAY,EA6GjD,CAAA;AAED,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,YAAY,GAAG,WAAW,GAAG,IAAI,CAY5E"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Slash command registry + parser. Pure logic — no React. Unit-tested.
3
+ *
4
+ * A command's `action` returns either a `system` message to push onto the
5
+ * transcript, an `exit` signal, or `void` (no transcript change). The
6
+ * caller (App) maps results onto state.
7
+ */
8
+ /**
9
+ * Autocomplete matches for a composer value that is a command-in-progress
10
+ * (`/`, `/me`, `/mo…` — slash + a partial name, no space yet). Returns []
11
+ * once a space is typed (the user has moved on to arguments) or the value
12
+ * isn't a slash command, so the dropdown only shows while picking a name.
13
+ */
14
+ export function matchSlashCommands(value) {
15
+ const m = /^\/([\w-]*)$/.exec(value);
16
+ if (!m)
17
+ return [];
18
+ const prefix = (m[1] ?? '').toLowerCase();
19
+ return SLASH_COMMANDS.filter((c) => c.name.startsWith(prefix));
20
+ }
21
+ /** Returns null when the line is not a slash command. */
22
+ export function parseSlash(line) {
23
+ const trimmed = line.trim();
24
+ if (!trimmed.startsWith('/'))
25
+ return null;
26
+ const [name, ...args] = trimmed.slice(1).split(/\s+/);
27
+ if (!name)
28
+ return null;
29
+ return { name, args };
30
+ }
31
+ export const SLASH_COMMANDS = [
32
+ {
33
+ name: 'help',
34
+ description: 'Show available slash commands.',
35
+ action: () => ({
36
+ kind: 'message',
37
+ role: 'system',
38
+ content: SLASH_COMMANDS.map((c) => `/${c.name.padEnd(10)} ${c.description}`).join('\n'),
39
+ }),
40
+ },
41
+ {
42
+ name: 'clear',
43
+ description: 'Clear the transcript.',
44
+ action: () => ({ kind: 'clear' }),
45
+ },
46
+ {
47
+ name: 'quit',
48
+ description: 'Exit namzu.',
49
+ action: () => ({ kind: 'exit' }),
50
+ },
51
+ {
52
+ name: 'exit',
53
+ description: 'Alias of /quit.',
54
+ action: () => ({ kind: 'exit' }),
55
+ },
56
+ {
57
+ name: 'tools',
58
+ description: 'List tools the agent can call (builtins + clawtool).',
59
+ action: (ctx) => ({
60
+ kind: 'message',
61
+ role: 'system',
62
+ content: ctx.availableTools.length === 0
63
+ ? 'No tools registered yet — the agent session may still be connecting.'
64
+ : `Registered tools (${ctx.availableTools.length}):\n ${ctx.availableTools.join('\n ')}`,
65
+ }),
66
+ },
67
+ {
68
+ name: 'remember',
69
+ description: 'Save a fact to durable memory: /remember <text>.',
70
+ action: (_ctx, args) => {
71
+ const text = args.join(' ').trim();
72
+ return text.length === 0
73
+ ? { kind: 'message', role: 'system', content: 'Usage: /remember <something to remember>' }
74
+ : { kind: 'remember', text };
75
+ },
76
+ },
77
+ {
78
+ name: 'memory',
79
+ description: 'Show what namzu remembers (USER.md + MEMORY.md).',
80
+ action: () => ({ kind: 'show-memory' }),
81
+ },
82
+ {
83
+ name: 'skills',
84
+ description: 'List available skills (~/.namzu/skills + ./skills).',
85
+ action: () => ({ kind: 'list-skills' }),
86
+ },
87
+ {
88
+ name: 'agents',
89
+ description: 'List namzu sessions running across your terminals (needs `namzu serve`)',
90
+ action: () => ({ kind: 'list-agents' }),
91
+ },
92
+ {
93
+ name: 'msg',
94
+ description: 'Message another agent peer: /msg <peer> <text> (peers via /agents)',
95
+ action: (_ctx, args) => {
96
+ const peer = (args[0] ?? '').trim();
97
+ const text = args.slice(1).join(' ').trim();
98
+ return peer.length === 0 || text.length === 0
99
+ ? {
100
+ kind: 'message',
101
+ role: 'system',
102
+ content: 'Usage: /msg <peer-name-or-id> <text> (list peers with /agents)',
103
+ }
104
+ : { kind: 'send-peer', peer, text };
105
+ },
106
+ },
107
+ {
108
+ name: 'resume',
109
+ description: 'Resume a past conversation in this folder.',
110
+ action: () => ({ kind: 'resume' }),
111
+ },
112
+ {
113
+ name: 'skill',
114
+ description: 'Activate a skill for this session: /skill <name>.',
115
+ action: (_ctx, args) => {
116
+ const name = args.join(' ').trim();
117
+ return name.length === 0
118
+ ? { kind: 'message', role: 'system', content: 'Usage: /skill <name> (see /skills)' }
119
+ : { kind: 'load-skill', name };
120
+ },
121
+ },
122
+ {
123
+ name: 'provider',
124
+ description: 'Show the current provider + model.',
125
+ action: (ctx) => ({
126
+ kind: 'message',
127
+ role: 'system',
128
+ content: ctx.providerSummary === null
129
+ ? 'No provider configured. Run /model to pick one, or set an LLM env var (ANTHROPIC_API_KEY / OPENAI_API_KEY / OPENROUTER_API_KEY) and restart namzu.'
130
+ : `Provider: ${ctx.providerSummary}${ctx.modelSummary ? `\nModel: ${ctx.modelSummary}` : ''}`,
131
+ }),
132
+ },
133
+ {
134
+ name: 'model',
135
+ description: 'Re-open the provider picker to switch the primary provider.',
136
+ action: () => ({ kind: 'repick' }),
137
+ },
138
+ ];
139
+ export function runSlash(line, ctx) {
140
+ const parsed = parseSlash(line);
141
+ if (!parsed)
142
+ return null;
143
+ const cmd = SLASH_COMMANDS.find((c) => c.name === parsed.name);
144
+ if (!cmd) {
145
+ return {
146
+ kind: 'message',
147
+ role: 'system',
148
+ content: `Unknown command: /${parsed.name}. Try /help.`,
149
+ };
150
+ }
151
+ return cmd.action(ctx, parsed.args);
152
+ }
153
+ //# sourceMappingURL=slashCommands.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slashCommands.js","sourceRoot":"","sources":["../../src/tui/slashCommands.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=slashCommands.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slashCommands.test.d.ts","sourceRoot":"","sources":["../../src/tui/slashCommands.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,114 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { SLASH_COMMANDS, matchSlashCommands, parseSlash, runSlash, } from './slashCommands.js';
3
+ const ctx = {
4
+ availableTools: [],
5
+ providerSummary: null,
6
+ modelSummary: null,
7
+ };
8
+ const ctxWithTools = {
9
+ availableTools: ['Bash', 'Read', 'Edit'],
10
+ providerSummary: 'anthropic-personal (anthropic)',
11
+ modelSummary: 'claude-opus-4-7',
12
+ };
13
+ describe('matchSlashCommands', () => {
14
+ it('returns all commands for a bare slash', () => {
15
+ expect(matchSlashCommands('/')).toEqual(SLASH_COMMANDS);
16
+ });
17
+ it('filters by name prefix (case-insensitive)', () => {
18
+ const names = matchSlashCommands('/me').map((c) => c.name);
19
+ expect(names).toContain('memory');
20
+ expect(names).not.toContain('help');
21
+ expect(matchSlashCommands('/MO').map((c) => c.name)).toContain('model');
22
+ });
23
+ it('returns [] once a space is typed (now entering arguments)', () => {
24
+ expect(matchSlashCommands('/model ')).toEqual([]);
25
+ expect(matchSlashCommands('/skill foo')).toEqual([]);
26
+ });
27
+ it('returns [] for non-slash input', () => {
28
+ expect(matchSlashCommands('hello')).toEqual([]);
29
+ expect(matchSlashCommands('')).toEqual([]);
30
+ });
31
+ it('returns [] when nothing matches the prefix', () => {
32
+ expect(matchSlashCommands('/zzz')).toEqual([]);
33
+ });
34
+ });
35
+ describe('parseSlash', () => {
36
+ it('returns null for non-slash lines', () => {
37
+ expect(parseSlash('hello world')).toBeNull();
38
+ expect(parseSlash('')).toBeNull();
39
+ expect(parseSlash(' ')).toBeNull();
40
+ });
41
+ it('tolerates leading whitespace', () => {
42
+ expect(parseSlash(' /help')).toEqual({ name: 'help', args: [] });
43
+ });
44
+ it('splits args on whitespace', () => {
45
+ expect(parseSlash('/model anthropic claude-opus-4-7')).toEqual({
46
+ name: 'model',
47
+ args: ['anthropic', 'claude-opus-4-7'],
48
+ });
49
+ });
50
+ it('returns null for a bare slash', () => {
51
+ expect(parseSlash('/')).toBeNull();
52
+ expect(parseSlash('/ ')).toBeNull();
53
+ });
54
+ });
55
+ describe('runSlash', () => {
56
+ it('returns null for non-slash input', () => {
57
+ expect(runSlash('plain message', ctx)).toBeNull();
58
+ });
59
+ it('reports unknown commands as system messages', () => {
60
+ const r = runSlash('/nope', ctx);
61
+ expect(r?.kind).toBe('message');
62
+ if (r?.kind === 'message')
63
+ expect(r.content).toContain('Unknown command');
64
+ });
65
+ it('/help lists every registered command', () => {
66
+ const r = runSlash('/help', ctx);
67
+ expect(r?.kind).toBe('message');
68
+ if (r?.kind === 'message') {
69
+ for (const cmd of SLASH_COMMANDS) {
70
+ expect(r.content).toContain(`/${cmd.name}`);
71
+ }
72
+ }
73
+ });
74
+ it('/clear returns a clear action', () => {
75
+ expect(runSlash('/clear', ctx)).toEqual({ kind: 'clear' });
76
+ });
77
+ it('/quit and /exit both produce an exit action', () => {
78
+ expect(runSlash('/quit', ctx)).toEqual({ kind: 'exit' });
79
+ expect(runSlash('/exit', ctx)).toEqual({ kind: 'exit' });
80
+ });
81
+ it('/tools reports "no tools" when registry is empty', () => {
82
+ const r = runSlash('/tools', ctx);
83
+ expect(r?.kind).toBe('message');
84
+ if (r?.kind === 'message')
85
+ expect(r.content).toContain('No tools registered');
86
+ });
87
+ it('/tools lists registered tools when present', () => {
88
+ const r = runSlash('/tools', ctxWithTools);
89
+ expect(r?.kind).toBe('message');
90
+ if (r?.kind === 'message') {
91
+ expect(r.content).toContain('Bash');
92
+ expect(r.content).toContain('Read');
93
+ expect(r.content).toContain('3');
94
+ }
95
+ });
96
+ it('/provider says "not configured" when no provider', () => {
97
+ const r = runSlash('/provider', ctx);
98
+ expect(r?.kind).toBe('message');
99
+ if (r?.kind === 'message')
100
+ expect(r.content).toContain('No provider configured');
101
+ });
102
+ it('/provider shows summary when configured', () => {
103
+ const r = runSlash('/provider', ctxWithTools);
104
+ expect(r?.kind).toBe('message');
105
+ if (r?.kind === 'message') {
106
+ expect(r.content).toContain('anthropic-personal');
107
+ expect(r.content).toContain('claude-opus-4-7');
108
+ }
109
+ });
110
+ it('/model re-opens the picker (repick action)', () => {
111
+ expect(runSlash('/model', ctxWithTools)).toEqual({ kind: 'repick' });
112
+ });
113
+ });
114
+ //# sourceMappingURL=slashCommands.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"slashCommands.test.js","sourceRoot":"","sources":["../../src/tui/slashCommands.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAA;AAE7C,OAAO,EACN,cAAc,EAEd,kBAAkB,EAClB,UAAU,EACV,QAAQ,GACR,MAAM,oBAAoB,CAAA;AAE3B,MAAM,GAAG,GAAiB;IACzB,cAAc,EAAE,EAAE;IAClB,eAAe,EAAE,IAAI;IACrB,YAAY,EAAE,IAAI;CAClB,CAAA;AAED,MAAM,YAAY,GAAiB;IAClC,cAAc,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;IACxC,eAAe,EAAE,gCAAgC;IACjD,YAAY,EAAE,iBAAiB;CAC/B,CAAA;AAED,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE;IACnC,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAChD,MAAM,CAAC,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,cAAc,CAAC,CAAA;IACxD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2CAA2C,EAAE,GAAG,EAAE;QACpD,MAAM,KAAK,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QAC1D,MAAM,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAA;QACjC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;QACnC,MAAM,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAA;IACxE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACpE,MAAM,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QACjD,MAAM,CAAC,kBAAkB,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IACrD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;QAC/C,MAAM,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAC3C,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,kBAAkB,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAA;IAC/C,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,YAAY,EAAE,GAAG,EAAE;IAC3B,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,UAAU,CAAC,aAAa,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAC5C,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QACjC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;IACpC,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACvC,MAAM,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAA;IAClE,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACpC,MAAM,CAAC,UAAU,CAAC,kCAAkC,CAAC,CAAC,CAAC,OAAO,CAAC;YAC9D,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,CAAC,WAAW,EAAE,iBAAiB,CAAC;SACtC,CAAC,CAAA;IACH,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;QAClC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;IACpC,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,UAAU,EAAE,GAAG,EAAE;IACzB,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC3C,MAAM,CAAC,QAAQ,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAA;IAClD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;QAChC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC/B,IAAI,CAAC,EAAE,IAAI,KAAK,SAAS;YAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAA;IAC1E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,sCAAsC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,GAAG,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;QAChC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC/B,IAAI,CAAC,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;YAC3B,KAAK,MAAM,GAAG,IAAI,cAAc,EAAE,CAAC;gBAClC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,IAAI,EAAE,CAAC,CAAA;YAC5C,CAAC;QACF,CAAC;IACF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAA;IAC3D,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACtD,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;QACxD,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAA;IACzD,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC3D,MAAM,CAAC,GAAG,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;QACjC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC/B,IAAI,CAAC,EAAE,IAAI,KAAK,SAAS;YAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAA;IAC9E,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,GAAG,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAA;QAC1C,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC/B,IAAI,CAAC,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;YACnC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAA;YACnC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAA;QACjC,CAAC;IACF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,kDAAkD,EAAE,GAAG,EAAE;QAC3D,MAAM,CAAC,GAAG,QAAQ,CAAC,WAAW,EAAE,GAAG,CAAC,CAAA;QACpC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC/B,IAAI,CAAC,EAAE,IAAI,KAAK,SAAS;YAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,wBAAwB,CAAC,CAAA;IACjF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QAClD,MAAM,CAAC,GAAG,QAAQ,CAAC,WAAW,EAAE,YAAY,CAAC,CAAA;QAC7C,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAC/B,IAAI,CAAC,EAAE,IAAI,KAAK,SAAS,EAAE,CAAC;YAC3B,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,oBAAoB,CAAC,CAAA;YACjD,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,SAAS,CAAC,iBAAiB,CAAC,CAAA;QAC/C,CAAC;IACF,CAAC,CAAC,CAAA;IAEF,EAAE,CAAC,4CAA4C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC,CAAA;IACrE,CAAC,CAAC,CAAA;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Theme tokens for the TUI — a single dark palette. We inherit the
3
+ * terminal's own background (like claude-code / gemini-cli) rather than
4
+ * painting one, and only theme the foreground; curated hex colors
5
+ * (GitHub-dark-leaning) give a consistent, premium look on dark terminals.
6
+ * `background` is kept for reference / a future light theme but is not
7
+ * forced onto the canvas. A theme registry/picker is a follow-up.
8
+ */
9
+ export interface SemanticColors {
10
+ /** Canvas background — the whole UI sits on this. */
11
+ readonly background: string;
12
+ readonly text: {
13
+ readonly primary: string;
14
+ readonly secondary: string;
15
+ readonly muted: string;
16
+ };
17
+ readonly accent: {
18
+ readonly user: string;
19
+ readonly assistant: string;
20
+ readonly system: string;
21
+ readonly tool: string;
22
+ };
23
+ readonly status: {
24
+ readonly ok: string;
25
+ readonly warn: string;
26
+ readonly error: string;
27
+ };
28
+ readonly border: {
29
+ readonly default: string;
30
+ readonly focus: string;
31
+ };
32
+ }
33
+ export declare const theme: SemanticColors;
34
+ //# sourceMappingURL=theme.d.ts.map