octo-agent 0.11.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 (319) hide show
  1. checksums.yaml +7 -0
  2. data/.clacky/skills/commit/SKILL.md +423 -0
  3. data/.clacky/skills/gem-release/SKILL.md +199 -0
  4. data/.clacky/skills/gem-release/scripts/release.sh +304 -0
  5. data/.clacky/skills/oss-upload/SKILL.md +47 -0
  6. data/.octorules +106 -0
  7. data/.rspec +3 -0
  8. data/.rubocop.yml +8 -0
  9. data/CHANGELOG.md +76 -0
  10. data/CODE_OF_CONDUCT.md +132 -0
  11. data/CONTRIBUTING.md +92 -0
  12. data/Dockerfile +28 -0
  13. data/LICENSE.txt +22 -0
  14. data/POSITIONING.md +46 -0
  15. data/README.md +134 -0
  16. data/README_CN.md +134 -0
  17. data/Rakefile +34 -0
  18. data/benchmark/fixtures/sample_project/Gemfile +3 -0
  19. data/benchmark/fixtures/sample_project/lib/api_handler.rb +32 -0
  20. data/benchmark/fixtures/sample_project/lib/order_calculator.rb +23 -0
  21. data/benchmark/fixtures/sample_project/lib/user_renderer.rb +20 -0
  22. data/benchmark/fixtures/sample_project/spec/order_calculator_spec.rb +20 -0
  23. data/benchmark/results/EVALUATION_REPORT.md +165 -0
  24. data/benchmark/results/baseline_20260511_174424.json +128 -0
  25. data/benchmark/results/report_20260511_175256.json +271 -0
  26. data/benchmark/results/report_20260511_175444.json +271 -0
  27. data/benchmark/results/treatment_20260511_175103.json +130 -0
  28. data/benchmark/runner.rb +441 -0
  29. data/bin/octo +7 -0
  30. data/docs/agent-first-ui-design.md +77 -0
  31. data/docs/billing-system.md +318 -0
  32. data/docs/channel-architecture.md +235 -0
  33. data/docs/engineering-article.md +343 -0
  34. data/docs/session-skill-invocation.md +69 -0
  35. data/docs/time_machine_design.md +247 -0
  36. data/docs/ui2-architecture.md +124 -0
  37. data/homebrew/README.md +96 -0
  38. data/homebrew/openocto.rb +24 -0
  39. data/lib/octo/agent/hook_manager.rb +61 -0
  40. data/lib/octo/agent/llm_caller.rb +800 -0
  41. data/lib/octo/agent/memory_updater.rb +246 -0
  42. data/lib/octo/agent/message_compressor.rb +225 -0
  43. data/lib/octo/agent/message_compressor_helper.rb +869 -0
  44. data/lib/octo/agent/next_message_suggester.rb +215 -0
  45. data/lib/octo/agent/session_serializer.rb +685 -0
  46. data/lib/octo/agent/skill_auto_creator.rb +114 -0
  47. data/lib/octo/agent/skill_evolution.rb +61 -0
  48. data/lib/octo/agent/skill_manager.rb +466 -0
  49. data/lib/octo/agent/skill_reflector.rb +89 -0
  50. data/lib/octo/agent/system_prompt_builder.rb +101 -0
  51. data/lib/octo/agent/time_machine.rb +214 -0
  52. data/lib/octo/agent/tool_executor.rb +454 -0
  53. data/lib/octo/agent/tool_registry.rb +150 -0
  54. data/lib/octo/agent.rb +2180 -0
  55. data/lib/octo/agent_config.rb +989 -0
  56. data/lib/octo/agent_profile.rb +112 -0
  57. data/lib/octo/anthropic_stream_aggregator.rb +137 -0
  58. data/lib/octo/background_task_registry.rb +324 -0
  59. data/lib/octo/banner.rb +34 -0
  60. data/lib/octo/bedrock_stream_aggregator.rb +137 -0
  61. data/lib/octo/block_font.rb +331 -0
  62. data/lib/octo/cli.rb +968 -0
  63. data/lib/octo/client.rb +623 -0
  64. data/lib/octo/default_agents/SOUL.md +3 -0
  65. data/lib/octo/default_agents/USER.md +1 -0
  66. data/lib/octo/default_agents/base_prompt.md +66 -0
  67. data/lib/octo/default_agents/coding/profile.yml +2 -0
  68. data/lib/octo/default_agents/coding/system_prompt.md +67 -0
  69. data/lib/octo/default_agents/general/profile.yml +2 -0
  70. data/lib/octo/default_agents/general/system_prompt.md +16 -0
  71. data/lib/octo/default_parsers/doc_parser.rb +69 -0
  72. data/lib/octo/default_parsers/docx_parser.rb +188 -0
  73. data/lib/octo/default_parsers/pdf_parser.rb +120 -0
  74. data/lib/octo/default_parsers/pdf_parser_ocr.py +103 -0
  75. data/lib/octo/default_parsers/pdf_parser_plumber.py +62 -0
  76. data/lib/octo/default_parsers/pptx_parser.rb +140 -0
  77. data/lib/octo/default_parsers/xlsx_parser.rb +121 -0
  78. data/lib/octo/default_skills/browser-setup/SKILL.md +426 -0
  79. data/lib/octo/default_skills/channel-manager/SKILL.md +623 -0
  80. data/lib/octo/default_skills/channel-manager/dingtalk_setup.rb +191 -0
  81. data/lib/octo/default_skills/channel-manager/discord_setup.rb +199 -0
  82. data/lib/octo/default_skills/channel-manager/feishu_setup.rb +574 -0
  83. data/lib/octo/default_skills/channel-manager/import_lark_skills.rb +97 -0
  84. data/lib/octo/default_skills/channel-manager/install_feishu_skills.rb +105 -0
  85. data/lib/octo/default_skills/channel-manager/weixin_setup.rb +274 -0
  86. data/lib/octo/default_skills/code-explorer/SKILL.md +36 -0
  87. data/lib/octo/default_skills/cron-task-creator/SKILL.md +257 -0
  88. data/lib/octo/default_skills/cron-task-creator/evals/evals.json +38 -0
  89. data/lib/octo/default_skills/onboard/SKILL.md +578 -0
  90. data/lib/octo/default_skills/onboard/scripts/import_external_skills.rb +413 -0
  91. data/lib/octo/default_skills/onboard/scripts/install_builtin_skills.rb +97 -0
  92. data/lib/octo/default_skills/persist-memory/SKILL.md +59 -0
  93. data/lib/octo/default_skills/personal-website/SKILL.md +113 -0
  94. data/lib/octo/default_skills/personal-website/publish.rb +235 -0
  95. data/lib/octo/default_skills/product-help/SKILL.md +123 -0
  96. data/lib/octo/default_skills/product-help/docs/agent-config.md +74 -0
  97. data/lib/octo/default_skills/product-help/docs/best-practices.md +49 -0
  98. data/lib/octo/default_skills/product-help/docs/browser-tool.md +53 -0
  99. data/lib/octo/default_skills/product-help/docs/built-in-skills.md +43 -0
  100. data/lib/octo/default_skills/product-help/docs/cli-reference.md +82 -0
  101. data/lib/octo/default_skills/product-help/docs/create-your-first-skill.md +47 -0
  102. data/lib/octo/default_skills/product-help/docs/faq.md +98 -0
  103. data/lib/octo/default_skills/product-help/docs/how-to-use-a-skill.md +58 -0
  104. data/lib/octo/default_skills/product-help/docs/installation.md +59 -0
  105. data/lib/octo/default_skills/product-help/docs/memory-system.md +61 -0
  106. data/lib/octo/default_skills/product-help/docs/octorules.md +62 -0
  107. data/lib/octo/default_skills/product-help/docs/session-management.md +63 -0
  108. data/lib/octo/default_skills/product-help/docs/skill-basics.md +55 -0
  109. data/lib/octo/default_skills/product-help/docs/skill-frontmatter.md +61 -0
  110. data/lib/octo/default_skills/product-help/docs/web-server.md +49 -0
  111. data/lib/octo/default_skills/product-help/docs/what-is-octo.md +37 -0
  112. data/lib/octo/default_skills/product-help/docs/windows-installation.md +36 -0
  113. data/lib/octo/default_skills/product-help/docs/writing-tips.md +53 -0
  114. data/lib/octo/default_skills/recall-memory/SKILL.md +65 -0
  115. data/lib/octo/default_skills/skill-add/SKILL.md +59 -0
  116. data/lib/octo/default_skills/skill-add/scripts/install_from_zip.rb +295 -0
  117. data/lib/octo/default_skills/skill-creator/SKILL.md +602 -0
  118. data/lib/octo/default_skills/skill-creator/agents/analyzer.md +274 -0
  119. data/lib/octo/default_skills/skill-creator/agents/comparator.md +202 -0
  120. data/lib/octo/default_skills/skill-creator/agents/grader.md +223 -0
  121. data/lib/octo/default_skills/skill-creator/eval-viewer/generate_review.py +471 -0
  122. data/lib/octo/default_skills/skill-creator/eval-viewer/viewer.html +1325 -0
  123. data/lib/octo/default_skills/skill-creator/references/schemas.md +430 -0
  124. data/lib/octo/default_skills/skill-creator/scripts/__init__.py +0 -0
  125. data/lib/octo/default_skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
  126. data/lib/octo/default_skills/skill-creator/scripts/generate_report.py +326 -0
  127. data/lib/octo/default_skills/skill-creator/scripts/improve_description.py +310 -0
  128. data/lib/octo/default_skills/skill-creator/scripts/quick_validate.py +103 -0
  129. data/lib/octo/default_skills/skill-creator/scripts/run_eval.py +317 -0
  130. data/lib/octo/default_skills/skill-creator/scripts/run_loop.py +331 -0
  131. data/lib/octo/default_skills/skill-creator/scripts/utils.py +47 -0
  132. data/lib/octo/default_skills/skill-creator/scripts/validate_skill_frontmatter.rb +143 -0
  133. data/lib/octo/idle_compression_timer.rb +115 -0
  134. data/lib/octo/json_ui_controller.rb +204 -0
  135. data/lib/octo/message_format/anthropic.rb +409 -0
  136. data/lib/octo/message_format/bedrock.rb +361 -0
  137. data/lib/octo/message_format/open_ai.rb +222 -0
  138. data/lib/octo/message_history.rb +373 -0
  139. data/lib/octo/openai_stream_aggregator.rb +130 -0
  140. data/lib/octo/plain_ui_controller.rb +166 -0
  141. data/lib/octo/providers.rb +534 -0
  142. data/lib/octo/server/browser_manager.rb +397 -0
  143. data/lib/octo/server/channel/adapters/base.rb +82 -0
  144. data/lib/octo/server/channel/adapters/dingtalk/adapter.rb +314 -0
  145. data/lib/octo/server/channel/adapters/dingtalk/api_client.rb +391 -0
  146. data/lib/octo/server/channel/adapters/dingtalk/stream_client.rb +203 -0
  147. data/lib/octo/server/channel/adapters/discord/adapter.rb +229 -0
  148. data/lib/octo/server/channel/adapters/discord/api_client.rb +107 -0
  149. data/lib/octo/server/channel/adapters/discord/gateway_client.rb +270 -0
  150. data/lib/octo/server/channel/adapters/feishu/adapter.rb +320 -0
  151. data/lib/octo/server/channel/adapters/feishu/bot.rb +478 -0
  152. data/lib/octo/server/channel/adapters/feishu/file_processor.rb +36 -0
  153. data/lib/octo/server/channel/adapters/feishu/message_parser.rb +129 -0
  154. data/lib/octo/server/channel/adapters/feishu/ws_client.rb +423 -0
  155. data/lib/octo/server/channel/adapters/telegram/adapter.rb +375 -0
  156. data/lib/octo/server/channel/adapters/telegram/api_client.rb +205 -0
  157. data/lib/octo/server/channel/adapters/wecom/adapter.rb +148 -0
  158. data/lib/octo/server/channel/adapters/wecom/media_downloader.rb +115 -0
  159. data/lib/octo/server/channel/adapters/wecom/ws_client.rb +395 -0
  160. data/lib/octo/server/channel/adapters/weixin/adapter.rb +692 -0
  161. data/lib/octo/server/channel/adapters/weixin/api_client.rb +402 -0
  162. data/lib/octo/server/channel/channel_config.rb +178 -0
  163. data/lib/octo/server/channel/channel_manager.rb +468 -0
  164. data/lib/octo/server/channel/channel_ui_controller.rb +224 -0
  165. data/lib/octo/server/channel.rb +33 -0
  166. data/lib/octo/server/discover.rb +77 -0
  167. data/lib/octo/server/epipe_safe_io.rb +105 -0
  168. data/lib/octo/server/http_server.rb +3554 -0
  169. data/lib/octo/server/scheduler.rb +317 -0
  170. data/lib/octo/server/server_master.rb +325 -0
  171. data/lib/octo/server/session_registry.rb +431 -0
  172. data/lib/octo/server/web_ui_controller.rb +487 -0
  173. data/lib/octo/session_manager.rb +385 -0
  174. data/lib/octo/skill.rb +466 -0
  175. data/lib/octo/skill_loader.rb +328 -0
  176. data/lib/octo/tools/base.rb +118 -0
  177. data/lib/octo/tools/browser.rb +625 -0
  178. data/lib/octo/tools/edit.rb +165 -0
  179. data/lib/octo/tools/file_reader.rb +549 -0
  180. data/lib/octo/tools/glob.rb +162 -0
  181. data/lib/octo/tools/grep.rb +356 -0
  182. data/lib/octo/tools/invoke_skill.rb +96 -0
  183. data/lib/octo/tools/list_tasks.rb +54 -0
  184. data/lib/octo/tools/redo_task.rb +41 -0
  185. data/lib/octo/tools/request_user_feedback.rb +84 -0
  186. data/lib/octo/tools/security.rb +333 -0
  187. data/lib/octo/tools/terminal/output_cleaner.rb +63 -0
  188. data/lib/octo/tools/terminal/persistent_session.rb +268 -0
  189. data/lib/octo/tools/terminal/safe_rm.sh +106 -0
  190. data/lib/octo/tools/terminal/session_manager.rb +213 -0
  191. data/lib/octo/tools/terminal.rb +1828 -0
  192. data/lib/octo/tools/todo_manager.rb +374 -0
  193. data/lib/octo/tools/trash_manager.rb +388 -0
  194. data/lib/octo/tools/undo_task.rb +35 -0
  195. data/lib/octo/tools/web_fetch.rb +242 -0
  196. data/lib/octo/tools/web_search.rb +260 -0
  197. data/lib/octo/tools/write.rb +77 -0
  198. data/lib/octo/ui2/block_font.rb +10 -0
  199. data/lib/octo/ui2/components/base_component.rb +163 -0
  200. data/lib/octo/ui2/components/command_suggestions.rb +290 -0
  201. data/lib/octo/ui2/components/common_component.rb +96 -0
  202. data/lib/octo/ui2/components/inline_input.rb +226 -0
  203. data/lib/octo/ui2/components/input_area.rb +1338 -0
  204. data/lib/octo/ui2/components/message_component.rb +99 -0
  205. data/lib/octo/ui2/components/modal_component.rb +419 -0
  206. data/lib/octo/ui2/components/todo_area.rb +149 -0
  207. data/lib/octo/ui2/components/tool_component.rb +107 -0
  208. data/lib/octo/ui2/components/welcome_banner.rb +139 -0
  209. data/lib/octo/ui2/layout_manager.rb +807 -0
  210. data/lib/octo/ui2/line_editor.rb +363 -0
  211. data/lib/octo/ui2/markdown_renderer.rb +100 -0
  212. data/lib/octo/ui2/output_buffer.rb +370 -0
  213. data/lib/octo/ui2/progress_handle.rb +362 -0
  214. data/lib/octo/ui2/progress_indicator.rb +55 -0
  215. data/lib/octo/ui2/screen_buffer.rb +273 -0
  216. data/lib/octo/ui2/terminal_detector.rb +119 -0
  217. data/lib/octo/ui2/theme_manager.rb +85 -0
  218. data/lib/octo/ui2/themes/base_theme.rb +105 -0
  219. data/lib/octo/ui2/themes/hacker_theme.rb +62 -0
  220. data/lib/octo/ui2/themes/minimal_theme.rb +56 -0
  221. data/lib/octo/ui2/thinking_verbs.rb +26 -0
  222. data/lib/octo/ui2/ui_controller.rb +1625 -0
  223. data/lib/octo/ui2/view_renderer.rb +177 -0
  224. data/lib/octo/ui2.rb +40 -0
  225. data/lib/octo/ui_interface.rb +154 -0
  226. data/lib/octo/utils/arguments_parser.rb +191 -0
  227. data/lib/octo/utils/browser_detector.rb +195 -0
  228. data/lib/octo/utils/encoding.rb +92 -0
  229. data/lib/octo/utils/environment_detector.rb +140 -0
  230. data/lib/octo/utils/file_ignore_helper.rb +170 -0
  231. data/lib/octo/utils/file_processor.rb +601 -0
  232. data/lib/octo/utils/gitignore_parser.rb +154 -0
  233. data/lib/octo/utils/limit_stack.rb +152 -0
  234. data/lib/octo/utils/logger.rb +124 -0
  235. data/lib/octo/utils/login_shell.rb +72 -0
  236. data/lib/octo/utils/model_pricing.rb +646 -0
  237. data/lib/octo/utils/parser_manager.rb +165 -0
  238. data/lib/octo/utils/path_helper.rb +15 -0
  239. data/lib/octo/utils/scripts_manager.rb +59 -0
  240. data/lib/octo/utils/string_matcher.rb +158 -0
  241. data/lib/octo/utils/trash_directory.rb +112 -0
  242. data/lib/octo/utils/workspace_rules.rb +46 -0
  243. data/lib/octo/version.rb +5 -0
  244. data/lib/octo/web/app.css +7141 -0
  245. data/lib/octo/web/app.js +543 -0
  246. data/lib/octo/web/apple-touch-icon.png +0 -0
  247. data/lib/octo/web/auth.js +150 -0
  248. data/lib/octo/web/channels.js +276 -0
  249. data/lib/octo/web/datepicker.js +205 -0
  250. data/lib/octo/web/favicon.png +0 -0
  251. data/lib/octo/web/i18n.js +1073 -0
  252. data/lib/octo/web/icon-512.png +0 -0
  253. data/lib/octo/web/icon-dark.svg +25 -0
  254. data/lib/octo/web/icon.svg +29 -0
  255. data/lib/octo/web/index.html +871 -0
  256. data/lib/octo/web/marked.min.js +69 -0
  257. data/lib/octo/web/onboard.js +491 -0
  258. data/lib/octo/web/profile.js +442 -0
  259. data/lib/octo/web/sessions.js +4421 -0
  260. data/lib/octo/web/settings.js +913 -0
  261. data/lib/octo/web/sidebar.js +32 -0
  262. data/lib/octo/web/skills.js +885 -0
  263. data/lib/octo/web/tasks.js +297 -0
  264. data/lib/octo/web/theme.js +105 -0
  265. data/lib/octo/web/trash.js +343 -0
  266. data/lib/octo/web/vendor/hljs/highlight.min.js +1244 -0
  267. data/lib/octo/web/vendor/hljs/hljs-theme.css +95 -0
  268. data/lib/octo/web/vendor/katex/auto-render.min.js +1 -0
  269. data/lib/octo/web/vendor/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
  270. data/lib/octo/web/vendor/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  271. data/lib/octo/web/vendor/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  272. data/lib/octo/web/vendor/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  273. data/lib/octo/web/vendor/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  274. data/lib/octo/web/vendor/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
  275. data/lib/octo/web/vendor/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  276. data/lib/octo/web/vendor/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
  277. data/lib/octo/web/vendor/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
  278. data/lib/octo/web/vendor/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  279. data/lib/octo/web/vendor/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
  280. data/lib/octo/web/vendor/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  281. data/lib/octo/web/vendor/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  282. data/lib/octo/web/vendor/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  283. data/lib/octo/web/vendor/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
  284. data/lib/octo/web/vendor/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
  285. data/lib/octo/web/vendor/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
  286. data/lib/octo/web/vendor/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
  287. data/lib/octo/web/vendor/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
  288. data/lib/octo/web/vendor/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  289. data/lib/octo/web/vendor/katex/katex.min.css +1 -0
  290. data/lib/octo/web/vendor/katex/katex.min.js +1 -0
  291. data/lib/octo/web/version.js +449 -0
  292. data/lib/octo/web/weixin-qr.html +209 -0
  293. data/lib/octo/web/ws-dispatcher.js +357 -0
  294. data/lib/octo/web/ws.js +128 -0
  295. data/lib/octo.rb +145 -0
  296. data/scripts/build/build.sh +329 -0
  297. data/scripts/build/lib/apt.sh +56 -0
  298. data/scripts/build/lib/brew.sh +89 -0
  299. data/scripts/build/lib/colors.sh +17 -0
  300. data/scripts/build/lib/gem.sh +95 -0
  301. data/scripts/build/lib/mise.sh +125 -0
  302. data/scripts/build/lib/network.sh +157 -0
  303. data/scripts/build/lib/os.sh +57 -0
  304. data/scripts/build/lib/shell.sh +37 -0
  305. data/scripts/build/src/install.sh.cc +174 -0
  306. data/scripts/build/src/install_browser.sh.cc +101 -0
  307. data/scripts/build/src/install_full.sh.cc +290 -0
  308. data/scripts/build/src/install_rails_deps.sh.cc +145 -0
  309. data/scripts/build/src/install_system_deps.sh.cc +123 -0
  310. data/scripts/build/src/uninstall.sh.cc +101 -0
  311. data/scripts/install.ps1 +532 -0
  312. data/scripts/install.sh +567 -0
  313. data/scripts/install_browser.sh +479 -0
  314. data/scripts/install_full.sh +838 -0
  315. data/scripts/install_rails_deps.sh +746 -0
  316. data/scripts/install_system_deps.sh +518 -0
  317. data/scripts/uninstall.sh +287 -0
  318. data/sig/octo.rbs +4 -0
  319. metadata +614 -0
