@pixelbyte-software/pixcode 1.55.2 → 1.55.6
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/package.json +1 -1
- package/server/cli.js +6 -2
- package/server/load-env.js +4 -1
- package/server/routes/auth.js +13 -6
- package/server/sessionManager.js +25 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixelbyte-software/pixcode",
|
|
3
|
-
"version": "1.55.
|
|
3
|
+
"version": "1.55.6",
|
|
4
4
|
"description": "Self-hosted AI coding agent control room for Claude Code, Cursor CLI, OpenAI Codex, Gemini CLI, Qwen Code, and OpenCode with chat, files, shell, Git, orchestration, API keys, Telegram, MCP, plugins, themes, and desktop/server deployment.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist-server/server/index.js",
|
package/server/cli.js
CHANGED
|
@@ -336,14 +336,18 @@ async function updatePackage(options = {}) {
|
|
|
336
336
|
}
|
|
337
337
|
|
|
338
338
|
console.log(`${c.info('[INFO]')} Updating from ${currentVersion} to ${latestVersion}...`);
|
|
339
|
-
|
|
339
|
+
// Global npm install requires root on system-wide installs
|
|
340
|
+
const npmCmd = process.getuid && process.getuid() === 0
|
|
341
|
+
? 'npm update -g @pixelbyte-software/pixcode'
|
|
342
|
+
: 'sudo npm update -g @pixelbyte-software/pixcode';
|
|
343
|
+
execSync(npmCmd, { stdio: 'inherit' });
|
|
340
344
|
console.log(`${c.ok('[OK]')} Update complete!`);
|
|
341
345
|
await maybeRestartDaemonAfterUpdate(options);
|
|
342
346
|
} catch (e) {
|
|
343
347
|
console.error(`${c.error('[ERROR]')} Update failed: ${e.message}`);
|
|
344
348
|
const fallbackCommand = installMode === 'git'
|
|
345
349
|
? 'pixcode update --restart-daemon'
|
|
346
|
-
: 'npm update -g @pixelbyte-software/pixcode';
|
|
350
|
+
: 'sudo npm update -g @pixelbyte-software/pixcode';
|
|
347
351
|
console.log(`${c.tip('[TIP]')} Try running manually: ${fallbackCommand}`);
|
|
348
352
|
}
|
|
349
353
|
}
|
package/server/load-env.js
CHANGED
|
@@ -23,7 +23,10 @@ try {
|
|
|
23
23
|
}
|
|
24
24
|
});
|
|
25
25
|
} catch (e) {
|
|
26
|
-
|
|
26
|
+
// .env is optional — only warn on unexpected errors (ENOENT is normal)
|
|
27
|
+
if (e.code !== 'ENOENT') {
|
|
28
|
+
console.warn('Error reading .env file:', e.message);
|
|
29
|
+
}
|
|
27
30
|
}
|
|
28
31
|
|
|
29
32
|
// Keep the default database in a stable user-level location so rebuilding dist-server
|
package/server/routes/auth.js
CHANGED
|
@@ -36,7 +36,7 @@ function publicUser(user) {
|
|
|
36
36
|
// Check auth status and setup requirements
|
|
37
37
|
router.get('/status', async (req, res) => {
|
|
38
38
|
try {
|
|
39
|
-
const hasUsers =
|
|
39
|
+
const hasUsers = userDb.hasUsers();
|
|
40
40
|
res.json({
|
|
41
41
|
needsSetup: !hasUsers,
|
|
42
42
|
isAuthenticated: false // Will be overridden by frontend if token exists
|
|
@@ -62,16 +62,23 @@ router.put('/connection-mode', async (req, res) => {
|
|
|
62
62
|
try {
|
|
63
63
|
// During first-run setup no users exist yet, so we skip auth.
|
|
64
64
|
// The setup form calls this endpoint before creating the admin account.
|
|
65
|
-
const hasUsers =
|
|
65
|
+
const hasUsers = userDb.hasUsers();
|
|
66
66
|
if (!hasUsers) {
|
|
67
67
|
return res.json({ success: true, connection: saveRemoteConnectionConfig(req.body || {}) });
|
|
68
68
|
}
|
|
69
69
|
// Post-setup: require authenticated admin
|
|
70
|
-
authenticateToken
|
|
71
|
-
|
|
72
|
-
|
|
70
|
+
// Wrap authenticateToken in a try/catch so that if it sends a response
|
|
71
|
+
// (e.g. 401 when no token is present) we don't double-send.
|
|
72
|
+
try {
|
|
73
|
+
authenticateToken(req, res, () => {
|
|
74
|
+
requireAdmin(req, res, () => {
|
|
75
|
+
res.json({ success: true, connection: saveRemoteConnectionConfig(req.body || {}) });
|
|
76
|
+
});
|
|
73
77
|
});
|
|
74
|
-
})
|
|
78
|
+
} catch (err) {
|
|
79
|
+
// If authenticateToken throws instead of calling next/send, return 401
|
|
80
|
+
res.status(401).json({ error: err.message || 'Authentication required' });
|
|
81
|
+
}
|
|
75
82
|
} catch (error) {
|
|
76
83
|
res.status(400).json({ success: false, error: error.message });
|
|
77
84
|
}
|
package/server/sessionManager.js
CHANGED
|
@@ -6,6 +6,7 @@ class SessionManager {
|
|
|
6
6
|
constructor() {
|
|
7
7
|
// Store sessions in memory with conversation history
|
|
8
8
|
this.sessions = new Map();
|
|
9
|
+
this.corruptedSessions = new Set();
|
|
9
10
|
this.maxSessions = 100;
|
|
10
11
|
this.sessionsDir = path.join(os.homedir(), '.gemini', 'sessions');
|
|
11
12
|
this.ready = this.init();
|
|
@@ -150,6 +151,21 @@ class SessionManager {
|
|
|
150
151
|
try {
|
|
151
152
|
const filePath = this._safeFilePath(sessionId);
|
|
152
153
|
await fs.writeFile(filePath, JSON.stringify(session, null, 2));
|
|
154
|
+
|
|
155
|
+
// Clean up any corrupted sessions that were marked during load
|
|
156
|
+
if (this.corruptedSessions.size > 0) {
|
|
157
|
+
const deleted = [];
|
|
158
|
+
for (const corruptedFile of this.corruptedSessions) {
|
|
159
|
+
try {
|
|
160
|
+
await fs.unlink(path.join(this.sessionsDir, corruptedFile));
|
|
161
|
+
deleted.push(corruptedFile);
|
|
162
|
+
} catch { /* already gone */ }
|
|
163
|
+
}
|
|
164
|
+
deleted.forEach(d => this.corruptedSessions.delete(d));
|
|
165
|
+
if (deleted.length > 0) {
|
|
166
|
+
console.warn(`SessionManager: Cleaned up ${deleted.length} corrupted session file(s): ${deleted.join(', ')}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
153
169
|
} catch (error) {
|
|
154
170
|
console.warn(`SessionManager: Error saving session ${sessionId}:`, error?.message || error);
|
|
155
171
|
}
|
|
@@ -176,7 +192,15 @@ class SessionManager {
|
|
|
176
192
|
|
|
177
193
|
this.sessions.set(session.id, session);
|
|
178
194
|
} catch (error) {
|
|
179
|
-
|
|
195
|
+
// Corrupted session file — skip it and optionally clean up
|
|
196
|
+
const isCorrupted = error instanceof SyntaxError && error.message.includes('JSON');
|
|
197
|
+
if (isCorrupted) {
|
|
198
|
+
console.warn(`SessionManager: Skipping corrupted session file ${file} — will auto-clean on next save.`);
|
|
199
|
+
// Mark for deletion on next successful save cycle
|
|
200
|
+
this.corruptedSessions.add(file);
|
|
201
|
+
} else {
|
|
202
|
+
console.warn(`SessionManager: Error loading session ${file}:`, error?.message || error);
|
|
203
|
+
}
|
|
180
204
|
}
|
|
181
205
|
}
|
|
182
206
|
}
|