@toddzheng024/dscode-bundle 0.7.11 → 0.7.12

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/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.7.11",
2
+ "version": "0.7.12",
3
3
  "type": "module",
4
4
  "license": "MIT",
5
5
  "author": "Todd Zheng",
@@ -40,7 +40,7 @@ export const MESSAGES = {
40
40
  'language.set': 'language → {name}', 'language.title': '/language — interface language', 'language.currentMark': 'current', 'language.unknown': 'Unknown language "{value}". Choose en, zh-CN, zh-TW, ja, ko or es.',
41
41
  'language.saveFailed': 'language save failed: {error}',
42
42
  'doctor.logs.new': 'Only warnings/errors since this TUI version started are recorded.',
43
- 'footer.current': 'current', 'footer.average': 'average', 'footer.context': 'context', 'footer.cache': 'cache hit', 'composer.placeholder': 'type a message',
43
+ 'footer.current': 'current', 'footer.average': 'average', 'footer.context': 'context', 'footer.cache': 'cache hit', 'composer.placeholder': 'type a message', 'composer.shellMode': '! shell mode · esc exits',
44
44
  'compaction.running': 'Compacting context, please wait', 'compaction.confirm.title': 'Switching to {model} will compact the conversation',
45
45
  'compaction.confirm.usage': 'context {used} ≥ compaction threshold {threshold} ({window} × {ratio})', 'compaction.confirm.next': 'the next step compacts older history first',
46
46
  'compaction.confirm.overflow': 'it already exceeds the {window} window: the next request compacts and retries', 'compaction.confirm.hint': 'y switch · n/esc back',
@@ -68,7 +68,7 @@ export const MESSAGES = {
68
68
  'language.set': '语言 → {name}', 'language.title': '/language — 界面语言', 'language.currentMark': '当前', 'language.unknown': '未知语言 "{value}"。可选 en、zh-CN、zh-TW、ja、ko、es。',
69
69
  'language.saveFailed': '语言设置保存失败:{error}',
70
70
  'doctor.logs.new': '仅记录新版 TUI 启动后的 warning/error。',
71
- 'footer.current': '当前', 'footer.average': '平均', 'footer.context': '上下文', 'footer.cache': '缓存命中', 'composer.placeholder': '输入消息',
71
+ 'footer.current': '当前', 'footer.average': '平均', 'footer.context': '上下文', 'footer.cache': '缓存命中', 'composer.placeholder': '输入消息', 'composer.shellMode': '! shell 模式 · esc 退出',
72
72
  'compaction.running': '正在压缩上下文,请稍后', 'compaction.confirm.title': '切换到 {model} 会触发自动压缩',
73
73
  'compaction.confirm.usage': '当前上下文 {used} ≥ 压缩阈值 {threshold}({window} × {ratio})', 'compaction.confirm.next': '下一步开始前会先压缩较早的对话',
74
74
  'compaction.confirm.overflow': '已超出新模型的 {window} 上下文窗口:下一次请求会先压缩再重试', 'compaction.confirm.hint': 'y 确认切换 · n/esc 返回',
@@ -96,7 +96,7 @@ export const MESSAGES = {
96
96
  'language.set': '語言 → {name}', 'language.title': '/language — 介面語言', 'language.currentMark': '目前', 'language.unknown': '未知語言 "{value}"。可選 en、zh-CN、zh-TW、ja、ko、es。',
97
97
  'language.saveFailed': '語言設定儲存失敗:{error}',
98
98
  'doctor.logs.new': '僅記錄新版 TUI 啟動後的 warning/error。',
99
- 'footer.current': '目前', 'footer.average': '平均', 'footer.context': '上下文', 'footer.cache': '快取命中', 'composer.placeholder': '輸入訊息',
99
+ 'footer.current': '目前', 'footer.average': '平均', 'footer.context': '上下文', 'footer.cache': '快取命中', 'composer.placeholder': '輸入訊息', 'composer.shellMode': '! shell 模式 · esc 離開',
100
100
  'compaction.running': '正在壓縮上下文,請稍候', 'compaction.confirm.title': '切換到 {model} 會觸發自動壓縮',
101
101
  'compaction.confirm.usage': '目前上下文 {used} ≥ 壓縮閾值 {threshold}({window} × {ratio})', 'compaction.confirm.next': '下一步開始前會先壓縮較早的對話',
102
102
  'compaction.confirm.overflow': '已超出新模型的 {window} 上下文視窗:下一次請求會先壓縮再重試', 'compaction.confirm.hint': 'y 確認切換 · n/esc 返回',
@@ -124,7 +124,7 @@ export const MESSAGES = {
124
124
  'language.set': '言語 → {name}', 'language.title': '/language — 表示言語', 'language.currentMark': '現在', 'language.unknown': '不明な言語 "{value}"。en、zh-CN、zh-TW、ja、ko、es から選んでください。',
125
125
  'language.saveFailed': '言語設定の保存に失敗しました:{error}',
126
126
  'doctor.logs.new': 'この TUI バージョンの起動以降の warning/error のみ記録されています。',
127
- 'footer.current': '現在', 'footer.average': '平均', 'footer.context': 'コンテキスト', 'footer.cache': 'キャッシュヒット', 'composer.placeholder': 'メッセージを入力',
127
+ 'footer.current': '現在', 'footer.average': '平均', 'footer.context': 'コンテキスト', 'footer.cache': 'キャッシュヒット', 'composer.placeholder': 'メッセージを入力', 'composer.shellMode': '! shell モード · esc で終了',
128
128
  'compaction.running': 'コンテキストを圧縮しています。しばらくお待ちください', 'compaction.confirm.title': '{model} に切り替えると自動圧縮が実行されます',
129
129
  'compaction.confirm.usage': '現在のコンテキスト {used} ≥ 圧縮しきい値 {threshold}({window} × {ratio})', 'compaction.confirm.next': '次のステップの前に古い履歴を圧縮します',
130
130
  'compaction.confirm.overflow': '新しいモデルの {window} ウィンドウを超えています。次のリクエストで圧縮して再試行します', 'compaction.confirm.hint': 'y 切り替え · n/esc 戻る',
@@ -152,7 +152,7 @@ export const MESSAGES = {
152
152
  'language.set': '언어 → {name}', 'language.title': '/language — 인터페이스 언어', 'language.currentMark': '현재', 'language.unknown': '알 수 없는 언어 "{value}". en, zh-CN, zh-TW, ja, ko, es 중에서 선택하세요.',
153
153
  'language.saveFailed': '언어 설정 저장 실패: {error}',
154
154
  'doctor.logs.new': '이 TUI 버전 시작 이후의 warning/error만 기록됩니다.',
155
- 'footer.current': '현재', 'footer.average': '평균', 'footer.context': '컨텍스트', 'footer.cache': '캐시 적중', 'composer.placeholder': '메시지를 입력하세요',
155
+ 'footer.current': '현재', 'footer.average': '평균', 'footer.context': '컨텍스트', 'footer.cache': '캐시 적중', 'composer.placeholder': '메시지를 입력하세요', 'composer.shellMode': '! shell 모드 · esc 종료',
156
156
  'compaction.running': '컨텍스트를 압축하는 중입니다. 잠시만 기다려 주세요', 'compaction.confirm.title': '{model}(으)로 전환하면 자동 압축이 실행됩니다',
157
157
  'compaction.confirm.usage': '현재 컨텍스트 {used} ≥ 압축 임계값 {threshold} ({window} × {ratio})', 'compaction.confirm.next': '다음 단계 전에 이전 대화를 먼저 압축합니다',
158
158
  'compaction.confirm.overflow': '새 모델의 {window} 창을 이미 넘었습니다. 다음 요청에서 압축한 뒤 재시도합니다', 'compaction.confirm.hint': 'y 전환 · n/esc 뒤로',
@@ -180,7 +180,7 @@ export const MESSAGES = {
180
180
  'language.set': 'idioma → {name}', 'language.title': '/language — idioma de la interfaz', 'language.currentMark': 'actual', 'language.unknown': 'Idioma desconocido "{value}". Elige en, zh-CN, zh-TW, ja, ko o es.',
181
181
  'language.saveFailed': 'no se pudo guardar el idioma: {error}',
182
182
  'doctor.logs.new': 'Solo se registran los warnings/errores desde que arrancó esta versión del TUI.',
183
- 'footer.current': 'actual', 'footer.average': 'promedio', 'footer.context': 'contexto', 'footer.cache': 'éxitos de caché', 'composer.placeholder': 'escribe un mensaje',
183
+ 'footer.current': 'actual', 'footer.average': 'promedio', 'footer.context': 'contexto', 'footer.cache': 'éxitos de caché', 'composer.placeholder': 'escribe un mensaje', 'composer.shellMode': '! modo shell · esc sale',
184
184
  'compaction.running': 'Compactando el contexto, espera un momento', 'compaction.confirm.title': 'Cambiar a {model} compactará la conversación',
185
185
  'compaction.confirm.usage': 'contexto {used} ≥ umbral de compactación {threshold} ({window} × {ratio})', 'compaction.confirm.next': 'el siguiente paso compacta antes el historial antiguo',
186
186
  'compaction.confirm.overflow': 'ya supera la ventana de {window}: la siguiente petición compacta y reintenta', 'compaction.confirm.hint': 'y cambiar · n/esc volver',
@@ -34,7 +34,10 @@ export function summarize(rows, events = [], corrupt = false) {
34
34
  if (!Number.isFinite(row.cost)) unknown = true;
35
35
  else cost += row.cost;
36
36
  const u = row.usage;
37
- if (!u || !Number.isFinite(u.inputTokens) || !Number.isFinite(u.outputTokens)) { cacheUnknown = true; continue; }
37
+ // An auxiliary call (memory, review, an aborted stream) can end without a usage chunk: that
38
+ // call is unaccounted, not a cache miss, so it must not blank the whole session's ratio.
39
+ if (!u) continue;
40
+ if (!Number.isFinite(u.inputTokens) || !Number.isFinite(u.outputTokens)) { cacheUnknown = true; continue; }
38
41
  const total = u.inputTokens + (u.cacheReadTokens ?? 0) + (u.cacheWriteTokens ?? 0);
39
42
  // OpenRouter reports cache reads only when there are some: a missing count is zero, not unknown.
40
43
  input += total; hit += u.cacheReadTokens ?? 0;
@@ -60,10 +63,10 @@ export function formatFooter(metrics, context, columns = 80, rates, locale = 'en
60
63
  `${label('footer.average')}: ${Number.isFinite(rates.average) ? rates.average.toFixed(1) : '--'} tps`,
61
64
  `${label('footer.context')}: ${ctx}`, dollars, `${label('footer.cache')}: ${cache}`,
62
65
  ] : [`${label('footer.context')}: ${ctx}`, dollars, `${label('footer.cache')}: ${cache}`];
63
- // Narrow terminals shed the quietest figures first: average, cache hit, current. The
66
+ // Narrow terminals shed the quietest figures first: average, current, context. The
64
67
  // model header then falls back to its bare `model @ effort` form, then context goes,
65
68
  // and only then the header itself — the running cost is the last thing standing.
66
- const drops = rates ? [1, 4, 0, 2] : [2, 0];
69
+ const drops = rates ? [1, 0, 2, 4] : [0, 2];
67
70
  const offset = header === '' ? 0 : 1;
68
71
  const parts = header === '' ? base : [header, ...base];
69
72
  const short = header.replace(/^[^:]+: /, '');
@@ -4,6 +4,7 @@ import { readLanguage, t } from '../i18n/messages.mjs';
4
4
  import { readFile, readdir, access } from 'node:fs/promises';
5
5
  import { dirname, join, resolve } from 'node:path';
6
6
  import { parse } from 'yaml';
7
+ import { createUserMessage } from '@deepseek-ai/dsh-llm';
7
8
  import { standingMountFor } from '@deepseek-ai/dsh-agent-presets';
8
9
  import { hookEvents, validateHooks } from './hooks.mjs';
9
10
  import { redact } from '../auto-review/policy.mjs';
@@ -83,7 +84,19 @@ export function apply(ctx) {
83
84
  try { const result = await handler(inv); return { ...result, text: redact(result.text ?? '') }; }
84
85
  catch (e) { return fail(redact(`${name}: ${e.message}`)); }
85
86
  }});
86
- register('shell-exec', 'Run a user shell command (also !command)', ({ rawInput, agent, signal }) => runShell(rawInput, { cwd: agent.session.header.cwd ?? process.cwd(), signal }));
87
+ register('shell-exec', 'Run a user shell command (also !command)', async ({ rawInput, agent, signal }) => {
88
+ const result = await runShell(rawInput, { cwd: agent.session.header.cwd ?? process.cwd(), signal });
89
+ // What the user ran belongs to the conversation: the command and its (redacted) output
90
+ // are handed to the agent, which then gets a turn to react to them.
91
+ const handover = redact(`[shell] $ ${rawInput.trim()}\n${result.text}`).slice(0, 8000);
92
+ try {
93
+ agent.followup(createUserMessage({ content: [{ type: 'text', text: handover }], source: { kind: 'plugin', plugin: 'dscode-shell-exec' } }));
94
+ await ctx.get('sessions')?.flush?.(agent.session);
95
+ } catch (error) {
96
+ return fail(`shell: the command ran, but its output could not reach the agent (${error.message})`);
97
+ }
98
+ return { ...result, text: `${result.text}\n\n[output handed to the agent]` };
99
+ });
87
100
  register('status', 'Session, model, permissions, usage and plugin health', ({ agent }) => {
88
101
  const session = agent.session;
89
102
  const route = session.requestHeader()?.config ?? agent.options;
@@ -15,11 +15,12 @@ function dscodeNewerVersion(candidate, current) {
15
15
  if (right.pre === '') return false;
16
16
  return false;
17
17
  }
18
+ // dscode-shell-mode-v1
18
19
  // dscode-turn-errors-v1
19
20
  // dscode-language-v2
20
21
  // dscode-language-v1
21
22
  const DSCODE_LANGUAGES = [{"code":"en","name":"English"},{"code":"zh-CN","name":"简体中文"},{"code":"zh-TW","name":"繁體中文"},{"code":"ja","name":"日本語"},{"code":"ko","name":"한국어"},{"code":"es","name":"Español"}];
22
- const DSCODE_MESSAGES = {"en":{"activity.replying":"Replying","activity.thinking":"Thinking","activity.running":"Running","activity.turn":"this turn","activity.interrupt":"Esc to interrupt","agents.running":"running","agents.idle":"idle","agents.done":"done","agents.total":"total","welcome.model":"model","welcome.effort":"effort","welcome.project":"project","verbose.on":"verbose on: thinking and tool calls are shown in the chat","verbose.off":"verbose off","mouse.on":"mouse on: the wheel scrolls the chat · hold Shift while dragging to select text (Option in iTerm2, Fn in Terminal)","mouse.off":"mouse off: select and copy freely · PageUp/PageDown scroll the chat · /mouse turns wheel scrolling on","language.current":"Language: {name} · /language en | zh-CN | zh-TW | ja | ko | es","update.available":"DSCODE {version} is available · run /update to upgrade","update.newest":"the newest release","update.scheduled":"DSCODE {version} will update after this session exits.\nLog: {log}","update.usage":"Usage: /update [exact-version]","language.set":"language → {name}","language.title":"/language — interface language","language.currentMark":"current","language.unknown":"Unknown language \"{value}\". Choose en, zh-CN, zh-TW, ja, ko or es.","language.saveFailed":"language save failed: {error}","doctor.logs.new":"Only warnings/errors since this TUI version started are recorded.","footer.current":"current","footer.average":"average","footer.context":"context","footer.cache":"cache hit","composer.placeholder":"type a message","compaction.running":"Compacting context, please wait","compaction.confirm.title":"Switching to {model} will compact the conversation","compaction.confirm.usage":"context {used} ≥ compaction threshold {threshold} ({window} × {ratio})","compaction.confirm.next":"the next step compacts older history first","compaction.confirm.overflow":"it already exceeds the {window} window: the next request compacts and retries","compaction.confirm.hint":"y switch · n/esc back","doctor.nearTimeout":"Assessment: {count} Bash calls ended at about 300 seconds, which matches the tool timeout; traces alone cannot prove the root cause. Next, check those calls' shell completion markers and terminal errors.","doctor.logs.none":"No log file yet; earlier console logs were not persisted and cannot be recovered.","doctor.evidence":"Diagnostic evidence: {traces} recent sessions, {logs} warnings/errors.","doctor.noFindings":"No clear timeouts, unfinished tool calls or error events in recent traces.","doctor.noRoute":"No model route is available, so the model analysis could not run.","doctor.scope":"Evidence scope: {traces} recent sessions, {logs} warnings/errors; conversation text, tool arguments and tool output were not read.","doctor.failed":"Model analysis did not finish: {error}."},"zh-CN":{"activity.replying":"正在回复","activity.thinking":"正在思考","activity.running":"正在执行","activity.turn":"本轮","activity.interrupt":"Esc 中断","agents.running":"运行中","agents.idle":"空闲","agents.done":"已完成","agents.total":"总计","welcome.model":"模型","welcome.effort":"推理","welcome.project":"项目","verbose.on":"详细模式已开启:对话中显示思考与工具调用","verbose.off":"详细模式已关闭","mouse.on":"鼠标捕获已开启:滚轮滚动对话 · 拖选文本时按住 Shift(iTerm2 按住 Option、Terminal 按住 Fn)","mouse.off":"鼠标捕获已关闭:可自由选择复制 · PageUp/PageDown 滚动对话 · /mouse 重新开启","language.current":"语言:{name} · /language en | zh-CN | zh-TW | ja | ko | es","update.available":"DSCODE {version} 已发布 · 输入 /update 升级","update.newest":"最新版本","update.scheduled":"DSCODE {version} 将在本次会话退出后升级。\n日志:{log}","update.usage":"用法:/update [精确版本号]","language.set":"语言 → {name}","language.title":"/language — 界面语言","language.currentMark":"当前","language.unknown":"未知语言 \"{value}\"。可选 en、zh-CN、zh-TW、ja、ko、es。","language.saveFailed":"语言设置保存失败:{error}","doctor.logs.new":"仅记录新版 TUI 启动后的 warning/error。","footer.current":"当前","footer.average":"平均","footer.context":"上下文","footer.cache":"缓存命中","composer.placeholder":"输入消息","compaction.running":"正在压缩上下文,请稍后","compaction.confirm.title":"切换到 {model} 会触发自动压缩","compaction.confirm.usage":"当前上下文 {used} ≥ 压缩阈值 {threshold}({window} × {ratio})","compaction.confirm.next":"下一步开始前会先压缩较早的对话","compaction.confirm.overflow":"已超出新模型的 {window} 上下文窗口:下一次请求会先压缩再重试","compaction.confirm.hint":"y 确认切换 · n/esc 返回","doctor.nearTimeout":"判断:{count} 次 Bash 调用在约 300 秒结束,符合工具超时特征;trace 不能单独证明触发超时的根因。下一步检查这些调用的 shell 完成标记和终端错误。","doctor.logs.none":"日志文件尚未建立;旧版控制台日志未持久化,无法回溯。","doctor.evidence":"诊断证据:{traces} 个近期会话、{logs} 条 warning/error。","doctor.noFindings":"近期 trace 中未发现明确的超时、未完成工具调用或错误事件。","doctor.noRoute":"没有可用的模型路由,无法运行模型分析。","doctor.scope":"证据范围:{traces} 个近期会话、{logs} 条 warning/error;未读取对话正文、工具参数或工具输出。","doctor.failed":"模型分析未完成:{error}。"},"zh-TW":{"activity.replying":"正在回覆","activity.thinking":"正在思考","activity.running":"正在執行","activity.turn":"本輪","activity.interrupt":"Esc 中斷","agents.running":"執行中","agents.idle":"閒置","agents.done":"已完成","agents.total":"總計","welcome.model":"模型","welcome.effort":"推理","welcome.project":"專案","verbose.on":"詳細模式已開啟:對話中顯示思考與工具呼叫","verbose.off":"詳細模式已關閉","mouse.on":"滑鼠擷取已開啟:滾輪捲動對話 · 拖選文字時按住 Shift(iTerm2 按住 Option、Terminal 按住 Fn)","mouse.off":"滑鼠擷取已關閉:可自由選取複製 · PageUp/PageDown 捲動對話 · /mouse 重新開啟","language.current":"語言:{name} · /language en | zh-CN | zh-TW | ja | ko | es","update.available":"DSCODE {version} 已發布 · 輸入 /update 升級","update.newest":"最新版本","update.scheduled":"DSCODE {version} 將在本次工作階段結束後升級。\n日誌:{log}","update.usage":"用法:/update [精確版本號]","language.set":"語言 → {name}","language.title":"/language — 介面語言","language.currentMark":"目前","language.unknown":"未知語言 \"{value}\"。可選 en、zh-CN、zh-TW、ja、ko、es。","language.saveFailed":"語言設定儲存失敗:{error}","doctor.logs.new":"僅記錄新版 TUI 啟動後的 warning/error。","footer.current":"目前","footer.average":"平均","footer.context":"上下文","footer.cache":"快取命中","composer.placeholder":"輸入訊息","compaction.running":"正在壓縮上下文,請稍候","compaction.confirm.title":"切換到 {model} 會觸發自動壓縮","compaction.confirm.usage":"目前上下文 {used} ≥ 壓縮閾值 {threshold}({window} × {ratio})","compaction.confirm.next":"下一步開始前會先壓縮較早的對話","compaction.confirm.overflow":"已超出新模型的 {window} 上下文視窗:下一次請求會先壓縮再重試","compaction.confirm.hint":"y 確認切換 · n/esc 返回","doctor.nearTimeout":"判斷:{count} 次 Bash 呼叫在約 300 秒結束,符合工具逾時特徵;trace 無法單獨證明觸發逾時的根因。下一步檢查這些呼叫的 shell 完成標記和終端錯誤。","doctor.logs.none":"日誌檔尚未建立;舊版主控台日誌未持久化,無法回溯。","doctor.evidence":"診斷證據:{traces} 個近期工作階段、{logs} 筆 warning/error。","doctor.noFindings":"近期 trace 中未發現明確的逾時、未完成工具呼叫或錯誤事件。","doctor.noRoute":"沒有可用的模型路由,無法執行模型分析。","doctor.scope":"證據範圍:{traces} 個近期工作階段、{logs} 筆 warning/error;未讀取對話內容、工具參數或工具輸出。","doctor.failed":"模型分析未完成:{error}。"},"ja":{"activity.replying":"応答中","activity.thinking":"思考中","activity.running":"実行中","activity.turn":"今回のターン","activity.interrupt":"Esc で中断","agents.running":"実行中","agents.idle":"待機中","agents.done":"完了","agents.total":"合計","welcome.model":"モデル","welcome.effort":"推論","welcome.project":"プロジェクト","verbose.on":"詳細モード オン:思考とツール呼び出しをチャットに表示します","verbose.off":"詳細モード オフ","mouse.on":"マウス キャプチャ オン:ホイールでチャットをスクロール · Shift(iTerm2 は Option、Terminal は Fn)を押しながらドラッグでテキスト選択","mouse.off":"マウス キャプチャ オフ:自由に選択・コピーできます · PageUp/PageDown でスクロール · /mouse で再びオン","language.current":"言語:{name} · /language en | zh-CN | zh-TW | ja | ko | es","update.available":"DSCODE {version} が公開されました · /update でアップグレード","update.newest":"最新リリース","update.scheduled":"DSCODE {version} はこのセッションの終了後に更新されます。\nログ: {log}","update.usage":"使用法: /update [正確なバージョン]","language.set":"言語 → {name}","language.title":"/language — 表示言語","language.currentMark":"現在","language.unknown":"不明な言語 \"{value}\"。en、zh-CN、zh-TW、ja、ko、es から選んでください。","language.saveFailed":"言語設定の保存に失敗しました:{error}","doctor.logs.new":"この TUI バージョンの起動以降の warning/error のみ記録されています。","footer.current":"現在","footer.average":"平均","footer.context":"コンテキスト","footer.cache":"キャッシュヒット","composer.placeholder":"メッセージを入力","compaction.running":"コンテキストを圧縮しています。しばらくお待ちください","compaction.confirm.title":"{model} に切り替えると自動圧縮が実行されます","compaction.confirm.usage":"現在のコンテキスト {used} ≥ 圧縮しきい値 {threshold}({window} × {ratio})","compaction.confirm.next":"次のステップの前に古い履歴を圧縮します","compaction.confirm.overflow":"新しいモデルの {window} ウィンドウを超えています。次のリクエストで圧縮して再試行します","compaction.confirm.hint":"y 切り替え · n/esc 戻る","doctor.nearTimeout":"判断:Bash 呼び出し {count} 件が約 300 秒で終了しており、ツールのタイムアウトの特徴に一致します。トレースだけでは根本原因を証明できません。次はこれらの呼び出しのシェル完了マーカーと端末エラーを確認してください。","doctor.logs.none":"ログファイルはまだありません。以前のコンソールログは保存されておらず、遡れません。","doctor.evidence":"診断の根拠:直近のセッション {traces} 件、warning/error {logs} 件。","doctor.noFindings":"直近のトレースに明確なタイムアウト、未完了ツール、停滞は見つかりませんでした。","doctor.noRoute":"利用できるモデルルートがないため、モデル分析を実行できません。","doctor.scope":"根拠の範囲:直近のセッション {traces} 件、warning/error {logs} 件。会話本文、ツール引数、ツール出力は読んでいません。","doctor.failed":"モデル分析が完了しませんでした:{error}。"},"ko":{"activity.replying":"응답 중","activity.thinking":"생각 중","activity.running":"실행 중","activity.turn":"이번 턴","activity.interrupt":"Esc 중단","agents.running":"실행 중","agents.idle":"대기","agents.done":"완료","agents.total":"전체","welcome.model":"모델","welcome.effort":"추론","welcome.project":"프로젝트","verbose.on":"상세 모드 켜짐: 생각과 도구 호출을 채팅에 표시합니다","verbose.off":"상세 모드 꺼짐","mouse.on":"마우스 캡처 켜짐: 휠로 채팅 스크롤 · Shift(iTerm2는 Option, Terminal은 Fn)를 누른 채 드래그하여 텍스트 선택","mouse.off":"마우스 캡처 꺼짐: 자유롭게 선택·복사 · PageUp/PageDown으로 채팅 스크롤 · /mouse로 다시 켜기","language.current":"언어: {name} · /language en | zh-CN | zh-TW | ja | ko | es","update.available":"DSCODE {version} 사용 가능 · /update 로 업그레이드","update.newest":"최신 릴리스","update.scheduled":"DSCODE {version} 은(는) 이 세션이 종료된 후 업데이트됩니다.\n로그: {log}","update.usage":"사용법: /update [정확한 버전]","language.set":"언어 → {name}","language.title":"/language — 인터페이스 언어","language.currentMark":"현재","language.unknown":"알 수 없는 언어 \"{value}\". en, zh-CN, zh-TW, ja, ko, es 중에서 선택하세요.","language.saveFailed":"언어 설정 저장 실패: {error}","doctor.logs.new":"이 TUI 버전 시작 이후의 warning/error만 기록됩니다.","footer.current":"현재","footer.average":"평균","footer.context":"컨텍스트","footer.cache":"캐시 적중","composer.placeholder":"메시지를 입력하세요","compaction.running":"컨텍스트를 압축하는 중입니다. 잠시만 기다려 주세요","compaction.confirm.title":"{model}(으)로 전환하면 자동 압축이 실행됩니다","compaction.confirm.usage":"현재 컨텍스트 {used} ≥ 압축 임계값 {threshold} ({window} × {ratio})","compaction.confirm.next":"다음 단계 전에 이전 대화를 먼저 압축합니다","compaction.confirm.overflow":"새 모델의 {window} 창을 이미 넘었습니다. 다음 요청에서 압축한 뒤 재시도합니다","compaction.confirm.hint":"y 전환 · n/esc 뒤로","doctor.nearTimeout":"판단: Bash 호출 {count}건이 약 300초에 종료되어 도구 시간 초과 특징과 일치합니다. 트레이스만으로는 근본 원인을 증명할 수 없습니다. 다음으로 해당 호출의 셸 완료 표시와 터미널 오류를 확인하세요.","doctor.logs.none":"아직 로그 파일이 없습니다. 이전 콘솔 로그는 저장되지 않아 복구할 수 없습니다.","doctor.evidence":"진단 근거: 최근 세션 {traces}개, warning/error {logs}건.","doctor.noFindings":"최근 트레이스에서 명확한 시간 초과, 미완료 도구, 정지는 발견되지 않았습니다.","doctor.noRoute":"사용 가능한 모델 경로가 없어 모델 분석을 실행할 수 없습니다.","doctor.scope":"근거 범위: 최근 세션 {traces}개, warning/error {logs}건. 대화 본문, 도구 인수, 도구 출력은 읽지 않았습니다.","doctor.failed":"모델 분석이 완료되지 않았습니다: {error}."},"es":{"activity.replying":"Respondiendo","activity.thinking":"Pensando","activity.running":"Ejecutando","activity.turn":"este turno","activity.interrupt":"Esc para interrumpir","agents.running":"en ejecución","agents.idle":"inactivo","agents.done":"terminado","agents.total":"en total","welcome.model":"modelo","welcome.effort":"esfuerzo","welcome.project":"proyecto","verbose.on":"modo detallado activado: el razonamiento y las llamadas a herramientas se muestran en el chat","verbose.off":"modo detallado desactivado","mouse.on":"ratón activado: la rueda desplaza el chat · mantén Shift al arrastrar para seleccionar texto (Option en iTerm2, Fn en Terminal)","mouse.off":"ratón desactivado: selecciona y copia libremente · PageUp/PageDown desplazan el chat · /mouse vuelve a activar la captura","language.current":"Idioma: {name} · /language en | zh-CN | zh-TW | ja | ko | es","update.available":"DSCODE {version} disponible · ejecuta /update para actualizar","update.newest":"la última versión","update.scheduled":"DSCODE {version} se actualizará cuando termine esta sesión.\nRegistro: {log}","update.usage":"Uso: /update [versión exacta]","language.set":"idioma → {name}","language.title":"/language — idioma de la interfaz","language.currentMark":"actual","language.unknown":"Idioma desconocido \"{value}\". Elige en, zh-CN, zh-TW, ja, ko o es.","language.saveFailed":"no se pudo guardar el idioma: {error}","doctor.logs.new":"Solo se registran los warnings/errores desde que arrancó esta versión del TUI.","footer.current":"actual","footer.average":"promedio","footer.context":"contexto","footer.cache":"éxitos de caché","composer.placeholder":"escribe un mensaje","compaction.running":"Compactando el contexto, espera un momento","compaction.confirm.title":"Cambiar a {model} compactará la conversación","compaction.confirm.usage":"contexto {used} ≥ umbral de compactación {threshold} ({window} × {ratio})","compaction.confirm.next":"el siguiente paso compacta antes el historial antiguo","compaction.confirm.overflow":"ya supera la ventana de {window}: la siguiente petición compacta y reintenta","compaction.confirm.hint":"y cambiar · n/esc volver","doctor.nearTimeout":"Valoración: {count} llamadas a Bash terminaron a unos 300 segundos, lo que coincide con el tiempo de espera de la herramienta; las trazas por sí solas no prueban la causa raíz. A continuación, revisa los marcadores de finalización del shell y los errores de terminal de esas llamadas.","doctor.logs.none":"Aún no hay archivo de registro; los registros de consola anteriores no se conservaron y no se pueden recuperar.","doctor.evidence":"Evidencia del diagnóstico: {traces} sesiones recientes, {logs} warnings/errores.","doctor.noFindings":"No hay tiempos de espera, herramientas sin terminar ni bloqueos claros en las trazas recientes.","doctor.noRoute":"No hay una ruta de modelo disponible, así que el análisis con modelo no se pudo ejecutar.","doctor.scope":"Alcance de la evidencia: {traces} sesiones recientes, {logs} warnings/errores; no se leyó el texto de la conversación, los argumentos ni la salida de las herramientas.","doctor.failed":"El análisis con modelo no terminó: {error}."}};
23
+ const DSCODE_MESSAGES = {"en":{"activity.replying":"Replying","activity.thinking":"Thinking","activity.running":"Running","activity.turn":"this turn","activity.interrupt":"Esc to interrupt","agents.running":"running","agents.idle":"idle","agents.done":"done","agents.total":"total","welcome.model":"model","welcome.effort":"effort","welcome.project":"project","verbose.on":"verbose on: thinking and tool calls are shown in the chat","verbose.off":"verbose off","mouse.on":"mouse on: the wheel scrolls the chat · hold Shift while dragging to select text (Option in iTerm2, Fn in Terminal)","mouse.off":"mouse off: select and copy freely · PageUp/PageDown scroll the chat · /mouse turns wheel scrolling on","language.current":"Language: {name} · /language en | zh-CN | zh-TW | ja | ko | es","update.available":"DSCODE {version} is available · run /update to upgrade","update.newest":"the newest release","update.scheduled":"DSCODE {version} will update after this session exits.\nLog: {log}","update.usage":"Usage: /update [exact-version]","language.set":"language → {name}","language.title":"/language — interface language","language.currentMark":"current","language.unknown":"Unknown language \"{value}\". Choose en, zh-CN, zh-TW, ja, ko or es.","language.saveFailed":"language save failed: {error}","doctor.logs.new":"Only warnings/errors since this TUI version started are recorded.","footer.current":"current","footer.average":"average","footer.context":"context","footer.cache":"cache hit","composer.placeholder":"type a message","composer.shellMode":"! shell mode · esc exits","compaction.running":"Compacting context, please wait","compaction.confirm.title":"Switching to {model} will compact the conversation","compaction.confirm.usage":"context {used} ≥ compaction threshold {threshold} ({window} × {ratio})","compaction.confirm.next":"the next step compacts older history first","compaction.confirm.overflow":"it already exceeds the {window} window: the next request compacts and retries","compaction.confirm.hint":"y switch · n/esc back","doctor.nearTimeout":"Assessment: {count} Bash calls ended at about 300 seconds, which matches the tool timeout; traces alone cannot prove the root cause. Next, check those calls' shell completion markers and terminal errors.","doctor.logs.none":"No log file yet; earlier console logs were not persisted and cannot be recovered.","doctor.evidence":"Diagnostic evidence: {traces} recent sessions, {logs} warnings/errors.","doctor.noFindings":"No clear timeouts, unfinished tool calls or error events in recent traces.","doctor.noRoute":"No model route is available, so the model analysis could not run.","doctor.scope":"Evidence scope: {traces} recent sessions, {logs} warnings/errors; conversation text, tool arguments and tool output were not read.","doctor.failed":"Model analysis did not finish: {error}."},"zh-CN":{"activity.replying":"正在回复","activity.thinking":"正在思考","activity.running":"正在执行","activity.turn":"本轮","activity.interrupt":"Esc 中断","agents.running":"运行中","agents.idle":"空闲","agents.done":"已完成","agents.total":"总计","welcome.model":"模型","welcome.effort":"推理","welcome.project":"项目","verbose.on":"详细模式已开启:对话中显示思考与工具调用","verbose.off":"详细模式已关闭","mouse.on":"鼠标捕获已开启:滚轮滚动对话 · 拖选文本时按住 Shift(iTerm2 按住 Option、Terminal 按住 Fn)","mouse.off":"鼠标捕获已关闭:可自由选择复制 · PageUp/PageDown 滚动对话 · /mouse 重新开启","language.current":"语言:{name} · /language en | zh-CN | zh-TW | ja | ko | es","update.available":"DSCODE {version} 已发布 · 输入 /update 升级","update.newest":"最新版本","update.scheduled":"DSCODE {version} 将在本次会话退出后升级。\n日志:{log}","update.usage":"用法:/update [精确版本号]","language.set":"语言 → {name}","language.title":"/language — 界面语言","language.currentMark":"当前","language.unknown":"未知语言 \"{value}\"。可选 en、zh-CN、zh-TW、ja、ko、es。","language.saveFailed":"语言设置保存失败:{error}","doctor.logs.new":"仅记录新版 TUI 启动后的 warning/error。","footer.current":"当前","footer.average":"平均","footer.context":"上下文","footer.cache":"缓存命中","composer.placeholder":"输入消息","composer.shellMode":"! shell 模式 · esc 退出","compaction.running":"正在压缩上下文,请稍后","compaction.confirm.title":"切换到 {model} 会触发自动压缩","compaction.confirm.usage":"当前上下文 {used} ≥ 压缩阈值 {threshold}({window} × {ratio})","compaction.confirm.next":"下一步开始前会先压缩较早的对话","compaction.confirm.overflow":"已超出新模型的 {window} 上下文窗口:下一次请求会先压缩再重试","compaction.confirm.hint":"y 确认切换 · n/esc 返回","doctor.nearTimeout":"判断:{count} 次 Bash 调用在约 300 秒结束,符合工具超时特征;trace 不能单独证明触发超时的根因。下一步检查这些调用的 shell 完成标记和终端错误。","doctor.logs.none":"日志文件尚未建立;旧版控制台日志未持久化,无法回溯。","doctor.evidence":"诊断证据:{traces} 个近期会话、{logs} 条 warning/error。","doctor.noFindings":"近期 trace 中未发现明确的超时、未完成工具调用或错误事件。","doctor.noRoute":"没有可用的模型路由,无法运行模型分析。","doctor.scope":"证据范围:{traces} 个近期会话、{logs} 条 warning/error;未读取对话正文、工具参数或工具输出。","doctor.failed":"模型分析未完成:{error}。"},"zh-TW":{"activity.replying":"正在回覆","activity.thinking":"正在思考","activity.running":"正在執行","activity.turn":"本輪","activity.interrupt":"Esc 中斷","agents.running":"執行中","agents.idle":"閒置","agents.done":"已完成","agents.total":"總計","welcome.model":"模型","welcome.effort":"推理","welcome.project":"專案","verbose.on":"詳細模式已開啟:對話中顯示思考與工具呼叫","verbose.off":"詳細模式已關閉","mouse.on":"滑鼠擷取已開啟:滾輪捲動對話 · 拖選文字時按住 Shift(iTerm2 按住 Option、Terminal 按住 Fn)","mouse.off":"滑鼠擷取已關閉:可自由選取複製 · PageUp/PageDown 捲動對話 · /mouse 重新開啟","language.current":"語言:{name} · /language en | zh-CN | zh-TW | ja | ko | es","update.available":"DSCODE {version} 已發布 · 輸入 /update 升級","update.newest":"最新版本","update.scheduled":"DSCODE {version} 將在本次工作階段結束後升級。\n日誌:{log}","update.usage":"用法:/update [精確版本號]","language.set":"語言 → {name}","language.title":"/language — 介面語言","language.currentMark":"目前","language.unknown":"未知語言 \"{value}\"。可選 en、zh-CN、zh-TW、ja、ko、es。","language.saveFailed":"語言設定儲存失敗:{error}","doctor.logs.new":"僅記錄新版 TUI 啟動後的 warning/error。","footer.current":"目前","footer.average":"平均","footer.context":"上下文","footer.cache":"快取命中","composer.placeholder":"輸入訊息","composer.shellMode":"! shell 模式 · esc 離開","compaction.running":"正在壓縮上下文,請稍候","compaction.confirm.title":"切換到 {model} 會觸發自動壓縮","compaction.confirm.usage":"目前上下文 {used} ≥ 壓縮閾值 {threshold}({window} × {ratio})","compaction.confirm.next":"下一步開始前會先壓縮較早的對話","compaction.confirm.overflow":"已超出新模型的 {window} 上下文視窗:下一次請求會先壓縮再重試","compaction.confirm.hint":"y 確認切換 · n/esc 返回","doctor.nearTimeout":"判斷:{count} 次 Bash 呼叫在約 300 秒結束,符合工具逾時特徵;trace 無法單獨證明觸發逾時的根因。下一步檢查這些呼叫的 shell 完成標記和終端錯誤。","doctor.logs.none":"日誌檔尚未建立;舊版主控台日誌未持久化,無法回溯。","doctor.evidence":"診斷證據:{traces} 個近期工作階段、{logs} 筆 warning/error。","doctor.noFindings":"近期 trace 中未發現明確的逾時、未完成工具呼叫或錯誤事件。","doctor.noRoute":"沒有可用的模型路由,無法執行模型分析。","doctor.scope":"證據範圍:{traces} 個近期工作階段、{logs} 筆 warning/error;未讀取對話內容、工具參數或工具輸出。","doctor.failed":"模型分析未完成:{error}。"},"ja":{"activity.replying":"応答中","activity.thinking":"思考中","activity.running":"実行中","activity.turn":"今回のターン","activity.interrupt":"Esc で中断","agents.running":"実行中","agents.idle":"待機中","agents.done":"完了","agents.total":"合計","welcome.model":"モデル","welcome.effort":"推論","welcome.project":"プロジェクト","verbose.on":"詳細モード オン:思考とツール呼び出しをチャットに表示します","verbose.off":"詳細モード オフ","mouse.on":"マウス キャプチャ オン:ホイールでチャットをスクロール · Shift(iTerm2 は Option、Terminal は Fn)を押しながらドラッグでテキスト選択","mouse.off":"マウス キャプチャ オフ:自由に選択・コピーできます · PageUp/PageDown でスクロール · /mouse で再びオン","language.current":"言語:{name} · /language en | zh-CN | zh-TW | ja | ko | es","update.available":"DSCODE {version} が公開されました · /update でアップグレード","update.newest":"最新リリース","update.scheduled":"DSCODE {version} はこのセッションの終了後に更新されます。\nログ: {log}","update.usage":"使用法: /update [正確なバージョン]","language.set":"言語 → {name}","language.title":"/language — 表示言語","language.currentMark":"現在","language.unknown":"不明な言語 \"{value}\"。en、zh-CN、zh-TW、ja、ko、es から選んでください。","language.saveFailed":"言語設定の保存に失敗しました:{error}","doctor.logs.new":"この TUI バージョンの起動以降の warning/error のみ記録されています。","footer.current":"現在","footer.average":"平均","footer.context":"コンテキスト","footer.cache":"キャッシュヒット","composer.placeholder":"メッセージを入力","composer.shellMode":"! shell モード · esc で終了","compaction.running":"コンテキストを圧縮しています。しばらくお待ちください","compaction.confirm.title":"{model} に切り替えると自動圧縮が実行されます","compaction.confirm.usage":"現在のコンテキスト {used} ≥ 圧縮しきい値 {threshold}({window} × {ratio})","compaction.confirm.next":"次のステップの前に古い履歴を圧縮します","compaction.confirm.overflow":"新しいモデルの {window} ウィンドウを超えています。次のリクエストで圧縮して再試行します","compaction.confirm.hint":"y 切り替え · n/esc 戻る","doctor.nearTimeout":"判断:Bash 呼び出し {count} 件が約 300 秒で終了しており、ツールのタイムアウトの特徴に一致します。トレースだけでは根本原因を証明できません。次はこれらの呼び出しのシェル完了マーカーと端末エラーを確認してください。","doctor.logs.none":"ログファイルはまだありません。以前のコンソールログは保存されておらず、遡れません。","doctor.evidence":"診断の根拠:直近のセッション {traces} 件、warning/error {logs} 件。","doctor.noFindings":"直近のトレースに明確なタイムアウト、未完了ツール、停滞は見つかりませんでした。","doctor.noRoute":"利用できるモデルルートがないため、モデル分析を実行できません。","doctor.scope":"根拠の範囲:直近のセッション {traces} 件、warning/error {logs} 件。会話本文、ツール引数、ツール出力は読んでいません。","doctor.failed":"モデル分析が完了しませんでした:{error}。"},"ko":{"activity.replying":"응답 중","activity.thinking":"생각 중","activity.running":"실행 중","activity.turn":"이번 턴","activity.interrupt":"Esc 중단","agents.running":"실행 중","agents.idle":"대기","agents.done":"완료","agents.total":"전체","welcome.model":"모델","welcome.effort":"추론","welcome.project":"프로젝트","verbose.on":"상세 모드 켜짐: 생각과 도구 호출을 채팅에 표시합니다","verbose.off":"상세 모드 꺼짐","mouse.on":"마우스 캡처 켜짐: 휠로 채팅 스크롤 · Shift(iTerm2는 Option, Terminal은 Fn)를 누른 채 드래그하여 텍스트 선택","mouse.off":"마우스 캡처 꺼짐: 자유롭게 선택·복사 · PageUp/PageDown으로 채팅 스크롤 · /mouse로 다시 켜기","language.current":"언어: {name} · /language en | zh-CN | zh-TW | ja | ko | es","update.available":"DSCODE {version} 사용 가능 · /update 로 업그레이드","update.newest":"최신 릴리스","update.scheduled":"DSCODE {version} 은(는) 이 세션이 종료된 후 업데이트됩니다.\n로그: {log}","update.usage":"사용법: /update [정확한 버전]","language.set":"언어 → {name}","language.title":"/language — 인터페이스 언어","language.currentMark":"현재","language.unknown":"알 수 없는 언어 \"{value}\". en, zh-CN, zh-TW, ja, ko, es 중에서 선택하세요.","language.saveFailed":"언어 설정 저장 실패: {error}","doctor.logs.new":"이 TUI 버전 시작 이후의 warning/error만 기록됩니다.","footer.current":"현재","footer.average":"평균","footer.context":"컨텍스트","footer.cache":"캐시 적중","composer.placeholder":"메시지를 입력하세요","composer.shellMode":"! shell 모드 · esc 종료","compaction.running":"컨텍스트를 압축하는 중입니다. 잠시만 기다려 주세요","compaction.confirm.title":"{model}(으)로 전환하면 자동 압축이 실행됩니다","compaction.confirm.usage":"현재 컨텍스트 {used} ≥ 압축 임계값 {threshold} ({window} × {ratio})","compaction.confirm.next":"다음 단계 전에 이전 대화를 먼저 압축합니다","compaction.confirm.overflow":"새 모델의 {window} 창을 이미 넘었습니다. 다음 요청에서 압축한 뒤 재시도합니다","compaction.confirm.hint":"y 전환 · n/esc 뒤로","doctor.nearTimeout":"판단: Bash 호출 {count}건이 약 300초에 종료되어 도구 시간 초과 특징과 일치합니다. 트레이스만으로는 근본 원인을 증명할 수 없습니다. 다음으로 해당 호출의 셸 완료 표시와 터미널 오류를 확인하세요.","doctor.logs.none":"아직 로그 파일이 없습니다. 이전 콘솔 로그는 저장되지 않아 복구할 수 없습니다.","doctor.evidence":"진단 근거: 최근 세션 {traces}개, warning/error {logs}건.","doctor.noFindings":"최근 트레이스에서 명확한 시간 초과, 미완료 도구, 정지는 발견되지 않았습니다.","doctor.noRoute":"사용 가능한 모델 경로가 없어 모델 분석을 실행할 수 없습니다.","doctor.scope":"근거 범위: 최근 세션 {traces}개, warning/error {logs}건. 대화 본문, 도구 인수, 도구 출력은 읽지 않았습니다.","doctor.failed":"모델 분석이 완료되지 않았습니다: {error}."},"es":{"activity.replying":"Respondiendo","activity.thinking":"Pensando","activity.running":"Ejecutando","activity.turn":"este turno","activity.interrupt":"Esc para interrumpir","agents.running":"en ejecución","agents.idle":"inactivo","agents.done":"terminado","agents.total":"en total","welcome.model":"modelo","welcome.effort":"esfuerzo","welcome.project":"proyecto","verbose.on":"modo detallado activado: el razonamiento y las llamadas a herramientas se muestran en el chat","verbose.off":"modo detallado desactivado","mouse.on":"ratón activado: la rueda desplaza el chat · mantén Shift al arrastrar para seleccionar texto (Option en iTerm2, Fn en Terminal)","mouse.off":"ratón desactivado: selecciona y copia libremente · PageUp/PageDown desplazan el chat · /mouse vuelve a activar la captura","language.current":"Idioma: {name} · /language en | zh-CN | zh-TW | ja | ko | es","update.available":"DSCODE {version} disponible · ejecuta /update para actualizar","update.newest":"la última versión","update.scheduled":"DSCODE {version} se actualizará cuando termine esta sesión.\nRegistro: {log}","update.usage":"Uso: /update [versión exacta]","language.set":"idioma → {name}","language.title":"/language — idioma de la interfaz","language.currentMark":"actual","language.unknown":"Idioma desconocido \"{value}\". Elige en, zh-CN, zh-TW, ja, ko o es.","language.saveFailed":"no se pudo guardar el idioma: {error}","doctor.logs.new":"Solo se registran los warnings/errores desde que arrancó esta versión del TUI.","footer.current":"actual","footer.average":"promedio","footer.context":"contexto","footer.cache":"éxitos de caché","composer.placeholder":"escribe un mensaje","composer.shellMode":"! modo shell · esc sale","compaction.running":"Compactando el contexto, espera un momento","compaction.confirm.title":"Cambiar a {model} compactará la conversación","compaction.confirm.usage":"contexto {used} ≥ umbral de compactación {threshold} ({window} × {ratio})","compaction.confirm.next":"el siguiente paso compacta antes el historial antiguo","compaction.confirm.overflow":"ya supera la ventana de {window}: la siguiente petición compacta y reintenta","compaction.confirm.hint":"y cambiar · n/esc volver","doctor.nearTimeout":"Valoración: {count} llamadas a Bash terminaron a unos 300 segundos, lo que coincide con el tiempo de espera de la herramienta; las trazas por sí solas no prueban la causa raíz. A continuación, revisa los marcadores de finalización del shell y los errores de terminal de esas llamadas.","doctor.logs.none":"Aún no hay archivo de registro; los registros de consola anteriores no se conservaron y no se pueden recuperar.","doctor.evidence":"Evidencia del diagnóstico: {traces} sesiones recientes, {logs} warnings/errores.","doctor.noFindings":"No hay tiempos de espera, herramientas sin terminar ni bloqueos claros en las trazas recientes.","doctor.noRoute":"No hay una ruta de modelo disponible, así que el análisis con modelo no se pudo ejecutar.","doctor.scope":"Alcance de la evidencia: {traces} sesiones recientes, {logs} warnings/errores; no se leyó el texto de la conversación, los argumentos ni la salida de las herramientas.","doctor.failed":"El análisis con modelo no terminó: {error}."}};
23
24
  const DSCODE_LANGUAGE_ALIASES = {"en":["en","english","eng","英文","英语","英語"],"zh-CN":["zh-cn","zh","zh-hans","zhhans","cn","chinese","simplified","中文","简体","简体中文","简中","中文简体"],"zh-TW":["zh-tw","zh-hant","zhhant","tw","hk","zh-hk","traditional","繁体","繁體","繁體中文","繁体中文","繁中"],"ja":["ja","jp","japanese","日本語","日语","日語"],"ko":["ko","kr","korean","한국어","韩语","韓語","韓文"],"es":["es","spanish","español","espanol","西班牙语","西班牙語"]};
24
25
  function dscodeNormalizeLanguage(value) {
25
26
  const aliasesByCode = DSCODE_LANGUAGE_ALIASES;
@@ -162,6 +163,7 @@ function ctrlCAction(armed, { interrupt, busy, preparingImages, active, hasDraft
162
163
  if (!active) return 'wait';
163
164
  return hasDraft ? 'clear-draft' : 'quit';
164
165
  }
166
+ // dscode-frame-v1
165
167
  // dscode-email-v4
166
168
  import { createImapConnector as dscodeCreateImapConnector } from "./dscode-email/imap.mjs";
167
169
  import { createGmailConnector as dscodeCreateGmailConnector } from "./dscode-email/gmail.mjs";
@@ -458,45 +460,6 @@ function DscodeActivityLine({ entries, streaming, since, animated = true }) {
458
460
 
459
461
  // dscode-footer-v1
460
462
  import { footerFor as dscodeFooterFor } from "../../plugins/session-metrics/view.mjs";
461
- // dscode-ime-v1
462
- const dscodeImeAnchors = new WeakMap();
463
- function imePosition(anchor, height, columns) {
464
- if (!anchor?.node || anchor.active === false || !Number.isFinite(height) || height < 1) return;
465
- let x = anchor.column, y = anchor.row;
466
- for (let node = anchor.node; node; node = node.parentNode) {
467
- if (node.yogaNode) {
468
- x += node.yogaNode.getComputedLeft();
469
- y += node.yogaNode.getComputedTop();
470
- }
471
- }
472
- if (y < 0 || y >= height) return;
473
- return { up: height - Math.floor(y), column: Math.max(1, Math.min(columns || 80, Math.floor(x) + 1)) };
474
- }
475
- function imeWriter(stream, anchors) {
476
- const write = stream.write;
477
- let parked = false;
478
- const restore = () => {
479
- if (!parked) return;
480
- parked = false;
481
- write.call(stream, '\x1b8');
482
- };
483
- const wrapped = function (...args) { restore(); return write.apply(this, args); };
484
- if (stream.isTTY) stream.write = wrapped;
485
- return {
486
- park(height) {
487
- if (!stream.isTTY) return;
488
- restore();
489
- const target = imePosition(anchors.get(stream), height, stream.columns);
490
- if (!target) return;
491
- write.call(stream, `\x1b7\x1b[${target.up}A\x1b[${target.column}G`);
492
- parked = true;
493
- },
494
- dispose() {
495
- restore();
496
- if (stream.write === wrapped) stream.write = write;
497
- }
498
- };
499
- }
500
463
  // dscode-session-relay-v1
501
464
  function dscodeVisibleRelay(message) {
502
465
  return message.source.kind === "plugin" && message.source.plugin === "dscode-session-bridge" && message.source.form === "relay";
@@ -23732,7 +23695,6 @@ cliCursor.toggle = (force, writableStream) => {
23732
23695
  //#endregion
23733
23696
  //#region node_modules/.pnpm/ink@5.2.1_@types+react@18.3.31_react@18.3.1/node_modules/ink/build/log-update.js
23734
23697
  const create = (stream, { showCursor = false } = {}) => {
23735
- const ime = imeWriter(stream, dscodeImeAnchors);
23736
23698
  let previousLineCount = 0;
23737
23699
  let previousOutput = "";
23738
23700
  let hasHiddenCursor = false;
@@ -23742,11 +23704,12 @@ const create = (stream, { showCursor = false } = {}) => {
23742
23704
  hasHiddenCursor = true;
23743
23705
  }
23744
23706
  const output = str + "\n";
23745
- if (output === previousOutput) { ime.park(output.split("\n").length - 1); return; }
23707
+ if (output === previousOutput) return;
23746
23708
  previousOutput = output;
23747
- stream.write(eraseLines(previousLineCount) + output);
23748
- previousLineCount = output.split("\n").length;
23749
- ime.park(previousLineCount - 1);
23709
+ const dscodeLineCount = output.split("\n").length;
23710
+ const dscodePad = Math.max(0, previousLineCount - dscodeLineCount);
23711
+ stream.write(eraseLines(previousLineCount) + "\n".repeat(dscodePad) + output);
23712
+ previousLineCount = dscodePad + dscodeLineCount;
23750
23713
  };
23751
23714
  render.clear = () => {
23752
23715
  stream.write(eraseLines(previousLineCount));
@@ -23754,7 +23717,6 @@ const create = (stream, { showCursor = false } = {}) => {
23754
23717
  previousLineCount = 0;
23755
23718
  };
23756
23719
  render.done = () => {
23757
- ime.dispose();
23758
23720
  previousOutput = "";
23759
23721
  previousLineCount = 0;
23760
23722
  if (!showCursor) {
@@ -24412,7 +24374,7 @@ var Ink = class {
24412
24374
  this.options.stdout.write(staticOutput);
24413
24375
  this.log(output);
24414
24376
  }
24415
- if (!hasStaticOutput) this.throttledLog(output);
24377
+ if (!hasStaticOutput && output !== this.lastOutput) this.throttledLog(output);
24416
24378
  this.lastOutput = output;
24417
24379
  };
24418
24380
  render(node) {
@@ -35614,7 +35576,7 @@ function Header({ cwd = "", model = "", effort = "", animated = false }) {
35614
35576
  if (!full) return (0, import_react.createElement)(Box, { flexDirection: "column", paddingX: 2, marginBottom: 1 },
35615
35577
  (0, import_react.createElement)(Text, { wrap: "truncate-end" },
35616
35578
  (0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright), bold: true }, "❄ DSCODE"),
35617
- (0, import_react.createElement)(Text, { color: inkColor(getPalette().dim) }, " v0.7.11")),
35579
+ (0, import_react.createElement)(Text, { color: inkColor(getPalette().dim) }, " v0.7.12")),
35618
35580
  (0, import_react.createElement)(Text, { wrap: "truncate-end" }, truncateColumns(modelName + " · " + effortName, width)),
35619
35581
  (0, import_react.createElement)(Text, { color: inkColor(getPalette().dim), wrap: "truncate-end" }, welcomePath(cwd, width)));
35620
35582
  return (0, import_react.createElement)(Box, { flexDirection: "column", width, borderStyle: "round", borderColor: inkColor(getPalette().brand), paddingX: 1 },
@@ -35625,7 +35587,7 @@ function Header({ cwd = "", model = "", effort = "", animated = false }) {
35625
35587
  (0, import_react.createElement)(Box, { flexDirection: "column", width: detailsWidth, marginTop: 2 },
35626
35588
  (0, import_react.createElement)(Text, { color: inkColor(getPalette().text), bold: true }, "DSCODE"),
35627
35589
  (0, import_react.createElement)(Text, { color: inkColor(getPalette().brandDeep) }, "────────────"),
35628
- (0, import_react.createElement)(Text, { color: inkColor(getPalette().dim) }, "v0.7.11"),
35590
+ (0, import_react.createElement)(Text, { color: inkColor(getPalette().dim) }, "v0.7.12"),
35629
35591
  (0, import_react.createElement)(Text, { wrap: "truncate-end" }, truncateColumns(dscodePadEnd(dscodeT("welcome.model"), 9) + modelName, detailsWidth)),
35630
35592
  (0, import_react.createElement)(Text, { wrap: "truncate-end" }, truncateColumns(dscodePadEnd(dscodeT("welcome.effort"), 9) + effortName, detailsWidth)),
35631
35593
  (0, import_react.createElement)(Text, null, " "),
@@ -36058,7 +36020,7 @@ function StatusLine({ facts, stats, busy, columns, items, onRows, animated }) {
36058
36020
  items,
36059
36021
  language
36060
36022
  ]);
36061
- const statusRowCount = layout.row2.left.length > 0 ? 2 : 1;
36023
+ const statusRowCount = layout.row2.left.length > 0 || layout.row2.right.length > 0 ? 2 : 1;
36062
36024
  (0, import_react.useEffect)(() => {
36063
36025
  onRows?.(statusRowCount);
36064
36026
  }, [onRows, statusRowCount]);
@@ -38425,19 +38387,13 @@ function Input({ effortSurface, ultraPulse, active, frozen, frozenHint, busy, de
38425
38387
  const { stdout: inputStdout } = useStdout();
38426
38388
  const columns = inputStdout?.columns ?? 80;
38427
38389
  const inputTerminalRows = inputStdout?.rows ?? 30;
38428
- const dscodeImeStdout = inputStdout;
38429
- const dscodeImeState = (0, import_react.useRef)({});
38430
- const dscodeImeRef = (0, import_react.useCallback)(node => {
38431
- dscodeImeState.current.node = node;
38432
- if (node) dscodeImeAnchors.set(dscodeImeStdout, dscodeImeState.current);
38433
- else dscodeImeAnchors.delete(dscodeImeStdout);
38434
- }, [dscodeImeStdout]);
38435
38390
  const tabTitleRef = (0, import_react.useRef)(tabTitle);
38436
38391
  tabTitleRef.current = tabTitle;
38437
38392
  const editorColumns = Math.max(1, columns - 6);
38438
38393
  const stdin = useStdin().stdin;
38439
38394
  const focusReporting = isVsCodeTerminalEnv();
38440
38395
  const [value, setValue] = (0, import_react.useState)("");
38396
+ const dscodeShellDraft = String(value ?? "").startsWith("!");
38441
38397
  const [cursor, setCursor] = (0, import_react.useState)(0);
38442
38398
  const valueRef = (0, import_react.useRef)(value);
38443
38399
  const cursorRef = (0, import_react.useRef)(cursor);
@@ -38961,6 +38917,11 @@ function Input({ effortSurface, ultraPulse, active, frozen, frozenHint, busy, de
38961
38917
  setDismissedMenuValue(liveValue);
38962
38918
  return;
38963
38919
  }
38920
+ if (liveValue.startsWith("!")) {
38921
+ // Dropping the bang shifts every character left: keep the caret on the same letter.
38922
+ applyEdit({ value: liveValue.slice(1), cursor: Math.max(0, liveCursor - 1) });
38923
+ return;
38924
+ }
38964
38925
  if (hasNotice) {
38965
38926
  dismissNotice();
38966
38927
  return;
@@ -39407,7 +39368,7 @@ function Input({ effortSurface, ultraPulse, active, frozen, frozenHint, busy, de
39407
39368
  const tierActive = waveTier !== null;
39408
39369
  const tierHues = waveTier === null ? null : deepseekWaveHues(waveTier);
39409
39370
  const promptColor = tierHues === null ? inkColor(getPalette().brand) : inkColor(tierHues[0]);
39410
- const promptGlyph = submitMode === "steer" ? "↳" : waveTier === "flash" ? "›" : waveTier === "deepseek" ? "»" : "❯";
39371
+ const promptGlyph = dscodeShellDraft ? " " : submitMode === "steer" ? "↳" : waveTier === "flash" ? "›" : waveTier === "deepseek" ? "»" : "❯";
39411
39372
  const placeholderText = composerPlaceholder(submitMode);
39412
39373
  const editorViewModel = editorModel(value, editorColumns);
39413
39374
  const clampedCursor = clampCursor(value, cursor);
@@ -39417,11 +39378,10 @@ function Input({ effortSurface, ultraPulse, active, frozen, frozenHint, busy, de
39417
39378
  const currentEditorScroll = Math.min(Math.max(0, editorScrollRef.current), maxEditorScroll);
39418
39379
  const editorWindowStart = caret.row < currentEditorScroll ? caret.row : caret.row >= currentEditorScroll + editorWindowRows ? caret.row - editorWindowRows + 1 : currentEditorScroll;
39419
39380
  editorScrollRef.current = editorWindowStart;
39420
- Object.assign(dscodeImeState.current, { row: caret.row - editorWindowStart, column: 2 + caret.column, active: active && !frozen && !preparingImages });
39421
39381
  const editorRowCount = frozen ? 1 : editorWindowRows;
39422
39382
  (0, import_react.useEffect)(() => {
39423
- onEditorRows(editorRowCount);
39424
- }, [editorRowCount, onEditorRows]);
39383
+ onEditorRows(editorRowCount + (dscodeShellDraft && !frozen ? 1 : 0));
39384
+ }, [editorRowCount, dscodeShellDraft, frozen, onEditorRows]);
39425
39385
  const caretRowInWindow = Math.max(0, Math.min(caret.row - editorWindowStart, editorWindowRows - 1));
39426
39386
  useImeCursorAnchor(!frozen, imeCursorRowsUp({
39427
39387
  editorWindowRows,
@@ -39434,8 +39394,9 @@ function Input({ effortSurface, ultraPulse, active, frozen, frozenHint, busy, de
39434
39394
  }, [menuHeightRows, onMenuRows]);
39435
39395
  const bandWidth = Math.max(1, columns - 1);
39436
39396
  const bandBg = inkColor(getPalette().composerBand);
39437
- const bandFill = (consumed) => " ".repeat(Math.max(0, bandWidth - consumed));
39438
- const band = (content) => (0, import_react.createElement)(Box, {
39397
+ const dscodeBandFillWidth = dscodeShellDraft ? Math.max(0, bandWidth - 2) : bandWidth;
39398
+ const bandFill = (consumed) => " ".repeat(Math.max(0, dscodeBandFillWidth - consumed));
39399
+ const band = (content) => dscodeShellDraft ? (0, import_react.createElement)(Box, { flexDirection: "column", width: bandWidth, borderStyle: "round", borderColor: inkColor(getPalette().brandBright) }, content) : (0, import_react.createElement)(Box, {
39439
39400
  flexDirection: "column",
39440
39401
  width: bandWidth
39441
39402
  }, (0, import_react.createElement)(Text, { backgroundColor: bandBg }, " ".repeat(bandWidth)), content, (0, import_react.createElement)(Text, { backgroundColor: bandBg }, " ".repeat(bandWidth)));
@@ -39462,7 +39423,7 @@ function Input({ effortSurface, ultraPulse, active, frozen, frozenHint, busy, de
39462
39423
  }, (0, import_react.createElement)(Text, {
39463
39424
  color: promptColor,
39464
39425
  bold: tierActive ? true : void 0
39465
- }, submitMode === "steer" ? "↳ " : busy ? "… " : `${promptGlyph} `), frozenLine, bandFill(2 + visibleColumns(frozenLine))));
39426
+ }, dscodeShellDraft ? `${promptGlyph} ` : submitMode === "steer" ? "↳ " : busy ? "… " : `${promptGlyph} `), frozenLine, bandFill(2 + visibleColumns(frozenLine))));
39466
39427
  }
39467
39428
  const menu = (0, import_react.createElement)(CompletionMenu, {
39468
39429
  active: menuActive,
@@ -39482,7 +39443,7 @@ function Input({ effortSurface, ultraPulse, active, frozen, frozenHint, busy, de
39482
39443
  key: index,
39483
39444
  backgroundColor: bandBg,
39484
39445
  wrap: "truncate-end"
39485
- }, index === 0 ? preparingImages ? (0, import_react.createElement)(Text, {
39446
+ }, index === 0 ? dscodeShellDraft ? (0, import_react.createElement)(Text, { color: promptColor }, `${promptGlyph} `) : preparingImages ? (0, import_react.createElement)(Text, {
39486
39447
  color: inkColor(getPalette().warn),
39487
39448
  bold: true
39488
39449
  }, "… ") : submitMode === "steer" ? (0, import_react.createElement)(Text, {
@@ -39496,11 +39457,8 @@ function Input({ effortSurface, ultraPulse, active, frozen, frozenHint, busy, de
39496
39457
  inverse: cursorVisible || void 0
39497
39458
  }, parts.caret) : null, placeholder ? (0, import_react.createElement)(Text, { dimColor: true }, tail) : parts.after, bandFill(consumed)));
39498
39459
  }
39499
- const staticEditor = (0, import_react.createElement)(Box, {
39500
- flexDirection: "column",
39501
- ref: dscodeImeRef
39502
- }, ...editorRows);
39503
- return (0, import_react.createElement)(Box, { flexDirection: "column" }, menu, burstArmed ? (0, import_react.createElement)(ComposerRainbowBurst, {
39460
+ const staticEditor = (0, import_react.createElement)(Box, { flexDirection: "column" }, ...editorRows);
39461
+ return (0, import_react.createElement)(Box, { flexDirection: "column" }, menu, dscodeShellDraft ? (0, import_react.createElement)(Text, { color: inkColor(getPalette().brandBright) }, dscodeT("composer.shellMode")) : null, burstArmed ? (0, import_react.createElement)(ComposerRainbowBurst, {
39504
39462
  key: burstKey,
39505
39463
  active: !busy && !preparingImages && animations,
39506
39464
  onSettled: () => {
@@ -39802,7 +39760,7 @@ function App(props) {
39802
39760
  .then((response) => response.ok ? response.json() : void 0)
39803
39761
  .then((data) => {
39804
39762
  const latest = data?.version;
39805
- if (typeof latest === "string" && dscodeNewerVersion(latest, "0.7.11")) notify(dscodeT("update.available", { version: latest }), "warning");
39763
+ if (typeof latest === "string" && dscodeNewerVersion(latest, "0.7.12")) notify(dscodeT("update.available", { version: latest }), "warning");
39806
39764
  })
39807
39765
  .catch(() => {})
39808
39766
  .finally(() => clearTimeout(dscodeUpdateTimer));
@@ -39893,7 +39851,7 @@ function App(props) {
39893
39851
  * turn, `steer` joins the turn already running. Tab on an empty composer
39894
39852
  * flips it; the prompt glyph and the placeholder both name the current mode.
39895
39853
  */
39896
- const [submitMode, setSubmitMode] = (0, import_react.useState)("queue");
39854
+ const [submitMode, setSubmitMode] = (0, import_react.useState)("steer");
39897
39855
  const [diffView, setDiffView] = (0, import_react.useState)(void 0);
39898
39856
  const [reviewPickerOpen, setReviewPickerOpen] = (0, import_react.useState)(false);
39899
39857
  const [helpOpen, setHelpOpen] = (0, import_react.useState)(false);
@@ -40083,7 +40041,7 @@ function App(props) {
40083
40041
  menuRows,
40084
40042
  gutterRows: composerGutterRows,
40085
40043
  notice: notice !== void 0,
40086
- todo: transcriptVisible && view.todos.length > 0,
40044
+ todo: transcriptVisible && (view.todos.length > 0 || busy),
40087
40045
  agents: transcriptVisible && agentRows.length > 0
40088
40046
  });
40089
40047
  const streamingActive = view.streaming !== "" || showReasoning && view.streamingReasoning !== "";
@@ -40100,14 +40058,14 @@ function App(props) {
40100
40058
  ]);
40101
40059
  const liveBudget = busy || streamingActive ? Math.max(1, Math.floor((dynamicRows - dscodeCompactionRows) / 3)) : Math.max(0, dynamicRows - (deepDivingVisible ? Math.max(1, dscodeCompactionRows) : 0));
40102
40060
  const visibleLiveLines = liveBudget === 0 ? [] : allLiveLines.slice(-liveBudget);
40103
- const streamRows = Math.max(1, dynamicRows - visibleLiveLines.length);
40061
+ const streamRows = Math.max(1, dynamicRows - dscodeCompactionRows - visibleLiveLines.length);
40104
40062
  const reasoningRows = !showReasoning || view.streamingReasoning === "" || view.streaming !== "" ? 0 : streamRows;
40105
40063
  const answerRows = view.streaming === "" ? 0 : Math.max(1, streamRows - reasoningRows);
40106
40064
  const liveAudit = clampLiveAllocation({
40107
40065
  live: visibleLiveLines.length,
40108
40066
  reasoning: reasoningRows,
40109
40067
  answer: answerRows
40110
- }, dynamicRows);
40068
+ }, Math.max(0, dynamicRows - dscodeCompactionRows));
40111
40069
  if (liveAudit.warning !== void 0 && budgetWarnRef.current !== liveAudit.warning) {
40112
40070
  budgetWarnRef.current = liveAudit.warning;
40113
40071
  console.warn(`[dsh-code] ${liveAudit.warning}`);