@pixelbyte-software/pixcode 1.53.2 → 1.53.3
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pixelbyte-software/pixcode",
|
|
3
|
-
"version": "1.53.
|
|
3
|
+
"version": "1.53.3",
|
|
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/index.js
CHANGED
|
@@ -273,6 +273,59 @@ function getActiveUpdateJob() {
|
|
|
273
273
|
return null;
|
|
274
274
|
}
|
|
275
275
|
|
|
276
|
+
function countByProvider(items) {
|
|
277
|
+
return items.reduce((counts, item) => {
|
|
278
|
+
const provider = item?.provider || 'unknown';
|
|
279
|
+
counts[provider] = (counts[provider] || 0) + 1;
|
|
280
|
+
return counts;
|
|
281
|
+
}, {});
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
function getActiveProviderWorkSummary() {
|
|
285
|
+
const sessions = [
|
|
286
|
+
...getActiveClaudeSDKSessions().map((id) => ({ id, provider: 'claude' })),
|
|
287
|
+
...getActiveCursorSessions().map((session) => ({ ...session, provider: 'cursor' })),
|
|
288
|
+
...getActiveCodexSessions().map((session) => ({ ...session, provider: 'codex' })),
|
|
289
|
+
...getActiveGeminiSessions().map((session) => ({ ...session, provider: 'gemini' })),
|
|
290
|
+
...getActiveQwenSessions().map((session) => ({ ...session, provider: 'qwen' })),
|
|
291
|
+
...getActiveOpencodeSessions().map((session) => ({ ...session, provider: 'opencode' })),
|
|
292
|
+
];
|
|
293
|
+
|
|
294
|
+
return {
|
|
295
|
+
total: sessions.length,
|
|
296
|
+
byProvider: countByProvider(sessions),
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function getActivePtyWorkSummary() {
|
|
301
|
+
const activePtys = Array.from(ptySessionsMap.values())
|
|
302
|
+
.filter((session) => session?.pty && session.lifecycleState === 'running')
|
|
303
|
+
.map((session) => ({
|
|
304
|
+
provider: session.isPlainShell ? 'plain-shell' : (session.provider || 'unknown'),
|
|
305
|
+
connected: Boolean(session.ws && session.ws.readyState === WebSocket.OPEN),
|
|
306
|
+
}));
|
|
307
|
+
|
|
308
|
+
return {
|
|
309
|
+
total: activePtys.length,
|
|
310
|
+
connected: activePtys.filter((session) => session.connected).length,
|
|
311
|
+
detached: activePtys.filter((session) => !session.connected).length,
|
|
312
|
+
byProvider: countByProvider(activePtys),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function getActiveWorkSummary() {
|
|
317
|
+
const pty = getActivePtyWorkSummary();
|
|
318
|
+
const agents = getActiveProviderWorkSummary();
|
|
319
|
+
const total = pty.total + agents.total;
|
|
320
|
+
|
|
321
|
+
return {
|
|
322
|
+
hasActiveWork: total > 0,
|
|
323
|
+
total,
|
|
324
|
+
pty,
|
|
325
|
+
agents,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
276
329
|
async function readLatestPixcodePackageMetadata() {
|
|
277
330
|
const registryRes = await fetch('https://registry.npmjs.org/@pixelbyte-software/pixcode');
|
|
278
331
|
if (!registryRes.ok) throw new Error(`Registry returned HTTP ${registryRes.status}`);
|
|
@@ -375,8 +428,10 @@ async function runCommandUpdateJob(job, updateCommand, updateCwd) {
|
|
|
375
428
|
cwd: updateCwd,
|
|
376
429
|
env: process.env,
|
|
377
430
|
shell: true,
|
|
431
|
+
detached: true,
|
|
378
432
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
379
433
|
});
|
|
434
|
+
try { child.unref(); } catch { /* noop */ }
|
|
380
435
|
child.stdout?.on('data', (data) => appendUpdateJobLog(job, 'stdout', data.toString()));
|
|
381
436
|
child.stderr?.on('data', (data) => appendUpdateJobLog(job, 'stderr', data.toString()));
|
|
382
437
|
child.on('error', reject);
|
|
@@ -1635,6 +1690,7 @@ app.get('/api/system/update-state', authenticateToken, (req, res) => {
|
|
|
1635
1690
|
success: true,
|
|
1636
1691
|
state: readSystemUpdateState(),
|
|
1637
1692
|
activeJob: snapshotUpdateJob(getActiveUpdateJob()),
|
|
1693
|
+
activeWork: getActiveWorkSummary(),
|
|
1638
1694
|
currentVersion: SERVER_VERSION,
|
|
1639
1695
|
installMode,
|
|
1640
1696
|
capabilities: {
|
|
@@ -2035,6 +2091,16 @@ app.post('/api/system/update', authenticateToken, requireAdmin, requireApiScope(
|
|
|
2035
2091
|
// (systemd/pm2/daemon manager) can bring the server back on the new code.
|
|
2036
2092
|
// Foreground installs without a wrapper will simply stop; the UI reports this.
|
|
2037
2093
|
app.post('/api/system/restart', authenticateToken, requireAdmin, requireApiScope('system:restart'), (req, res) => {
|
|
2094
|
+
const forceRestart = req.body?.force === true || req.query.force === 'true';
|
|
2095
|
+
const activeWork = getActiveWorkSummary();
|
|
2096
|
+
if (!forceRestart && activeWork.hasActiveWork) {
|
|
2097
|
+
return res.status(409).json({
|
|
2098
|
+
success: false,
|
|
2099
|
+
error: 'Active terminal or agent sessions are running. Confirm restart to interrupt them.',
|
|
2100
|
+
activeWork,
|
|
2101
|
+
});
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2038
2104
|
res.json({
|
|
2039
2105
|
success: true,
|
|
2040
2106
|
version: SERVER_VERSION,
|