gencode-ai 0.1.0 → 0.1.2

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 (356) hide show
  1. package/.gencode/settings.local.json +7 -0
  2. package/README.md +20 -102
  3. package/dist/agent/agent.d.ts +43 -2
  4. package/dist/agent/agent.d.ts.map +1 -1
  5. package/dist/agent/agent.js +90 -17
  6. package/dist/agent/agent.js.map +1 -1
  7. package/dist/agent/types.d.ts +9 -1
  8. package/dist/agent/types.d.ts.map +1 -1
  9. package/dist/cli/components/AllModelsSelector.d.ts +11 -0
  10. package/dist/cli/components/AllModelsSelector.d.ts.map +1 -0
  11. package/dist/cli/components/AllModelsSelector.js +153 -0
  12. package/dist/cli/components/AllModelsSelector.js.map +1 -0
  13. package/dist/cli/components/App.d.ts +8 -1
  14. package/dist/cli/components/App.d.ts.map +1 -1
  15. package/dist/cli/components/App.js +276 -40
  16. package/dist/cli/components/App.js.map +1 -1
  17. package/dist/cli/components/CommandSuggestions.d.ts.map +1 -1
  18. package/dist/cli/components/CommandSuggestions.js +3 -0
  19. package/dist/cli/components/CommandSuggestions.js.map +1 -1
  20. package/dist/cli/components/Header.d.ts +1 -1
  21. package/dist/cli/components/Header.d.ts.map +1 -1
  22. package/dist/cli/components/Header.js +4 -6
  23. package/dist/cli/components/Header.js.map +1 -1
  24. package/dist/cli/components/Logo.d.ts +1 -0
  25. package/dist/cli/components/Logo.d.ts.map +1 -1
  26. package/dist/cli/components/Logo.js +16 -3
  27. package/dist/cli/components/Logo.js.map +1 -1
  28. package/dist/cli/components/Messages.d.ts +17 -3
  29. package/dist/cli/components/Messages.d.ts.map +1 -1
  30. package/dist/cli/components/Messages.js +70 -18
  31. package/dist/cli/components/Messages.js.map +1 -1
  32. package/dist/cli/components/ModelSelector.d.ts +7 -7
  33. package/dist/cli/components/ModelSelector.d.ts.map +1 -1
  34. package/dist/cli/components/ModelSelector.js +116 -33
  35. package/dist/cli/components/ModelSelector.js.map +1 -1
  36. package/dist/cli/components/PermissionPrompt.d.ts +60 -0
  37. package/dist/cli/components/PermissionPrompt.d.ts.map +1 -0
  38. package/dist/cli/components/PermissionPrompt.js +192 -0
  39. package/dist/cli/components/PermissionPrompt.js.map +1 -0
  40. package/dist/cli/components/ProviderManager.d.ts +8 -0
  41. package/dist/cli/components/ProviderManager.d.ts.map +1 -0
  42. package/dist/cli/components/ProviderManager.js +280 -0
  43. package/dist/cli/components/ProviderManager.js.map +1 -0
  44. package/dist/cli/components/Spinner.d.ts +7 -2
  45. package/dist/cli/components/Spinner.d.ts.map +1 -1
  46. package/dist/cli/components/Spinner.js +116 -25
  47. package/dist/cli/components/Spinner.js.map +1 -1
  48. package/dist/cli/components/TodoList.d.ts +7 -0
  49. package/dist/cli/components/TodoList.d.ts.map +1 -0
  50. package/dist/cli/components/TodoList.js +34 -0
  51. package/dist/cli/components/TodoList.js.map +1 -0
  52. package/dist/cli/components/index.d.ts +1 -0
  53. package/dist/cli/components/index.d.ts.map +1 -1
  54. package/dist/cli/components/index.js +1 -0
  55. package/dist/cli/components/index.js.map +1 -1
  56. package/dist/cli/components/markdown.d.ts +9 -0
  57. package/dist/cli/components/markdown.d.ts.map +1 -0
  58. package/dist/cli/components/markdown.js +129 -0
  59. package/dist/cli/components/markdown.js.map +1 -0
  60. package/dist/cli/components/theme.d.ts +5 -0
  61. package/dist/cli/components/theme.d.ts.map +1 -1
  62. package/dist/cli/components/theme.js +7 -0
  63. package/dist/cli/components/theme.js.map +1 -1
  64. package/dist/cli/index.js +66 -12
  65. package/dist/cli/index.js.map +1 -1
  66. package/dist/config/index.d.ts +14 -4
  67. package/dist/config/index.d.ts.map +1 -1
  68. package/dist/config/index.js +19 -3
  69. package/dist/config/index.js.map +1 -1
  70. package/dist/config/levels.d.ts +49 -0
  71. package/dist/config/levels.d.ts.map +1 -0
  72. package/dist/config/levels.js +222 -0
  73. package/dist/config/levels.js.map +1 -0
  74. package/dist/config/loader.d.ts +46 -0
  75. package/dist/config/loader.d.ts.map +1 -0
  76. package/dist/config/loader.js +153 -0
  77. package/dist/config/loader.js.map +1 -0
  78. package/dist/config/manager.d.ts +115 -15
  79. package/dist/config/manager.d.ts.map +1 -1
  80. package/dist/config/manager.js +260 -34
  81. package/dist/config/manager.js.map +1 -1
  82. package/dist/config/manager.test.d.ts +5 -0
  83. package/dist/config/manager.test.d.ts.map +1 -0
  84. package/dist/config/manager.test.js +192 -0
  85. package/dist/config/manager.test.js.map +1 -0
  86. package/dist/config/merger.d.ts +56 -0
  87. package/dist/config/merger.d.ts.map +1 -0
  88. package/dist/config/merger.js +177 -0
  89. package/dist/config/merger.js.map +1 -0
  90. package/dist/config/providers-config.d.ts +28 -0
  91. package/dist/config/providers-config.d.ts.map +1 -0
  92. package/dist/config/providers-config.js +79 -0
  93. package/dist/config/providers-config.js.map +1 -0
  94. package/dist/config/test-utils.d.ts +24 -0
  95. package/dist/config/test-utils.d.ts.map +1 -0
  96. package/dist/config/test-utils.js +55 -0
  97. package/dist/config/test-utils.js.map +1 -0
  98. package/dist/config/types.d.ts +108 -9
  99. package/dist/config/types.d.ts.map +1 -1
  100. package/dist/config/types.js +53 -2
  101. package/dist/config/types.js.map +1 -1
  102. package/dist/memory/import-resolver.d.ts +46 -0
  103. package/dist/memory/import-resolver.d.ts.map +1 -0
  104. package/dist/memory/import-resolver.js +117 -0
  105. package/dist/memory/import-resolver.js.map +1 -0
  106. package/dist/memory/index.d.ts +7 -6
  107. package/dist/memory/index.d.ts.map +1 -1
  108. package/dist/memory/index.js +7 -5
  109. package/dist/memory/index.js.map +1 -1
  110. package/dist/memory/init-prompt.d.ts +22 -0
  111. package/dist/memory/init-prompt.d.ts.map +1 -0
  112. package/dist/memory/init-prompt.js +103 -0
  113. package/dist/memory/init-prompt.js.map +1 -0
  114. package/dist/memory/memory-manager.d.ts +119 -0
  115. package/dist/memory/memory-manager.d.ts.map +1 -0
  116. package/dist/memory/memory-manager.js +587 -0
  117. package/dist/memory/memory-manager.js.map +1 -0
  118. package/dist/memory/rules-parser.d.ts +38 -0
  119. package/dist/memory/rules-parser.d.ts.map +1 -0
  120. package/dist/memory/rules-parser.js +69 -0
  121. package/dist/memory/rules-parser.js.map +1 -0
  122. package/dist/memory/test-utils.d.ts +20 -0
  123. package/dist/memory/test-utils.d.ts.map +1 -0
  124. package/dist/memory/test-utils.js +44 -0
  125. package/dist/memory/test-utils.js.map +1 -0
  126. package/dist/memory/types.d.ts +70 -63
  127. package/dist/memory/types.d.ts.map +1 -1
  128. package/dist/memory/types.js +42 -2
  129. package/dist/memory/types.js.map +1 -1
  130. package/dist/permissions/audit.d.ts +82 -0
  131. package/dist/permissions/audit.d.ts.map +1 -0
  132. package/dist/permissions/audit.js +229 -0
  133. package/dist/permissions/audit.js.map +1 -0
  134. package/dist/permissions/index.d.ts +11 -1
  135. package/dist/permissions/index.d.ts.map +1 -1
  136. package/dist/permissions/index.js +15 -0
  137. package/dist/permissions/index.js.map +1 -1
  138. package/dist/permissions/manager.d.ts +149 -13
  139. package/dist/permissions/manager.d.ts.map +1 -1
  140. package/dist/permissions/manager.js +480 -35
  141. package/dist/permissions/manager.js.map +1 -1
  142. package/dist/permissions/manager.test.d.ts +5 -0
  143. package/dist/permissions/manager.test.d.ts.map +1 -0
  144. package/dist/permissions/manager.test.js +213 -0
  145. package/dist/permissions/manager.test.js.map +1 -0
  146. package/dist/permissions/persistence.d.ts +74 -0
  147. package/dist/permissions/persistence.d.ts.map +1 -0
  148. package/dist/permissions/persistence.js +248 -0
  149. package/dist/permissions/persistence.js.map +1 -0
  150. package/dist/permissions/persistence.test.d.ts +5 -0
  151. package/dist/permissions/persistence.test.d.ts.map +1 -0
  152. package/dist/permissions/persistence.test.js +171 -0
  153. package/dist/permissions/persistence.test.js.map +1 -0
  154. package/dist/permissions/prompt-matcher.d.ts +64 -0
  155. package/dist/permissions/prompt-matcher.d.ts.map +1 -0
  156. package/dist/permissions/prompt-matcher.js +415 -0
  157. package/dist/permissions/prompt-matcher.js.map +1 -0
  158. package/dist/permissions/prompt-matcher.test.d.ts +5 -0
  159. package/dist/permissions/prompt-matcher.test.d.ts.map +1 -0
  160. package/dist/permissions/prompt-matcher.test.js +107 -0
  161. package/dist/permissions/prompt-matcher.test.js.map +1 -0
  162. package/dist/permissions/types.d.ts +157 -0
  163. package/dist/permissions/types.d.ts.map +1 -1
  164. package/dist/permissions/types.js +43 -8
  165. package/dist/permissions/types.js.map +1 -1
  166. package/dist/prompts/index.d.ts +92 -0
  167. package/dist/prompts/index.d.ts.map +1 -0
  168. package/dist/prompts/index.js +241 -0
  169. package/dist/prompts/index.js.map +1 -0
  170. package/dist/providers/gemini.d.ts.map +1 -1
  171. package/dist/providers/gemini.js +14 -3
  172. package/dist/providers/gemini.js.map +1 -1
  173. package/dist/providers/index.d.ts +5 -3
  174. package/dist/providers/index.d.ts.map +1 -1
  175. package/dist/providers/index.js +13 -1
  176. package/dist/providers/index.js.map +1 -1
  177. package/dist/providers/registry.d.ts +66 -0
  178. package/dist/providers/registry.d.ts.map +1 -0
  179. package/dist/providers/registry.js +158 -0
  180. package/dist/providers/registry.js.map +1 -0
  181. package/dist/providers/search/brave.d.ts +14 -0
  182. package/dist/providers/search/brave.d.ts.map +1 -0
  183. package/dist/providers/search/brave.js +87 -0
  184. package/dist/providers/search/brave.js.map +1 -0
  185. package/dist/providers/search/exa.d.ts +12 -0
  186. package/dist/providers/search/exa.d.ts.map +1 -0
  187. package/dist/providers/search/exa.js +158 -0
  188. package/dist/providers/search/exa.js.map +1 -0
  189. package/dist/providers/search/index.d.ts +31 -0
  190. package/dist/providers/search/index.d.ts.map +1 -0
  191. package/dist/providers/search/index.js +75 -0
  192. package/dist/providers/search/index.js.map +1 -0
  193. package/dist/providers/search/serper.d.ts +14 -0
  194. package/dist/providers/search/serper.d.ts.map +1 -0
  195. package/dist/providers/search/serper.js +87 -0
  196. package/dist/providers/search/serper.js.map +1 -0
  197. package/dist/providers/search/types.d.ts +21 -0
  198. package/dist/providers/search/types.d.ts.map +1 -0
  199. package/dist/providers/search/types.js +5 -0
  200. package/dist/providers/search/types.js.map +1 -0
  201. package/dist/providers/store.d.ts +104 -0
  202. package/dist/providers/store.d.ts.map +1 -0
  203. package/dist/providers/store.js +171 -0
  204. package/dist/providers/store.js.map +1 -0
  205. package/dist/providers/types.d.ts +7 -1
  206. package/dist/providers/types.d.ts.map +1 -1
  207. package/dist/providers/vertex-ai.d.ts +33 -0
  208. package/dist/providers/vertex-ai.d.ts.map +1 -0
  209. package/dist/providers/vertex-ai.js +407 -0
  210. package/dist/providers/vertex-ai.js.map +1 -0
  211. package/dist/tools/builtin/bash.d.ts.map +1 -1
  212. package/dist/tools/builtin/bash.js +2 -1
  213. package/dist/tools/builtin/bash.js.map +1 -1
  214. package/dist/tools/builtin/edit.d.ts.map +1 -1
  215. package/dist/tools/builtin/edit.js +2 -1
  216. package/dist/tools/builtin/edit.js.map +1 -1
  217. package/dist/tools/builtin/glob.d.ts.map +1 -1
  218. package/dist/tools/builtin/glob.js +2 -1
  219. package/dist/tools/builtin/glob.js.map +1 -1
  220. package/dist/tools/builtin/grep.d.ts.map +1 -1
  221. package/dist/tools/builtin/grep.js +2 -1
  222. package/dist/tools/builtin/grep.js.map +1 -1
  223. package/dist/tools/builtin/read.d.ts.map +1 -1
  224. package/dist/tools/builtin/read.js +2 -1
  225. package/dist/tools/builtin/read.js.map +1 -1
  226. package/dist/tools/builtin/todowrite.d.ts +15 -0
  227. package/dist/tools/builtin/todowrite.d.ts.map +1 -0
  228. package/dist/tools/builtin/todowrite.js +88 -0
  229. package/dist/tools/builtin/todowrite.js.map +1 -0
  230. package/dist/tools/builtin/webfetch.d.ts +20 -0
  231. package/dist/tools/builtin/webfetch.d.ts.map +1 -0
  232. package/dist/tools/builtin/webfetch.js +228 -0
  233. package/dist/tools/builtin/webfetch.js.map +1 -0
  234. package/dist/tools/builtin/websearch.d.ts +17 -0
  235. package/dist/tools/builtin/websearch.d.ts.map +1 -0
  236. package/dist/tools/builtin/websearch.js +87 -0
  237. package/dist/tools/builtin/websearch.js.map +1 -0
  238. package/dist/tools/builtin/write.d.ts.map +1 -1
  239. package/dist/tools/builtin/write.js +2 -1
  240. package/dist/tools/builtin/write.js.map +1 -1
  241. package/dist/tools/index.d.ts +18 -0
  242. package/dist/tools/index.d.ts.map +1 -1
  243. package/dist/tools/index.js +28 -2
  244. package/dist/tools/index.js.map +1 -1
  245. package/dist/tools/types.d.ts +41 -0
  246. package/dist/tools/types.d.ts.map +1 -1
  247. package/dist/tools/types.js +16 -0
  248. package/dist/tools/types.js.map +1 -1
  249. package/dist/tools/utils/ssrf.d.ts +18 -0
  250. package/dist/tools/utils/ssrf.d.ts.map +1 -0
  251. package/dist/tools/utils/ssrf.js +70 -0
  252. package/dist/tools/utils/ssrf.js.map +1 -0
  253. package/docs/README.md +5 -4
  254. package/docs/config-system-comparison.md +707 -0
  255. package/docs/memory-system.md +238 -0
  256. package/docs/permissions.md +368 -0
  257. package/docs/proposals/0001-web-fetch-tool.md +32 -2
  258. package/docs/proposals/0002-web-search-tool.md +59 -2
  259. package/docs/proposals/0005-todo-system.md +350 -85
  260. package/docs/proposals/0006-memory-system.md +11 -10
  261. package/docs/proposals/0012-ask-user-question.md +941 -206
  262. package/docs/proposals/0023-permission-enhancements.md +61 -2
  263. package/docs/proposals/0041-configuration-system.md +587 -0
  264. package/docs/proposals/0042-prompt-optimization.md +866 -0
  265. package/docs/proposals/README.md +8 -6
  266. package/docs/providers.md +220 -0
  267. package/jest.config.js +26 -0
  268. package/package.json +14 -3
  269. package/src/agent/agent.ts +120 -18
  270. package/src/agent/types.ts +9 -1
  271. package/src/cli/components/App.tsx +369 -47
  272. package/src/cli/components/CommandSuggestions.tsx +3 -0
  273. package/src/cli/components/Header.tsx +11 -17
  274. package/src/cli/components/Logo.tsx +76 -9
  275. package/src/cli/components/Messages.tsx +146 -38
  276. package/src/cli/components/ModelSelector.tsx +169 -52
  277. package/src/cli/components/PermissionPrompt.tsx +388 -0
  278. package/src/cli/components/ProviderManager.tsx +534 -0
  279. package/src/cli/components/Spinner.tsx +138 -25
  280. package/src/cli/components/TodoList.tsx +54 -0
  281. package/src/cli/components/index.ts +6 -0
  282. package/src/cli/components/markdown.ts +157 -0
  283. package/src/cli/components/theme.ts +7 -0
  284. package/src/cli/index.tsx +76 -13
  285. package/src/config/index.ts +79 -4
  286. package/src/config/levels.test.ts +163 -0
  287. package/src/config/levels.ts +285 -0
  288. package/src/config/loader.test.ts +120 -0
  289. package/src/config/loader.ts +178 -0
  290. package/src/config/manager.test.ts +215 -0
  291. package/src/config/manager.ts +328 -40
  292. package/src/config/merger.test.ts +360 -0
  293. package/src/config/merger.ts +221 -0
  294. package/src/config/providers-config.ts +85 -0
  295. package/src/config/test-utils.ts +79 -0
  296. package/src/config/types.ts +186 -9
  297. package/src/memory/import-resolver.test.ts +117 -0
  298. package/src/memory/import-resolver.ts +149 -0
  299. package/src/memory/index.ts +11 -0
  300. package/src/memory/init-prompt.ts +113 -0
  301. package/src/memory/memory-manager.test.ts +198 -0
  302. package/src/memory/memory-manager.ts +716 -0
  303. package/src/memory/rules-parser.test.ts +182 -0
  304. package/src/memory/rules-parser.ts +82 -0
  305. package/src/memory/test-utils.ts +60 -0
  306. package/src/memory/types.ts +119 -0
  307. package/src/permissions/audit.ts +284 -0
  308. package/src/permissions/index.ts +20 -1
  309. package/src/permissions/manager.test.ts +260 -0
  310. package/src/permissions/manager.ts +592 -40
  311. package/src/permissions/persistence.test.ts +220 -0
  312. package/src/permissions/persistence.ts +301 -0
  313. package/src/permissions/prompt-matcher.test.ts +213 -0
  314. package/src/permissions/prompt-matcher.ts +472 -0
  315. package/src/permissions/types.ts +236 -8
  316. package/src/prompts/index.test.ts +279 -0
  317. package/src/prompts/index.ts +306 -0
  318. package/src/prompts/system/anthropic.txt +29 -0
  319. package/src/prompts/system/base.txt +124 -0
  320. package/src/prompts/system/gemini.txt +35 -0
  321. package/src/prompts/system/generic.txt +128 -0
  322. package/src/prompts/system/openai.txt +29 -0
  323. package/src/prompts/tools/bash.txt +60 -0
  324. package/src/prompts/tools/edit.txt +29 -0
  325. package/src/prompts/tools/glob.txt +35 -0
  326. package/src/prompts/tools/grep.txt +43 -0
  327. package/src/prompts/tools/read.txt +22 -0
  328. package/src/prompts/tools/todowrite.txt +71 -0
  329. package/src/prompts/tools/webfetch.txt +34 -0
  330. package/src/prompts/tools/websearch.txt +41 -0
  331. package/src/prompts/tools/write.txt +23 -0
  332. package/src/providers/gemini.ts +20 -4
  333. package/src/providers/index.ts +18 -3
  334. package/src/providers/registry.ts +198 -0
  335. package/src/providers/search/brave.ts +132 -0
  336. package/src/providers/search/exa.ts +217 -0
  337. package/src/providers/search/index.ts +79 -0
  338. package/src/providers/search/serper.ts +133 -0
  339. package/src/providers/search/types.ts +24 -0
  340. package/src/providers/store.ts +216 -0
  341. package/src/providers/types.ts +9 -1
  342. package/src/providers/vertex-ai.ts +594 -0
  343. package/src/tools/builtin/bash.ts +2 -1
  344. package/src/tools/builtin/edit.ts +2 -1
  345. package/src/tools/builtin/glob.ts +2 -1
  346. package/src/tools/builtin/grep.ts +2 -1
  347. package/src/tools/builtin/read.ts +2 -1
  348. package/src/tools/builtin/todowrite.ts +102 -0
  349. package/src/tools/builtin/webfetch.ts +261 -0
  350. package/src/tools/builtin/websearch.ts +103 -0
  351. package/src/tools/builtin/write.ts +2 -1
  352. package/src/tools/index.ts +28 -2
  353. package/src/tools/types.ts +32 -0
  354. package/src/tools/utils/ssrf.ts +79 -0
  355. package/tsconfig.json +1 -1
  356. package/CLAUDE.md +0 -70
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Spinner Component - Compact thinking animation (Claude Code style)
2
+ * Spinner Component - Vivid thinking animation
3
3
  */
