@austinthesing/magic-shell 0.2.28 → 0.2.29

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.
Files changed (3) hide show
  1. package/dist/cli.js +141 -115
  2. package/dist/tui.js +141 -115
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -76817,11 +76817,10 @@ var inputHintText;
76817
76817
  var helpBarText;
76818
76818
  var modelSelector = null;
76819
76819
  var providerSelector = null;
76820
- var slashCommandContainer = null;
76821
- var slashCommandSelector = null;
76822
76820
  var slashCommandMatches = [];
76823
76821
  var slashCommandSelectedIndex = 0;
76824
76822
  var slashCommandSyncQueued = false;
76823
+ var slashCommandExecuting = false;
76825
76824
  var pendingMessageId = null;
76826
76825
  var awaitingConfirmation = false;
76827
76826
  function generateMessageId() {
@@ -77106,6 +77105,10 @@ function createMainUI() {
77106
77105
  { name: "j", ctrl: true, action: "newline" }
77107
77106
  ],
77108
77107
  onSubmit: () => {
77108
+ if (slashCommandModal && slashCommandMatches.length > 0) {
77109
+ executeSelectedSlashCommand();
77110
+ return;
77111
+ }
77109
77112
  const value = inputField.editBuffer.getText();
77110
77113
  handleInput(value);
77111
77114
  }
@@ -77434,27 +77437,18 @@ function refreshThemeColors() {
77434
77437
  if (inputHintText) {
77435
77438
  inputHintText.content = getInputHintContent();
77436
77439
  }
77437
- if (slashCommandContainer) {
77438
- slashCommandContainer.borderColor = theme.colors.border;
77439
- slashCommandContainer.backgroundColor = theme.colors.backgroundPanel;
77440
- }
77441
- if (slashCommandSelector) {
77442
- slashCommandSelector.selectedBackgroundColor = theme.colors.backgroundElement;
77443
- slashCommandSelector.textColor = theme.colors.text;
77444
- slashCommandSelector.selectedTextColor = theme.colors.primary;
77445
- slashCommandSelector.descriptionColor = theme.colors.textMuted;
77446
- slashCommandSelector.selectedDescriptionColor = theme.colors.textMuted;
77447
- }
77448
77440
  }
77449
77441
  async function handleInput(value) {
77450
77442
  const input = value.trim();
77451
77443
  if (!input)
77452
77444
  return;
77453
- inputField.setText("");
77454
- closeSlashCommandMenu();
77455
77445
  if (input.startsWith("/") && await tryHandleSlashCommand(input)) {
77446
+ inputField.setText("");
77447
+ closeSlashCommandMenu();
77456
77448
  return;
77457
77449
  }
77450
+ inputField.setText("");
77451
+ closeSlashCommandMenu();
77458
77452
  if (input.startsWith("!")) {
77459
77453
  await handleSpecialCommand(input);
77460
77454
  return;
@@ -77466,15 +77460,22 @@ async function handleInput(value) {
77466
77460
  }
77467
77461
  await translateAndProcess(input);
77468
77462
  }
77463
+ async function executeSelectedSlashCommand() {
77464
+ if (slashCommandExecuting || !slashCommandModal || slashCommandMatches.length === 0)
77465
+ return;
77466
+ slashCommandExecuting = true;
77467
+ try {
77468
+ const selected = slashCommandMatches[Math.min(slashCommandSelectedIndex, slashCommandMatches.length - 1)];
77469
+ inputField.setText("");
77470
+ closeSlashCommandMenu();
77471
+ await selected.action();
77472
+ } finally {
77473
+ slashCommandExecuting = false;
77474
+ }
77475
+ }
77469
77476
  async function tryHandleSlashCommand(input) {
77470
77477
  if (!input.startsWith("/"))
77471
77478
  return false;
77472
- const slashBody = input.slice(1).trim();
77473
- if (!slashBody.includes(" ") && slashCommandMatches.length > 0) {
77474
- const selected = slashCommandMatches[Math.min(slashCommandSelectedIndex, slashCommandMatches.length - 1)];
77475
- await handleSpecialCommand(`/${selected.slash}`);
77476
- return true;
77477
- }
77478
77479
  await handleSpecialCommand(input);
77479
77480
  return true;
77480
77481
  }
@@ -77957,7 +77958,10 @@ function showThemeSelector() {
77957
77958
  renderer.keyInput.on("keypress", escHandler);
77958
77959
  themeSelector.focus();
77959
77960
  }
77960
- var commandPalette = null;
77961
+ var MODAL_LIST_WIDTH = 55;
77962
+ var MODAL_LIST_MAX_ITEMS = 12;
77963
+ var commandPaletteModal = null;
77964
+ var slashCommandModal = null;
77961
77965
  var commandPaletteQuery = "";
77962
77966
  var chordMode = "none";
77963
77967
  function cycleThinkingLevel() {
@@ -78149,60 +78153,100 @@ function getSlashCommandMatches(inputText) {
78149
78153
  return `${cmd.slash} ${cmd.name} ${cmd.description}`.toLowerCase().includes(query);
78150
78154
  });
78151
78155
  }
78152
- function ensureSlashCommandMenu() {
78153
- if (slashCommandContainer && slashCommandSelector)
78154
- return;
78155
- slashCommandContainer = new BoxRenderable(renderer, {
78156
- id: "slash-command-container",
78157
- width: "100%",
78156
+ function openModalList(config3) {
78157
+ const theme = getTheme();
78158
+ const width = MODAL_LIST_WIDTH;
78159
+ const termWidth = process.stdout.columns || 80;
78160
+ const left = Math.max(2, Math.floor((termWidth - width) / 2));
78161
+ const itemCount = Math.max(config3.options.length, 1);
78162
+ const listHeight = Math.min(itemCount + 2, MODAL_LIST_MAX_ITEMS);
78163
+ const containerHeight = listHeight + 2;
78164
+ const container = new BoxRenderable(renderer, {
78165
+ id: config3.containerId,
78166
+ position: "absolute",
78167
+ left,
78168
+ top: 3,
78169
+ width,
78170
+ height: containerHeight,
78171
+ backgroundColor: theme.colors.backgroundPanel,
78158
78172
  border: true,
78159
- borderColor: getTheme().colors.border,
78173
+ borderColor: theme.colors.primary,
78160
78174
  borderStyle: "single",
78161
- backgroundColor: getTheme().colors.backgroundPanel,
78162
- paddingLeft: 1,
78163
- paddingRight: 1,
78164
- paddingTop: 0,
78165
- paddingBottom: 0,
78166
- marginTop: 1
78175
+ title: config3.title,
78176
+ titleAlignment: "center",
78177
+ zIndex: 200,
78178
+ padding: 1
78167
78179
  });
78168
- inputContainer.add(slashCommandContainer);
78169
- slashCommandSelector = new SelectRenderable(renderer, {
78170
- id: "slash-command-select",
78180
+ renderer.root.add(container);
78181
+ const selector = new SelectRenderable(renderer, {
78182
+ id: config3.selectorId,
78171
78183
  width: "100%",
78172
- height: 6,
78173
- options: [],
78184
+ height: listHeight,
78185
+ options: config3.options,
78174
78186
  backgroundColor: "transparent",
78175
78187
  focusedBackgroundColor: "transparent",
78176
- selectedBackgroundColor: getTheme().colors.backgroundElement,
78177
- textColor: getTheme().colors.text,
78178
- selectedTextColor: getTheme().colors.primary,
78179
- descriptionColor: getTheme().colors.textMuted,
78180
- selectedDescriptionColor: getTheme().colors.textMuted,
78188
+ selectedBackgroundColor: theme.colors.backgroundElement,
78189
+ textColor: theme.colors.text,
78190
+ selectedTextColor: theme.colors.primary,
78191
+ descriptionColor: theme.colors.textMuted,
78192
+ selectedDescriptionColor: theme.colors.textMuted,
78181
78193
  showDescription: true,
78182
78194
  wrapSelection: true
78183
78195
  });
78184
- slashCommandContainer.add(slashCommandSelector);
78196
+ container.add(selector);
78197
+ const handle = {
78198
+ containerId: config3.containerId,
78199
+ container,
78200
+ selector,
78201
+ updateOptions(options, selectedIndex = 0) {
78202
+ const count = Math.max(options.length, 1);
78203
+ const newListHeight = Math.min(count + 2, MODAL_LIST_MAX_ITEMS);
78204
+ selector.options = options;
78205
+ selector.height = newListHeight;
78206
+ container.height = newListHeight + 2;
78207
+ selector.setSelectedIndex(Math.min(selectedIndex, Math.max(options.length - 1, 0)));
78208
+ },
78209
+ setSelectedIndex(index) {
78210
+ selector.setSelectedIndex(index);
78211
+ },
78212
+ close() {
78213
+ renderer.root.remove(config3.containerId);
78214
+ inputField?.focus();
78215
+ }
78216
+ };
78217
+ if (config3.onSelect) {
78218
+ selector.on(SelectRenderableEvents.ITEM_SELECTED, async (index, option) => {
78219
+ await config3.onSelect?.(index, option);
78220
+ });
78221
+ }
78222
+ const initialIndex = config3.selectedIndex ?? 0;
78223
+ if (config3.focusList !== false) {
78224
+ selector.focus();
78225
+ } else {
78226
+ selector.setSelectedIndex(initialIndex);
78227
+ }
78228
+ return handle;
78185
78229
  }
78186
- function updateSlashCommandMenuOptions() {
78187
- if (!slashCommandSelector)
78188
- return;
78189
- slashCommandSelector.options = slashCommandMatches.map((cmd) => ({
78230
+ function getSlashCommandSelectOptions() {
78231
+ return slashCommandMatches.map((cmd) => ({
78190
78232
  name: `/${cmd.slash}`,
78191
78233
  description: cmd.description,
78192
78234
  value: cmd
78193
78235
  }));
78194
- slashCommandSelector.height = Math.min(Math.max(slashCommandMatches.length, 1), 6);
78195
- slashCommandSelector.setSelectedIndex(slashCommandSelectedIndex);
78196
78236
  }
78197
78237
  function closeSlashCommandMenu() {
78198
- if (slashCommandContainer) {
78199
- inputContainer.remove("slash-command-container");
78200
- slashCommandContainer = null;
78201
- slashCommandSelector = null;
78238
+ if (slashCommandModal) {
78239
+ slashCommandModal.close();
78240
+ slashCommandModal = null;
78202
78241
  }
78203
78242
  slashCommandMatches = [];
78204
78243
  slashCommandSelectedIndex = 0;
78205
78244
  }
78245
+ function updateSlashCommandModalOptions() {
78246
+ if (!slashCommandModal)
78247
+ return;
78248
+ slashCommandModal.updateOptions(getSlashCommandSelectOptions(), slashCommandSelectedIndex);
78249
+ }
78206
78250
  function syncSlashCommandMenu() {
78207
78251
  const inputText = inputField.editBuffer.getText();
78208
78252
  const matches = getSlashCommandMatches(inputText);
@@ -78210,10 +78254,21 @@ function syncSlashCommandMenu() {
78210
78254
  closeSlashCommandMenu();
78211
78255
  return;
78212
78256
  }
78213
- ensureSlashCommandMenu();
78214
78257
  slashCommandMatches = matches;
78215
78258
  slashCommandSelectedIndex = Math.min(slashCommandSelectedIndex, slashCommandMatches.length - 1);
78216
- updateSlashCommandMenuOptions();
78259
+ const options = getSlashCommandSelectOptions();
78260
+ if (slashCommandModal) {
78261
+ slashCommandModal.updateOptions(options, slashCommandSelectedIndex);
78262
+ return;
78263
+ }
78264
+ slashCommandModal = openModalList({
78265
+ containerId: "slash-command-modal",
78266
+ selectorId: "slash-command-select",
78267
+ title: "Commands",
78268
+ options,
78269
+ focusList: false,
78270
+ selectedIndex: slashCommandSelectedIndex
78271
+ });
78217
78272
  }
78218
78273
  function queueSlashCommandSync() {
78219
78274
  if (slashCommandSyncQueued)
@@ -78226,55 +78281,24 @@ function queueSlashCommandSync() {
78226
78281
  }, 0);
78227
78282
  }
78228
78283
  function showCommandPalette() {
78229
- if (commandPalette) {
78284
+ if (commandPaletteModal) {
78230
78285
  return;
78231
78286
  }
78232
78287
  commandPaletteQuery = "";
78233
- const commands = getCommandPaletteOptions();
78234
- const paletteWidth = 55;
78235
- const termWidth = process.stdout.columns || 80;
78236
- const paletteLeft = Math.max(2, Math.floor((termWidth - paletteWidth) / 2));
78237
- const container = new BoxRenderable(renderer, {
78238
- id: "command-palette-container",
78239
- position: "absolute",
78240
- left: paletteLeft,
78241
- top: 3,
78242
- width: paletteWidth,
78243
- height: Math.min(commands.length + 4, 16),
78244
- backgroundColor: "#1e293b",
78245
- border: true,
78246
- borderColor: "#60a5fa",
78247
- borderStyle: "single",
78288
+ commandPaletteModal = openModalList({
78289
+ containerId: "command-palette-container",
78290
+ selectorId: "command-palette-select",
78248
78291
  title: "Commands",
78249
- titleAlignment: "center",
78250
- zIndex: 200,
78251
- padding: 1
78252
- });
78253
- renderer.root.add(container);
78254
- commandPalette = new SelectRenderable(renderer, {
78255
- id: "command-palette-select",
78256
- width: "100%",
78257
- height: Math.min(commands.length + 2, 12),
78258
78292
  options: getCommandPaletteSelectOptions(),
78259
- backgroundColor: "transparent",
78260
- focusedBackgroundColor: "transparent",
78261
- selectedBackgroundColor: "#334155",
78262
- textColor: "#e2e8f0",
78263
- selectedTextColor: "#60a5fa",
78264
- descriptionColor: "#64748b",
78265
- selectedDescriptionColor: "#94a3b8",
78266
- showDescription: true,
78267
- wrapSelection: true
78268
- });
78269
- container.add(commandPalette);
78270
- commandPalette.on(SelectRenderableEvents.ITEM_SELECTED, async (_2, option) => {
78271
- if (!option.value)
78272
- return;
78273
- const cmd = option.value;
78274
- closeCommandPalette();
78275
- await cmd.action();
78293
+ focusList: true,
78294
+ onSelect: async (_2, option) => {
78295
+ if (!option.value)
78296
+ return;
78297
+ const cmd = option.value;
78298
+ closeCommandPalette();
78299
+ await cmd.action();
78300
+ }
78276
78301
  });
78277
- commandPalette.focus();
78278
78302
  }
78279
78303
  function getCommandPaletteSelectOptions() {
78280
78304
  const query = commandPaletteQuery.toLowerCase();
@@ -78297,30 +78321,28 @@ function getCommandPaletteSelectOptions() {
78297
78321
  }));
78298
78322
  }
78299
78323
  function updateCommandPaletteOptions() {
78300
- if (!commandPalette)
78324
+ if (!commandPaletteModal)
78301
78325
  return;
78302
- commandPalette.options = getCommandPaletteSelectOptions();
78303
- commandPalette.setSelectedIndex(0);
78326
+ commandPaletteModal.updateOptions(getCommandPaletteSelectOptions(), 0);
78304
78327
  }
78305
78328
  function closeCommandPalette() {
78306
- if (commandPalette) {
78307
- renderer.root.remove("command-palette-container");
78308
- commandPalette = null;
78329
+ if (commandPaletteModal) {
78330
+ commandPaletteModal.close();
78331
+ commandPaletteModal = null;
78309
78332
  commandPaletteQuery = "";
78310
- inputField?.focus();
78311
78333
  }
78312
78334
  }
78313
78335
  function handleKeypress(key) {
78314
78336
  const commands = getCommandPaletteOptions();
78315
- if (slashCommandMatches.length > 0) {
78337
+ if (slashCommandModal && slashCommandMatches.length > 0) {
78316
78338
  if (key.name === "up") {
78317
78339
  slashCommandSelectedIndex = slashCommandSelectedIndex === 0 ? slashCommandMatches.length - 1 : slashCommandSelectedIndex - 1;
78318
- updateSlashCommandMenuOptions();
78340
+ updateSlashCommandModalOptions();
78319
78341
  return;
78320
78342
  }
78321
78343
  if (key.name === "down") {
78322
78344
  slashCommandSelectedIndex = (slashCommandSelectedIndex + 1) % slashCommandMatches.length;
78323
- updateSlashCommandMenuOptions();
78345
+ updateSlashCommandModalOptions();
78324
78346
  return;
78325
78347
  }
78326
78348
  if (key.name === "tab") {
@@ -78329,6 +78351,10 @@ function handleKeypress(key) {
78329
78351
  inputField.focus();
78330
78352
  return;
78331
78353
  }
78354
+ if (key.name === "return" && !key.shift && !key.ctrl && !key.meta) {
78355
+ executeSelectedSlashCommand();
78356
+ return;
78357
+ }
78332
78358
  }
78333
78359
  if (key.ctrl && key.name === "p") {
78334
78360
  showCommandPalette();
@@ -78356,7 +78382,7 @@ function handleKeypress(key) {
78356
78382
  }
78357
78383
  return;
78358
78384
  }
78359
- if (commandPalette) {
78385
+ if (commandPaletteModal) {
78360
78386
  if (key.name === "backspace" || key.name === "delete") {
78361
78387
  commandPaletteQuery = commandPaletteQuery.slice(0, -1);
78362
78388
  updateCommandPaletteOptions();
@@ -78370,7 +78396,7 @@ function handleKeypress(key) {
78370
78396
  }
78371
78397
  }
78372
78398
  if (key.ctrl && key.name === "c") {
78373
- if (commandPalette) {
78399
+ if (commandPaletteModal) {
78374
78400
  closeCommandPalette();
78375
78401
  return;
78376
78402
  }
@@ -78401,7 +78427,7 @@ function handleKeypress(key) {
78401
78427
  }
78402
78428
  if (key.name === "escape") {
78403
78429
  chordMode = "none";
78404
- if (commandPalette) {
78430
+ if (commandPaletteModal) {
78405
78431
  closeCommandPalette();
78406
78432
  return;
78407
78433
  }
@@ -78448,7 +78474,7 @@ function handleKeypress(key) {
78448
78474
  addSystemMessage(`Copied to clipboard: ${msg.command}`);
78449
78475
  }
78450
78476
  }
78451
- if (key.name === "o" && !awaitingConfirmation && !commandPalette && !modelSelector) {
78477
+ if (key.name === "o" && !awaitingConfirmation && !commandPaletteModal && !modelSelector) {
78452
78478
  toggleLastResultExpand();
78453
78479
  }
78454
78480
  }
package/dist/tui.js CHANGED
@@ -76817,11 +76817,10 @@ var inputHintText;
76817
76817
  var helpBarText;
76818
76818
  var modelSelector = null;
76819
76819
  var providerSelector = null;
76820
- var slashCommandContainer = null;
76821
- var slashCommandSelector = null;
76822
76820
  var slashCommandMatches = [];
76823
76821
  var slashCommandSelectedIndex = 0;
76824
76822
  var slashCommandSyncQueued = false;
76823
+ var slashCommandExecuting = false;
76825
76824
  var pendingMessageId = null;
76826
76825
  var awaitingConfirmation = false;
76827
76826
  function generateMessageId() {
@@ -77106,6 +77105,10 @@ function createMainUI() {
77106
77105
  { name: "j", ctrl: true, action: "newline" }
77107
77106
  ],
77108
77107
  onSubmit: () => {
77108
+ if (slashCommandModal && slashCommandMatches.length > 0) {
77109
+ executeSelectedSlashCommand();
77110
+ return;
77111
+ }
77109
77112
  const value = inputField.editBuffer.getText();
77110
77113
  handleInput(value);
77111
77114
  }
@@ -77434,27 +77437,18 @@ function refreshThemeColors() {
77434
77437
  if (inputHintText) {
77435
77438
  inputHintText.content = getInputHintContent();
77436
77439
  }
77437
- if (slashCommandContainer) {
77438
- slashCommandContainer.borderColor = theme.colors.border;
77439
- slashCommandContainer.backgroundColor = theme.colors.backgroundPanel;
77440
- }
77441
- if (slashCommandSelector) {
77442
- slashCommandSelector.selectedBackgroundColor = theme.colors.backgroundElement;
77443
- slashCommandSelector.textColor = theme.colors.text;
77444
- slashCommandSelector.selectedTextColor = theme.colors.primary;
77445
- slashCommandSelector.descriptionColor = theme.colors.textMuted;
77446
- slashCommandSelector.selectedDescriptionColor = theme.colors.textMuted;
77447
- }
77448
77440
  }
77449
77441
  async function handleInput(value) {
77450
77442
  const input = value.trim();
77451
77443
  if (!input)
77452
77444
  return;
77453
- inputField.setText("");
77454
- closeSlashCommandMenu();
77455
77445
  if (input.startsWith("/") && await tryHandleSlashCommand(input)) {
77446
+ inputField.setText("");
77447
+ closeSlashCommandMenu();
77456
77448
  return;
77457
77449
  }
77450
+ inputField.setText("");
77451
+ closeSlashCommandMenu();
77458
77452
  if (input.startsWith("!")) {
77459
77453
  await handleSpecialCommand(input);
77460
77454
  return;
@@ -77466,15 +77460,22 @@ async function handleInput(value) {
77466
77460
  }
77467
77461
  await translateAndProcess(input);
77468
77462
  }
77463
+ async function executeSelectedSlashCommand() {
77464
+ if (slashCommandExecuting || !slashCommandModal || slashCommandMatches.length === 0)
77465
+ return;
77466
+ slashCommandExecuting = true;
77467
+ try {
77468
+ const selected = slashCommandMatches[Math.min(slashCommandSelectedIndex, slashCommandMatches.length - 1)];
77469
+ inputField.setText("");
77470
+ closeSlashCommandMenu();
77471
+ await selected.action();
77472
+ } finally {
77473
+ slashCommandExecuting = false;
77474
+ }
77475
+ }
77469
77476
  async function tryHandleSlashCommand(input) {
77470
77477
  if (!input.startsWith("/"))
77471
77478
  return false;
77472
- const slashBody = input.slice(1).trim();
77473
- if (!slashBody.includes(" ") && slashCommandMatches.length > 0) {
77474
- const selected = slashCommandMatches[Math.min(slashCommandSelectedIndex, slashCommandMatches.length - 1)];
77475
- await handleSpecialCommand(`/${selected.slash}`);
77476
- return true;
77477
- }
77478
77479
  await handleSpecialCommand(input);
77479
77480
  return true;
77480
77481
  }
@@ -77957,7 +77958,10 @@ function showThemeSelector() {
77957
77958
  renderer.keyInput.on("keypress", escHandler);
77958
77959
  themeSelector.focus();
77959
77960
  }
77960
- var commandPalette = null;
77961
+ var MODAL_LIST_WIDTH = 55;
77962
+ var MODAL_LIST_MAX_ITEMS = 12;
77963
+ var commandPaletteModal = null;
77964
+ var slashCommandModal = null;
77961
77965
  var commandPaletteQuery = "";
77962
77966
  var chordMode = "none";
77963
77967
  function cycleThinkingLevel() {
@@ -78149,60 +78153,100 @@ function getSlashCommandMatches(inputText) {
78149
78153
  return `${cmd.slash} ${cmd.name} ${cmd.description}`.toLowerCase().includes(query);
78150
78154
  });
78151
78155
  }
78152
- function ensureSlashCommandMenu() {
78153
- if (slashCommandContainer && slashCommandSelector)
78154
- return;
78155
- slashCommandContainer = new BoxRenderable(renderer, {
78156
- id: "slash-command-container",
78157
- width: "100%",
78156
+ function openModalList(config3) {
78157
+ const theme = getTheme();
78158
+ const width = MODAL_LIST_WIDTH;
78159
+ const termWidth = process.stdout.columns || 80;
78160
+ const left = Math.max(2, Math.floor((termWidth - width) / 2));
78161
+ const itemCount = Math.max(config3.options.length, 1);
78162
+ const listHeight = Math.min(itemCount + 2, MODAL_LIST_MAX_ITEMS);
78163
+ const containerHeight = listHeight + 2;
78164
+ const container = new BoxRenderable(renderer, {
78165
+ id: config3.containerId,
78166
+ position: "absolute",
78167
+ left,
78168
+ top: 3,
78169
+ width,
78170
+ height: containerHeight,
78171
+ backgroundColor: theme.colors.backgroundPanel,
78158
78172
  border: true,
78159
- borderColor: getTheme().colors.border,
78173
+ borderColor: theme.colors.primary,
78160
78174
  borderStyle: "single",
78161
- backgroundColor: getTheme().colors.backgroundPanel,
78162
- paddingLeft: 1,
78163
- paddingRight: 1,
78164
- paddingTop: 0,
78165
- paddingBottom: 0,
78166
- marginTop: 1
78175
+ title: config3.title,
78176
+ titleAlignment: "center",
78177
+ zIndex: 200,
78178
+ padding: 1
78167
78179
  });
78168
- inputContainer.add(slashCommandContainer);
78169
- slashCommandSelector = new SelectRenderable(renderer, {
78170
- id: "slash-command-select",
78180
+ renderer.root.add(container);
78181
+ const selector = new SelectRenderable(renderer, {
78182
+ id: config3.selectorId,
78171
78183
  width: "100%",
78172
- height: 6,
78173
- options: [],
78184
+ height: listHeight,
78185
+ options: config3.options,
78174
78186
  backgroundColor: "transparent",
78175
78187
  focusedBackgroundColor: "transparent",
78176
- selectedBackgroundColor: getTheme().colors.backgroundElement,
78177
- textColor: getTheme().colors.text,
78178
- selectedTextColor: getTheme().colors.primary,
78179
- descriptionColor: getTheme().colors.textMuted,
78180
- selectedDescriptionColor: getTheme().colors.textMuted,
78188
+ selectedBackgroundColor: theme.colors.backgroundElement,
78189
+ textColor: theme.colors.text,
78190
+ selectedTextColor: theme.colors.primary,
78191
+ descriptionColor: theme.colors.textMuted,
78192
+ selectedDescriptionColor: theme.colors.textMuted,
78181
78193
  showDescription: true,
78182
78194
  wrapSelection: true
78183
78195
  });
78184
- slashCommandContainer.add(slashCommandSelector);
78196
+ container.add(selector);
78197
+ const handle = {
78198
+ containerId: config3.containerId,
78199
+ container,
78200
+ selector,
78201
+ updateOptions(options, selectedIndex = 0) {
78202
+ const count = Math.max(options.length, 1);
78203
+ const newListHeight = Math.min(count + 2, MODAL_LIST_MAX_ITEMS);
78204
+ selector.options = options;
78205
+ selector.height = newListHeight;
78206
+ container.height = newListHeight + 2;
78207
+ selector.setSelectedIndex(Math.min(selectedIndex, Math.max(options.length - 1, 0)));
78208
+ },
78209
+ setSelectedIndex(index) {
78210
+ selector.setSelectedIndex(index);
78211
+ },
78212
+ close() {
78213
+ renderer.root.remove(config3.containerId);
78214
+ inputField?.focus();
78215
+ }
78216
+ };
78217
+ if (config3.onSelect) {
78218
+ selector.on(SelectRenderableEvents.ITEM_SELECTED, async (index, option) => {
78219
+ await config3.onSelect?.(index, option);
78220
+ });
78221
+ }
78222
+ const initialIndex = config3.selectedIndex ?? 0;
78223
+ if (config3.focusList !== false) {
78224
+ selector.focus();
78225
+ } else {
78226
+ selector.setSelectedIndex(initialIndex);
78227
+ }
78228
+ return handle;
78185
78229
  }
78186
- function updateSlashCommandMenuOptions() {
78187
- if (!slashCommandSelector)
78188
- return;
78189
- slashCommandSelector.options = slashCommandMatches.map((cmd) => ({
78230
+ function getSlashCommandSelectOptions() {
78231
+ return slashCommandMatches.map((cmd) => ({
78190
78232
  name: `/${cmd.slash}`,
78191
78233
  description: cmd.description,
78192
78234
  value: cmd
78193
78235
  }));
78194
- slashCommandSelector.height = Math.min(Math.max(slashCommandMatches.length, 1), 6);
78195
- slashCommandSelector.setSelectedIndex(slashCommandSelectedIndex);
78196
78236
  }
78197
78237
  function closeSlashCommandMenu() {
78198
- if (slashCommandContainer) {
78199
- inputContainer.remove("slash-command-container");
78200
- slashCommandContainer = null;
78201
- slashCommandSelector = null;
78238
+ if (slashCommandModal) {
78239
+ slashCommandModal.close();
78240
+ slashCommandModal = null;
78202
78241
  }
78203
78242
  slashCommandMatches = [];
78204
78243
  slashCommandSelectedIndex = 0;
78205
78244
  }
78245
+ function updateSlashCommandModalOptions() {
78246
+ if (!slashCommandModal)
78247
+ return;
78248
+ slashCommandModal.updateOptions(getSlashCommandSelectOptions(), slashCommandSelectedIndex);
78249
+ }
78206
78250
  function syncSlashCommandMenu() {
78207
78251
  const inputText = inputField.editBuffer.getText();
78208
78252
  const matches = getSlashCommandMatches(inputText);
@@ -78210,10 +78254,21 @@ function syncSlashCommandMenu() {
78210
78254
  closeSlashCommandMenu();
78211
78255
  return;
78212
78256
  }
78213
- ensureSlashCommandMenu();
78214
78257
  slashCommandMatches = matches;
78215
78258
  slashCommandSelectedIndex = Math.min(slashCommandSelectedIndex, slashCommandMatches.length - 1);
78216
- updateSlashCommandMenuOptions();
78259
+ const options = getSlashCommandSelectOptions();
78260
+ if (slashCommandModal) {
78261
+ slashCommandModal.updateOptions(options, slashCommandSelectedIndex);
78262
+ return;
78263
+ }
78264
+ slashCommandModal = openModalList({
78265
+ containerId: "slash-command-modal",
78266
+ selectorId: "slash-command-select",
78267
+ title: "Commands",
78268
+ options,
78269
+ focusList: false,
78270
+ selectedIndex: slashCommandSelectedIndex
78271
+ });
78217
78272
  }
78218
78273
  function queueSlashCommandSync() {
78219
78274
  if (slashCommandSyncQueued)
@@ -78226,55 +78281,24 @@ function queueSlashCommandSync() {
78226
78281
  }, 0);
78227
78282
  }
78228
78283
  function showCommandPalette() {
78229
- if (commandPalette) {
78284
+ if (commandPaletteModal) {
78230
78285
  return;
78231
78286
  }
78232
78287
  commandPaletteQuery = "";
78233
- const commands = getCommandPaletteOptions();
78234
- const paletteWidth = 55;
78235
- const termWidth = process.stdout.columns || 80;
78236
- const paletteLeft = Math.max(2, Math.floor((termWidth - paletteWidth) / 2));
78237
- const container = new BoxRenderable(renderer, {
78238
- id: "command-palette-container",
78239
- position: "absolute",
78240
- left: paletteLeft,
78241
- top: 3,
78242
- width: paletteWidth,
78243
- height: Math.min(commands.length + 4, 16),
78244
- backgroundColor: "#1e293b",
78245
- border: true,
78246
- borderColor: "#60a5fa",
78247
- borderStyle: "single",
78288
+ commandPaletteModal = openModalList({
78289
+ containerId: "command-palette-container",
78290
+ selectorId: "command-palette-select",
78248
78291
  title: "Commands",
78249
- titleAlignment: "center",
78250
- zIndex: 200,
78251
- padding: 1
78252
- });
78253
- renderer.root.add(container);
78254
- commandPalette = new SelectRenderable(renderer, {
78255
- id: "command-palette-select",
78256
- width: "100%",
78257
- height: Math.min(commands.length + 2, 12),
78258
78292
  options: getCommandPaletteSelectOptions(),
78259
- backgroundColor: "transparent",
78260
- focusedBackgroundColor: "transparent",
78261
- selectedBackgroundColor: "#334155",
78262
- textColor: "#e2e8f0",
78263
- selectedTextColor: "#60a5fa",
78264
- descriptionColor: "#64748b",
78265
- selectedDescriptionColor: "#94a3b8",
78266
- showDescription: true,
78267
- wrapSelection: true
78268
- });
78269
- container.add(commandPalette);
78270
- commandPalette.on(SelectRenderableEvents.ITEM_SELECTED, async (_2, option) => {
78271
- if (!option.value)
78272
- return;
78273
- const cmd = option.value;
78274
- closeCommandPalette();
78275
- await cmd.action();
78293
+ focusList: true,
78294
+ onSelect: async (_2, option) => {
78295
+ if (!option.value)
78296
+ return;
78297
+ const cmd = option.value;
78298
+ closeCommandPalette();
78299
+ await cmd.action();
78300
+ }
78276
78301
  });
78277
- commandPalette.focus();
78278
78302
  }
78279
78303
  function getCommandPaletteSelectOptions() {
78280
78304
  const query = commandPaletteQuery.toLowerCase();
@@ -78297,30 +78321,28 @@ function getCommandPaletteSelectOptions() {
78297
78321
  }));
78298
78322
  }
78299
78323
  function updateCommandPaletteOptions() {
78300
- if (!commandPalette)
78324
+ if (!commandPaletteModal)
78301
78325
  return;
78302
- commandPalette.options = getCommandPaletteSelectOptions();
78303
- commandPalette.setSelectedIndex(0);
78326
+ commandPaletteModal.updateOptions(getCommandPaletteSelectOptions(), 0);
78304
78327
  }
78305
78328
  function closeCommandPalette() {
78306
- if (commandPalette) {
78307
- renderer.root.remove("command-palette-container");
78308
- commandPalette = null;
78329
+ if (commandPaletteModal) {
78330
+ commandPaletteModal.close();
78331
+ commandPaletteModal = null;
78309
78332
  commandPaletteQuery = "";
78310
- inputField?.focus();
78311
78333
  }
78312
78334
  }
78313
78335
  function handleKeypress(key) {
78314
78336
  const commands = getCommandPaletteOptions();
78315
- if (slashCommandMatches.length > 0) {
78337
+ if (slashCommandModal && slashCommandMatches.length > 0) {
78316
78338
  if (key.name === "up") {
78317
78339
  slashCommandSelectedIndex = slashCommandSelectedIndex === 0 ? slashCommandMatches.length - 1 : slashCommandSelectedIndex - 1;
78318
- updateSlashCommandMenuOptions();
78340
+ updateSlashCommandModalOptions();
78319
78341
  return;
78320
78342
  }
78321
78343
  if (key.name === "down") {
78322
78344
  slashCommandSelectedIndex = (slashCommandSelectedIndex + 1) % slashCommandMatches.length;
78323
- updateSlashCommandMenuOptions();
78345
+ updateSlashCommandModalOptions();
78324
78346
  return;
78325
78347
  }
78326
78348
  if (key.name === "tab") {
@@ -78329,6 +78351,10 @@ function handleKeypress(key) {
78329
78351
  inputField.focus();
78330
78352
  return;
78331
78353
  }
78354
+ if (key.name === "return" && !key.shift && !key.ctrl && !key.meta) {
78355
+ executeSelectedSlashCommand();
78356
+ return;
78357
+ }
78332
78358
  }
78333
78359
  if (key.ctrl && key.name === "p") {
78334
78360
  showCommandPalette();
@@ -78356,7 +78382,7 @@ function handleKeypress(key) {
78356
78382
  }
78357
78383
  return;
78358
78384
  }
78359
- if (commandPalette) {
78385
+ if (commandPaletteModal) {
78360
78386
  if (key.name === "backspace" || key.name === "delete") {
78361
78387
  commandPaletteQuery = commandPaletteQuery.slice(0, -1);
78362
78388
  updateCommandPaletteOptions();
@@ -78370,7 +78396,7 @@ function handleKeypress(key) {
78370
78396
  }
78371
78397
  }
78372
78398
  if (key.ctrl && key.name === "c") {
78373
- if (commandPalette) {
78399
+ if (commandPaletteModal) {
78374
78400
  closeCommandPalette();
78375
78401
  return;
78376
78402
  }
@@ -78401,7 +78427,7 @@ function handleKeypress(key) {
78401
78427
  }
78402
78428
  if (key.name === "escape") {
78403
78429
  chordMode = "none";
78404
- if (commandPalette) {
78430
+ if (commandPaletteModal) {
78405
78431
  closeCommandPalette();
78406
78432
  return;
78407
78433
  }
@@ -78448,7 +78474,7 @@ function handleKeypress(key) {
78448
78474
  addSystemMessage(`Copied to clipboard: ${msg.command}`);
78449
78475
  }
78450
78476
  }
78451
- if (key.name === "o" && !awaitingConfirmation && !commandPalette && !modelSelector) {
78477
+ if (key.name === "o" && !awaitingConfirmation && !commandPaletteModal && !modelSelector) {
78452
78478
  toggleLastResultExpand();
78453
78479
  }
78454
78480
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@austinthesing/magic-shell",
3
- "version": "0.2.28",
3
+ "version": "0.2.29",
4
4
  "description": "Natural language to terminal commands with safety features. Supports OpenCode Zen, OpenRouter, AI gateways, Workers AI, and custom models.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",