wiki-plugin-allyabase 0.0.5 → 0.0.7

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/BUGFIXES.md ADDED
@@ -0,0 +1,277 @@
1
+ # Allyabase Plugin - Critical Bug Fixes
2
+
3
+ ## Date: February 9, 2026
4
+
5
+ ### Critical Bug #1: Invalid Express Route Wildcard
6
+
7
+ **Problem:**
8
+ Multiple routes used the wildcard `*` syntax which is invalid in newer versions of path-to-regexp (used by Express):
9
+
10
+ ```javascript
11
+ // Federation route (line 291)
12
+ app.use('/plugin/allyabase/federation/*', function(req, res, next) {
13
+
14
+ // Service proxy routes (line 633)
15
+ app.all(`/plugin/allyabase/${service}/*`, function(req, res) {
16
+ ```
17
+
18
+ This caused:
19
+ ```
20
+ PathError: Missing parameter name at index 30: /plugin/allyabase/federation/*
21
+ PathError: Missing parameter name at index 25: /plugin/allyabase/julia/*
22
+ ```
23
+
24
+ **Fix:**
25
+ Changed both to use regex patterns:
26
+
27
+ ```javascript
28
+ // Federation route (line 291)
29
+ app.use(/^\/plugin\/allyabase\/federation\/.*/, function(req, res, next) {
30
+
31
+ // Service proxy routes (line 633)
32
+ app.all(new RegExp(`^\\/plugin\\/allyabase\\/${service}\\/.*`), function(req, res) {
33
+ ```
34
+
35
+ **Locations:**
36
+ - `server/server.js:291` - Federation route
37
+ - `server/server.js:633` - Service proxy routes (all 14 services)
38
+
39
+ **Impact:** Plugin would crash immediately on load, making all federation endpoints and service proxies unusable.
40
+
41
+ ---
42
+
43
+ ### Critical Bug #2: Process Suicide in Docker Containers
44
+
45
+ **Problem:**
46
+ The `cleanupOrphanedProcesses()` function scans ports and kills any process using them. In Docker containers:
47
+ - PID 1 is always the main container process (the wiki server)
48
+ - When the plugin finds the wiki using a port, it tries to kill PID 1
49
+ - This kills the entire container
50
+
51
+ **Symptoms:**
52
+ ```
53
+ [wiki-plugin-allyabase] Found process 1 using port 3005
54
+ [wiki-plugin-allyabase] Attempting to kill process 1...
55
+ [wiki-plugin-allyabase] Process 1 still running, sending SIGKILL...
56
+ ```
57
+
58
+ Followed by container crash.
59
+
60
+ **Fix #1: PID Protection**
61
+ Added safety checks to `killProcessByPid()`:
62
+ ```javascript
63
+ // CRITICAL: Never kill PID 1 in Docker containers
64
+ if (pid === 1) {
65
+ console.log('⚠️ Skipping PID 1 (init process)');
66
+ return false;
67
+ }
68
+
69
+ // Also don't kill our own process
70
+ if (pid === process.pid) {
71
+ console.log('⚠️ Skipping PID ${pid} (this is us!)');
72
+ return false;
73
+ }
74
+ ```
75
+
76
+ **Fix #2: Docker Detection**
77
+ Added Docker environment detection to skip port cleanup entirely:
78
+ ```javascript
79
+ const isDocker = fs.existsSync('/.dockerenv') || fs.existsSync('/run/.containerenv');
80
+
81
+ if (isDocker) {
82
+ console.log('🐳 Detected Docker environment - skipping port cleanup');
83
+ console.log('In Docker, services should run in separate containers');
84
+ return;
85
+ }
86
+ ```
87
+
88
+ **Location:** `server/server.js:63-100, 156-175`
89
+
90
+ **Rationale:**
91
+ In Docker/containerized environments:
92
+ - Each service runs in its own container
93
+ - Services don't share the same process space
94
+ - Attempting to kill processes by port is:
95
+ - Dangerous (can kill the wiki itself)
96
+ - Unnecessary (services are isolated)
97
+ - Won't work anyway (can't kill processes in other containers)
98
+
99
+ ---
100
+
101
+ ## Testing the Fixes
102
+
103
+ ### Before Fix:
104
+ ```bash
105
+ # Install allyabase plugin
106
+ docker exec -u node -w /home/node/lib/node_modules/wiki wiki-dave npm install wiki-plugin-allyabase
107
+
108
+ # Restart wiki
109
+ docker-compose restart wiki-dave
110
+
111
+ # Result: Wiki crashes immediately
112
+ # Logs show: Attempting to kill process 1... [crash]
113
+ ```
114
+
115
+ ### After Fix:
116
+ ```bash
117
+ # Install allyabase plugin
118
+ docker exec -u node -w /home/node/lib/node_modules/wiki wiki-dave npm install wiki-plugin-allyabase
119
+
120
+ # Restart wiki
121
+ docker-compose restart wiki-dave
122
+
123
+ # Result: Wiki starts successfully
124
+ # Logs show:
125
+ # 🐳 Detected Docker environment - skipping port cleanup
126
+ # ✅ wiki-plugin-allyabase ready!
127
+ ```
128
+
129
+ ---
130
+
131
+ ## Architecture Implications
132
+
133
+ ### Original Design (Non-Docker):
134
+ ```
135
+ ┌─────────────────────────────┐
136
+ │ Single Machine/VM │
137
+ │ │
138
+ │ ┌──────────────────────┐ │
139
+ │ │ Wiki (PID 123) │ │
140
+ │ │ Port 3333 │ │
141
+ │ └──────────────────────┘ │
142
+ │ │
143
+ │ ┌──────────────────────┐ │
144
+ │ │ PM2 │ │
145
+ │ │ ├─ Fount (PID 456) │ │
146
+ │ │ ├─ BDO (PID 789) │ │
147
+ │ │ ├─ Joan (PID 101) │ │
148
+ │ │ └─ ...13 more │ │
149
+ │ └──────────────────────┘ │
150
+ │ │
151
+ │ Allyabase plugin can: │
152
+ │ - Kill orphaned PM2 │
153
+ │ - Kill processes on ports │
154
+ │ - Restart services │
155
+ └─────────────────────────────┘
156
+ ```
157
+
158
+ ### Docker Design (Current):
159
+ ```
160
+ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
161
+ │ Wiki Container │ │ Fount Container │ │ BDO Container │
162
+ │ │ │ │ │ │
163
+ │ ┌──────────────┐ │ │ ┌──────────────┐ │ │ ┌──────────────┐ │
164
+ │ │ Wiki (PID 1) │ │ │ │ Fount (PID 1)│ │ │ │ BDO (PID 1) │ │
165
+ │ │ Port 3000 │ │ │ │ Port 3006 │ │ │ │ Port 3003 │ │
166
+ │ └──────────────┘ │ │ └──────────────┘ │ │ └──────────────┘ │
167
+ └──────────────────┘ └──────────────────┘ └──────────────────┘
168
+ │ │ │
169
+ └─────────────────────┴──────────────────────┘
170
+
171
+ Docker Network
172
+
173
+ Each container:
174
+ - Has its own PID 1 (init process)
175
+ - Isolated process space
176
+ - Cannot kill processes in other containers
177
+ - Managed by Docker Compose, not PM2
178
+
179
+ Allyabase plugin in Docker:
180
+ - ✅ Provides proxy routes to services
181
+ - ✅ Handles federation resolution
182
+ - ❌ Cannot manage service lifecycles (that's Docker's job)
183
+ - ❌ Cannot kill processes (dangerous and won't work)
184
+ ```
185
+
186
+ ---
187
+
188
+ ## Future Considerations
189
+
190
+ ### Service Management in Docker
191
+
192
+ The plugin's service management features (launch, healthcheck) need rethinking for Docker:
193
+
194
+ **Current Approach (Non-Docker):**
195
+ - `POST /plugin/allyabase/launch` - Runs `allyabase_setup.sh` which spawns PM2
196
+ - PM2 manages all 14 services as child processes
197
+ - Plugin can kill/restart services
198
+
199
+ **Docker Approach Options:**
200
+
201
+ 1. **Docker Compose (Recommended):**
202
+ ```yaml
203
+ services:
204
+ wiki:
205
+ image: wiki-federation:latest
206
+ fount:
207
+ image: fount:latest
208
+ bdo:
209
+ image: bdo:latest
210
+ # ...etc
211
+ ```
212
+ - Services managed by Docker Compose
213
+ - Plugin acts as pure proxy layer
214
+ - No lifecycle management in plugin
215
+
216
+ 2. **Docker API Integration:**
217
+ - Plugin calls Docker API to start/stop containers
218
+ - Requires Docker socket mount
219
+ - More complex but gives control
220
+
221
+ 3. **Hybrid (Current State):**
222
+ - Plugin works as proxy in Docker
223
+ - Manual service management via docker-compose CLI
224
+ - Plugin's /launch endpoint doesn't work in Docker (services already running)
225
+
226
+ ### Recommendation
227
+
228
+ For Docker deployments:
229
+ 1. Use docker-compose to manage all services
230
+ 2. Allyabase plugin provides:
231
+ - ✅ Service proxy routes
232
+ - ✅ Federation resolution
233
+ - ✅ Healthcheck endpoint (checks if services respond)
234
+ - ❌ Launch/lifecycle management (handled by Docker)
235
+
236
+ For non-Docker deployments:
237
+ 1. Original design works as intended
238
+ 2. PM2 process management
239
+ 3. Full lifecycle control via plugin
240
+
241
+ ---
242
+
243
+ ## Files Modified
244
+
245
+ 1. **server/server.js**
246
+ - Line 291: Fixed Express federation route wildcard (`*` → regex)
247
+ - Line 633: Fixed Express service proxy route wildcards (all 14 services, `*` → regex)
248
+ - Lines 63-100: Added PID 1 protection and self-protection
249
+ - Lines 156-175: Added Docker detection and port cleanup skip
250
+
251
+ ## Backward Compatibility
252
+
253
+ These changes are **fully backward compatible**:
254
+
255
+ - **Non-Docker environments:** Port cleanup still works (unless PID 1 or self)
256
+ - **Docker environments:** Automatically detected and handled safely
257
+ - **Existing functionality:** All proxy routes, federation, and endpoints unchanged
258
+
259
+ ## Testing Checklist
260
+
261
+ - [ ] Plugin loads without crash in Docker
262
+ - [ ] Federation endpoints respond (no PathError)
263
+ - [ ] Wiki doesn't kill itself on startup
264
+ - [ ] Proxy routes work (e.g., `/plugin/allyabase/bdo/*`)
265
+ - [ ] Healthcheck endpoint works
266
+ - [ ] Docker detection logs appear
267
+ - [ ] Non-Docker deployment still works (if applicable)
268
+
269
+ ---
270
+
271
+ ## Related Issues
272
+
273
+ - Original crash report: Dave's wiki crashed when allyabase installed
274
+ - Error 1: `PathError: Missing parameter name at index 30`
275
+ - Error 2: `Attempting to kill process 1` followed by container death
276
+
277
+ Both issues now resolved.
@@ -112,11 +112,11 @@ setup_ecosystem() {
112
112
  declare -A service_ports=(
113
113
  [julia]=3000
114
114
  [continuebee]=2999
115
- [fount]=3002
115
+ [fount]=3006
116
116
  [bdo]=3003
117
117
  [joan]=3004
118
118
  [addie]=3005
119
- [pref]=3006
119
+ [pref]=3002
120
120
  [dolores]=3007
121
121
  [prof]=3008
122
122
  [covenant]=3011
@@ -168,9 +168,22 @@ main() {
168
168
  setup_ecosystem
169
169
 
170
170
  # Start with pm2 daemon (allows pm2 logs, pm2 status, etc.)
171
+ echo "Starting PM2 with ecosystem config..."
171
172
  ./node_modules/.bin/pm2 start ecosystem.config.js
172
173
 
173
- # Keep the script running so services stay up
174
- # This allows the wiki plugin to keep the process alive
175
- ./node_modules/.bin/pm2 logs
174
+ # Wait a moment for services to start
175
+ echo "Waiting for services to initialize..."
176
+ sleep 5
177
+
178
+ # Show PM2 status
179
+ ./node_modules/.bin/pm2 status
180
+
181
+ echo "✅ Allyabase services launched successfully"
182
+ echo "Services are running in PM2 daemon mode"
183
+ echo "Use 'pm2 status' to check service status"
184
+ echo "Use 'pm2 logs' to view logs"
185
+
186
+ # Don't block - exit cleanly so wiki plugin can track the setup script's PID
187
+ # PM2 daemon will keep services running in the background
188
+ exit 0
176
189
  }; main
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wiki-plugin-allyabase",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "Allyabase management plugin for the federated wiki",
5
5
  "keywords": [
6
6
  "wiki",
package/server/server.js CHANGED
@@ -1,5 +1,5 @@
1
1
  (function() {
2
- const { exec } = require('child_process');
2
+ const { exec, spawn } = require('child_process');
3
3
  const path = require('path');
4
4
  const http = require('http');
5
5
  const httpProxy = require('http-proxy');
@@ -26,12 +26,17 @@ const SERVICE_PORTS = {
26
26
  sanora: 7243
27
27
  };
28
28
 
29
+ // PID file for tracking PM2 process
30
+ const PM2_PID_FILE = path.join(__dirname, 'allyabase-pm2.pid');
31
+
29
32
  let baseStatus = {
30
33
  running: false,
31
34
  services: {},
32
35
  lastLaunch: null
33
36
  };
34
37
 
38
+ let allyabaseProcess = null;
39
+
35
40
  // Function to load wiki's owner.json for keypair and location emoji
36
41
  function loadWikiKeypair() {
37
42
  try {
@@ -55,6 +60,185 @@ function loadWikiKeypair() {
55
60
  }
56
61
  }
57
62
 
63
+ // Function to kill process by PID
64
+ function killProcessByPid(pid) {
65
+ try {
66
+ // CRITICAL: Never kill PID 1 in Docker containers - it's the main container process
67
+ if (pid === 1) {
68
+ console.log(`[wiki-plugin-allyabase] ⚠️ Skipping PID 1 (init process) - this is likely the wiki server itself in Docker`);
69
+ return false;
70
+ }
71
+
72
+ // Also don't kill our own process
73
+ if (pid === process.pid) {
74
+ console.log(`[wiki-plugin-allyabase] ⚠️ Skipping PID ${pid} (this is us!)`);
75
+ return false;
76
+ }
77
+
78
+ console.log(`[wiki-plugin-allyabase] Attempting to kill process ${pid}...`);
79
+ process.kill(pid, 'SIGTERM');
80
+
81
+ // Wait a bit, then force kill if still running
82
+ setTimeout(() => {
83
+ try {
84
+ process.kill(pid, 0); // Check if still alive
85
+ console.log(`[wiki-plugin-allyabase] Process ${pid} still running, sending SIGKILL...`);
86
+ process.kill(pid, 'SIGKILL');
87
+ } catch (err) {
88
+ // Process is dead, which is what we want
89
+ console.log(`[wiki-plugin-allyabase] ✅ Process ${pid} terminated successfully`);
90
+ }
91
+ }, 2000);
92
+
93
+ return true;
94
+ } catch (err) {
95
+ if (err.code === 'ESRCH') {
96
+ console.log(`[wiki-plugin-allyabase] Process ${pid} does not exist`);
97
+ } else {
98
+ console.error(`[wiki-plugin-allyabase] Error killing process ${pid}:`, err.message);
99
+ }
100
+ return false;
101
+ }
102
+ }
103
+
104
+ // Function to find and kill process using a specific port
105
+ function killProcessByPort(port) {
106
+ return new Promise((resolve) => {
107
+ // Use lsof to find process using the port
108
+ exec(`lsof -ti tcp:${port}`, (err, stdout, stderr) => {
109
+ if (err || !stdout.trim()) {
110
+ console.log(`[wiki-plugin-allyabase] No process found using port ${port}`);
111
+ resolve(false);
112
+ return;
113
+ }
114
+
115
+ const pid = parseInt(stdout.trim(), 10);
116
+ console.log(`[wiki-plugin-allyabase] Found process ${pid} using port ${port}`);
117
+
118
+ const killed = killProcessByPid(pid);
119
+ resolve(killed);
120
+ });
121
+ });
122
+ }
123
+
124
+ // Function to stop PM2 and all managed services
125
+ async function stopPM2() {
126
+ console.log('[wiki-plugin-allyabase] Stopping PM2 and all services...');
127
+
128
+ return new Promise((resolve) => {
129
+ // Try to stop PM2 gracefully using pm2 kill
130
+ exec('pm2 kill', (err, stdout, stderr) => {
131
+ if (err) {
132
+ console.log(`[wiki-plugin-allyabase] PM2 kill failed (might not be running): ${err.message}`);
133
+ } else {
134
+ console.log(`[wiki-plugin-allyabase] PM2 killed successfully`);
135
+ }
136
+
137
+ // Clean up PID file
138
+ cleanupPidFile();
139
+ resolve();
140
+ });
141
+ });
142
+ }
143
+
144
+ // Function to clean up orphaned processes from previous run
145
+ async function cleanupOrphanedProcesses() {
146
+ console.log('[wiki-plugin-allyabase] Checking for orphaned allyabase processes...');
147
+
148
+ // Check PID file for PM2 process
149
+ if (fs.existsSync(PM2_PID_FILE)) {
150
+ try {
151
+ const pidString = fs.readFileSync(PM2_PID_FILE, 'utf8').trim();
152
+ const pid = parseInt(pidString, 10);
153
+
154
+ console.log(`[wiki-plugin-allyabase] Found PID file with PID ${pid}`);
155
+ killProcessByPid(pid);
156
+
157
+ // Wait for process to die
158
+ await new Promise(resolve => setTimeout(resolve, 2500));
159
+
160
+ // Clean up PID file
161
+ fs.unlinkSync(PM2_PID_FILE);
162
+ console.log(`[wiki-plugin-allyabase] Cleaned up PID file`);
163
+ } catch (err) {
164
+ console.error(`[wiki-plugin-allyabase] Error reading PID file:`, err.message);
165
+ }
166
+ }
167
+
168
+ // Stop PM2 if it's running (cleans up all managed services)
169
+ await stopPM2();
170
+
171
+ // Detect if we're in a Docker container
172
+ // In Docker, services run in separate containers, so port cleanup is unnecessary and dangerous
173
+ const isDocker = fs.existsSync('/.dockerenv') || fs.existsSync('/run/.containerenv');
174
+
175
+ if (isDocker) {
176
+ console.log('[wiki-plugin-allyabase] 🐳 Detected Docker environment - skipping port cleanup');
177
+ console.log('[wiki-plugin-allyabase] In Docker, services should run in separate containers, not as processes on ports');
178
+ console.log('[wiki-plugin-allyabase] Cleanup complete (Docker mode)');
179
+ return;
180
+ }
181
+
182
+ // Fallback: kill any processes using our ports (only in non-Docker environments)
183
+ console.log('[wiki-plugin-allyabase] Cleaning up any processes on service ports...');
184
+ for (const [service, port] of Object.entries(SERVICE_PORTS)) {
185
+ await killProcessByPort(port);
186
+ }
187
+
188
+ // Extra wait to ensure everything is dead
189
+ await new Promise(resolve => setTimeout(resolve, 2000));
190
+ console.log('[wiki-plugin-allyabase] Cleanup complete');
191
+ }
192
+
193
+ // Function to write PID file
194
+ function writePidFile(pid) {
195
+ try {
196
+ fs.writeFileSync(PM2_PID_FILE, pid.toString(), 'utf8');
197
+ console.log(`[wiki-plugin-allyabase] Wrote PID ${pid} to ${PM2_PID_FILE}`);
198
+ } catch (err) {
199
+ console.error(`[wiki-plugin-allyabase] Error writing PID file:`, err.message);
200
+ }
201
+ }
202
+
203
+ // Function to clean up PID file
204
+ function cleanupPidFile() {
205
+ try {
206
+ if (fs.existsSync(PM2_PID_FILE)) {
207
+ fs.unlinkSync(PM2_PID_FILE);
208
+ console.log(`[wiki-plugin-allyabase] Cleaned up PID file`);
209
+ }
210
+ } catch (err) {
211
+ console.error(`[wiki-plugin-allyabase] Error cleaning up PID file:`, err.message);
212
+ }
213
+ }
214
+
215
+ // Function to gracefully shutdown allyabase
216
+ async function shutdownAllyabase() {
217
+ console.log('[wiki-plugin-allyabase] Shutting down allyabase services...');
218
+
219
+ if (allyabaseProcess && !allyabaseProcess.killed) {
220
+ console.log(`[wiki-plugin-allyabase] Killing allyabase process ${allyabaseProcess.pid}...`);
221
+
222
+ try {
223
+ allyabaseProcess.kill('SIGTERM');
224
+
225
+ // Force kill after timeout
226
+ setTimeout(() => {
227
+ if (allyabaseProcess && !allyabaseProcess.killed) {
228
+ console.log(`[wiki-plugin-allyabase] Force killing allyabase process...`);
229
+ allyabaseProcess.kill('SIGKILL');
230
+ }
231
+ }, 2000);
232
+ } catch (err) {
233
+ console.error(`[wiki-plugin-allyabase] Error killing allyabase:`, err.message);
234
+ }
235
+ }
236
+
237
+ // Stop PM2
238
+ await stopPM2();
239
+ cleanupPidFile();
240
+ }
241
+
58
242
  // Function to check if a port is responding
59
243
  function checkPort(port) {
60
244
  return new Promise((resolve) => {
@@ -112,6 +296,11 @@ async function healthcheck() {
112
296
  async function startServer(params) {
113
297
  const app = params.app;
114
298
 
299
+ console.log('🔗 wiki-plugin-allyabase starting...');
300
+
301
+ // Clean up any orphaned allyabase/PM2 processes from previous run
302
+ await cleanupOrphanedProcesses();
303
+
115
304
  // Owner middleware to protect state-changing endpoints
116
305
  const owner = function (req, res, next) {
117
306
  if (!app.securityhandler.isAuthorized(req)) {
@@ -122,7 +311,8 @@ async function startServer(params) {
122
311
 
123
312
  // CORS middleware for federation endpoints
124
313
  // Allows cross-origin requests from other federated wikis
125
- app.use('/plugin/allyabase/federation/*', function(req, res, next) {
314
+ // Use regex to match all federation paths (Express doesn't support * wildcard in newer versions)
315
+ app.use(/^\/plugin\/allyabase\/federation\/.*/, function(req, res, next) {
126
316
  res.setHeader('Access-Control-Allow-Origin', '*');
127
317
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
128
318
  res.setHeader('Access-Control-Allow-Headers', 'Content-Type');
@@ -440,7 +630,8 @@ async function startServer(params) {
440
630
  // Create proxy routes for each service
441
631
  Object.entries(SERVICE_PORTS).forEach(([service, port]) => {
442
632
  // Proxy all methods (GET, POST, PUT, DELETE, etc.)
443
- app.all(`/plugin/allyabase/${service}/*`, function(req, res) {
633
+ // Use regex pattern instead of wildcard to avoid PathError in newer path-to-regexp
634
+ app.all(new RegExp(`^\\/plugin\\/allyabase\\/${service}\\/.*`), function(req, res) {
444
635
  const targetPath = req.url.replace(`/plugin/allyabase/${service}`, '');
445
636
  console.log(`[PROXY] ${req.method} /plugin/allyabase/${service}${targetPath} -> http://localhost:${port}${targetPath}`);
446
637
  console.log(`[PROXY] Headers:`, JSON.stringify(req.headers, null, 2));
@@ -476,25 +667,50 @@ async function startServer(params) {
476
667
  console.log('Timestamp:', new Date().toISOString());
477
668
  console.log('-'.repeat(80));
478
669
 
479
- // Launch the setup script with spawn for better output streaming
480
- const { spawn } = require('child_process');
481
- const setupProcess = spawn('bash', [scriptPath], {
482
- stdio: 'inherit', // This will pipe stdout/stderr directly to the parent process
483
- env: process.env
670
+ // Launch the setup script with spawn
671
+ allyabaseProcess = spawn('bash', [scriptPath], {
672
+ stdio: ['ignore', 'pipe', 'pipe'], // Don't inherit stdio, capture it
673
+ env: process.env,
674
+ detached: false // Keep as child of this process
484
675
  });
485
676
 
486
- setupProcess.on('error', (error) => {
487
- console.error('❌ Error spawning allyabase process:', error);
677
+ // Write PID file immediately after spawning
678
+ writePidFile(allyabaseProcess.pid);
679
+
680
+ // Log stdout
681
+ allyabaseProcess.stdout.on('data', (data) => {
682
+ const lines = data.toString().split('\n').filter(line => line.trim());
683
+ lines.forEach(line => {
684
+ console.log(`[allyabase:${allyabaseProcess.pid}] ${line}`);
685
+ });
686
+ });
687
+
688
+ // Log stderr
689
+ allyabaseProcess.stderr.on('data', (data) => {
690
+ console.error(`[allyabase:${allyabaseProcess.pid}] ERROR: ${data.toString().trim()}`);
488
691
  });
489
692
 
490
- setupProcess.on('exit', (code, signal) => {
693
+ // Handle process exit
694
+ allyabaseProcess.on('exit', (code, signal) => {
491
695
  console.log('-'.repeat(80));
492
696
  if (code === 0) {
493
697
  console.log('✅ Allyabase setup completed successfully');
494
- } else {
495
- console.log(`⚠️ Allyabase setup exited with code: ${code}, signal: ${signal}`);
698
+ } else if (code) {
699
+ console.log(`⚠️ Allyabase setup exited with code: ${code}`);
700
+ } else if (signal) {
701
+ console.log(`⚠️ Allyabase setup killed by signal: ${signal}`);
496
702
  }
497
703
  console.log('='.repeat(80));
704
+
705
+ // Clean up PID file when process exits
706
+ cleanupPidFile();
707
+ allyabaseProcess = null;
708
+ });
709
+
710
+ allyabaseProcess.on('error', (error) => {
711
+ console.error('❌ Error spawning allyabase process:', error);
712
+ cleanupPidFile();
713
+ allyabaseProcess = null;
498
714
  });
499
715
 
500
716
  baseStatus.lastLaunch = new Date().toISOString();
@@ -503,7 +719,8 @@ async function startServer(params) {
503
719
  success: true,
504
720
  message: 'Allyabase launch initiated',
505
721
  timestamp: baseStatus.lastLaunch,
506
- scriptPath: scriptPath
722
+ scriptPath: scriptPath,
723
+ pid: allyabaseProcess.pid
507
724
  });
508
725
  } catch (err) {
509
726
  console.error('❌ Error launching allyabase:', err);
@@ -829,6 +1046,44 @@ async function startServer(params) {
829
1046
 
830
1047
  // Add deployment routes
831
1048
  deployment.addRoutes(params);
1049
+
1050
+ console.log('✅ wiki-plugin-allyabase ready!');
1051
+
1052
+ // Set up shutdown hooks to clean up allyabase/PM2 processes
1053
+ let isShuttingDown = false;
1054
+
1055
+ const handleShutdown = async (signal) => {
1056
+ if (isShuttingDown) {
1057
+ return; // Already shutting down
1058
+ }
1059
+ isShuttingDown = true;
1060
+
1061
+ console.log(`[wiki-plugin-allyabase] Received ${signal}, shutting down...`);
1062
+ await shutdownAllyabase();
1063
+
1064
+ // Give it a moment to clean up
1065
+ setTimeout(() => {
1066
+ console.log('[wiki-plugin-allyabase] Shutdown complete');
1067
+ // Don't call process.exit() here - let the parent process handle that
1068
+ }, 3000);
1069
+ };
1070
+
1071
+ // Register shutdown handlers (only once per process)
1072
+ if (!process.allyabaseShutdownRegistered) {
1073
+ process.allyabaseShutdownRegistered = true;
1074
+
1075
+ process.on('SIGINT', () => handleShutdown('SIGINT'));
1076
+ process.on('SIGTERM', () => handleShutdown('SIGTERM'));
1077
+ process.on('exit', () => {
1078
+ if (!isShuttingDown) {
1079
+ // Synchronous cleanup on exit
1080
+ console.log('[wiki-plugin-allyabase] Process exiting, cleaning up...');
1081
+ cleanupPidFile();
1082
+ }
1083
+ });
1084
+
1085
+ console.log('[wiki-plugin-allyabase] Shutdown handlers registered');
1086
+ }
832
1087
  }
833
1088
 
834
1089
  module.exports = { startServer };