4
- import { useState, useEffect } from 'react';
4
+ import { useState, useEffect, useMemo } from 'react';
5
5
  import { Box, Text } from 'ink';
6
6
  import InkSpinner from 'ink-spinner';
7
7
  import { colors } from './theme.js';
@@ -33,40 +33,153 @@ export function LoadingSpinner({ text = 'Loading...' }: SpinnerProps) {
33
33
  );
34
34
  }
35
35
 
36
+ // Thinking phrases that rotate during processing
37
+ const thinkingPhrases = [
38
+ 'Thinking',
39
+ 'Pondering',
40
+ 'Analyzing',
41
+ 'Processing',
42
+ 'Reasoning',
43
+ 'Contemplating',
44
+ 'Figuring out',
45
+ 'Working on it',
46
+ 'Almost there',
47
+ 'Crafting response',
48
+ ];
49
+
50
+ // Animation frames for different styles
51
+ const animations = {
52
+ // Brainwave animation
53
+ brainwave: ['🧠 ∿∿∿', '🧠∿ ∿∿', '🧠∿∿ ∿', '🧠∿∿∿ ', '🧠 ∿∿∿', '🧠∿ ∿∿'],
54
+ // Sparkle animation
55
+ sparkle: ['✨ ', ' ✨ ', ' ✨ ', ' ✨ ', ' ✨', ' ✨ ', ' ✨ ', ' ✨ '],
56
+ // DNA helix
57
+ dna: ['🔬 ⌬⌬⌬', '🔬⌬ ⌬⌬', '🔬⌬⌬ ⌬', '🔬⌬⌬⌬ ', '🔬 ⌬⌬⌬'],
58
+ // Pulse dots
59
+ pulse: ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'],
60
+ // Wave animation
61
+ wave: ['≋≈∼∽', '∽≋≈∼', '∼∽≋≈', '≈∼∽≋'],
62
+ // Bounce bar with gradient
63
+ bounceGradient: [
64
+ '█▓▒░ ',
65
+ ' █▓▒░ ',
66
+ ' █▓▒░ ',
67
+ ' █▓▒░ ',
68
+ ' █▓▒░',
69
+ ' ░▒▓█ ',
70
+ ' ░▒▓█ ',
71
+ ' ░▒▓█ ',
72
+ '░▒▓█ ',
73
+ ],
74
+ // Orbit animation
75
+ orbit: ['◐', '◓', '◑', '◒'],
76
+ // Loading bar with shimmer
77
+ shimmer: [
78
+ '▓▓▓▓▓░░░',
79
+ '░▓▓▓▓▓░░',
80
+ '░░▓▓▓▓▓░',
81
+ '░░░▓▓▓▓▓',
82
+ '░░░░▓▓▓▓',
83
+ '░░░▓▓▓▓▓',
84
+ '░░▓▓▓▓▓░',
85
+ '░▓▓▓▓▓░░',
86
+ ],
87
+ };
88
+
89
+ type AnimationType = keyof typeof animations;
90
+ const animationTypes = Object.keys(animations) as AnimationType[];
91
+
92
+ // Format elapsed time
93
+ function formatElapsed(ms: number): string {
94
+ const secs = Math.floor(ms / 1000);
95
+ if (secs < 60) return `${secs}s`;
96
+ const mins = Math.floor(secs / 60);
97
+ const remainSecs = secs % 60;
98
+ return `${mins}m ${remainSecs}s`;
99
+ }
100
+
101
+ // Format token count
102
+ function formatTokens(count: number): string {
103
+ if (count >= 1000) {
104
+ return `${(count / 1000).toFixed(1)}k`;
105
+ }
106
+ return `${count}`;
107
+ }
108
+
109
+ interface ProgressBarProps {
110
+ startTime?: number;
111
+ tokenCount?: number;
112
+ isThinking?: boolean;
113
+ }
114
+
36
115
  /**
37
116
  * Progress bar animation for processing state
38
- * Bouncing ball with trail effect
117
+ * Claude Code style with time, tokens, and thinking status
39
118
  */
