@pixelbyte-software/pixcode 1.38.1 → 1.38.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/dist/assets/index-BzgMq98S.css +32 -0
- package/dist/assets/{index-Br191izN.js → index-Cc0uLPZw.js} +140 -140
- package/dist/index.html +2 -2
- package/dist-server/server/modules/orchestration/workflows/workflow-runner.js +76 -1
- package/dist-server/server/modules/orchestration/workflows/workflow-runner.js.map +1 -1
- package/dist-server/server/modules/orchestration/workflows/workspace-target.js +2 -0
- package/dist-server/server/modules/orchestration/workflows/workspace-target.js.map +1 -1
- package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js +2 -1
- package/dist-server/server/modules/providers/list/codex/codex-auth.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js +5 -2
- package/dist-server/server/modules/providers/list/cursor/cursor-auth.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js +1 -1
- package/dist-server/server/modules/providers/list/gemini/gemini-auth.provider.js.map +1 -1
- package/dist-server/server/modules/providers/list/qwen/qwen-auth.provider.js +1 -1
- package/dist-server/server/modules/providers/list/qwen/qwen-auth.provider.js.map +1 -1
- package/dist-server/server/routes/taskmaster.js +31 -52
- package/dist-server/server/routes/taskmaster.js.map +1 -1
- package/dist-server/server/services/install-jobs.js +152 -17
- package/dist-server/server/services/install-jobs.js.map +1 -1
- package/package.json +1 -1
- package/scripts/smoke/chat-session-provider-pools.mjs +35 -0
- package/scripts/smoke/desktop-native-notifications.mjs +30 -0
- package/scripts/smoke/desktop-tray-icon.mjs +33 -0
- package/scripts/smoke/mac-desktop-runtime.mjs +43 -0
- package/scripts/smoke/multi-project-ui.mjs +45 -0
- package/scripts/smoke/orchestration-permission-fallback.mjs +34 -0
- package/server/modules/orchestration/workflows/workflow-runner.ts +105 -1
- package/server/modules/orchestration/workflows/workspace-target.ts +2 -0
- package/server/modules/providers/list/codex/codex-auth.provider.ts +2 -1
- package/server/modules/providers/list/cursor/cursor-auth.provider.ts +6 -2
- package/server/modules/providers/list/gemini/gemini-auth.provider.ts +1 -1
- package/server/modules/providers/list/qwen/qwen-auth.provider.ts +1 -1
- package/server/routes/taskmaster.js +36 -57
- package/server/services/install-jobs.js +159 -16
- package/dist/assets/index-BzL2G4Sw.css +0 -32
|
@@ -48,6 +48,11 @@ import spawn from 'cross-spawn';
|
|
|
48
48
|
const jobs = new Map();
|
|
49
49
|
const FINISHED_TTL_MS = 10 * 60 * 1000;
|
|
50
50
|
const HARD_TIMEOUT_MS = 10 * 60 * 1000;
|
|
51
|
+
const USER_SHELL_PATH_CACHE_TTL_MS = 5 * 60 * 1000;
|
|
52
|
+
const userShellPathCache = {
|
|
53
|
+
value: null,
|
|
54
|
+
readAt: 0,
|
|
55
|
+
};
|
|
51
56
|
|
|
52
57
|
export const CLI_HOME = path.join(os.homedir(), '.pixcode', 'cli-bin');
|
|
53
58
|
export const CLI_BIN_DIR = path.join(CLI_HOME, 'node_modules', '.bin');
|
|
@@ -94,13 +99,9 @@ function ensureCliHome() {
|
|
|
94
99
|
*/
|
|
95
100
|
export function primeCliBinPath(env = process.env) {
|
|
96
101
|
ensureCliHome();
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
if (
|
|
100
|
-
const next = current ? `${CLI_BIN_DIR}${sep}${current}` : CLI_BIN_DIR;
|
|
101
|
-
env.PATH = next;
|
|
102
|
-
if ('Path' in env) env.Path = next;
|
|
103
|
-
}
|
|
102
|
+
const augmentedEnv = buildCliSpawnEnv(env);
|
|
103
|
+
env.PATH = augmentedEnv.PATH;
|
|
104
|
+
if ('Path' in env || augmentedEnv.Path) env.Path = augmentedEnv.Path || augmentedEnv.PATH;
|
|
104
105
|
// Once PATH is ready, resolve any well-known provider binaries to absolute
|
|
105
106
|
// paths and export them as *_CLI_PATH env vars. This side-steps a Windows
|
|
106
107
|
// gotcha: `child_process.spawn('claude', …)` does NOT auto-resolve .cmd /
|
|
@@ -141,6 +142,135 @@ export function resolveProviderExecutables(env = process.env) {
|
|
|
141
142
|
}
|
|
142
143
|
}
|
|
143
144
|
|
|
145
|
+
function pathSeparator() {
|
|
146
|
+
return process.platform === 'win32' ? ';' : ':';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function splitPathList(value) {
|
|
150
|
+
return String(value || '').split(pathSeparator()).map((entry) => entry.trim()).filter(Boolean);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function collectNvmNodeBins(home) {
|
|
154
|
+
const versionsDir = path.join(home, '.nvm', 'versions', 'node');
|
|
155
|
+
try {
|
|
156
|
+
return fs.readdirSync(versionsDir)
|
|
157
|
+
.map((version) => path.join(versionsDir, version, 'bin'))
|
|
158
|
+
.filter((candidate) => {
|
|
159
|
+
try {
|
|
160
|
+
return fs.statSync(candidate).isDirectory();
|
|
161
|
+
} catch {
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
})
|
|
165
|
+
.sort()
|
|
166
|
+
.reverse();
|
|
167
|
+
} catch {
|
|
168
|
+
return [];
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function collectKnownUserBinDirs(env = process.env) {
|
|
173
|
+
const home = os.homedir();
|
|
174
|
+
if (process.platform === 'win32') {
|
|
175
|
+
return [
|
|
176
|
+
path.join(env.APPDATA || path.join(home, 'AppData', 'Roaming'), 'npm'),
|
|
177
|
+
path.join(env.LOCALAPPDATA || path.join(home, 'AppData', 'Local'), 'Programs', 'nodejs'),
|
|
178
|
+
];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return [
|
|
182
|
+
CLI_BIN_DIR,
|
|
183
|
+
path.dirname(process.execPath),
|
|
184
|
+
...collectNvmNodeBins(home),
|
|
185
|
+
path.join(home, '.volta', 'bin'),
|
|
186
|
+
path.join(home, '.asdf', 'shims'),
|
|
187
|
+
path.join(home, '.bun', 'bin'),
|
|
188
|
+
path.join(home, '.local', 'bin'),
|
|
189
|
+
path.join(home, '.npm-global', 'bin'),
|
|
190
|
+
'/opt/homebrew/bin',
|
|
191
|
+
'/opt/homebrew/sbin',
|
|
192
|
+
'/usr/local/bin',
|
|
193
|
+
'/usr/local/sbin',
|
|
194
|
+
'/usr/bin',
|
|
195
|
+
'/bin',
|
|
196
|
+
];
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function collectUserShellPath(env = process.env) {
|
|
200
|
+
if (process.platform === 'win32') return [];
|
|
201
|
+
|
|
202
|
+
const now = Date.now();
|
|
203
|
+
if (userShellPathCache.value && now - userShellPathCache.readAt < USER_SHELL_PATH_CACHE_TTL_MS) {
|
|
204
|
+
return userShellPathCache.value;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const shells = [env.SHELL, '/bin/zsh', '/bin/bash']
|
|
208
|
+
.filter(Boolean)
|
|
209
|
+
.filter((candidate, index, list) => list.indexOf(candidate) === index)
|
|
210
|
+
.filter((candidate) => {
|
|
211
|
+
try {
|
|
212
|
+
return fs.existsSync(candidate);
|
|
213
|
+
} catch {
|
|
214
|
+
return false;
|
|
215
|
+
}
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
const marker = '__PIXCODE_LOGIN_PATH__=';
|
|
219
|
+
for (const shell of shells) {
|
|
220
|
+
try {
|
|
221
|
+
const output = execFileSync(shell, ['-lc', `printf '\\n${marker}%s\\n' "$PATH"`], {
|
|
222
|
+
encoding: 'utf8',
|
|
223
|
+
env,
|
|
224
|
+
timeout: 2500,
|
|
225
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
226
|
+
});
|
|
227
|
+
const line = output.split(/\r?\n/).reverse().find((part) => part.startsWith(marker));
|
|
228
|
+
const shellPath = line?.slice(marker.length);
|
|
229
|
+
if (shellPath) {
|
|
230
|
+
const entries = splitPathList(shellPath);
|
|
231
|
+
userShellPathCache.value = entries;
|
|
232
|
+
userShellPathCache.readAt = now;
|
|
233
|
+
return entries;
|
|
234
|
+
}
|
|
235
|
+
} catch {
|
|
236
|
+
// GUI-launched macOS apps often have a tiny PATH. If the user's
|
|
237
|
+
// shell startup files are noisy or slow, fall back to known bins.
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
userShellPathCache.value = [];
|
|
242
|
+
userShellPathCache.readAt = now;
|
|
243
|
+
return [];
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function mergePathEntries(env, preferredEntries) {
|
|
247
|
+
const existing = splitPathList(env.PATH || env.Path || '');
|
|
248
|
+
const seen = new Set();
|
|
249
|
+
const merged = [];
|
|
250
|
+
|
|
251
|
+
for (const entry of [...preferredEntries, ...existing]) {
|
|
252
|
+
if (!entry) continue;
|
|
253
|
+
const key = path.resolve(entry);
|
|
254
|
+
if (seen.has(key)) continue;
|
|
255
|
+
seen.add(key);
|
|
256
|
+
merged.push(entry);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const nextPath = merged.join(pathSeparator());
|
|
260
|
+
env.PATH = nextPath;
|
|
261
|
+
if ('Path' in env) env.Path = nextPath;
|
|
262
|
+
return env;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
export function buildCliSpawnEnv(baseEnv = process.env) {
|
|
266
|
+
const env = { ...baseEnv };
|
|
267
|
+
return mergePathEntries(env, [
|
|
268
|
+
CLI_BIN_DIR,
|
|
269
|
+
...collectUserShellPath(baseEnv),
|
|
270
|
+
...collectKnownUserBinDirs(baseEnv),
|
|
271
|
+
]);
|
|
272
|
+
}
|
|
273
|
+
|
|
144
274
|
/**
|
|
145
275
|
* Cross-platform lookup for the Claude Code CLI executable. The
|
|
146
276
|
* @anthropic-ai/claude-agent-sdk SDK spawns its target with plain
|
|
@@ -301,10 +431,8 @@ export function findExecutableOnPath(name, env = process.env) {
|
|
|
301
431
|
paths.push(path.join(env.LOCALAPPDATA || path.join(home, 'AppData', 'Local'), 'Programs', `${name}-code`));
|
|
302
432
|
paths.push(path.join(env.LOCALAPPDATA || path.join(home, 'AppData', 'Local'), 'AnthropicClaude'));
|
|
303
433
|
} else {
|
|
304
|
-
paths.push(
|
|
305
|
-
paths.push(
|
|
306
|
-
paths.push('/usr/local/bin');
|
|
307
|
-
paths.push('/opt/homebrew/bin');
|
|
434
|
+
paths.push(...collectUserShellPath(env));
|
|
435
|
+
paths.push(...collectKnownUserBinDirs(env));
|
|
308
436
|
}
|
|
309
437
|
|
|
310
438
|
const exts = isWindows
|
|
@@ -331,7 +459,7 @@ export function findExecutableOnPath(name, env = process.env) {
|
|
|
331
459
|
* more reliable than trusting PATH — when Pixcode runs as a daemon, PATH
|
|
332
460
|
* is often minimal and doesn't include the user's node install.
|
|
333
461
|
*/
|
|
334
|
-
function resolveNpmCommand() {
|
|
462
|
+
function resolveNpmCommand(env = process.env) {
|
|
335
463
|
const nodeDir = path.dirname(process.execPath);
|
|
336
464
|
const isWindows = process.platform === 'win32';
|
|
337
465
|
const candidates = isWindows
|
|
@@ -348,8 +476,11 @@ function resolveNpmCommand() {
|
|
|
348
476
|
return siblingNpm; // we'll invoke `node <npm-cli.js>`
|
|
349
477
|
}
|
|
350
478
|
}
|
|
351
|
-
|
|
352
|
-
|
|
479
|
+
|
|
480
|
+
const resolvedFromPath = findExecutableOnPath('npm', env);
|
|
481
|
+
if (resolvedFromPath) return resolvedFromPath;
|
|
482
|
+
|
|
483
|
+
return null;
|
|
353
484
|
}
|
|
354
485
|
|
|
355
486
|
function packageFromCommand(installCmd) {
|
|
@@ -406,7 +537,19 @@ export function createInstallJob({ provider, installCmd, packageName }) {
|
|
|
406
537
|
appendLog('meta', `Installing ${pkg} into ${CLI_HOME}\n`);
|
|
407
538
|
appendLog('meta', `(sandboxed — no sudo / admin required)\n`);
|
|
408
539
|
|
|
409
|
-
const
|
|
540
|
+
const installEnv = buildCliSpawnEnv(process.env);
|
|
541
|
+
const npmCmd = resolveNpmCommand(installEnv);
|
|
542
|
+
if (!npmCmd) {
|
|
543
|
+
job.status = 'error';
|
|
544
|
+
job.error = 'npm was not found. Install Node.js/npm or add it to your macOS login shell PATH, then click Refresh.';
|
|
545
|
+
job.finishedAt = new Date().toISOString();
|
|
546
|
+
appendLog('stderr', job.error + '\n');
|
|
547
|
+
emitter.emit('done', buildDonePayload(job));
|
|
548
|
+
scheduleCleanup(job);
|
|
549
|
+
jobs.set(id, job);
|
|
550
|
+
return job;
|
|
551
|
+
}
|
|
552
|
+
|
|
410
553
|
const useNodeRunner = npmCmd.endsWith('.js');
|
|
411
554
|
|
|
412
555
|
const cmd = useNodeRunner ? process.execPath : npmCmd;
|
|
@@ -420,7 +563,7 @@ export function createInstallJob({ provider, installCmd, packageName }) {
|
|
|
420
563
|
try {
|
|
421
564
|
child = spawn(cmd, args, {
|
|
422
565
|
cwd: CLI_HOME,
|
|
423
|
-
env: { ...
|
|
566
|
+
env: { ...installEnv, npm_config_yes: 'true' },
|
|
424
567
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
425
568
|
windowsHide: true,
|
|
426
569
|
// cross-spawn handles .cmd/.bat resolution itself — no shell
|