@pixelbyte-software/pixcode 1.50.1 → 1.50.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.
@@ -35,7 +35,7 @@ const tools = [
35
35
  },
36
36
  {
37
37
  name: 'pixcode_open_cli_terminal',
38
- description: 'Use this instead of Hermes shell/proc/skill execution whenever the user asks to open Codex, Claude, Cursor, Gemini, Qwen, or OpenCode inside Pixcode. It asks the open Pixcode workbench to open a visible provider CLI terminal in the project and can type startup input into that terminal. For multi-step, piece-by-piece, or long-running work, put the full user instruction in startupInput so the provider CLI does the work visibly inside Pixcode.',
38
+ description: 'Use this instead of Hermes shell/proc/skill execution whenever the user asks to open Codex, Claude, Cursor, Gemini, Qwen, or OpenCode inside Pixcode. It asks the open Pixcode workbench to open a visible provider CLI terminal in the project and submit startup input there. Do not run a parallel Hermes codex/claude/proc command for the same request. For multi-step, piece-by-piece, or long-running work, put the full user instruction in startupInput so the provider CLI does the work visibly inside Pixcode. If the user asks for the provider output, set waitForOutputMs or call pixcode_read_cli_terminal after launch.',
39
39
  inputSchema: {
40
40
  type: 'object',
41
41
  properties: {
@@ -27,6 +27,7 @@ assert.match(settingsTab, /command:\s*'hermes model'/, 'Hermes settings should e
27
27
  assert.match(settingsTab, /command:\s*'hermes auth'/, 'Hermes settings should expose the credential manager.');
28
28
  assert.match(settingsTab, /command:\s*'hermes setup tools'/, 'Hermes settings should expose tool setup.');
29
29
  assert.match(settingsTab, /command:\s*'hermes doctor'/, 'Hermes settings should expose diagnostics.');
30
+ assert.match(settingsTab, /command:\s*'hermes sessions browse'/, 'Hermes settings should open the interactive sessions browser, not the sessions usage screen.');
30
31
  assert.match(
31
32
  settingsTab,
32
33
  /pixcode:hermes-terminal[\s\S]+command[\s\S]+title/,
@@ -139,14 +140,34 @@ assert.match(
139
140
  );
140
141
  assert.match(
141
142
  shellConnection,
142
- /provider === 'codex' \? '\\n' : '\\r'/,
143
- 'Codex startup input should submit with LF because CR can leave /init typed but unsubmitted in Codex TUI.',
143
+ /provider === 'codex'[\s\S]+startupInputRef\.current/,
144
+ 'Codex startup input should be handled at process launch instead of typed into an already-open TUI.',
145
+ );
146
+ assert.match(
147
+ shellConnection,
148
+ /startupInput:\s*handlesStartupInputInCommand \? startupInputForCommand : null/,
149
+ 'Shell websocket init should send Codex startup input to the backend command builder.',
144
150
  );
145
151
  assert.doesNotMatch(
146
152
  workbench,
147
153
  /hermesCliLaunch\.startupInput \? `\$\{hermesCliLaunch\.startupInput\}\\r` : null/,
148
154
  'Workbench should not pre-append CR before provider-aware startup input normalization.',
149
155
  );
156
+ assert.match(
157
+ shellTypes,
158
+ /startupInput\?: string \| null/,
159
+ 'Shell init messages should carry launch-time startup input for providers that accept an initial prompt.',
160
+ );
161
+ assert.match(
162
+ serverIndex,
163
+ /const startupInput = typeof data\.startupInput === 'string'/,
164
+ 'Shell backend should read launch-time startup input from the websocket init payload.',
165
+ );
166
+ assert.match(
167
+ serverIndex,
168
+ /provider === 'codex'[\s\S]+startupInput[\s\S]+quoteShellArgForPlatform\(startupInput\)/,
169
+ 'Codex provider terminals should start with the requested prompt as a CLI argument so banners/update notices cannot swallow Enter.',
170
+ );
150
171
  assert.match(
151
172
  shellView,
152
173
  /permissionOverride/,
@@ -63,11 +63,19 @@ assert.match(workbench, /WORKBENCH_CLI_STATE_STORAGE_KEY/, 'CLI terminal should
63
63
  assert.match(workbench, /function WorkbenchBottomTerminal/, 'Terminal activity should render as a bottom plain-shell panel.');
64
64
  assert.match(workbench, /BOTTOM_TERMINAL_MIN_HEIGHT/, 'Bottom terminal should support height resizing.');
65
65
  assert.match(workbench, /isBottomTerminalMinimized/, 'Bottom terminal should support minimizing without closing.');
66
+ assert.match(workbench, /bottomTerminalProject/, 'Bottom terminal should stay bound to the project it was opened for.');
67
+ assert.match(workbench, /setBottomTerminalProject/, 'Opening a bottom terminal should capture its project instead of following workspace selection changes.');
68
+ assert.match(workbench, /terminalProject = bottomTerminalProject \?\? selectedProject/, 'Workbench should render bottom terminals against their captured project binding.');
69
+ assert.match(workbench, /WORKBENCH_HERMES_STATE_STORAGE_KEY/, 'Hermes bottom terminal open state should be stored per workspace.');
70
+ assert.match(workbench, /readWorkbenchHermesState/, 'Workspace switches should restore the Hermes terminal state for that project.');
71
+ assert.match(workbench, /writeWorkbenchHermesState/, 'Opening, minimizing, and closing Hermes should persist per-project state.');
66
72
  assert.match(workbench, /isPlainShell/, 'Bottom terminal should open the selected project folder without starting the selected AI CLI.');
67
73
  assert.doesNotMatch(workbench, /HERMES_AGENT_START_COMMAND/, 'Hermes Agent should not launch from the bottom terminal through a server-side sentinel.');
68
74
  assert.doesNotMatch(workbench, /HermesApiChatPanel|HermesTerminalTranscript/, 'Hermes Agent should use the real PTY terminal UI, not a custom REST chat transcript.');
69
75
  assert.doesNotMatch(workbench, /REST POST \/|transport=|response=|gateway=http/, 'Hermes terminal UI must not expose REST debug internals to the user.');
70
76
  assert.match(workbench, /HERMES_DEFAULT_COMMAND = 'hermes --yolo'/, 'Hermes Agent bottom panel should launch the actual `hermes` CLI in a bypass-enabled PTY.');
77
+ assert.match(workbench, /HERMES_HISTORY_COMMAND = 'hermes sessions browse'/, 'Hermes terminal history should open the native interactive session picker.');
78
+ assert.match(workbench, /onOpenHistory=\{openHermesHistory\}/, 'Hermes terminal header should wire its history button to the native Hermes sessions command.');
71
79
  assert.match(workbench, /Pixcode MCP Live/, 'Hermes terminal should show a user-facing Pixcode MCP live badge.');
72
80
  assert.doesNotMatch(workbench, /ml-auto border-blue-500\/40 bg-blue-500\/10/, 'Hermes REST panel must not use right-aligned chat bubbles.');
73
81
  assert.match(workbench, /terminal-launches\/stream/, 'Hermes CLI launch requests should arrive through an EventSource stream.');
@@ -132,6 +140,7 @@ assert.match(shellTerminal, /handleTerminalPaste/, 'Terminal should support brow
132
140
  assert.match(shellTerminal, /handleCopyPasteShortcut/, 'Terminal should normalize Ctrl/Cmd copy and paste shortcuts.');
133
141
  assert.match(shellTerminal, /event\.shiftKey/, 'Terminal should support Ctrl+Shift+C/V style shortcuts.');
134
142
  assert.match(shellTerminal, /copyTerminalSelection/, 'Terminal should copy selected terminal text through shortcuts.');
143
+ assert.match(read('src/components/shell/view/Shell.tsx'), /sendInput\(`\$\{opt\.number\}\\r`\)/, 'CLI prompt option buttons should submit the selected option with Enter, not leave the choice typed.');
135
144
  assert.match(serverIndex, /forceNewSession/, 'Shell backend should support explicit fresh-session launches from the workbench.');
136
145
  assert.match(serverIndex, /killProviderPtySessions/, 'Shell backend should terminate old provider PTYs when a fresh CLI session is requested.');
137
146
 
@@ -282,6 +282,12 @@ for (const token of ['BOTTOM_TERMINAL_MIN_HEIGHT', 'isBottomTerminalMinimized',
282
282
  assert.match(workbench, new RegExp(token), `Workbench should include ${token}.`);
283
283
  }
284
284
 
285
+ assert.match(
286
+ workbench,
287
+ /bottomTerminalProject/,
288
+ 'Bottom terminal should keep its original project while workspace tabs change.',
289
+ );
290
+
285
291
  assert.match(
286
292
  workbench,
287
293
  /isPlainShell/,
@@ -306,6 +312,12 @@ assert.match(
306
312
  'Hermes Agent should launch the Hermes CLI directly in bypass mode.',
307
313
  );
308
314
 
315
+ assert.match(
316
+ workbench,
317
+ /HERMES_HISTORY_COMMAND = 'hermes sessions browse'/,
318
+ 'Hermes Agent should expose the native interactive Hermes session browser from the bottom terminal.',
319
+ );
320
+
309
321
  assert.doesNotMatch(
310
322
  workbench,
311
323
  /Project-scoped agent terminal\. Installs Hermes when missing/,
package/server/index.js CHANGED
@@ -405,6 +405,10 @@ function quotePowerShellArg(value) {
405
405
  return `"${String(value).replace(/`/g, '``').replace(/\$/g, '`$').replace(/"/g, '`"')}"`;
406
406
  }
407
407
 
408
+ function quoteShellArgForPlatform(value) {
409
+ return os.platform() === 'win32' ? quotePowerShellArg(value) : quoteBashArg(value);
410
+ }
411
+
408
412
  const HERMES_CLI_COMMAND_PATTERN = /^hermes(?:\s+[A-Za-z0-9._:/=@+-]+)*\s*$/;
409
413
 
410
414
  function isHermesCliCommand(command) {
@@ -2261,6 +2265,9 @@ function handleShellConnection(ws, request) {
2261
2265
  const hasSession = data.hasSession;
2262
2266
  const provider = data.provider || 'claude';
2263
2267
  const initialCommand = data.initialCommand;
2268
+ const startupInput = typeof data.startupInput === 'string' && data.startupInput.trim()
2269
+ ? data.startupInput.trim()
2270
+ : null;
2264
2271
  const isPlainShell = data.isPlainShell || (!!initialCommand && !hasSession) || provider === 'plain-shell';
2265
2272
  const isHermesCliLaunch = isPlainShell && isHermesCliCommand(initialCommand);
2266
2273
  const forceNewSession = Boolean(data.forceNewSession);
@@ -2418,6 +2425,8 @@ function handleShellConnection(ws, request) {
2418
2425
  } else {
2419
2426
  shellCommand = `${command} resume "${sessionId}" || ${command}`;
2420
2427
  }
2428
+ } else if (startupInput) {
2429
+ shellCommand = `${command} ${quoteShellArgForPlatform(startupInput)}`;
2421
2430
  } else {
2422
2431
  shellCommand = command;
2423
2432
  }