@pixelbyte-software/pixcode 1.49.10 → 1.50.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-DVpGrdpT.js → index-81sOpj25.js} +182 -182
- package/dist/assets/index-DMz0zv6T.css +32 -0
- package/dist/hermes-agent.png +0 -0
- package/dist/index.html +2 -2
- package/dist-server/server/index.js +77 -1
- package/dist-server/server/index.js.map +1 -1
- package/dist-server/server/modules/orchestration/hermes/hermes.routes.js +40 -7
- package/dist-server/server/modules/orchestration/hermes/hermes.routes.js.map +1 -1
- package/dist-server/server/services/hermes-gateway.js +115 -1
- package/dist-server/server/services/hermes-gateway.js.map +1 -1
- package/dist-server/server/services/hermes-install-jobs.js +9 -1
- package/dist-server/server/services/hermes-install-jobs.js.map +1 -1
- package/package.json +1 -1
- package/scripts/hermes/configure-pixcode-mcp.mjs +37 -1
- package/scripts/hermes/pixcode-mcp-server.mjs +166 -8
- package/scripts/smoke/hermes-api-install.mjs +4 -4
- package/scripts/smoke/hermes-gateway-persistence.mjs +104 -0
- package/scripts/smoke/hermes-mcp-pixcode-roundtrip.mjs +27 -0
- package/scripts/smoke/hermes-rest-chat-live.mjs +4 -0
- package/scripts/smoke/hermes-rest-codex-launch.mjs +11 -4
- package/scripts/smoke/hermes-rest-gateway.mjs +9 -1
- package/scripts/smoke/hermes-settings-commands.mjs +166 -0
- package/scripts/smoke/pixcode-workbench-1-48.mjs +13 -5
- package/server/index.js +94 -1
- package/server/modules/orchestration/hermes/hermes.routes.ts +45 -7
- package/server/services/hermes-gateway.js +128 -1
- package/server/services/hermes-install-jobs.js +11 -1
- package/dist/assets/index-BT6txdBK.css +0 -32
|
@@ -319,6 +319,30 @@ function resolvePublicBaseUrl(request) {
|
|
|
319
319
|
const host = headers['x-forwarded-host'] || headers.host || `127.0.0.1:${process.env.SERVER_PORT || process.env.PORT || '3001'}`;
|
|
320
320
|
return `${proto}://${String(host).split(',')[0].trim()}`;
|
|
321
321
|
}
|
|
322
|
+
function resolveHermesMcpBaseUrl() {
|
|
323
|
+
const configured = process.env.PIXCODE_INTERNAL_BASE_URL || process.env.PIXCODE_HERMES_BASE_URL;
|
|
324
|
+
if (configured)
|
|
325
|
+
return configured.replace(/\/$/, '');
|
|
326
|
+
return `http://127.0.0.1:${process.env.SERVER_PORT || process.env.PORT || '3001'}`;
|
|
327
|
+
}
|
|
328
|
+
function quoteBashArg(value) {
|
|
329
|
+
return `'${String(value).replace(/'/g, "'\\''")}'`;
|
|
330
|
+
}
|
|
331
|
+
function quotePowerShellArg(value) {
|
|
332
|
+
return `"${String(value).replace(/`/g, '``').replace(/\$/g, '`$').replace(/"/g, '`"')}"`;
|
|
333
|
+
}
|
|
334
|
+
const HERMES_CLI_COMMAND_PATTERN = /^hermes(?:\s+[A-Za-z0-9._:/=@+-]+)*\s*$/;
|
|
335
|
+
function isHermesCliCommand(command) {
|
|
336
|
+
return typeof command === 'string' && HERMES_CLI_COMMAND_PATTERN.test(command.trim());
|
|
337
|
+
}
|
|
338
|
+
function buildHermesCliCommand(command) {
|
|
339
|
+
const hermesCommand = typeof command === 'string' && command.trim() ? command.trim() : 'hermes';
|
|
340
|
+
const configureScript = path.join(APP_ROOT, 'scripts', 'hermes', 'configure-pixcode-mcp.mjs');
|
|
341
|
+
if (os.platform() === 'win32') {
|
|
342
|
+
return `& ${quotePowerShellArg(process.execPath)} ${quotePowerShellArg(configureScript)} *> $null; ${hermesCommand}`;
|
|
343
|
+
}
|
|
344
|
+
return `${quoteBashArg(process.execPath)} ${quoteBashArg(configureScript)} >/dev/null 2>&1; exec ${hermesCommand}`;
|
|
345
|
+
}
|
|
322
346
|
function getOrCreateHermesApiKey(userId) {
|
|
323
347
|
if (!userId)
|
|
324
348
|
return null;
|
|
@@ -407,6 +431,45 @@ app.post('/api/shell/sessions/terminate', authenticateToken, (req, res) => {
|
|
|
407
431
|
const killedSessions = killProviderPtySessions(projectPath, provider);
|
|
408
432
|
res.json({ success: true, killedSessions });
|
|
409
433
|
});
|
|
434
|
+
app.get('/api/shell/sessions/provider-output', authenticateToken, (req, res) => {
|
|
435
|
+
const provider = String(req.query.provider || 'claude');
|
|
436
|
+
const projectPath = typeof req.query.projectPath === 'string' && req.query.projectPath.trim()
|
|
437
|
+
? req.query.projectPath.trim()
|
|
438
|
+
: null;
|
|
439
|
+
const maxChars = Math.min(20000, Math.max(1000, Number.parseInt(String(req.query.maxChars || '12000'), 10) || 12000));
|
|
440
|
+
if (!SHELL_CLI_PROVIDERS.has(provider)) {
|
|
441
|
+
return res.status(400).json({ error: 'Unsupported provider' });
|
|
442
|
+
}
|
|
443
|
+
const requestedProjectPath = projectPath ? path.resolve(projectPath) : null;
|
|
444
|
+
let matchedSession = null;
|
|
445
|
+
for (const session of ptySessionsMap.values()) {
|
|
446
|
+
if (session?.provider === provider &&
|
|
447
|
+
!session?.isPlainShell &&
|
|
448
|
+
(!requestedProjectPath || path.resolve(session.projectPath || os.homedir()) === requestedProjectPath)) {
|
|
449
|
+
if (!matchedSession || (session.updatedAt || 0) > (matchedSession.updatedAt || 0)) {
|
|
450
|
+
matchedSession = session;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
if (!matchedSession) {
|
|
455
|
+
return res.json({
|
|
456
|
+
active: false,
|
|
457
|
+
provider,
|
|
458
|
+
projectPath: requestedProjectPath,
|
|
459
|
+
output: '',
|
|
460
|
+
message: 'No active provider terminal session found for this project.',
|
|
461
|
+
});
|
|
462
|
+
}
|
|
463
|
+
const rawOutput = matchedSession.buffer.join('').slice(-maxChars);
|
|
464
|
+
res.json({
|
|
465
|
+
active: true,
|
|
466
|
+
provider,
|
|
467
|
+
projectPath: path.resolve(matchedSession.projectPath || os.homedir()),
|
|
468
|
+
sessionId: matchedSession.sessionId || null,
|
|
469
|
+
updatedAt: matchedSession.updatedAt || null,
|
|
470
|
+
output: stripAnsiSequences(rawOutput),
|
|
471
|
+
});
|
|
472
|
+
});
|
|
410
473
|
// Authentication routes (public)
|
|
411
474
|
app.use('/api/auth', authRoutes);
|
|
412
475
|
// Projects API Routes (protected)
|
|
@@ -2012,10 +2075,14 @@ function handleShellConnection(ws, request) {
|
|
|
2012
2075
|
const provider = data.provider || 'claude';
|
|
2013
2076
|
const initialCommand = data.initialCommand;
|
|
2014
2077
|
const isPlainShell = data.isPlainShell || (!!initialCommand && !hasSession) || provider === 'plain-shell';
|
|
2078
|
+
const isHermesCliLaunch = isPlainShell && isHermesCliCommand(initialCommand);
|
|
2015
2079
|
const forceNewSession = Boolean(data.forceNewSession);
|
|
2016
2080
|
const shellPermissionMode = normalizeShellPermissionMode(data.permissionMode);
|
|
2017
2081
|
const shellSkipPermissions = Boolean(data.skipPermissions);
|
|
2018
2082
|
const shellPermissionFlags = buildProviderShellPermissionFlags(provider, shellPermissionMode, shellSkipPermissions);
|
|
2083
|
+
const hermesApiKey = isHermesCliLaunch
|
|
2084
|
+
? getOrCreateHermesApiKey(request.user?.id ?? request.user?.userId ?? null)
|
|
2085
|
+
: null;
|
|
2019
2086
|
urlDetectionBuffer = '';
|
|
2020
2087
|
announcedAuthUrls.clear();
|
|
2021
2088
|
// Login commands should never reuse cached sessions — each login
|
|
@@ -2131,7 +2198,9 @@ function handleShellConnection(ws, request) {
|
|
|
2131
2198
|
let shellCommand;
|
|
2132
2199
|
if (isPlainShell) {
|
|
2133
2200
|
// Plain shell mode without an initial command must stay interactive.
|
|
2134
|
-
shellCommand =
|
|
2201
|
+
shellCommand = isHermesCliLaunch
|
|
2202
|
+
? buildHermesCliCommand(initialCommand)
|
|
2203
|
+
: initialCommand || null;
|
|
2135
2204
|
}
|
|
2136
2205
|
else if (provider === 'cursor') {
|
|
2137
2206
|
const command = buildProviderShellCommand('cursor-agent', shellPermissionFlags);
|
|
@@ -2257,6 +2326,11 @@ function handleShellConnection(ws, request) {
|
|
|
2257
2326
|
TERM: 'xterm-256color',
|
|
2258
2327
|
COLORTERM: 'truecolor',
|
|
2259
2328
|
FORCE_COLOR: '3',
|
|
2329
|
+
...(isHermesCliLaunch ? {
|
|
2330
|
+
PIXCODE_BASE_URL: resolveHermesMcpBaseUrl(),
|
|
2331
|
+
PIXCODE_API_KEY: hermesApiKey || '',
|
|
2332
|
+
PIXCODE_APP_ROOT: APP_ROOT,
|
|
2333
|
+
} : {}),
|
|
2260
2334
|
});
|
|
2261
2335
|
shellProcess = pty.spawn(shell, shellArgs, {
|
|
2262
2336
|
name: 'xterm-256color',
|
|
@@ -2276,12 +2350,14 @@ function handleShellConnection(ws, request) {
|
|
|
2276
2350
|
provider,
|
|
2277
2351
|
isPlainShell,
|
|
2278
2352
|
keepAliveUntilExit: false,
|
|
2353
|
+
updatedAt: Date.now(),
|
|
2279
2354
|
});
|
|
2280
2355
|
// Handle data output
|
|
2281
2356
|
shellProcess.onData((data) => {
|
|
2282
2357
|
const session = ptySessionsMap.get(ptySessionKey);
|
|
2283
2358
|
if (!session)
|
|
2284
2359
|
return;
|
|
2360
|
+
session.updatedAt = Date.now();
|
|
2285
2361
|
if (session.buffer.length < 5000) {
|
|
2286
2362
|
session.buffer.push(data);
|
|
2287
2363
|
}
|