@@ -25,28 +25,60 @@ REPO="agentralabs/codebase"
2525BINARY_NAME=" acb-mcp"
2626SERVER_KEY=" agentic-codebase"
2727INSTALL_DIR=" $HOME /.local/bin"
28+ INSTALL_DIR_EXPLICIT=false
2829VERSION=" latest"
2930PROFILE=" ${AGENTRA_INSTALL_PROFILE:- desktop} "
3031DRY_RUN=false
3132BAR_ONLY=" ${AGENTRA_INSTALL_BAR_ONLY:- 1} "
3233MCP_ENTRYPOINT=" "
34+ HOST_OS=" "
3335SERVER_ARGS_JSON=' []'
3436SERVER_ARGS_TEXT=' []'
3537SERVER_CHECK_CMD_SUFFIX=" "
3638MCP_CONFIGURED_CLIENTS=()
3739MCP_SCANNED_CONFIG_FILES=()
3840
3941# ── Parse arguments ──────────────────────────────────────────────────
40- for arg in " $@ " ; do
41- case " $arg " in
42- --version=* ) VERSION=" ${arg#* =} " ;;
43- --dir=* ) INSTALL_DIR=" ${arg#* =} " ;;
44- --profile=* ) PROFILE=" ${arg#* =} " ;;
45- --dry-run) DRY_RUN=true ;;
42+ while [ $# -gt 0 ]; do
43+ case " $1 " in
44+ --version=* )
45+ VERSION=" ${1#* =} "
46+ shift
47+ ;;
48+ --version)
49+ VERSION=" ${2:- } "
50+ shift 2
51+ ;;
52+ --dir=* )
53+ INSTALL_DIR=" ${1#* =} "
54+ INSTALL_DIR_EXPLICIT=true
55+ shift
56+ ;;
57+ --dir)
58+ INSTALL_DIR=" ${2:- } "
59+ INSTALL_DIR_EXPLICIT=true
60+ shift 2
61+ ;;
62+ --profile=* )
63+ PROFILE=" ${1#* =} "
64+ shift
65+ ;;
66+ --profile)
67+ PROFILE=" ${2:- } "
68+ shift 2
69+ ;;
70+ --dry-run)
71+ DRY_RUN=true
72+ shift
73+ ;;
4674 --help|-h)
47- echo " Usage: install.sh [--version=X.Y.Z] [--dir=/path] [--profile=desktop|terminal|server] [--dry-run]"
75+ echo " Usage: install.sh [--version X.Y.Z|--version =X.Y.Z] [--dir /path|--dir =/path] [--profile desktop|terminal|server| --profile=desktop|terminal|server] [--dry-run]"
4876 exit 0
4977 ;;
78+ * )
79+ echo " Error: unknown option '$1 '" >&2
80+ exit 1
81+ ;;
5082 esac
5183done
5284
@@ -136,6 +168,7 @@ detect_platform() {
136168 case " $os " in
137169 darwin) os=" darwin" ;;
138170 linux) os=" linux" ;;
171+ msys* |mingw* |cygwin* |windows_nt) os=" windows" ;;
139172 * ) echo " Error: Unsupported OS: $os " >&2 ; exit 1 ;;
140173 esac
141174
@@ -145,20 +178,21 @@ detect_platform() {
145178 * ) echo " Error: Unsupported architecture: $arch " >&2 ; exit 1 ;;
146179 esac
147180
181+ HOST_OS=" $os "
148182 echo " ${os} -${arch} "
149183}
150184
151185# ── Check dependencies ────────────────────────────────────────────────
152186check_deps () {
153- for cmd in curl jq ; do
154- if ! command -v " $cmd " & > /dev/null ; then
155- echo " Error: ' $cmd ' is required but not installed. " >&2
156- if [ " $cmd " = " jq " ] ; then
157- echo " Install: brew install jq (macOS) or apt install jq (Linux) " >&2
158- fi
159- exit 1
160- fi
161- done
187+ if ! command -v curl & > /dev/null ; then
188+ echo " Error: 'curl' is required but not installed. " >&2
189+ exit 1
190+ fi
191+ if ! command -v jq & > /dev/null && ! command -v python3 & > /dev/null ; then
192+ echo " Error: JSON merge requires 'jq' or 'python3'. " >&2
193+ echo " Install jq (preferred) or python3, then rerun. " >&2
194+ exit 1
195+ fi
162196}
163197
164198# ── Get latest release tag (empty when unavailable) ──────────────────
@@ -279,13 +313,15 @@ args=("\$@")
279313has_graph=0
280314has_name=0
281315has_command=0
316+ serve_requested=0
282317
283318for arg in "\$ {args[@]}"; do
284319 case "\$ arg" in
285320 -h|--help|-V|--version) has_command=1 ;;
286321 --graph|--graph=*|-g) has_graph=1 ;;
287322 --name|--name=*) has_name=1 ;;
288- serve|help) has_command=1 ;;
323+ serve) has_command=1; serve_requested=1 ;;
324+ help) has_command=1 ;;
289325 esac
290326done
291327
@@ -301,14 +337,59 @@ if [ "\$has_graph" -eq 0 ]; then
301337fi
302338
303339if [ "\$ has_command" -eq 0 ]; then
340+ serve_requested=1
304341 args+=("serve")
305342fi
306343
344+ if [ "\$ serve_requested" -eq 1 ]; then
345+ if [ "\$ {AGENTRA_RUNTIME_MODE:-}" = "server" ] || [ "\$ {AGENTRA_SERVER:-}" = "1" ] || [ "\$ {AGENTRA_INSTALL_PROFILE:-}" = "server" ]; then
346+ if [ -z "\$ {AGENTIC_TOKEN:-}" ] && [ -z "\$ {AGENTIC_TOKEN_FILE:-}" ] && [ -z "\$ {AGENTRA_AUTH_TOKEN_FILE:-}" ]; then
347+ echo "Error: server mode requires AGENTIC_TOKEN or AGENTIC_TOKEN_FILE." >&2
348+ exit 2
349+ fi
350+ fi
351+ fi
352+
307353exec "\$ BIN" "\$ {args[@]}"
308354EOF
309355 chmod +x " ${MCP_ENTRYPOINT} "
310356}
311357
358+ merge_config_with_python () {
359+ local config_file=" $1 "
360+ python3 - " $config_file " " $SERVER_KEY " " $MCP_ENTRYPOINT " " $SERVER_ARGS_JSON " << 'PY '
361+ import json
362+ import os
363+ import sys
364+
365+ path, key, command, args_json = sys.argv[1:]
366+ args = json.loads(args_json)
367+ cfg = {}
368+
369+ if os.path.exists(path) and os.path.getsize(path) > 0:
370+ try:
371+ with open(path, "r", encoding="utf-8") as handle:
372+ loaded = json.load(handle)
373+ if isinstance(loaded, dict):
374+ cfg = loaded
375+ except Exception:
376+ cfg = {}
377+
378+ mcp = cfg.get("mcpServers")
379+ if not isinstance(mcp, dict):
380+ mcp = {}
381+ cfg["mcpServers"] = mcp
382+ mcp[key] = {"command": command, "args": args}
383+
384+ os.makedirs(os.path.dirname(path), exist_ok=True)
385+ tmp = f"{path}.tmp"
386+ with open(tmp, "w", encoding="utf-8") as handle:
387+ json.dump(cfg, handle, indent=2)
388+ handle.write("\n")
389+ os.replace(tmp, path)
390+ PY
391+ }
392+
312393# ── Merge MCP server into a config file ───────────────────────────────
313394# Uses jq to add our server WITHOUT touching other servers.
314395merge_config () {
@@ -323,20 +404,25 @@ merge_config() {
323404
324405 mkdir -p " $config_dir "
325406
326- if [ -f " $config_file " ] && [ -s " $config_file " ]; then
327- echo " Existing config found, merging..."
328- jq --arg key " $SERVER_KEY " \
329- --arg cmd " ${MCP_ENTRYPOINT} " \
330- --argjson args " $SERVER_ARGS_JSON " \
331- ' .mcpServers //= {} | .mcpServers[$key] = {"command": $cmd, "args": $args}' \
332- " $config_file " > " $config_file .tmp" && mv " $config_file .tmp" " $config_file "
407+ if command -v jq > /dev/null 2>&1 ; then
408+ if [ -f " $config_file " ] && [ -s " $config_file " ]; then
409+ echo " Existing config found, merging..."
410+ jq --arg key " $SERVER_KEY " \
411+ --arg cmd " ${MCP_ENTRYPOINT} " \
412+ --argjson args " $SERVER_ARGS_JSON " \
413+ ' .mcpServers //= {} | .mcpServers[$key] = {"command": $cmd, "args": $args}' \
414+ " $config_file " > " $config_file .tmp" && mv " $config_file .tmp" " $config_file "
415+ else
416+ echo " Creating new config..."
417+ jq -n --arg key " $SERVER_KEY " \
418+ --arg cmd " ${MCP_ENTRYPOINT} " \
419+ --argjson args " $SERVER_ARGS_JSON " \
420+ ' { "mcpServers": { ($key): { "command": $cmd, "args": $args } } }' \
421+ > " $config_file "
422+ fi
333423 else
334- echo " Creating new config..."
335- jq -n --arg key " $SERVER_KEY " \
336- --arg cmd " ${MCP_ENTRYPOINT} " \
337- --argjson args " $SERVER_ARGS_JSON " \
338- ' { "mcpServers": { ($key): { "command": $cmd, "args": $args } } }' \
339- > " $config_file "
424+ echo " Merging with python3 fallback..."
425+ merge_config_with_python " $config_file "
340426 fi
341427}
342428
@@ -404,9 +490,11 @@ configure_json_client_if_present() {
404490# ── Configure Claude Desktop ─────────────────────────────────────────
405491configure_claude_desktop () {
406492 local config_file
407- case " $( uname -s ) " in
493+ case " ${HOST_OS} " in
408494 Darwin) config_file=" $HOME /Library/Application Support/Claude/claude_desktop_config.json" ;;
409- Linux) config_file=" ${XDG_CONFIG_HOME:- $HOME / .config} /Claude/claude_desktop_config.json" ;;
495+ darwin) config_file=" $HOME /Library/Application Support/Claude/claude_desktop_config.json" ;;
496+ Linux|linux) config_file=" ${XDG_CONFIG_HOME:- $HOME / .config} /Claude/claude_desktop_config.json" ;;
497+ windows) config_file=" ${APPDATA:- $HOME / AppData/ Roaming} /Claude/claude_desktop_config.json" ;;
410498 * ) return ;;
411499 esac
412500
@@ -467,6 +555,8 @@ configure_generic_mcp_json_files() {
467555 local roots=(
468556 " $HOME /.config"
469557 " $HOME /Library/Application Support"
558+ " ${APPDATA:- $HOME / AppData/ Roaming} "
559+ " ${LOCALAPPDATA:- $HOME / AppData/ Local} "
470560 " $HOME /.cursor"
471561 " $HOME /.windsurf"
472562 " $HOME /.codeium"
@@ -497,10 +587,16 @@ configure_mcp_clients() {
497587 configure_json_client_if_present " Cursor" " $HOME /.cursor/mcp.json" " $HOME /.cursor"
498588 configure_json_client_if_present " Windsurf" " $HOME /.windsurf/mcp.json" " $HOME /.windsurf"
499589 configure_json_client_if_present " Windsurf (Codeium)" " $HOME /.codeium/windsurf/mcp_config.json" " $HOME /.codeium/windsurf"
500- if [ " $( uname -s ) " = " Darwin " ]; then
590+ if [ " ${HOST_OS} " = " darwin " ]; then
501591 configure_json_client_if_present " VS Code" " $HOME /Library/Application Support/Code/User/mcp.json" " $HOME /Library/Application Support/Code/User"
502592 configure_json_client_if_present " VS Code + Cline" " $HOME /Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json" " $HOME /Library/Application Support/Code/User/globalStorage/saoudrizwan.claude-dev"
503593 configure_json_client_if_present " VSCodium" " $HOME /Library/Application Support/VSCodium/User/mcp.json" " $HOME /Library/Application Support/VSCodium/User"
594+ elif [ " ${HOST_OS} " = " windows" ]; then
595+ configure_json_client_if_present " Cursor" " ${APPDATA:- $HOME / AppData/ Roaming} /Cursor/User/mcp.json" " ${APPDATA:- $HOME / AppData/ Roaming} /Cursor/User"
596+ configure_json_client_if_present " Windsurf" " ${APPDATA:- $HOME / AppData/ Roaming} /Windsurf/User/mcp.json" " ${APPDATA:- $HOME / AppData/ Roaming} /Windsurf/User"
597+ configure_json_client_if_present " VS Code" " ${APPDATA:- $HOME / AppData/ Roaming} /Code/User/mcp.json" " ${APPDATA:- $HOME / AppData/ Roaming} /Code/User"
598+ configure_json_client_if_present " VS Code + Cline" " ${APPDATA:- $HOME / AppData/ Roaming} /Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json" " ${APPDATA:- $HOME / AppData/ Roaming} /Code/User/globalStorage/saoudrizwan.claude-dev"
599+ configure_json_client_if_present " VSCodium" " ${APPDATA:- $HOME / AppData/ Roaming} /VSCodium/User/mcp.json" " ${APPDATA:- $HOME / AppData/ Roaming} /VSCodium/User"
504600 else
505601 configure_json_client_if_present " VS Code" " ${XDG_CONFIG_HOME:- $HOME / .config} /Code/User/mcp.json" " ${XDG_CONFIG_HOME:- $HOME / .config} /Code/User"
506602 configure_json_client_if_present " VS Code + Cline" " ${XDG_CONFIG_HOME:- $HOME / .config} /Code/User/globalStorage/saoudrizwan.claude-dev/settings/cline_mcp_settings.json" " ${XDG_CONFIG_HOME:- $HOME / .config} /Code/User/globalStorage/saoudrizwan.claude-dev"
@@ -594,9 +690,9 @@ check_path() {
594690 if [[ " :$PATH :" != * " :$INSTALL_DIR :" * ]]; then
595691 echo " "
596692 echo " Note: Add ${INSTALL_DIR} to your PATH if not already:"
597- echo " export PATH=\"\$ HOME/.local/bin :\$ PATH\" "
693+ echo " export PATH=\" ${INSTALL_DIR} :\$ PATH\" "
598694 echo " "
599- echo " Add this line to your ~/.zshrc or ~/.bashrc to make it permanent."
695+ echo " Add this line to your shell profile to make it permanent."
600696 fi
601697}
602698
@@ -616,6 +712,11 @@ main() {
616712 echo " Platform: ${platform} "
617713 validate_profile
618714 echo " Profile: ${PROFILE} "
715+ if [ " ${HOST_OS} " = " windows" ] && [ " $INSTALL_DIR_EXPLICIT " = false ]; then
716+ INSTALL_DIR=" ${HOME} /.agentra/bin"
717+ fi
718+ MCP_ENTRYPOINT=" ${INSTALL_DIR} /${BINARY_NAME} -agentra"
719+ echo " Install dir: ${INSTALL_DIR} "
619720
620721 set_progress 30 " Resolving release"
621722 local installed_from_release=false
0 commit comments