@pixelbyte-software/pixcode 1.31.10 → 1.31.12
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-XT7dX9Q7.js → index-Bb2tV2Uy.js} +156 -152
- package/dist/assets/index-CLxSMbv1.css +32 -0
- package/dist/index.html +2 -2
- package/dist-server/server/index.js +89 -28
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/modules/providers/services/mcp.service.js +4 -9
- package/dist-server/server/modules/providers/services/mcp.service.js.map +1 -1
- package/dist-server/server/routes/projects.js +11 -17
- package/dist-server/server/routes/projects.js.map +1 -1
- package/package.json +1 -1
- package/server/index.js +93 -29
- package/server/modules/providers/services/mcp.service.ts +4 -12
- package/server/routes/projects.js +12 -20
- package/dist/assets/index-CDpePeIN.css +0 -32
|
@@ -95,7 +95,14 @@ const WATCHER_IGNORED_PATTERNS = [
|
|
|
95
95
|
'**/*.swp',
|
|
96
96
|
'**/.DS_Store'
|
|
97
97
|
];
|
|
98
|
-
|
|
98
|
+
// Debounce chokidar events before rescanning all provider project trees.
|
|
99
|
+
// During an active chat, each model writes its transcript to
|
|
100
|
+
// ~/.<provider>/projects/<encoded>/*.jsonl in small chunks — with a 300ms
|
|
101
|
+
// window every few chunks triggered a full getProjects() + broadcast to
|
|
102
|
+
// every open tab, which shows up as mouse/UI stutter. 1500ms collapses
|
|
103
|
+
// a full chat reply into ~1 scan while still feeling responsive when
|
|
104
|
+
// the user flips to the projects list.
|
|
105
|
+
const WATCHER_DEBOUNCE_MS = 1500;
|
|
99
106
|
let projectsWatchers = [];
|
|
100
107
|
let projectsWatcherDebounceTimer = null;
|
|
101
108
|
const connectedClients = new Set();
|
|
@@ -179,8 +186,14 @@ async function setupProjectsWatcher() {
|
|
|
179
186
|
followSymlinks: false,
|
|
180
187
|
depth: 10, // Reasonable depth limit
|
|
181
188
|
awaitWriteFinish: {
|
|
182
|
-
|
|
183
|
-
|
|
189
|
+
// Raised from (100, 50) to (500, 250). The old settings
|
|
190
|
+
// had chokidar polling every 50ms per in-flight file; an
|
|
191
|
+
// active chat writes its .jsonl transcript continuously,
|
|
192
|
+
// so 50ms polls meant ~20 wakeups/sec per file. The new
|
|
193
|
+
// cadence still stabilizes reliably and cuts the wakeup
|
|
194
|
+
// count by 5x.
|
|
195
|
+
stabilityThreshold: 500,
|
|
196
|
+
pollInterval: 250
|
|
184
197
|
}
|
|
185
198
|
});
|
|
186
199
|
// Set up event listeners
|
|
@@ -716,6 +729,22 @@ const expandWorkspacePath = (inputPath) => {
|
|
|
716
729
|
return WORKSPACES_BASE;
|
|
717
730
|
return normalizeWorkspacePath(inputPath);
|
|
718
731
|
};
|
|
732
|
+
// Filesystem browser uses a home-centric expansion rather than the
|
|
733
|
+
// WORKSPACES_BASE-centric one above. The workspace-base treatment of `~`
|
|
734
|
+
// is right for NEW project creation (users say "my-app" and get it under
|
|
735
|
+
// ~/pixcode/projects/my-app) but wrong for browsing — users want to pick
|
|
736
|
+
// any folder on their disk, not be trapped inside the default base.
|
|
737
|
+
const expandBrowsePath = (inputPath) => {
|
|
738
|
+
if (!inputPath)
|
|
739
|
+
return os.homedir();
|
|
740
|
+
const trimmed = String(inputPath).trim();
|
|
741
|
+
if (!trimmed || trimmed === '~')
|
|
742
|
+
return os.homedir();
|
|
743
|
+
if (trimmed.startsWith('~/') || trimmed.startsWith('~\\')) {
|
|
744
|
+
return path.join(os.homedir(), trimmed.slice(2));
|
|
745
|
+
}
|
|
746
|
+
return path.resolve(trimmed);
|
|
747
|
+
};
|
|
719
748
|
// Browse filesystem endpoint for project suggestions - uses existing getFileTree
|
|
720
749
|
app.get('/api/browse-filesystem', authenticateToken, async (req, res) => {
|
|
721
750
|
try {
|
|
@@ -723,9 +752,11 @@ app.get('/api/browse-filesystem', authenticateToken, async (req, res) => {
|
|
|
723
752
|
console.log('[API] Browse filesystem request for path:', dirPath);
|
|
724
753
|
console.log('[API] WORKSPACES_ROOT is:', WORKSPACES_ROOT);
|
|
725
754
|
console.log('[API] WORKSPACES_BASE is:', WORKSPACES_BASE);
|
|
726
|
-
// Default to home directory
|
|
727
|
-
|
|
728
|
-
|
|
755
|
+
// Default to the user's home directory so the picker feels natural
|
|
756
|
+
// — users can reach arbitrary drives/folders from there. The
|
|
757
|
+
// ~/pixcode/projects shortcut stays available as a suggestion.
|
|
758
|
+
const defaultRoot = os.homedir();
|
|
759
|
+
let targetPath = dirPath ? expandBrowsePath(dirPath) : defaultRoot;
|
|
729
760
|
// Security check - ensure path is within allowed workspace root
|
|
730
761
|
let validation = await validateWorkspacePath(targetPath);
|
|
731
762
|
if (!validation.valid) {
|
|
@@ -1505,39 +1536,31 @@ function handleChatConnection(ws, request) {
|
|
|
1505
1536
|
ws.on('message', async (message) => {
|
|
1506
1537
|
try {
|
|
1507
1538
|
const data = JSON.parse(message);
|
|
1539
|
+
// Per-submission logs removed from hot paths — gate behind
|
|
1540
|
+
// CHAT_DEBUG so production stdout stays clean. Each keypress
|
|
1541
|
+
// that triggers a submit was costing 4 synchronous writes.
|
|
1542
|
+
const chatDebug = process.env.CHAT_DEBUG
|
|
1543
|
+
? (provider, d) => console.log(`[${provider}]`, d.command?.slice(0, 60) || '[resume]', d.options?.projectPath || d.options?.cwd || '', d.options?.sessionId ? 'resume' : 'new')
|
|
1544
|
+
: () => { };
|
|
1508
1545
|
if (data.type === 'claude-command') {
|
|
1509
|
-
|
|
1510
|
-
console.log('📁 Project:', data.options?.projectPath || 'Unknown');
|
|
1511
|
-
console.log('🔄 Session:', data.options?.sessionId ? 'Resume' : 'New');
|
|
1546
|
+
chatDebug('claude', data);
|
|
1512
1547
|
// Use Claude Agents SDK
|
|
1513
1548
|
await queryClaudeSDK(data.command, data.options, writer);
|
|
1514
1549
|
}
|
|
1515
1550
|
else if (data.type === 'cursor-command') {
|
|
1516
|
-
|
|
1517
|
-
console.log('📁 Project:', data.options?.cwd || 'Unknown');
|
|
1518
|
-
console.log('🔄 Session:', data.options?.sessionId ? 'Resume' : 'New');
|
|
1519
|
-
console.log('🤖 Model:', data.options?.model || 'default');
|
|
1551
|
+
chatDebug('cursor', data);
|
|
1520
1552
|
await spawnCursor(data.command, data.options, writer);
|
|
1521
1553
|
}
|
|
1522
1554
|
else if (data.type === 'codex-command') {
|
|
1523
|
-
|
|
1524
|
-
console.log('📁 Project:', data.options?.projectPath || data.options?.cwd || 'Unknown');
|
|
1525
|
-
console.log('🔄 Session:', data.options?.sessionId ? 'Resume' : 'New');
|
|
1526
|
-
console.log('🤖 Model:', data.options?.model || 'default');
|
|
1555
|
+
chatDebug('codex', data);
|
|
1527
1556
|
await queryCodex(data.command, data.options, writer);
|
|
1528
1557
|
}
|
|
1529
1558
|
else if (data.type === 'gemini-command') {
|
|
1530
|
-
|
|
1531
|
-
console.log('📁 Project:', data.options?.projectPath || data.options?.cwd || 'Unknown');
|
|
1532
|
-
console.log('🔄 Session:', data.options?.sessionId ? 'Resume' : 'New');
|
|
1533
|
-
console.log('🤖 Model:', data.options?.model || 'default');
|
|
1559
|
+
chatDebug('gemini', data);
|
|
1534
1560
|
await spawnGemini(data.command, data.options, writer);
|
|
1535
1561
|
}
|
|
1536
1562
|
else if (data.type === 'qwen-command') {
|
|
1537
|
-
|
|
1538
|
-
console.log('📁 Project:', data.options?.projectPath || data.options?.cwd || 'Unknown');
|
|
1539
|
-
console.log('🔄 Session:', data.options?.sessionId ? 'Resume' : 'New');
|
|
1540
|
-
console.log('🤖 Model:', data.options?.model || 'default');
|
|
1563
|
+
chatDebug('qwen', data);
|
|
1541
1564
|
await spawnQwen(data.command, data.options, writer);
|
|
1542
1565
|
}
|
|
1543
1566
|
else if (data.type === 'cursor-resume') {
|
|
@@ -1673,9 +1696,22 @@ function handleShellConnection(ws) {
|
|
|
1673
1696
|
ws.on('message', async (message) => {
|
|
1674
1697
|
try {
|
|
1675
1698
|
const data = JSON.parse(message);
|
|
1676
|
-
|
|
1699
|
+
// Per-message log would fire once per keystroke — gate behind
|
|
1700
|
+
// SHELL_DEBUG so stdout isn't flooded during normal typing.
|
|
1701
|
+
if (process.env.SHELL_DEBUG) {
|
|
1702
|
+
console.log('[shell]', data.type);
|
|
1703
|
+
}
|
|
1677
1704
|
if (data.type === 'init') {
|
|
1678
|
-
|
|
1705
|
+
// Fallback to the user's home directory (not process.cwd()).
|
|
1706
|
+
// In the Electron wrapper, process.cwd() is the runtime dir
|
|
1707
|
+
// under %APPDATA%\pixcode-desktop\pixcode-runtime — spawning a
|
|
1708
|
+
// login terminal there shows the user a confusing path and
|
|
1709
|
+
// sometimes trips up CLIs that expect a "normal" location
|
|
1710
|
+
// (e.g. codex login exited 1 because the runtime dir is
|
|
1711
|
+
// read-only-feeling / non-writable for cache paths). home
|
|
1712
|
+
// is writable, has a git-friendly cwd, and matches where
|
|
1713
|
+
// every provider already stores its config (~/.codex etc.).
|
|
1714
|
+
const projectPath = data.projectPath || os.homedir();
|
|
1679
1715
|
const sessionId = data.sessionId;
|
|
1680
1716
|
const hasSession = data.hasSession;
|
|
1681
1717
|
const provider = data.provider || 'claude';
|
|
@@ -1683,9 +1719,16 @@ function handleShellConnection(ws) {
|
|
|
1683
1719
|
const isPlainShell = data.isPlainShell || (!!initialCommand && !hasSession) || provider === 'plain-shell';
|
|
1684
1720
|
urlDetectionBuffer = '';
|
|
1685
1721
|
announcedAuthUrls.clear();
|
|
1686
|
-
// Login commands
|
|
1722
|
+
// Login commands should never reuse cached sessions — each login
|
|
1723
|
+
// is a fresh OAuth handshake with a new callback URL. Missing
|
|
1724
|
+
// entries here used to cause "Process exited with code 1" on
|
|
1725
|
+
// the second login attempt because the cached PTY from the
|
|
1726
|
+
// first attempt was still alive and the CLI refused to
|
|
1727
|
+
// re-bind its localhost callback port.
|
|
1687
1728
|
const isLoginCommand = initialCommand && (initialCommand.includes('setup-token') ||
|
|
1688
1729
|
initialCommand.includes('cursor-agent login') ||
|
|
1730
|
+
initialCommand.includes('codex login') ||
|
|
1731
|
+
initialCommand.includes('qwen auth') ||
|
|
1689
1732
|
initialCommand.includes('auth login'));
|
|
1690
1733
|
// Include command hash in session key so different commands get separate sessions
|
|
1691
1734
|
const commandSuffix = isPlainShell && initialCommand
|
|
@@ -2293,6 +2336,24 @@ app.get(/.*/, (req, res) => {
|
|
|
2293
2336
|
if (path.extname(req.path)) {
|
|
2294
2337
|
return res.status(404).send('Not found');
|
|
2295
2338
|
}
|
|
2339
|
+
// Never serve index.html for unmatched API / WS routes — returning HTML
|
|
2340
|
+
// there gives the frontend a bogus 200 + `<!doctype ...` body, which
|
|
2341
|
+
// then explodes `res.json()` as "Unexpected token '<'". Sending a real
|
|
2342
|
+
// JSON 404 here means missing endpoints surface as a clear HTTP error
|
|
2343
|
+
// instead of a misleading parse failure. Fixes the Settings → Agents →
|
|
2344
|
+
// Configuration tab on hosts still running an older backend that
|
|
2345
|
+
// predates `/api/providers/:p/config-files`.
|
|
2346
|
+
if (req.path.startsWith('/api/') || req.path === '/api' ||
|
|
2347
|
+
req.path.startsWith('/ws') || req.path.startsWith('/shell') ||
|
|
2348
|
+
req.path === '/health') {
|
|
2349
|
+
return res.status(404).json({
|
|
2350
|
+
success: false,
|
|
2351
|
+
error: {
|
|
2352
|
+
code: 'ROUTE_NOT_FOUND',
|
|
2353
|
+
message: `No handler for ${req.method} ${req.path}. The backend may be an older build — restart the server after an update.`,
|
|
2354
|
+
},
|
|
2355
|
+
});
|
|
2356
|
+
}
|
|
2296
2357
|
// Only serve index.html for HTML routes, not for static assets
|
|
2297
2358
|
// Static assets should already be handled by express.static middleware above
|
|
2298
2359
|
const indexPath = path.join(APP_ROOT, 'dist', 'index.html');
|