@pixelbyte-software/pixcode 1.37.0 → 1.38.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/dist/assets/{index-D8uNxHf1.js → index-C-gVa0Gf.js} +1 -1
- package/dist/index.html +1 -1
- package/dist-server/server/index.js +5 -0
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/routes/diagnostics.js +12 -0
- package/dist-server/server/routes/diagnostics.js.map +1 -0
- package/dist-server/server/services/diagnostics.js +91 -0
- package/dist-server/server/services/diagnostics.js.map +1 -0
- package/package.json +5 -1
- package/scripts/github/create-v1.38-issues.mjs +351 -0
- package/scripts/smoke/discord-release-workflow.mjs +24 -0
- package/scripts/smoke/v138-desktop-release-hardening.mjs +69 -0
- package/scripts/smoke/v138-diagnostics.mjs +63 -0
- package/scripts/smoke/v138-issue-planner.mjs +33 -0
- package/server/index.js +6 -0
- package/server/routes/diagnostics.js +15 -0
- package/server/services/diagnostics.js +105 -0
package/server/index.js
CHANGED
|
@@ -75,6 +75,7 @@ import geminiRoutes from './routes/gemini.js';
|
|
|
75
75
|
import qwenRoutes from './routes/qwen.js';
|
|
76
76
|
import pluginsRoutes from './routes/plugins.js';
|
|
77
77
|
import messagesRoutes from './routes/messages.js';
|
|
78
|
+
import diagnosticsRoutes from './routes/diagnostics.js';
|
|
78
79
|
import providerRoutes from './modules/providers/provider.routes.js';
|
|
79
80
|
import {
|
|
80
81
|
createA2ARouter,
|
|
@@ -320,6 +321,8 @@ const wss = new WebSocketServer({
|
|
|
320
321
|
|
|
321
322
|
// Make WebSocket server available to routes
|
|
322
323
|
app.locals.wss = wss;
|
|
324
|
+
app.locals.installMode = installMode;
|
|
325
|
+
app.locals.serverVersion = SERVER_VERSION;
|
|
323
326
|
setNotificationWebSocketServer(wss);
|
|
324
327
|
|
|
325
328
|
app.use(cors({ exposedHeaders: ['X-Refreshed-Token'] }));
|
|
@@ -391,6 +394,9 @@ app.use('/api/plugins', authenticateToken, pluginsRoutes);
|
|
|
391
394
|
// Unified session messages route (protected)
|
|
392
395
|
app.use('/api/sessions', authenticateToken, messagesRoutes);
|
|
393
396
|
|
|
397
|
+
// Diagnostics API Routes (protected)
|
|
398
|
+
app.use('/api/diagnostics', authenticateToken, diagnosticsRoutes);
|
|
399
|
+
|
|
394
400
|
// Unified provider MCP routes (protected)
|
|
395
401
|
app.use('/api/providers', authenticateToken, providerRoutes);
|
|
396
402
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import express from 'express';
|
|
2
|
+
|
|
3
|
+
import { collectDiagnostics } from '../services/diagnostics.js';
|
|
4
|
+
|
|
5
|
+
const router = express.Router();
|
|
6
|
+
|
|
7
|
+
router.get('/', (req, res) => {
|
|
8
|
+
res.json(collectDiagnostics({
|
|
9
|
+
installMode: req.app.locals.installMode,
|
|
10
|
+
serverVersion: req.app.locals.serverVersion,
|
|
11
|
+
wss: req.app.locals.wss,
|
|
12
|
+
}));
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export default router;
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
const SAFE_ENV_KEYS = [
|
|
2
|
+
'NODE_ENV',
|
|
3
|
+
'SERVER_PORT',
|
|
4
|
+
'VITE_PORT',
|
|
5
|
+
'HOST',
|
|
6
|
+
'PORT',
|
|
7
|
+
'DATABASE_PATH',
|
|
8
|
+
'PIXCODE_NO_DAEMON',
|
|
9
|
+
'PIXCODE_DISABLE_UPDATE_CHECK',
|
|
10
|
+
'GITHUB_TOKEN',
|
|
11
|
+
'NPM_TOKEN',
|
|
12
|
+
'TELEGRAM_BOT_TOKEN',
|
|
13
|
+
'ANTHROPIC_API_KEY',
|
|
14
|
+
'OPENAI_API_KEY',
|
|
15
|
+
'GEMINI_API_KEY',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
const SENSITIVE_KEY_PATTERN = /(authorization|cookie|credential|password|secret|token|api[_-]?key)/i;
|
|
19
|
+
|
|
20
|
+
function isSensitiveKey(key) {
|
|
21
|
+
return SENSITIVE_KEY_PATTERN.test(key);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function redactEnv(env = process.env) {
|
|
25
|
+
return SAFE_ENV_KEYS.reduce((acc, key) => {
|
|
26
|
+
if (!(key in env)) {
|
|
27
|
+
return acc;
|
|
28
|
+
}
|
|
29
|
+
acc[key] = isSensitiveKey(key) ? '[redacted]' : String(env[key]);
|
|
30
|
+
return acc;
|
|
31
|
+
}, {});
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function providerCredentialState(env = process.env) {
|
|
35
|
+
return {
|
|
36
|
+
claude: Boolean(env.ANTHROPIC_API_KEY || env.CLAUDE_API_KEY),
|
|
37
|
+
codex: Boolean(env.OPENAI_API_KEY),
|
|
38
|
+
gemini: Boolean(env.GEMINI_API_KEY || env.GOOGLE_API_KEY),
|
|
39
|
+
telegram: Boolean(env.TELEGRAM_BOT_TOKEN),
|
|
40
|
+
github: Boolean(env.GITHUB_TOKEN),
|
|
41
|
+
npm: Boolean(env.NPM_TOKEN),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function normalizeMemory(memory) {
|
|
46
|
+
return Object.fromEntries(
|
|
47
|
+
Object.entries(memory).map(([key, value]) => [key, Number.isFinite(value) ? value : 0])
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function resolveWebSocketClientCount(options) {
|
|
52
|
+
if (Number.isInteger(options.wsClientCount)) {
|
|
53
|
+
return options.wsClientCount;
|
|
54
|
+
}
|
|
55
|
+
return options.wss?.clients?.size || 0;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function collectDiagnostics(options = {}) {
|
|
59
|
+
const now = options.now || new Date();
|
|
60
|
+
const env = options.env || process.env;
|
|
61
|
+
const versions = options.versions || process.versions;
|
|
62
|
+
const memoryUsage = options.memoryUsage || process.memoryUsage;
|
|
63
|
+
const uptime = options.uptime ?? process.uptime();
|
|
64
|
+
|
|
65
|
+
return {
|
|
66
|
+
status: 'ok',
|
|
67
|
+
timestamp: now.toISOString(),
|
|
68
|
+
version: options.serverVersion || '0.0.0',
|
|
69
|
+
installMode: options.installMode || 'unknown',
|
|
70
|
+
runtime: {
|
|
71
|
+
node: versions.node,
|
|
72
|
+
v8: versions.v8,
|
|
73
|
+
platform: options.platform || process.platform,
|
|
74
|
+
arch: options.arch || process.arch,
|
|
75
|
+
uptimeSeconds: Math.round(uptime),
|
|
76
|
+
},
|
|
77
|
+
memory: normalizeMemory(memoryUsage()),
|
|
78
|
+
websocket: {
|
|
79
|
+
clients: resolveWebSocketClientCount(options),
|
|
80
|
+
},
|
|
81
|
+
environment: redactEnv(env),
|
|
82
|
+
credentials: providerCredentialState(env),
|
|
83
|
+
notifications: {
|
|
84
|
+
telegramConfigured: Boolean(env.TELEGRAM_BOT_TOKEN),
|
|
85
|
+
webPushConfigured: Boolean(env.VAPID_PUBLIC_KEY && env.VAPID_PRIVATE_KEY),
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function redactDiagnostics(input) {
|
|
91
|
+
if (Array.isArray(input)) {
|
|
92
|
+
return input.map(item => redactDiagnostics(item));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!input || typeof input !== 'object') {
|
|
96
|
+
return input;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
return Object.fromEntries(
|
|
100
|
+
Object.entries(input).map(([key, value]) => [
|
|
101
|
+
key,
|
|
102
|
+
isSensitiveKey(key) ? '[redacted]' : redactDiagnostics(value),
|
|
103
|
+
])
|
|
104
|
+
);
|
|
105
|
+
}
|