@hexidecibel/companion 0.0.1
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.
- package/dist/__tests__/task-parser.test.d.ts +2 -0
- package/dist/__tests__/task-parser.test.d.ts.map +1 -0
- package/dist/__tests__/task-parser.test.js +79 -0
- package/dist/__tests__/task-parser.test.js.map +1 -0
- package/dist/anthropic-usage.d.ts +5 -0
- package/dist/anthropic-usage.d.ts.map +1 -0
- package/dist/anthropic-usage.js +112 -0
- package/dist/anthropic-usage.js.map +1 -0
- package/dist/cert-generator.d.ts +15 -0
- package/dist/cert-generator.d.ts.map +1 -0
- package/dist/cert-generator.js +298 -0
- package/dist/cert-generator.js.map +1 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +122 -0
- package/dist/config.js.map +1 -0
- package/dist/encryption.d.ts +28 -0
- package/dist/encryption.d.ts.map +1 -0
- package/dist/encryption.js +95 -0
- package/dist/encryption.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +211 -0
- package/dist/index.js.map +1 -0
- package/dist/input-injector.d.ts +21 -0
- package/dist/input-injector.d.ts.map +1 -0
- package/dist/input-injector.js +126 -0
- package/dist/input-injector.js.map +1 -0
- package/dist/mdns.d.ts +11 -0
- package/dist/mdns.d.ts.map +1 -0
- package/dist/mdns.js +93 -0
- package/dist/mdns.js.map +1 -0
- package/dist/parser.d.ts +43 -0
- package/dist/parser.d.ts.map +1 -0
- package/dist/parser.js +800 -0
- package/dist/parser.js.map +1 -0
- package/dist/push.d.ts +38 -0
- package/dist/push.d.ts.map +1 -0
- package/dist/push.js +359 -0
- package/dist/push.js.map +1 -0
- package/dist/qr-server.d.ts +13 -0
- package/dist/qr-server.d.ts.map +1 -0
- package/dist/qr-server.js +421 -0
- package/dist/qr-server.js.map +1 -0
- package/dist/scaffold/generator.d.ts +11 -0
- package/dist/scaffold/generator.d.ts.map +1 -0
- package/dist/scaffold/generator.js +206 -0
- package/dist/scaffold/generator.js.map +1 -0
- package/dist/scaffold/templates/index.d.ts +5 -0
- package/dist/scaffold/templates/index.d.ts.map +1 -0
- package/dist/scaffold/templates/index.js +22 -0
- package/dist/scaffold/templates/index.js.map +1 -0
- package/dist/scaffold/templates/node-express.d.ts +3 -0
- package/dist/scaffold/templates/node-express.d.ts.map +1 -0
- package/dist/scaffold/templates/node-express.js +218 -0
- package/dist/scaffold/templates/node-express.js.map +1 -0
- package/dist/scaffold/templates/python-fastapi.d.ts +3 -0
- package/dist/scaffold/templates/python-fastapi.d.ts.map +1 -0
- package/dist/scaffold/templates/python-fastapi.js +302 -0
- package/dist/scaffold/templates/python-fastapi.js.map +1 -0
- package/dist/scaffold/templates/react-mui-website.d.ts +3 -0
- package/dist/scaffold/templates/react-mui-website.d.ts.map +1 -0
- package/dist/scaffold/templates/react-mui-website.js +405 -0
- package/dist/scaffold/templates/react-mui-website.js.map +1 -0
- package/dist/scaffold/templates/react-typescript.d.ts +3 -0
- package/dist/scaffold/templates/react-typescript.d.ts.map +1 -0
- package/dist/scaffold/templates/react-typescript.js +275 -0
- package/dist/scaffold/templates/react-typescript.js.map +1 -0
- package/dist/scaffold/types.d.ts +55 -0
- package/dist/scaffold/types.d.ts.map +1 -0
- package/dist/scaffold/types.js +3 -0
- package/dist/scaffold/types.js.map +1 -0
- package/dist/subagent-watcher.d.ts +24 -0
- package/dist/subagent-watcher.d.ts.map +1 -0
- package/dist/subagent-watcher.js +307 -0
- package/dist/subagent-watcher.js.map +1 -0
- package/dist/tls.d.ts +10 -0
- package/dist/tls.d.ts.map +1 -0
- package/dist/tls.js +77 -0
- package/dist/tls.js.map +1 -0
- package/dist/tmux-manager.d.ts +71 -0
- package/dist/tmux-manager.d.ts.map +1 -0
- package/dist/tmux-manager.js +243 -0
- package/dist/tmux-manager.js.map +1 -0
- package/dist/tool-config.d.ts +33 -0
- package/dist/tool-config.d.ts.map +1 -0
- package/dist/tool-config.js +211 -0
- package/dist/tool-config.js.map +1 -0
- package/dist/types.d.ts +218 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/watcher.d.ts +63 -0
- package/dist/watcher.d.ts.map +1 -0
- package/dist/watcher.js +596 -0
- package/dist/watcher.js.map +1 -0
- package/dist/watcher.test.d.ts +2 -0
- package/dist/watcher.test.d.ts.map +1 -0
- package/dist/watcher.test.js +110 -0
- package/dist/watcher.test.js.map +1 -0
- package/dist/websocket.d.ts +62 -0
- package/dist/websocket.d.ts.map +1 -0
- package/dist/websocket.js +1695 -0
- package/dist/websocket.js.map +1 -0
- package/package.json +71 -0
- package/scripts/build.sh +23 -0
- package/scripts/install-remote.sh +18 -0
- package/scripts/install.sh +558 -0
- package/scripts/uninstall.sh +113 -0
|
@@ -0,0 +1,558 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# Colors for output
|
|
5
|
+
RED='\033[0;31m'
|
|
6
|
+
GREEN='\033[0;32m'
|
|
7
|
+
YELLOW='\033[1;33m'
|
|
8
|
+
BLUE='\033[0;34m'
|
|
9
|
+
NC='\033[0m' # No Color
|
|
10
|
+
|
|
11
|
+
echo -e "${BLUE}"
|
|
12
|
+
echo "╔══════════════════════════════════════════════════════════════╗"
|
|
13
|
+
echo "║ Companion Daemon Installer ║"
|
|
14
|
+
echo "╚══════════════════════════════════════════════════════════════╝"
|
|
15
|
+
echo -e "${NC}"
|
|
16
|
+
|
|
17
|
+
# Detect OS
|
|
18
|
+
detect_os() {
|
|
19
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
20
|
+
OS="macos"
|
|
21
|
+
PACKAGE_MANAGER="brew"
|
|
22
|
+
elif [[ -f /etc/debian_version ]]; then
|
|
23
|
+
OS="debian"
|
|
24
|
+
PACKAGE_MANAGER="apt"
|
|
25
|
+
elif [[ -f /etc/redhat-release ]]; then
|
|
26
|
+
OS="redhat"
|
|
27
|
+
PACKAGE_MANAGER="dnf"
|
|
28
|
+
# Fall back to yum for older systems
|
|
29
|
+
if ! command -v dnf &> /dev/null; then
|
|
30
|
+
PACKAGE_MANAGER="yum"
|
|
31
|
+
fi
|
|
32
|
+
elif [[ -f /etc/arch-release ]]; then
|
|
33
|
+
OS="arch"
|
|
34
|
+
PACKAGE_MANAGER="pacman"
|
|
35
|
+
elif [[ -f /etc/alpine-release ]]; then
|
|
36
|
+
OS="alpine"
|
|
37
|
+
PACKAGE_MANAGER="apk"
|
|
38
|
+
else
|
|
39
|
+
OS="unknown"
|
|
40
|
+
PACKAGE_MANAGER="unknown"
|
|
41
|
+
fi
|
|
42
|
+
echo -e "${GREEN}Detected OS:${NC} $OS ($PACKAGE_MANAGER)"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
# Check if running as root/sudo (not needed on macOS for user install)
|
|
46
|
+
check_permissions() {
|
|
47
|
+
if [[ "$OS" == "macos" ]]; then
|
|
48
|
+
# macOS: running as user is fine for user-level install
|
|
49
|
+
ACTUAL_USER="$USER"
|
|
50
|
+
ACTUAL_HOME="$HOME"
|
|
51
|
+
INSTALL_DIR="$HOME/.companion"
|
|
52
|
+
CONFIG_DIR="$HOME/.companion"
|
|
53
|
+
NEEDS_SUDO=false
|
|
54
|
+
else
|
|
55
|
+
# Linux: prefer system-wide install with sudo
|
|
56
|
+
if [ "$EUID" -ne 0 ]; then
|
|
57
|
+
echo -e "${YELLOW}Running without sudo - will install to user directory${NC}"
|
|
58
|
+
ACTUAL_USER="$USER"
|
|
59
|
+
ACTUAL_HOME="$HOME"
|
|
60
|
+
INSTALL_DIR="$HOME/.companion"
|
|
61
|
+
CONFIG_DIR="$HOME/.companion"
|
|
62
|
+
NEEDS_SUDO=false
|
|
63
|
+
else
|
|
64
|
+
ACTUAL_USER="${SUDO_USER:-$USER}"
|
|
65
|
+
ACTUAL_HOME=$(eval echo "~$ACTUAL_USER")
|
|
66
|
+
INSTALL_DIR="/opt/companion"
|
|
67
|
+
CONFIG_DIR="/etc/companion"
|
|
68
|
+
NEEDS_SUDO=true
|
|
69
|
+
fi
|
|
70
|
+
fi
|
|
71
|
+
|
|
72
|
+
echo -e "${GREEN}Installing for user:${NC} $ACTUAL_USER"
|
|
73
|
+
echo -e "${GREEN}Install directory:${NC} $INSTALL_DIR"
|
|
74
|
+
echo -e "${GREEN}Config directory:${NC} $CONFIG_DIR"
|
|
75
|
+
echo ""
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
# Install system dependencies
|
|
79
|
+
install_dependencies() {
|
|
80
|
+
echo -e "${BLUE}Checking dependencies...${NC}"
|
|
81
|
+
|
|
82
|
+
local DEPS_TO_INSTALL=()
|
|
83
|
+
|
|
84
|
+
# Check Node.js
|
|
85
|
+
if ! command -v node &> /dev/null; then
|
|
86
|
+
DEPS_TO_INSTALL+=("nodejs")
|
|
87
|
+
else
|
|
88
|
+
NODE_VERSION=$(node -v)
|
|
89
|
+
echo -e " ${GREEN}✓${NC} Node.js $NODE_VERSION"
|
|
90
|
+
fi
|
|
91
|
+
|
|
92
|
+
# Check npm
|
|
93
|
+
if ! command -v npm &> /dev/null; then
|
|
94
|
+
DEPS_TO_INSTALL+=("npm")
|
|
95
|
+
else
|
|
96
|
+
NPM_VERSION=$(npm -v)
|
|
97
|
+
echo -e " ${GREEN}✓${NC} npm $NPM_VERSION"
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# Check tmux
|
|
101
|
+
if ! command -v tmux &> /dev/null; then
|
|
102
|
+
DEPS_TO_INSTALL+=("tmux")
|
|
103
|
+
else
|
|
104
|
+
TMUX_VERSION=$(tmux -V)
|
|
105
|
+
echo -e " ${GREEN}✓${NC} $TMUX_VERSION"
|
|
106
|
+
fi
|
|
107
|
+
|
|
108
|
+
# Check git (needed for clone)
|
|
109
|
+
if ! command -v git &> /dev/null; then
|
|
110
|
+
DEPS_TO_INSTALL+=("git")
|
|
111
|
+
else
|
|
112
|
+
echo -e " ${GREEN}✓${NC} git $(git --version | cut -d' ' -f3)"
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# Check openssl (for token generation)
|
|
116
|
+
if ! command -v openssl &> /dev/null; then
|
|
117
|
+
DEPS_TO_INSTALL+=("openssl")
|
|
118
|
+
else
|
|
119
|
+
echo -e " ${GREEN}✓${NC} openssl"
|
|
120
|
+
fi
|
|
121
|
+
|
|
122
|
+
if [ ${#DEPS_TO_INSTALL[@]} -eq 0 ]; then
|
|
123
|
+
echo -e "${GREEN}All dependencies satisfied!${NC}"
|
|
124
|
+
return 0
|
|
125
|
+
fi
|
|
126
|
+
|
|
127
|
+
echo ""
|
|
128
|
+
echo -e "${YELLOW}Installing missing dependencies: ${DEPS_TO_INSTALL[*]}${NC}"
|
|
129
|
+
|
|
130
|
+
case "$PACKAGE_MANAGER" in
|
|
131
|
+
brew)
|
|
132
|
+
# macOS with Homebrew
|
|
133
|
+
if ! command -v brew &> /dev/null; then
|
|
134
|
+
echo -e "${YELLOW}Homebrew not found. Installing Homebrew...${NC}"
|
|
135
|
+
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
|
|
136
|
+
fi
|
|
137
|
+
for dep in "${DEPS_TO_INSTALL[@]}"; do
|
|
138
|
+
case "$dep" in
|
|
139
|
+
nodejs) brew install node ;;
|
|
140
|
+
npm) ;; # Comes with node
|
|
141
|
+
*) brew install "$dep" ;;
|
|
142
|
+
esac
|
|
143
|
+
done
|
|
144
|
+
;;
|
|
145
|
+
apt)
|
|
146
|
+
# Debian/Ubuntu
|
|
147
|
+
if $NEEDS_SUDO; then
|
|
148
|
+
apt-get update
|
|
149
|
+
for dep in "${DEPS_TO_INSTALL[@]}"; do
|
|
150
|
+
case "$dep" in
|
|
151
|
+
nodejs)
|
|
152
|
+
# Use NodeSource for newer Node.js
|
|
153
|
+
curl -fsSL https://deb.nodesource.com/setup_20.x | bash -
|
|
154
|
+
apt-get install -y nodejs
|
|
155
|
+
;;
|
|
156
|
+
npm) ;; # Comes with nodejs from NodeSource
|
|
157
|
+
*) apt-get install -y "$dep" ;;
|
|
158
|
+
esac
|
|
159
|
+
done
|
|
160
|
+
else
|
|
161
|
+
echo -e "${RED}Cannot install system packages without sudo.${NC}"
|
|
162
|
+
echo "Please install manually: sudo apt install ${DEPS_TO_INSTALL[*]}"
|
|
163
|
+
exit 1
|
|
164
|
+
fi
|
|
165
|
+
;;
|
|
166
|
+
dnf|yum)
|
|
167
|
+
# RHEL/CentOS/Fedora
|
|
168
|
+
if $NEEDS_SUDO; then
|
|
169
|
+
for dep in "${DEPS_TO_INSTALL[@]}"; do
|
|
170
|
+
case "$dep" in
|
|
171
|
+
nodejs)
|
|
172
|
+
curl -fsSL https://rpm.nodesource.com/setup_20.x | bash -
|
|
173
|
+
$PACKAGE_MANAGER install -y nodejs
|
|
174
|
+
;;
|
|
175
|
+
npm) ;; # Comes with nodejs
|
|
176
|
+
*) $PACKAGE_MANAGER install -y "$dep" ;;
|
|
177
|
+
esac
|
|
178
|
+
done
|
|
179
|
+
else
|
|
180
|
+
echo -e "${RED}Cannot install system packages without sudo.${NC}"
|
|
181
|
+
echo "Please install manually: sudo $PACKAGE_MANAGER install ${DEPS_TO_INSTALL[*]}"
|
|
182
|
+
exit 1
|
|
183
|
+
fi
|
|
184
|
+
;;
|
|
185
|
+
pacman)
|
|
186
|
+
# Arch Linux
|
|
187
|
+
if $NEEDS_SUDO; then
|
|
188
|
+
pacman -Sy --noconfirm "${DEPS_TO_INSTALL[@]}"
|
|
189
|
+
else
|
|
190
|
+
echo -e "${RED}Cannot install system packages without sudo.${NC}"
|
|
191
|
+
echo "Please install manually: sudo pacman -S ${DEPS_TO_INSTALL[*]}"
|
|
192
|
+
exit 1
|
|
193
|
+
fi
|
|
194
|
+
;;
|
|
195
|
+
apk)
|
|
196
|
+
# Alpine
|
|
197
|
+
if $NEEDS_SUDO; then
|
|
198
|
+
apk add --no-cache "${DEPS_TO_INSTALL[@]}"
|
|
199
|
+
else
|
|
200
|
+
echo -e "${RED}Cannot install system packages without sudo.${NC}"
|
|
201
|
+
echo "Please install manually: sudo apk add ${DEPS_TO_INSTALL[*]}"
|
|
202
|
+
exit 1
|
|
203
|
+
fi
|
|
204
|
+
;;
|
|
205
|
+
*)
|
|
206
|
+
echo -e "${RED}Unknown package manager. Please install manually:${NC}"
|
|
207
|
+
echo " - Node.js 18+ (https://nodejs.org)"
|
|
208
|
+
echo " - tmux"
|
|
209
|
+
echo " - git"
|
|
210
|
+
echo " - openssl"
|
|
211
|
+
exit 1
|
|
212
|
+
;;
|
|
213
|
+
esac
|
|
214
|
+
|
|
215
|
+
echo -e "${GREEN}Dependencies installed!${NC}"
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
# Find or download the source code
|
|
219
|
+
setup_source() {
|
|
220
|
+
echo ""
|
|
221
|
+
echo -e "${BLUE}Setting up source code...${NC}"
|
|
222
|
+
|
|
223
|
+
# Check if we're already in the daemon directory
|
|
224
|
+
if [[ -f "./package.json" ]] && grep -q "companion-daemon" "./package.json" 2>/dev/null; then
|
|
225
|
+
SOURCE_DIR="$(pwd)"
|
|
226
|
+
echo -e " ${GREEN}✓${NC} Using current directory: $SOURCE_DIR"
|
|
227
|
+
elif [[ -f "../daemon/package.json" ]] && grep -q "companion-daemon" "../daemon/package.json" 2>/dev/null; then
|
|
228
|
+
SOURCE_DIR="$(cd ../daemon && pwd)"
|
|
229
|
+
echo -e " ${GREEN}✓${NC} Using parent daemon directory: $SOURCE_DIR"
|
|
230
|
+
else
|
|
231
|
+
# Need to clone
|
|
232
|
+
echo -e " ${YELLOW}Source not found locally. Cloning repository...${NC}"
|
|
233
|
+
TEMP_DIR=$(mktemp -d)
|
|
234
|
+
git clone --depth 1 https://github.com/Hexidecibel/companion.git "$TEMP_DIR/companion"
|
|
235
|
+
SOURCE_DIR="$TEMP_DIR/companion/daemon"
|
|
236
|
+
CLEANUP_TEMP=true
|
|
237
|
+
fi
|
|
238
|
+
|
|
239
|
+
cd "$SOURCE_DIR"
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
# Build the daemon
|
|
243
|
+
build_daemon() {
|
|
244
|
+
echo ""
|
|
245
|
+
echo -e "${BLUE}Building daemon...${NC}"
|
|
246
|
+
|
|
247
|
+
cd "$SOURCE_DIR"
|
|
248
|
+
|
|
249
|
+
# Check if already built
|
|
250
|
+
if [[ -f "./dist/index.js" ]]; then
|
|
251
|
+
echo -e " ${GREEN}✓${NC} Build already exists"
|
|
252
|
+
|
|
253
|
+
# Check if source is newer than build
|
|
254
|
+
if [[ "./src/index.ts" -nt "./dist/index.js" ]]; then
|
|
255
|
+
echo -e " ${YELLOW}Source is newer than build, rebuilding...${NC}"
|
|
256
|
+
npm install
|
|
257
|
+
npm run build
|
|
258
|
+
fi
|
|
259
|
+
else
|
|
260
|
+
echo -e " Installing npm dependencies..."
|
|
261
|
+
npm install
|
|
262
|
+
|
|
263
|
+
echo -e " Compiling TypeScript..."
|
|
264
|
+
npm run build
|
|
265
|
+
fi
|
|
266
|
+
|
|
267
|
+
if [[ ! -f "./dist/index.js" ]]; then
|
|
268
|
+
echo -e "${RED}Build failed! dist/index.js not found${NC}"
|
|
269
|
+
exit 1
|
|
270
|
+
fi
|
|
271
|
+
|
|
272
|
+
echo -e " ${GREEN}✓${NC} Build complete"
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
# Install to target directory
|
|
276
|
+
install_files() {
|
|
277
|
+
echo ""
|
|
278
|
+
echo -e "${BLUE}Installing files...${NC}"
|
|
279
|
+
|
|
280
|
+
# Create directories
|
|
281
|
+
mkdir -p "$INSTALL_DIR"
|
|
282
|
+
mkdir -p "$CONFIG_DIR"
|
|
283
|
+
mkdir -p "$CONFIG_DIR/certs"
|
|
284
|
+
chmod 700 "$CONFIG_DIR/certs"
|
|
285
|
+
|
|
286
|
+
# Copy files
|
|
287
|
+
cp -r "$SOURCE_DIR/dist" "$INSTALL_DIR/"
|
|
288
|
+
cp "$SOURCE_DIR/package.json" "$INSTALL_DIR/"
|
|
289
|
+
cp "$SOURCE_DIR/package-lock.json" "$INSTALL_DIR/" 2>/dev/null || true
|
|
290
|
+
|
|
291
|
+
# Install production dependencies
|
|
292
|
+
cd "$INSTALL_DIR"
|
|
293
|
+
npm install --production --silent
|
|
294
|
+
|
|
295
|
+
echo -e " ${GREEN}✓${NC} Files installed to $INSTALL_DIR"
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
# Generate or preserve config
|
|
299
|
+
setup_config() {
|
|
300
|
+
echo ""
|
|
301
|
+
echo -e "${BLUE}Setting up configuration...${NC}"
|
|
302
|
+
|
|
303
|
+
CONFIG_FILE="$CONFIG_DIR/config.json"
|
|
304
|
+
|
|
305
|
+
if [[ -f "$CONFIG_FILE" ]]; then
|
|
306
|
+
echo -e " ${GREEN}✓${NC} Config file already exists"
|
|
307
|
+
TOKEN=$(grep -o '"token": *"[^"]*"' "$CONFIG_FILE" | cut -d'"' -f4)
|
|
308
|
+
else
|
|
309
|
+
# Generate new token
|
|
310
|
+
TOKEN=$(openssl rand -hex 32)
|
|
311
|
+
|
|
312
|
+
cat << EOF > "$CONFIG_FILE"
|
|
313
|
+
{
|
|
314
|
+
"port": 9877,
|
|
315
|
+
"token": "$TOKEN",
|
|
316
|
+
"tls": true,
|
|
317
|
+
"cert_path": "$CONFIG_DIR/certs/cert.pem",
|
|
318
|
+
"key_path": "$CONFIG_DIR/certs/key.pem",
|
|
319
|
+
"tmux_session": "companion",
|
|
320
|
+
"code_home": "$ACTUAL_HOME/.claude",
|
|
321
|
+
"mdns_enabled": true,
|
|
322
|
+
"push_delay_ms": 60000
|
|
323
|
+
}
|
|
324
|
+
EOF
|
|
325
|
+
|
|
326
|
+
echo -e " ${GREEN}✓${NC} Config file created"
|
|
327
|
+
fi
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
# Setup service (systemd or launchd)
|
|
331
|
+
setup_service() {
|
|
332
|
+
echo ""
|
|
333
|
+
echo -e "${BLUE}Setting up service...${NC}"
|
|
334
|
+
|
|
335
|
+
if [[ "$OS" == "macos" ]]; then
|
|
336
|
+
setup_launchd
|
|
337
|
+
else
|
|
338
|
+
setup_systemd
|
|
339
|
+
fi
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
# macOS launchd setup
|
|
343
|
+
setup_launchd() {
|
|
344
|
+
PLIST_PATH="$HOME/Library/LaunchAgents/com.companion.daemon.plist"
|
|
345
|
+
mkdir -p "$HOME/Library/LaunchAgents"
|
|
346
|
+
|
|
347
|
+
cat << EOF > "$PLIST_PATH"
|
|
348
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
349
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
350
|
+
<plist version="1.0">
|
|
351
|
+
<dict>
|
|
352
|
+
<key>Label</key>
|
|
353
|
+
<string>com.companion.daemon</string>
|
|
354
|
+
<key>ProgramArguments</key>
|
|
355
|
+
<array>
|
|
356
|
+
<string>/usr/local/bin/node</string>
|
|
357
|
+
<string>$INSTALL_DIR/dist/index.js</string>
|
|
358
|
+
</array>
|
|
359
|
+
<key>EnvironmentVariables</key>
|
|
360
|
+
<dict>
|
|
361
|
+
<key>CONFIG_PATH</key>
|
|
362
|
+
<string>$CONFIG_DIR/config.json</string>
|
|
363
|
+
<key>NODE_ENV</key>
|
|
364
|
+
<string>production</string>
|
|
365
|
+
</dict>
|
|
366
|
+
<key>WorkingDirectory</key>
|
|
367
|
+
<string>$INSTALL_DIR</string>
|
|
368
|
+
<key>RunAtLoad</key>
|
|
369
|
+
<true/>
|
|
370
|
+
<key>KeepAlive</key>
|
|
371
|
+
<true/>
|
|
372
|
+
<key>StandardOutPath</key>
|
|
373
|
+
<string>$HOME/Library/Logs/companion.log</string>
|
|
374
|
+
<key>StandardErrorPath</key>
|
|
375
|
+
<string>$HOME/Library/Logs/companion.error.log</string>
|
|
376
|
+
</dict>
|
|
377
|
+
</plist>
|
|
378
|
+
EOF
|
|
379
|
+
|
|
380
|
+
# Find node path
|
|
381
|
+
NODE_PATH=$(which node)
|
|
382
|
+
sed -i '' "s|/usr/local/bin/node|$NODE_PATH|g" "$PLIST_PATH"
|
|
383
|
+
|
|
384
|
+
# Load the service
|
|
385
|
+
launchctl unload "$PLIST_PATH" 2>/dev/null || true
|
|
386
|
+
launchctl load "$PLIST_PATH"
|
|
387
|
+
|
|
388
|
+
echo -e " ${GREEN}✓${NC} LaunchAgent created and loaded"
|
|
389
|
+
|
|
390
|
+
SERVICE_TYPE="launchd"
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
# Linux systemd setup
|
|
394
|
+
setup_systemd() {
|
|
395
|
+
if ! command -v systemctl &> /dev/null; then
|
|
396
|
+
echo -e " ${YELLOW}systemd not found, skipping service setup${NC}"
|
|
397
|
+
echo -e " You can run manually: node $INSTALL_DIR/dist/index.js"
|
|
398
|
+
SERVICE_TYPE="manual"
|
|
399
|
+
return
|
|
400
|
+
fi
|
|
401
|
+
|
|
402
|
+
if $NEEDS_SUDO; then
|
|
403
|
+
SERVICE_FILE="/etc/systemd/system/companion.service"
|
|
404
|
+
else
|
|
405
|
+
mkdir -p "$HOME/.config/systemd/user"
|
|
406
|
+
SERVICE_FILE="$HOME/.config/systemd/user/companion.service"
|
|
407
|
+
fi
|
|
408
|
+
|
|
409
|
+
cat << EOF > "$SERVICE_FILE"
|
|
410
|
+
[Unit]
|
|
411
|
+
Description=Companion Daemon
|
|
412
|
+
After=network.target
|
|
413
|
+
|
|
414
|
+
[Service]
|
|
415
|
+
Type=simple
|
|
416
|
+
WorkingDirectory=$INSTALL_DIR
|
|
417
|
+
ExecStart=$(which node) $INSTALL_DIR/dist/index.js
|
|
418
|
+
Restart=always
|
|
419
|
+
RestartSec=5
|
|
420
|
+
Environment=CONFIG_PATH=$CONFIG_DIR/config.json
|
|
421
|
+
Environment=NODE_ENV=production
|
|
422
|
+
|
|
423
|
+
[Install]
|
|
424
|
+
WantedBy=default.target
|
|
425
|
+
EOF
|
|
426
|
+
|
|
427
|
+
if $NEEDS_SUDO; then
|
|
428
|
+
systemctl daemon-reload
|
|
429
|
+
systemctl enable companion
|
|
430
|
+
systemctl start companion
|
|
431
|
+
echo -e " ${GREEN}✓${NC} Systemd service created (system-wide)"
|
|
432
|
+
else
|
|
433
|
+
systemctl --user daemon-reload
|
|
434
|
+
systemctl --user enable companion
|
|
435
|
+
systemctl --user start companion
|
|
436
|
+
echo -e " ${GREEN}✓${NC} Systemd service created (user-level)"
|
|
437
|
+
fi
|
|
438
|
+
|
|
439
|
+
SERVICE_TYPE="systemd"
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
# Verify installation
|
|
443
|
+
verify_installation() {
|
|
444
|
+
echo ""
|
|
445
|
+
echo -e "${BLUE}Verifying installation...${NC}"
|
|
446
|
+
|
|
447
|
+
sleep 2
|
|
448
|
+
|
|
449
|
+
# Check if process is running
|
|
450
|
+
if pgrep -f "node.*companion" > /dev/null; then
|
|
451
|
+
echo -e " ${GREEN}✓${NC} Daemon is running"
|
|
452
|
+
else
|
|
453
|
+
echo -e " ${RED}✗${NC} Daemon is not running"
|
|
454
|
+
echo ""
|
|
455
|
+
echo "Check logs:"
|
|
456
|
+
if [[ "$OS" == "macos" ]]; then
|
|
457
|
+
echo " cat ~/Library/Logs/companion.log"
|
|
458
|
+
echo " cat ~/Library/Logs/companion.error.log"
|
|
459
|
+
elif [[ "$SERVICE_TYPE" == "systemd" ]]; then
|
|
460
|
+
if $NEEDS_SUDO; then
|
|
461
|
+
echo " sudo journalctl -u companion -e"
|
|
462
|
+
else
|
|
463
|
+
echo " journalctl --user -u companion -e"
|
|
464
|
+
fi
|
|
465
|
+
fi
|
|
466
|
+
return 1
|
|
467
|
+
fi
|
|
468
|
+
|
|
469
|
+
# Check if port is listening
|
|
470
|
+
if command -v lsof &> /dev/null; then
|
|
471
|
+
if lsof -i :9877 > /dev/null 2>&1; then
|
|
472
|
+
echo -e " ${GREEN}✓${NC} Listening on port 9877"
|
|
473
|
+
fi
|
|
474
|
+
elif command -v ss &> /dev/null; then
|
|
475
|
+
if ss -tln | grep -q ":9877"; then
|
|
476
|
+
echo -e " ${GREEN}✓${NC} Listening on port 9877"
|
|
477
|
+
fi
|
|
478
|
+
fi
|
|
479
|
+
|
|
480
|
+
return 0
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
# Print success message
|
|
484
|
+
print_success() {
|
|
485
|
+
echo ""
|
|
486
|
+
echo -e "${GREEN}"
|
|
487
|
+
echo "╔══════════════════════════════════════════════════════════════╗"
|
|
488
|
+
echo "║ Installation Complete! ║"
|
|
489
|
+
echo "╚══════════════════════════════════════════════════════════════╝"
|
|
490
|
+
echo -e "${NC}"
|
|
491
|
+
echo ""
|
|
492
|
+
echo -e "${GREEN}Your authentication token:${NC}"
|
|
493
|
+
echo -e " ${YELLOW}$TOKEN${NC}"
|
|
494
|
+
echo ""
|
|
495
|
+
echo -e "${GREEN}Add this to your Companion mobile app.${NC}"
|
|
496
|
+
echo ""
|
|
497
|
+
echo -e "${BLUE}Service commands:${NC}"
|
|
498
|
+
|
|
499
|
+
if [[ "$OS" == "macos" ]]; then
|
|
500
|
+
echo " View logs: tail -f ~/Library/Logs/companion.log"
|
|
501
|
+
echo " Restart: launchctl kickstart -k gui/\$(id -u)/com.companion.daemon"
|
|
502
|
+
echo " Stop: launchctl unload ~/Library/LaunchAgents/com.companion.daemon.plist"
|
|
503
|
+
echo " Start: launchctl load ~/Library/LaunchAgents/com.companion.daemon.plist"
|
|
504
|
+
elif [[ "$SERVICE_TYPE" == "systemd" ]]; then
|
|
505
|
+
if $NEEDS_SUDO; then
|
|
506
|
+
echo " View logs: sudo journalctl -u companion -f"
|
|
507
|
+
echo " Restart: sudo systemctl restart companion"
|
|
508
|
+
echo " Stop: sudo systemctl stop companion"
|
|
509
|
+
echo " Status: sudo systemctl status companion"
|
|
510
|
+
else
|
|
511
|
+
echo " View logs: journalctl --user -u companion -f"
|
|
512
|
+
echo " Restart: systemctl --user restart companion"
|
|
513
|
+
echo " Stop: systemctl --user stop companion"
|
|
514
|
+
echo " Status: systemctl --user status companion"
|
|
515
|
+
fi
|
|
516
|
+
else
|
|
517
|
+
echo " Run manually: CONFIG_PATH=$CONFIG_DIR/config.json node $INSTALL_DIR/dist/index.js"
|
|
518
|
+
fi
|
|
519
|
+
|
|
520
|
+
echo ""
|
|
521
|
+
echo -e "${BLUE}Config file:${NC} $CONFIG_DIR/config.json"
|
|
522
|
+
echo ""
|
|
523
|
+
echo -e "${YELLOW}Next steps:${NC}"
|
|
524
|
+
echo " 1. Make sure tmux is running: tmux new -s companion"
|
|
525
|
+
echo " 2. Start your coding session in tmux"
|
|
526
|
+
echo " 3. Connect from the mobile app using your token"
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
# Cleanup
|
|
530
|
+
cleanup() {
|
|
531
|
+
if [[ "${CLEANUP_TEMP:-false}" == "true" ]] && [[ -n "${TEMP_DIR:-}" ]]; then
|
|
532
|
+
rm -rf "$TEMP_DIR"
|
|
533
|
+
fi
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
trap cleanup EXIT
|
|
537
|
+
|
|
538
|
+
# Main installation flow
|
|
539
|
+
main() {
|
|
540
|
+
detect_os
|
|
541
|
+
check_permissions
|
|
542
|
+
install_dependencies
|
|
543
|
+
setup_source
|
|
544
|
+
build_daemon
|
|
545
|
+
install_files
|
|
546
|
+
setup_config
|
|
547
|
+
setup_service
|
|
548
|
+
|
|
549
|
+
if verify_installation; then
|
|
550
|
+
print_success
|
|
551
|
+
else
|
|
552
|
+
echo ""
|
|
553
|
+
echo -e "${YELLOW}Installation completed with warnings. Please check the logs.${NC}"
|
|
554
|
+
echo -e "Token: ${YELLOW}$TOKEN${NC}"
|
|
555
|
+
fi
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
main "$@"
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
set -e
|
|
3
|
+
|
|
4
|
+
# Colors
|
|
5
|
+
RED='\033[0;31m'
|
|
6
|
+
GREEN='\033[0;32m'
|
|
7
|
+
YELLOW='\033[1;33m'
|
|
8
|
+
BLUE='\033[0;34m'
|
|
9
|
+
NC='\033[0m'
|
|
10
|
+
|
|
11
|
+
echo -e "${BLUE}"
|
|
12
|
+
echo "╔══════════════════════════════════════════════════════════════╗"
|
|
13
|
+
echo "║ Companion Daemon Uninstaller ║"
|
|
14
|
+
echo "╚══════════════════════════════════════════════════════════════╝"
|
|
15
|
+
echo -e "${NC}"
|
|
16
|
+
|
|
17
|
+
# Detect OS
|
|
18
|
+
if [[ "$OSTYPE" == "darwin"* ]]; then
|
|
19
|
+
OS="macos"
|
|
20
|
+
else
|
|
21
|
+
OS="linux"
|
|
22
|
+
fi
|
|
23
|
+
|
|
24
|
+
# Confirm
|
|
25
|
+
echo -e "${YELLOW}This will remove Companion daemon.${NC}"
|
|
26
|
+
echo ""
|
|
27
|
+
read -p "Continue? (y/N) " -n 1 -r
|
|
28
|
+
echo
|
|
29
|
+
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
30
|
+
echo "Cancelled."
|
|
31
|
+
exit 0
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
echo ""
|
|
35
|
+
echo -e "${BLUE}Stopping service...${NC}"
|
|
36
|
+
|
|
37
|
+
if [[ "$OS" == "macos" ]]; then
|
|
38
|
+
# macOS: unload launchd
|
|
39
|
+
PLIST_PATH="$HOME/Library/LaunchAgents/com.companion.daemon.plist"
|
|
40
|
+
if [[ -f "$PLIST_PATH" ]]; then
|
|
41
|
+
launchctl unload "$PLIST_PATH" 2>/dev/null || true
|
|
42
|
+
rm -f "$PLIST_PATH"
|
|
43
|
+
echo -e " ${GREEN}✓${NC} LaunchAgent removed"
|
|
44
|
+
fi
|
|
45
|
+
else
|
|
46
|
+
# Linux: stop systemd
|
|
47
|
+
if systemctl --user is-active companion &>/dev/null; then
|
|
48
|
+
systemctl --user stop companion
|
|
49
|
+
systemctl --user disable companion
|
|
50
|
+
rm -f "$HOME/.config/systemd/user/companion.service"
|
|
51
|
+
systemctl --user daemon-reload
|
|
52
|
+
echo -e " ${GREEN}✓${NC} User systemd service removed"
|
|
53
|
+
elif systemctl is-active companion &>/dev/null 2>&1; then
|
|
54
|
+
if [ "$EUID" -eq 0 ]; then
|
|
55
|
+
systemctl stop companion
|
|
56
|
+
systemctl disable companion
|
|
57
|
+
rm -f /etc/systemd/system/companion.service
|
|
58
|
+
systemctl daemon-reload
|
|
59
|
+
echo -e " ${GREEN}✓${NC} System systemd service removed"
|
|
60
|
+
else
|
|
61
|
+
echo -e " ${YELLOW}System service found. Run with sudo to remove.${NC}"
|
|
62
|
+
fi
|
|
63
|
+
fi
|
|
64
|
+
fi
|
|
65
|
+
|
|
66
|
+
# Kill any running processes
|
|
67
|
+
pkill -f "node.*companion" 2>/dev/null || true
|
|
68
|
+
|
|
69
|
+
echo ""
|
|
70
|
+
echo -e "${BLUE}Removing files...${NC}"
|
|
71
|
+
|
|
72
|
+
# Remove install directories
|
|
73
|
+
DIRS_TO_CHECK=(
|
|
74
|
+
"$HOME/.companion"
|
|
75
|
+
"/opt/companion"
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
for dir in "${DIRS_TO_CHECK[@]}"; do
|
|
79
|
+
if [[ -d "$dir" ]]; then
|
|
80
|
+
rm -rf "$dir"
|
|
81
|
+
echo -e " ${GREEN}✓${NC} Removed $dir"
|
|
82
|
+
fi
|
|
83
|
+
done
|
|
84
|
+
|
|
85
|
+
# Ask about config
|
|
86
|
+
echo ""
|
|
87
|
+
read -p "Remove configuration and certificates? (y/N) " -n 1 -r
|
|
88
|
+
echo
|
|
89
|
+
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
|
90
|
+
CONFIG_DIRS=(
|
|
91
|
+
"$HOME/.companion"
|
|
92
|
+
"/etc/companion"
|
|
93
|
+
)
|
|
94
|
+
for dir in "${CONFIG_DIRS[@]}"; do
|
|
95
|
+
if [[ -d "$dir" ]]; then
|
|
96
|
+
if [[ "$dir" == "/etc/companion" ]] && [ "$EUID" -ne 0 ]; then
|
|
97
|
+
echo -e " ${YELLOW}Cannot remove $dir without sudo${NC}"
|
|
98
|
+
else
|
|
99
|
+
rm -rf "$dir"
|
|
100
|
+
echo -e " ${GREEN}✓${NC} Removed $dir"
|
|
101
|
+
fi
|
|
102
|
+
fi
|
|
103
|
+
done
|
|
104
|
+
fi
|
|
105
|
+
|
|
106
|
+
# Remove logs on macOS
|
|
107
|
+
if [[ "$OS" == "macos" ]]; then
|
|
108
|
+
rm -f "$HOME/Library/Logs/companion.log" 2>/dev/null
|
|
109
|
+
rm -f "$HOME/Library/Logs/companion.error.log" 2>/dev/null
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
echo ""
|
|
113
|
+
echo -e "${GREEN}Companion daemon has been uninstalled.${NC}"
|