nikcli 0.0.6

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 (602) hide show
  1. package/.turbo/turbo-typecheck.log +1 -0
  2. package/AGENTS.md +27 -0
  3. package/Dockerfile +18 -0
  4. package/README.md +15 -0
  5. package/bin/nikcli +84 -0
  6. package/config.json +13 -0
  7. package/docs/tailscale-mobile/01-tailscale-setup.md +94 -0
  8. package/docs/tailscale-mobile/02-host-setup.md +115 -0
  9. package/docs/tailscale-mobile/03-phone-and-serve.md +134 -0
  10. package/docs/tailscale-mobile/README.md +59 -0
  11. package/examples/README.md +54 -0
  12. package/package.json +147 -0
  13. package/parsers-config.ts +253 -0
  14. package/script/build.ts +179 -0
  15. package/script/postinstall.mjs +125 -0
  16. package/script/publish-registries.ts +187 -0
  17. package/script/publish.ts +100 -0
  18. package/script/schema.ts +47 -0
  19. package/script/seed-e2e.ts +50 -0
  20. package/sequential-prancing-forest.md +373 -0
  21. package/src/acp/README.md +164 -0
  22. package/src/acp/agent.ts +1303 -0
  23. package/src/acp/session.ts +105 -0
  24. package/src/acp/types.ts +22 -0
  25. package/src/agent/agent.ts +528 -0
  26. package/src/agent/generate.txt +32 -0
  27. package/src/agent/prompt/compaction.txt +14 -0
  28. package/src/agent/prompt/explore.txt +18 -0
  29. package/src/agent/prompt/summary.txt +11 -0
  30. package/src/agent/prompt/title.txt +44 -0
  31. package/src/auth/index.ts +73 -0
  32. package/src/bun/index.ts +119 -0
  33. package/src/bun/registry.ts +54 -0
  34. package/src/bus/bus-event.ts +43 -0
  35. package/src/bus/global.ts +10 -0
  36. package/src/bus/index.ts +105 -0
  37. package/src/chatbot/handlers.ts +150 -0
  38. package/src/chatbot/index.ts +132 -0
  39. package/src/cli/bootstrap.ts +17 -0
  40. package/src/cli/cmd/acp.ts +69 -0
  41. package/src/cli/cmd/ads.ts +377 -0
  42. package/src/cli/cmd/agent.ts +259 -0
  43. package/src/cli/cmd/auth.ts +400 -0
  44. package/src/cli/cmd/chatbot.ts +420 -0
  45. package/src/cli/cmd/cmd.ts +7 -0
  46. package/src/cli/cmd/companion.ts +81 -0
  47. package/src/cli/cmd/connectors.ts +593 -0
  48. package/src/cli/cmd/debug/agent.ts +166 -0
  49. package/src/cli/cmd/debug/config.ts +16 -0
  50. package/src/cli/cmd/debug/file.ts +97 -0
  51. package/src/cli/cmd/debug/index.ts +48 -0
  52. package/src/cli/cmd/debug/lsp.ts +52 -0
  53. package/src/cli/cmd/debug/ripgrep.ts +87 -0
  54. package/src/cli/cmd/debug/scrap.ts +16 -0
  55. package/src/cli/cmd/debug/skill.ts +16 -0
  56. package/src/cli/cmd/debug/snapshot.ts +52 -0
  57. package/src/cli/cmd/export.ts +88 -0
  58. package/src/cli/cmd/generate.ts +38 -0
  59. package/src/cli/cmd/github.ts +412 -0
  60. package/src/cli/cmd/image-model.ts +128 -0
  61. package/src/cli/cmd/import.ts +201 -0
  62. package/src/cli/cmd/lovable.ts +128 -0
  63. package/src/cli/cmd/mcp.ts +738 -0
  64. package/src/cli/cmd/mobile.ts +223 -0
  65. package/src/cli/cmd/models.ts +77 -0
  66. package/src/cli/cmd/plug.ts +231 -0
  67. package/src/cli/cmd/pr.ts +104 -0
  68. package/src/cli/cmd/rag-model.ts +167 -0
  69. package/src/cli/cmd/remote.ts +416 -0
  70. package/src/cli/cmd/run.ts +589 -0
  71. package/src/cli/cmd/serve.ts +51 -0
  72. package/src/cli/cmd/session.ts +133 -0
  73. package/src/cli/cmd/speak-model.ts +204 -0
  74. package/src/cli/cmd/stats.ts +402 -0
  75. package/src/cli/cmd/tui/app.tsx +841 -0
  76. package/src/cli/cmd/tui/attach.ts +31 -0
  77. package/src/cli/cmd/tui/component/border.tsx +75 -0
  78. package/src/cli/cmd/tui/component/dialog-agent.tsx +31 -0
  79. package/src/cli/cmd/tui/component/dialog-command.tsx +172 -0
  80. package/src/cli/cmd/tui/component/dialog-config.tsx +291 -0
  81. package/src/cli/cmd/tui/component/dialog-connectors.tsx +440 -0
  82. package/src/cli/cmd/tui/component/dialog-image-model.tsx +97 -0
  83. package/src/cli/cmd/tui/component/dialog-mcp.tsx +86 -0
  84. package/src/cli/cmd/tui/component/dialog-model.tsx +234 -0
  85. package/src/cli/cmd/tui/component/dialog-provider.tsx +260 -0
  86. package/src/cli/cmd/tui/component/dialog-rag-model.tsx +217 -0
  87. package/src/cli/cmd/tui/component/dialog-remote.tsx +489 -0
  88. package/src/cli/cmd/tui/component/dialog-session-list.tsx +170 -0
  89. package/src/cli/cmd/tui/component/dialog-session-rename.tsx +31 -0
  90. package/src/cli/cmd/tui/component/dialog-settings/index.tsx +59 -0
  91. package/src/cli/cmd/tui/component/dialog-settings/prompt.tsx +40 -0
  92. package/src/cli/cmd/tui/component/dialog-settings/sidebar.tsx +39 -0
  93. package/src/cli/cmd/tui/component/dialog-settings/spinner.tsx +62 -0
  94. package/src/cli/cmd/tui/component/dialog-settings/ui.tsx +58 -0
  95. package/src/cli/cmd/tui/component/dialog-skills.tsx +117 -0
  96. package/src/cli/cmd/tui/component/dialog-speak-model.tsx +304 -0
  97. package/src/cli/cmd/tui/component/dialog-stash.tsx +87 -0
  98. package/src/cli/cmd/tui/component/dialog-status.tsx +165 -0
  99. package/src/cli/cmd/tui/component/dialog-tag.tsx +44 -0
  100. package/src/cli/cmd/tui/component/dialog-theme-create.tsx +717 -0
  101. package/src/cli/cmd/tui/component/dialog-theme-list.tsx +52 -0
  102. package/src/cli/cmd/tui/component/dialog-workspace-list.tsx +350 -0
  103. package/src/cli/cmd/tui/component/error-component.tsx +91 -0
  104. package/src/cli/cmd/tui/component/logo.tsx +103 -0
  105. package/src/cli/cmd/tui/component/plugin-route-missing.tsx +14 -0
  106. package/src/cli/cmd/tui/component/prompt/autocomplete.tsx +669 -0
  107. package/src/cli/cmd/tui/component/prompt/frecency.tsx +89 -0
  108. package/src/cli/cmd/tui/component/prompt/history.tsx +108 -0
  109. package/src/cli/cmd/tui/component/prompt/index.tsx +2165 -0
  110. package/src/cli/cmd/tui/component/prompt/stash.tsx +63 -0
  111. package/src/cli/cmd/tui/component/spinner.tsx +24 -0
  112. package/src/cli/cmd/tui/component/startup-loading.tsx +63 -0
  113. package/src/cli/cmd/tui/component/table/markdown-table.tsx +267 -0
  114. package/src/cli/cmd/tui/component/table-db/db/connections.ts +75 -0
  115. package/src/cli/cmd/tui/component/table-db/db/db-connection.ts +223 -0
  116. package/src/cli/cmd/tui/component/table-db/db/db-preview.ts +202 -0
  117. package/src/cli/cmd/tui/component/table-db/db/factory.ts +77 -0
  118. package/src/cli/cmd/tui/component/table-db/db/index.ts +9 -0
  119. package/src/cli/cmd/tui/component/table-db/db/mysql-connection.ts +330 -0
  120. package/src/cli/cmd/tui/component/table-db/db/postgres-connection.ts +338 -0
  121. package/src/cli/cmd/tui/component/table-db/db/sqlite-connection.ts +302 -0
  122. package/src/cli/cmd/tui/component/table-db/db/types.ts +108 -0
  123. package/src/cli/cmd/tui/component/table-db/table/dbedit-hooks.ts +74 -0
  124. package/src/cli/cmd/tui/component/table-db/table/index.ts +15 -0
  125. package/src/cli/cmd/tui/component/table-db/table/table-events.ts +54 -0
  126. package/src/cli/cmd/tui/component/table-db/table/table-formatters.ts +191 -0
  127. package/src/cli/cmd/tui/component/table-db/table/table-hooks.ts +105 -0
  128. package/src/cli/cmd/tui/component/table-db/table/table-keyboard-handler.ts +255 -0
  129. package/src/cli/cmd/tui/component/table-db/table/table-layout-engine.ts +208 -0
  130. package/src/cli/cmd/tui/component/table-db/table/table-renderable.ts +486 -0
  131. package/src/cli/cmd/tui/component/table-db/table/table-selection-manager.ts +136 -0
  132. package/src/cli/cmd/tui/component/table-db/table/table-state.ts +198 -0
  133. package/src/cli/cmd/tui/component/table-db/table/types.ts +69 -0
  134. package/src/cli/cmd/tui/component/table-db/ui/db-visualizer.tsx +71 -0
  135. package/src/cli/cmd/tui/component/table-db/ui/index.ts +2 -0
  136. package/src/cli/cmd/tui/component/table-db/ui/table-renderer.ts +607 -0
  137. package/src/cli/cmd/tui/component/textarea-keybindings.ts +73 -0
  138. package/src/cli/cmd/tui/component/tips.tsx +195 -0
  139. package/src/cli/cmd/tui/component/todo-item.tsx +32 -0
  140. package/src/cli/cmd/tui/context/args.tsx +14 -0
  141. package/src/cli/cmd/tui/context/directory.ts +13 -0
  142. package/src/cli/cmd/tui/context/exit.tsx +24 -0
  143. package/src/cli/cmd/tui/context/helper.tsx +25 -0
  144. package/src/cli/cmd/tui/context/keybind.tsx +102 -0
  145. package/src/cli/cmd/tui/context/kv.tsx +52 -0
  146. package/src/cli/cmd/tui/context/local.tsx +458 -0
  147. package/src/cli/cmd/tui/context/plugin-keybinds.ts +41 -0
  148. package/src/cli/cmd/tui/context/prompt.tsx +18 -0
  149. package/src/cli/cmd/tui/context/route.tsx +54 -0
  150. package/src/cli/cmd/tui/context/sdk.tsx +128 -0
  151. package/src/cli/cmd/tui/context/server.tsx +8 -0
  152. package/src/cli/cmd/tui/context/sync.tsx +510 -0
  153. package/src/cli/cmd/tui/context/theme/abyss.json +233 -0
  154. package/src/cli/cmd/tui/context/theme/apple.json +235 -0
  155. package/src/cli/cmd/tui/context/theme/arctic.json +232 -0
  156. package/src/cli/cmd/tui/context/theme/aura.json +69 -0
  157. package/src/cli/cmd/tui/context/theme/ayu.json +80 -0
  158. package/src/cli/cmd/tui/context/theme/ayuai.json +229 -0
  159. package/src/cli/cmd/tui/context/theme/blood.json +229 -0
  160. package/src/cli/cmd/tui/context/theme/carbonfox.json +248 -0
  161. package/src/cli/cmd/tui/context/theme/catmoe.json +235 -0
  162. package/src/cli/cmd/tui/context/theme/catppuccin-frappe.json +233 -0
  163. package/src/cli/cmd/tui/context/theme/catppuccin-latte.json +233 -0
  164. package/src/cli/cmd/tui/context/theme/catppuccin-macchiato.json +233 -0
  165. package/src/cli/cmd/tui/context/theme/catppuccin.json +259 -0
  166. package/src/cli/cmd/tui/context/theme/charcoal.json +230 -0
  167. package/src/cli/cmd/tui/context/theme/chromatic.json +235 -0
  168. package/src/cli/cmd/tui/context/theme/cobalt2.json +228 -0
  169. package/src/cli/cmd/tui/context/theme/cosmic.json +234 -0
  170. package/src/cli/cmd/tui/context/theme/cursor.json +249 -0
  171. package/src/cli/cmd/tui/context/theme/cyber.json +235 -0
  172. package/src/cli/cmd/tui/context/theme/dawnfox.json +229 -0
  173. package/src/cli/cmd/tui/context/theme/dimension.json +235 -0
  174. package/src/cli/cmd/tui/context/theme/dracula-official.json +222 -0
  175. package/src/cli/cmd/tui/context/theme/dracula.json +219 -0
  176. package/src/cli/cmd/tui/context/theme/dream.json +235 -0
  177. package/src/cli/cmd/tui/context/theme/duo.json +235 -0
  178. package/src/cli/cmd/tui/context/theme/dusk.json +235 -0
  179. package/src/cli/cmd/tui/context/theme/ebony.json +232 -0
  180. package/src/cli/cmd/tui/context/theme/equilibrium.json +232 -0
  181. package/src/cli/cmd/tui/context/theme/ethereal.json +235 -0
  182. package/src/cli/cmd/tui/context/theme/everforest.json +241 -0
  183. package/src/cli/cmd/tui/context/theme/flexoki.json +237 -0
  184. package/src/cli/cmd/tui/context/theme/fusion.json +235 -0
  185. package/src/cli/cmd/tui/context/theme/ghost.json +235 -0
  186. package/src/cli/cmd/tui/context/theme/github-dark.json +229 -0
  187. package/src/cli/cmd/tui/context/theme/github-dimmed.json +231 -0
  188. package/src/cli/cmd/tui/context/theme/github-light.json +229 -0
  189. package/src/cli/cmd/tui/context/theme/github.json +233 -0
  190. package/src/cli/cmd/tui/context/theme/glass.json +235 -0
  191. package/src/cli/cmd/tui/context/theme/gold.json +235 -0
  192. package/src/cli/cmd/tui/context/theme/gone.json +234 -0
  193. package/src/cli/cmd/tui/context/theme/greyscale.json +229 -0
  194. package/src/cli/cmd/tui/context/theme/gruvbox.json +242 -0
  195. package/src/cli/cmd/tui/context/theme/hacker.json +229 -0
  196. package/src/cli/cmd/tui/context/theme/holo.json +235 -0
  197. package/src/cli/cmd/tui/context/theme/ink.json +235 -0
  198. package/src/cli/cmd/tui/context/theme/jet.json +233 -0
  199. package/src/cli/cmd/tui/context/theme/kanagawa.json +227 -0
  200. package/src/cli/cmd/tui/context/theme/lavender.json +236 -0
  201. package/src/cli/cmd/tui/context/theme/lightph.json +235 -0
  202. package/src/cli/cmd/tui/context/theme/lucent-orng.json +237 -0
  203. package/src/cli/cmd/tui/context/theme/material-ocean.json +230 -0
  204. package/src/cli/cmd/tui/context/theme/material.json +235 -0
  205. package/src/cli/cmd/tui/context/theme/matrix.json +227 -0
  206. package/src/cli/cmd/tui/context/theme/mercury.json +245 -0
  207. package/src/cli/cmd/tui/context/theme/midnight.json +235 -0
  208. package/src/cli/cmd/tui/context/theme/modern.json +235 -0
  209. package/src/cli/cmd/tui/context/theme/monokai.json +221 -0
  210. package/src/cli/cmd/tui/context/theme/muted.json +229 -0
  211. package/src/cli/cmd/tui/context/theme/neon.json +229 -0
  212. package/src/cli/cmd/tui/context/theme/neonfusion.json +235 -0
  213. package/src/cli/cmd/tui/context/theme/neutral.json +235 -0
  214. package/src/cli/cmd/tui/context/theme/nightowl.json +221 -0
  215. package/src/cli/cmd/tui/context/theme/nikcli.json +245 -0
  216. package/src/cli/cmd/tui/context/theme/nord.json +223 -0
  217. package/src/cli/cmd/tui/context/theme/nordic.json +235 -0
  218. package/src/cli/cmd/tui/context/theme/nova.json +235 -0
  219. package/src/cli/cmd/tui/context/theme/obsidian.json +234 -0
  220. package/src/cli/cmd/tui/context/theme/one-dark.json +231 -0
  221. package/src/cli/cmd/tui/context/theme/one-pro.json +229 -0
  222. package/src/cli/cmd/tui/context/theme/onyx.json +233 -0
  223. package/src/cli/cmd/tui/context/theme/orng.json +249 -0
  224. package/src/cli/cmd/tui/context/theme/osaka-jade.json +240 -0
  225. package/src/cli/cmd/tui/context/theme/oxocarbon.json +229 -0
  226. package/src/cli/cmd/tui/context/theme/palenight.json +222 -0
  227. package/src/cli/cmd/tui/context/theme/poimandres.json +230 -0
  228. package/src/cli/cmd/tui/context/theme/prism.json +235 -0
  229. package/src/cli/cmd/tui/context/theme/radiant.json +235 -0
  230. package/src/cli/cmd/tui/context/theme/rosepine.json +234 -0
  231. package/src/cli/cmd/tui/context/theme/shadow.json +235 -0
  232. package/src/cli/cmd/tui/context/theme/silicon.json +235 -0
  233. package/src/cli/cmd/tui/context/theme/slate.json +233 -0
  234. package/src/cli/cmd/tui/context/theme/soft.json +235 -0
  235. package/src/cli/cmd/tui/context/theme/solarized.json +223 -0
  236. package/src/cli/cmd/tui/context/theme/spectrum.json +235 -0
  237. package/src/cli/cmd/tui/context/theme/starlight.json +233 -0
  238. package/src/cli/cmd/tui/context/theme/sunrise.json +235 -0
  239. package/src/cli/cmd/tui/context/theme/synthwave84.json +226 -0
  240. package/src/cli/cmd/tui/context/theme/tech.json +235 -0
  241. package/src/cli/cmd/tui/context/theme/tokyonight-storm.json +245 -0
  242. package/src/cli/cmd/tui/context/theme/tokyonight.json +243 -0
  243. package/src/cli/cmd/tui/context/theme/vapor.json +235 -0
  244. package/src/cli/cmd/tui/context/theme/vercel.json +245 -0
  245. package/src/cli/cmd/tui/context/theme/vesper.json +218 -0
  246. package/src/cli/cmd/tui/context/theme/vivid.json +232 -0
  247. package/src/cli/cmd/tui/context/theme/void.json +235 -0
  248. package/src/cli/cmd/tui/context/theme/vscode.json +235 -0
  249. package/src/cli/cmd/tui/context/theme/zenburn.json +223 -0
  250. package/src/cli/cmd/tui/context/theme/zinc.json +236 -0
  251. package/src/cli/cmd/tui/context/theme.tsx +1303 -0
  252. package/src/cli/cmd/tui/event.ts +48 -0
  253. package/src/cli/cmd/tui/feature-plugins/home/tips-view.tsx +152 -0
  254. package/src/cli/cmd/tui/feature-plugins/home/tips.tsx +50 -0
  255. package/src/cli/cmd/tui/feature-plugins/sidebar/context.tsx +63 -0
  256. package/src/cli/cmd/tui/feature-plugins/sidebar/files.tsx +62 -0
  257. package/src/cli/cmd/tui/feature-plugins/sidebar/footer.tsx +93 -0
  258. package/src/cli/cmd/tui/feature-plugins/sidebar/lsp.tsx +66 -0
  259. package/src/cli/cmd/tui/feature-plugins/sidebar/mcp.tsx +96 -0
  260. package/src/cli/cmd/tui/feature-plugins/sidebar/todo.tsx +48 -0
  261. package/src/cli/cmd/tui/feature-plugins/system/plugins.tsx +288 -0
  262. package/src/cli/cmd/tui/plugin/api.tsx +407 -0
  263. package/src/cli/cmd/tui/plugin/index.ts +3 -0
  264. package/src/cli/cmd/tui/plugin/internal.ts +25 -0
  265. package/src/cli/cmd/tui/plugin/runtime.ts +1048 -0
  266. package/src/cli/cmd/tui/plugin/slots.tsx +61 -0
  267. package/src/cli/cmd/tui/routes/home.tsx +153 -0
  268. package/src/cli/cmd/tui/routes/session/dbedit.tsx +474 -0
  269. package/src/cli/cmd/tui/routes/session/dialog-fork-from-timeline.tsx +65 -0
  270. package/src/cli/cmd/tui/routes/session/dialog-message.tsx +110 -0
  271. package/src/cli/cmd/tui/routes/session/dialog-subagent.tsx +105 -0
  272. package/src/cli/cmd/tui/routes/session/dialog-timeline.tsx +47 -0
  273. package/src/cli/cmd/tui/routes/session/footer.tsx +75 -0
  274. package/src/cli/cmd/tui/routes/session/header.tsx +177 -0
  275. package/src/cli/cmd/tui/routes/session/index.tsx +2280 -0
  276. package/src/cli/cmd/tui/routes/session/permission.tsx +540 -0
  277. package/src/cli/cmd/tui/routes/session/question.tsx +435 -0
  278. package/src/cli/cmd/tui/routes/session/sidebar.tsx +313 -0
  279. package/src/cli/cmd/tui/thread.ts +174 -0
  280. package/src/cli/cmd/tui/ui/dialog-alert.tsx +57 -0
  281. package/src/cli/cmd/tui/ui/dialog-confirm.tsx +83 -0
  282. package/src/cli/cmd/tui/ui/dialog-export-options.tsx +204 -0
  283. package/src/cli/cmd/tui/ui/dialog-help.tsx +38 -0
  284. package/src/cli/cmd/tui/ui/dialog-prompt.tsx +102 -0
  285. package/src/cli/cmd/tui/ui/dialog-select.tsx +389 -0
  286. package/src/cli/cmd/tui/ui/dialog.tsx +180 -0
  287. package/src/cli/cmd/tui/ui/link.tsx +34 -0
  288. package/src/cli/cmd/tui/ui/spinner.ts +368 -0
  289. package/src/cli/cmd/tui/ui/toast.tsx +138 -0
  290. package/src/cli/cmd/tui/util/clipboard.ts +154 -0
  291. package/src/cli/cmd/tui/util/editor.ts +32 -0
  292. package/src/cli/cmd/tui/util/signal.ts +7 -0
  293. package/src/cli/cmd/tui/util/terminal.ts +114 -0
  294. package/src/cli/cmd/tui/util/transcript.ts +98 -0
  295. package/src/cli/cmd/tui/win32.ts +110 -0
  296. package/src/cli/cmd/tui/worker.ts +156 -0
  297. package/src/cli/cmd/uninstall.ts +357 -0
  298. package/src/cli/cmd/upgrade.ts +72 -0
  299. package/src/cli/cmd/web.ts +87 -0
  300. package/src/cli/cmd/workspace-serve.ts +16 -0
  301. package/src/cli/error.ts +57 -0
  302. package/src/cli/network.ts +55 -0
  303. package/src/cli/remote/index.ts +36 -0
  304. package/src/cli/remote/notifications.ts +104 -0
  305. package/src/cli/remote/qr-renderer.ts +86 -0
  306. package/src/cli/remote/remote-service.ts +757 -0
  307. package/src/cli/remote/session-manager.ts +284 -0
  308. package/src/cli/remote/subagent-hooks.ts +151 -0
  309. package/src/cli/remote/types.ts +121 -0
  310. package/src/cli/ui.ts +96 -0
  311. package/src/cli/upgrade.ts +25 -0
  312. package/src/command/index.ts +174 -0
  313. package/src/command/template/initialize.txt +10 -0
  314. package/src/command/template/review.txt +99 -0
  315. package/src/config/config.ts +1760 -0
  316. package/src/config/markdown.ts +88 -0
  317. package/src/config/migrate-tui-config.ts +155 -0
  318. package/src/config/paths.ts +174 -0
  319. package/src/config/tui-schema.ts +36 -0
  320. package/src/config/tui.ts +209 -0
  321. package/src/connectors/api/base.ts +75 -0
  322. package/src/connectors/api/figma.ts +103 -0
  323. package/src/connectors/api/github.ts +247 -0
  324. package/src/connectors/api/lovable.ts +126 -0
  325. package/src/connectors/api/slack.ts +137 -0
  326. package/src/connectors/auth.ts +68 -0
  327. package/src/connectors/cache.ts +119 -0
  328. package/src/connectors/credentials.ts +81 -0
  329. package/src/connectors/index.ts +202 -0
  330. package/src/connectors/registry.ts +358 -0
  331. package/src/docs/context.ts +120 -0
  332. package/src/docs/library.ts +189 -0
  333. package/src/env/index.ts +26 -0
  334. package/src/file/ignore.ts +83 -0
  335. package/src/file/index.ts +411 -0
  336. package/src/file/ripgrep.ts +402 -0
  337. package/src/file/time.ts +65 -0
  338. package/src/file/watcher.ts +127 -0
  339. package/src/flag/flag.ts +128 -0
  340. package/src/format/formatter.ts +356 -0
  341. package/src/format/index.ts +137 -0
  342. package/src/global/index.ts +57 -0
  343. package/src/id/id.ts +83 -0
  344. package/src/ide/index.ts +76 -0
  345. package/src/index.ts +184 -0
  346. package/src/installation/index.ts +246 -0
  347. package/src/lsp/client.ts +250 -0
  348. package/src/lsp/index.ts +483 -0
  349. package/src/lsp/language.ts +119 -0
  350. package/src/lsp/server.ts +2046 -0
  351. package/src/mcp/auth.ts +121 -0
  352. package/src/mcp/index.ts +860 -0
  353. package/src/mcp/oauth-callback.ts +198 -0
  354. package/src/mcp/oauth-provider.ts +148 -0
  355. package/src/mobile/auth.ts +97 -0
  356. package/src/mobile/github-repo.ts +185 -0
  357. package/src/patch/index.ts +631 -0
  358. package/src/permission/arity.ts +150 -0
  359. package/src/permission/dbedit.ts +236 -0
  360. package/src/permission/index.ts +210 -0
  361. package/src/permission/next.ts +287 -0
  362. package/src/plugin/codex.ts +493 -0
  363. package/src/plugin/copilot.ts +261 -0
  364. package/src/plugin/index.ts +714 -0
  365. package/src/plugin/install.ts +379 -0
  366. package/src/plugin/meta.ts +165 -0
  367. package/src/plugin/shared.ts +188 -0
  368. package/src/project/bootstrap.ts +35 -0
  369. package/src/project/instance.ts +84 -0
  370. package/src/project/project.ts +373 -0
  371. package/src/project/state.ts +66 -0
  372. package/src/project/vcs.ts +76 -0
  373. package/src/prompt/stash-store.ts +93 -0
  374. package/src/provider/auth.ts +147 -0
  375. package/src/provider/models-macro.ts +22 -0
  376. package/src/provider/models.ts +216 -0
  377. package/src/provider/provider.ts +1483 -0
  378. package/src/provider/sdk/openai-compatible/src/README.md +5 -0
  379. package/src/provider/sdk/openai-compatible/src/index.ts +2 -0
  380. package/src/provider/sdk/openai-compatible/src/openai-compatible-provider.ts +100 -0
  381. package/src/provider/sdk/openai-compatible/src/responses/convert-to-openai-responses-input.ts +303 -0
  382. package/src/provider/sdk/openai-compatible/src/responses/map-openai-responses-finish-reason.ts +22 -0
  383. package/src/provider/sdk/openai-compatible/src/responses/openai-config.ts +18 -0
  384. package/src/provider/sdk/openai-compatible/src/responses/openai-error.ts +22 -0
  385. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-api-types.ts +207 -0
  386. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-language-model.ts +1732 -0
  387. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-prepare-tools.ts +177 -0
  388. package/src/provider/sdk/openai-compatible/src/responses/openai-responses-settings.ts +1 -0
  389. package/src/provider/sdk/openai-compatible/src/responses/tool/code-interpreter.ts +88 -0
  390. package/src/provider/sdk/openai-compatible/src/responses/tool/file-search.ts +128 -0
  391. package/src/provider/sdk/openai-compatible/src/responses/tool/image-generation.ts +115 -0
  392. package/src/provider/sdk/openai-compatible/src/responses/tool/local-shell.ts +65 -0
  393. package/src/provider/sdk/openai-compatible/src/responses/tool/web-search-preview.ts +104 -0
  394. package/src/provider/sdk/openai-compatible/src/responses/tool/web-search.ts +103 -0
  395. package/src/provider/transform.ts +828 -0
  396. package/src/pty/index.ts +241 -0
  397. package/src/question/index.ts +171 -0
  398. package/src/rag/chunk.ts +43 -0
  399. package/src/rag/embed.ts +179 -0
  400. package/src/rag/index.ts +376 -0
  401. package/src/rag/storage.ts +76 -0
  402. package/src/scheduler/index.ts +61 -0
  403. package/src/server/error.ts +36 -0
  404. package/src/server/event.ts +7 -0
  405. package/src/server/mdns.ts +59 -0
  406. package/src/server/routes/chatbot.ts +205 -0
  407. package/src/server/routes/companion.ts +729 -0
  408. package/src/server/routes/config.ts +92 -0
  409. package/src/server/routes/connectors.ts +121 -0
  410. package/src/server/routes/dbedit.ts +76 -0
  411. package/src/server/routes/experimental.ts +210 -0
  412. package/src/server/routes/file.ts +197 -0
  413. package/src/server/routes/global.ts +135 -0
  414. package/src/server/routes/mcp.ts +225 -0
  415. package/src/server/routes/mobile.ts +2044 -0
  416. package/src/server/routes/permission.ts +68 -0
  417. package/src/server/routes/project.ts +82 -0
  418. package/src/server/routes/provider.ts +235 -0
  419. package/src/server/routes/pty.ts +169 -0
  420. package/src/server/routes/question.ts +98 -0
  421. package/src/server/routes/session.ts +968 -0
  422. package/src/server/routes/tui.ts +379 -0
  423. package/src/server/routes/workspace.ts +104 -0
  424. package/src/server/server.ts +761 -0
  425. package/src/server/ssh.ts +207 -0
  426. package/src/session/auth.ts +402 -0
  427. package/src/session/compaction.ts +253 -0
  428. package/src/session/generate.ts +38 -0
  429. package/src/session/index.ts +598 -0
  430. package/src/session/llm.ts +273 -0
  431. package/src/session/message-v2.ts +836 -0
  432. package/src/session/message.ts +189 -0
  433. package/src/session/processor.ts +408 -0
  434. package/src/session/prompt/anthropic-20250930.txt +165 -0
  435. package/src/session/prompt/anthropic.txt +105 -0
  436. package/src/session/prompt/anthropic_spoof.txt +1 -0
  437. package/src/session/prompt/beast.txt +147 -0
  438. package/src/session/prompt/build-switch.txt +5 -0
  439. package/src/session/prompt/codex_header.txt +79 -0
  440. package/src/session/prompt/copilot-gpt-5.txt +143 -0
  441. package/src/session/prompt/gemini.txt +155 -0
  442. package/src/session/prompt/max-steps.txt +16 -0
  443. package/src/session/prompt/plan-reminder-anthropic.txt +67 -0
  444. package/src/session/prompt/plan.txt +25 -0
  445. package/src/session/prompt/qwen.txt +108 -0
  446. package/src/session/prompt.ts +1942 -0
  447. package/src/session/retry.ts +90 -0
  448. package/src/session/revert.ts +120 -0
  449. package/src/session/stats.ts +404 -0
  450. package/src/session/status.ts +84 -0
  451. package/src/session/summary.ts +184 -0
  452. package/src/session/system.ts +195 -0
  453. package/src/session/toast.tsx +105 -0
  454. package/src/session/todo.ts +258 -0
  455. package/src/session/uninstall.ts +357 -0
  456. package/src/share/share-next.ts +421 -0
  457. package/src/share/share.ts +92 -0
  458. package/src/shell/shell.ts +65 -0
  459. package/src/skill/index.ts +1 -0
  460. package/src/skill/skill.ts +232 -0
  461. package/src/snapshot/index.ts +297 -0
  462. package/src/storage/storage.ts +227 -0
  463. package/src/tool/apply_patch.ts +288 -0
  464. package/src/tool/apply_patch.txt +33 -0
  465. package/src/tool/bash.ts +252 -0
  466. package/src/tool/bash.txt +115 -0
  467. package/src/tool/batch.ts +175 -0
  468. package/src/tool/batch.txt +24 -0
  469. package/src/tool/codesearch.ts +132 -0
  470. package/src/tool/codesearch.txt +12 -0
  471. package/src/tool/context_collect.ts +152 -0
  472. package/src/tool/context_collect.txt +9 -0
  473. package/src/tool/context_diagnostics.ts +81 -0
  474. package/src/tool/context_diagnostics.txt +5 -0
  475. package/src/tool/context_related.ts +117 -0
  476. package/src/tool/context_related.txt +5 -0
  477. package/src/tool/context_search.ts +108 -0
  478. package/src/tool/context_search.txt +8 -0
  479. package/src/tool/db-diff.ts +434 -0
  480. package/src/tool/db-table.txt +15 -0
  481. package/src/tool/docs_add.ts +50 -0
  482. package/src/tool/docs_add.txt +5 -0
  483. package/src/tool/docs_context.ts +56 -0
  484. package/src/tool/docs_context.txt +4 -0
  485. package/src/tool/docs_gap_report.ts +79 -0
  486. package/src/tool/docs_gap_report.txt +7 -0
  487. package/src/tool/docs_load.ts +41 -0
  488. package/src/tool/docs_load.txt +4 -0
  489. package/src/tool/docs_request.ts +129 -0
  490. package/src/tool/docs_request.txt +7 -0
  491. package/src/tool/docs_search.ts +51 -0
  492. package/src/tool/docs_search.txt +6 -0
  493. package/src/tool/docs_unload.ts +38 -0
  494. package/src/tool/docs_unload.txt +5 -0
  495. package/src/tool/edit.ts +614 -0
  496. package/src/tool/edit.txt +10 -0
  497. package/src/tool/external-directory.ts +32 -0
  498. package/src/tool/generate_image.ts +174 -0
  499. package/src/tool/generate_image.txt +12 -0
  500. package/src/tool/glob.ts +79 -0
  501. package/src/tool/glob.txt +6 -0
  502. package/src/tool/grep.ts +153 -0
  503. package/src/tool/grep.txt +8 -0
  504. package/src/tool/invalid.ts +17 -0
  505. package/src/tool/ls.ts +116 -0
  506. package/src/tool/ls.txt +1 -0
  507. package/src/tool/lsp.ts +96 -0
  508. package/src/tool/lsp.txt +19 -0
  509. package/src/tool/memory_search.ts +141 -0
  510. package/src/tool/memory_search.txt +8 -0
  511. package/src/tool/multiedit.ts +46 -0
  512. package/src/tool/multiedit.txt +41 -0
  513. package/src/tool/plan-enter.txt +14 -0
  514. package/src/tool/plan-exit.txt +13 -0
  515. package/src/tool/plan.ts +130 -0
  516. package/src/tool/question.ts +33 -0
  517. package/src/tool/question.txt +10 -0
  518. package/src/tool/rag_index.ts +77 -0
  519. package/src/tool/rag_index.txt +10 -0
  520. package/src/tool/rag_reset.ts +26 -0
  521. package/src/tool/rag_reset.txt +4 -0
  522. package/src/tool/rag_search.ts +62 -0
  523. package/src/tool/rag_search.txt +6 -0
  524. package/src/tool/rag_status.ts +45 -0
  525. package/src/tool/rag_status.txt +4 -0
  526. package/src/tool/read.ts +203 -0
  527. package/src/tool/read.txt +12 -0
  528. package/src/tool/registry.ts +214 -0
  529. package/src/tool/skill.ts +169 -0
  530. package/src/tool/skill.txt +3 -0
  531. package/src/tool/smart_docs.ts +74 -0
  532. package/src/tool/smart_docs.txt +7 -0
  533. package/src/tool/speak/elevenlabs.ts +201 -0
  534. package/src/tool/speak/openrouter.ts +240 -0
  535. package/src/tool/speak/provider.ts +83 -0
  536. package/src/tool/speak.ts +440 -0
  537. package/src/tool/task.ts +194 -0
  538. package/src/tool/task.txt +60 -0
  539. package/src/tool/todo.ts +53 -0
  540. package/src/tool/todoread.txt +14 -0
  541. package/src/tool/todowrite.txt +167 -0
  542. package/src/tool/tool.ts +87 -0
  543. package/src/tool/tree.ts +218 -0
  544. package/src/tool/tree.txt +8 -0
  545. package/src/tool/truncation.ts +106 -0
  546. package/src/tool/use-connector.ts +47 -0
  547. package/src/tool/voice.ts +188 -0
  548. package/src/tool/webfetch.ts +205 -0
  549. package/src/tool/webfetch.txt +13 -0
  550. package/src/tool/websearch.ts +150 -0
  551. package/src/tool/websearch.txt +14 -0
  552. package/src/tool/write.ts +80 -0
  553. package/src/tool/write.txt +8 -0
  554. package/src/util/archive.ts +16 -0
  555. package/src/util/color.ts +19 -0
  556. package/src/util/context.ts +25 -0
  557. package/src/util/defer.ts +12 -0
  558. package/src/util/error.ts +77 -0
  559. package/src/util/eventloop.ts +20 -0
  560. package/src/util/filesystem.ts +125 -0
  561. package/src/util/flock.ts +329 -0
  562. package/src/util/fn.ts +11 -0
  563. package/src/util/format.ts +20 -0
  564. package/src/util/hash.ts +7 -0
  565. package/src/util/iife.ts +3 -0
  566. package/src/util/keybind.ts +103 -0
  567. package/src/util/lazy.ts +18 -0
  568. package/src/util/locale.ts +81 -0
  569. package/src/util/lock.ts +98 -0
  570. package/src/util/log.ts +180 -0
  571. package/src/util/network.ts +9 -0
  572. package/src/util/process.ts +15 -0
  573. package/src/util/queue.ts +32 -0
  574. package/src/util/record.ts +3 -0
  575. package/src/util/rpc.ts +66 -0
  576. package/src/util/scrap.ts +10 -0
  577. package/src/util/signal.ts +12 -0
  578. package/src/util/timeout.ts +14 -0
  579. package/src/util/token.ts +7 -0
  580. package/src/util/wildcard.ts +56 -0
  581. package/src/workspace/adaptors/index.ts +271 -0
  582. package/src/workspace/adaptors/types.ts +14 -0
  583. package/src/workspace/adaptors/worktree.ts +31 -0
  584. package/src/workspace/config.ts +19 -0
  585. package/src/workspace/index.ts +223 -0
  586. package/src/workspace/session-proxy-middleware.ts +97 -0
  587. package/src/workspace/sse.ts +66 -0
  588. package/src/workspace/workspace-context.ts +23 -0
  589. package/src/workspace/workspace-server/routes.ts +33 -0
  590. package/src/workspace/workspace-server/server.ts +47 -0
  591. package/src/worktree/index.ts +487 -0
  592. package/sst-env.d.ts +10 -0
  593. package/test/benchmark.test.ts +121 -0
  594. package/test/build-optimizations.test.ts +124 -0
  595. package/test/id-benchmark.test.ts +132 -0
  596. package/test/optimizations.test.ts +302 -0
  597. package/test/preload.ts +1 -0
  598. package/test/solidjs-benchmark.test.ts +262 -0
  599. package/test/solidjs-optimizations.test.ts +259 -0
  600. package/test/tui-benchmark.test.ts +230 -0
  601. package/test/wildcard-benchmark.test.ts +180 -0
  602. package/tsconfig.json +26 -0
