Repository navigation
Expand file tree
/
Copy pathsetup.sh
More file actions
executable file
·225 lines (190 loc) · 7.26 KB
/
Copy pathsetup.sh
File metadata and controls
executable file
·225 lines (190 loc) · 7.26 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
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
#!/bin/bash
# NPC-Forge User-Space Installer
#
# Usage:
#
# ./setup.sh # install NPC-Forge production copy
# ./setup.sh --dev # install using symlink sources (edit-in-place)
# ./setup.sh --uninstall # uninstall NPC-Forge
set -euo pipefail
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Standard XDG Directory
FORGE_DIR="$HOME/.local/share/npc-forge"
BIN_DIR="$HOME/.local/bin"
SERVICE_DIR="$HOME/.config/systemd/user"
SERVICE_FILE="$SERVICE_DIR/npc-forge.service"
SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# uninstall if requested
if [ "${1:-}" == "--uninstall" ]; then
echo -e "\nRemoving NPC-Forge Framework and User Service...\n"
# Stops and disables user's Systemd service if present
if systemctl --user list-unit-files | grep -q "npc-forge.service"; then
echo -e "${YELLOW} Stopping Systemd user service...${NC}\n"
systemctl --user stop npc-forge.service 2>/dev/null || true
systemctl --user disable npc-forge.service 2>/dev/null || true
fi
# Removes service file if present
rm -f "$SERVICE_FILE"
systemctl --user daemon-reload 2>/dev/null || true
# Removes npc-forge binary
rm -f "$BIN_DIR/npc-forge"
# Removes the framework directory
rm -rf "$FORGE_DIR"
hash -r
echo -e "${YELLOW}npc-forge${NC} removed from user space!\n"
exit 0
fi
echo -e "\n${YELLOW}npc-forge${NC} User Installation\n"
if [ "$EUID" -eq 0 ]; then
echo -e "${RED}⛔ Error: Do NOT run this script as root/sudo.${NC}\n"
echo -e "${YELLOW}This installer is designed to run in user space${NC}\n"
exit 1
fi
DEV_MODE=0
if [ "${1:-}" == "--dev" ]; then
DEV_MODE=1
echo -e "${YELLOW} Dev mode:${NC} symlinking from $SOURCE_DIR"
fi
echo -e " Installing for user: $(whoami)"
# Check for Python 3
if ! command -v python3 >/dev/null 2>&1; then
echo -e "${RED}⛔ Error: Python 3 is not installed or not in PATH.${NC}\n"
exit 1
fi
# Check for Python venv module
if ! python3 -c "import venv" &> /dev/null; then
echo -e "${RED}⛔ Error: Python 'venv' module is not installed.${NC}\n"
echo -e "${YELLOW}On Ubuntu/Debian, install it by running: sudo apt install python3-venv${NC}\n"
exit 1
fi
echo -e " Copying sources to $FORGE_DIR..."
mkdir -p "$FORGE_DIR"
mkdir -p "$BIN_DIR"
# Always start from a clean slate: drop any previously installed sources
# (symlinks or real files/dirs) but never touch generated runtime state.
find "$FORGE_DIR" -mindepth 1 -maxdepth 1 \
! -name venv ! -name npc_forge.log ! -name logs ! -name '*.egg-info' \
-exec rm -rf {} +
if [ "$DEV_MODE" -eq 1 ]; then
# Symlink each top-level entry of src/ (and npcs/) so the whole subtree
# (including js/, html/, npcs/*) is live-editable without per-file loops.
if [ -d "$SOURCE_DIR/src" ]; then
for entry in "$SOURCE_DIR"/src/*; do
ln -sfn "$entry" "$FORGE_DIR/$(basename "$entry")"
done
else
for entry in "$SOURCE_DIR"/*.py; do
[ -f "$entry" ] && ln -sf "$entry" "$FORGE_DIR/$(basename "$entry")"
done
fi
[ -f "$SOURCE_DIR/pyproject.toml" ] && ln -sf "$SOURCE_DIR/pyproject.toml" "$FORGE_DIR/pyproject.toml"
[ -d "$SOURCE_DIR/npcs" ] && ln -sfn "$SOURCE_DIR/npcs" "$FORGE_DIR/npcs"
[ -d "$SOURCE_DIR/tests" ] && ln -sfn "$SOURCE_DIR/tests" "$FORGE_DIR/tests"
else
# Mirror the source tree exactly (adds, updates, AND removes stale files),
# excluding VCS metadata. Requires rsync; falls back to a plain recursive
# copy (without stale-file removal) if rsync is unavailable.
if command -v rsync >/dev/null 2>&1; then
if [ -d "$SOURCE_DIR/src" ]; then
rsync -a --delete --exclude='.git' "$SOURCE_DIR/src/" "$FORGE_DIR/"
else
rsync -a --delete --exclude='.git' --include='*.py' --exclude='*' "$SOURCE_DIR/" "$FORGE_DIR/"
fi
[ -d "$SOURCE_DIR/npcs" ] && rsync -a --delete --exclude='.git' "$SOURCE_DIR/npcs/" "$FORGE_DIR/npcs/"
else
echo -e "${YELLOW}⚠ rsync not found, falling back to cp (stale files won't be pruned)${NC}"
if [ -d "$SOURCE_DIR/src" ]; then
cp -r "$SOURCE_DIR"/src/. "$FORGE_DIR/"
else
cp -r "$SOURCE_DIR"/*.py "$FORGE_DIR/"
fi
[ -d "$SOURCE_DIR/npcs" ] && cp -r "$SOURCE_DIR/npcs" "$FORGE_DIR/npcs"
fi
[ -d "$SOURCE_DIR/tests" ] && cp -r "$SOURCE_DIR/tests" "$FORGE_DIR/tests"
[ -f "$SOURCE_DIR/pyproject.toml" ] && cp "$SOURCE_DIR/pyproject.toml" "$FORGE_DIR/"
[ -f "$SOURCE_DIR/README.md" ] && cp "$SOURCE_DIR/README.md" "$FORGE_DIR/"
fi
echo -e " Configuring virtual environment..."
if [ ! -d "$FORGE_DIR/venv" ]; then
python3 -m venv "$FORGE_DIR/venv"
"$FORGE_DIR/venv/bin/pip" install --upgrade pip -q
fi
cd "$FORGE_DIR"
if [ "$DEV_MODE" -eq 1 ]; then
# Editable mode installation
"$FORGE_DIR/venv/bin/pip" install -e . -q
else
# Standard installation
"$FORGE_DIR/venv/bin/pip" install . -q
fi
echo -e " Setting up npc-forge terminal command..."
cat << EOF > "$BIN_DIR/npc-forge"
#!$FORGE_DIR/venv/bin/python3
import sys
sys.path.insert(0, "$FORGE_DIR")
from cli import main
if __name__ == "__main__":
sys.exit(main())
EOF
chmod +x "$BIN_DIR/npc-forge"
echo -e " Configuring User Service..."
if command -v systemctl >/dev/null 2>&1; then
echo -e " Systemd detected, configuring systemd service..."
mkdir -p "$SERVICE_DIR"
cat << EOF > "$SERVICE_FILE"
[Unit]
Description=NPC-Forge System Registry Server Gateway
After=network.target
[Service]
Type=simple
WorkingDirectory=$FORGE_DIR
ExecStart=$FORGE_DIR/venv/bin/python3 $FORGE_DIR/server.py
StandardOutput=append:$FORGE_DIR/npc_forge.log
StandardError=append:$FORGE_DIR/npc_forge.log
Restart=always
RestartSec=3
[Install]
WantedBy=default.target
EOF
systemctl --user daemon-reload
systemctl --user enable npc-forge.service 2>/dev/null || true
systemctl --user restart npc-forge.service
SERVICE_RUNNING=1
else
if [[ "$OSTYPE" == "darwin"* ]]; then
echo -e "${YELLOW}macOS detected. Systemd is not available.${NC}\n"
else
echo -e "${YELLOW}Systemd not found. Service will not start automatically.${NC}\n"
fi
SERVICE_RUNNING=0
fi
# $PATH automatic configuration
echo -e " Verifying environment \$PATH..."
hash -r
DETECTED_SHELL=$(basename "$SHELL")
RC_FILE=""
if [ "$DETECTED_SHELL" == "bash" ]; then
RC_FILE="$HOME/.bashrc"
elif [ "$DETECTED_SHELL" == "zsh" ]; then
RC_FILE="$HOME/.zshrc"
fi
if [[ ":$PATH:" != *":$BIN_DIR:"* ]]; then
if [ -n "$RC_FILE" ] && [ -f "$RC_FILE" ]; then
echo -e "${YELLOW}⚙ Adding $BIN_DIR to your \$PATH in $RC_FILE...${NC}"
echo "" >> "$RC_FILE"
echo "# NPC-Forge user binaries path" >> "$RC_FILE"
echo "export PATH=\"\$HOME/.local/bin:\$PATH\"" >> "$RC_FILE"
export PATH="$BIN_DIR:$PATH"
fi
fi
echo -e "\n${YELLOW}npc-forge${NC}${GREEN} installed successfully${NC} in user space."
if [ "$SERVICE_RUNNING" -eq 1 ]; then
echo -e "Server service is now running in background via Systemd."
echo -e "\nYou can now use the ${YELLOW}npc-forge${NC} command\n"
else
echo -e "${YELLOW}Note: Since Systemd is not available, you need to run the server manually:${NC}"
echo -e "${YELLOW}Run 'npc-forge server' in a separate terminal before using the tools.${NC}\n"
fi