-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathinstall.sh
More file actions
194 lines (177 loc) · 7.98 KB
/
Copy pathinstall.sh
File metadata and controls
194 lines (177 loc) · 7.98 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
#!/bin/sh
# moshcode — one-line installer 🤘
#
# Usage:
# curl -fsSL https://moshcoding.com/install.sh | sh
# curl -fsSL https://moshcoding.com/install.sh | sh -s -- update (alias: upgrade)
# curl -fsSL https://moshcoding.com/install.sh | sh -s -- remove (alias: uninstall)
#
# (also works straight from GitHub:)
# curl -fsSL https://raw.githubusercontent.com/moshcoder/moshcode/main/install.sh | sh
#
# What it does — dead simple, no build step:
# 1. Checks for Node.js 18+ (moshcode is zero-dependency ESM — needs a node).
# 2. Downloads the latest release tarball of moshcoder/moshcode from GitHub
# (falls back to the main branch if no release is published yet).
# 3. Unpacks it to $MOSHCODE_HOME (default: $HOME/.moshcode).
# 4. Drops a `moshcode` wrapper at $MOSHCODE_BIN (default: $HOME/.local/bin)
# that just exec's `node $MOSHCODE_HOME/bin/moshcode.mjs "$@"`.
# 5. Ensures that bin dir is on your PATH.
#
# Env overrides:
# MOSHCODE_HOME=/path install dir (default: $HOME/.moshcode)
# MOSHCODE_BIN=/path/dir wrapper bin dir (default: $HOME/.local/bin)
# MOSHCODE_REF=vX.Y.Z pin a tag/branch (default: latest release, else main)
# MOSHCODE_ALLOW_ROOT=1 install as root anyway (see below)
#
# Do not install this with sudo. moshcode is a user-level CLI, and every path
# here is derived from $HOME — under sudo that is /root, so the payload and the
# wrapper land in root's home where your own user cannot read them. Nothing
# fails at install time; it surfaces later as "permission denied" on a binary
# that looks installed. The installer refuses that case and tells you how.
#
# Re-running updates an existing install in place.
set -eu
REPO="moshcoder/moshcode"
INSTALL_URL="https://moshcoding.com/install.sh"
MOSHCODE_HOME="${MOSHCODE_HOME:-$HOME/.moshcode}"
MOSHCODE_BIN="${MOSHCODE_BIN:-$HOME/.local/bin}"
WRAPPER="$MOSHCODE_BIN/moshcode"
SCRIPT_WRAPPER="$MOSHCODE_BIN/moshscript"
# ---- pretty output (acid-lime, matching the CLI) --------------------------
if [ -t 1 ] && [ -z "${NO_COLOR:-}" ]; then
ACID=$(printf '\033[38;2;158;240;26m'); ASH=$(printf '\033[38;2;139;147;138m')
RED=$(printf '\033[31m'); BOLD=$(printf '\033[1m'); RESET=$(printf '\033[0m')
else
ACID=''; ASH=''; RED=''; BOLD=''; RESET=''
fi
info() { printf '%s·%s %s\n' "$ASH" "$RESET" "$*"; }
ok() { printf '%s✓%s %s\n' "$ACID" "$RESET" "$*"; }
fail() { printf '%s✗%s %s\n' "$RED" "$RESET" "$*" >&2; exit 1; }
# ---- prerequisites --------------------------------------------------------
need() { command -v "$1" >/dev/null 2>&1 || fail "$1 is required but not found."; }
# Installing under sudo silently installs for the wrong user. Every path here
# comes from $HOME, which sudo sets to /root, so the payload and wrappers land
# in a directory mode 0700 root — invisible to the user who ran the command.
# The install reports success and only breaks later, at first use.
#
# A bare root shell (containers, CI images, root-only boxes) has no SUDO_USER
# and is a legitimate way to install, so only the sudo-from-a-real-user case is
# refused, and MOSHCODE_ALLOW_ROOT overrides even that.
check_not_sudo() {
[ "$(id -u)" = "0" ] || return 0
[ -n "${SUDO_USER:-}" ] || return 0
if [ -n "${MOSHCODE_ALLOW_ROOT:-}" ]; then
info "MOSHCODE_ALLOW_ROOT set — installing as root into $MOSHCODE_HOME"
return 0
fi
fail "don't install moshcode with sudo.
Every path is based on \$HOME, which sudo has set to $HOME, so this would
install for root and leave $SUDO_USER unable to run it.
Run it as yourself instead:
curl -fsSL $INSTALL_URL | sh
If you really do want it system-wide, choose the paths explicitly:
sudo MOSHCODE_ALLOW_ROOT=1 MOSHCODE_HOME=/opt/moshcode \\
MOSHCODE_BIN=/usr/local/bin sh -c 'curl -fsSL $INSTALL_URL | sh'"
}
check_node() {
command -v node >/dev/null 2>&1 || fail \
"Node.js 18+ is required. Install it (https://nodejs.org) and re-run."
_major="$(node -v 2>/dev/null | sed 's/^v//' | cut -d. -f1)"
[ "${_major:-0}" -ge 18 ] || fail "Node.js 18+ required, found $(node -v)."
ok "Node.js $(node -v)"
unset _major
}
# Resolve the download URL for the latest release tag, or fall back to main.
resolve_ref() {
if [ -n "${MOSHCODE_REF:-}" ]; then
echo "$MOSHCODE_REF"; return 0
fi
# Ask GitHub for the latest release tag (no auth needed for public repos).
_tag="$(curl -fsSL "https://api.github.com/repos/$REPO/releases/latest" 2>/dev/null \
| grep '"tag_name"' | head -1 | sed 's/.*"tag_name":[[:space:]]*"\([^"]*\)".*/\1/')"
if [ -n "$_tag" ]; then echo "$_tag"; else echo "main"; fi
unset _tag
}
fetch_and_unpack() {
_ref="$1"
_url="https://codeload.github.com/$REPO/tar.gz/$_ref"
info "downloading moshcode@$_ref"
_tmp="$(mktemp -d 2>/dev/null || mktemp -d -t moshcode)"
if ! curl -fsSL "$_url" | tar -xz -C "$_tmp" 2>/dev/null; then
rm -rf "$_tmp"; fail "download failed ($_url) — check the ref/network."
fi
# Tarball extracts to a single top-level dir (e.g. moshcode-main/).
_src="$(find "$_tmp" -maxdepth 1 -type d -name 'moshcode-*' | head -1)"
[ -n "$_src" ] && [ -f "$_src/bin/moshcode.mjs" ] || { rm -rf "$_tmp"; fail "unexpected tarball layout."; }
rm -rf "$MOSHCODE_HOME"
mkdir -p "$(dirname "$MOSHCODE_HOME")"
mv "$_src" "$MOSHCODE_HOME"
rm -rf "$_tmp"
chmod +x "$MOSHCODE_HOME/bin/moshcode.mjs" 2>/dev/null || true
ok "installed to $MOSHCODE_HOME"
unset _ref _url _tmp _src
}
write_wrapper() {
mkdir -p "$MOSHCODE_BIN"
cat > "$WRAPPER" <<WRAP_EOF
#!/bin/sh
# moshcode wrapper — installed by $INSTALL_URL. Re-run the installer to update.
exec node "$MOSHCODE_HOME/bin/moshcode.mjs" "\$@"
WRAP_EOF
chmod +x "$WRAPPER"
ok "wrapper at $WRAPPER"
# moshscript — thin alias for `moshcode run`, so .mosh files can use
# #!/usr/bin/env moshscript as a shebang and run like shell scripts.
cat > "$SCRIPT_WRAPPER" <<SCRIPT_EOF
#!/bin/sh
# moshscript wrapper — installed by $INSTALL_URL. Re-run the installer to update.
exec node "$MOSHCODE_HOME/bin/moshcode.mjs" run "\$@"
SCRIPT_EOF
chmod +x "$SCRIPT_WRAPPER"
ok "wrapper at $SCRIPT_WRAPPER"
}
ensure_path() {
case ":$PATH:" in *":$MOSHCODE_BIN:"*) return 0 ;; esac
for rc in "$HOME/.bashrc" "$HOME/.zshrc" "$HOME/.profile"; do
[ -f "$rc" ] || continue
grep -q "$MOSHCODE_BIN" "$rc" 2>/dev/null && continue
printf '\n# Added by moshcode installer\nexport PATH="%s:$PATH"\n' "$MOSHCODE_BIN" >> "$rc"
done
info "add $MOSHCODE_BIN to PATH in this shell: export PATH=\"$MOSHCODE_BIN:\$PATH\""
}
# ---- commands -------------------------------------------------------------
run_install() {
printf '\n%smoshcode installer%s %s— code hard, mosh harder 🤘%s\n\n' "$BOLD" "$RESET" "$ASH" "$RESET"
check_not_sudo
need curl; need tar
check_node
_ref="$(resolve_ref)"
fetch_and_unpack "$_ref"
write_wrapper
ensure_path
printf '\n%sdone.%s run:\n' "$ACID" "$RESET"
printf ' moshcode # open the TUI shell\n'
printf ' moshcode start claude # raw engine session (use agents for autonomous)\n'
printf ' moshcode prd "your idea" # plan with a numbered OpenPRD\n'
printf ' moshcode tools # install/run UGig and CoinPay CLIs\n'
printf ' moshcode help\n\n'
unset _ref
}
run_remove() {
info "removing moshcode"
rm -f "$WRAPPER" 2>/dev/null || true
rm -f "$SCRIPT_WRAPPER" 2>/dev/null || true
rm -rf "$MOSHCODE_HOME" 2>/dev/null || true
ok "removed $WRAPPER, $SCRIPT_WRAPPER, and $MOSHCODE_HOME. 🤘"
}
CMD="${1:-install}"
if [ $# -gt 0 ]; then shift; fi
case "$CMD" in
install) run_install ;;
update|upgrade) run_install ;; # re-fetch latest, same path
remove|uninstall) run_remove ;;
-h|--help|help)
sed -n '2,33p' "$0" 2>/dev/null || printf 'moshcode installer — install | update | remove\n' ;;
*) fail "unknown command: $CMD (try: install | update | remove)" ;;
esac