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