@austinthesing/magic-shell 0.2.8 → 0.2.9

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 +56 -32
  2. package/dist/tui.js +56 -32
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -22914,13 +22914,13 @@ function getStatusBarContent() {
22914
22914
  function getHelpBarContent() {
22915
22915
  const theme = getTheme();
22916
22916
  if (awaitingConfirmation) {
22917
- return t`${fg(theme.colors.warning)(">>> Press Enter to execute command <<<")} ${fg(theme.colors.textMuted)("|")} ${fg(theme.colors.error)("Esc")}${fg(theme.colors.textMuted)(" Cancel")} ${fg(theme.colors.primary)("e")}${fg(theme.colors.textMuted)(" Edit")} ${fg(theme.colors.primary)("c")}${fg(theme.colors.textMuted)(" Copy")}`;
22917
+ return t`${fg(theme.colors.warning)(">>> Cmd+Enter or Enter to execute <<<")} ${fg(theme.colors.textMuted)("|")} ${fg(theme.colors.error)("Esc")}${fg(theme.colors.textMuted)(" Cancel")} ${fg(theme.colors.primary)("e")}${fg(theme.colors.textMuted)(" Edit")} ${fg(theme.colors.primary)("c")}${fg(theme.colors.textMuted)(" Copy")}`;
22918
22918
  }
22919
22919
  return t`${fg(theme.colors.primary)("Ctrl+X P")}${fg(theme.colors.textMuted)(" Commands")} ${fg(theme.colors.primary)("Ctrl+Y")}${fg(theme.colors.textMuted)(" Safety")} ${fg(theme.colors.primary)("Ctrl+Z")}${fg(theme.colors.textMuted)(" Exit")}`;
22920
22920
  }
22921
22921
  function getInputHintContent() {
22922
22922
  const theme = getTheme();
22923
- return t`${fg(theme.colors.textMuted)("Enter")}${fg(theme.colors.border)(" send")} ${fg(theme.colors.textMuted)("Shift+Enter")}${fg(theme.colors.border)(" newline")} ${fg(theme.colors.textMuted)("!")}${fg(theme.colors.border)(" shell")}`;
22923
+ return t`${fg(theme.colors.textMuted)("Enter")}${fg(theme.colors.border)(" send")} ${fg(theme.colors.textMuted)("Shift+Enter")}${fg(theme.colors.border)(" newline")}`;
22924
22924
  }
22925
22925
  function getWelcomeMessage() {
22926
22926
  const providerName = config.provider === "opencode-zen" ? "OpenCode Zen" : "OpenRouter";
@@ -22965,13 +22965,15 @@ function addAssistantMessage(content, command, safety) {
22965
22965
  renderMessage(msg);
22966
22966
  return msg;
22967
22967
  }
22968
- function addResultMessage(content, exitCode) {
22968
+ function addResultMessage(content, exitCode, executionKind, parentMessageId) {
22969
22969
  const msg = {
22970
22970
  id: generateMessageId(),
22971
22971
  type: "result",
22972
22972
  content,
22973
22973
  timestamp: Date.now(),
22974
- exitCode
22974
+ exitCode,
22975
+ executionKind,
22976
+ parentMessageId
22975
22977
  };
22976
22978
  chatMessages.push(msg);
22977
22979
  renderMessage(msg);
@@ -23016,7 +23018,7 @@ function createAssistantMessageRenderable(msg, theme) {
23016
23018
  width: "100%",
23017
23019
  border: true,
23018
23020
  borderColor: isSelected ? theme.colors.primary : theme.colors.border,
23019
- borderStyle: "single",
23021
+ borderStyle: "rounded",
23020
23022
  paddingLeft: 1,
23021
23023
  paddingRight: 1,
23022
23024
  paddingTop: 0,
@@ -23025,34 +23027,32 @@ function createAssistantMessageRenderable(msg, theme) {
23025
23027
  });
23026
23028
  const commandText = new TextRenderable(renderer, {
23027
23029
  id: `msg-${msg.id}-cmd`,
23028
- content: t`${fg(theme.colors.textMuted)("Command:")} ${fg(theme.colors.text)(msg.command || "")}`
23030
+ content: t`${fg(theme.colors.textMuted)("Command:")} ${fg(theme.colors.secondary)(msg.command || "")}`
23029
23031
  });
23030
23032
  card.add(commandText);
23031
23033
  if (msg.safety) {
23032
23034
  const severityColor = getSeverityColor(msg.safety.severity);
23033
- const severityText = msg.safety.isDangerous ? `${msg.safety.severity.toUpperCase()} risk${msg.safety.reason ? ` - ${msg.safety.reason}` : ""}` : "Low risk";
23035
+ const severityLabel = msg.safety.severity === "low" ? "Low risk" : `${msg.safety.severity[0].toUpperCase()}${msg.safety.severity.slice(1)} risk`;
23034
23036
  const safetyText = new TextRenderable(renderer, {
23035
23037
  id: `msg-${msg.id}-safety`,
23036
- content: t`${fg(severityColor)("●")} ${fg(theme.colors.textMuted)(severityText)}`
23038
+ content: t`${fg(severityColor)(severityLabel)}`
23037
23039
  });
23038
23040
  card.add(safetyText);
23041
+ if (msg.safety.isDangerous && msg.safety.reason) {
23042
+ const reasonText = new TextRenderable(renderer, {
23043
+ id: `msg-${msg.id}-safety-reason`,
23044
+ content: t`${fg(theme.colors.textMuted)(msg.safety.reason)}`
23045
+ });
23046
+ card.add(reasonText);
23047
+ }
23039
23048
  }
23040
23049
  if (isSelected && !msg.executed) {
23041
23050
  const actionsText = new TextRenderable(renderer, {
23042
23051
  id: `msg-${msg.id}-actions`,
23043
- content: t`${fg(theme.colors.warning)("Press Enter to run")} ${fg(theme.colors.textMuted)("|")} ${fg(theme.colors.primary)("[c]")} ${fg(theme.colors.textMuted)("Copy")} ${fg(theme.colors.primary)("[e]")} ${fg(theme.colors.textMuted)("Edit")} ${fg(theme.colors.error)("[Esc]")} ${fg(theme.colors.textMuted)("Cancel")}`
23052
+ content: t`${fg(theme.colors.warning)("Cmd+Enter or Enter to run")} ${fg(theme.colors.textMuted)("|")} ${fg(theme.colors.primary)("[c]")} ${fg(theme.colors.textMuted)("Copy")} ${fg(theme.colors.primary)("[e]")} ${fg(theme.colors.textMuted)("Edit")} ${fg(theme.colors.error)("[Esc]")} ${fg(theme.colors.textMuted)("Cancel")}`
23044
23053
  });
23045
23054
  card.add(actionsText);
23046
23055
  }
23047
- if (msg.executed) {
23048
- const wasAutoRun = !msg.safety?.isDangerous;
23049
- const execLabel = wasAutoRun ? "Auto-executed (safe)" : "Executed";
23050
- const execText = new TextRenderable(renderer, {
23051
- id: `msg-${msg.id}-exec`,
23052
- content: t`${fg(theme.colors.success)("✓")} ${fg(theme.colors.success)(execLabel)}`
23053
- });
23054
- card.add(execText);
23055
- }
23056
23056
  return card;
23057
23057
  }
23058
23058
  function createResultMessageRenderable(msg, theme) {
@@ -23063,28 +23063,30 @@ function createResultMessageRenderable(msg, theme) {
23063
23063
  `) : [];
23064
23064
  const isLongOutput = outputLines.length > 5;
23065
23065
  const PREVIEW_LINES = 3;
23066
+ const executionKind = msg.executionKind || "manual";
23066
23067
  const card = new BoxRenderable(renderer, {
23067
23068
  id: `msg-${msg.id}`,
23068
23069
  flexDirection: "column",
23069
23070
  width: "100%",
23070
23071
  border: true,
23071
- borderColor: isSuccess ? theme.colors.success : theme.colors.error,
23072
- borderStyle: "single",
23072
+ borderColor: theme.colors.border,
23073
+ borderStyle: "rounded",
23073
23074
  paddingLeft: 1,
23074
23075
  paddingRight: 1,
23076
+ paddingTop: 0,
23077
+ paddingBottom: 0,
23075
23078
  backgroundColor: theme.colors.backgroundPanel,
23076
23079
  onMouseDown: isLongOutput ? () => {
23077
23080
  toggleResultExpand(msg.id);
23078
23081
  } : undefined
23079
23082
  });
23080
- const statusIcon = isSuccess ? "✓" : "✗";
23081
23083
  const statusColor = isSuccess ? theme.colors.success : theme.colors.error;
23082
- const statusLabel = isSuccess ? "Executed successfully" : `Exit code: ${msg.exitCode}`;
23084
+ const statusLabel = isSuccess ? executionKind === "auto" ? "Auto-executed (safe command)" : executionKind === "dry-run" ? "Dry run (not executed)" : "Executed (confirmed)" : `Command failed (exit code: ${msg.exitCode})`;
23083
23085
  const expandIcon = isLongOutput ? isExpanded ? "▼" : "▶" : "";
23084
23086
  const lineCount = isLongOutput ? ` (${outputLines.length} lines)` : "";
23085
23087
  const statusText = new TextRenderable(renderer, {
23086
23088
  id: `msg-${msg.id}-status`,
23087
- content: t`${fg(statusColor)(statusIcon)} ${fg(theme.colors.text)(statusLabel)}${fg(theme.colors.textMuted)(lineCount)} ${fg(theme.colors.primary)(expandIcon)}`
23089
+ content: t`${fg(statusColor)(">")} ${fg(statusColor)(statusLabel)}${fg(theme.colors.textMuted)(lineCount)} ${fg(theme.colors.primary)(expandIcon)}`
23088
23090
  });
23089
23091
  card.add(statusText);
23090
23092
  if (hasOutput) {
@@ -23097,11 +23099,26 @@ function createResultMessageRenderable(msg, theme) {
23097
23099
  `) + `
23098
23100
  ... ${outputLines.length - PREVIEW_LINES} more lines`;
23099
23101
  }
23102
+ const outputBox = new BoxRenderable(renderer, {
23103
+ id: `msg-${msg.id}-output-box`,
23104
+ flexDirection: "column",
23105
+ width: "100%",
23106
+ border: true,
23107
+ borderColor: theme.colors.borderSubtle,
23108
+ borderStyle: "single",
23109
+ paddingLeft: 1,
23110
+ paddingRight: 1,
23111
+ paddingTop: 0,
23112
+ paddingBottom: 0,
23113
+ backgroundColor: theme.colors.backgroundElement,
23114
+ marginTop: 1
23115
+ });
23100
23116
  const outputText = new TextRenderable(renderer, {
23101
23117
  id: `msg-${msg.id}-output`,
23102
23118
  content: t`${fg(theme.colors.textMuted)(displayContent)}`
23103
23119
  });
23104
- card.add(outputText);
23120
+ outputBox.add(outputText);
23121
+ card.add(outputBox);
23105
23122
  if (isLongOutput) {
23106
23123
  const hintText = new TextRenderable(renderer, {
23107
23124
  id: `msg-${msg.id}-hint`,
@@ -23275,6 +23292,8 @@ async function processDirectCommand(input, command) {
23275
23292
  }
23276
23293
  }
23277
23294
  async function executeAndShowResult(input, command, assistantMsgId) {
23295
+ const executionKind = getExecutionKind(assistantMsgId, dryRunMode);
23296
+ updateAssistantMessage(assistantMsgId, { executed: true });
23278
23297
  if (command.startsWith("cd ")) {
23279
23298
  const path2 = command.slice(3).trim().replace(/^["']|["']$/g, "");
23280
23299
  try {
@@ -23282,7 +23301,7 @@ async function executeAndShowResult(input, command, assistantMsgId) {
23282
23301
  process.chdir(expandedPath);
23283
23302
  currentCwd = getCwd();
23284
23303
  statusBarText.content = getStatusBarContent();
23285
- addResultMessage(`Changed directory to ${currentCwd}`, 0);
23304
+ addResultMessage(`Changed directory to ${currentCwd}`, 0, executionKind, assistantMsgId);
23286
23305
  addToHistory({
23287
23306
  input,
23288
23307
  command,
@@ -23290,22 +23309,20 @@ async function executeAndShowResult(input, command, assistantMsgId) {
23290
23309
  timestamp: Date.now()
23291
23310
  });
23292
23311
  history = loadHistory();
23293
- updateAssistantMessage(assistantMsgId, { executed: true });
23294
23312
  } catch (err) {
23295
- addResultMessage(`cd: ${err instanceof Error ? err.message : String(err)}`, 1);
23313
+ addResultMessage(`cd: ${err instanceof Error ? err.message : String(err)}`, 1, executionKind, assistantMsgId);
23296
23314
  }
23297
23315
  clearCommandState();
23298
23316
  return;
23299
23317
  }
23300
23318
  if (dryRunMode) {
23301
- addResultMessage(`[DRY RUN] Would execute: ${command}`, 0);
23302
- updateAssistantMessage(assistantMsgId, { executed: true });
23319
+ addResultMessage(`[DRY RUN] Would execute: ${command}`, 0, executionKind, assistantMsgId);
23303
23320
  clearCommandState();
23304
23321
  return;
23305
23322
  }
23306
23323
  try {
23307
23324
  const { output, exitCode } = await executeCommandWithCode(command);
23308
- addResultMessage(output || "Command completed successfully", exitCode);
23325
+ addResultMessage(output || "Command completed successfully", exitCode, executionKind, assistantMsgId);
23309
23326
  addToHistory({
23310
23327
  input,
23311
23328
  command,
@@ -23313,13 +23330,20 @@ async function executeAndShowResult(input, command, assistantMsgId) {
23313
23330
  timestamp: Date.now()
23314
23331
  });
23315
23332
  history = loadHistory();
23316
- updateAssistantMessage(assistantMsgId, { executed: true });
23317
23333
  } catch (error) {
23318
23334
  const message = error instanceof Error ? error.message : String(error);
23319
- addResultMessage(`Error: ${message}`, 1);
23335
+ addResultMessage(`Error: ${message}`, 1, executionKind, assistantMsgId);
23320
23336
  }
23321
23337
  clearCommandState();
23322
23338
  }
23339
+ function getExecutionKind(assistantMsgId, isDryRun) {
23340
+ if (isDryRun)
23341
+ return "dry-run";
23342
+ const assistantMsg = chatMessages.find((msg) => msg.id === assistantMsgId);
23343
+ if (!assistantMsg || assistantMsg.type !== "assistant")
23344
+ return "manual";
23345
+ return assistantMsg.safety?.isDangerous ? "manual" : "auto";
23346
+ }
23323
23347
  function executeCommandWithCode(command) {
23324
23348
  return new Promise((resolve3, reject) => {
23325
23349
  const child = spawn(command, {
package/dist/tui.js CHANGED
@@ -22914,13 +22914,13 @@ function getStatusBarContent() {
22914
22914
  function getHelpBarContent() {
22915
22915
  const theme = getTheme();
22916
22916
  if (awaitingConfirmation) {
22917
- return t`${fg(theme.colors.warning)(">>> Press Enter to execute command <<<")} ${fg(theme.colors.textMuted)("|")} ${fg(theme.colors.error)("Esc")}${fg(theme.colors.textMuted)(" Cancel")} ${fg(theme.colors.primary)("e")}${fg(theme.colors.textMuted)(" Edit")} ${fg(theme.colors.primary)("c")}${fg(theme.colors.textMuted)(" Copy")}`;
22917
+ return t`${fg(theme.colors.warning)(">>> Cmd+Enter or Enter to execute <<<")} ${fg(theme.colors.textMuted)("|")} ${fg(theme.colors.error)("Esc")}${fg(theme.colors.textMuted)(" Cancel")} ${fg(theme.colors.primary)("e")}${fg(theme.colors.textMuted)(" Edit")} ${fg(theme.colors.primary)("c")}${fg(theme.colors.textMuted)(" Copy")}`;
22918
22918
  }
22919
22919
  return t`${fg(theme.colors.primary)("Ctrl+X P")}${fg(theme.colors.textMuted)(" Commands")} ${fg(theme.colors.primary)("Ctrl+Y")}${fg(theme.colors.textMuted)(" Safety")} ${fg(theme.colors.primary)("Ctrl+Z")}${fg(theme.colors.textMuted)(" Exit")}`;
22920
22920
  }
22921
22921
  function getInputHintContent() {
22922
22922
  const theme = getTheme();
22923
- return t`${fg(theme.colors.textMuted)("Enter")}${fg(theme.colors.border)(" send")} ${fg(theme.colors.textMuted)("Shift+Enter")}${fg(theme.colors.border)(" newline")} ${fg(theme.colors.textMuted)("!")}${fg(theme.colors.border)(" shell")}`;
22923
+ return t`${fg(theme.colors.textMuted)("Enter")}${fg(theme.colors.border)(" send")} ${fg(theme.colors.textMuted)("Shift+Enter")}${fg(theme.colors.border)(" newline")}`;
22924
22924
  }
22925
22925
  function getWelcomeMessage() {
22926
22926
  const providerName = config.provider === "opencode-zen" ? "OpenCode Zen" : "OpenRouter";
@@ -22965,13 +22965,15 @@ function addAssistantMessage(content, command, safety) {
22965
22965
  renderMessage(msg);
22966
22966
  return msg;
22967
22967
  }
22968
- function addResultMessage(content, exitCode) {
22968
+ function addResultMessage(content, exitCode, executionKind, parentMessageId) {
22969
22969
  const msg = {
22970
22970
  id: generateMessageId(),
22971
22971
  type: "result",
22972
22972
  content,
22973
22973
  timestamp: Date.now(),
22974
- exitCode
22974
+ exitCode,
22975
+ executionKind,
22976
+ parentMessageId
22975
22977
  };
22976
22978
  chatMessages.push(msg);
22977
22979
  renderMessage(msg);
@@ -23016,7 +23018,7 @@ function createAssistantMessageRenderable(msg, theme) {
23016
23018
  width: "100%",
23017
23019
  border: true,
23018
23020
  borderColor: isSelected ? theme.colors.primary : theme.colors.border,
23019
- borderStyle: "single",
23021
+ borderStyle: "rounded",
23020
23022
  paddingLeft: 1,
23021
23023
  paddingRight: 1,
23022
23024
  paddingTop: 0,
@@ -23025,34 +23027,32 @@ function createAssistantMessageRenderable(msg, theme) {
23025
23027
  });
23026
23028
  const commandText = new TextRenderable(renderer, {
23027
23029
  id: `msg-${msg.id}-cmd`,
23028
- content: t`${fg(theme.colors.textMuted)("Command:")} ${fg(theme.colors.text)(msg.command || "")}`
23030
+ content: t`${fg(theme.colors.textMuted)("Command:")} ${fg(theme.colors.secondary)(msg.command || "")}`
23029
23031
  });
23030
23032
  card.add(commandText);
23031
23033
  if (msg.safety) {
23032
23034
  const severityColor = getSeverityColor(msg.safety.severity);
23033
- const severityText = msg.safety.isDangerous ? `${msg.safety.severity.toUpperCase()} risk${msg.safety.reason ? ` - ${msg.safety.reason}` : ""}` : "Low risk";
23035
+ const severityLabel = msg.safety.severity === "low" ? "Low risk" : `${msg.safety.severity[0].toUpperCase()}${msg.safety.severity.slice(1)} risk`;
23034
23036
  const safetyText = new TextRenderable(renderer, {
23035
23037
  id: `msg-${msg.id}-safety`,
23036
- content: t`${fg(severityColor)("●")} ${fg(theme.colors.textMuted)(severityText)}`
23038
+ content: t`${fg(severityColor)(severityLabel)}`
23037
23039
  });
23038
23040
  card.add(safetyText);
23041
+ if (msg.safety.isDangerous && msg.safety.reason) {
23042
+ const reasonText = new TextRenderable(renderer, {
23043
+ id: `msg-${msg.id}-safety-reason`,
23044
+ content: t`${fg(theme.colors.textMuted)(msg.safety.reason)}`
23045
+ });
23046
+ card.add(reasonText);
23047
+ }
23039
23048
  }
23040
23049
  if (isSelected && !msg.executed) {
23041
23050
  const actionsText = new TextRenderable(renderer, {
23042
23051
  id: `msg-${msg.id}-actions`,
23043
- content: t`${fg(theme.colors.warning)("Press Enter to run")} ${fg(theme.colors.textMuted)("|")} ${fg(theme.colors.primary)("[c]")} ${fg(theme.colors.textMuted)("Copy")} ${fg(theme.colors.primary)("[e]")} ${fg(theme.colors.textMuted)("Edit")} ${fg(theme.colors.error)("[Esc]")} ${fg(theme.colors.textMuted)("Cancel")}`
23052
+ content: t`${fg(theme.colors.warning)("Cmd+Enter or Enter to run")} ${fg(theme.colors.textMuted)("|")} ${fg(theme.colors.primary)("[c]")} ${fg(theme.colors.textMuted)("Copy")} ${fg(theme.colors.primary)("[e]")} ${fg(theme.colors.textMuted)("Edit")} ${fg(theme.colors.error)("[Esc]")} ${fg(theme.colors.textMuted)("Cancel")}`
23044
23053
  });
23045
23054
  card.add(actionsText);
23046
23055
  }
23047
- if (msg.executed) {
23048
- const wasAutoRun = !msg.safety?.isDangerous;
23049
- const execLabel = wasAutoRun ? "Auto-executed (safe)" : "Executed";
23050
- const execText = new TextRenderable(renderer, {
23051
- id: `msg-${msg.id}-exec`,
23052
- content: t`${fg(theme.colors.success)("✓")} ${fg(theme.colors.success)(execLabel)}`
23053
- });
23054
- card.add(execText);
23055
- }
23056
23056
  return card;
23057
23057
  }
23058
23058
  function createResultMessageRenderable(msg, theme) {
@@ -23063,28 +23063,30 @@ function createResultMessageRenderable(msg, theme) {
23063
23063
  `) : [];
23064
23064
  const isLongOutput = outputLines.length > 5;
23065
23065
  const PREVIEW_LINES = 3;
23066
+ const executionKind = msg.executionKind || "manual";
23066
23067
  const card = new BoxRenderable(renderer, {
23067
23068
  id: `msg-${msg.id}`,
23068
23069
  flexDirection: "column",
23069
23070
  width: "100%",
23070
23071
  border: true,
23071
- borderColor: isSuccess ? theme.colors.success : theme.colors.error,
23072
- borderStyle: "single",
23072
+ borderColor: theme.colors.border,
23073
+ borderStyle: "rounded",
23073
23074
  paddingLeft: 1,
23074
23075
  paddingRight: 1,
23076
+ paddingTop: 0,
23077
+ paddingBottom: 0,
23075
23078
  backgroundColor: theme.colors.backgroundPanel,
23076
23079
  onMouseDown: isLongOutput ? () => {
23077
23080
  toggleResultExpand(msg.id);
23078
23081
  } : undefined
23079
23082
  });
23080
- const statusIcon = isSuccess ? "✓" : "✗";
23081
23083
  const statusColor = isSuccess ? theme.colors.success : theme.colors.error;
23082
- const statusLabel = isSuccess ? "Executed successfully" : `Exit code: ${msg.exitCode}`;
23084
+ const statusLabel = isSuccess ? executionKind === "auto" ? "Auto-executed (safe command)" : executionKind === "dry-run" ? "Dry run (not executed)" : "Executed (confirmed)" : `Command failed (exit code: ${msg.exitCode})`;
23083
23085
  const expandIcon = isLongOutput ? isExpanded ? "▼" : "▶" : "";
23084
23086
  const lineCount = isLongOutput ? ` (${outputLines.length} lines)` : "";
23085
23087
  const statusText = new TextRenderable(renderer, {
23086
23088
  id: `msg-${msg.id}-status`,
23087
- content: t`${fg(statusColor)(statusIcon)} ${fg(theme.colors.text)(statusLabel)}${fg(theme.colors.textMuted)(lineCount)} ${fg(theme.colors.primary)(expandIcon)}`
23089
+ content: t`${fg(statusColor)(">")} ${fg(statusColor)(statusLabel)}${fg(theme.colors.textMuted)(lineCount)} ${fg(theme.colors.primary)(expandIcon)}`
23088
23090
  });
23089
23091
  card.add(statusText);
23090
23092
  if (hasOutput) {
@@ -23097,11 +23099,26 @@ function createResultMessageRenderable(msg, theme) {
23097
23099
  `) + `
23098
23100
  ... ${outputLines.length - PREVIEW_LINES} more lines`;
23099
23101
  }
23102
+ const outputBox = new BoxRenderable(renderer, {
23103
+ id: `msg-${msg.id}-output-box`,
23104
+ flexDirection: "column",
23105
+ width: "100%",
23106
+ border: true,
23107
+ borderColor: theme.colors.borderSubtle,
23108
+ borderStyle: "single",
23109
+ paddingLeft: 1,
23110
+ paddingRight: 1,
23111
+ paddingTop: 0,
23112
+ paddingBottom: 0,
23113
+ backgroundColor: theme.colors.backgroundElement,
23114
+ marginTop: 1
23115
+ });
23100
23116
  const outputText = new TextRenderable(renderer, {
23101
23117
  id: `msg-${msg.id}-output`,
23102
23118
  content: t`${fg(theme.colors.textMuted)(displayContent)}`
23103
23119
  });
23104
- card.add(outputText);
23120
+ outputBox.add(outputText);
23121
+ card.add(outputBox);
23105
23122
  if (isLongOutput) {
23106
23123
  const hintText = new TextRenderable(renderer, {
23107
23124
  id: `msg-${msg.id}-hint`,
@@ -23275,6 +23292,8 @@ async function processDirectCommand(input, command) {
23275
23292
  }
23276
23293
  }
23277
23294
  async function executeAndShowResult(input, command, assistantMsgId) {
23295
+ const executionKind = getExecutionKind(assistantMsgId, dryRunMode);
23296
+ updateAssistantMessage(assistantMsgId, { executed: true });
23278
23297
  if (command.startsWith("cd ")) {
23279
23298
  const path2 = command.slice(3).trim().replace(/^["']|["']$/g, "");
23280
23299
  try {
@@ -23282,7 +23301,7 @@ async function executeAndShowResult(input, command, assistantMsgId) {
23282
23301
  process.chdir(expandedPath);
23283
23302
  currentCwd = getCwd();
23284
23303
  statusBarText.content = getStatusBarContent();
23285
- addResultMessage(`Changed directory to ${currentCwd}`, 0);
23304
+ addResultMessage(`Changed directory to ${currentCwd}`, 0, executionKind, assistantMsgId);
23286
23305
  addToHistory({
23287
23306
  input,
23288
23307
  command,
@@ -23290,22 +23309,20 @@ async function executeAndShowResult(input, command, assistantMsgId) {
23290
23309
  timestamp: Date.now()
23291
23310
  });
23292
23311
  history = loadHistory();
23293
- updateAssistantMessage(assistantMsgId, { executed: true });
23294
23312
  } catch (err) {
23295
- addResultMessage(`cd: ${err instanceof Error ? err.message : String(err)}`, 1);
23313
+ addResultMessage(`cd: ${err instanceof Error ? err.message : String(err)}`, 1, executionKind, assistantMsgId);
23296
23314
  }
23297
23315
  clearCommandState();
23298
23316
  return;
23299
23317
  }
23300
23318
  if (dryRunMode) {
23301
- addResultMessage(`[DRY RUN] Would execute: ${command}`, 0);
23302
- updateAssistantMessage(assistantMsgId, { executed: true });
23319
+ addResultMessage(`[DRY RUN] Would execute: ${command}`, 0, executionKind, assistantMsgId);
23303
23320
  clearCommandState();
23304
23321
  return;
23305
23322
  }
23306
23323
  try {
23307
23324
  const { output, exitCode } = await executeCommandWithCode(command);
23308
- addResultMessage(output || "Command completed successfully", exitCode);
23325
+ addResultMessage(output || "Command completed successfully", exitCode, executionKind, assistantMsgId);
23309
23326
  addToHistory({
23310
23327
  input,
23311
23328
  command,
@@ -23313,13 +23330,20 @@ async function executeAndShowResult(input, command, assistantMsgId) {
23313
23330
  timestamp: Date.now()
23314
23331
  });
23315
23332
  history = loadHistory();
23316
- updateAssistantMessage(assistantMsgId, { executed: true });
23317
23333
  } catch (error) {
23318
23334
  const message = error instanceof Error ? error.message : String(error);
23319
- addResultMessage(`Error: ${message}`, 1);
23335
+ addResultMessage(`Error: ${message}`, 1, executionKind, assistantMsgId);
23320
23336
  }
23321
23337
  clearCommandState();
23322
23338
  }
23339
+ function getExecutionKind(assistantMsgId, isDryRun) {
23340
+ if (isDryRun)
23341
+ return "dry-run";
23342
+ const assistantMsg = chatMessages.find((msg) => msg.id === assistantMsgId);
23343
+ if (!assistantMsg || assistantMsg.type !== "assistant")
23344
+ return "manual";
23345
+ return assistantMsg.safety?.isDangerous ? "manual" : "auto";
23346
+ }
23323
23347
  function executeCommandWithCode(command) {
23324
23348
  return new Promise((resolve3, reject) => {
23325
23349
  const child = spawn(command, {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@austinthesing/magic-shell",
3
- "version": "0.2.8",
3
+ "version": "0.2.9",
4
4
  "description": "Natural language to terminal commands with safety features. Supports OpenCode Zen (with free models) and OpenRouter.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",