@@ -0,0 +1,258 @@
1
+ import { BusEvent } from "@/bus/bus-event"
2
+ import { Bus } from "@/bus"
3
+ import os from "os"
4
+ import path from "path"
5
+ import { fileURLToPath } from "url"
6
+ import z from "zod"
7
+ import { Storage } from "../storage/storage"
8
+ import { Config } from "../config/config"
9
+ import { resolveCredential } from "../connectors/credentials"
10
+ import { Log } from "../util/log"
11
+ import { Flag } from "../flag/flag"
12
+
13
+ const log = Log.create({ service: "todo-notifications" })
14
+
15
+ type MacIcon = {
16
+ value: string
17
+ remote: boolean
18
+ }
19
+
20
+ export namespace Todo {
21
+ export const Info = z
22
+ .object({
23
+ content: z.string().describe("Brief description of the task"),
24
+ status: z.string().describe("Current status of the task: pending, in_progress, completed, cancelled"),
25
+ priority: z.string().describe("Priority level of the task: high, medium, low"),
26
+ id: z.string().describe("Unique identifier for the todo item"),
27
+ })
28
+ .meta({ ref: "Todo" })
29
+ export type Info = z.infer<typeof Info>
30
+
31
+ export const Event = {
32
+ Updated: BusEvent.define(
33
+ "todo.updated",
34
+ z.object({
35
+ sessionID: z.string(),
36
+ todos: z.array(Info),
37
+ diff: z.object({
38
+ added: z.array(Info),
39
+ completed: z.array(Info),
40
+ }),
41
+ }),
42
+ ),
43
+ }
44
+
45
+ function done(status: string) {
46
+ return status === "completed" || status === "cancelled"
47
+ }
48
+
49
+ function diff(prev: Info[], next: Info[]) {
50
+ const prevMap = new Map(prev.map((todo) => [todo.id, todo]))
51
+ const added = next.filter((todo) => !prevMap.has(todo.id))
52
+ const completed = next.filter((todo) => {
53
+ if (!done(todo.status)) return false
54
+ const old = prevMap.get(todo.id)
55
+ if (!old) return false
56
+ return !done(old.status)
57
+ })
58
+ return { added, completed }
59
+ }
60
+
61
+ export async function update(input: { sessionID: string; todos: Info[] }) {
62
+ const prev = await get(input.sessionID)
63
+ const change = diff(prev, input.todos)
64
+ await Storage.write(["todo", input.sessionID], input.todos)
65
+ Bus.publish(Event.Updated, { ...input, diff: change })
66
+ }
67
+
68
+ export async function get(sessionID: string) {
69
+ return Storage.read<Info[]>(["todo", sessionID])
70
+ .then((todo) => todo || [])
71
+ .catch(() => [])
72
+ }
73
+
74
+ type ConnectorEntry = NonNullable<Config.Info["connectors"]>[string]
75
+
76
+ function isConnector(entry: ConnectorEntry | undefined): entry is Config.Connector {
77
+ return typeof entry === "object" && entry !== null && "type" in entry
78
+ }
79
+
80
+ function list(todos: Info[]) {
81
+ return todos.map((todo) => `- ${todo.content} (${todo.priority})`).join("\n")
82
+ }
83
+
84
+ function iconPath(value: string) {
85
+ if (!value) return undefined
86
+ if (value === "~") return os.homedir()
87
+ if (value.startsWith("~/")) return path.join(os.homedir(), value.slice(2))
88
+ if (value.startsWith("file://")) return fileURLToPath(value)
89
+ if (path.isAbsolute(value)) return value
90
+ return undefined
91
+ }
92
+
93
+ function iconMac(config: Config.Info): MacIcon | undefined {
94
+ const icon = config.notifications?.icon
95
+ if (!icon) return undefined
96
+ const value = icon.url
97
+ if (!value) return undefined
98
+ if (value.startsWith("http://") || value.startsWith("https://")) {
99
+ return { value, remote: true }
100
+ }
101
+ const local = iconPath(value)
102
+ if (!local) return undefined
103
+ return { value: local, remote: false }
104
+ }
105
+
106
+ async function macos(config: Config.Info, title: string, body: string) {
107
+ if (process.platform !== "darwin") return
108
+ const icon = iconMac(config)
109
+ const message = body.length ? body : " "
110
+
111
+ const notifier = icon && !icon.remote ? Bun.which("terminal-notifier") : null
112
+ if (icon && notifier && !icon.remote) {
113
+ const result = await Bun.$`${notifier} -title ${title} -message ${message} -contentImage ${icon.value}`
114
+ .nothrow()
115
+ .quiet()
116
+ if (result.exitCode === 0) return
117
+ }
118
+ if (!icon) {
119
+ const escapedTitle = title.replace(/"/g, '\\"')
120
+ const escapedBody = body.replace(/"/g, '\\"')
121
+ await Bun.$`osascript -e 'display notification "${escapedBody}" with title "${escapedTitle}"'`.nothrow().quiet()
122
+ return
123
+ }
124
+ const script = `
125
+ ObjC.import('Cocoa')
126
+ const title = ${JSON.stringify(title)}
127
+ const body = ${JSON.stringify(body)}
128
+ const image = ${JSON.stringify(icon.value)}
129
+ const remote = ${JSON.stringify(icon.remote)}
130
+ const notification = $.NSUserNotification.alloc.init
131
+ notification.title = title
132
+ notification.informativeText = body
133
+ const url = remote ? $.NSURL.URLWithString(image) : $.NSURL.fileURLWithPath(image)
134
+ const img = $.NSImage.alloc.initWithContentsOfURL(url)
135
+ if (!img) throw new Error('icon load failed')
136
+ notification.contentImage = img
137
+ const center = $.NSUserNotificationCenter.defaultUserNotificationCenter
138
+ center.deliverNotification(notification)
139
+ $.NSThread.sleepForTimeInterval(0.2)
140
+ if (!notification.presented) throw new Error('notification not presented')
141
+ `
142
+ const result = await Bun.$`osascript -l JavaScript -e ${script}`.nothrow().quiet()
143
+ if (result.exitCode === 0) return
144
+ const escapedTitle = title.replace(/"/g, '\\"')
145
+ const escapedBody = body.replace(/"/g, '\\"')
146
+ await Bun.$`osascript -e 'display notification "${escapedBody}" with title "${escapedTitle}"'`.nothrow().quiet()
147
+ }
148
+
149
+ async function slack(config: Config.Info, message: string) {
150
+ const settings = config.notifications?.todo
151
+ if (!settings) return
152
+ const cfg = settings.slack
153
+ if (!cfg) return
154
+ if (cfg.enabled === false) return
155
+
156
+ const enabled = cfg.enabled ?? Flag.NIKCLI_SLACK_TASK_NOTIFICATIONS
157
+ if (!enabled) return
158
+
159
+ if (!cfg.connector) return
160
+ const name = cfg.connector
161
+ const channel = cfg.channel || Flag.NIKCLI_SLACK_CHANNEL
162
+ if (!channel) return
163
+ const connectors = config.connectors ?? {}
164
+ const entry = connectors[name]
165
+ if (!isConnector(entry)) return
166
+ if (entry.enabled === false) return
167
+ if (entry.type !== "slack") return
168
+
169
+ const credential = await resolveCredential(name, entry)
170
+ if (!credential) return
171
+ const api = await import("../connectors/api/slack")
172
+ await api.SlackApi.sendMessage(credential, channel, message).catch((error) => {
173
+ const text = error instanceof Error ? error.message : String(error)
174
+ log.error("failed to send Slack notification", { error: text })
175
+ })
176
+ }
177
+
178
+ async function discord(config: Config.Info, message: string) {
179
+ const settings = config.notifications?.todo
180
+ if (!settings) return
181
+ const cfg = settings.discord
182
+ if (!cfg) return
183
+ if (cfg.enabled === false) return
184
+
185
+ const enabled = cfg.enabled ?? Flag.NIKCLI_DISCORD_TASK_NOTIFICATIONS
186
+ if (!enabled) return
187
+ const webhook = cfg.webhook || Flag.NIKCLI_DISCORD_WEBHOOK_URL
188
+ if (!webhook) return
189
+
190
+ await fetch(webhook, {
191
+ method: "POST",
192
+ headers: { "Content-Type": "application/json" },
193
+ body: JSON.stringify({ content: message }),
194
+ })
195
+ .then(async (response) => {
196
+ if (response.ok) return
197
+ const text = await response.text().catch(() => "")
198
+ const detail = text ? `Discord webhook failed: ${text}` : `Discord webhook failed: ${response.status}`
199
+ throw new Error(detail)
200
+ })
201
+ .catch((error) => {
202
+ const text = error instanceof Error ? error.message : String(error)
203
+ log.error("failed to send Discord notification", { error: text })
204
+ })
205
+ }
206
+
207
+ async function notify(change: { added: Info[]; completed: Info[] }) {
208
+ const config = await Config.get()
209
+ const settings = config.notifications?.todo
210
+ if (!settings) return
211
+ if (settings.enabled === false) return
212
+
213
+ const envEnabled =
214
+ Flag.NIKCLI_TODO_NOTIFICATIONS || Flag.NIKCLI_SLACK_TASK_NOTIFICATIONS || Flag.NIKCLI_DISCORD_TASK_NOTIFICATIONS
215
+ const enabled = settings.enabled ?? envEnabled
216
+ if (!enabled) return
217
+
218
+ const added = change.added
219
+ const completed = change.completed
220
+ if (added.length === 0 && completed.length === 0) return
221
+
222
+ if (added.length > 0) {
223
+ const title = added.length === 1 ? "New Todo Created" : `${added.length} New Todos`
224
+ const body = added.length === 1 ? added[0].content : list(added)
225
+ const slackMessage =
226
+ added.length === 1 ? `New todo: ${added[0].content}` : `${added.length} new todos:\n${list(added)}`
227
+ const discordMessage = slackMessage
228
+
229
+ if (settings.macos === true) {
230
+ await macos(config, title, body).catch(() => {})
231
+ }
232
+ await slack(config, slackMessage)
233
+ await discord(config, discordMessage)
234
+ }
235
+
236
+ if (completed.length > 0) {
237
+ const title = completed.length === 1 ? "Todo Completed" : `${completed.length} Todos Completed`
238
+ const body = completed.length === 1 ? completed[0].content : list(completed)
239
+ const slackMessage =
240
+ completed.length === 1
241
+ ? `Completed: ${completed[0].content}`
242
+ : `${completed.length} todos completed:\n${list(completed)}`
243
+ const discordMessage = slackMessage
244
+
245
+ if (settings.macos === true) {
246
+ await macos(config, title, body).catch(() => {})
247
+ }
248
+ await slack(config, slackMessage)
249
+ await discord(config, discordMessage)
250
+ }
251
+ }
252
+
253
+ export function init() {
254
+ Bus.subscribe(Event.Updated, async (evt) => {
255
+ await notify(evt.properties.diff)
256
+ })
257
+ }
258
+ }
@@ -0,0 +1,357 @@
1
+ import type { Argv } from "yargs"
2
+ import * as prompts from "@clack/prompts"
3
+ import { Installation } from "../installation"
4
+ import { Global } from "../global"
5
+ import { $ } from "bun"
6
+ import fs from "fs/promises"
7
+ import path from "path"
8
+ import os from "os"
9
+ import { UI } from "@/cli/ui"
10
+
11
+ interface UninstallArgs {
12
+ keepConfig: boolean
13
+ keepData: boolean
14
+ dryRun: boolean
15
+ force: boolean
16
+ }
17
+
18
+ interface RemovalTargets {
19
+ directories: Array<{ path: string; label: string; keep: boolean }>
20
+ shellConfig: string | null
21
+ binary: string | null
22
+ }
23
+
24
+ export const UninstallCommand = {
25
+ command: "uninstall",
26
+ describe: "uninstall nikcli and remove all related files",
27
+ builder: (yargs: Argv) =>
28
+ yargs
29
+ .option("keep-config", {
30
+ alias: "c",
31
+ type: "boolean",
32
+ describe: "keep configuration files",
33
+ default: false,
34
+ })
35
+ .option("keep-data", {
36
+ alias: "d",
37
+ type: "boolean",
38
+ describe: "keep session data and snapshots",
39
+ default: false,
40
+ })
41
+ .option("dry-run", {
42
+ type: "boolean",
43
+ describe: "show what would be removed without removing",
44
+ default: false,
45
+ })
46
+ .option("force", {
47
+ alias: "f",
48
+ type: "boolean",
49
+ describe: "skip confirmation prompts",
50
+ default: false,
51
+ }),
52
+
53
+ handler: async (args: UninstallArgs) => {
54
+ UI.empty()
55
+ UI.println(UI.logo(" "))
56
+ UI.empty()
57
+ prompts.intro("Uninstall Nikcli")
58
+
59
+ const method = await Installation.method()
60
+ prompts.log.info(`Installation method: ${method}`)
61
+
62
+ const targets = await collectRemovalTargets(args, method)
63
+
64
+ await showRemovalSummary(targets, method)
65
+
66
+ if (!args.force && !args.dryRun) {
67
+ const confirm = await prompts.confirm({
68
+ message: "Are you sure you want to uninstall?",
69
+ initialValue: false,
70
+ })
71
+ if (!confirm || prompts.isCancel(confirm)) {
72
+ prompts.outro("Cancelled")
73
+ return
74
+ }
75
+ }
76
+
77
+ if (args.dryRun) {
78
+ prompts.log.warn("Dry run - no changes made")
79
+ prompts.outro("Done")
80
+ return
81
+ }
82
+
83
+ await executeUninstall(method, targets)
84
+
85
+ prompts.outro("Done")
86
+ },
87
+ }
88
+
89
+ async function collectRemovalTargets(args: UninstallArgs, method: Installation.Method): Promise<RemovalTargets> {
90
+ const directories: RemovalTargets["directories"] = [
91
+ { path: Global.Path.data, label: "Data", keep: args.keepData },
92
+ { path: Global.Path.cache, label: "Cache", keep: false },
93
+ { path: Global.Path.config, label: "Config", keep: args.keepConfig },
94
+ { path: Global.Path.state, label: "State", keep: false },
95
+ ]
96
+
97
+ const shellConfig = method === "curl" ? await getShellConfigFile() : null
98
+ const binary = method === "curl" ? process.execPath : null
99
+
100
+ return { directories, shellConfig, binary }
101
+ }
102
+
103
+ async function showRemovalSummary(targets: RemovalTargets, method: Installation.Method) {
104
+ prompts.log.message("The following will be removed:")
105
+
106
+ for (const dir of targets.directories) {
107
+ const exists = await fs
108
+ .access(dir.path)
109
+ .then(() => true)
110
+ .catch(() => false)
111
+ if (!exists) continue
112
+
113
+ const size = await getDirectorySize(dir.path)
114
+ const sizeStr = formatSize(size)
115
+ const status = dir.keep ? UI.Style.TEXT_DIM + "(keeping)" : ""
116
+ const prefix = dir.keep ? "○" : "✓"
117
+
118
+ prompts.log.info(` ${prefix} ${dir.label}: ${shortenPath(dir.path)} ${UI.Style.TEXT_DIM}(${sizeStr})${status}`)
119
+ }
120
+
121
+ if (targets.binary) {
122
+ prompts.log.info(` ✓ Binary: ${shortenPath(targets.binary)}`)
123
+ }
124
+
125
+ if (targets.shellConfig) {
126
+ prompts.log.info(` ✓ Shell PATH in ${shortenPath(targets.shellConfig)}`)
127
+ }
128
+
129
+ if (method !== "curl" && method !== "unknown") {
130
+ const cmds: Record<string, string> = {
131
+ npm: "npm uninstall -g nikcli-ai",
132
+ pnpm: "pnpm uninstall -g nikcli-ai",
133
+ bun: "bun remove -g nikcli-ai",
134
+ yarn: "yarn global remove nikcli-ai",
135
+ brew: "brew uninstall nikcli",
136
+ choco: "choco uninstall nikcli",
137
+ scoop: "scoop uninstall nikcli",
138
+ }
139
+ prompts.log.info(` ✓ Package: ${cmds[method] || method}`)
140
+ }
141
+ }
142
+
143
+ async function executeUninstall(method: Installation.Method, targets: RemovalTargets) {
144
+ const spinner = prompts.spinner()
145
+ const errors: string[] = []
146
+
147
+ for (const dir of targets.directories) {
148
+ if (dir.keep) {
149
+ prompts.log.step(`Skipping ${dir.label} (--keep-${dir.label.toLowerCase()})`)
150
+ continue
151
+ }
152
+
153
+ const exists = await fs
154
+ .access(dir.path)
155
+ .then(() => true)
156
+ .catch(() => false)
157
+ if (!exists) continue
158
+
159
+ spinner.start(`Removing ${dir.label}...`)
160
+ const err = await fs.rm(dir.path, { recursive: true, force: true }).catch((e) => e)
161
+ if (err) {
162
+ spinner.stop(`Failed to remove ${dir.label}`, 1)
163
+ errors.push(`${dir.label}: ${err.message}`)
164
+ continue
165
+ }
166
+ spinner.stop(`Removed ${dir.label}`)
167
+ }
168
+
169
+ if (targets.shellConfig) {
170
+ spinner.start("Cleaning shell config...")
171
+ const err = await cleanShellConfig(targets.shellConfig).catch((e) => e)
172
+ if (err) {
173
+ spinner.stop("Failed to clean shell config", 1)
174
+ errors.push(`Shell config: ${err.message}`)
175
+ } else {
176
+ spinner.stop("Cleaned shell config")
177
+ }
178
+ }
179
+
180
+ if (method !== "curl" && method !== "unknown") {
181
+ const cmds: Record<string, string[]> = {
182
+ npm: ["npm", "uninstall", "-g", "nikcli-ai"],
183
+ pnpm: ["pnpm", "uninstall", "-g", "nikcli-ai"],
184
+ bun: ["bun", "remove", "-g", "nikcli-ai"],
185
+ yarn: ["yarn", "global", "remove", "nikcli-ai"],
186
+ brew: ["brew", "uninstall", "nikcli"],
187
+ choco: ["choco", "uninstall", "nikcli"],
188
+ scoop: ["scoop", "uninstall", "nikcli"],
189
+ }
190
+
191
+ const cmd = cmds[method]
192
+ if (cmd) {
193
+ spinner.start(`Running ${cmd.join(" ")}...`)
194
+ const result =
195
+ method === "choco"
196
+ ? await $`echo Y | choco uninstall nikcli -y -r`.quiet().nothrow()
197
+ : await $`${cmd}`.quiet().nothrow()
198
+ if (result.exitCode !== 0) {
199
+ spinner.stop(`Package manager uninstall failed: exit code ${result.exitCode}`, 1)
200
+ if (
201
+ method === "choco" &&
202
+ result.stdout.toString("utf8").includes("not running from an elevated command shell")
203
+ ) {
204
+ prompts.log.warn(`You may need to run '${cmd.join(" ")}' from an elevated command shell`)
205
+ } else {
206
+ prompts.log.warn(`You may need to run manually: ${cmd.join(" ")}`)
207
+ }
208
+ } else {
209
+ spinner.stop("Package removed")
210
+ }
211
+ }
212
+ }
213
+
214
+ if (method === "curl" && targets.binary) {
215
+ UI.empty()
216
+ prompts.log.message("To finish removing the binary, run:")
217
+ prompts.log.info(` rm "${targets.binary}"`)
218
+
219
+ const binDir = path.dirname(targets.binary)
220
+ if (binDir.includes(".nikcli")) {
221
+ prompts.log.info(` rmdir "${binDir}" 2>/dev/null`)
222
+ }
223
+ }
224
+
225
+ if (errors.length > 0) {
226
+ UI.empty()
227
+ prompts.log.warn("Some operations failed:")
228
+ for (const err of errors) {
229
+ prompts.log.error(` ${err}`)
230
+ }
231
+ }
232
+
233
+ UI.empty()
234
+ prompts.log.success("Thank you for using Nikcli!")
235
+ }
236
+
237
+ async function getShellConfigFile(): Promise<string | null> {
238
+ const shell = path.basename(process.env.SHELL || "bash")
239
+ const home = os.homedir()
240
+ const xdgConfig = process.env.XDG_CONFIG_HOME || path.join(home, ".config")
241
+
242
+ const configFiles: Record<string, string[]> = {
243
+ fish: [path.join(xdgConfig, "fish", "config.fish")],
244
+ zsh: [
245
+ path.join(home, ".zshrc"),
246
+ path.join(home, ".zshenv"),
247
+ path.join(xdgConfig, "zsh", ".zshrc"),
248
+ path.join(xdgConfig, "zsh", ".zshenv"),
249
+ ],
250
+ bash: [
251
+ path.join(home, ".bashrc"),
252
+ path.join(home, ".bash_profile"),
253
+ path.join(home, ".profile"),
254
+ path.join(xdgConfig, "bash", ".bashrc"),
255
+ path.join(xdgConfig, "bash", ".bash_profile"),
256
+ ],
257
+ ash: [path.join(home, ".ashrc"), path.join(home, ".profile")],
258
+ sh: [path.join(home, ".profile")],
259
+ }
260
+
261
+ const candidates = configFiles[shell] || configFiles.bash
262
+
263
+ for (const file of candidates) {
264
+ const exists = await fs
265
+ .access(file)
266
+ .then(() => true)
267
+ .catch(() => false)
268
+ if (!exists) continue
269
+
270
+ const content = await Bun.file(file)
271
+ .text()
272
+ .catch(() => "")
273
+ if (content.includes("# nikcli") || content.includes(".nikcli/bin")) {
274
+ return file
275
+ }
276
+ }
277
+
278
+ return null
279
+ }
280
+
281
+ async function cleanShellConfig(file: string) {
282
+ const content = await Bun.file(file).text()
283
+ const lines = content.split("\n")
284
+
285
+ const filtered: string[] = []
286
+ let skip = false
287
+
288
+ for (const line of lines) {
289
+ const trimmed = line.trim()
290
+
291
+ if (trimmed === "# nikcli") {
292
+ skip = true
293
+ continue
294
+ }
295
+
296
+ if (skip) {
297
+ skip = false
298
+ if (trimmed.includes(".nikcli/bin") || trimmed.includes("fish_add_path")) {
299
+ continue
300
+ }
301
+ }
302
+
303
+ if (
304
+ (trimmed.startsWith("export PATH=") && trimmed.includes(".nikcli/bin")) ||
305
+ (trimmed.startsWith("fish_add_path") && trimmed.includes(".nikcli"))
306
+ ) {
307
+ continue
308
+ }
309
+
310
+ filtered.push(line)
311
+ }
312
+
313
+ while (filtered.length > 0 && filtered[filtered.length - 1].trim() === "") {
314
+ filtered.pop()
315
+ }
316
+
317
+ const output = filtered.join("\n") + "\n"
318
+ await Bun.write(file, output)
319
+ }
320
+
321
+ async function getDirectorySize(dir: string): Promise<number> {
322
+ let total = 0
323
+
324
+ const walk = async (current: string) => {
325
+ const entries = await fs.readdir(current, { withFileTypes: true }).catch(() => [])
326
+
327
+ for (const entry of entries) {
328
+ const full = path.join(current, entry.name)
329
+ if (entry.isDirectory()) {
330
+ await walk(full)
331
+ continue
332
+ }
333
+ if (entry.isFile()) {
334
+ const stat = await fs.stat(full).catch(() => null)
335
+ if (stat) total += stat.size
336
+ }
337
+ }
338
+ }
339
+
340
+ await walk(dir)
341
+ return total
342
+ }
343
+
344
+ function formatSize(bytes: number): string {
345
+ if (bytes < 1024) return `${bytes} B`
346
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
347
+ if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
348
+ return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`
349
+ }
350
+
351
+ function shortenPath(p: string): string {
352
+ const home = os.homedir()
353
+ if (p.startsWith(home)) {
354
+ return p.replace(home, "~")
355
+ }
356
+ return p
357
+ }