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.
- checksums.yaml +7 -0
- data/.clacky/skills/commit/SKILL.md +423 -0
- data/.clacky/skills/gem-release/SKILL.md +199 -0
- data/.clacky/skills/gem-release/scripts/release.sh +304 -0
- data/.clacky/skills/oss-upload/SKILL.md +47 -0
- data/.octorules +106 -0
- data/.rspec +3 -0
- data/.rubocop.yml +8 -0
- data/CHANGELOG.md +76 -0
- data/CODE_OF_CONDUCT.md +132 -0
- data/CONTRIBUTING.md +92 -0
- data/Dockerfile +28 -0
- data/LICENSE.txt +22 -0
- data/POSITIONING.md +46 -0
- data/README.md +134 -0
- data/README_CN.md +134 -0
- data/Rakefile +34 -0
- data/benchmark/fixtures/sample_project/Gemfile +3 -0
- data/benchmark/fixtures/sample_project/lib/api_handler.rb +32 -0
- data/benchmark/fixtures/sample_project/lib/order_calculator.rb +23 -0
- data/benchmark/fixtures/sample_project/lib/user_renderer.rb +20 -0
- data/benchmark/fixtures/sample_project/spec/order_calculator_spec.rb +20 -0
- data/benchmark/results/EVALUATION_REPORT.md +165 -0
- data/benchmark/results/baseline_20260511_174424.json +128 -0
- data/benchmark/results/report_20260511_175256.json +271 -0
- data/benchmark/results/report_20260511_175444.json +271 -0
- data/benchmark/results/treatment_20260511_175103.json +130 -0
- data/benchmark/runner.rb +441 -0
- data/bin/octo +7 -0
- data/docs/agent-first-ui-design.md +77 -0
- data/docs/billing-system.md +318 -0
- data/docs/channel-architecture.md +235 -0
- data/docs/engineering-article.md +343 -0
- data/docs/session-skill-invocation.md +69 -0
- data/docs/time_machine_design.md +247 -0
- data/docs/ui2-architecture.md +124 -0
- data/homebrew/README.md +96 -0
- data/homebrew/openocto.rb +24 -0
- data/lib/octo/agent/hook_manager.rb +61 -0
- data/lib/octo/agent/llm_caller.rb +800 -0
- data/lib/octo/agent/memory_updater.rb +246 -0
- data/lib/octo/agent/message_compressor.rb +225 -0
- data/lib/octo/agent/message_compressor_helper.rb +869 -0
- data/lib/octo/agent/next_message_suggester.rb +215 -0
- data/lib/octo/agent/session_serializer.rb +685 -0
- data/lib/octo/agent/skill_auto_creator.rb +114 -0
- data/lib/octo/agent/skill_evolution.rb +61 -0
- data/lib/octo/agent/skill_manager.rb +466 -0
- data/lib/octo/agent/skill_reflector.rb +89 -0
- data/lib/octo/agent/system_prompt_builder.rb +101 -0
- data/lib/octo/agent/time_machine.rb +214 -0
- data/lib/octo/agent/tool_executor.rb +454 -0
- data/lib/octo/agent/tool_registry.rb +150 -0
- data/lib/octo/agent.rb +2180 -0
- data/lib/octo/agent_config.rb +989 -0
- data/lib/octo/agent_profile.rb +112 -0
- data/lib/octo/anthropic_stream_aggregator.rb +137 -0
- data/lib/octo/background_task_registry.rb +324 -0
- data/lib/octo/banner.rb +34 -0
- data/lib/octo/bedrock_stream_aggregator.rb +137 -0
- data/lib/octo/block_font.rb +331 -0
- data/lib/octo/cli.rb +968 -0
- data/lib/octo/client.rb +623 -0
- data/lib/octo/default_agents/SOUL.md +3 -0
- data/lib/octo/default_agents/USER.md +1 -0
- data/lib/octo/default_agents/base_prompt.md +66 -0
- data/lib/octo/default_agents/coding/profile.yml +2 -0
- data/lib/octo/default_agents/coding/system_prompt.md +67 -0
- data/lib/octo/default_agents/general/profile.yml +2 -0
- data/lib/octo/default_agents/general/system_prompt.md +16 -0
- data/lib/octo/default_parsers/doc_parser.rb +69 -0
- data/lib/octo/default_parsers/docx_parser.rb +188 -0
- data/lib/octo/default_parsers/pdf_parser.rb +120 -0
- data/lib/octo/default_parsers/pdf_parser_ocr.py +103 -0
- data/lib/octo/default_parsers/pdf_parser_plumber.py +62 -0
- data/lib/octo/default_parsers/pptx_parser.rb +140 -0
- data/lib/octo/default_parsers/xlsx_parser.rb +121 -0
- data/lib/octo/default_skills/browser-setup/SKILL.md +426 -0
- data/lib/octo/default_skills/channel-manager/SKILL.md +623 -0
- data/lib/octo/default_skills/channel-manager/dingtalk_setup.rb +191 -0
- data/lib/octo/default_skills/channel-manager/discord_setup.rb +199 -0
- data/lib/octo/default_skills/channel-manager/feishu_setup.rb +574 -0
- data/lib/octo/default_skills/channel-manager/import_lark_skills.rb +97 -0
- data/lib/octo/default_skills/channel-manager/install_feishu_skills.rb +105 -0
- data/lib/octo/default_skills/channel-manager/weixin_setup.rb +274 -0
- data/lib/octo/default_skills/code-explorer/SKILL.md +36 -0
- data/lib/octo/default_skills/cron-task-creator/SKILL.md +257 -0
- data/lib/octo/default_skills/cron-task-creator/evals/evals.json +38 -0
- data/lib/octo/default_skills/onboard/SKILL.md +578 -0
- data/lib/octo/default_skills/onboard/scripts/import_external_skills.rb +413 -0
- data/lib/octo/default_skills/onboard/scripts/install_builtin_skills.rb +97 -0
- data/lib/octo/default_skills/persist-memory/SKILL.md +59 -0
- data/lib/octo/default_skills/personal-website/SKILL.md +113 -0
- data/lib/octo/default_skills/personal-website/publish.rb +235 -0
- data/lib/octo/default_skills/product-help/SKILL.md +123 -0
- data/lib/octo/default_skills/product-help/docs/agent-config.md +74 -0
- data/lib/octo/default_skills/product-help/docs/best-practices.md +49 -0
- data/lib/octo/default_skills/product-help/docs/browser-tool.md +53 -0
- data/lib/octo/default_skills/product-help/docs/built-in-skills.md +43 -0
- data/lib/octo/default_skills/product-help/docs/cli-reference.md +82 -0
- data/lib/octo/default_skills/product-help/docs/create-your-first-skill.md +47 -0
- data/lib/octo/default_skills/product-help/docs/faq.md +98 -0
- data/lib/octo/default_skills/product-help/docs/how-to-use-a-skill.md +58 -0
- data/lib/octo/default_skills/product-help/docs/installation.md +59 -0
- data/lib/octo/default_skills/product-help/docs/memory-system.md +61 -0
- data/lib/octo/default_skills/product-help/docs/octorules.md +62 -0
- data/lib/octo/default_skills/product-help/docs/session-management.md +63 -0
- data/lib/octo/default_skills/product-help/docs/skill-basics.md +55 -0
- data/lib/octo/default_skills/product-help/docs/skill-frontmatter.md +61 -0
- data/lib/octo/default_skills/product-help/docs/web-server.md +49 -0
- data/lib/octo/default_skills/product-help/docs/what-is-octo.md +37 -0
- data/lib/octo/default_skills/product-help/docs/windows-installation.md +36 -0
- data/lib/octo/default_skills/product-help/docs/writing-tips.md +53 -0
- data/lib/octo/default_skills/recall-memory/SKILL.md +65 -0
- data/lib/octo/default_skills/skill-add/SKILL.md +59 -0
- data/lib/octo/default_skills/skill-add/scripts/install_from_zip.rb +295 -0
- data/lib/octo/default_skills/skill-creator/SKILL.md +602 -0
- data/lib/octo/default_skills/skill-creator/agents/analyzer.md +274 -0
- data/lib/octo/default_skills/skill-creator/agents/comparator.md +202 -0
- data/lib/octo/default_skills/skill-creator/agents/grader.md +223 -0
- data/lib/octo/default_skills/skill-creator/eval-viewer/generate_review.py +471 -0
- data/lib/octo/default_skills/skill-creator/eval-viewer/viewer.html +1325 -0
- data/lib/octo/default_skills/skill-creator/references/schemas.md +430 -0
- data/lib/octo/default_skills/skill-creator/scripts/__init__.py +0 -0
- data/lib/octo/default_skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- data/lib/octo/default_skills/skill-creator/scripts/generate_report.py +326 -0
- data/lib/octo/default_skills/skill-creator/scripts/improve_description.py +310 -0
- data/lib/octo/default_skills/skill-creator/scripts/quick_validate.py +103 -0
- data/lib/octo/default_skills/skill-creator/scripts/run_eval.py +317 -0
- data/lib/octo/default_skills/skill-creator/scripts/run_loop.py +331 -0
- data/lib/octo/default_skills/skill-creator/scripts/utils.py +47 -0
- data/lib/octo/default_skills/skill-creator/scripts/validate_skill_frontmatter.rb +143 -0
- data/lib/octo/idle_compression_timer.rb +115 -0
- data/lib/octo/json_ui_controller.rb +204 -0
- data/lib/octo/message_format/anthropic.rb +409 -0
- data/lib/octo/message_format/bedrock.rb +361 -0
- data/lib/octo/message_format/open_ai.rb +222 -0
- data/lib/octo/message_history.rb +373 -0
- data/lib/octo/openai_stream_aggregator.rb +130 -0
- data/lib/octo/plain_ui_controller.rb +166 -0
- data/lib/octo/providers.rb +534 -0
- data/lib/octo/server/browser_manager.rb +397 -0
- data/lib/octo/server/channel/adapters/base.rb +82 -0
- data/lib/octo/server/channel/adapters/dingtalk/adapter.rb +314 -0
- data/lib/octo/server/channel/adapters/dingtalk/api_client.rb +391 -0
- data/lib/octo/server/channel/adapters/dingtalk/stream_client.rb +203 -0
- data/lib/octo/server/channel/adapters/discord/adapter.rb +229 -0
- data/lib/octo/server/channel/adapters/discord/api_client.rb +107 -0
- data/lib/octo/server/channel/adapters/discord/gateway_client.rb +270 -0
- data/lib/octo/server/channel/adapters/feishu/adapter.rb +320 -0
- data/lib/octo/server/channel/adapters/feishu/bot.rb +478 -0
- data/lib/octo/server/channel/adapters/feishu/file_processor.rb +36 -0
- data/lib/octo/server/channel/adapters/feishu/message_parser.rb +129 -0
- data/lib/octo/server/channel/adapters/feishu/ws_client.rb +423 -0
- data/lib/octo/server/channel/adapters/telegram/adapter.rb +375 -0
- data/lib/octo/server/channel/adapters/telegram/api_client.rb +205 -0
- data/lib/octo/server/channel/adapters/wecom/adapter.rb +148 -0
- data/lib/octo/server/channel/adapters/wecom/media_downloader.rb +115 -0
- data/lib/octo/server/channel/adapters/wecom/ws_client.rb +395 -0
- data/lib/octo/server/channel/adapters/weixin/adapter.rb +692 -0
- data/lib/octo/server/channel/adapters/weixin/api_client.rb +402 -0
- data/lib/octo/server/channel/channel_config.rb +178 -0
- data/lib/octo/server/channel/channel_manager.rb +468 -0
- data/lib/octo/server/channel/channel_ui_controller.rb +224 -0
- data/lib/octo/server/channel.rb +33 -0
- data/lib/octo/server/discover.rb +77 -0
- data/lib/octo/server/epipe_safe_io.rb +105 -0
- data/lib/octo/server/http_server.rb +3554 -0
- data/lib/octo/server/scheduler.rb +317 -0
- data/lib/octo/server/server_master.rb +325 -0
- data/lib/octo/server/session_registry.rb +431 -0
- data/lib/octo/server/web_ui_controller.rb +487 -0
- data/lib/octo/session_manager.rb +385 -0
- data/lib/octo/skill.rb +466 -0
- data/lib/octo/skill_loader.rb +328 -0
- data/lib/octo/tools/base.rb +118 -0
- data/lib/octo/tools/browser.rb +625 -0
- data/lib/octo/tools/edit.rb +165 -0
- data/lib/octo/tools/file_reader.rb +549 -0
- data/lib/octo/tools/glob.rb +162 -0
- data/lib/octo/tools/grep.rb +356 -0
- data/lib/octo/tools/invoke_skill.rb +96 -0
- data/lib/octo/tools/list_tasks.rb +54 -0
- data/lib/octo/tools/redo_task.rb +41 -0
- data/lib/octo/tools/request_user_feedback.rb +84 -0
- data/lib/octo/tools/security.rb +333 -0
- data/lib/octo/tools/terminal/output_cleaner.rb +63 -0
- data/lib/octo/tools/terminal/persistent_session.rb +268 -0
- data/lib/octo/tools/terminal/safe_rm.sh +106 -0
- data/lib/octo/tools/terminal/session_manager.rb +213 -0
- data/lib/octo/tools/terminal.rb +1828 -0
- data/lib/octo/tools/todo_manager.rb +374 -0
- data/lib/octo/tools/trash_manager.rb +388 -0
- data/lib/octo/tools/undo_task.rb +35 -0
- data/lib/octo/tools/web_fetch.rb +242 -0
- data/lib/octo/tools/web_search.rb +260 -0
- data/lib/octo/tools/write.rb +77 -0
- data/lib/octo/ui2/block_font.rb +10 -0
- data/lib/octo/ui2/components/base_component.rb +163 -0
- data/lib/octo/ui2/components/command_suggestions.rb +290 -0
- data/lib/octo/ui2/components/common_component.rb +96 -0
- data/lib/octo/ui2/components/inline_input.rb +226 -0
- data/lib/octo/ui2/components/input_area.rb +1338 -0
- data/lib/octo/ui2/components/message_component.rb +99 -0
- data/lib/octo/ui2/components/modal_component.rb +419 -0
- data/lib/octo/ui2/components/todo_area.rb +149 -0
- data/lib/octo/ui2/components/tool_component.rb +107 -0
- data/lib/octo/ui2/components/welcome_banner.rb +139 -0
- data/lib/octo/ui2/layout_manager.rb +807 -0
- data/lib/octo/ui2/line_editor.rb +363 -0
- data/lib/octo/ui2/markdown_renderer.rb +100 -0
- data/lib/octo/ui2/output_buffer.rb +370 -0
- data/lib/octo/ui2/progress_handle.rb +362 -0
- data/lib/octo/ui2/progress_indicator.rb +55 -0
- data/lib/octo/ui2/screen_buffer.rb +273 -0
- data/lib/octo/ui2/terminal_detector.rb +119 -0
- data/lib/octo/ui2/theme_manager.rb +85 -0
- data/lib/octo/ui2/themes/base_theme.rb +105 -0
- data/lib/octo/ui2/themes/hacker_theme.rb +62 -0
- data/lib/octo/ui2/themes/minimal_theme.rb +56 -0
- data/lib/octo/ui2/thinking_verbs.rb +26 -0
- data/lib/octo/ui2/ui_controller.rb +1625 -0
- data/lib/octo/ui2/view_renderer.rb +177 -0
- data/lib/octo/ui2.rb +40 -0
- data/lib/octo/ui_interface.rb +154 -0
- data/lib/octo/utils/arguments_parser.rb +191 -0
- data/lib/octo/utils/browser_detector.rb +195 -0
- data/lib/octo/utils/encoding.rb +92 -0
- data/lib/octo/utils/environment_detector.rb +140 -0
- data/lib/octo/utils/file_ignore_helper.rb +170 -0
- data/lib/octo/utils/file_processor.rb +601 -0
- data/lib/octo/utils/gitignore_parser.rb +154 -0
- data/lib/octo/utils/limit_stack.rb +152 -0
- data/lib/octo/utils/logger.rb +124 -0
- data/lib/octo/utils/login_shell.rb +72 -0
- data/lib/octo/utils/model_pricing.rb +646 -0
- data/lib/octo/utils/parser_manager.rb +165 -0
- data/lib/octo/utils/path_helper.rb +15 -0
- data/lib/octo/utils/scripts_manager.rb +59 -0
- data/lib/octo/utils/string_matcher.rb +158 -0
- data/lib/octo/utils/trash_directory.rb +112 -0
- data/lib/octo/utils/workspace_rules.rb +46 -0
- data/lib/octo/version.rb +5 -0
- data/lib/octo/web/app.css +7141 -0
- data/lib/octo/web/app.js +543 -0
- data/lib/octo/web/apple-touch-icon.png +0 -0
- data/lib/octo/web/auth.js +150 -0
- data/lib/octo/web/channels.js +276 -0
- data/lib/octo/web/datepicker.js +205 -0
- data/lib/octo/web/favicon.png +0 -0
- data/lib/octo/web/i18n.js +1073 -0
- data/lib/octo/web/icon-512.png +0 -0
- data/lib/octo/web/icon-dark.svg +25 -0
- data/lib/octo/web/icon.svg +29 -0
- data/lib/octo/web/index.html +871 -0
- data/lib/octo/web/marked.min.js +69 -0
- data/lib/octo/web/onboard.js +491 -0
- data/lib/octo/web/profile.js +442 -0
- data/lib/octo/web/sessions.js +4421 -0
- data/lib/octo/web/settings.js +913 -0
- data/lib/octo/web/sidebar.js +32 -0
- data/lib/octo/web/skills.js +885 -0
- data/lib/octo/web/tasks.js +297 -0
- data/lib/octo/web/theme.js +105 -0
- data/lib/octo/web/trash.js +343 -0
- data/lib/octo/web/vendor/hljs/highlight.min.js +1244 -0
- data/lib/octo/web/vendor/hljs/hljs-theme.css +95 -0
- data/lib/octo/web/vendor/katex/auto-render.min.js +1 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_AMS-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Main-Bold.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Main-Italic.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Main-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Math-Italic.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Script-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Size1-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Size2-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Size3-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Size4-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
- data/lib/octo/web/vendor/katex/katex.min.css +1 -0
- data/lib/octo/web/vendor/katex/katex.min.js +1 -0
- data/lib/octo/web/version.js +449 -0
- data/lib/octo/web/weixin-qr.html +209 -0
- data/lib/octo/web/ws-dispatcher.js +357 -0
- data/lib/octo/web/ws.js +128 -0
- data/lib/octo.rb +145 -0
- data/scripts/build/build.sh +329 -0
- data/scripts/build/lib/apt.sh +56 -0
- data/scripts/build/lib/brew.sh +89 -0
- data/scripts/build/lib/colors.sh +17 -0
- data/scripts/build/lib/gem.sh +95 -0
- data/scripts/build/lib/mise.sh +125 -0
- data/scripts/build/lib/network.sh +157 -0
- data/scripts/build/lib/os.sh +57 -0
- data/scripts/build/lib/shell.sh +37 -0
- data/scripts/build/src/install.sh.cc +174 -0
- data/scripts/build/src/install_browser.sh.cc +101 -0
- data/scripts/build/src/install_full.sh.cc +290 -0
- data/scripts/build/src/install_rails_deps.sh.cc +145 -0
- data/scripts/build/src/install_system_deps.sh.cc +123 -0
- data/scripts/build/src/uninstall.sh.cc +101 -0
- data/scripts/install.ps1 +532 -0
- data/scripts/install.sh +567 -0
- data/scripts/install_browser.sh +479 -0
- data/scripts/install_full.sh +838 -0
- data/scripts/install_rails_deps.sh +746 -0
- data/scripts/install_system_deps.sh +518 -0
- data/scripts/uninstall.sh +287 -0
- data/sig/octo.rbs +4 -0
- metadata +614 -0
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# mise.sh — install mise, Ruby, and Node via mise
|
|
2
|
+
# Depends-On: colors.sh os.sh
|
|
3
|
+
# Requires-Vars: $SHELL_RC $USE_CN_MIRRORS $CURRENT_SHELL $MISE_INSTALL_URL $NODE_MIRROR_URL $RUBY_VERSION_SPEC $CN_RUBY_PRECOMPILED_URL
|
|
4
|
+
# Sets-Vars: $MISE_BIN
|
|
5
|
+
# Include via: @include lib/mise.sh
|
|
6
|
+
|
|
7
|
+
# --------------------------------------------------------------------------
|
|
8
|
+
# Internal helper — locate the mise binary
|
|
9
|
+
# --------------------------------------------------------------------------
|
|
10
|
+
_mise_bin() {
|
|
11
|
+
if [ -x "$HOME/.local/bin/mise" ]; then
|
|
12
|
+
echo "$HOME/.local/bin/mise"
|
|
13
|
+
elif command_exists mise; then
|
|
14
|
+
command -v mise
|
|
15
|
+
else
|
|
16
|
+
echo ""
|
|
17
|
+
fi
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
# --------------------------------------------------------------------------
|
|
21
|
+
# ensure_mise — install mise if missing, activate it in the current session
|
|
22
|
+
# --------------------------------------------------------------------------
|
|
23
|
+
ensure_mise() {
|
|
24
|
+
local mise
|
|
25
|
+
mise=$(_mise_bin)
|
|
26
|
+
|
|
27
|
+
if [ -n "$mise" ]; then
|
|
28
|
+
print_success "mise already installed: $($mise --version 2>/dev/null || echo 'n/a')"
|
|
29
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
30
|
+
eval "$($mise activate bash 2>/dev/null)" 2>/dev/null || true
|
|
31
|
+
MISE_BIN="$mise"
|
|
32
|
+
return 0
|
|
33
|
+
fi
|
|
34
|
+
|
|
35
|
+
print_step "Installing mise..."
|
|
36
|
+
if curl -fsSL "$MISE_INSTALL_URL" | sh; then
|
|
37
|
+
export PATH="$HOME/.local/bin:$PATH"
|
|
38
|
+
eval "$(~/.local/bin/mise activate bash 2>/dev/null)" 2>/dev/null || true
|
|
39
|
+
|
|
40
|
+
# Persist mise activation to shell rc
|
|
41
|
+
local init_line='eval "$(~/.local/bin/mise activate '"$CURRENT_SHELL"')"'
|
|
42
|
+
if ! grep -q "mise activate" "$SHELL_RC" 2>/dev/null; then
|
|
43
|
+
echo "$init_line" >> "$SHELL_RC"
|
|
44
|
+
print_info "Added mise activation to $SHELL_RC"
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
MISE_BIN="$HOME/.local/bin/mise"
|
|
48
|
+
print_success "mise installed"
|
|
49
|
+
else
|
|
50
|
+
print_error "Failed to install mise"
|
|
51
|
+
return 1
|
|
52
|
+
fi
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# --------------------------------------------------------------------------
|
|
56
|
+
# install_ruby_via_mise — install Ruby via mise
|
|
57
|
+
# CN mode: precompiled binary from oss.1024code.com
|
|
58
|
+
# Global: mise default (precompiled where available)
|
|
59
|
+
# --------------------------------------------------------------------------
|
|
60
|
+
install_ruby_via_mise() {
|
|
61
|
+
local mise="${MISE_BIN:-$(_mise_bin)}"
|
|
62
|
+
if [ -z "$mise" ]; then
|
|
63
|
+
print_error "mise not found — call ensure_mise first"
|
|
64
|
+
return 1
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
print_info "Installing Ruby via mise ($RUBY_VERSION_SPEC)..."
|
|
68
|
+
|
|
69
|
+
if [ "$USE_CN_MIRRORS" = true ]; then
|
|
70
|
+
"$mise" settings ruby.compile=false 2>/dev/null || true
|
|
71
|
+
"$mise" settings ruby.precompiled_url="$CN_RUBY_PRECOMPILED_URL" 2>/dev/null || true
|
|
72
|
+
print_info "Using precompiled Ruby from CN CDN"
|
|
73
|
+
else
|
|
74
|
+
# Enable precompiled binaries globally (mise supports this on common platforms)
|
|
75
|
+
"$mise" settings ruby.compile=false 2>/dev/null || true
|
|
76
|
+
"$mise" settings unset ruby.precompiled_url 2>/dev/null || true
|
|
77
|
+
fi
|
|
78
|
+
|
|
79
|
+
if "$mise" use -g "$RUBY_VERSION_SPEC"; then
|
|
80
|
+
eval "$($mise activate bash 2>/dev/null)" 2>/dev/null || true
|
|
81
|
+
local installed
|
|
82
|
+
installed=$(ruby -e 'puts RUBY_VERSION' 2>/dev/null || echo "unknown")
|
|
83
|
+
print_success "Ruby $installed installed"
|
|
84
|
+
else
|
|
85
|
+
print_error "Failed to install Ruby via mise"
|
|
86
|
+
return 1
|
|
87
|
+
fi
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
# --------------------------------------------------------------------------
|
|
91
|
+
# install_node_via_mise — install Node.js 22 via mise
|
|
92
|
+
# --------------------------------------------------------------------------
|
|
93
|
+
install_node_via_mise() {
|
|
94
|
+
local mise="${MISE_BIN:-$(_mise_bin)}"
|
|
95
|
+
if [ -z "$mise" ]; then
|
|
96
|
+
print_error "mise not found — call ensure_mise first"
|
|
97
|
+
return 1
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# Skip if compatible Node is already active
|
|
101
|
+
if command_exists node; then
|
|
102
|
+
local ver major
|
|
103
|
+
ver=$(node --version 2>/dev/null | sed 's/v//')
|
|
104
|
+
major="${ver%%.*}"
|
|
105
|
+
if [ "${major:-0}" -ge 22 ] 2>/dev/null; then
|
|
106
|
+
print_success "Node.js v${ver} already satisfies >= 22 — skipping"
|
|
107
|
+
return 0
|
|
108
|
+
fi
|
|
109
|
+
fi
|
|
110
|
+
|
|
111
|
+
# Apply CN Node mirror if needed
|
|
112
|
+
if [ "$USE_CN_MIRRORS" = true ] && [ -n "$NODE_MIRROR_URL" ]; then
|
|
113
|
+
"$mise" settings node.mirror_url="$NODE_MIRROR_URL" 2>/dev/null || true
|
|
114
|
+
print_info "Node mirror → ${NODE_MIRROR_URL}"
|
|
115
|
+
fi
|
|
116
|
+
|
|
117
|
+
print_info "Installing Node.js 22 via mise..."
|
|
118
|
+
if "$mise" use -g node@22; then
|
|
119
|
+
eval "$($mise activate bash 2>/dev/null)" 2>/dev/null || true
|
|
120
|
+
print_success "Node.js $(node --version 2>/dev/null) installed"
|
|
121
|
+
else
|
|
122
|
+
print_error "Failed to install Node.js via mise"
|
|
123
|
+
return 1
|
|
124
|
+
fi
|
|
125
|
+
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# network.sh — network region detection, mirror variables, URL probing
|
|
2
|
+
# Depends-On: colors.sh
|
|
3
|
+
# Requires-Vars: (none)
|
|
4
|
+
# Sets-Vars: $USE_CN_MIRRORS $NETWORK_REGION $CN_CDN_BASE_URL $CN_ALIYUN_MIRROR $CN_RUBYGEMS_URL $CN_NODE_MIRROR_URL $CN_NPM_REGISTRY $CN_MISE_INSTALL_URL $CN_RUBY_PRECOMPILED_URL $MISE_INSTALL_URL $NODE_MIRROR_URL $NPM_REGISTRY_URL $RUBY_VERSION_SPEC $DEFAULT_RUBYGEMS_URL $DEFAULT_MISE_INSTALL_URL $DEFAULT_NPM_REGISTRY
|
|
5
|
+
# Include via: @include lib/network.sh
|
|
6
|
+
|
|
7
|
+
# --------------------------------------------------------------------------
|
|
8
|
+
# Mirror variables — overridden by detect_network_region()
|
|
9
|
+
# --------------------------------------------------------------------------
|
|
10
|
+
SLOW_THRESHOLD_MS=5000
|
|
11
|
+
NETWORK_REGION="global" # china | global | unknown
|
|
12
|
+
USE_CN_MIRRORS=false
|
|
13
|
+
|
|
14
|
+
GITHUB_RAW_BASE_URL="https://raw.githubusercontent.com"
|
|
15
|
+
DEFAULT_RUBYGEMS_URL="https://rubygems.org"
|
|
16
|
+
DEFAULT_NPM_REGISTRY="https://registry.npmjs.org"
|
|
17
|
+
DEFAULT_MISE_INSTALL_URL="https://mise.run"
|
|
18
|
+
|
|
19
|
+
CN_CDN_BASE_URL="https://oss.1024code.com"
|
|
20
|
+
CN_ALIYUN_MIRROR="https://mirrors.aliyun.com"
|
|
21
|
+
CN_MISE_INSTALL_URL="${CN_CDN_BASE_URL}/mise.sh"
|
|
22
|
+
CN_RUBY_PRECOMPILED_URL="${CN_CDN_BASE_URL}/ruby/ruby-{version}.{platform}.tar.gz"
|
|
23
|
+
CN_RUBYGEMS_URL="${CN_ALIYUN_MIRROR}/rubygems/"
|
|
24
|
+
CN_NPM_REGISTRY="https://registry.npmmirror.com"
|
|
25
|
+
CN_NODE_MIRROR_URL="https://cdn.npmmirror.com/binaries/node/"
|
|
26
|
+
CN_GEM_BASE_URL="${CN_CDN_BASE_URL}/octo"
|
|
27
|
+
CN_GEM_LATEST_URL="${CN_GEM_BASE_URL}/latest.txt"
|
|
28
|
+
|
|
29
|
+
# Active values (set by detect_network_region)
|
|
30
|
+
MISE_INSTALL_URL="$DEFAULT_MISE_INSTALL_URL"
|
|
31
|
+
RUBYGEMS_INSTALL_URL="$DEFAULT_RUBYGEMS_URL"
|
|
32
|
+
NPM_REGISTRY_URL="$DEFAULT_NPM_REGISTRY"
|
|
33
|
+
NODE_MIRROR_URL="" # empty = mise default (nodejs.org)
|
|
34
|
+
RUBY_VERSION_SPEC="ruby@3" # CN mode pins to a specific precompiled build
|
|
35
|
+
|
|
36
|
+
# --------------------------------------------------------------------------
|
|
37
|
+
# Internal probe helpers
|
|
38
|
+
# --------------------------------------------------------------------------
|
|
39
|
+
|
|
40
|
+
# Probe a single URL; echoes round-trip time in ms, or "timeout"
|
|
41
|
+
_probe_url() {
|
|
42
|
+
local url="$1"
|
|
43
|
+
local out http_code total_time
|
|
44
|
+
out=$(curl -s -o /dev/null -w "%{http_code} %{time_total}" \
|
|
45
|
+
--connect-timeout 5 --max-time 5 "$url" 2>/dev/null) || true
|
|
46
|
+
http_code="${out%% *}"
|
|
47
|
+
total_time="${out#* }"
|
|
48
|
+
if [ -z "$http_code" ] || [ "$http_code" = "000" ] || [ "$http_code" = "$out" ]; then
|
|
49
|
+
echo "timeout"; return
|
|
50
|
+
fi
|
|
51
|
+
awk -v s="$total_time" 'BEGIN { printf "%d", s * 1000 }'
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
# Returns 0 (true) if result is slow or unreachable
|
|
55
|
+
_is_slow_or_unreachable() {
|
|
56
|
+
local r="$1"
|
|
57
|
+
[ "$r" = "timeout" ] && return 0
|
|
58
|
+
[ "${r:-9999}" -ge "$SLOW_THRESHOLD_MS" ] 2>/dev/null
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
_format_probe_time() {
|
|
62
|
+
local r="$1"
|
|
63
|
+
[ "$r" = "timeout" ] && echo "timeout" && return
|
|
64
|
+
awk -v ms="$r" 'BEGIN { printf "%.1fs", ms / 1000 }'
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
_print_probe_result() {
|
|
68
|
+
local label="$1" result="$2"
|
|
69
|
+
if [ "$result" = "timeout" ]; then
|
|
70
|
+
print_warning "UNREACHABLE ${label}"
|
|
71
|
+
elif _is_slow_or_unreachable "$result"; then
|
|
72
|
+
print_warning "SLOW ($(_format_probe_time "$result")) ${label}"
|
|
73
|
+
else
|
|
74
|
+
print_success "OK ($(_format_probe_time "$result")) ${label}"
|
|
75
|
+
fi
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# Probe URL up to max_retries times; returns first fast result or last result
|
|
79
|
+
_probe_url_with_retry() {
|
|
80
|
+
local url="$1" max="${2:-2}" result
|
|
81
|
+
for _ in $(seq 1 "$max"); do
|
|
82
|
+
result=$(_probe_url "$url")
|
|
83
|
+
! _is_slow_or_unreachable "$result" && { echo "$result"; return 0; }
|
|
84
|
+
done
|
|
85
|
+
echo "$result"
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
# --------------------------------------------------------------------------
|
|
89
|
+
# detect_network_region — sets USE_CN_MIRRORS and active mirror variables
|
|
90
|
+
# --------------------------------------------------------------------------
|
|
91
|
+
detect_network_region() {
|
|
92
|
+
print_step "Network pre-flight check..."
|
|
93
|
+
echo ""
|
|
94
|
+
|
|
95
|
+
local google_result baidu_result
|
|
96
|
+
google_result=$(_probe_url "https://www.google.com")
|
|
97
|
+
baidu_result=$(_probe_url "https://www.baidu.com")
|
|
98
|
+
|
|
99
|
+
_print_probe_result "google.com" "$google_result"
|
|
100
|
+
_print_probe_result "baidu.com" "$baidu_result"
|
|
101
|
+
|
|
102
|
+
local google_ok=false baidu_ok=false
|
|
103
|
+
! _is_slow_or_unreachable "$google_result" && google_ok=true
|
|
104
|
+
! _is_slow_or_unreachable "$baidu_result" && baidu_ok=true
|
|
105
|
+
|
|
106
|
+
if [ "$google_ok" = true ]; then
|
|
107
|
+
NETWORK_REGION="global"
|
|
108
|
+
print_success "Region: global"
|
|
109
|
+
elif [ "$baidu_ok" = true ]; then
|
|
110
|
+
NETWORK_REGION="china"
|
|
111
|
+
print_success "Region: china"
|
|
112
|
+
else
|
|
113
|
+
NETWORK_REGION="unknown"
|
|
114
|
+
print_warning "Region: unknown (both unreachable)"
|
|
115
|
+
fi
|
|
116
|
+
echo ""
|
|
117
|
+
|
|
118
|
+
if [ "$NETWORK_REGION" = "china" ]; then
|
|
119
|
+
local cdn_result mirror_result
|
|
120
|
+
cdn_result=$(_probe_url_with_retry "$CN_MISE_INSTALL_URL")
|
|
121
|
+
mirror_result=$(_probe_url_with_retry "$CN_RUBYGEMS_URL")
|
|
122
|
+
|
|
123
|
+
_print_probe_result "CN CDN (mise/Ruby)" "$cdn_result"
|
|
124
|
+
_print_probe_result "Aliyun (gem)" "$mirror_result"
|
|
125
|
+
|
|
126
|
+
local cdn_ok=false mirror_ok=false
|
|
127
|
+
! _is_slow_or_unreachable "$cdn_result" && cdn_ok=true
|
|
128
|
+
! _is_slow_or_unreachable "$mirror_result" && mirror_ok=true
|
|
129
|
+
|
|
130
|
+
if [ "$cdn_ok" = true ] || [ "$mirror_ok" = true ]; then
|
|
131
|
+
USE_CN_MIRRORS=true
|
|
132
|
+
MISE_INSTALL_URL="$CN_MISE_INSTALL_URL"
|
|
133
|
+
RUBYGEMS_INSTALL_URL="$CN_RUBYGEMS_URL"
|
|
134
|
+
NPM_REGISTRY_URL="$CN_NPM_REGISTRY"
|
|
135
|
+
NODE_MIRROR_URL="$CN_NODE_MIRROR_URL"
|
|
136
|
+
RUBY_VERSION_SPEC="ruby@3.4.8"
|
|
137
|
+
print_info "CN mirrors applied"
|
|
138
|
+
else
|
|
139
|
+
print_warning "CN mirrors unreachable — falling back to global sources"
|
|
140
|
+
fi
|
|
141
|
+
else
|
|
142
|
+
local rubygems_result mise_result
|
|
143
|
+
rubygems_result=$(_probe_url_with_retry "$DEFAULT_RUBYGEMS_URL")
|
|
144
|
+
mise_result=$(_probe_url_with_retry "$DEFAULT_MISE_INSTALL_URL")
|
|
145
|
+
|
|
146
|
+
_print_probe_result "RubyGems" "$rubygems_result"
|
|
147
|
+
_print_probe_result "mise.run" "$mise_result"
|
|
148
|
+
|
|
149
|
+
_is_slow_or_unreachable "$rubygems_result" && print_warning "RubyGems is slow/unreachable."
|
|
150
|
+
_is_slow_or_unreachable "$mise_result" && print_warning "mise.run is slow/unreachable."
|
|
151
|
+
|
|
152
|
+
USE_CN_MIRRORS=false
|
|
153
|
+
RUBY_VERSION_SPEC="ruby@3"
|
|
154
|
+
fi
|
|
155
|
+
|
|
156
|
+
echo ""
|
|
157
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# os.sh — OS/distro detection, command_exists, version_ge
|
|
2
|
+
# Depends-On: colors.sh
|
|
3
|
+
# Requires-Vars: (none)
|
|
4
|
+
# Sets-Vars: $OS $DISTRO
|
|
5
|
+
# Include via: @include lib/os.sh
|
|
6
|
+
|
|
7
|
+
# Sets OS (macOS | Linux | Windows | Unknown) and DISTRO (ubuntu | debian | …)
|
|
8
|
+
detect_os() {
|
|
9
|
+
case "$(uname -s)" in
|
|
10
|
+
Linux*) OS=Linux ;;
|
|
11
|
+
Darwin*) OS=macOS ;;
|
|
12
|
+
CYGWIN*) OS=Windows ;;
|
|
13
|
+
MINGW*) OS=Windows ;;
|
|
14
|
+
*) OS=Unknown ;;
|
|
15
|
+
esac
|
|
16
|
+
print_info "Detected OS: $OS"
|
|
17
|
+
|
|
18
|
+
if [ "$OS" = "Linux" ] && [ -f /etc/os-release ]; then
|
|
19
|
+
# shellcheck source=/dev/null
|
|
20
|
+
. /etc/os-release
|
|
21
|
+
DISTRO=$ID
|
|
22
|
+
print_info "Detected Linux distribution: $DISTRO"
|
|
23
|
+
else
|
|
24
|
+
DISTRO=unknown
|
|
25
|
+
fi
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
# Returns 0 if the given command is on PATH
|
|
29
|
+
command_exists() { command -v "$1" >/dev/null 2>&1; }
|
|
30
|
+
|
|
31
|
+
# Boolean helpers — use these in business logic instead of inline string comparisons
|
|
32
|
+
is_macos() { [ "$OS" = "macOS" ]; }
|
|
33
|
+
is_linux_apt() { [ "$OS" = "Linux" ] && { [ "$DISTRO" = "ubuntu" ] || [ "$DISTRO" = "debian" ]; }; }
|
|
34
|
+
|
|
35
|
+
# Returns 0 (true) if $1 >= $2 (semantic version comparison)
|
|
36
|
+
version_ge() { printf '%s\n%s\n' "$2" "$1" | sort -V -C; }
|
|
37
|
+
|
|
38
|
+
# Assert that the current OS/distro is supported (macOS or Ubuntu/Debian).
|
|
39
|
+
# Optional $1: hint message printed on failure (e.g. manual install instructions).
|
|
40
|
+
# Exits with code 1 on unsupported OS or distro.
|
|
41
|
+
assert_supported_os() {
|
|
42
|
+
local hint="${1:-}"
|
|
43
|
+
if [ "$OS" = "Linux" ]; then
|
|
44
|
+
if [ "$DISTRO" = "ubuntu" ] || [ "$DISTRO" = "debian" ]; then
|
|
45
|
+
return 0
|
|
46
|
+
fi
|
|
47
|
+
print_error "Unsupported Linux distribution: $DISTRO"
|
|
48
|
+
[ -n "$hint" ] && print_info "$hint"
|
|
49
|
+
exit 1
|
|
50
|
+
elif [ "$OS" = "macOS" ]; then
|
|
51
|
+
return 0
|
|
52
|
+
else
|
|
53
|
+
print_error "Unsupported OS: $OS"
|
|
54
|
+
[ -n "$hint" ] && print_info "$hint"
|
|
55
|
+
exit 1
|
|
56
|
+
fi
|
|
57
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# shell.sh — detect current interactive shell and its rc file
|
|
2
|
+
# Depends-On: colors.sh os.sh
|
|
3
|
+
# Requires-Vars: (none)
|
|
4
|
+
# Sets-Vars: $CURRENT_SHELL $SHELL_RC
|
|
5
|
+
# Include via: @include lib/shell.sh
|
|
6
|
+
|
|
7
|
+
# Sets CURRENT_SHELL (zsh | bash | fish) and SHELL_RC (path to rc file)
|
|
8
|
+
detect_shell() {
|
|
9
|
+
local shell_name
|
|
10
|
+
shell_name=$(basename "$SHELL")
|
|
11
|
+
|
|
12
|
+
case "$shell_name" in
|
|
13
|
+
zsh)
|
|
14
|
+
CURRENT_SHELL="zsh"
|
|
15
|
+
SHELL_RC="$HOME/.zshrc"
|
|
16
|
+
;;
|
|
17
|
+
fish)
|
|
18
|
+
CURRENT_SHELL="fish"
|
|
19
|
+
SHELL_RC="$HOME/.config/fish/config.fish"
|
|
20
|
+
;;
|
|
21
|
+
bash)
|
|
22
|
+
CURRENT_SHELL="bash"
|
|
23
|
+
# macOS uses ~/.bash_profile; Linux uses ~/.bashrc
|
|
24
|
+
if is_macos; then
|
|
25
|
+
SHELL_RC="$HOME/.bash_profile"
|
|
26
|
+
else
|
|
27
|
+
SHELL_RC="$HOME/.bashrc"
|
|
28
|
+
fi
|
|
29
|
+
;;
|
|
30
|
+
*)
|
|
31
|
+
CURRENT_SHELL="bash"
|
|
32
|
+
SHELL_RC="$HOME/.bashrc"
|
|
33
|
+
;;
|
|
34
|
+
esac
|
|
35
|
+
|
|
36
|
+
print_info "Detected shell: $CURRENT_SHELL (rc file: $SHELL_RC)"
|
|
37
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# install.sh — OpenClacky installer
|
|
3
|
+
# Generated from scripts/build/src/install.sh.cc — DO NOT EDIT DIRECTLY
|
|
4
|
+
|
|
5
|
+
set -e
|
|
6
|
+
|
|
7
|
+
# Brand configuration (populated by --brand-name / --command flags)
|
|
8
|
+
BRAND_NAME=""
|
|
9
|
+
BRAND_COMMAND=""
|
|
10
|
+
|
|
11
|
+
@include lib/colors.sh
|
|
12
|
+
@include lib/os.sh
|
|
13
|
+
@include lib/shell.sh
|
|
14
|
+
@include lib/network.sh
|
|
15
|
+
@include lib/apt.sh
|
|
16
|
+
|
|
17
|
+
@include lib/gem.sh
|
|
18
|
+
|
|
19
|
+
# --------------------------------------------------------------------------
|
|
20
|
+
# Ensure Ruby >= 2.6 is available
|
|
21
|
+
# macOS: uses system Ruby or user-installed Ruby
|
|
22
|
+
# Linux: tries apt first; if missing or too old, prints manual install hint
|
|
23
|
+
# --------------------------------------------------------------------------
|
|
24
|
+
check_ruby() {
|
|
25
|
+
command_exists ruby || return 1
|
|
26
|
+
local ver; ver=$(ruby -e 'puts RUBY_VERSION' 2>/dev/null)
|
|
27
|
+
version_ge "$ver" "2.6.0" && { print_success "Ruby $ver — OK"; return 0; }
|
|
28
|
+
print_warning "Ruby $ver too old (need >= 2.6.0)"; return 1
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
ensure_ruby() {
|
|
32
|
+
print_step "Checking Ruby..."
|
|
33
|
+
check_ruby && return 0
|
|
34
|
+
|
|
35
|
+
if is_linux_apt; then
|
|
36
|
+
print_info "Installing Ruby via apt..."
|
|
37
|
+
sudo apt-get install -y ruby ruby-dev 2>/dev/null && check_ruby && return 0
|
|
38
|
+
print_warning "apt Ruby install failed or version too old"
|
|
39
|
+
fi
|
|
40
|
+
|
|
41
|
+
return 1
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
# --------------------------------------------------------------------------
|
|
45
|
+
# gem install openclacky
|
|
46
|
+
# --------------------------------------------------------------------------
|
|
47
|
+
install_via_gem() {
|
|
48
|
+
print_step "Installing ${DISPLAY_NAME} via gem..."
|
|
49
|
+
configure_gem_source
|
|
50
|
+
setup_gem_home
|
|
51
|
+
|
|
52
|
+
local target source_args=()
|
|
53
|
+
if [ "$USE_CN_MIRRORS" = true ]; then
|
|
54
|
+
print_info "Fetching latest version from OSS..."
|
|
55
|
+
local cn_version; cn_version=$(curl -fsSL "$CN_GEM_LATEST_URL" | tr -d '[:space:]')
|
|
56
|
+
print_info "Latest version: ${cn_version}"
|
|
57
|
+
local gem_url="${CN_GEM_BASE_URL}/openclacky-${cn_version}.gem"
|
|
58
|
+
local gem_file="/tmp/openclacky-${cn_version}.gem"
|
|
59
|
+
print_info "Downloading openclacky-${cn_version}.gem..."
|
|
60
|
+
curl -fsSL "$gem_url" -o "$gem_file"
|
|
61
|
+
target="$gem_file"
|
|
62
|
+
source_args=(--source "$CN_RUBYGEMS_URL")
|
|
63
|
+
else
|
|
64
|
+
target="openclacky"
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
# macOS system Ruby 2.6 has a buggy gem resolver that fails on rouge 4.x.
|
|
68
|
+
# Pre-install a 2.6-compatible rouge to avoid resolver failure.
|
|
69
|
+
local ruby_ver; ruby_ver=$(ruby -e 'puts RUBY_VERSION' 2>/dev/null)
|
|
70
|
+
if [[ "$ruby_ver" == 2.6.* ]]; then
|
|
71
|
+
print_warning "Ruby 2.6 detected — pinning rouge 3.30.0 first"
|
|
72
|
+
gem install rouge -v 3.30.0 --no-document "${source_args[@]}" || { print_error "gem install rouge failed"; return 1; }
|
|
73
|
+
fi
|
|
74
|
+
|
|
75
|
+
if gem install "$target" --no-document "${source_args[@]}"; then
|
|
76
|
+
print_success "${DISPLAY_NAME} installed successfully!"
|
|
77
|
+
return 0
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
print_error "gem install failed"; return 1
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
# --------------------------------------------------------------------------
|
|
84
|
+
# Parse CLI args
|
|
85
|
+
# --------------------------------------------------------------------------
|
|
86
|
+
parse_args() {
|
|
87
|
+
for arg in "$0" "$@"; do
|
|
88
|
+
case "$arg" in
|
|
89
|
+
--brand-name=*) BRAND_NAME="${arg#--brand-name=}" ;;
|
|
90
|
+
--command=*) BRAND_COMMAND="${arg#--command=}" ;;
|
|
91
|
+
esac
|
|
92
|
+
done
|
|
93
|
+
DISPLAY_NAME="${BRAND_NAME:-OpenClacky}"
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
# --------------------------------------------------------------------------
|
|
97
|
+
# Brand wrapper setup
|
|
98
|
+
# --------------------------------------------------------------------------
|
|
99
|
+
setup_brand() {
|
|
100
|
+
[ -z "$BRAND_NAME" ] && return 0
|
|
101
|
+
local clacky_dir="$HOME/.clacky"
|
|
102
|
+
local brand_file="$clacky_dir/brand.yml"
|
|
103
|
+
mkdir -p "$clacky_dir"
|
|
104
|
+
print_step "Configuring brand: $BRAND_NAME"
|
|
105
|
+
cat > "$brand_file" <<YAML
|
|
106
|
+
product_name: "${BRAND_NAME}"
|
|
107
|
+
package_name: "${BRAND_COMMAND}"
|
|
108
|
+
YAML
|
|
109
|
+
print_success "Brand config written to $brand_file"
|
|
110
|
+
|
|
111
|
+
if [ -n "$BRAND_COMMAND" ]; then
|
|
112
|
+
local clacky_bin bin_dir
|
|
113
|
+
clacky_bin=$(command -v openclacky 2>/dev/null || true)
|
|
114
|
+
if [ -n "$clacky_bin" ]; then
|
|
115
|
+
bin_dir=$(dirname "$clacky_bin")
|
|
116
|
+
else
|
|
117
|
+
print_warning "openclacky binary not found in PATH; skipping wrapper install"
|
|
118
|
+
return 0
|
|
119
|
+
fi
|
|
120
|
+
local wrapper="$bin_dir/$BRAND_COMMAND"
|
|
121
|
+
cat > "$wrapper" <<WRAPPER
|
|
122
|
+
#!/bin/sh
|
|
123
|
+
exec openclacky "\$@"
|
|
124
|
+
WRAPPER
|
|
125
|
+
chmod +x "$wrapper"
|
|
126
|
+
print_success "Wrapper installed: $wrapper"
|
|
127
|
+
fi
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
# --------------------------------------------------------------------------
|
|
131
|
+
# Post-install info
|
|
132
|
+
# --------------------------------------------------------------------------
|
|
133
|
+
show_post_install_info() {
|
|
134
|
+
local cmd="${BRAND_COMMAND:-openclacky}"
|
|
135
|
+
echo ""
|
|
136
|
+
echo -e " ${GREEN}${DISPLAY_NAME} installed successfully!${NC}"
|
|
137
|
+
echo ""
|
|
138
|
+
echo " Reload your shell:"
|
|
139
|
+
echo -e " ${YELLOW}source ${SHELL_RC}${NC}"
|
|
140
|
+
echo ""
|
|
141
|
+
echo -e " ${GREEN}Web UI${NC} (recommended):"
|
|
142
|
+
echo " $cmd server"
|
|
143
|
+
echo " Open http://localhost:7070"
|
|
144
|
+
echo ""
|
|
145
|
+
echo -e " ${GREEN}Terminal${NC}:"
|
|
146
|
+
echo " $cmd"
|
|
147
|
+
echo ""
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
# --------------------------------------------------------------------------
|
|
151
|
+
# Main
|
|
152
|
+
# --------------------------------------------------------------------------
|
|
153
|
+
main() {
|
|
154
|
+
parse_args "$@"
|
|
155
|
+
echo ""
|
|
156
|
+
echo "${DISPLAY_NAME} Installation"
|
|
157
|
+
echo ""
|
|
158
|
+
|
|
159
|
+
detect_os
|
|
160
|
+
detect_shell
|
|
161
|
+
detect_network_region
|
|
162
|
+
|
|
163
|
+
assert_supported_os "Please install Ruby >= 2.6.0 manually and run: gem install openclacky"
|
|
164
|
+
|
|
165
|
+
if [ "$OS" = "Linux" ]; then
|
|
166
|
+
setup_apt_mirror
|
|
167
|
+
fi
|
|
168
|
+
|
|
169
|
+
ensure_ruby || { print_error "Could not install a compatible Ruby"; exit 1; }
|
|
170
|
+
install_via_gem && { setup_brand; show_post_install_info; exit 0; }
|
|
171
|
+
print_error "Failed to install ${DISPLAY_NAME}"; exit 1
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
main "$@"
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# install_browser.sh — install Node.js + chrome-devtools-mcp for browser automation
|
|
3
|
+
# Generated from scripts/build/src/install_browser.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/network.sh
|
|
11
|
+
@include lib/mise.sh
|
|
12
|
+
|
|
13
|
+
# Chrome DMG — update CHROME_VERSION when re-uploading a newer build to OSS
|
|
14
|
+
CHROME_VERSION="134"
|
|
15
|
+
DEFAULT_CHROME_DMG_URL="https://dl.google.com/chrome/mac/universal/stable/GGRO/googlechrome.dmg"
|
|
16
|
+
CN_CHROME_DMG_URL="${CN_CDN_BASE_URL}/browsers/googlechrome-mac-${CHROME_VERSION}.dmg"
|
|
17
|
+
|
|
18
|
+
# --------------------------------------------------------------------------
|
|
19
|
+
# Ensure Chrome is installed (macOS only)
|
|
20
|
+
# Downloads DMG to Desktop, opens it, then exits with instructions.
|
|
21
|
+
# Re-run the script after Chrome is installed.
|
|
22
|
+
# --------------------------------------------------------------------------
|
|
23
|
+
ensure_chrome_macos() {
|
|
24
|
+
print_step "Checking Google Chrome..."
|
|
25
|
+
|
|
26
|
+
if [ -d "/Applications/Google Chrome.app" ] || [ -d "$HOME/Applications/Google Chrome.app" ]; then
|
|
27
|
+
print_success "Google Chrome already installed"
|
|
28
|
+
return 0
|
|
29
|
+
fi
|
|
30
|
+
|
|
31
|
+
print_warning "Google Chrome not found — downloading..."
|
|
32
|
+
local dmg_url="$DEFAULT_CHROME_DMG_URL"
|
|
33
|
+
if [ "$USE_CN_MIRRORS" = true ]; then
|
|
34
|
+
dmg_url="$CN_CHROME_DMG_URL"
|
|
35
|
+
print_info "Using OSS mirror (Chrome ${CHROME_VERSION})"
|
|
36
|
+
else
|
|
37
|
+
print_info "Using official Google download"
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
local dmg_path="$HOME/Desktop/googlechrome.dmg"
|
|
41
|
+
print_info "Downloading Chrome (~238 MB) to Desktop..."
|
|
42
|
+
curl -L --progress-bar "$dmg_url" -o "$dmg_path" || {
|
|
43
|
+
print_error "Download failed"
|
|
44
|
+
print_info "Please download manually: ${dmg_url}"
|
|
45
|
+
exit 1
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
print_success "Downloaded: ${dmg_path}"
|
|
49
|
+
print_info "Opening DMG installer..."
|
|
50
|
+
open "$dmg_path"
|
|
51
|
+
echo ""
|
|
52
|
+
print_info "Drag 'Google Chrome' to Applications, then re-run this script."
|
|
53
|
+
exit 0
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
# --------------------------------------------------------------------------
|
|
57
|
+
# install_chrome_devtools_mcp — npm global install
|
|
58
|
+
# --------------------------------------------------------------------------
|
|
59
|
+
install_chrome_devtools_mcp() {
|
|
60
|
+
print_step "Installing chrome-devtools-mcp..."
|
|
61
|
+
|
|
62
|
+
if [ "$USE_CN_MIRRORS" = true ]; then
|
|
63
|
+
npm config set registry "$NPM_REGISTRY_URL" 2>/dev/null || true
|
|
64
|
+
print_info "npm registry → ${NPM_REGISTRY_URL}"
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
if npm install -g chrome-devtools-mcp@latest 2>/dev/null; then
|
|
68
|
+
print_success "chrome-devtools-mcp installed"
|
|
69
|
+
else
|
|
70
|
+
print_error "chrome-devtools-mcp installation failed"
|
|
71
|
+
print_info "Try manually: npm install -g chrome-devtools-mcp@latest"
|
|
72
|
+
return 1
|
|
73
|
+
fi
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
# --------------------------------------------------------------------------
|
|
77
|
+
# Main
|
|
78
|
+
# --------------------------------------------------------------------------
|
|
79
|
+
main() {
|
|
80
|
+
echo ""
|
|
81
|
+
echo "Browser Automation Setup"
|
|
82
|
+
echo "========================"
|
|
83
|
+
|
|
84
|
+
detect_os
|
|
85
|
+
detect_shell
|
|
86
|
+
detect_network_region
|
|
87
|
+
|
|
88
|
+
is_macos && ensure_chrome_macos
|
|
89
|
+
|
|
90
|
+
print_step "Checking Node.js..."
|
|
91
|
+
ensure_mise || exit 1
|
|
92
|
+
install_node_via_mise || exit 1
|
|
93
|
+
|
|
94
|
+
install_chrome_devtools_mcp || exit 1
|
|
95
|
+
|
|
96
|
+
echo ""
|
|
97
|
+
print_success "Done. Browser automation is ready."
|
|
98
|
+
echo ""
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
main "$@"
|