@sarkar-ai/deskmate 0.2.0
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/.env.example +49 -0
- package/LICENSE +21 -0
- package/README.md +360 -0
- package/dist/cli/init.js +387 -0
- package/dist/cli.js +184 -0
- package/dist/clients/telegram.js +148 -0
- package/dist/core/agent/factory.js +67 -0
- package/dist/core/agent/index.js +32 -0
- package/dist/core/agent/providers/claude-code.js +158 -0
- package/dist/core/agent/types.js +9 -0
- package/dist/core/approval.js +192 -0
- package/dist/core/executor.js +237 -0
- package/dist/core/logger.js +76 -0
- package/dist/core/platform.js +130 -0
- package/dist/gateway/gateway.js +435 -0
- package/dist/gateway/index.js +9 -0
- package/dist/gateway/security.js +35 -0
- package/dist/gateway/session.js +195 -0
- package/dist/gateway/types.js +8 -0
- package/dist/index.js +130 -0
- package/dist/mcp/server.js +156 -0
- package/dist/telegram/bot.js +333 -0
- package/install.sh +817 -0
- package/package.json +73 -0
- package/uninstall.sh +121 -0
package/install.sh
ADDED
|
@@ -0,0 +1,817 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
|
|
3
|
+
set -e
|
|
4
|
+
|
|
5
|
+
# Colors for output
|
|
6
|
+
RED='\033[0;31m'
|
|
7
|
+
GREEN='\033[0;32m'
|
|
8
|
+
YELLOW='\033[1;33m'
|
|
9
|
+
BLUE='\033[0;34m'
|
|
10
|
+
NC='\033[0m' # No Color
|
|
11
|
+
|
|
12
|
+
# =============================================================================
|
|
13
|
+
# OS Detection
|
|
14
|
+
# =============================================================================
|
|
15
|
+
OS_TYPE="$(uname -s)"
|
|
16
|
+
case "$OS_TYPE" in
|
|
17
|
+
Darwin) PLATFORM="macos" ;;
|
|
18
|
+
Linux) PLATFORM="linux" ;;
|
|
19
|
+
CYGWIN*|MINGW*|MSYS*) PLATFORM="windows" ;;
|
|
20
|
+
*)
|
|
21
|
+
echo -e "${RED}Unsupported platform: $OS_TYPE${NC}"
|
|
22
|
+
echo "Deskmate supports macOS and Linux. On Windows, use WSL2."
|
|
23
|
+
exit 1
|
|
24
|
+
;;
|
|
25
|
+
esac
|
|
26
|
+
|
|
27
|
+
# Configuration
|
|
28
|
+
PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
29
|
+
LOGS_DIR="$PROJECT_DIR/logs"
|
|
30
|
+
NODE_PATH=$(which node)
|
|
31
|
+
|
|
32
|
+
# Platform-specific paths
|
|
33
|
+
if [ "$PLATFORM" = "macos" ]; then
|
|
34
|
+
PLIST_NAME="com.deskmate.service"
|
|
35
|
+
PLIST_PATH="$HOME/Library/LaunchAgents/$PLIST_NAME.plist"
|
|
36
|
+
CLAUDE_DESKTOP_CONFIG="$HOME/Library/Application Support/Claude/claude_desktop_config.json"
|
|
37
|
+
elif [ "$PLATFORM" = "linux" ]; then
|
|
38
|
+
SYSTEMD_SERVICE="deskmate.service"
|
|
39
|
+
SYSTEMD_DIR="$HOME/.config/systemd/user"
|
|
40
|
+
SYSTEMD_PATH="$SYSTEMD_DIR/$SYSTEMD_SERVICE"
|
|
41
|
+
CLAUDE_DESKTOP_CONFIG="$HOME/.config/Claude/claude_desktop_config.json"
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Helper: cross-platform sed -i
|
|
45
|
+
sed_inplace() {
|
|
46
|
+
if [ "$PLATFORM" = "macos" ]; then
|
|
47
|
+
sed -i '' "$@"
|
|
48
|
+
else
|
|
49
|
+
sed -i "$@"
|
|
50
|
+
fi
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
echo -e "${BLUE}"
|
|
54
|
+
echo "╔════════════════════════════════════════╗"
|
|
55
|
+
echo "║ Deskmate Installer ║"
|
|
56
|
+
echo "╚════════════════════════════════════════╝"
|
|
57
|
+
echo -e "${NC}"
|
|
58
|
+
echo -e "Detected platform: ${GREEN}$PLATFORM${NC}"
|
|
59
|
+
|
|
60
|
+
if [ "$PLATFORM" = "windows" ]; then
|
|
61
|
+
echo -e "${RED}Native Windows is not supported.${NC}"
|
|
62
|
+
echo "Please use WSL2 (Windows Subsystem for Linux) to run Deskmate."
|
|
63
|
+
echo ""
|
|
64
|
+
echo " 1. Install WSL2: wsl --install"
|
|
65
|
+
echo " 2. Open a WSL2 terminal"
|
|
66
|
+
echo " 3. Re-run this installer from inside WSL2"
|
|
67
|
+
exit 1
|
|
68
|
+
fi
|
|
69
|
+
|
|
70
|
+
# =============================================================================
|
|
71
|
+
# 1. Prerequisites
|
|
72
|
+
# =============================================================================
|
|
73
|
+
echo -e "${YELLOW}Checking prerequisites...${NC}"
|
|
74
|
+
|
|
75
|
+
if [ -z "$NODE_PATH" ]; then
|
|
76
|
+
echo -e "${RED}Error: Node.js not found. Please install Node.js first.${NC}"
|
|
77
|
+
exit 1
|
|
78
|
+
fi
|
|
79
|
+
|
|
80
|
+
echo -e "${GREEN}✓ Node.js found: $NODE_PATH${NC}"
|
|
81
|
+
|
|
82
|
+
# Check if Claude Code is installed (required for Agent SDK)
|
|
83
|
+
CLAUDE_PATH=$(which claude 2>/dev/null || echo "")
|
|
84
|
+
if [ -z "$CLAUDE_PATH" ]; then
|
|
85
|
+
echo -e "${RED}Error: Claude Code CLI not found. Please install it first:${NC}"
|
|
86
|
+
echo -e "${YELLOW} curl -fsSL https://claude.ai/install.sh | bash${NC}"
|
|
87
|
+
exit 1
|
|
88
|
+
fi
|
|
89
|
+
echo -e "${GREEN}✓ Claude Code found: $CLAUDE_PATH${NC}"
|
|
90
|
+
|
|
91
|
+
# Linux: check for screenshot tool
|
|
92
|
+
if [ "$PLATFORM" = "linux" ]; then
|
|
93
|
+
SCREENSHOT_TOOL=""
|
|
94
|
+
if command -v import &>/dev/null; then
|
|
95
|
+
SCREENSHOT_TOOL="import (ImageMagick)"
|
|
96
|
+
elif command -v gnome-screenshot &>/dev/null; then
|
|
97
|
+
SCREENSHOT_TOOL="gnome-screenshot"
|
|
98
|
+
elif command -v scrot &>/dev/null; then
|
|
99
|
+
SCREENSHOT_TOOL="scrot"
|
|
100
|
+
fi
|
|
101
|
+
|
|
102
|
+
if [ -n "$SCREENSHOT_TOOL" ]; then
|
|
103
|
+
echo -e "${GREEN}✓ Screenshot tool found: $SCREENSHOT_TOOL${NC}"
|
|
104
|
+
else
|
|
105
|
+
echo -e "${YELLOW}Warning: No screenshot tool found. Install ImageMagick for screenshot support:${NC}"
|
|
106
|
+
echo -e "${YELLOW} sudo apt install imagemagick # Debian/Ubuntu${NC}"
|
|
107
|
+
echo -e "${YELLOW} sudo dnf install ImageMagick # Fedora${NC}"
|
|
108
|
+
echo -e "${YELLOW} sudo pacman -S imagemagick # Arch${NC}"
|
|
109
|
+
fi
|
|
110
|
+
fi
|
|
111
|
+
|
|
112
|
+
# =============================================================================
|
|
113
|
+
# 2. .env Configuration
|
|
114
|
+
# =============================================================================
|
|
115
|
+
echo -e "\n${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
116
|
+
echo -e "${YELLOW}Configuring environment...${NC}"
|
|
117
|
+
echo ""
|
|
118
|
+
|
|
119
|
+
CONFIGURE_ENV=true
|
|
120
|
+
|
|
121
|
+
if [ -f "$PROJECT_DIR/.env" ]; then
|
|
122
|
+
echo -e "${GREEN}Found existing .env file.${NC}"
|
|
123
|
+
read -p "Reconfigure? [y/N]: " RECONFIGURE
|
|
124
|
+
if [ "$RECONFIGURE" != "y" ] && [ "$RECONFIGURE" != "Y" ]; then
|
|
125
|
+
CONFIGURE_ENV=false
|
|
126
|
+
echo -e "${GREEN}✓ Keeping existing .env${NC}"
|
|
127
|
+
fi
|
|
128
|
+
fi
|
|
129
|
+
|
|
130
|
+
if [ "$CONFIGURE_ENV" = true ]; then
|
|
131
|
+
echo ""
|
|
132
|
+
echo -e "${YELLOW}Enter your credentials (press Enter to skip optional fields):${NC}"
|
|
133
|
+
echo ""
|
|
134
|
+
|
|
135
|
+
read -p " Anthropic API Key: " ANTHROPIC_API_KEY
|
|
136
|
+
if [ -z "$ANTHROPIC_API_KEY" ]; then
|
|
137
|
+
echo -e " ${RED}Warning: No API key entered. You'll need to set ANTHROPIC_API_KEY in .env later.${NC}"
|
|
138
|
+
fi
|
|
139
|
+
|
|
140
|
+
echo ""
|
|
141
|
+
echo -e " ${BLUE}Telegram setup — get these from Telegram:${NC}"
|
|
142
|
+
echo -e " Bot token → message @BotFather, send /newbot"
|
|
143
|
+
echo -e " User ID → message @userinfobot, copy the number"
|
|
144
|
+
echo ""
|
|
145
|
+
|
|
146
|
+
read -p " Telegram Bot Token (from @BotFather): " TELEGRAM_BOT_TOKEN
|
|
147
|
+
read -p " Telegram User ID (from @userinfobot): " TELEGRAM_USER_ID
|
|
148
|
+
|
|
149
|
+
echo ""
|
|
150
|
+
read -p " Working directory (default: $HOME): " WORKING_DIR
|
|
151
|
+
WORKING_DIR=${WORKING_DIR:-$HOME}
|
|
152
|
+
|
|
153
|
+
read -p " Bot name (default: Deskmate): " BOT_NAME
|
|
154
|
+
BOT_NAME=${BOT_NAME:-Deskmate}
|
|
155
|
+
|
|
156
|
+
# Write .env
|
|
157
|
+
cat > "$PROJECT_DIR/.env" << EOF
|
|
158
|
+
# Deskmate Configuration (generated by install.sh)
|
|
159
|
+
|
|
160
|
+
TELEGRAM_BOT_TOKEN=${TELEGRAM_BOT_TOKEN}
|
|
161
|
+
ALLOWED_USER_ID=${TELEGRAM_USER_ID}
|
|
162
|
+
ALLOWED_USERS=telegram:${TELEGRAM_USER_ID}
|
|
163
|
+
ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
|
164
|
+
AGENT_PROVIDER=claude-code
|
|
165
|
+
WORKING_DIR=${WORKING_DIR}
|
|
166
|
+
BOT_NAME=${BOT_NAME}
|
|
167
|
+
LOG_LEVEL=info
|
|
168
|
+
REQUIRE_APPROVAL_FOR_ALL=false
|
|
169
|
+
EOF
|
|
170
|
+
|
|
171
|
+
echo -e "\n${GREEN}✓ .env file written${NC}"
|
|
172
|
+
fi
|
|
173
|
+
|
|
174
|
+
# =============================================================================
|
|
175
|
+
# 3. Build
|
|
176
|
+
# =============================================================================
|
|
177
|
+
echo -e "\n${YELLOW}Building project...${NC}"
|
|
178
|
+
cd "$PROJECT_DIR"
|
|
179
|
+
npm install --legacy-peer-deps
|
|
180
|
+
npm run build
|
|
181
|
+
echo -e "${GREEN}✓ Build complete${NC}"
|
|
182
|
+
|
|
183
|
+
# Create logs directory
|
|
184
|
+
mkdir -p "$LOGS_DIR"
|
|
185
|
+
echo -e "${GREEN}✓ Logs directory created: $LOGS_DIR${NC}"
|
|
186
|
+
|
|
187
|
+
# =============================================================================
|
|
188
|
+
# 4. macOS Permissions Setup (macOS only)
|
|
189
|
+
# =============================================================================
|
|
190
|
+
if [ "$PLATFORM" = "macos" ]; then
|
|
191
|
+
echo -e "\n${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
192
|
+
echo -e "${YELLOW}Setting up macOS permissions...${NC}"
|
|
193
|
+
echo ""
|
|
194
|
+
echo -e "Deskmate needs the following permissions to work properly:"
|
|
195
|
+
echo -e " • ${GREEN}Screen Recording${NC} - To take screenshots when requested"
|
|
196
|
+
echo -e " • ${GREEN}Accessibility${NC} - To control system functions"
|
|
197
|
+
echo -e " • ${GREEN}Full Disk Access${NC} - To read/write files anywhere"
|
|
198
|
+
echo -e " • ${GREEN}Automation${NC} - To control other applications"
|
|
199
|
+
echo ""
|
|
200
|
+
read -p "Would you like to configure permissions now? [Y/n]: " SETUP_PERMISSIONS
|
|
201
|
+
SETUP_PERMISSIONS=${SETUP_PERMISSIONS:-y}
|
|
202
|
+
|
|
203
|
+
if [ "$SETUP_PERMISSIONS" = "y" ] || [ "$SETUP_PERMISSIONS" = "Y" ]; then
|
|
204
|
+
|
|
205
|
+
# Get the terminal app being used
|
|
206
|
+
TERMINAL_APP=$(osascript -e 'tell application "System Events" to get name of first process whose frontmost is true' 2>/dev/null || echo "Terminal")
|
|
207
|
+
|
|
208
|
+
echo -e "\n${YELLOW}1. Screen Recording Permission${NC}"
|
|
209
|
+
echo " This allows taking screenshots when you request them."
|
|
210
|
+
read -p " Trigger Screen Recording permission dialog? [Y/n]: " TRIGGER_SCREEN
|
|
211
|
+
TRIGGER_SCREEN=${TRIGGER_SCREEN:-y}
|
|
212
|
+
|
|
213
|
+
if [ "$TRIGGER_SCREEN" = "y" ] || [ "$TRIGGER_SCREEN" = "Y" ]; then
|
|
214
|
+
echo -e " ${YELLOW}Triggering permission dialog...${NC}"
|
|
215
|
+
# Attempt to capture screen to trigger the permission dialog
|
|
216
|
+
screencapture -x /tmp/sarkar-test-screenshot.png 2>/dev/null || true
|
|
217
|
+
rm -f /tmp/sarkar-test-screenshot.png 2>/dev/null || true
|
|
218
|
+
echo -e " ${GREEN}✓ If a dialog appeared, please click 'Allow'${NC}"
|
|
219
|
+
echo -e " ${YELLOW} If no dialog appeared, the permission may already be granted${NC}"
|
|
220
|
+
sleep 1
|
|
221
|
+
fi
|
|
222
|
+
|
|
223
|
+
echo -e "\n${YELLOW}2. Accessibility Permission${NC}"
|
|
224
|
+
echo " This allows controlling system functions."
|
|
225
|
+
read -p " Open Accessibility settings? [Y/n]: " OPEN_ACCESSIBILITY
|
|
226
|
+
OPEN_ACCESSIBILITY=${OPEN_ACCESSIBILITY:-y}
|
|
227
|
+
|
|
228
|
+
if [ "$OPEN_ACCESSIBILITY" = "y" ] || [ "$OPEN_ACCESSIBILITY" = "Y" ]; then
|
|
229
|
+
echo -e " ${YELLOW}Opening System Settings > Privacy & Security > Accessibility...${NC}"
|
|
230
|
+
open "x-apple.systempreferences:com.apple.preference.security?Privacy_Accessibility"
|
|
231
|
+
echo -e " ${GREEN}Please add '$TERMINAL_APP' and/or 'deskmate' to the list${NC}"
|
|
232
|
+
read -p " Press Enter when done..."
|
|
233
|
+
fi
|
|
234
|
+
|
|
235
|
+
echo -e "\n${YELLOW}3. Full Disk Access Permission${NC}"
|
|
236
|
+
echo " This allows reading and writing files in protected locations."
|
|
237
|
+
read -p " Open Full Disk Access settings? [Y/n]: " OPEN_DISK
|
|
238
|
+
OPEN_DISK=${OPEN_DISK:-y}
|
|
239
|
+
|
|
240
|
+
if [ "$OPEN_DISK" = "y" ] || [ "$OPEN_DISK" = "Y" ]; then
|
|
241
|
+
echo -e " ${YELLOW}Opening System Settings > Privacy & Security > Full Disk Access...${NC}"
|
|
242
|
+
open "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles"
|
|
243
|
+
echo -e " ${GREEN}Please add '$TERMINAL_APP' and/or 'deskmate' to the list${NC}"
|
|
244
|
+
read -p " Press Enter when done..."
|
|
245
|
+
fi
|
|
246
|
+
|
|
247
|
+
echo -e "\n${YELLOW}4. Automation Permission${NC}"
|
|
248
|
+
echo " This allows controlling other applications via AppleScript."
|
|
249
|
+
read -p " Open Automation settings? [Y/n]: " OPEN_AUTOMATION
|
|
250
|
+
OPEN_AUTOMATION=${OPEN_AUTOMATION:-y}
|
|
251
|
+
|
|
252
|
+
if [ "$OPEN_AUTOMATION" = "y" ] || [ "$OPEN_AUTOMATION" = "Y" ]; then
|
|
253
|
+
echo -e " ${YELLOW}Opening System Settings > Privacy & Security > Automation...${NC}"
|
|
254
|
+
open "x-apple.systempreferences:com.apple.preference.security?Privacy_Automation"
|
|
255
|
+
echo -e " ${GREEN}Please enable automation for '$TERMINAL_APP' if listed${NC}"
|
|
256
|
+
read -p " Press Enter when done..."
|
|
257
|
+
fi
|
|
258
|
+
|
|
259
|
+
echo -e "\n${YELLOW}5. Background Items (Login Items)${NC}"
|
|
260
|
+
echo " This allows the service to run in the background and start at login."
|
|
261
|
+
read -p " Open Login Items settings? [Y/n]: " OPEN_LOGIN
|
|
262
|
+
OPEN_LOGIN=${OPEN_LOGIN:-y}
|
|
263
|
+
|
|
264
|
+
if [ "$OPEN_LOGIN" = "y" ] || [ "$OPEN_LOGIN" = "Y" ]; then
|
|
265
|
+
echo -e " ${YELLOW}Opening System Settings > General > Login Items...${NC}"
|
|
266
|
+
open "x-apple.systempreferences:com.apple.LoginItems-Settings.extension"
|
|
267
|
+
echo -e " ${GREEN}Ensure 'node' is enabled under 'Allow in the Background'${NC}"
|
|
268
|
+
read -p " Press Enter when done..."
|
|
269
|
+
fi
|
|
270
|
+
|
|
271
|
+
echo -e "\n${GREEN}✓ Permissions setup complete${NC}"
|
|
272
|
+
echo -e "${YELLOW}Note: Some permissions may require restarting the terminal or service${NC}"
|
|
273
|
+
else
|
|
274
|
+
echo -e "${YELLOW}Skipping permissions setup. You can configure them later in:${NC}"
|
|
275
|
+
echo -e " System Settings > Privacy & Security"
|
|
276
|
+
fi
|
|
277
|
+
fi
|
|
278
|
+
|
|
279
|
+
# =============================================================================
|
|
280
|
+
# 5. Folder Access Configuration (macOS only — Linux doesn't have TCC dialogs)
|
|
281
|
+
# =============================================================================
|
|
282
|
+
if [ "$PLATFORM" = "macos" ]; then
|
|
283
|
+
echo -e "\n${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
284
|
+
echo -e "${YELLOW}Configuring folder access...${NC}"
|
|
285
|
+
echo ""
|
|
286
|
+
echo -e "macOS will ask for permission when the agent accesses protected folders."
|
|
287
|
+
echo -e "Let's configure which folders the agent should have access to."
|
|
288
|
+
echo ""
|
|
289
|
+
|
|
290
|
+
# Common protected folders
|
|
291
|
+
FOLDERS_TO_CONFIGURE=""
|
|
292
|
+
|
|
293
|
+
echo -e "${YELLOW}Select folders to grant access (this will trigger macOS permission dialogs):${NC}"
|
|
294
|
+
echo ""
|
|
295
|
+
|
|
296
|
+
# Desktop
|
|
297
|
+
read -p " Grant access to Desktop? [Y/n]: " ACCESS_DESKTOP
|
|
298
|
+
ACCESS_DESKTOP=${ACCESS_DESKTOP:-y}
|
|
299
|
+
if [ "$ACCESS_DESKTOP" = "y" ] || [ "$ACCESS_DESKTOP" = "Y" ]; then
|
|
300
|
+
echo -e " ${YELLOW}Triggering Desktop access...${NC}"
|
|
301
|
+
ls "$HOME/Desktop" > /dev/null 2>&1 || true
|
|
302
|
+
FOLDERS_TO_CONFIGURE="$HOME/Desktop"
|
|
303
|
+
echo -e " ${GREEN}✓ Desktop access requested${NC}"
|
|
304
|
+
fi
|
|
305
|
+
|
|
306
|
+
# Documents
|
|
307
|
+
read -p " Grant access to Documents? [Y/n]: " ACCESS_DOCUMENTS
|
|
308
|
+
ACCESS_DOCUMENTS=${ACCESS_DOCUMENTS:-y}
|
|
309
|
+
if [ "$ACCESS_DOCUMENTS" = "y" ] || [ "$ACCESS_DOCUMENTS" = "Y" ]; then
|
|
310
|
+
echo -e " ${YELLOW}Triggering Documents access...${NC}"
|
|
311
|
+
ls "$HOME/Documents" > /dev/null 2>&1 || true
|
|
312
|
+
FOLDERS_TO_CONFIGURE="$FOLDERS_TO_CONFIGURE:$HOME/Documents"
|
|
313
|
+
echo -e " ${GREEN}✓ Documents access requested${NC}"
|
|
314
|
+
fi
|
|
315
|
+
|
|
316
|
+
# Downloads
|
|
317
|
+
read -p " Grant access to Downloads? [Y/n]: " ACCESS_DOWNLOADS
|
|
318
|
+
ACCESS_DOWNLOADS=${ACCESS_DOWNLOADS:-y}
|
|
319
|
+
if [ "$ACCESS_DOWNLOADS" = "y" ] || [ "$ACCESS_DOWNLOADS" = "Y" ]; then
|
|
320
|
+
echo -e " ${YELLOW}Triggering Downloads access...${NC}"
|
|
321
|
+
ls "$HOME/Downloads" > /dev/null 2>&1 || true
|
|
322
|
+
FOLDERS_TO_CONFIGURE="$FOLDERS_TO_CONFIGURE:$HOME/Downloads"
|
|
323
|
+
echo -e " ${GREEN}✓ Downloads access requested${NC}"
|
|
324
|
+
fi
|
|
325
|
+
|
|
326
|
+
# Pictures
|
|
327
|
+
read -p " Grant access to Pictures? [y/N]: " ACCESS_PICTURES
|
|
328
|
+
if [ "$ACCESS_PICTURES" = "y" ] || [ "$ACCESS_PICTURES" = "Y" ]; then
|
|
329
|
+
echo -e " ${YELLOW}Triggering Pictures access...${NC}"
|
|
330
|
+
ls "$HOME/Pictures" > /dev/null 2>&1 || true
|
|
331
|
+
FOLDERS_TO_CONFIGURE="$FOLDERS_TO_CONFIGURE:$HOME/Pictures"
|
|
332
|
+
echo -e " ${GREEN}✓ Pictures access requested${NC}"
|
|
333
|
+
fi
|
|
334
|
+
|
|
335
|
+
# Movies
|
|
336
|
+
read -p " Grant access to Movies? [y/N]: " ACCESS_MOVIES
|
|
337
|
+
if [ "$ACCESS_MOVIES" = "y" ] || [ "$ACCESS_MOVIES" = "Y" ]; then
|
|
338
|
+
echo -e " ${YELLOW}Triggering Movies access...${NC}"
|
|
339
|
+
ls "$HOME/Movies" > /dev/null 2>&1 || true
|
|
340
|
+
FOLDERS_TO_CONFIGURE="$FOLDERS_TO_CONFIGURE:$HOME/Movies"
|
|
341
|
+
echo -e " ${GREEN}✓ Movies access requested${NC}"
|
|
342
|
+
fi
|
|
343
|
+
|
|
344
|
+
# Music
|
|
345
|
+
read -p " Grant access to Music? [y/N]: " ACCESS_MUSIC
|
|
346
|
+
if [ "$ACCESS_MUSIC" = "y" ] || [ "$ACCESS_MUSIC" = "Y" ]; then
|
|
347
|
+
echo -e " ${YELLOW}Triggering Music access...${NC}"
|
|
348
|
+
ls "$HOME/Music" > /dev/null 2>&1 || true
|
|
349
|
+
FOLDERS_TO_CONFIGURE="$FOLDERS_TO_CONFIGURE:$HOME/Music"
|
|
350
|
+
echo -e " ${GREEN}✓ Music access requested${NC}"
|
|
351
|
+
fi
|
|
352
|
+
|
|
353
|
+
# iCloud Drive
|
|
354
|
+
if [ -d "$HOME/Library/Mobile Documents/com~apple~CloudDocs" ]; then
|
|
355
|
+
read -p " Grant access to iCloud Drive? [y/N]: " ACCESS_ICLOUD
|
|
356
|
+
if [ "$ACCESS_ICLOUD" = "y" ] || [ "$ACCESS_ICLOUD" = "Y" ]; then
|
|
357
|
+
echo -e " ${YELLOW}Triggering iCloud Drive access...${NC}"
|
|
358
|
+
ls "$HOME/Library/Mobile Documents/com~apple~CloudDocs" > /dev/null 2>&1 || true
|
|
359
|
+
FOLDERS_TO_CONFIGURE="$FOLDERS_TO_CONFIGURE:$HOME/Library/Mobile Documents/com~apple~CloudDocs"
|
|
360
|
+
echo -e " ${GREEN}✓ iCloud Drive access requested${NC}"
|
|
361
|
+
fi
|
|
362
|
+
fi
|
|
363
|
+
|
|
364
|
+
# Custom folder
|
|
365
|
+
echo ""
|
|
366
|
+
read -p " Add a custom folder path? [y/N]: " ADD_CUSTOM
|
|
367
|
+
if [ "$ADD_CUSTOM" = "y" ] || [ "$ADD_CUSTOM" = "Y" ]; then
|
|
368
|
+
read -p " Enter folder path: " CUSTOM_FOLDER
|
|
369
|
+
if [ -d "$CUSTOM_FOLDER" ]; then
|
|
370
|
+
echo -e " ${YELLOW}Triggering access to $CUSTOM_FOLDER...${NC}"
|
|
371
|
+
ls "$CUSTOM_FOLDER" > /dev/null 2>&1 || true
|
|
372
|
+
FOLDERS_TO_CONFIGURE="$FOLDERS_TO_CONFIGURE:$CUSTOM_FOLDER"
|
|
373
|
+
echo -e " ${GREEN}✓ Custom folder access requested${NC}"
|
|
374
|
+
else
|
|
375
|
+
echo -e " ${RED}✗ Folder not found: $CUSTOM_FOLDER${NC}"
|
|
376
|
+
fi
|
|
377
|
+
fi
|
|
378
|
+
|
|
379
|
+
# Clean up the folders string (remove leading colon)
|
|
380
|
+
FOLDERS_TO_CONFIGURE=$(echo "$FOLDERS_TO_CONFIGURE" | sed 's/^://')
|
|
381
|
+
|
|
382
|
+
# Save to .env if not already there
|
|
383
|
+
if [ -n "$FOLDERS_TO_CONFIGURE" ]; then
|
|
384
|
+
# Check if ALLOWED_FOLDERS exists in .env
|
|
385
|
+
if grep -q "^ALLOWED_FOLDERS=" "$PROJECT_DIR/.env" 2>/dev/null; then
|
|
386
|
+
# Update existing
|
|
387
|
+
sed_inplace "s|^ALLOWED_FOLDERS=.*|ALLOWED_FOLDERS=$FOLDERS_TO_CONFIGURE|" "$PROJECT_DIR/.env"
|
|
388
|
+
else
|
|
389
|
+
# Add new
|
|
390
|
+
echo "" >> "$PROJECT_DIR/.env"
|
|
391
|
+
echo "# Folders the agent is allowed to access" >> "$PROJECT_DIR/.env"
|
|
392
|
+
echo "ALLOWED_FOLDERS=$FOLDERS_TO_CONFIGURE" >> "$PROJECT_DIR/.env"
|
|
393
|
+
fi
|
|
394
|
+
echo -e "\n${GREEN}✓ Folder access configuration saved to .env${NC}"
|
|
395
|
+
fi
|
|
396
|
+
|
|
397
|
+
echo -e "${YELLOW}Note: If permission dialogs appeared, make sure to click 'Allow'${NC}"
|
|
398
|
+
echo -e "${YELLOW} You may need to restart the service for changes to take effect${NC}"
|
|
399
|
+
fi
|
|
400
|
+
|
|
401
|
+
# =============================================================================
|
|
402
|
+
# 6. Mode Selection
|
|
403
|
+
# =============================================================================
|
|
404
|
+
echo -e "\n${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
405
|
+
echo -e "${YELLOW}Which mode would you like to install?${NC}"
|
|
406
|
+
echo ""
|
|
407
|
+
echo -e " ${GREEN}1)${NC} Gateway (recommended)"
|
|
408
|
+
echo " Multi-client gateway with Telegram"
|
|
409
|
+
echo ""
|
|
410
|
+
echo -e " ${GREEN}2)${NC} MCP only"
|
|
411
|
+
echo " Expose as MCP server for Claude Desktop"
|
|
412
|
+
echo ""
|
|
413
|
+
echo -e " ${GREEN}3)${NC} Both"
|
|
414
|
+
echo " Gateway + MCP server together"
|
|
415
|
+
echo ""
|
|
416
|
+
read -p "Choose mode [1/2/3] (default: 1): " MODE_CHOICE
|
|
417
|
+
MODE_CHOICE=${MODE_CHOICE:-1}
|
|
418
|
+
|
|
419
|
+
case $MODE_CHOICE in
|
|
420
|
+
2)
|
|
421
|
+
RUN_MODE="mcp"
|
|
422
|
+
echo -e "${GREEN}✓ MCP mode selected${NC}"
|
|
423
|
+
;;
|
|
424
|
+
3)
|
|
425
|
+
RUN_MODE="both"
|
|
426
|
+
echo -e "${GREEN}✓ Both modes selected${NC}"
|
|
427
|
+
;;
|
|
428
|
+
*)
|
|
429
|
+
RUN_MODE="gateway"
|
|
430
|
+
echo -e "${GREEN}✓ Gateway mode selected${NC}"
|
|
431
|
+
;;
|
|
432
|
+
esac
|
|
433
|
+
|
|
434
|
+
# MCP Configuration for Claude Desktop - auto-configure when MCP mode is selected
|
|
435
|
+
CONFIGURE_CLAUDE_DESKTOP=false
|
|
436
|
+
if [ "$RUN_MODE" = "mcp" ] || [ "$RUN_MODE" = "both" ]; then
|
|
437
|
+
CONFIGURE_CLAUDE_DESKTOP=true
|
|
438
|
+
echo -e "${GREEN}✓ Will configure Claude Desktop for MCP${NC}"
|
|
439
|
+
fi
|
|
440
|
+
|
|
441
|
+
# =============================================================================
|
|
442
|
+
# 7. Sleep Prevention (for gateway/both modes)
|
|
443
|
+
# =============================================================================
|
|
444
|
+
if [ "$RUN_MODE" = "gateway" ] || [ "$RUN_MODE" = "both" ]; then
|
|
445
|
+
echo -e "\n${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
446
|
+
echo -e "${YELLOW}Configuring system sleep settings...${NC}"
|
|
447
|
+
|
|
448
|
+
USE_CAFFEINATE=false
|
|
449
|
+
|
|
450
|
+
if [ "$PLATFORM" = "macos" ]; then
|
|
451
|
+
echo -e "${YELLOW}This requires sudo access to modify power management settings.${NC}"
|
|
452
|
+
sudo pmset -c sleep 0 displaysleep 10
|
|
453
|
+
echo -e "${GREEN}✓ System configured: sleep disabled when plugged in, display sleeps after 10 min${NC}"
|
|
454
|
+
|
|
455
|
+
# Ask if user also wants caffeinate as extra protection
|
|
456
|
+
echo ""
|
|
457
|
+
echo -e "${YELLOW}Optional: Also use caffeinate for extra protection?${NC}"
|
|
458
|
+
echo " This adds an extra layer - prevents sleep specifically while the service runs."
|
|
459
|
+
echo ""
|
|
460
|
+
read -p "Enable caffeinate? [y/N]: " ENABLE_CAFFEINATE
|
|
461
|
+
|
|
462
|
+
if [ "$ENABLE_CAFFEINATE" = "y" ] || [ "$ENABLE_CAFFEINATE" = "Y" ]; then
|
|
463
|
+
USE_CAFFEINATE=true
|
|
464
|
+
echo -e "${GREEN}✓ Caffeinate enabled${NC}"
|
|
465
|
+
else
|
|
466
|
+
echo -e "${GREEN}✓ Using system settings only${NC}"
|
|
467
|
+
fi
|
|
468
|
+
elif [ "$PLATFORM" = "linux" ]; then
|
|
469
|
+
echo -e "${YELLOW}On Linux, sleep prevention depends on your desktop environment.${NC}"
|
|
470
|
+
echo -e " You can use ${GREEN}systemd-inhibit${NC} to prevent sleep while the service runs."
|
|
471
|
+
echo -e " The systemd service will be configured with the Idle inhibitor."
|
|
472
|
+
echo -e "${GREEN}✓ Sleep prevention will be handled by the systemd service${NC}"
|
|
473
|
+
fi
|
|
474
|
+
fi
|
|
475
|
+
|
|
476
|
+
# =============================================================================
|
|
477
|
+
# 8. Service Installation (platform-specific)
|
|
478
|
+
# =============================================================================
|
|
479
|
+
|
|
480
|
+
if [ "$PLATFORM" = "macos" ]; then
|
|
481
|
+
# ── macOS: launchd ──────────────────────────────────────────────────
|
|
482
|
+
|
|
483
|
+
# Unload existing service if present
|
|
484
|
+
if launchctl list 2>/dev/null | grep -q "$PLIST_NAME"; then
|
|
485
|
+
echo -e "\n${YELLOW}Stopping existing service...${NC}"
|
|
486
|
+
launchctl unload "$PLIST_PATH" 2>/dev/null || true
|
|
487
|
+
echo -e "${GREEN}✓ Existing service stopped${NC}"
|
|
488
|
+
fi
|
|
489
|
+
|
|
490
|
+
# Create the launchd plist file (for gateway or both modes)
|
|
491
|
+
if [ "$RUN_MODE" = "gateway" ] || [ "$RUN_MODE" = "both" ]; then
|
|
492
|
+
echo -e "\n${YELLOW}Creating launchd service...${NC}"
|
|
493
|
+
|
|
494
|
+
if [ "$USE_CAFFEINATE" = true ]; then
|
|
495
|
+
cat > "$PLIST_PATH" << EOF
|
|
496
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
497
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
498
|
+
<plist version="1.0">
|
|
499
|
+
<dict>
|
|
500
|
+
<key>Label</key>
|
|
501
|
+
<string>$PLIST_NAME</string>
|
|
502
|
+
|
|
503
|
+
<key>ProgramArguments</key>
|
|
504
|
+
<array>
|
|
505
|
+
<string>/usr/bin/caffeinate</string>
|
|
506
|
+
<string>-i</string>
|
|
507
|
+
<string>$NODE_PATH</string>
|
|
508
|
+
<string>$PROJECT_DIR/dist/index.js</string>
|
|
509
|
+
<string>$RUN_MODE</string>
|
|
510
|
+
</array>
|
|
511
|
+
|
|
512
|
+
<key>WorkingDirectory</key>
|
|
513
|
+
<string>$PROJECT_DIR</string>
|
|
514
|
+
|
|
515
|
+
<key>EnvironmentVariables</key>
|
|
516
|
+
<dict>
|
|
517
|
+
<key>PATH</key>
|
|
518
|
+
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$HOME/.local/bin</string>
|
|
519
|
+
</dict>
|
|
520
|
+
|
|
521
|
+
<key>RunAtLoad</key>
|
|
522
|
+
<true/>
|
|
523
|
+
|
|
524
|
+
<key>KeepAlive</key>
|
|
525
|
+
<true/>
|
|
526
|
+
|
|
527
|
+
<key>StandardOutPath</key>
|
|
528
|
+
<string>$LOGS_DIR/stdout.log</string>
|
|
529
|
+
|
|
530
|
+
<key>StandardErrorPath</key>
|
|
531
|
+
<string>$LOGS_DIR/stderr.log</string>
|
|
532
|
+
</dict>
|
|
533
|
+
</plist>
|
|
534
|
+
EOF
|
|
535
|
+
else
|
|
536
|
+
cat > "$PLIST_PATH" << EOF
|
|
537
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
538
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
539
|
+
<plist version="1.0">
|
|
540
|
+
<dict>
|
|
541
|
+
<key>Label</key>
|
|
542
|
+
<string>$PLIST_NAME</string>
|
|
543
|
+
|
|
544
|
+
<key>ProgramArguments</key>
|
|
545
|
+
<array>
|
|
546
|
+
<string>$NODE_PATH</string>
|
|
547
|
+
<string>$PROJECT_DIR/dist/index.js</string>
|
|
548
|
+
<string>$RUN_MODE</string>
|
|
549
|
+
</array>
|
|
550
|
+
|
|
551
|
+
<key>WorkingDirectory</key>
|
|
552
|
+
<string>$PROJECT_DIR</string>
|
|
553
|
+
|
|
554
|
+
<key>EnvironmentVariables</key>
|
|
555
|
+
<dict>
|
|
556
|
+
<key>PATH</key>
|
|
557
|
+
<string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$HOME/.local/bin</string>
|
|
558
|
+
</dict>
|
|
559
|
+
|
|
560
|
+
<key>RunAtLoad</key>
|
|
561
|
+
<true/>
|
|
562
|
+
|
|
563
|
+
<key>KeepAlive</key>
|
|
564
|
+
<true/>
|
|
565
|
+
|
|
566
|
+
<key>StandardOutPath</key>
|
|
567
|
+
<string>$LOGS_DIR/stdout.log</string>
|
|
568
|
+
|
|
569
|
+
<key>StandardErrorPath</key>
|
|
570
|
+
<string>$LOGS_DIR/stderr.log</string>
|
|
571
|
+
</dict>
|
|
572
|
+
</plist>
|
|
573
|
+
EOF
|
|
574
|
+
fi
|
|
575
|
+
|
|
576
|
+
echo -e "${GREEN}✓ Service configuration created${NC}"
|
|
577
|
+
|
|
578
|
+
# Load the service
|
|
579
|
+
echo -e "\n${YELLOW}Starting service...${NC}"
|
|
580
|
+
launchctl load "$PLIST_PATH"
|
|
581
|
+
sleep 2
|
|
582
|
+
|
|
583
|
+
# Check if service is running
|
|
584
|
+
if launchctl list | grep -q "$PLIST_NAME"; then
|
|
585
|
+
echo -e "${GREEN}✓ Service started successfully${NC}"
|
|
586
|
+
else
|
|
587
|
+
echo -e "${RED}✗ Service failed to start. Check logs:${NC}"
|
|
588
|
+
echo -e " tail -f $LOGS_DIR/stderr.log"
|
|
589
|
+
exit 1
|
|
590
|
+
fi
|
|
591
|
+
fi
|
|
592
|
+
|
|
593
|
+
elif [ "$PLATFORM" = "linux" ]; then
|
|
594
|
+
# ── Linux: systemd user service ─────────────────────────────────────
|
|
595
|
+
|
|
596
|
+
# Stop existing service if present
|
|
597
|
+
if systemctl --user is-active "$SYSTEMD_SERVICE" &>/dev/null; then
|
|
598
|
+
echo -e "\n${YELLOW}Stopping existing service...${NC}"
|
|
599
|
+
systemctl --user stop "$SYSTEMD_SERVICE" 2>/dev/null || true
|
|
600
|
+
echo -e "${GREEN}✓ Existing service stopped${NC}"
|
|
601
|
+
fi
|
|
602
|
+
|
|
603
|
+
# Create the systemd user service (for gateway or both modes)
|
|
604
|
+
if [ "$RUN_MODE" = "gateway" ] || [ "$RUN_MODE" = "both" ]; then
|
|
605
|
+
echo -e "\n${YELLOW}Creating systemd user service...${NC}"
|
|
606
|
+
|
|
607
|
+
mkdir -p "$SYSTEMD_DIR"
|
|
608
|
+
cat > "$SYSTEMD_PATH" << EOF
|
|
609
|
+
[Unit]
|
|
610
|
+
Description=Deskmate - Local Machine Assistant
|
|
611
|
+
After=network-online.target
|
|
612
|
+
Wants=network-online.target
|
|
613
|
+
|
|
614
|
+
[Service]
|
|
615
|
+
Type=simple
|
|
616
|
+
ExecStart=$NODE_PATH $PROJECT_DIR/dist/index.js $RUN_MODE
|
|
617
|
+
WorkingDirectory=$PROJECT_DIR
|
|
618
|
+
Environment=PATH=/usr/local/bin:/usr/bin:/bin:$HOME/.local/bin
|
|
619
|
+
Restart=always
|
|
620
|
+
RestartSec=5
|
|
621
|
+
|
|
622
|
+
# Prevent system sleep while running
|
|
623
|
+
InhibitDelayMaxSec=5
|
|
624
|
+
|
|
625
|
+
StandardOutput=append:$LOGS_DIR/stdout.log
|
|
626
|
+
StandardError=append:$LOGS_DIR/stderr.log
|
|
627
|
+
|
|
628
|
+
[Install]
|
|
629
|
+
WantedBy=default.target
|
|
630
|
+
EOF
|
|
631
|
+
|
|
632
|
+
echo -e "${GREEN}✓ Service configuration created${NC}"
|
|
633
|
+
|
|
634
|
+
# Reload and start the service
|
|
635
|
+
echo -e "\n${YELLOW}Starting service...${NC}"
|
|
636
|
+
systemctl --user daemon-reload
|
|
637
|
+
systemctl --user enable "$SYSTEMD_SERVICE"
|
|
638
|
+
systemctl --user start "$SYSTEMD_SERVICE"
|
|
639
|
+
sleep 2
|
|
640
|
+
|
|
641
|
+
# Check if service is running
|
|
642
|
+
if systemctl --user is-active "$SYSTEMD_SERVICE" &>/dev/null; then
|
|
643
|
+
echo -e "${GREEN}✓ Service started successfully${NC}"
|
|
644
|
+
else
|
|
645
|
+
echo -e "${RED}✗ Service failed to start. Check logs:${NC}"
|
|
646
|
+
echo -e " journalctl --user -u $SYSTEMD_SERVICE -f"
|
|
647
|
+
echo -e " tail -f $LOGS_DIR/stderr.log"
|
|
648
|
+
exit 1
|
|
649
|
+
fi
|
|
650
|
+
|
|
651
|
+
# Enable lingering so the user service runs without an active login session
|
|
652
|
+
if command -v loginctl &>/dev/null; then
|
|
653
|
+
loginctl enable-linger "$(whoami)" 2>/dev/null || true
|
|
654
|
+
echo -e "${GREEN}✓ Lingering enabled (service runs without active login)${NC}"
|
|
655
|
+
fi
|
|
656
|
+
fi
|
|
657
|
+
fi
|
|
658
|
+
|
|
659
|
+
# =============================================================================
|
|
660
|
+
# 9. Claude Desktop MCP Config
|
|
661
|
+
# =============================================================================
|
|
662
|
+
if [ "$CONFIGURE_CLAUDE_DESKTOP" = true ]; then
|
|
663
|
+
echo -e "\n${YELLOW}Configuring Claude Desktop...${NC}"
|
|
664
|
+
|
|
665
|
+
# Create config directory if it doesn't exist
|
|
666
|
+
mkdir -p "$(dirname "$CLAUDE_DESKTOP_CONFIG")"
|
|
667
|
+
|
|
668
|
+
# Get WORKING_DIR from .env or use HOME
|
|
669
|
+
WORKING_DIR=$(grep -E "^WORKING_DIR=" "$PROJECT_DIR/.env" | cut -d'=' -f2 || echo "$HOME")
|
|
670
|
+
WORKING_DIR=${WORKING_DIR:-$HOME}
|
|
671
|
+
|
|
672
|
+
# Check if config file exists and has content
|
|
673
|
+
if [ -f "$CLAUDE_DESKTOP_CONFIG" ] && [ -s "$CLAUDE_DESKTOP_CONFIG" ]; then
|
|
674
|
+
# Backup existing config
|
|
675
|
+
cp "$CLAUDE_DESKTOP_CONFIG" "$CLAUDE_DESKTOP_CONFIG.backup"
|
|
676
|
+
echo -e "${GREEN}✓ Backed up existing config${NC}"
|
|
677
|
+
|
|
678
|
+
# Check if deskmate already configured
|
|
679
|
+
if grep -q '"deskmate"' "$CLAUDE_DESKTOP_CONFIG"; then
|
|
680
|
+
echo -e "${YELLOW}⚠ deskmate already configured in Claude Desktop${NC}"
|
|
681
|
+
echo " Please manually update the config if needed."
|
|
682
|
+
else
|
|
683
|
+
# Add to existing config using Python (more reliable JSON handling)
|
|
684
|
+
python3 << PYTHON_EOF
|
|
685
|
+
import json
|
|
686
|
+
|
|
687
|
+
config_path = "$CLAUDE_DESKTOP_CONFIG"
|
|
688
|
+
with open(config_path, 'r') as f:
|
|
689
|
+
config = json.load(f)
|
|
690
|
+
|
|
691
|
+
if 'mcpServers' not in config:
|
|
692
|
+
config['mcpServers'] = {}
|
|
693
|
+
|
|
694
|
+
config['mcpServers']['deskmate'] = {
|
|
695
|
+
"command": "$NODE_PATH",
|
|
696
|
+
"args": ["$PROJECT_DIR/dist/index.js", "mcp"],
|
|
697
|
+
"env": {
|
|
698
|
+
"WORKING_DIR": "$WORKING_DIR"
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
with open(config_path, 'w') as f:
|
|
703
|
+
json.dump(config, f, indent=2)
|
|
704
|
+
|
|
705
|
+
print("Config updated successfully")
|
|
706
|
+
PYTHON_EOF
|
|
707
|
+
echo -e "${GREEN}✓ Added deskmate to Claude Desktop config${NC}"
|
|
708
|
+
fi
|
|
709
|
+
else
|
|
710
|
+
# Create new config file
|
|
711
|
+
cat > "$CLAUDE_DESKTOP_CONFIG" << EOF
|
|
712
|
+
{
|
|
713
|
+
"mcpServers": {
|
|
714
|
+
"deskmate": {
|
|
715
|
+
"command": "$NODE_PATH",
|
|
716
|
+
"args": ["$PROJECT_DIR/dist/index.js", "mcp"],
|
|
717
|
+
"env": {
|
|
718
|
+
"WORKING_DIR": "$WORKING_DIR"
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
EOF
|
|
724
|
+
echo -e "${GREEN}✓ Created Claude Desktop config${NC}"
|
|
725
|
+
fi
|
|
726
|
+
|
|
727
|
+
echo -e "${YELLOW}Note: Restart Claude Desktop for changes to take effect${NC}"
|
|
728
|
+
fi
|
|
729
|
+
|
|
730
|
+
# =============================================================================
|
|
731
|
+
# 10. Summary
|
|
732
|
+
# =============================================================================
|
|
733
|
+
echo -e "\n${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
734
|
+
echo -e "${GREEN}Installation complete!${NC}"
|
|
735
|
+
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|
|
736
|
+
echo ""
|
|
737
|
+
|
|
738
|
+
case $RUN_MODE in
|
|
739
|
+
gateway)
|
|
740
|
+
echo -e "Your gateway is now running as a background service."
|
|
741
|
+
echo -e "Telegram client is active — open Telegram and message your bot."
|
|
742
|
+
;;
|
|
743
|
+
mcp)
|
|
744
|
+
echo -e "MCP server configured for Claude Desktop."
|
|
745
|
+
echo -e "Claude Desktop will start the MCP server on demand."
|
|
746
|
+
;;
|
|
747
|
+
both)
|
|
748
|
+
echo -e "Both gateway and MCP server are configured!"
|
|
749
|
+
echo -e "• Gateway: Running as background service (Telegram active)"
|
|
750
|
+
echo -e "• MCP server: Available to Claude Desktop"
|
|
751
|
+
;;
|
|
752
|
+
esac
|
|
753
|
+
|
|
754
|
+
echo ""
|
|
755
|
+
echo -e "${YELLOW}Useful commands:${NC}"
|
|
756
|
+
|
|
757
|
+
if [ "$RUN_MODE" = "gateway" ] || [ "$RUN_MODE" = "both" ]; then
|
|
758
|
+
echo -e " ${GREEN}View logs:${NC}"
|
|
759
|
+
echo " tail -f $LOGS_DIR/stdout.log"
|
|
760
|
+
echo " tail -f $LOGS_DIR/stderr.log"
|
|
761
|
+
echo ""
|
|
762
|
+
|
|
763
|
+
if [ "$PLATFORM" = "macos" ]; then
|
|
764
|
+
echo -e " ${GREEN}Stop service:${NC}"
|
|
765
|
+
echo " launchctl unload $PLIST_PATH"
|
|
766
|
+
echo ""
|
|
767
|
+
echo -e " ${GREEN}Start service:${NC}"
|
|
768
|
+
echo " launchctl load $PLIST_PATH"
|
|
769
|
+
echo ""
|
|
770
|
+
echo -e " ${GREEN}Restart service:${NC}"
|
|
771
|
+
echo " launchctl unload $PLIST_PATH && launchctl load $PLIST_PATH"
|
|
772
|
+
echo ""
|
|
773
|
+
echo -e " ${GREEN}Check status:${NC}"
|
|
774
|
+
echo " launchctl list | grep deskmate"
|
|
775
|
+
echo ""
|
|
776
|
+
echo -e " ${GREEN}Restore default sleep settings:${NC}"
|
|
777
|
+
echo " sudo pmset -c sleep 1"
|
|
778
|
+
elif [ "$PLATFORM" = "linux" ]; then
|
|
779
|
+
echo -e " ${GREEN}Stop service:${NC}"
|
|
780
|
+
echo " systemctl --user stop $SYSTEMD_SERVICE"
|
|
781
|
+
echo ""
|
|
782
|
+
echo -e " ${GREEN}Start service:${NC}"
|
|
783
|
+
echo " systemctl --user start $SYSTEMD_SERVICE"
|
|
784
|
+
echo ""
|
|
785
|
+
echo -e " ${GREEN}Restart service:${NC}"
|
|
786
|
+
echo " systemctl --user restart $SYSTEMD_SERVICE"
|
|
787
|
+
echo ""
|
|
788
|
+
echo -e " ${GREEN}Check status:${NC}"
|
|
789
|
+
echo " systemctl --user status $SYSTEMD_SERVICE"
|
|
790
|
+
echo ""
|
|
791
|
+
echo -e " ${GREEN}View journal logs:${NC}"
|
|
792
|
+
echo " journalctl --user -u $SYSTEMD_SERVICE -f"
|
|
793
|
+
fi
|
|
794
|
+
fi
|
|
795
|
+
|
|
796
|
+
if [ "$RUN_MODE" = "mcp" ] || [ "$RUN_MODE" = "both" ]; then
|
|
797
|
+
echo ""
|
|
798
|
+
echo -e " ${GREEN}Test MCP server manually:${NC}"
|
|
799
|
+
echo " npm run start:mcp"
|
|
800
|
+
echo ""
|
|
801
|
+
echo -e " ${GREEN}Claude Desktop config location:${NC}"
|
|
802
|
+
echo " $CLAUDE_DESKTOP_CONFIG"
|
|
803
|
+
fi
|
|
804
|
+
|
|
805
|
+
echo ""
|
|
806
|
+
echo -e " ${GREEN}Reconfigure:${NC}"
|
|
807
|
+
echo " deskmate init"
|
|
808
|
+
echo ""
|
|
809
|
+
|
|
810
|
+
if [ "$PLATFORM" = "macos" ]; then
|
|
811
|
+
echo -e "${YELLOW}Permissions reminder:${NC}"
|
|
812
|
+
echo " If you skipped permissions setup or need to reconfigure:"
|
|
813
|
+
echo " System Settings > Privacy & Security > [Screen Recording/Accessibility/Full Disk Access]"
|
|
814
|
+
echo ""
|
|
815
|
+
fi
|
|
816
|
+
|
|
817
|
+
echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}"
|