@@ -0,0 +1,290 @@
1
+ #!/bin/bash
2
+ # install_full.sh — OpenClacky full installer (macOS + Linux, with Homebrew)
3
+ # Generated from scripts/build/src/install_full.sh.cc — DO NOT EDIT DIRECTLY
4
+
5
+ set -e
6
+
7
+ BRAND_NAME=""
8
+ BRAND_COMMAND=""
9
+ RESTORE_MIRRORS=false
10
+
11
+ @include lib/colors.sh
12
+ @include lib/os.sh
13
+ @include lib/shell.sh
14
+ @include lib/network.sh
15
+ @include lib/brew.sh
16
+ @include lib/mise.sh
17
+ @include lib/gem.sh
18
+
19
+ # --------------------------------------------------------------------------
20
+ # CN mirror config — gem, npm (persisted to dotfiles)
21
+ # --------------------------------------------------------------------------
22
+ configure_cn_mirrors() {
23
+ [ "$USE_CN_MIRRORS" = true ] || return 0
24
+ print_step "Configuring CN mirrors (permanent)..."
25
+
26
+ # gem: ~/.gemrc
27
+ configure_gem_source
28
+
29
+ # npm: ~/.npmrc
30
+ local npmrc="$HOME/.npmrc"
31
+ if grep -q "${NPM_REGISTRY_URL}" "$npmrc" 2>/dev/null; then
32
+ print_success "npm registry already set → ${NPM_REGISTRY_URL}"
33
+ else
34
+ [ -f "$npmrc" ] && [ ! -f "$HOME/.npmrc_clackybak" ] && cp "$npmrc" "$HOME/.npmrc_clackybak"
35
+ if command_exists npm; then
36
+ npm config set registry "$NPM_REGISTRY_URL" 2>/dev/null && \
37
+ print_success "npm registry → ${NPM_REGISTRY_URL}"
38
+ else
39
+ echo "registry=${NPM_REGISTRY_URL}" >> "$npmrc"
40
+ print_success "npm registry → ${NPM_REGISTRY_URL} (pre-set)"
41
+ fi
42
+ fi
43
+
44
+ echo ""
45
+ }
46
+
47
+ restore_mirrors() {
48
+ print_step "Restoring original mirror settings..."
49
+
50
+ # gem
51
+ restore_gemrc
52
+
53
+ # npm
54
+ local npmrc="$HOME/.npmrc" npmrc_bak="$HOME/.npmrc_clackybak"
55
+ if [ -f "$npmrc_bak" ]; then
56
+ mv "$npmrc_bak" "$npmrc"; print_success "~/.npmrc restored from backup"
57
+ elif [ -f "$npmrc" ]; then
58
+ rm "$npmrc"; print_success "~/.npmrc removed"
59
+ else
60
+ print_info "~/.npmrc — nothing to restore"
61
+ fi
62
+
63
+ # mise node.mirror_url
64
+ local mise_bin=""
65
+ command_exists mise && mise_bin="mise"
66
+ [ -x "$HOME/.local/bin/mise" ] && mise_bin="$HOME/.local/bin/mise"
67
+ [ -n "$mise_bin" ] && "$mise_bin" settings unset node.mirror_url 2>/dev/null && \
68
+ print_success "mise node.mirror_url unset"
69
+
70
+ restore_homebrew_cn_mirrors
71
+
72
+ echo ""
73
+ print_success "Done. All mirror settings restored."
74
+ echo ""
75
+ }
76
+
77
+ # --------------------------------------------------------------------------
78
+ # Ruby check
79
+ # --------------------------------------------------------------------------
80
+ check_ruby() {
81
+ command_exists ruby || return 1
82
+ local ver; ver=$(ruby -e 'puts RUBY_VERSION' 2>/dev/null)
83
+ version_ge "$ver" "3.1.0" && { print_success "Ruby $ver — OK (>= 3.1.0)"; return 0; }
84
+ print_warning "Ruby $ver too old (need >= 3.1.0)"; return 1
85
+ }
86
+
87
+ # --------------------------------------------------------------------------
88
+ # macOS: Homebrew + build deps + Ruby via mise
89
+ # --------------------------------------------------------------------------
90
+ install_macos_dependencies() {
91
+ print_step "Installing macOS dependencies and Ruby..."
92
+ echo ""
93
+
94
+ configure_homebrew_cn_mirrors
95
+ ensure_homebrew || return 1
96
+
97
+ print_info "Installing build dependencies..."
98
+ brew install openssl@3 libyaml gmp || { print_error "Failed to install build deps"; return 1; }
99
+ print_success "Build dependencies installed"
100
+
101
+ ensure_mise || return 1
102
+ install_ruby_via_mise || return 1
103
+ check_ruby || { print_error "Ruby installation verification failed"; return 1; }
104
+ }
105
+
106
+ # --------------------------------------------------------------------------
107
+ # Linux (Ubuntu/Debian): apt mirror + build deps + Ruby via mise
108
+ # --------------------------------------------------------------------------
109
+ install_ubuntu_dependencies() {
110
+ print_step "Installing Ubuntu dependencies and Ruby..."
111
+ echo ""
112
+
113
+ if [ "$USE_CN_MIRRORS" = true ]; then
114
+ print_info "Configuring apt mirror (Aliyun)..."
115
+ local codename="${VERSION_CODENAME:-jammy}"
116
+ local components="main restricted universe multiverse"
117
+ local arch; arch=$(dpkg --print-architecture 2>/dev/null || uname -m)
118
+ if [ "$arch" = "arm64" ] || [ "$arch" = "aarch64" ]; then
119
+ local mirror_base="https://mirrors.aliyun.com/ubuntu-ports/"
120
+ else
121
+ local mirror_base="https://mirrors.aliyun.com/ubuntu/"
122
+ fi
123
+ sudo tee /etc/apt/sources.list > /dev/null <<EOF
124
+ deb ${mirror_base} ${codename} ${components}
125
+ deb ${mirror_base} ${codename}-updates ${components}
126
+ deb ${mirror_base} ${codename}-backports ${components}
127
+ deb ${mirror_base} ${codename}-security ${components}
128
+ EOF
129
+ print_success "Aliyun apt mirror configured"
130
+ fi
131
+
132
+ sudo apt update || { print_error "apt update failed"; return 1; }
133
+ sudo apt install -y build-essential libssl-dev libyaml-dev zlib1g-dev libgmp-dev git || \
134
+ { print_error "Build deps install failed"; return 1; }
135
+ print_success "Build dependencies installed"
136
+
137
+ # WSL: auto-trust Windows system32 to suppress mise warnings
138
+ export MISE_TRUSTED_CONFIG_PATHS="/mnt/c/Windows/system32"
139
+
140
+ ensure_mise || return 1
141
+ install_ruby_via_mise || return 1
142
+ check_ruby || { print_error "Ruby installation verification failed"; return 1; }
143
+ }
144
+
145
+ # --------------------------------------------------------------------------
146
+ # gem install openclacky
147
+ # --------------------------------------------------------------------------
148
+ install_via_gem() {
149
+ print_step "Installing via RubyGems..."
150
+ command_exists gem || { print_error "RubyGems not available"; return 1; }
151
+ command_exists ruby || { print_error "Ruby not available"; return 1; }
152
+
153
+ local ver; ver=$(ruby -e 'puts RUBY_VERSION' 2>/dev/null)
154
+ version_ge "$ver" "3.1.0" || { print_error "Ruby $ver too old (>= 3.1.0 required)"; return 1; }
155
+
156
+ print_info "Installing ${DISPLAY_NAME}..."
157
+ if gem install openclacky --no-document; then
158
+ print_success "${DISPLAY_NAME} installed!"
159
+ install_chrome_devtools_mcp
160
+ return 0
161
+ else
162
+ print_error "gem install failed"; return 1
163
+ fi
164
+ }
165
+
166
+ # --------------------------------------------------------------------------
167
+ # Optional: chrome-devtools-mcp (browser automation)
168
+ # --------------------------------------------------------------------------
169
+ install_chrome_devtools_mcp() {
170
+ print_step "Installing chrome-devtools-mcp..."
171
+
172
+ if ! command_exists npm; then
173
+ local mise_bin=""
174
+ command_exists mise && mise_bin="mise"
175
+ [ -x "$HOME/.local/bin/mise" ] && mise_bin="$HOME/.local/bin/mise"
176
+ if [ -n "$mise_bin" ]; then
177
+ "$mise_bin" install node@22 >/dev/null 2>&1 || true
178
+ "$mise_bin" use -g node@22 >/dev/null 2>&1 || true
179
+ eval "$($mise_bin activate bash 2>/dev/null)" 2>/dev/null || true
180
+ fi
181
+ fi
182
+
183
+ if ! command_exists npm; then
184
+ print_warning "npm not found — browser automation unavailable"
185
+ print_info "Install Node.js then run: npm install -g chrome-devtools-mcp"
186
+ return 0
187
+ fi
188
+
189
+ if npm install -g chrome-devtools-mcp >/dev/null 2>&1; then
190
+ print_success "chrome-devtools-mcp installed"
191
+ else
192
+ print_warning "chrome-devtools-mcp install failed"
193
+ print_info "Run manually: npm install -g chrome-devtools-mcp"
194
+ fi
195
+ }
196
+
197
+ # --------------------------------------------------------------------------
198
+ # Parse args
199
+ # --------------------------------------------------------------------------
200
+ parse_args() {
201
+ for arg in "$0" "$@"; do
202
+ case "$arg" in
203
+ --brand-name=*) BRAND_NAME="${arg#--brand-name=}" ;;
204
+ --command=*) BRAND_COMMAND="${arg#--command=}" ;;
205
+ --restore-mirrors) RESTORE_MIRRORS=true ;;
206
+ esac
207
+ done
208
+ DISPLAY_NAME="${BRAND_NAME:-OpenClacky}"
209
+ }
210
+
211
+ # --------------------------------------------------------------------------
212
+ # Brand setup
213
+ # --------------------------------------------------------------------------
214
+ setup_brand() {
215
+ [ -z "$BRAND_NAME" ] && return 0
216
+ local brand_file="$HOME/.clacky/brand.yml"
217
+ mkdir -p "$HOME/.clacky"
218
+ print_step "Configuring brand: $BRAND_NAME"
219
+ cat > "$brand_file" <<YAML
220
+ product_name: "${BRAND_NAME}"
221
+ package_name: "${BRAND_COMMAND}"
222
+ YAML
223
+ print_success "Brand config written to $brand_file"
224
+
225
+ if [ -n "$BRAND_COMMAND" ]; then
226
+ local bin_dir="$HOME/.local/bin"
227
+ mkdir -p "$bin_dir"
228
+ local wrapper="$bin_dir/$BRAND_COMMAND"
229
+ cat > "$wrapper" <<WRAPPER
230
+ #!/bin/sh
231
+ exec openclacky "\$@"
232
+ WRAPPER
233
+ chmod +x "$wrapper"
234
+ print_success "Wrapper installed: $wrapper"
235
+ case ":$PATH:" in
236
+ *":$bin_dir:"*) ;;
237
+ *) print_warning "Add to PATH: export PATH=\"\$HOME/.local/bin:\$PATH\"" ;;
238
+ esac
239
+ fi
240
+ }
241
+
242
+ # --------------------------------------------------------------------------
243
+ # Post-install info
244
+ # --------------------------------------------------------------------------
245
+ show_post_install_info() {
246
+ local cmd="${BRAND_COMMAND:-openclacky}"
247
+ echo ""
248
+ echo -e " ${GREEN}${DISPLAY_NAME} installed successfully!${NC}"
249
+ echo ""
250
+ echo " Reload your shell:"
251
+ echo -e " ${YELLOW}source ${SHELL_RC}${NC}"
252
+ echo ""
253
+ echo -e " ${GREEN}Web UI${NC} (recommended):"
254
+ echo " $cmd server → http://localhost:7070"
255
+ echo ""
256
+ echo -e " ${GREEN}Terminal${NC}:"
257
+ echo " $cmd"
258
+ echo ""
259
+ }
260
+
261
+ # --------------------------------------------------------------------------
262
+ # Main
263
+ # --------------------------------------------------------------------------
264
+ main() {
265
+ parse_args "$@"
266
+
267
+ [ "$RESTORE_MIRRORS" = true ] && { restore_mirrors; exit 0; }
268
+
269
+ echo ""
270
+ echo "${DISPLAY_NAME} Installation"
271
+ echo ""
272
+
273
+ detect_os
274
+ detect_shell
275
+ detect_network_region
276
+ configure_cn_mirrors
277
+
278
+ assert_supported_os "Please install Ruby manually and run: gem install openclacky"
279
+
280
+ if [ "$OS" = "macOS" ]; then
281
+ install_macos_dependencies || { print_error "Failed to install dependencies"; exit 1; }
282
+ elif [ "$OS" = "Linux" ]; then
283
+ install_ubuntu_dependencies || { print_error "Failed to install dependencies"; exit 1; }
284
+ fi
285
+
286
+ install_via_gem && { setup_brand; show_post_install_info; exit 0; }
287
+ print_error "Failed to install ${DISPLAY_NAME}"; exit 1
288
+ }
289
+
290
+ main "$@"
@@ -0,0 +1,145 @@
1
+ #!/bin/bash
2
+ # install_rails_deps.sh — install Ruby 3.3+ and Node.js 22+ via mise, and PostgreSQL for Rails development
3
+ # Generated from scripts/build/src/install_rails_deps.sh.cc — DO NOT EDIT DIRECTLY
4
+ #
5
+ # Usage:
6
+ # bash install_rails_deps.sh # install ruby + node + postgres
7
+ # bash install_rails_deps.sh ruby # ruby only
8
+ # bash install_rails_deps.sh node # node only
9
+ # bash install_rails_deps.sh postgres # postgres only
10
+
11
+ set -e
12
+
13
+ INSTALL_TARGET="${1:-all}" # all | ruby | node | postgres
14
+
15
+ @include lib/colors.sh
16
+ @include lib/os.sh
17
+ @include lib/shell.sh
18
+ @include lib/network.sh
19
+ @include lib/apt.sh
20
+ @include lib/brew.sh
21
+ @include lib/mise.sh
22
+ @include lib/gem.sh
23
+
24
+ # --------------------------------------------------------------------------
25
+ # Ruby: install via mise and configure gem source
26
+ # --------------------------------------------------------------------------
27
+ install_ruby() {
28
+ print_step "Installing Ruby via mise..."
29
+
30
+ # Install Ruby compile-time dependencies first
31
+ if is_macos; then
32
+ brew install openssl@3 libyaml gmp
33
+ elif is_linux_apt; then
34
+ sudo apt-get install -y \
35
+ rustc libssl-dev libyaml-dev zlib1g-dev libgmp-dev
36
+ fi
37
+
38
+ ensure_mise || return 1
39
+ install_ruby_via_mise || return 1
40
+
41
+ # Configure gem source for CN users
42
+ configure_gem_source
43
+
44
+ # Reinstall openclacky in the new Ruby environment
45
+ "${MISE_BIN:-mise}" exec -- gem install openclacky --no-document \
46
+ && print_success "openclacky reinstalled" \
47
+ || print_warning "Could not reinstall openclacky — run manually: gem install openclacky --no-document"
48
+ }
49
+
50
+ # --------------------------------------------------------------------------
51
+ # Node: install via mise and configure npm registry
52
+ # --------------------------------------------------------------------------
53
+ install_node() {
54
+ print_step "Installing Node.js via mise..."
55
+
56
+ ensure_mise || return 1
57
+ install_node_via_mise || return 1
58
+
59
+ if [ "$USE_CN_MIRRORS" = true ] && command_exists npm; then
60
+ npm config set registry "$NPM_REGISTRY_URL" 2>/dev/null || true
61
+ print_info "npm registry → ${NPM_REGISTRY_URL}"
62
+ fi
63
+ }
64
+
65
+ # --------------------------------------------------------------------------
66
+ # PostgreSQL: install server + client via brew (macOS) or apt (Linux/WSL)
67
+ # --------------------------------------------------------------------------
68
+ install_postgres() {
69
+ print_step "Installing PostgreSQL..."
70
+
71
+ if is_macos; then
72
+ ensure_homebrew || return 1
73
+ brew install postgresql
74
+ brew services start postgresql
75
+
76
+ elif is_linux_apt; then
77
+ setup_apt_mirror
78
+ sudo apt-get install -y postgresql libpq-dev \
79
+ libssl-dev libreadline-dev zlib1g-dev libyaml-dev libffi-dev
80
+ sudo systemctl enable --now postgresql || true
81
+ fi
82
+
83
+ print_success "PostgreSQL installed"
84
+ }
85
+
86
+ # --------------------------------------------------------------------------
87
+ # Main
88
+ # --------------------------------------------------------------------------
89
+ main() {
90
+ echo ""
91
+ echo "╔═══════════════════════════════════════════════════════════╗"
92
+ echo "║ ║"
93
+ echo "║ 🔧 Rails Dependencies Installer ║"
94
+ echo "║ ║"
95
+ echo "╚═══════════════════════════════════════════════════════════╝"
96
+ echo ""
97
+
98
+ detect_shell
99
+ detect_network_region
100
+
101
+ # On macOS, Homebrew is required — if missing, guide the user to install_full.sh
102
+ if is_macos && ! command_exists brew; then
103
+ local install_cmd
104
+ if [ "$USE_CN_MIRRORS" = true ]; then
105
+ install_cmd='/bin/bash -c "$(curl -sSL https://oss.1024code.com/scripts/install_full.sh)"'
106
+ else
107
+ install_cmd='/bin/bash -c "$(curl -sSL https://raw.githubusercontent.com/clacky-ai/openclacky/main/scripts/install_full.sh)"'
108
+ fi
109
+ echo ""
110
+ print_error "Homebrew is not installed — it is required to continue."
111
+ echo ""
112
+ echo " Homebrew installation requires your sudo password and interactive confirmation"
113
+ echo " — it cannot be run automatically by the AI agent."
114
+ echo ""
115
+ echo " Please open a new terminal window and run the full installer:"
116
+ echo ""
117
+ echo " ${install_cmd}"
118
+ echo ""
119
+ echo " This will install Homebrew, Ruby, Node.js, and all required dependencies."
120
+ echo " Once done, come back and try again."
121
+ echo ""
122
+ exit 1
123
+ fi
124
+
125
+ # Run system deps script if available
126
+ local sys_deps="$HOME/.clacky/scripts/install_system_deps.sh"
127
+ [ -f "$sys_deps" ] && { bash "$sys_deps" || print_warning "System deps install had warnings — continuing"; }
128
+
129
+ case "$INSTALL_TARGET" in
130
+ ruby) install_ruby || exit 1 ;;
131
+ node) install_node || exit 1 ;;
132
+ postgres) install_postgres || exit 1 ;;
133
+ *)
134
+ install_ruby || exit 1
135
+ install_node || exit 1
136
+ install_postgres || exit 1
137
+ ;;
138
+ esac
139
+
140
+ echo ""
141
+ print_success "Done. Please re-source your shell or open a new terminal if paths changed."
142
+ echo ""
143
+ }
144
+
145
+ main "$@"
@@ -0,0 +1,123 @@
1
+ #!/bin/bash
2
+ # install_system_deps.sh — install system-level build tools
3
+ # Generated from scripts/build/src/install_system_deps.sh.cc — DO NOT EDIT DIRECTLY
4
+ #
5
+ # macOS : Xcode Command Line Tools + Homebrew
6
+ # Linux : build-essential + python3 + git + curl (apt, Ubuntu/Debian)
7
+
8
+ set -e
9
+
10
+ @include lib/colors.sh
11
+ @include lib/os.sh
12
+ @include lib/shell.sh
13
+ @include lib/network.sh
14
+ @include lib/apt.sh
15
+ @include lib/brew.sh
16
+ _clt_installed() {
17
+ [ -e "/Library/Developer/CommandLineTools/usr/bin/git" ]
18
+ }
19
+
20
+ ensure_xcode_clt() {
21
+ print_step "Checking Xcode Command Line Tools..."
22
+ _clt_installed && { print_success "Xcode CLT already installed"; return 0; }
23
+
24
+ print_info "Xcode CLT not found — attempting headless install via softwareupdate..."
25
+ local clt_placeholder="/tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress"
26
+ touch "$clt_placeholder"
27
+
28
+ local clt_label
29
+ clt_label=$(softwareupdate -l 2>/dev/null \
30
+ | grep -B 1 -E 'Command Line Tools' \
31
+ | awk -F'*' '/^ *\*/ {print $2}' \
32
+ | sed -e 's/^ *Label: //' -e 's/^ *//' \
33
+ | sort -V | tail -n1)
34
+
35
+ local headless_ok=false
36
+ if [ -n "$clt_label" ]; then
37
+ print_info "Found package: $clt_label"
38
+ if softwareupdate -i "$clt_label" --agree-to-license 2>/dev/null; then
39
+ xcode-select --switch "/Library/Developer/CommandLineTools" 2>/dev/null || true
40
+ headless_ok=true
41
+ elif sudo -n softwareupdate -i "$clt_label" --agree-to-license 2>/dev/null; then
42
+ sudo xcode-select --switch "/Library/Developer/CommandLineTools" 2>/dev/null || true
43
+ headless_ok=true
44
+ fi
45
+ else
46
+ print_warning "softwareupdate could not find a CLT package"
47
+ fi
48
+
49
+ rm -f "$clt_placeholder"
50
+
51
+ if _clt_installed; then
52
+ print_success "Xcode CLT installed successfully"
53
+ return 0
54
+ fi
55
+
56
+ [ "$headless_ok" = false ] && print_warning "Headless install failed (sudo password required or package not found)"
57
+ print_error "Could not install Xcode CLT automatically."
58
+ echo ""
59
+ echo " Please run this command and re-run this script:"
60
+ echo " sudo xcode-select --install"
61
+ echo ""
62
+ return 1
63
+ }
64
+
65
+ ensure_linux_deps() {
66
+ print_step "Installing Linux build dependencies..."
67
+
68
+ detect_network_region
69
+ setup_apt_mirror
70
+ sudo apt-get install -y build-essential git curl python3
71
+ print_success "Dependencies installed"
72
+ }
73
+
74
+ # --------------------------------------------------------------------------
75
+ # Verify key tools are present
76
+ # --------------------------------------------------------------------------
77
+ verify_deps() {
78
+ print_step "Verifying installed tools..."
79
+ local failed=false
80
+ for tool in python3 git curl make; do
81
+ if command_exists "$tool"; then
82
+ print_success "$tool $(command -v "$tool")"
83
+ else
84
+ print_warning "$tool not found"
85
+ failed=true
86
+ fi
87
+ done
88
+ [ "$failed" = true ] && print_warning "Some tools still missing. You may need to restart your shell."
89
+ }
90
+
91
+ # --------------------------------------------------------------------------
92
+ # Main
93
+ # --------------------------------------------------------------------------
94
+ main() {
95
+ echo ""
96
+ echo "System Dependencies Setup"
97
+ echo "========================="
98
+
99
+ detect_os
100
+ print_info "OS: $OS"
101
+ [ "$OS" = "Linux" ] && print_info "Distro: $DISTRO"
102
+ echo ""
103
+
104
+ assert_supported_os
105
+
106
+ case "$OS" in
107
+ macOS)
108
+ detect_shell
109
+ ensure_xcode_clt || exit 1
110
+ detect_network_region
111
+ configure_homebrew_cn_mirrors
112
+ ensure_homebrew || exit 1
113
+ ;;
114
+ Linux) ensure_linux_deps || exit 1 ;;
115
+ esac
116
+
117
+ verify_deps
118
+ echo ""
119
+ print_success "Done. System dependencies are ready."
120
+ echo ""
121
+ }
122
+
123
+ main "$@"
@@ -0,0 +1,101 @@
1
+ #!/bin/bash
2
+ # uninstall.sh — OpenClacky uninstaller
3
+ # Generated from scripts/build/src/uninstall.sh.cc — DO NOT EDIT DIRECTLY
4
+
5
+ set -e
6
+
7
+ @include lib/colors.sh
8
+ @include lib/os.sh
9
+ @include lib/shell.sh
10
+ @include lib/gem.sh
11
+
12
+ # --------------------------------------------------------------------------
13
+ # Load brand config
14
+ # --------------------------------------------------------------------------
15
+ BRAND_NAME=""
16
+ BRAND_COMMAND=""
17
+ DISPLAY_NAME="OpenClacky"
18
+
19
+ load_brand() {
20
+ local brand_file="$HOME/.clacky/brand.yml"
21
+ [ -f "$brand_file" ] || return 0
22
+ BRAND_NAME=$(awk -F': ' '/^product_name:/{gsub(/^"|"$/, "", $2); gsub(/^ +| +$/, "", $2); print $2}' "$brand_file") || true
23
+ BRAND_COMMAND=$(awk -F': ' '/^package_name:/{gsub(/^"|"$/, "", $2); gsub(/^ +| +$/, "", $2); print $2}' "$brand_file") || true
24
+ [ -n "$BRAND_NAME" ] && DISPLAY_NAME="$BRAND_NAME"
25
+ }
26
+
27
+ check_installation() {
28
+ command_exists clacky || command_exists openclacky && return 0
29
+ [ -n "$BRAND_COMMAND" ] && command_exists "$BRAND_COMMAND" && return 0
30
+ return 1
31
+ }
32
+
33
+ uninstall_gem() {
34
+ command_exists gem || return 1
35
+ if gem list -i openclacky >/dev/null 2>&1; then
36
+ print_step "Uninstalling via RubyGems..."
37
+ gem uninstall openclacky -x
38
+ else
39
+ print_info "Gem 'openclacky' not found (already removed)"
40
+ fi
41
+ }
42
+
43
+ remove_brand() {
44
+ [ -z "$BRAND_COMMAND" ] && return 0
45
+ local clacky_bin dir
46
+ clacky_bin=$(command -v openclacky 2>/dev/null || true)
47
+ [ -z "$clacky_bin" ] && return 0
48
+ dir=$(dirname "$clacky_bin")
49
+ if [ -f "$dir/$BRAND_COMMAND" ]; then
50
+ rm -f "$dir/$BRAND_COMMAND"
51
+ print_success "Brand wrapper removed: $dir/$BRAND_COMMAND"
52
+ fi
53
+ }
54
+
55
+ remove_config() {
56
+ local config_dir="$HOME/.clacky"
57
+ [ -d "$config_dir" ] || return 0
58
+ print_warning "Configuration directory found: $config_dir"
59
+ read -r -p "Remove configuration files (including API keys)? [y/N] " reply
60
+ if [ "$reply" = "y" ] || [ "$reply" = "Y" ]; then
61
+ rm -rf "$config_dir"
62
+ print_success "Configuration removed"
63
+ else
64
+ print_info "Configuration preserved at: $config_dir"
65
+ fi
66
+ }
67
+
68
+ # --------------------------------------------------------------------------
69
+ # Main
70
+ # --------------------------------------------------------------------------
71
+ main() {
72
+ load_brand
73
+ detect_shell
74
+
75
+ echo ""
76
+ echo "╔═══════════════════════════════════════════════════════════╗"
77
+ echo "║ ║"
78
+ echo -e "║ 🗑️ ${DISPLAY_NAME} Uninstallation ║"
79
+ echo "║ ║"
80
+ echo "╚═══════════════════════════════════════════════════════════╝"
81
+ echo ""
82
+
83
+ if ! check_installation; then
84
+ print_warning "${DISPLAY_NAME} does not appear to be installed"
85
+ echo ""; exit 0
86
+ fi
87
+
88
+ remove_brand
89
+ uninstall_gem || print_warning "gem command not found, skipping gem uninstall"
90
+ print_success "${DISPLAY_NAME} uninstalled successfully"
91
+ restore_gemrc
92
+ restore_gem_home
93
+ remove_config
94
+
95
+ echo ""
96
+ print_success "Uninstallation complete!"
97
+ print_info "Thank you for using ${DISPLAY_NAME} 👋"
98
+ echo ""
99
+ }
100
+
101
+ main