40
- export function ProgressBar() {
119
+ export function ProgressBar({ startTime, tokenCount = 0, isThinking = false }: ProgressBarProps) {
41
120
  const [frame, setFrame] = useState(0);
121
+ const [phraseIndex, setPhraseIndex] = useState(0);
122
+ const [elapsed, setElapsed] = useState(0);
42
123
 
43
- useEffect(() => {
44
- const timer = setInterval(() => {
45
- setFrame((f) => (f + 1) % 14);
46
- }, 100);
47
- return () => clearInterval(timer);
124
+ // Pick a random animation style on mount
125
+ const animStyle = useMemo(() => {
126
+ const randomIndex = Math.floor(Math.random() * animationTypes.length);
127
+ return animationTypes[randomIndex];
48
128
  }, []);
49
129
 
50
- // Bouncing ball animation: ball moves left-right with trail
51
- const width = 7;
52
- // Frame 0-6: left to right, 7-13: right to left
53
- const pos = frame < 7 ? frame : 13 - frame;
54
-
55
- let bar = '';
56
- for (let i = 0; i < width; i++) {
57
- if (i === pos) {
58
- bar += '●';
59
- } else if (i === pos - 1 || i === pos + 1) {
60
- bar += '○';
61
- } else {
62
- bar += '·';
63
- }
130
+ const currentAnim = animations[animStyle];
131
+
132
+ useEffect(() => {
133
+ // Fast animation update
134
+ const animTimer = setInterval(() => {
135
+ setFrame((f) => (f + 1) % currentAnim.length);
136
+ }, 120);
137
+
138
+ // Slower phrase rotation (every 2.5 seconds)
139
+ const phraseTimer = setInterval(() => {
140
+ setPhraseIndex((p) => (p + 1) % thinkingPhrases.length);
141
+ }, 2500);
142
+
143
+ // Update elapsed time every second
144
+ const elapsedTimer = setInterval(() => {
145
+ if (startTime) {
146
+ setElapsed(Date.now() - startTime);
147
+ }
148
+ }, 1000);
149
+
150
+ return () => {
151
+ clearInterval(animTimer);
152
+ clearInterval(phraseTimer);
153
+ clearInterval(elapsedTimer);
154
+ };
155
+ }, [currentAnim.length, startTime]);
156
+
157
+ const animFrame = currentAnim[frame];
158
+ const phrase = thinkingPhrases[phraseIndex];
159
+
160
+ // Animated ellipsis
161
+ const ellipsis = '.'.repeat((frame % 3) + 1).padEnd(3, ' ');
162
+
163
+ // Build status parts
164
+ const parts: string[] = [];
165
+ if (startTime && elapsed > 0) {
166
+ parts.push(formatElapsed(elapsed));
167
+ }
168
+ if (tokenCount > 0) {
169
+ parts.push(`↓ ${formatTokens(tokenCount)} tokens`);
64
170
  }
171
+ if (isThinking) {
172
+ parts.push('thinking');
173
+ }
174
+
175
+ const statusText = parts.length > 0 ? ` · ${parts.join(' · ')}` : '';
65
176
 
66
177
  return (
67
178
  <Box>
68
- <Text color={colors.brand}>{bar}</Text>
69
- <Text color={colors.textMuted}> esc to stop</Text>
179
+ <Text color={colors.brand}>{animFrame}</Text>
180
+ <Text color={colors.textSecondary}> {phrase}</Text>
181
+ <Text color={colors.textMuted}>{ellipsis}</Text>
182
+ <Text color={colors.textMuted}>(esc to stop{statusText})</Text>
70
183
  </Box>
71
184
  );
72
185
  }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * TodoList Component - Display current todos in CLI
3
+ * Design: Minimal, clean, status-driven with clear visual hierarchy
4
+ */
5
+ import { Box, Text } from 'ink';
6
+ import { colors } from './theme.js';
7
+ import type { TodoItem } from '../../tools/types.js';
8
+
9
+ interface TodoListProps {
10
+ todos: TodoItem[];
11
+ }
12
+
13
+ export function TodoList({ todos }: TodoListProps) {
14
+ if (todos.length === 0) return null;
15
+
16
+ const completed = todos.filter((t) => t.status === 'completed').length;
17
+ const total = todos.length;
18
+
19
+ return (
20
+ <Box flexDirection="column" marginTop={1} marginLeft={2}>
21
+ {/* Header with count */}
22
+ <Text color={colors.textMuted}>
23
+ Tasks {completed}/{total}
24
+ </Text>
25
+ {/* Task list */}
26
+ {todos.map((todo, i) => {
27
+ const isCompleted = todo.status === 'completed';
28
+ const isInProgress = todo.status === 'in_progress';
29
+
30
+ // Status indicators: [x] done, [>] active, [ ] pending
31
+ let bracket: string;
32
+ let bracketColor: string;
33
+
34
+ if (isCompleted) {
35
+ bracket = '[x]';
36
+ bracketColor = colors.success;
37
+ } else if (isInProgress) {
38
+ bracket = '[>]';
39
+ bracketColor = colors.warning;
40
+ } else {
41
+ bracket = '[ ]';
42
+ bracketColor = colors.textMuted;
43
+ }
44
+
45
+ return (
46
+ <Text key={i} dimColor={isCompleted}>
47
+ <Text color={bracketColor}>{bracket}</Text>
48
+ <Text strikethrough={isCompleted}> {todo.content}</Text>
49
+ </Text>
50
+ );
51
+ })}
52
+ </Box>
53
+ );
54
+ }
@@ -19,3 +19,9 @@ export { PromptInput, ConfirmPrompt } from './Input.js';
19
19
  export { colors, icons } from './theme.js';
20
20
  export { ModelSelector } from './ModelSelector.js';
21
21
  export { CommandSuggestions, COMMANDS, getFilteredCommands } from './CommandSuggestions.js';
22
+ export {
23
+ PermissionPrompt,
24
+ SimpleConfirmPrompt,
25
+ PermissionRulesDisplay,
26
+ PermissionAuditDisplay,
27
+ } from './PermissionPrompt.js';
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Simple Terminal Markdown Renderer
3
+ * Uses marked for parsing, chalk for ANSI colors
4
+ */
5
+
6
+ import { marked, type Tokens, type RendererObject, type Token } from 'marked';
7
+ import chalk from 'chalk';
8
+
9
+ // Helper type for renderer context with parser access
10
+ type RendererContext = {
11
+ parser?: {
12
+ parseInline(tokens: Token[]): string;
13
+ parse(tokens: Token[]): string;
14
+ }
15
+ };
16
+
17
+ // Helper to parse inline tokens from renderer context
18
+ function parseInline(ctx: unknown, tokens: Token[], fallback: string): string {
19
+ const context = ctx as RendererContext;
20
+ return context.parser?.parseInline(tokens) ?? fallback;
21
+ }
22
+
23
+ // Helper to parse block tokens (like list item content)
24
+ function parseTokens(ctx: unknown, tokens: Token[], fallback: string): string {
25
+ const context = ctx as RendererContext;
26
+ // For list items, tokens may contain text tokens with nested inline tokens
27
+ // Use parse() for block-level token arrays
28
+ return context.parser?.parse(tokens).trim() ?? fallback;
29
+ }
30
+
31
+ // Custom terminal renderer
32
+ const terminalRenderer: RendererObject = {
33
+ // Headings: colored and bold
34
+ heading(token: Tokens.Heading): string {
35
+ const colors = [
36
+ chalk.bold.magenta, // h1
37
+ chalk.bold.cyan, // h2
38
+ chalk.bold.green, // h3
39
+ chalk.bold.yellow, // h4+
40
+ ];
41
+ const colorFn = colors[Math.min(token.depth - 1, 3)];
42
+ const content = parseInline(this, token.tokens, token.text);
43
+ return '\n' + colorFn(content) + '\n\n';
44
+ },
45
+
46
+ // Paragraphs - must parse inline tokens for bold/italic/etc
47
+ paragraph(token: Tokens.Paragraph): string {
48
+ const content = parseInline(this, token.tokens, token.text);
49
+ return content + '\n\n';
50
+ },
51
+
52
+ // Bold text
53
+ strong(token: Tokens.Strong): string {
54
+ const content = parseInline(this, token.tokens, token.text);
55
+ return chalk.bold(content);
56
+ },
57
+
58
+ // Italic text
59
+ em(token: Tokens.Em): string {
60
+ const content = parseInline(this, token.tokens, token.text);
61
+ return chalk.italic(content);
62
+ },
63
+
64
+ // Inline code
65
+ codespan({ text }: Tokens.Codespan): string {
66
+ return chalk.yellow('`' + text + '`');
67
+ },
68
+
69
+ // Code blocks - clean format without ``` markers
70
+ code({ text, lang }: Tokens.Code): string {
71
+ const langHeader = lang ? chalk.dim(` [${lang}]`) + '\n' : '';
72
+ const lines = text.split('\n').map(line => chalk.cyan(' ' + line)).join('\n');
73
+ return '\n' + langHeader + lines + '\n\n';
74
+ },
75
+
76
+ // List - parse block tokens for each item (they may contain nested text+inline tokens)
77
+ list(token: Tokens.List): string {
78
+ const result = token.items.map((item, i) => {
79
+ const bullet = token.ordered ? chalk.dim(`${i + 1}.`) : chalk.dim('•');
80
+ const content = parseTokens(this, item.tokens, item.text);
81
+ return ` ${bullet} ${content}`;
82
+ }).join('\n');
83
+ return result + '\n\n';
84
+ },
85
+
86
+ // List item - use block parser since items contain text tokens with nested inline
87
+ listitem(token: Tokens.ListItem): string {
88
+ return parseTokens(this, token.tokens, token.text);
89
+ },
90
+
91
+ // Links
92
+ link(token: Tokens.Link): string {
93
+ const content = parseInline(this, token.tokens, token.text);
94
+ return chalk.blue.underline(content) + chalk.dim(` (${token.href})`);
95
+ },
96
+
97
+ // Blockquotes
98
+ blockquote(token: Tokens.Blockquote): string {
99
+ const text = token.text.trim();
100
+ const lines = text.split('\n').map(line =>
101
+ chalk.dim('│ ') + chalk.italic(line)
102
+ ).join('\n');
103
+ return '\n' + lines + '\n\n';
104
+ },
105
+
106
+ // Horizontal rule
107
+ hr(): string {
108
+ return '\n' + chalk.dim('─'.repeat(40)) + '\n\n';
109
+ },
110
+
111
+ // Line break
112
+ br(): string {
113
+ return '\n';
114
+ },
115
+
116
+ // Delete/strikethrough
117
+ del(token: Tokens.Del): string {
118
+ const content = parseInline(this, token.tokens, token.text);
119
+ return chalk.strikethrough(content);
120
+ },
121
+
122
+ // Plain text - may contain nested inline tokens (like in list items)
123
+ text(token: Tokens.Text | Tokens.Escape): string {
124
+ // Tokens.Text can have nested tokens array with inline formatting
125
+ if ('tokens' in token && token.tokens && token.tokens.length > 0) {
126
+ return parseInline(this, token.tokens, token.text);
127
+ }
128
+ return token.text ?? '';
129
+ },
130
+
131
+ // HTML (strip tags)
132
+ html(token: Tokens.HTML | Tokens.Tag): string {
133
+ const text = 'text' in token ? token.text : '';
134
+ return text.replace(/<[^>]*>/g, '');
135
+ },
136
+ };
137
+
138
+ // Configure marked with custom renderer
139
+ marked.use({ renderer: terminalRenderer });
140
+
141
+ /**
142
+ * Render markdown text to terminal-formatted string
143
+ */
144
+ export function renderMarkdown(text: string): string {
145
+ try {
146
+ const result = marked.parse(text);
147
+ // marked.parse can return string or Promise<string>
148
+ if (typeof result === 'string') {
149
+ return result.trim();
150
+ }
151
+ // If async, return original text (shouldn't happen with sync renderer)
152
+ return text;
153
+ } catch {
154
+ // On error, return original text
155
+ return text;
156
+ }
157
+ }
@@ -14,6 +14,7 @@ export const colors = {
14
14
  textMuted: '#64748B', // Slate 500
15
15
  tool: '#C084FC', // Purple 400
16
16
  separator: '#1E293B', // Slate 800
17
+ inputBg: '#111827', // Gray 900 - subtle background for user input
17
18
  };
18
19
 
19
20
  export const icons = {
@@ -29,8 +30,14 @@ export const icons = {
29
30
  info: 'ℹ',
30
31
  // Tools
31
32
  tool: '⚡', // Lightning for tools
33
+ fetch: '●', // Filled circle for fetch (Claude Code style)
32
34
  arrow: '→',
33
35
  // UI
34
36
  thinking: '✱', // Star for thinking state
35
37
  cursor: '▋',
38
+ // Selection
39
+ radio: '●', // Filled radio for selected
40
+ radioEmpty: '○', // Empty radio for unselected
41
+ // Tree connectors
42
+ treeEnd: '└', // Tree end connector for tool results
36
43
  };
package/src/cli/index.tsx CHANGED
@@ -9,7 +9,7 @@ import { render } from 'ink';
9
9
  import React from 'react';
10
10
  import { App } from './components/App.js';
11
11
  import type { AgentConfig } from '../agent/types.js';
12
- import { SettingsManager, type Settings } from '../config/index.js';
12
+ import { SettingsManager, ProvidersConfigManager, type Settings, type ProviderName } from '../config/index.js';
13
13
 
14
14
  // ============================================================================
15
15
  // Proxy Setup
@@ -31,12 +31,17 @@ async function setupProxy(): Promise<void> {
31
31
  // ============================================================================
32
32
  // Configuration
33
33
  // ============================================================================
34
- function detectConfig(settings: Settings): AgentConfig {
35
- let provider: 'openai' | 'anthropic' | 'gemini' = 'gemini';
34
+ function detectConfig(settings: Settings, providersConfig: ProvidersConfigManager): AgentConfig {
35
+ let provider: ProviderName = 'gemini';
36
36
  let model = 'gemini-2.0-flash';
37
37
 
38
+ // Check for explicit Vertex AI enablement first (highest priority for auto-detect)
39
+ if (process.env.GENCODE_USE_VERTEX === '1' || process.env.CLAUDE_CODE_USE_VERTEX === '1') {
40
+ provider = 'vertex-ai';
41
+ model = process.env.VERTEX_AI_MODEL ?? 'claude-sonnet-4-5@20250929';
42
+ }
38
43
  // Auto-detect from API keys
39
- if (process.env.ANTHROPIC_API_KEY) {
44
+ else if (process.env.ANTHROPIC_API_KEY) {
40
45
  provider = 'anthropic';
41
46
  model = 'claude-sonnet-4-20250514';
42
47
  } else if (process.env.OPENAI_API_KEY) {
@@ -49,7 +54,7 @@ function detectConfig(settings: Settings): AgentConfig {
49
54
 
50
55
  // Override from env vars
51
56
  if (process.env.GENCODE_PROVIDER) {
52
- provider = process.env.GENCODE_PROVIDER as 'openai' | 'anthropic' | 'gemini';
57
+ provider = process.env.GENCODE_PROVIDER as ProviderName;
53
58
  }
54
59
  if (process.env.GENCODE_MODEL) {
55
60
  model = process.env.GENCODE_MODEL;
@@ -61,6 +66,13 @@ function detectConfig(settings: Settings): AgentConfig {
61
66
  }
62
67
  if (settings.model) {
63
68
  model = settings.model;
69
+ // Auto-infer provider from model using providers.json (if not explicitly set)
70
+ if (!settings.provider) {
71
+ const inferredProvider = providersConfig.inferProvider(model);
72
+ if (inferredProvider) {
73
+ provider = inferredProvider;
74
+ }
75
+ }
64
76
  }
65
77
 
66
78
  return {
@@ -76,10 +88,21 @@ function detectConfig(settings: Settings): AgentConfig {
76
88
  // ============================================================================
77
89
  function parseArgs() {
78
90
  const args = process.argv.slice(2);
91
+
92
+ // Extract prompt value from -p "message" or --prompt "message"
93
+ let prompt: string | undefined;
94
+ for (let i = 0; i < args.length; i++) {
95
+ if ((args[i] === '-p' || args[i] === '--prompt') && args[i + 1]) {
96
+ prompt = args[i + 1];
97
+ break;
98
+ }
99
+ }
100
+
79
101
  return {
80
102
  continue: args.includes('-c') || args.includes('--continue'),
81
103
  resume: args.includes('-r') || args.includes('--resume'),
82
104
  help: args.includes('-h') || args.includes('--help'),
105
+ prompt,
83
106
  };
84
107
  }
85
108
 
@@ -90,17 +113,47 @@ function printUsage(): void {
90
113
  console.log(' Usage: gencode [options]');
91
114
  console.log();
92
115
  console.log(' Options:');
93
- console.log(' -c, --continue Resume the most recent session');
94
- console.log(' -r, --resume Select a session interactively');
95
- console.log(' -h, --help Show this help');
116
+ console.log(' -c, --continue Resume the most recent session');
117
+ console.log(' -r, --resume Select a session interactively');
118
+ console.log(' -p, --prompt <msg> Run a single prompt (non-interactive)');
119
+ console.log(' -h, --help Show this help');
96
120
  console.log();
97
121
  console.log(' Examples:');
98
- console.log(' gencode Start new session');
99
- console.log(' gencode -c Continue last session');
100
- console.log(' gencode -r Pick a session');
122
+ console.log(' gencode Start new session');
123
+ console.log(' gencode -c Continue last session');
124
+ console.log(' gencode -r Pick a session');
125
+ console.log(' gencode -p "2+2" Run single prompt');
101
126
  console.log();
102
127
  }
103
128
 
129
+ // ============================================================================
130
+ // Non-interactive mode
131
+ // ============================================================================
132
+ async function runNonInteractive(prompt: string, config: AgentConfig): Promise<void> {
133
+ const { Agent } = await import('../agent/agent.js');
134
+
135
+ const agent = new Agent(config);
136
+
137
+ let response = '';
138
+ for await (const event of agent.run(prompt)) {
139
+ switch (event.type) {
140
+ case 'text':
141
+ response += event.text;
142
+ break;
143
+ case 'tool_start':
144
+ console.error(`[tool] ${event.name}`);
145
+ break;
146
+ case 'error':
147
+ console.error(`[error] ${event.error.message}`);
148
+ break;
149
+ case 'done':
150
+ break;
151
+ }
152
+ }
153
+
154
+ console.log(response);
155
+ }
156
+
104
157
  // ============================================================================
105
158
  // Main
106
159
  // ============================================================================
@@ -114,11 +167,20 @@ async function main() {
114
167
 
115
168
  await setupProxy();
116
169
 
117
- // Load saved settings
170
+ // Load saved settings and providers config
118
171
  const settingsManager = new SettingsManager();
119
172
  const settings = await settingsManager.load();
120
173
 
121
- const config = detectConfig(settings);
174
+ const providersConfig = new ProvidersConfigManager();
175
+ await providersConfig.load();
176
+
177
+ const config = detectConfig(settings, providersConfig);
178
+
179
+ // Non-interactive mode with -p flag
180
+ if (args.prompt) {
181
+ await runNonInteractive(args.prompt, config);
182
+ return;
183
+ }
122
184
 
123
185
  // Render the Ink app
124
186
  render(
@@ -126,6 +188,7 @@ async function main() {
126
188
  config={config}
127
189
  settingsManager={settingsManager}
128
190
  resumeLatest={args.continue}
191
+ permissionSettings={settings.permissions}
129
192
  />
130
193
  );
131
194
  }
@@ -1,7 +1,82 @@
1
1
  /**
2
- * Config Module Exports
2
+ * Configuration Module - Multi-level configuration system (Claude Code compatible)
3
+ *
4
+ * This module provides a hierarchical configuration system that:
5
+ * - Supports multiple levels: user, project, local, managed
6
+ * - Merges .gencode and .claude directories at each level (gencode wins)
7
+ * - Supports GENCODE_CONFIG_DIRS environment variable for extra config dirs
8
+ * - Enforces managed settings that cannot be overridden
3
9
  */
4
10
 
5
- export { SettingsManager } from './manager.js';
6
- export type { Settings, SettingsManagerOptions, ProviderName } from './types.js';
7
- export { DEFAULT_SETTINGS_DIR, SETTINGS_FILE_NAME } from './types.js';
11
+ // Core types
12
+ export type {
13
+ Settings,
14
+ SettingsManagerOptions,
15
+ ProviderName,
16
+ PermissionRules,
17
+ ConfigLevelType,
18
+ ConfigLevel,
19
+ ConfigSource,
20
+ MergedConfig,
21
+ ProvidersConfig,
22
+ ProviderConnection,
23
+ CachedModel,
24
+ ProviderModels,
25
+ } from './types.js';
26
+
27
+ // Constants
28
+ export {
29
+ DEFAULT_SETTINGS_DIR,
30
+ PROJECT_SETTINGS_DIR,
31
+ FALLBACK_SETTINGS_DIR,
32
+ FALLBACK_PROJECT_DIR,
33
+ SETTINGS_FILE_NAME,
34
+ SETTINGS_LOCAL_FILE_NAME,
35
+ MANAGED_SETTINGS_FILE_NAME,
36
+ PROVIDERS_FILE_NAME,
37
+ GENCODE_DIR,
38
+ CLAUDE_DIR,
39
+ USER_GENCODE_DIR,
40
+ USER_CLAUDE_DIR,
41
+ GENCODE_CONFIG_DIRS_ENV,
42
+ getManagedPaths,
43
+ } from './types.js';
44
+
45
+ // Configuration levels
46
+ export {
47
+ findProjectRoot,
48
+ parseExtraConfigDirs,
49
+ getConfigLevels,
50
+ getPrimarySettingsDir,
51
+ getSettingsFilePath,
52
+ type ConfigPathInfo,
53
+ type ResolvedLevel,
54
+ } from './levels.js';
55
+
56
+ // Configuration loader
57
+ export {
58
+ loadAllSources,
59
+ loadSourcesByLevel,
60
+ loadUserSettings,
61
+ loadProjectSettings,
62
+ loadManagedSettings,
63
+ getConfigInfo,
64
+ getExistingConfigFiles,
65
+ } from './loader.js';
66
+
67
+ // Configuration merger
68
+ export {
69
+ deepMerge,
70
+ mergeSettings,
71
+ extractManagedDeny,
72
+ applyManagedRestrictions,
73
+ mergeAllSources,
74
+ mergeWithCliArgs,
75
+ createMergeSummary,
76
+ } from './merger.js';
77
+
78
+ // Configuration managers
79
+ export { ConfigManager, SettingsManager } from './manager.js';
80
+
81
+ // Providers configuration
82
+ export { ProvidersConfigManager } from './providers-config.js';