diff --git a/.changeset/shell-syntax-highlighting.md b/.changeset/shell-syntax-highlighting.md
new file mode 100644
index 00000000000..038f51dd685
--- /dev/null
+++ b/.changeset/shell-syntax-highlighting.md
@@ -0,0 +1,5 @@
+---
+"kilo-code": minor
+---
+
+Add syntax highlighting to shell command output with Shiki, labeled "Command" and "Output" sections, per-section copy buttons, and an "Open in Editor" action that opens the full untruncated output in a VS Code editor tab.
diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/message-list-tool-to-queued-user-spacing-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/message-list-tool-to-queued-user-spacing-chromium-linux.png
index ff195b4d918..edc40570888 100644
--- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/message-list-tool-to-queued-user-spacing-chromium-linux.png
+++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/chat/message-list-tool-to-queued-user-spacing-chromium-linux.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:c3f37193389ad7937c7b2103ad2fe3dd63123a0d4f60a0fbfd65b31d3982c092
-size 12105
+oid sha256:dbaab3a1ff10eac8f710b0ed8ddc99d96188c06a09c227e634ca712bcee12130
+size 11543
diff --git a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/components-shell/shell-execution-chromium-linux.png b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/components-shell/shell-execution-chromium-linux.png
index 4d612a7ad03..ddcba78b314 100644
--- a/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/components-shell/shell-execution-chromium-linux.png
+++ b/packages/kilo-docs/public/img/screenshot-tests/kilo-vscode/visual-regression/components-shell/shell-execution-chromium-linux.png
@@ -1,3 +1,3 @@
version https://git-lfs.github.com/spec/v1
-oid sha256:74a42ec77a8ac8d5a1c555b46e3d550c9acf3198f45cc87da6582c0ff924d5f9
-size 17677
+oid sha256:7cabfff215cef485ec913b9a082aaac844275e506e88ba0fab112d95ff6de329
+size 18200
diff --git a/packages/kilo-i18n/src/ar.ts b/packages/kilo-i18n/src/ar.ts
index 7dd1f9304fa..d7a778caa65 100644
--- a/packages/kilo-i18n/src/ar.ts
+++ b/packages/kilo-i18n/src/ar.ts
@@ -91,7 +91,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"أوقف لقطات Kilo لهذا المشروع. ستفقد ميزة التراجع/الإعادة لتعديلات Kilo، لكن git سيستمر في تتبع كل شيء.",
+ // Edit-tool header and shell-tool section labels
"ui.messagePart.openInDiffViewer": "فتح في عارض الفروقات",
+ "ui.messagePart.shell.command": "الأمر",
+ "ui.messagePart.shell.output": "المخرجات",
+ "ui.messagePart.openInEditor": "فتح في المحرر",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "كان هذا مفيدًا",
diff --git a/packages/kilo-i18n/src/br.ts b/packages/kilo-i18n/src/br.ts
index e79ef39bf30..bbf53cd2ff3 100644
--- a/packages/kilo-i18n/src/br.ts
+++ b/packages/kilo-i18n/src/br.ts
@@ -91,7 +91,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"Desligue os snapshots do Kilo para este projeto. Você perde desfazer/refazer das mudanças feitas pelo Kilo, mas o git continua rastreando tudo.",
+ // Edit-tool header and shell-tool section labels
"ui.messagePart.openInDiffViewer": "Abrir no Visualizador de Diferenças",
+ "ui.messagePart.shell.command": "Comando",
+ "ui.messagePart.shell.output": "Saída",
+ "ui.messagePart.openInEditor": "Abrir no Editor",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Isso foi útil",
diff --git a/packages/kilo-i18n/src/bs.ts b/packages/kilo-i18n/src/bs.ts
index e23e964bbd5..2e4983260dc 100644
--- a/packages/kilo-i18n/src/bs.ts
+++ b/packages/kilo-i18n/src/bs.ts
@@ -96,7 +96,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"Isključi Kilo snapshotove za ovaj projekat. Izgubićete poništi/vrati za izmjene koje napravi Kilo, ali git i dalje prati sve.",
+ // Edit-tool header and shell-tool section labels
"ui.messagePart.openInDiffViewer": "Otvori u pregledniku razlika",
+ "ui.messagePart.shell.command": "Naredba",
+ "ui.messagePart.shell.output": "Izlaz",
+ "ui.messagePart.openInEditor": "Otvori u editoru",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Ovo je bilo korisno",
diff --git a/packages/kilo-i18n/src/da.ts b/packages/kilo-i18n/src/da.ts
index 2a086970b40..e930733acbe 100644
--- a/packages/kilo-i18n/src/da.ts
+++ b/packages/kilo-i18n/src/da.ts
@@ -91,7 +91,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"Slå Kilos snapshots fra for dette projekt. Du mister fortryd/gentag for Kilo-ændringer, men git sporer stadig alt.",
- "ui.messagePart.openInDiffViewer": "Åbn i diff-viser",
+ // Edit-tool header and shell-tool section labels
+ "ui.messagePart.openInDiffViewer": "Åbn i Diff-visning",
+ "ui.messagePart.shell.command": "Kommando",
+ "ui.messagePart.shell.output": "Output",
+ "ui.messagePart.openInEditor": "Åbn i editor",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Dette var nyttigt",
diff --git a/packages/kilo-i18n/src/de.ts b/packages/kilo-i18n/src/de.ts
index 437f5fc649f..ce73601069b 100644
--- a/packages/kilo-i18n/src/de.ts
+++ b/packages/kilo-i18n/src/de.ts
@@ -91,7 +91,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"Kilo-Snapshots für dieses Projekt ausschalten. Rückgängig/Wiederherstellen für Kilo-Änderungen ist nicht mehr möglich, aber git verfolgt weiterhin alles.",
+ // Edit-tool header and shell-tool section labels
"ui.messagePart.openInDiffViewer": "Im Diff-Viewer öffnen",
+ "ui.messagePart.shell.command": "Befehl",
+ "ui.messagePart.shell.output": "Ausgabe",
+ "ui.messagePart.openInEditor": "Im Editor öffnen",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Das war hilfreich",
diff --git a/packages/kilo-i18n/src/en.ts b/packages/kilo-i18n/src/en.ts
index bd80d92857d..7f908032995 100644
--- a/packages/kilo-i18n/src/en.ts
+++ b/packages/kilo-i18n/src/en.ts
@@ -99,6 +99,10 @@ export const dict = {
// Edit-tool header: hover-revealed action opening the diff in a full tab.
"ui.messagePart.openInDiffViewer": "Open in Diff Viewer",
+ // Shell-tool section labels and actions.
+ "ui.messagePart.shell.command": "Command",
+ "ui.messagePart.shell.output": "Output",
+ "ui.messagePart.openInEditor": "Open in Editor",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "This was helpful",
diff --git a/packages/kilo-i18n/src/es.ts b/packages/kilo-i18n/src/es.ts
index 8b05522cb9f..07af68a1a0f 100644
--- a/packages/kilo-i18n/src/es.ts
+++ b/packages/kilo-i18n/src/es.ts
@@ -91,7 +91,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"Apaga las instantáneas de Kilo para este proyecto. Perderás deshacer/rehacer de los cambios de Kilo, pero git seguirá rastreando todo.",
+ // Edit-tool header and shell-tool section labels
"ui.messagePart.openInDiffViewer": "Abrir en el visor de diferencias",
+ "ui.messagePart.shell.command": "Comando",
+ "ui.messagePart.shell.output": "Salida",
+ "ui.messagePart.openInEditor": "Abrir en el editor",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Esto fue útil",
diff --git a/packages/kilo-i18n/src/fr.ts b/packages/kilo-i18n/src/fr.ts
index b64ace8f1f9..2faf61d345b 100644
--- a/packages/kilo-i18n/src/fr.ts
+++ b/packages/kilo-i18n/src/fr.ts
@@ -91,7 +91,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"Désactivez les instantanés Kilo pour ce projet. Vous perdez l'annulation/restauration des modifications faites par Kilo, mais git continue de tout suivre.",
- "ui.messagePart.openInDiffViewer": "Ouvrir dans la visionneuse de différences",
+ // Edit-tool header and shell-tool section labels
+ "ui.messagePart.openInDiffViewer": "Ouvrir dans le visualiseur de différences",
+ "ui.messagePart.shell.command": "Commande",
+ "ui.messagePart.shell.output": "Sortie",
+ "ui.messagePart.openInEditor": "Ouvrir dans l'éditeur",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "C'était utile",
diff --git a/packages/kilo-i18n/src/ja.ts b/packages/kilo-i18n/src/ja.ts
index 9d5214c7a48..f30eae15557 100644
--- a/packages/kilo-i18n/src/ja.ts
+++ b/packages/kilo-i18n/src/ja.ts
@@ -89,7 +89,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"このプロジェクトでは Kilo のスナップショットを無効にします。Kilo による変更の取り消し/やり直しはできなくなりますが、git は引き続きすべてを追跡します。",
- "ui.messagePart.openInDiffViewer": "差分ビューアで開く",
+ // Edit-tool header and shell-tool section labels
+ "ui.messagePart.openInDiffViewer": "差分ビューアーで開く",
+ "ui.messagePart.shell.command": "コマンド",
+ "ui.messagePart.shell.output": "出力",
+ "ui.messagePart.openInEditor": "エディタで開く",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "役に立ちました",
diff --git a/packages/kilo-i18n/src/ko.ts b/packages/kilo-i18n/src/ko.ts
index 6308cf9fc68..8a9692001fe 100644
--- a/packages/kilo-i18n/src/ko.ts
+++ b/packages/kilo-i18n/src/ko.ts
@@ -89,7 +89,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"이 프로젝트의 Kilo 스냅샷을 끕니다. Kilo 변경에 대한 실행 취소/다시 실행은 사용할 수 없지만 git은 여전히 모든 것을 추적합니다.",
- "ui.messagePart.openInDiffViewer": "Diff 뷰어에서 열기",
+ // Edit-tool header and shell-tool section labels
+ "ui.messagePart.openInDiffViewer": "차이점 뷰어에서 열기",
+ "ui.messagePart.shell.command": "명령어",
+ "ui.messagePart.shell.output": "출력",
+ "ui.messagePart.openInEditor": "편집기에서 열기",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "도움이 됐어요",
diff --git a/packages/kilo-i18n/src/nl.ts b/packages/kilo-i18n/src/nl.ts
index 4fb55eddca5..142c0958286 100644
--- a/packages/kilo-i18n/src/nl.ts
+++ b/packages/kilo-i18n/src/nl.ts
@@ -93,7 +93,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"Zet Kilo-snapshots uit voor dit project. Je verliest ongedaan maken/opnieuw doen van Kilo-wijzigingen, maar git blijft alles volgen.",
- "ui.messagePart.openInDiffViewer": "Openen in diff-viewer",
+ // Edit-tool header and shell-tool section labels
+ "ui.messagePart.openInDiffViewer": "Openen in Diff-weergave",
+ "ui.messagePart.shell.command": "Opdracht",
+ "ui.messagePart.shell.output": "Uitvoer",
+ "ui.messagePart.openInEditor": "Openen in editor",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Dit was nuttig",
diff --git a/packages/kilo-i18n/src/no.ts b/packages/kilo-i18n/src/no.ts
index 915801390af..e7f223b923b 100644
--- a/packages/kilo-i18n/src/no.ts
+++ b/packages/kilo-i18n/src/no.ts
@@ -91,7 +91,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"Slå av Kilos snapshots for dette prosjektet. Du mister angre/gjør om for Kilo-endringer, men git fortsetter å spore alt.",
- "ui.messagePart.openInDiffViewer": "Åpne i diff-viser",
+ // Edit-tool header and shell-tool section labels
+ "ui.messagePart.openInDiffViewer": "Åpne i diff-visning",
+ "ui.messagePart.shell.command": "Kommando",
+ "ui.messagePart.shell.output": "Utdata",
+ "ui.messagePart.openInEditor": "Åpne i editor",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Dette var nyttig",
diff --git a/packages/kilo-i18n/src/pl.ts b/packages/kilo-i18n/src/pl.ts
index 67b83e46c29..8cfd61e3c2b 100644
--- a/packages/kilo-i18n/src/pl.ts
+++ b/packages/kilo-i18n/src/pl.ts
@@ -91,7 +91,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"Wyłącz snapshoty Kilo dla tego projektu. Stracisz cofanie/przywracanie zmian Kilo, ale git nadal śledzi wszystko.",
+ // Edit-tool header and shell-tool section labels
"ui.messagePart.openInDiffViewer": "Otwórz w podglądzie różnic",
+ "ui.messagePart.shell.command": "Polecenie",
+ "ui.messagePart.shell.output": "Wyjście",
+ "ui.messagePart.openInEditor": "Otwórz w edytorze",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "To było pomocne",
diff --git a/packages/kilo-i18n/src/ru.ts b/packages/kilo-i18n/src/ru.ts
index d9cff803db5..2a923436c22 100644
--- a/packages/kilo-i18n/src/ru.ts
+++ b/packages/kilo-i18n/src/ru.ts
@@ -91,7 +91,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"Выключите снимки Kilo для этого проекта. Вы потеряете отмену/повтор изменений Kilo, но git по-прежнему отслеживает всё.",
- "ui.messagePart.openInDiffViewer": "Открыть в просмотрщике различий",
+ // Edit-tool header and shell-tool section labels
+ "ui.messagePart.openInDiffViewer": "Открыть в просмотре различий",
+ "ui.messagePart.shell.command": "Команда",
+ "ui.messagePart.shell.output": "Вывод",
+ "ui.messagePart.openInEditor": "Открыть в редакторе",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Это было полезно",
diff --git a/packages/kilo-i18n/src/th.ts b/packages/kilo-i18n/src/th.ts
index be90eddc10a..ae0c5a4d88c 100644
--- a/packages/kilo-i18n/src/th.ts
+++ b/packages/kilo-i18n/src/th.ts
@@ -91,7 +91,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"ปิดสแน็ปช็อตของ Kilo สำหรับโปรเจกต์นี้ คุณจะสูญเสียการยกเลิก/ทำซ้ำสำหรับการเปลี่ยนแปลงของ Kilo แต่ git ยังคงติดตามทุกอย่าง",
+ // Edit-tool header and shell-tool section labels
"ui.messagePart.openInDiffViewer": "เปิดในตัวดูความแตกต่าง",
+ "ui.messagePart.shell.command": "คำสั่ง",
+ "ui.messagePart.shell.output": "ผลลัพธ์",
+ "ui.messagePart.openInEditor": "เปิดในตัวแก้ไข",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "สิ่งนี้มีประโยชน์",
diff --git a/packages/kilo-i18n/src/tr.ts b/packages/kilo-i18n/src/tr.ts
index 0ebf2a73f24..6297ed3295a 100644
--- a/packages/kilo-i18n/src/tr.ts
+++ b/packages/kilo-i18n/src/tr.ts
@@ -91,7 +91,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"Bu proje için Kilo anlık görüntülerini kapat. Kilo değişiklikleri için geri alma/yeniden yapmayı kaybedersiniz, ancak git her şeyi izlemeye devam eder.",
- "ui.messagePart.openInDiffViewer": "Fark görüntüleyicide aç",
+ // Edit-tool header and shell-tool section labels
+ "ui.messagePart.openInDiffViewer": "Fark Görüntüleyicide Aç",
+ "ui.messagePart.shell.command": "Komut",
+ "ui.messagePart.shell.output": "Çıktı",
+ "ui.messagePart.openInEditor": "Düzenleyicide Aç",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Bu yardımcı oldu",
diff --git a/packages/kilo-i18n/src/uk.ts b/packages/kilo-i18n/src/uk.ts
index 3e325a33f7d..afc11ae14e1 100644
--- a/packages/kilo-i18n/src/uk.ts
+++ b/packages/kilo-i18n/src/uk.ts
@@ -91,7 +91,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"Вимкніть знімки Kilo для цього проєкту. Ви втратите скасування/повторення для змін Kilo, але git продовжить відстежувати все.",
- "ui.messagePart.openInDiffViewer": "Відкрити у переглядачі відмінностей",
+ // Edit-tool header and shell-tool section labels
+ "ui.messagePart.openInDiffViewer": "Відкрити в переглядачі відмінностей",
+ "ui.messagePart.shell.command": "Команда",
+ "ui.messagePart.shell.output": "Вивід",
+ "ui.messagePart.openInEditor": "Відкрити в редакторі",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "Це було корисно",
diff --git a/packages/kilo-i18n/src/zh.ts b/packages/kilo-i18n/src/zh.ts
index 29a57c5290d..37954ff59d2 100644
--- a/packages/kilo-i18n/src/zh.ts
+++ b/packages/kilo-i18n/src/zh.ts
@@ -86,7 +86,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"关闭本项目的 Kilo 快照。你将失去对 Kilo 更改的撤销/重做,但 git 仍会追踪所有内容。",
+ // Edit-tool header and shell-tool section labels
"ui.messagePart.openInDiffViewer": "在差异查看器中打开",
+ "ui.messagePart.shell.command": "命令",
+ "ui.messagePart.shell.output": "输出",
+ "ui.messagePart.openInEditor": "在编辑器中打开",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "这有帮助",
diff --git a/packages/kilo-i18n/src/zht.ts b/packages/kilo-i18n/src/zht.ts
index 08582812567..5561173b89d 100644
--- a/packages/kilo-i18n/src/zht.ts
+++ b/packages/kilo-i18n/src/zht.ts
@@ -86,7 +86,11 @@ export const dict = {
"snapshot.slowRepo.answer.disable.description":
"關閉本專案的 Kilo 快照。你將失去對 Kilo 變更的撤銷/重做,但 git 仍會追蹤所有內容。",
+ // Edit-tool header and shell-tool section labels
"ui.messagePart.openInDiffViewer": "在差異檢視器中開啟",
+ "ui.messagePart.shell.command": "命令",
+ "ui.messagePart.shell.output": "輸出",
+ "ui.messagePart.openInEditor": "在編輯器中開啟",
// Message feedback (thumbs up/down per assistant response)
"ui.message.feedback.helpful": "這有幫助",
diff --git a/packages/kilo-ui/src/components/message-part.css b/packages/kilo-ui/src/components/message-part.css
index bb6f99c515a..5494f7c0c71 100644
--- a/packages/kilo-ui/src/components/message-part.css
+++ b/packages/kilo-ui/src/components/message-part.css
@@ -195,11 +195,69 @@ html[data-theme="kilo-vscode"] [data-component="bash-output"] {
color: var(--vscode-terminal-foreground, var(--vscode-editor-foreground));
}
- [data-slot="bash-copy"] [data-component="icon-button"][data-variant="secondary"] {
- background: var(--vscode-terminal-background, var(--vscode-panel-background));
+ [data-slot="bash-divider"] {
+ background: var(--vscode-panel-border, var(--border-weak-base));
}
}
+/* Bash tool: section layout (command + output) */
+[data-component="bash-output"] [data-slot="bash-section"] {
+ position: relative;
+}
+
+[data-component="bash-output"] [data-slot="bash-section-code"] {
+ overflow-y: auto;
+ overflow-x: hidden;
+ max-height: 240px;
+ scrollbar-width: none;
+ &::-webkit-scrollbar {
+ display: none;
+ }
+}
+
+[data-component="bash-output"] [data-slot="bash-section-actions"] {
+ position: absolute;
+ top: 4px;
+ right: 4px;
+ display: flex;
+ align-items: center;
+ gap: 2px;
+ opacity: 0;
+ pointer-events: none;
+ transition: opacity 0.15s ease;
+}
+
+[data-component="bash-output"] [data-slot="bash-section"]:hover [data-slot="bash-section-actions"],
+[data-component="bash-output"] [data-slot="bash-section"]:focus-within [data-slot="bash-section-actions"] {
+ opacity: 1;
+ pointer-events: auto;
+}
+
+/* Edge-to-edge divider (matches MCP tool divider) */
+[data-component="bash-output"] [data-slot="bash-divider"] {
+ height: 1px;
+ background: var(--border-weak-base);
+}
+
+/* Shiki syntax-highlighted shell output */
+[data-component="bash-output"] .shiki,
+[data-component="shell-expanded-output"] .shiki {
+ margin: 0;
+ padding: 12px;
+ background: transparent !important;
+}
+
+[data-component="bash-output"] .shiki code,
+[data-component="shell-expanded-output"] .shiki code {
+ font-family: var(--font-family-mono);
+ font-feature-settings: var(--font-family-mono--font-feature-settings);
+ font-size: var(--font-size-small);
+ line-height: var(--line-height-large);
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+ background: transparent;
+}
+
/* Tool error inline card (upstream removed these styles in v1.2.25) */
[data-component="tool-error"] {
display: flex;
diff --git a/packages/kilo-ui/src/components/message-part.tsx b/packages/kilo-ui/src/components/message-part.tsx
index 5df2fd231a1..8e1e72648a0 100644
--- a/packages/kilo-ui/src/components/message-part.tsx
+++ b/packages/kilo-ui/src/components/message-part.tsx
@@ -54,6 +54,8 @@ import { ContextToolGroupHeader, ContextToolExpandedList, ContextToolRollingResu
import { ShellRollingResults } from "./shell-rolling-results"
import { extractFilePathFromHref } from "../file-path"
import { normalize } from "./session-diff"
+import { deferredHighlight } from "../context/marked"
+import { escapeHtml } from "../util/escape-html"
// Windows CLI tools (e.g. winget) use \r to overwrite progress bars in-place.
// Without this, every progress frame renders as a separate visual line.
@@ -2028,6 +2030,112 @@ ToolRegistry.register({
},
})
+function BashCopyButton(props: { value: () => string; label: string }) {
+ const i18n = useI18n()
+ const [copied, setCopied] = createSignal(false)
+ const handler = async () => {
+ const text = props.value()
+ if (!text) return
+ await navigator.clipboard.writeText(text)
+ setCopied(true)
+ setTimeout(() => setCopied(false), 2000)
+ }
+ return (
+
${escapeHtml(cmd)}`
+ void deferredHighlight(cmdRef, undefined, signal)
+ })
+
+ createEffect(() => {
+ outState.signal.aborted = true
+ if (!props.active) return
+ const out = props.output
+ if (!outRef || !out) return
+ const signal = { aborted: false }
+ outState.signal = signal
+ outRef.innerHTML = `${escapeHtml(out)}`
+ void deferredHighlight(outRef, undefined, signal)
+ })
+
+ onCleanup(() => {
+ cmdState.signal.aborted = true
+ outState.signal.aborted = true
+ })
+
+ const openInEditor = () => {
+ // When output was truncated, open the full output file on disk
+ if (props.outputPath && data.openFile) {
+ data.openFile(props.outputPath)
+ return
+ }
+ if (!data.openContent) return
+ data.openContent(props.output, "log")
+ }
+
+ return (
+
- {text()}
-
- ${escapeHtml(code)}`
+ void deferredHighlight(ref, undefined, signal)
+ })
+
+ onCleanup(() => {
+ state.signal.aborted = true
+ })
+
+ return
+}
+
function ShellExpanded(props: { cmd: string; out: string; open: boolean }) {
const i18n = useI18n()
const rows = 10
@@ -156,9 +180,7 @@ function ShellExpanded(props: { cmd: string; out: string; open: boolean }) {
onScroll={updateMask}
style={{ "max-height": `${cap()}px` }}
>
-
- {props.out}
-
+