dsh-super-code 0.3.9 → 0.3.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/README.en.md +36 -11
  2. package/README.md +36 -11
  3. package/client/index.js +168 -64
  4. package/cordis.patch.yml +3 -7
  5. package/docs/Changelog.md +59 -0
  6. package/docs/Compatibility.md +51 -3
  7. package/docs/EvaluationResults.md +21 -5
  8. package/docs/UsageGuide.md +48 -9
  9. package/docs/en/Changelog.md +59 -0
  10. package/docs/en/Compatibility.md +51 -3
  11. package/docs/en/EvaluationResults.md +21 -5
  12. package/docs/en/UsageGuide.md +48 -9
  13. package/lib/connection/directories.d.ts.map +1 -1
  14. package/lib/connection/directories.js +14 -5
  15. package/lib/connection/directories.js.map +1 -1
  16. package/lib/connection/guidance.d.ts.map +1 -1
  17. package/lib/connection/guidance.js +7 -0
  18. package/lib/connection/guidance.js.map +1 -1
  19. package/lib/connection/http.d.ts.map +1 -1
  20. package/lib/connection/http.js +59 -30
  21. package/lib/connection/http.js.map +1 -1
  22. package/lib/connection/service.d.ts +3 -0
  23. package/lib/connection/service.d.ts.map +1 -1
  24. package/lib/connection/service.js +82 -33
  25. package/lib/connection/service.js.map +1 -1
  26. package/lib/connection/store.d.ts +2 -0
  27. package/lib/connection/store.d.ts.map +1 -1
  28. package/lib/connection/store.js +95 -30
  29. package/lib/connection/store.js.map +1 -1
  30. package/lib/connection/tasks.d.ts +6 -3
  31. package/lib/connection/tasks.d.ts.map +1 -1
  32. package/lib/connection/tasks.js +125 -53
  33. package/lib/connection/tasks.js.map +1 -1
  34. package/lib/connection/types.d.ts +1 -0
  35. package/lib/connection/types.d.ts.map +1 -1
  36. package/lib/connection/types.js.map +1 -1
  37. package/lib/core/deletion-command.d.ts.map +1 -1
  38. package/lib/core/deletion-command.js +84 -23
  39. package/lib/core/deletion-command.js.map +1 -1
  40. package/lib/core/windows-runtime.d.ts +16 -0
  41. package/lib/core/windows-runtime.d.ts.map +1 -0
  42. package/lib/core/windows-runtime.js +123 -0
  43. package/lib/core/windows-runtime.js.map +1 -0
  44. package/lib/dsh/budget-settings.d.ts +2 -0
  45. package/lib/dsh/budget-settings.d.ts.map +1 -1
  46. package/lib/dsh/budget-settings.js +9 -3
  47. package/lib/dsh/budget-settings.js.map +1 -1
  48. package/lib/dsh/budgets.d.ts +2 -0
  49. package/lib/dsh/budgets.d.ts.map +1 -1
  50. package/lib/dsh/budgets.js +6 -0
  51. package/lib/dsh/budgets.js.map +1 -1
  52. package/lib/dsh/compaction.d.ts.map +1 -1
  53. package/lib/dsh/compaction.js +1 -0
  54. package/lib/dsh/compaction.js.map +1 -1
  55. package/lib/dsh/connection-history.d.ts.map +1 -1
  56. package/lib/dsh/connection-history.js +3 -0
  57. package/lib/dsh/connection-history.js.map +1 -1
  58. package/lib/dsh/connection-host.js +1 -1
  59. package/lib/dsh/connection-host.js.map +1 -1
  60. package/lib/dsh/connection.d.ts.map +1 -1
  61. package/lib/dsh/connection.js +24 -3
  62. package/lib/dsh/connection.js.map +1 -1
  63. package/lib/dsh/deletion-protection.d.ts.map +1 -1
  64. package/lib/dsh/deletion-protection.js +18 -10
  65. package/lib/dsh/deletion-protection.js.map +1 -1
  66. package/lib/dsh/index.d.ts.map +1 -1
  67. package/lib/dsh/index.js +6 -0
  68. package/lib/dsh/index.js.map +1 -1
  69. package/lib/dsh/official-budgets.d.ts.map +1 -1
  70. package/lib/dsh/official-budgets.js +15 -3
  71. package/lib/dsh/official-budgets.js.map +1 -1
  72. package/lib/dsh/official-windows-shell.d.ts +4 -0
  73. package/lib/dsh/official-windows-shell.d.ts.map +1 -0
  74. package/lib/dsh/official-windows-shell.js +128 -0
  75. package/lib/dsh/official-windows-shell.js.map +1 -0
  76. package/lib/dsh/preset-declaration.d.ts +3 -0
  77. package/lib/dsh/preset-declaration.d.ts.map +1 -1
  78. package/lib/dsh/preset-declaration.js +68 -45
  79. package/lib/dsh/preset-declaration.js.map +1 -1
  80. package/lib/dsh/preset-installation.d.ts +10 -7
  81. package/lib/dsh/preset-installation.d.ts.map +1 -1
  82. package/lib/dsh/preset-installation.js +66 -30
  83. package/lib/dsh/preset-installation.js.map +1 -1
  84. package/lib/dsh/preset-metadata.d.ts.map +1 -1
  85. package/lib/dsh/preset-metadata.js +2 -1
  86. package/lib/dsh/preset-metadata.js.map +1 -1
  87. package/lib/dsh/preset-recovery-runtime.d.ts +76 -0
  88. package/lib/dsh/preset-recovery-runtime.d.ts.map +1 -0
  89. package/lib/dsh/preset-recovery-runtime.js +322 -0
  90. package/lib/dsh/preset-recovery-runtime.js.map +1 -0
  91. package/lib/dsh/preset-recovery.d.ts +14 -0
  92. package/lib/dsh/preset-recovery.d.ts.map +1 -0
  93. package/lib/dsh/preset-recovery.js +140 -0
  94. package/lib/dsh/preset-recovery.js.map +1 -0
  95. package/lib/dsh/ptc-budget.d.ts.map +1 -1
  96. package/lib/dsh/ptc-budget.js +20 -10
  97. package/lib/dsh/ptc-budget.js.map +1 -1
  98. package/lib/dsh/windows-shell.d.ts +53 -0
  99. package/lib/dsh/windows-shell.d.ts.map +1 -0
  100. package/lib/dsh/windows-shell.js +196 -0
  101. package/lib/dsh/windows-shell.js.map +1 -0
  102. package/lib/long-memory.d.ts.map +1 -1
  103. package/lib/long-memory.js +3 -2
  104. package/lib/long-memory.js.map +1 -1
  105. package/lib/super-agent-usage.d.ts +2 -0
  106. package/lib/super-agent-usage.d.ts.map +1 -1
  107. package/lib/super-agent-usage.js +16 -11
  108. package/lib/super-agent-usage.js.map +1 -1
  109. package/lib/task-feedback-projection.d.ts +11 -0
  110. package/lib/task-feedback-projection.d.ts.map +1 -1
  111. package/lib/task-feedback-projection.js +37 -12
  112. package/lib/task-feedback-projection.js.map +1 -1
  113. package/package.json +21 -16
  114. package/presets/super-code/agent.cordis.yml +3 -7
  115. package/runtime/windows/README.md +45 -0
  116. package/runtime/windows/arm64-busybox.exe.gz +0 -0
  117. package/runtime/windows/bash.exe.gz +0 -0
  118. package/runtime/windows/grep.exe.gz +0 -0
  119. package/runtime/windows/licenses/BusyBox-LICENSE.txt +348 -0
  120. package/runtime/windows/licenses/GPL-3.0.txt +674 -0
  121. package/runtime/windows/licenses/LGPL-3.0.txt +165 -0
  122. package/runtime/windows/licenses/MSYS-COPYING.LIB +165 -0
  123. package/runtime/windows/licenses/MSYS-COPYING.RUNTIME +674 -0
  124. package/runtime/windows/licenses/PCRE-LICENCE.txt +93 -0
  125. package/runtime/windows/licenses/ncurses-COPYING.txt +29 -0
  126. package/runtime/windows/manifest.json +236 -0
  127. package/runtime/windows/msys-2.0.dll.gz +0 -0
  128. package/runtime/windows/msys-iconv-2.dll.gz +0 -0
  129. package/runtime/windows/msys-intl-8.dll.gz +0 -0
  130. package/runtime/windows/msys-pcre-1.dll.gz +0 -0
  131. package/runtime/windows/sources/busybox-w32-FRP-6354-g5f09fb446.tgz +0 -0
  132. package/runtime/windows/sources.json +45 -0
  133. package/runtime/windows/x64-busybox.exe.gz +0 -0
package/client/index.js CHANGED
@@ -173,11 +173,11 @@ function AgentMessage({ record, saved, t, toolName }) {
173
173
  if (event.currentTarget.open) saved.open.add(item.seq); else saved.open.delete(item.seq)
174
174
  } },
175
175
  React.createElement('summary', null, label, React.createElement(Glyph, { type: 'chevron' })),
176
- React.createElement(DetailText, { text: item.text, t }))
177
- : React.createElement(React.Fragment, null, label, React.createElement(DetailText, { text: item.text, t }))))
176
+ React.createElement(DetailText, { text: item.text, format: item.format, t }))
177
+ : React.createElement(React.Fragment, null, label, React.createElement(DetailText, { text: item.text, format: item.format, t }))))
178
178
  }
179
179
 
180
- /* Keep the native button and its refs/events; mount name bubbles outside clipped
180
+ /* Keep native controls and their refs/events; mount name bubbles outside clipped
181
181
  * panels, or in the active dialog's top layer. No host-private UI is needed. */
182
182
  let actionTooltipSequence = 0
183
183
  let actionTooltipDismiss = () => {}
@@ -188,7 +188,7 @@ function actionButtonText(children) {
188
188
  return actionButtonText(child.props.children)
189
189
  }).filter(Boolean).join(' ').replace(/\s+/g, ' ').trim()
190
190
  }
191
- const ActionButton = React.forwardRef(function ActionButton({ children, title, ...props }, forwardedRef) {
191
+ const ActionButton = React.forwardRef(function ActionButton({ as: Tag = 'button', children, title, ...props }, forwardedRef) {
192
192
  const button = useRef(null), pending = useRef(0), cleanup = useRef(() => {})
193
193
  const name = props['aria-label'] || title || actionButtonText(children)
194
194
  const attach = React.useCallback(node => {
@@ -244,7 +244,7 @@ const ActionButton = React.forwardRef(function ActionButton({ children, title, .
244
244
  }
245
245
  useEffect(() => { hide() }, [name])
246
246
  useEffect(() => () => hide(), [])
247
- return React.createElement('button', {
247
+ return React.createElement(Tag, {
248
248
  ...props, ref: attach, 'data-tooltip-name': name,
249
249
  onPointerEnter: event => {
250
250
  props.onPointerEnter?.(event)
@@ -268,6 +268,9 @@ const zh = {
268
268
  'feedback.source.record': '任务记录',
269
269
  'feedback.source.request': '用户原文',
270
270
  'feedback.latest': '本轮要求',
271
+ 'feedback.previous': '此前要求',
272
+ 'feedback.historicalStatus': '{status}(历史记录)',
273
+ 'feedback.historyPartial': '部分较早的要求或步骤未展示,完整记录见执行记录。',
271
274
  'feedback.progress': '步骤 {done} / {total}',
272
275
  'feedback.progressPartial': '已记录步骤 {done} / {total}',
273
276
  'feedback.steps': '步骤进度',
@@ -299,6 +302,13 @@ const zh = {
299
302
  'status.blocked': '受阻',
300
303
 
301
304
  'settings.homeTab': '首页', 'settings.presetTab': '预设配置', 'settings.protectionTab': '删除保护',
305
+ 'shell.title': '命令环境', 'shell.enabled': '使用内置 Bash(Windows)',
306
+ 'shell.hint': '无需安装 Git。新启动的会话生效,子 Agent 继承。Windows 限权模式下需由 DSH 逐条审批,不自动修改会话权限。',
307
+ 'shell.official': '同时应用到官方预设',
308
+ 'shell.officialHint': '用于标准、PTC、创建模式,默认关闭。极简模式保留原有持久终端;自定义预设不受影响。',
309
+ 'shell.windowsOnly': '仅 Windows 生效',
310
+ 'shell.host': '使用宿主命令环境', 'shell.pending': '首次使用时自动准备', 'shell.ready': '内置 Bash 已就绪',
311
+ 'shell.error': '内置 Bash 不可用,请关闭此开关使用宿主环境。', 'shell.otherPlatform': '当前宿主沿用系统命令环境,无需启用。',
302
312
  "connection.requestTitle": "请求访问工作目录",
303
313
  "connection.requestHint": "外部 MCP 客户端申请访问以下目录及其子目录。同意后会加入允许列表,后续委派仍使用 DSH 的权限设置。",
304
314
  "connection.requestClient": "请求客户端",
@@ -340,7 +350,7 @@ const zh = {
340
350
  'connection.tokenHint': '请将凭证安全保存在客户端。更换凭证后,旧凭证立即失效。',
341
351
  'connection.rotated': '已更换凭证,请更新客户端。', 'connection.copied': '已复制。',
342
352
  'connection.error.unavailable': '连接服务尚未就绪或当前配置目录不可写,请重新读取。', 'connection.error.invalid': '请检查端口、最大连接数和目录。启用连接至少需要一个有效目录。', 'connection.error.new-conversation-disabled': 'MCP 新增对话已关闭,请选择已有对话继续。',
343
- 'connection.error.conflict': '连接设置已在别处修改。草稿已保留,请重新读取。', 'connection.error.save-failed': '保存失败,草稿已保留。', 'connection.error.port-unavailable': '端口被占用或无法监听。请更换端口并保存。', 'connection.error.storage-unavailable': '任务状态保存失败,请检查配置目录。', 'connection.error.clipboard': '复制失败,请手动复制。',
353
+ 'connection.error.conflict': '连接设置已在别处修改。草稿已保留,请重新读取。', 'connection.error.save-failed': '保存失败,草稿已保留。', 'connection.error.port-unavailable': '端口被占用或无法监听。请更换端口,或稍后重试。', 'connection.error.cleanup-failed': '设置已保存,但连接清理失败。请点击“重试”恢复连接。', 'connection.error.storage-unavailable': '任务状态保存失败,请检查配置目录。', 'connection.error.clipboard': '复制失败,请手动复制。',
344
354
  'settings.contextTab': '上下文配置', 'settings.tabs': 'Super Code 配置',
345
355
  'budget.common': '通用预算', 'budget.superCode': 'Super Code 专属预算',
346
356
  'budget.applyToOfficialPresets': '同时应用到官方预设', 'budget.officialHint': '开启后,通用预算也用于标准、PTC、极简和创造模式;不包含下方的 Super Code 专属预算。',
@@ -381,6 +391,8 @@ const zh = {
381
391
  'workspace.title': 'Super Code', 'workspace.description': '任务状态、Agent 执行树与记忆库', 'workspace.resize': '调整执行树与记忆库高度',
382
392
  'tree.collapsedLabel': '已收起', 'tree.organizeLabel': '自动整理',
383
393
  'detail.toolCall': '工具调用', 'detail.toolResult': '工具结果', 'detail.toolError': '工具失败',
394
+ 'detail.authError': '模型身份验证失败,请检查模型配置。',
395
+ 'detail.copy': '复制', 'detail.copied': '已复制', 'detail.footnotes': '脚注',
384
396
  'detail.cache': '缓存', 'detail.info': '详情', 'tree.countCompact': '{shown}/{total} · 运行 {running}',
385
397
  'memory.loading': '正在读取记忆…', 'memory.topics': '知识主题', 'memory.allTopics': '全部主题', 'memory.related': '同主题知识', 'preset.configuration': '预设配置',
386
398
  'memory.title': '记忆', 'memory.project': '当前项目', 'memory.global': '全局偏好', 'memory.search': '搜索主题或记忆',
@@ -450,6 +462,9 @@ const en = {
450
462
  'feedback.source.record': 'Recorded objective',
451
463
  'feedback.source.request': 'User request',
452
464
  'feedback.latest': 'Latest request',
465
+ 'feedback.previous': 'Earlier request',
466
+ 'feedback.historicalStatus': '{status} (historical record)',
467
+ 'feedback.historyPartial': 'Some earlier requests or steps are omitted; open the execution log for the full record.',
453
468
  'feedback.progress': 'Steps {done} / {total}',
454
469
  'feedback.progressPartial': 'Recorded steps {done} / {total}',
455
470
  'feedback.steps': 'Step progress',
@@ -481,6 +496,13 @@ const en = {
481
496
  'status.blocked': 'Blocked',
482
497
 
483
498
  'settings.homeTab': 'Home', 'settings.presetTab': 'Preset configuration', 'settings.protectionTab': 'Deletion protection',
499
+ 'shell.title': 'Command environment', 'shell.enabled': 'Use bundled Bash (Windows)',
500
+ 'shell.hint': 'No Git installation required. Takes effect when a conversation starts; child Agents inherit it. Confined Windows modes require DSH approval for each command without changing session permissions.',
501
+ 'shell.official': 'Also apply to official presets',
502
+ 'shell.officialHint': 'Applies to Standard, PTC and Create; off by default. Minimal keeps its persistent terminal. Custom presets are unaffected.',
503
+ 'shell.windowsOnly': 'Only available on Windows',
504
+ 'shell.host': 'Using the host command environment', 'shell.pending': 'Prepared automatically on first use', 'shell.ready': 'Bundled Bash is ready',
505
+ 'shell.error': 'Bundled Bash is unavailable. Turn this off to use the host environment.', 'shell.otherPlatform': 'This host uses its existing command environment.',
484
506
  "connection.requestTitle": "Working directory access request",
485
507
  "connection.requestHint": "An external MCP client requests access to this directory and its descendants. Approval adds it to the allowlist. DSH permissions still apply to delegated tasks.",
486
508
  "connection.requestClient": "Requesting client",
@@ -522,7 +544,7 @@ const en = {
522
544
  'connection.tokenHint': 'Store the token securely in the client. Rotation invalidates the previous token immediately.',
523
545
  'connection.rotated': 'Token rotated. Update your client.', 'connection.copied': 'Copied.',
524
546
  'connection.error.unavailable': 'The service is not ready or the profile directory is not writable. Reload to retry.', 'connection.error.invalid': 'Check the port, maximum connections and directories. Enabling requires at least one valid directory.', 'connection.error.new-conversation-disabled': 'MCP new conversations are disabled. Choose an existing conversation to continue.',
525
- 'connection.error.conflict': 'Connection settings changed elsewhere. Your draft is retained; reload to continue.', 'connection.error.save-failed': 'Save failed. Your draft is retained.', 'connection.error.port-unavailable': 'The port is occupied or cannot be opened. Save with another port.', 'connection.error.storage-unavailable': 'Task state could not be saved. Check the profile directory.', 'connection.error.clipboard': 'Copy failed. Copy the text manually.',
547
+ 'connection.error.conflict': 'Connection settings changed elsewhere. Your draft is retained; reload to continue.', 'connection.error.save-failed': 'Save failed. Your draft is retained.', 'connection.error.port-unavailable': 'The port is occupied or cannot be opened. Choose another port or retry later.', 'connection.error.cleanup-failed': 'Settings were saved, but connection cleanup failed. Click Retry to restore the connection.', 'connection.error.storage-unavailable': 'Task state could not be saved. Check the profile directory.', 'connection.error.clipboard': 'Copy failed. Copy the text manually.',
526
548
  'settings.contextTab': 'Context settings', 'settings.tabs': 'Super Code settings',
527
549
  'budget.common': 'Common budgets', 'budget.superCode': 'Super Code budgets',
528
550
  'budget.applyToOfficialPresets': 'Also apply to official presets', 'budget.officialHint': 'Apply common budgets to Standard, PTC, Minimal and Create. Super Code task and memory limits below remain exclusive to Super Code.',
@@ -563,6 +585,8 @@ const en = {
563
585
  'workspace.title': 'Super Code', 'workspace.description': 'Task status, Agent tree and memory library', 'workspace.resize': 'Resize agent tree and memory library',
564
586
  'tree.collapsedLabel': 'Collapsed', 'tree.organizeLabel': 'Organize',
565
587
  'detail.toolCall': 'Tool call', 'detail.toolResult': 'Tool result', 'detail.toolError': 'Tool failed',
588
+ 'detail.authError': 'Model authentication failed. Check the model settings.',
589
+ 'detail.copy': 'Copy', 'detail.copied': 'Copied', 'detail.footnotes': 'Footnotes',
566
590
  'detail.cache': 'Cache', 'detail.info': 'Details', 'tree.countCompact': '{shown}/{total} · Running {running}',
567
591
  'memory.loading': 'Loading memories…', 'memory.topics': 'Knowledge topics', 'memory.allTopics': 'All topics', 'memory.related': 'More in this topic', 'preset.configuration': 'Preset configuration',
568
592
  'memory.title': 'Memory', 'memory.project': 'This project', 'memory.global': 'Global preferences', 'memory.search': 'Search topics or memories',
@@ -1010,19 +1034,24 @@ function FeedbackTools({ tools, t }) {
1010
1034
  function feedbackListItems(model, root, partial) {
1011
1035
  const items = []
1012
1036
  const add = (kind, key, data = {}, row) => items.push({ kind, key: JSON.stringify(key), row, ...data,
1013
- signature: JSON.stringify([kind, data.content, data.todo, data.tools, data.label, data.count,
1037
+ signature: JSON.stringify([kind, data.content, data.todo, data.historical, data.tools, data.label, data.count,
1014
1038
  data.file && [data.file.name, data.file.directory, [...data.file.operations]], kind === 'task' &&
1015
1039
  [row.title, row.owner, row.done, row.total, row.complete, row.taskStatus, row.facts?.phase, row.node.running]]) })
1016
1040
  for (const row of model.tasks) {
1017
1041
  const facts = row.facts
1018
1042
  add('task', [row.id, 'task'], {}, row)
1019
1043
  if (row.goal && row.goal !== row.title) add('text', [row.id, 'goal'], { content: row.goal }, row)
1020
- if (facts?.latestRequest && facts.latestRequest !== facts.request) add('request', [row.id, 'request'], { content: facts.latestRequest }, row)
1044
+ if (facts?.latestRequest && (facts.latestRequest !== row.title || facts.history?.length)) add('request', [row.id, 'request'], { content: facts.latestRequest }, row)
1021
1045
  row.todos.forEach((todo, index) => add('step', [row.id, 'step', index], { todo }, row))
1022
1046
  const tools = feedbackToolSummary(facts?.activities)
1023
1047
  if (tools.length) add('tools', [row.id, 'tools'], { tools }, row)
1024
1048
  if (!row.total && !tools.length) add('note', [row.id, 'empty'], { label: facts ? 'feedback.noSteps' : 'feedback.loading' }, row)
1025
1049
  if (facts?.omittedActivities) add('note', [row.id, 'recent'], { label: 'feedback.recentOnly' }, row)
1050
+ for (const previous of [...(facts?.history || [])].reverse()) {
1051
+ add('request', [row.id, 'history', previous.seq], { content: previous.request, historical: true }, row)
1052
+ previous.todos.forEach((todo, index) => add('step', [row.id, 'history', previous.seq, index], { todo, historical: true }, row))
1053
+ }
1054
+ if (facts?.omittedRequests || facts?.history?.some(previous => previous.omittedTodos)) add('note', [row.id, 'historyPartial'], { label: 'feedback.historyPartial' }, row)
1026
1055
  add('open', [row.id, 'open'], { focusable: !row.node.unavailable }, row)
1027
1056
  }
1028
1057
  if (root) {
@@ -1082,8 +1111,9 @@ function FeedbackRowContent({ item, root, openDetail, t }) {
1082
1111
  row.total > 0 && React.createElement('span', { className: 'dsh-super-code-feedback-count', 'aria-label': progressLabel, title: progressLabel }, `${row.done}/${row.total}${row.complete ? '' : '+'}`),
1083
1112
  row.total > 0 && row.complete && React.createElement('progress', { max: row.total, value: row.done, 'aria-label': text(t, 'feedback.steps') }))
1084
1113
  }
1085
- if (item.kind === 'step') return React.createElement('div', { className: 'dsh-super-code-feedback-step', 'data-step-state': item.todo.status },
1086
- React.createElement(FeedbackMark, { tone: item.todo.status === 'completed' ? 'success' : item.todo.status === 'in_progress' ? 'active' : 'pending', label: text(t, 'feedback.todo.' + item.todo.status) }),
1114
+ if (item.kind === 'step') return React.createElement('div', { className: 'dsh-super-code-feedback-step', 'data-step-state': item.todo.status, 'data-step-history': item.historical || undefined },
1115
+ React.createElement(FeedbackMark, { tone: item.todo.status === 'completed' ? 'success' : !item.historical && item.todo.status === 'in_progress' ? 'active' : 'pending',
1116
+ label: item.historical ? text(t, 'feedback.historicalStatus', { status: text(t, 'feedback.todo.' + item.todo.status) }) : text(t, 'feedback.todo.' + item.todo.status) }),
1087
1117
  React.createElement('span', null, item.todo.content))
1088
1118
  if (item.kind === 'tools') return React.createElement(FeedbackTools, { tools: item.tools, t })
1089
1119
  if (item.kind === 'open') return React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-feedback-open', disabled: !item.focusable,
@@ -1101,7 +1131,7 @@ function FeedbackRowContent({ item, root, openDetail, t }) {
1101
1131
  if (item.label === 'tree.empty') return React.createElement('p', { className: 'dsh-super-code-state', 'data-tone': 'empty' }, React.createElement(Glyph, { type: 'context' }), text(t, item.label))
1102
1132
  if (item.kind === 'note') return React.createElement('p', { className: 'dsh-super-code-feedback-muted' }, text(t, item.label))
1103
1133
  return React.createElement('p', { className: 'dsh-super-code-feedback-text' },
1104
- item.kind === 'request' && React.createElement('small', null, text(t, 'feedback.latest')), item.content)
1134
+ item.kind === 'request' && React.createElement('small', null, text(t, item.historical ? 'feedback.previous' : 'feedback.latest')), item.content)
1105
1135
  }
1106
1136
 
1107
1137
  /** One measured, variable-height viewport for tasks, steps, activity and files. */
@@ -1258,7 +1288,7 @@ function WorkspaceSectionToggle({ section, expanded, onToggle, children, t }) {
1258
1288
  React.createElement('strong', null, label), children)
1259
1289
  }
1260
1290
 
1261
- /** Accordion: at most one open view; clicking the open heading collapses it. Tab state retains drafts. */
1291
+ /** Accordion: exactly one open view. Tab state retains drafts across section switches. */
1262
1292
  function SuperCodeWorkspace(props) {
1263
1293
  const { tab } = props.useTabInfo()
1264
1294
  const address = typeof tab.navigation?.params?.memory === 'string' ? tab.navigation.params.memory : tab.contentId
@@ -1266,6 +1296,7 @@ function SuperCodeWorkspace(props) {
1266
1296
  const memoryTarget = memoryLibraryTarget(address, '')
1267
1297
  const saved = useMemo(() => {
1268
1298
  const value = props.workspaceStates.get(tab.signal) || { active: 'tasks' }
1299
+ if (!['tasks', 'tree', 'memory'].includes(value.active)) value.active = 'tasks'
1269
1300
  if (value.navigationKey !== navigationKey) {
1270
1301
  value.navigationKey = navigationKey
1271
1302
  if (memoryTarget.id) value.active = 'memory'
@@ -1273,11 +1304,11 @@ function SuperCodeWorkspace(props) {
1273
1304
  props.workspaceStates.set(tab.signal, value)
1274
1305
  return value
1275
1306
  }, [props.workspaceStates, tab.signal])
1276
- const [active, setActive] = useState(['tasks', 'tree', 'memory', ''].includes(saved.active) ? saved.active : 'tasks')
1307
+ const [active, setActive] = useState(saved.active)
1277
1308
  const layout = useRef(null), focusSection = useRef('')
1278
1309
  const toggle = section => {
1279
- const next = active === section ? '' : section
1280
- saved.active = next; focusSection.current = section; setActive(next)
1310
+ if (active === section) return
1311
+ saved.active = section; focusSection.current = section; setActive(section)
1281
1312
  }
1282
1313
  useLayoutEffect(() => {
1283
1314
  if (saved.navigationKey === navigationKey) return
@@ -1577,27 +1608,44 @@ function detailRecord(entry, t = key => zh[key] || key) {
1577
1608
  const base = { seq: event.seq, time: event.time, entry }
1578
1609
  if (event.type === 'user/message') {
1579
1610
  if (data.source?.kind !== 'user') return { kind: 'skip' }
1580
- return { ...base, kind: 'message', label: text(t, 'detail.task'), text: contentText(data.content, t) }
1581
- }
1582
- if (event.type === 'assistant/message') return { ...base, kind: 'message', label: data.interrupted ? text(t, 'detail.interrupted') : text(t, 'detail.agent'), text: contentText(data.message?.content, t) }
1583
- if (event.type === 'tool/call' && typeof data.name === 'string' && data.name) {
1584
- let value = typeof data.arguments === 'string' ? data.arguments : JSON.stringify(data.arguments ?? {})
1611
+ return { ...base, kind: 'message', format: 'text', label: text(t, 'detail.task'), text: contentText(data.content, t) }
1612
+ }
1613
+ if (event.type === 'assistant/message') return { ...base, kind: 'message', format: 'markdown', label: data.interrupted ? text(t, 'detail.interrupted') : text(t, 'detail.agent'), text: contentText(data.message?.content, t) }
1614
+ const nestedCall = event.type === 'tool/ptc-dispatch-start'
1615
+ if ((event.type === 'tool/call' || nestedCall) && typeof data.name === 'string' && data.name) {
1616
+ // Native arguments are raw JSON; PTC arguments are already decoded values.
1617
+ let value = !nestedCall && typeof data.arguments === 'string' ? data.arguments
1618
+ : JSON.stringify(data.arguments === undefined ? {} : data.arguments)
1585
1619
  try { value = JSON.stringify(JSON.parse(value), null, 2) } catch { /* Incomplete arguments remain readable. */ }
1586
- return { ...base, kind: 'tool', collapsed: true, toolName: data.name, callId: data.callId,
1620
+ return { ...base, kind: 'tool', format: 'json', collapsed: true, toolName: data.name,
1621
+ callId: nestedCall ? data.subCallId : data.callId, ...(nestedCall ? { parentCallId: data.parentCallId } : {}),
1587
1622
  label: text(t, 'detail.toolCall') + ' · ' + data.name, text: value }
1588
1623
  }
1624
+ if (event.type === 'tool/ptc-dispatch' && typeof data.name === 'string' && data.name) {
1625
+ return { ...base, kind: data.isError ? 'error' : 'tool', format: 'code', collapsed: true,
1626
+ callId: data.subCallId, parentCallId: data.parentCallId, toolName: data.name,
1627
+ label: text(t, data.isError ? 'detail.toolError' : 'detail.toolResult') + ' · ' + data.name,
1628
+ text: contentText(data.content, t) }
1629
+ }
1589
1630
  if (event.type === 'tool/result') {
1590
1631
  const blocks = (data.message?.content || []).filter(block => block.type === 'tool-result')
1591
1632
  // Harness journals use both direct tool messages (v4) and nested results.
1592
1633
  const direct = data.message?.role === 'tool'
1593
1634
  if (!blocks.length && !direct) return { kind: 'skip' }
1594
1635
  const failed = direct ? data.message.isError : blocks.some(block => block.isError)
1595
- return { ...base, kind: failed ? 'error' : 'tool', collapsed: true,
1636
+ return { ...base, kind: failed ? 'error' : 'tool', format: 'code', collapsed: true,
1596
1637
  callId: direct ? data.message.toolCallId : blocks[0]?.toolCallId,
1597
1638
  label: text(t, failed ? 'detail.toolError' : 'detail.toolResult'),
1598
1639
  text: contentText(direct ? data.message.content : blocks.flatMap(block => block.content || []), t) }
1599
1640
  }
1600
- if (event.type === 'turn/error') return { ...base, kind: 'error', label: text(t, 'detail.error'), text: data.message || text(t, 'detail.incomplete') }
1641
+ if (event.type === 'turn/end' && data.reason?.kind === 'error') {
1642
+ const failure = data.reason.error
1643
+ // Match the host's AUTH handling: provider diagnostics can echo credentials.
1644
+ const message = failure?.code === 'AUTH' ? text(t, 'detail.authError')
1645
+ : (typeof failure?.message === 'string' && failure.message) || text(t, 'detail.incomplete')
1646
+ return { ...base, kind: 'error', format: 'text', label: text(t, 'detail.error'), text: message }
1647
+ }
1648
+ if (event.type === 'turn/error') return { ...base, kind: 'error', format: 'text', label: text(t, 'detail.error'), text: data.message || text(t, 'detail.incomplete') }
1601
1649
  return { kind: 'skip' }
1602
1650
  }
1603
1651
 
@@ -1606,7 +1654,7 @@ function detailRecord(entry, t = key => zh[key] || key) {
1606
1654
  function createAgentInspector(createStream, address, readPage, initial, t = key => zh[key] || key) {
1607
1655
  let snapshot = initial || { status: 'loading', items: [], hasMore: false, earlier: false, truncated: false, projections: {}, error: '', firstSeq: 0, cursor: -1 }
1608
1656
  let cursor = snapshot.cursor
1609
- let disposed = false, stream
1657
+ let disposed = false, paging = false, stream
1610
1658
  const listeners = new Set()
1611
1659
  const publish = patch => {
1612
1660
  if (disposed) return
@@ -1620,7 +1668,7 @@ function createAgentInspector(createStream, address, readPage, initial, t = key
1620
1668
  if (disposed) return
1621
1669
  if (change.type === 'replace') {
1622
1670
  if (snapshot.earlier) {
1623
- publish({ status: 'ready', projections: change.page.projections?.values || {}, error: '' })
1671
+ publish({ status: paging ? 'paging' : 'ready', projections: change.page.projections?.values || {}, error: '' })
1624
1672
  return
1625
1673
  }
1626
1674
  const fresh = itemsOf(change.entries)
@@ -1629,7 +1677,7 @@ function createAgentInspector(createStream, address, readPage, initial, t = key
1629
1677
  // A resumed tail page can start later than the user's reading window.
1630
1678
  // Immutable journal records can be merged without moving that window.
1631
1679
  const items = overlaps ? [...new Map([...snapshot.items, ...fresh].map(item => [item.seq, item])).values()].sort((a, b) => a.seq - b.seq) : fresh
1632
- publish({ status: 'ready', items: items.slice(-200), hasMore: (overlaps ? snapshot.hasMore : change.hasMore) || items.length > 200, earlier: false, truncated: items.length > 200,
1680
+ publish({ status: paging ? 'paging' : 'ready', items: items.slice(-200), hasMore: (overlaps ? snapshot.hasMore : change.hasMore) || items.length > 200, earlier: false, truncated: items.length > 200,
1633
1681
  firstSeq: items.length > 200 ? items.at(-200).seq : overlaps ? snapshot.firstSeq : change.entries[0]?.event.seq ?? 0,
1634
1682
  cursor: change.entries.at(-1)?.event.seq ?? -1,
1635
1683
  projections: change.page.projections?.values || {}, error: '' })
@@ -1651,7 +1699,8 @@ function createAgentInspector(createStream, address, readPage, initial, t = key
1651
1699
  subscribe: listener => { listeners.add(listener); return () => listeners.delete(listener) },
1652
1700
  start: () => { stream.open({ maxMessages: 40 }).catch(() => publish({ status: 'error', error: 'detail.loadError' })) },
1653
1701
  older: async () => {
1654
- if (snapshot.status === 'paging' || !snapshot.hasMore) return
1702
+ if (disposed || paging || !snapshot.hasMore) return
1703
+ paging = true
1655
1704
  publish({ status: 'paging', error: '' })
1656
1705
  const throughSeq = cursor
1657
1706
  try {
@@ -1663,15 +1712,23 @@ function createAgentInspector(createStream, address, readPage, initial, t = key
1663
1712
  hasMore: result.value.hasMore || items.length > 200 })
1664
1713
  }
1665
1714
  catch { publish({ status: 'error', error: 'detail.historyError' }) }
1715
+ finally { paging = false }
1666
1716
  },
1667
1717
  dispose: () => { disposed = true; listeners.clear(); void stream.dispose() },
1668
1718
  }
1669
1719
  }
1670
1720
 
1671
- function DetailText({ text: value, t = key => zh[key] || key }) {
1721
+ function DetailText({ text: value, format = 'text', t = key => zh[key] || key }) {
1672
1722
  const [full, setFull] = useState(false)
1723
+ const copyLabel = text(t, 'detail.copy'), copiedLabel = text(t, 'detail.copied'), footnotes = text(t, 'detail.footnotes')
1724
+ const labels = useMemo(() => ({ code: { copyLabel, copiedLabel }, footnotes }), [copyLabel, copiedLabel, footnotes])
1725
+ const content = full ? value : value.slice(0, 12000)
1673
1726
  return React.createElement(React.Fragment, null,
1674
- React.createElement('pre', null, full ? value : value.slice(0, 12000)),
1727
+ React.createElement('div', { className: 'dsh-super-code-detail-content' },
1728
+ format === 'markdown' ? React.createElement(icons.MarkdownText, { text: content, labels })
1729
+ : format === 'json' || format === 'code' ? React.createElement(icons.CodeBlock, { code: content,
1730
+ lang: format === 'json' ? 'json' : 'text', copyLabel, copiedLabel })
1731
+ : React.createElement('pre', { className: 'dsh-super-code-detail-plain' }, content)),
1675
1732
  !full && value.length > 12000 && React.createElement(ActionButton, { type: 'button', onClick: () => setFull(true) }, text(t, 'detail.open')))
1676
1733
  }
1677
1734
 
@@ -1729,7 +1786,10 @@ function memoryLibraryWindow(items, query, top, height) {
1729
1786
 
1730
1787
  /** Drafts and in-flight operations survive the host unmounting a hidden tab. */
1731
1788
  function createMemoryEditor(saved, api) {
1732
- if (saved.editorStore) return saved.editorStore
1789
+ if (saved.editorStore) {
1790
+ saved.editorStore.bindApi(api)
1791
+ return saved.editorStore
1792
+ }
1733
1793
  let snapshot = { draft: null, confirmation: null, busy: false, error: '', refresh: 0 }
1734
1794
  const listeners = new Set()
1735
1795
  const update = patch => { snapshot = { ...snapshot, ...patch }; for (const listener of listeners) listener() }
@@ -1757,6 +1817,8 @@ function createMemoryEditor(saved, api) {
1757
1817
  }
1758
1818
  }
1759
1819
  saved.editorStore = { getSnapshot: () => snapshot, subscribe: listener => { listeners.add(listener); return () => listeners.delete(listener) },
1820
+ // The host may replace its Remote while the retained draft is still open.
1821
+ bindApi: value => { api = value },
1760
1822
  update, save: () => run('save', snapshot.draft), remove: () => run('remove', snapshot.confirmation) }
1761
1823
  return saved.editorStore
1762
1824
  }
@@ -2094,7 +2156,7 @@ const budgetFields = [
2094
2156
  ]
2095
2157
  function budgetDraft(configuration) {
2096
2158
  const deletion = configuration.deletionProtection
2097
- return Object.fromEntries([['deletionProtection', deletion === true ? 'strict' : deletion === false ? 'off' : deletion ?? 'relaxed'], ['deletionProtectionForOfficialPresets', configuration.deletionProtectionForOfficialPresets ?? false], ['applyToOfficialPresets', configuration.applyToOfficialPresets ?? false], ['pressureBasis', configuration.budgets?.pressureBasis ?? ''],
2159
+ return Object.fromEntries([['windowsBash', configuration.windowsBash ?? true], ['windowsBashForOfficialPresets', configuration.windowsBashForOfficialPresets ?? false], ['deletionProtection', deletion === true ? 'strict' : deletion === false ? 'off' : deletion ?? 'relaxed'], ['deletionProtectionForOfficialPresets', configuration.deletionProtectionForOfficialPresets ?? false], ['applyToOfficialPresets', configuration.applyToOfficialPresets ?? false], ['pressureBasis', configuration.budgets?.pressureBasis ?? ''],
2098
2160
  ...budgetFields.map(field => {
2099
2161
  const value = field.root ? configuration[field.key] : configuration.budgets?.[field.key]
2100
2162
  return [field.key, value === undefined ? '' : String(value / field.factor)]
@@ -2138,7 +2200,7 @@ function budgetConfiguration(draft) {
2138
2200
  * one callout style for notices, and one autosave indicator. */
2139
2201
  function SettingsSection({ id, title, description, actions, plain = false, children }) {
2140
2202
  const lines = [].concat(description ?? []).filter(Boolean)
2141
- return React.createElement('section', { className: 'dsh-super-code-section', 'aria-labelledby': `${id}-title` },
2203
+ return React.createElement('section', { id, className: 'dsh-super-code-section', 'aria-labelledby': `${id}-title` },
2142
2204
  React.createElement('header', { className: 'dsh-super-code-section-head' },
2143
2205
  React.createElement('div', { className: 'dsh-super-code-section-heading' },
2144
2206
  React.createElement('h3', { id: `${id}-title` }, title),
@@ -2179,12 +2241,15 @@ function ChoiceCards({ name, label, value, choices, onChange, disabled = false }
2179
2241
 
2180
2242
  /** Each budget tab writes only its own fields and carries the other tab's stored values through. */
2181
2243
  function budgetSectionConfiguration(section, draft, snapshot) {
2244
+ if (section === 'shell') return typeof draft.windowsBash === 'boolean' && typeof draft.windowsBashForOfficialPresets === 'boolean'
2245
+ ? { ok: true, configuration: { ...snapshot.configuration, windowsBash: draft.windowsBash, windowsBashForOfficialPresets: draft.windowsBashForOfficialPresets } }
2246
+ : { ok: false, error: 'invalid' }
2182
2247
  const parsed = budgetConfiguration(draft)
2183
2248
  if (!parsed.ok) return parsed
2184
2249
  const current = snapshot.configuration
2185
2250
  return { ok: true, configuration: section === 'protection'
2186
2251
  ? { ...current, deletionProtection: draft.deletionProtection, deletionProtectionForOfficialPresets: draft.deletionProtectionForOfficialPresets }
2187
- : { ...parsed.configuration, deletionProtection: current.deletionProtection, deletionProtectionForOfficialPresets: current.deletionProtectionForOfficialPresets } }
2252
+ : { ...parsed.configuration, windowsBash: current.windowsBash, windowsBashForOfficialPresets: current.windowsBashForOfficialPresets, deletionProtection: current.deletionProtection, deletionProtectionForOfficialPresets: current.deletionProtectionForOfficialPresets } }
2188
2253
  }
2189
2254
  function createBudgetAutosave(api, section = 'context') {
2190
2255
  return createAutosave(api, { draft: budgetDraft({}), toDraft: budgetDraft,
@@ -2207,6 +2272,7 @@ function autosaveState(editing) {
2207
2272
 
2208
2273
  function BudgetSettings({ api, t, active, section = 'context', onSaved = () => {} }) {
2209
2274
  const protection = section === 'protection'
2275
+ const shell = section === 'shell'
2210
2276
  const editor = useMemo(() => createBudgetAutosave(api, section), [api, section])
2211
2277
  const editing = useSyncExternalStore(editor.subscribe, editor.getSnapshot, editor.getSnapshot)
2212
2278
  const { snapshot, draft } = editing
@@ -2230,15 +2296,16 @@ function BudgetSettings({ api, t, active, section = 'context', onSaved = () => {
2230
2296
  const reset = async () => {
2231
2297
  setConfirmReset(false)
2232
2298
  if (pending.current) return
2233
- await editor.flush()
2234
- const current = editor.getSnapshot().snapshot
2235
- if (!alive.current || !current?.writable) return
2236
- const base = current.configuration
2237
- const configuration = protection
2238
- ? { ...base, deletionProtection: 'relaxed', deletionProtectionForOfficialPresets: false }
2239
- : { deletionProtection: base.deletionProtection, deletionProtectionForOfficialPresets: base.deletionProtectionForOfficialPresets }
2299
+ // Claim the whole operation, including the wait for an earlier autosave.
2240
2300
  pending.current = true; setLoading(true); setFailure(''); setNotice('')
2241
2301
  try {
2302
+ await editor.flush()
2303
+ const current = editor.getSnapshot().snapshot
2304
+ if (!alive.current || !current?.writable) return
2305
+ const base = current.configuration
2306
+ const configuration = protection
2307
+ ? { ...base, deletionProtection: 'relaxed', deletionProtectionForOfficialPresets: false }
2308
+ : { windowsBash: base.windowsBash, windowsBashForOfficialPresets: base.windowsBashForOfficialPresets, deletionProtection: base.deletionProtection, deletionProtectionForOfficialPresets: base.deletionProtectionForOfficialPresets }
2242
2309
  const response = await api.saveConfig(JSON.stringify(configuration), String(current.revision))
2243
2310
  if (!response.ok) throw new Error('Remote unavailable')
2244
2311
  if (!alive.current) return
@@ -2271,7 +2338,25 @@ function BudgetSettings({ api, t, active, section = 'context', onSaved = () => {
2271
2338
  const saveError = editing.error && !autosaveValidationErrors.includes(editing.error) ? editing.error : ''
2272
2339
  const problem = failure || saveError
2273
2340
  const button = (label, onClick, extra = {}) => React.createElement(ActionButton, { type: 'button', disabled: loading, onClick, ...extra }, label)
2274
- const content = protection ? React.createElement(React.Fragment, null,
2341
+ const shellStatus = snapshot?.shell
2342
+ const windowsHost = shellStatus?.platform === 'win32'
2343
+ const shellTooltip = shellStatus && !windowsHost ? t('shell.windowsOnly') : undefined
2344
+ const content = shell ? React.createElement(SettingsSection, { id: 'super-code-shell', title: t('shell.title') },
2345
+ React.createElement(SettingRow, { id: 'super-code-windows-bash', label: t('shell.enabled'),
2346
+ hint: !windowsHost ? t('shell.otherPlatform') : t('shell.hint') }, described =>
2347
+ React.createElement(ConnectionSwitch, { id: 'super-code-windows-bash', checked: draft.windowsBash,
2348
+ disabled: disabled || !windowsHost, tooltip: shellTooltip, 'aria-describedby': described,
2349
+ onChange: value => edit('windowsBash', value) })),
2350
+ React.createElement(SettingRow, { id: 'super-code-windows-bash-official', label: t('shell.official'), hint: t('shell.officialHint') }, described =>
2351
+ React.createElement(ConnectionSwitch, { id: 'super-code-windows-bash-official', checked: draft.windowsBashForOfficialPresets,
2352
+ disabled: disabled || !windowsHost || !draft.windowsBash, tooltip: shellTooltip, 'aria-describedby': described,
2353
+ onChange: value => edit('windowsBashForOfficialPresets', value) })),
2354
+ windowsHost && React.createElement('p', { className: 'dsh-super-code-shell-status', role: 'status' },
2355
+ React.createElement('span', null, t(!draft.windowsBash ? 'shell.host' : `shell.${shellStatus.state}`)),
2356
+ shellStatus.version && draft.windowsBash && React.createElement('code', null, shellStatus.version)),
2357
+ shellStatus?.state === 'error' && draft.windowsBash && React.createElement(Callout, { tone: 'error' },
2358
+ React.createElement('p', null, shellStatus.error)))
2359
+ : protection ? React.createElement(React.Fragment, null,
2275
2360
  React.createElement(SettingsSection, { id: 'super-code-deletion-mode', title: t('delete.mode'), plain: true },
2276
2361
  React.createElement(ChoiceCards, { name: 'super-code-deletion-mode', label: t('delete.mode'), value: draft.deletionProtection, disabled,
2277
2362
  choices: ['off', 'relaxed', 'strict'].map(mode => [mode, t(`delete.${mode}`), t(`delete.hint.${mode}`)]),
@@ -2299,7 +2384,7 @@ function BudgetSettings({ api, t, active, section = 'context', onSaved = () => {
2299
2384
  snapshot?.ptcMaxTimeoutMs && text(t, 'budget.ptcCeiling', { seconds: snapshot.ptcMaxTimeoutMs / 1000 })] }, ...rows('execution')),
2300
2385
  React.createElement(SettingsSection, { id: 'super-code-budget-exclusive', title: t('budget.superCode'), description: t('budget.superCodeHint') }, ...rows('superCode')))
2301
2386
  return React.createElement('section', { className: 'dsh-super-code-budgets' },
2302
- React.createElement('form', { className: 'dsh-super-code-stack', 'aria-label': t(protection ? 'delete.title' : 'budget.title'), 'aria-busy': loading || editing.saving,
2387
+ React.createElement('form', { className: 'dsh-super-code-stack', 'aria-label': t(shell ? 'shell.title' : protection ? 'delete.title' : 'budget.title'), 'aria-busy': loading || editing.saving,
2303
2388
  onSubmit: event => { event.preventDefault(); void editor.flush() } },
2304
2389
  problem && React.createElement(Callout, { tone: 'error',
2305
2390
  action: failure === 'connection' || problem === 'conflict' ? button(t('budget.reload'), () => load(true))
@@ -2310,7 +2395,7 @@ function BudgetSettings({ api, t, active, section = 'context', onSaved = () => {
2310
2395
  content,
2311
2396
  React.createElement('div', { className: 'dsh-super-code-settings-footer' },
2312
2397
  React.createElement(SaveIndicator, { state: autosaveState(editing), t }),
2313
- React.createElement('div', { className: 'dsh-super-code-settings-footer-actions' },
2398
+ !shell && React.createElement('div', { className: 'dsh-super-code-settings-footer-actions' },
2314
2399
  confirmReset ? React.createElement(React.Fragment, null,
2315
2400
  React.createElement('span', null, t('budget.resetQuestion')),
2316
2401
  button(t('preset.cancel'), () => setConfirmReset(false)),
@@ -2424,9 +2509,11 @@ function createConnectionAutosave(api) {
2424
2509
  return createAutosave(api, { draft: connectionDraft({ enabled: false, port: 23457, allowedDirectories: [] }),
2425
2510
  toDraft: connectionDraft, toConfiguration: draft => connectionConfiguration(draft) })
2426
2511
  }
2427
- /** The single switch control for every settings toggle; extra props go to the input. */
2428
- function ConnectionSwitch({ checked, disabled, onChange, children, ...input }) {
2429
- return React.createElement('label', { className: 'dsh-super-code-connection-switch' },
2512
+ /** Disabled inputs do not receive hover; their label hosts the shared top-side tooltip. */
2513
+ function ConnectionSwitch({ checked, disabled, onChange, children, tooltip, ...input }) {
2514
+ return React.createElement(tooltip ? ActionButton : 'label', {
2515
+ className: 'dsh-super-code-connection-switch', ...(tooltip ? { as: 'label', title: tooltip } : {}),
2516
+ },
2430
2517
  React.createElement('input', { ...input, type: 'checkbox', role: 'switch', checked, disabled, onChange: event => onChange(event.target.checked) }),
2431
2518
  React.createElement('span', { className: 'dsh-super-code-connection-track', 'aria-hidden': true }, React.createElement('i')), children)
2432
2519
  }
@@ -2505,7 +2592,7 @@ function ConnectionSettings({ api, t, active, openSession, onSaved = () => {} })
2505
2592
  const editor = useMemo(() => createConnectionAutosave(api), [api])
2506
2593
  const editing = useSyncExternalStore(editor.subscribe, editor.getSnapshot, editor.getSnapshot)
2507
2594
  const { snapshot, draft, saving } = editing
2508
- const [catalog, setCatalog] = useState({ items: [], picker: 'unavailable' }), [custom, setCustom] = useState([]), [browser, setBrowser] = useState(false)
2595
+ const [catalog, setCatalog] = useState({ items: [], picker: 'unavailable' }), [browser, setBrowser] = useState(false)
2509
2596
  const [busy, setBusy] = useState(false), [error, setError] = useState(''), [notice, setNotice] = useState(''), [token, setToken] = useState('')
2510
2597
  const alive = useRef(false), pending = useRef(false), visible = useRef(active)
2511
2598
  visible.current = active
@@ -2565,7 +2652,7 @@ function ConnectionSettings({ api, t, active, openSession, onSaved = () => {} })
2565
2652
  const edit = (key, value) => change({ [key]: value }, ['port', 'maxConnections'].includes(key) ? 350 : 0)
2566
2653
  const choose = path => {
2567
2654
  if (!draft.allowedDirectories.includes(path) && draft.allowedDirectories.length >= 32) { setError('directory-limit'); return }
2568
- setCustom(rows => [...new Set([...rows, path])]); change({ allowedDirectories: [...new Set([...draft.allowedDirectories, path])], knownDirectories: [...new Set([...draft.knownDirectories, path])].slice(-128) }); setNotice(''); setError(''); setBrowser(false)
2655
+ change({ allowedDirectories: [...new Set([...draft.allowedDirectories, path])], knownDirectories: [...new Set([...draft.knownDirectories, path])].slice(-128) }); setNotice(''); setError(''); setBrowser(false)
2569
2656
  }
2570
2657
  const addDirectory = async () => {
2571
2658
  if (pending.current) return
@@ -2579,7 +2666,7 @@ function ConnectionSettings({ api, t, active, openSession, onSaved = () => {} })
2579
2666
  finally { pending.current = false; if (alive.current) setBusy(false) }
2580
2667
  }
2581
2668
  const rows = [...catalog.items]
2582
- for (const path of [...custom, ...draft.knownDirectories, ...draft.allowedDirectories]) if (!rows.some(row => row.path === path)) rows.push({ path, title: '', available: true, workspace: false })
2669
+ for (const path of [...draft.knownDirectories, ...draft.allowedDirectories]) if (!rows.some(row => row.path === path)) rows.push({ path, title: '', available: true, workspace: false })
2583
2670
  const copy = async value => {
2584
2671
  try { await navigator.clipboard.writeText(value); if (alive.current) { setNotice('copied'); setError('') } }
2585
2672
  catch { if (alive.current) setError('clipboard') }
@@ -2590,7 +2677,10 @@ function ConnectionSettings({ api, t, active, openSession, onSaved = () => {} })
2590
2677
  React.createElement('p', { className: 'dsh-super-code-preset-status', role: 'status', 'data-available': snapshot?.state === 'listening' },
2591
2678
  React.createElement('i', { 'aria-hidden': true }), t(`connection.state.${snapshot?.state || 'loading'}`)),
2592
2679
  React.createElement('div', { className: 'dsh-super-code-settings-actions' }, React.createElement(ActionButton, { type: 'button', disabled: busy, onClick: () => load(true) }, t('connection.reload')))),
2593
- snapshot?.error && React.createElement('p', { role: 'alert' }, t(`connection.error.${snapshot.error}`)),
2680
+ snapshot?.error && React.createElement('div', { className: 'dsh-super-code-settings-actions' },
2681
+ React.createElement('p', { role: 'alert' }, t(`connection.error.${snapshot.error}`)),
2682
+ snapshot.state === 'error' && React.createElement(ActionButton, { type: 'button', disabled: disabled || dirty,
2683
+ onClick: () => { if (!disabled && !editor.hasChanges()) change({}) } }, t('save.retry'))),
2594
2684
  React.createElement(ConnectionActivity, { api, t, active, openSession }),
2595
2685
  React.createElement('form', { 'aria-label': t('connection.title'), 'aria-busy': saving, onSubmit: event => { event.preventDefault(); void editor.flush() } },
2596
2686
  React.createElement(ConnectionSwitch, { checked: draft.enabled, disabled, onChange: value => edit('enabled', value) }, t('connection.enabled')),
@@ -2617,7 +2707,7 @@ function ConnectionSettings({ api, t, active, openSession, onSaved = () => {} })
2617
2707
  React.createElement('span', null, row.title && React.createElement('strong', null, row.title), React.createElement('code', null, row.path),
2618
2708
  React.createElement('small', { 'data-unavailable': !row.available }, t(!row.available ? 'connection.directoryUnavailable' : row.workspace ? 'connection.workspaceDirectory' : 'connection.customDirectory')))),
2619
2709
  !row.workspace && React.createElement(ActionButton, { type: 'button', disabled, 'aria-label': `${t('connection.removeDirectory')}: ${row.path}`,
2620
- onClick: () => { setCustom(values => values.filter(path => path !== row.path)); setCatalog(value => ({ ...value, items: value.items.filter(item => item.path !== row.path) })); change({ knownDirectories: draft.knownDirectories.filter(path => path !== row.path), allowedDirectories: draft.allowedDirectories.filter(path => path !== row.path) }) } }, t('preset.remove')))),
2710
+ onClick: () => { setCatalog(value => ({ ...value, items: value.items.filter(item => item.path !== row.path) })); change({ knownDirectories: draft.knownDirectories.filter(path => path !== row.path), allowedDirectories: draft.allowedDirectories.filter(path => path !== row.path) }) } }, t('preset.remove')))),
2621
2711
  !rows.length && React.createElement('p', null, t('connection.noDirectories'))),
2622
2712
  React.createElement('div', { className: 'dsh-super-code-settings-actions' },
2623
2713
  React.createElement(ActionButton, { type: 'button', disabled: disabled || catalog.picker === 'unavailable', onClick: addDirectory }, t('connection.addDirectory'))),
@@ -2634,7 +2724,10 @@ function ConnectionSettings({ api, t, active, openSession, onSaved = () => {} })
2634
2724
  active && token && React.createElement('input', { className: 'dsh-super-code-connection-token', 'aria-label': t('connection.token'), value: token, readOnly: true, autoComplete: 'off', spellCheck: false }),
2635
2725
  React.createElement('small', null, t('connection.tokenHint'))),
2636
2726
  notice && React.createElement('p', { role: 'status' }, t(`connection.${notice}`)),
2637
- (error || editing.error) && React.createElement('p', { role: 'alert' }, t(`connection.error.${error || editing.error}`)),
2727
+ (error || editing.error) && React.createElement('div', { className: 'dsh-super-code-settings-actions' },
2728
+ React.createElement('p', { role: 'alert' }, t(`connection.error.${error || editing.error}`)),
2729
+ !error && editing.error === 'save-failed' && React.createElement(ActionButton, { type: 'button', disabled: disabled || saving,
2730
+ onClick: () => { if (!disabled && !editor.getSnapshot().saving) void editor.retry() } }, t('save.retry'))),
2638
2731
  browser && React.createElement(DirectoryBrowser, { api, t, onSelect: choose, onClose: () => setBrowser(false) }))
2639
2732
  }
2640
2733
 
@@ -2659,7 +2752,7 @@ function SegmentedControl({ label, value, choices, onChange, disabled = false, b
2659
2752
  }
2660
2753
  function SettingsHome({ budgetApi, connectionApi, t, active, revision, navigate, children }) {
2661
2754
  const [budget, setBudget] = useState(null), [connection, setConnection] = useState(null), [overview, setOverview] = useState({ connections: [], sessions: [] })
2662
- // `saving` keeps the chosen value on screen until the reread confirms it.
2755
+ // Keep the choice visible until the save is acknowledged.
2663
2756
  const [saving, setSaving] = useState(null), [failure, setFailure] = useState('')
2664
2757
  const alive = useRef(false), request = useRef(0), loading = useRef(false), writing = useRef(false)
2665
2758
  const load = async (force = false) => {
@@ -2688,6 +2781,10 @@ function SettingsHome({ budgetApi, connectionApi, t, active, revision, navigate,
2688
2781
  const configuration = kind === 'protection' ? { ...current.configuration, deletionProtection: value } : { ...current.configuration, enabled: value }
2689
2782
  const response = await (kind === 'protection' ? budgetApi : connectionApi).saveConfig(JSON.stringify(configuration), String(current.revision))
2690
2783
  saved = Boolean(response.ok && response.value.ok)
2784
+ if (saved && alive.current) {
2785
+ if (kind === 'protection') setBudget(response.value.snapshot)
2786
+ else setConnection(response.value.snapshot)
2787
+ }
2691
2788
  } catch { /* Reported on the row below. */ }
2692
2789
  if (saved && alive.current) await load(true)
2693
2790
  writing.current = false
@@ -2902,7 +2999,8 @@ function PresetSettings({ api, budgetApi, connectionApi, openSession = () => {},
2902
2999
  status?.userConflict && status.state !== 'conflict' && React.createElement('p', null, t('preset.userConflict')),
2903
3000
  status?.delivery === 'declaration' && !status.authorable && React.createElement('p', { role: 'note' }, t('preset.declaredReadonly')),
2904
3001
  status?.delivery === 'directory' && !status.authorable && React.createElement('p', { role: 'note' }, t('preset.readonly'))),
2905
- error && React.createElement('p', { role: 'alert' }, t(error))),
3002
+ error && React.createElement('p', { role: 'alert' }, t(error)),
3003
+ React.createElement(BudgetSettings, { api: budgetApi, t, section: 'shell', active: tab === 'preset', onSaved })),
2906
3004
  React.createElement('div', { role: 'tabpanel', id: 'super-code-panel-context', 'aria-labelledby': 'super-code-tab-context', hidden: tab !== 'context' },
2907
3005
  React.createElement(BudgetSettings, { api: budgetApi, t, active: tab === 'context', onSaved })),
2908
3006
  React.createElement('div', { role: 'tabpanel', id: 'super-code-panel-protection', 'aria-labelledby': 'super-code-tab-protection', hidden: tab !== 'protection' },
@@ -3078,6 +3176,12 @@ function apply(ctx) {
3078
3176
  .dsh-super-code-setting-row-control{display:flex;justify-content:flex-end;min-width:0}
3079
3177
  .dsh-super-code-setting-row-control>:is(input,.dsh-super-code-select){width:180px}
3080
3178
  .dsh-super-code-setting-row-control>input{height:32px;padding:5px 10px;border-radius:8px;font-variant-numeric:tabular-nums;text-align:right}
3179
+ .dsh-super-code-shell-status{display:flex;align-items:baseline;flex-wrap:wrap;gap:4px 8px;margin:0;padding:12px 16px;border-top:1px solid var(--sc-line);color:var(--sc-muted);font-size:12px;line-height:1.6;overflow-wrap:anywhere}
3180
+ .dsh-super-code-shell-status code{max-width:100%;font-size:11px}
3181
+ #super-code-shell .dsh-super-code-connection-switch:has(input:disabled){cursor:not-allowed}
3182
+ #super-code-shell .dsh-super-code-connection-switch input:disabled{pointer-events:none}
3183
+ #super-code-shell .dsh-super-code-connection-switch input:disabled+.dsh-super-code-connection-track{background:var(--sc-line);border-color:var(--sc-line);opacity:1}
3184
+ #super-code-shell .dsh-super-code-connection-switch input:disabled+.dsh-super-code-connection-track i{background:var(--sc-muted)}
3081
3185
  .dsh-super-code-setting-row[data-invalid] input{border-color:var(--sc-error)}
3082
3186
  .dsh-super-code-settings input[type=number]{appearance:textfield}
3083
3187
  .dsh-super-code-settings input::-webkit-inner-spin-button{appearance:none}
@@ -3318,7 +3422,7 @@ function apply(ctx) {
3318
3422
  .dsh-super-code-feedback-step[data-step-state=completed]{color:var(--sc-muted)}
3319
3423
  .dsh-super-code-feedback-step[data-step-state=completed]>span:last-child{text-decoration:line-through;text-decoration-color:color-mix(in srgb,var(--sc-muted) 40%,transparent)}
3320
3424
  .dsh-super-code-feedback-step[data-step-state=pending]{color:var(--sc-muted)}
3321
- .dsh-super-code-feedback-step[data-step-state=in_progress]{background:color-mix(in srgb,var(--sc-accent) 7%,transparent);box-shadow:inset 2px 0 color-mix(in srgb,var(--sc-accent) 55%,transparent);color:var(--sc-text)}
3425
+ .dsh-super-code-feedback-step[data-step-state=in_progress]:not([data-step-history]){background:color-mix(in srgb,var(--sc-accent) 7%,transparent);box-shadow:inset 2px 0 color-mix(in srgb,var(--sc-accent) 55%,transparent);color:var(--sc-text)}
3322
3426
  .dsh-super-code-feedback-mark{position:relative;display:inline-flex;align-items:center;justify-content:center;flex:none;width:14px;height:14px;margin-top:3px;color:var(--sc-muted);font-size:11px;line-height:14px}
3323
3427
  .dsh-super-code-feedback-mark>svg{width:14px;height:14px}
3324
3428
  .dsh-super-code-feedback-mark.pending:before,.dsh-super-code-feedback-mark.idle:before,.dsh-super-code-feedback-mark.unavailable:before{content:"";width:7px;height:7px;border:1px solid var(--sc-faint);border-radius:50%}
@@ -3595,8 +3699,8 @@ function apply(ctx) {
3595
3699
  .dsh-super-code-detail-entry-label>span{min-width:0;overflow-wrap:anywhere}
3596
3700
  .dsh-super-code-detail-entry.user .dsh-super-code-detail-entry-label{color:var(--sc-accent)}
3597
3701
  .dsh-super-code-detail-entry time{flex:none;font-family:var(--sc-mono);font-size:11px;font-weight:400;color:var(--sc-faint)}
3598
- .dsh-super-code-detail-entry pre{min-width:0;font:inherit;font-size:14px;line-height:1.75;white-space:pre-wrap;overflow-wrap:anywhere;margin:6px 0 0}
3599
- .dsh-super-code-detail-entry.tool pre{font-family:var(--sc-mono);font-size:12px;line-height:1.6;color:var(--sc-muted)}
3702
+ .dsh-super-code-detail-content{min-width:0;margin-top:6px}
3703
+ .dsh-super-code-detail-plain{min-width:0;font:inherit;font-size:14px;line-height:1.75;white-space:pre-wrap;overflow-wrap:anywhere;margin:0}
3600
3704
  .dsh-super-code-detail-message>details{min-width:0;color:var(--sc-muted)}
3601
3705
  .dsh-super-code-detail-message>details[open]{color:var(--sc-text)}
3602
3706
  .dsh-super-code-detail-message summary{display:flex;align-items:center;gap:6px;cursor:pointer;overflow-wrap:anywhere;list-style:none}
@@ -3604,8 +3708,8 @@ function apply(ctx) {
3604
3708
  .dsh-super-code-detail-message summary .dsh-super-code-detail-entry-label{flex:1;min-width:0;font-size:12px}
3605
3709
  .dsh-super-code-detail-message summary>.dsh-super-code-glyph{width:14px;height:14px;transition:transform .12s}
3606
3710
  .dsh-super-code-detail-message details[open] summary>.dsh-super-code-glyph{transform:rotate(180deg)}
3607
- .dsh-super-code-detail-message details pre{margin-top:10px;padding:8px 10px;border:1px solid var(--sc-line);border-radius:7px;background:var(--sc-bg)}
3608
- .dsh-super-code-detail-entry button{margin:8px 0 0}
3711
+ .dsh-super-code-detail-message details .dsh-super-code-detail-content{margin-top:10px}
3712
+ .dsh-super-code-detail-message>button,.dsh-super-code-detail-message>details>button{margin:8px 0 0}
3609
3713
  .dsh-super-code-new-content{flex:none;align-self:center;margin:8px 16px 12px;border:1px solid var(--sc-line);border-radius:8px;padding:6px 12px;background:var(--sc-bg);font-size:13px}
3610
3714
  @media(hover:none) and (pointer:coarse){:where(.dsh-super-code-workspace,.dsh-super-code-settings,.dsh-super-code-memory,.dsh-super-code-tree) input{font-size:16px}}
3611
3715
  @media(prefers-reduced-motion:reduce){:where(.dsh-super-code-workspace,.dsh-super-code-settings,.dsh-super-code-tree,.dsh-super-code-detail,.dsh-super-code-memory,.dsh-super-code-confirm,.dsh-super-code-select) *{transition:none!important;animation:none!important}.dsh-super-code-graph-node>.dsh-super-code-circle:after{animation:none!important}}
@@ -3632,9 +3736,9 @@ function apply(ctx) {
3632
3736
 
3633
3737
  /* Shared action-name bubble. Fixed outside the panel avoids graph transforms
3634
3738
  * and scroll clipping; dialog bubbles remain in the modal's top layer. */
3635
- .dsh-super-code-tooltip{position:fixed;z-index:1400;max-width:min(260px,calc(100vw - 16px));padding:5px 8px;border-radius:6px;background:var(--sc-text);color:var(--sc-bg);box-shadow:0 2px 8px #0002;font-size:12px;line-height:1.5;font-weight:400;text-align:left;overflow-wrap:anywhere;pointer-events:none}
3636
- .dsh-super-code-tooltip:after{content:"";position:absolute;left:var(--sc-tooltip-arrow-left);width:6px;height:6px;background:inherit;transform:translateX(-50%) rotate(45deg)}
3637
- .dsh-super-code-tooltip[data-side=top]:after{bottom:-3px}
3739
+ .dsh-super-code-tooltip{position:fixed;z-index:1400;max-width:min(260px,calc(100vw - 16px));padding:5px 8px;border:1px solid var(--sc-line);border-radius:6px;background:var(--sc-bg);color:var(--sc-text);box-shadow:0 2px 8px var(--sc-shadow);font-size:12px;line-height:1.5;font-weight:400;text-align:left;overflow-wrap:anywhere;pointer-events:none}
3740
+ .dsh-super-code-tooltip:after{content:"";position:absolute;left:var(--sc-tooltip-arrow-left);width:7px;height:7px;box-sizing:border-box;background:inherit;border-right:1px solid var(--sc-line);border-bottom:1px solid var(--sc-line);transform:translateX(-50%) rotate(45deg)}
3741
+ .dsh-super-code-tooltip[data-side=top]:after{bottom:-4px}
3638
3742
  `
3639
3743
  document.head.appendChild(style)
3640
3744
  return () => { style.remove() }
@@ -3695,5 +3799,5 @@ function apply(ctx) {
3695
3799
  ctx.effect(() => disposeMemoryType, 'super-code: memory library tab')
3696
3800
  }
3697
3801
 
3698
- return { inject, apply, taskFeedbackRows, feedbackStatus, feedbackListItems, feedbackListLayout, feedbackListIndex, feedbackListWindow, feedbackListAnchor, connectionSessions, createConnectionAutosave, connectionDraft, connectionConfiguration, budgetDraft, budgetConfiguration, synchronizePresetDisplay, agentSessionState, buildAgentView, visibleAgentRows, agentTreeDisplay, agentTreeTotals, agentTreeLayout, agentExecutionStatus, agentDetailAddress, agentDetailTarget, agentPath, detailRecord, createAgentInspector, agentHistoryRange, agentHistoryRows, agentHistoryWindow, memoryLibraryAddress, memoryLibraryTarget, memoryLibraryNavigation, memoryLibraryWindow, createMemoryEditor, MemoryLibrary }
3802
+ return { inject, apply, taskFeedbackRows, feedbackStatus, feedbackListItems, feedbackListLayout, feedbackListIndex, feedbackListWindow, feedbackListAnchor, connectionSessions, createConnectionAutosave, createBudgetAutosave, connectionDraft, connectionConfiguration, budgetDraft, budgetConfiguration, synchronizePresetDisplay, agentSessionState, buildAgentView, visibleAgentRows, agentTreeDisplay, agentTreeTotals, agentTreeLayout, agentExecutionStatus, agentDetailAddress, agentDetailTarget, agentPath, detailRecord, createAgentInspector, agentHistoryRange, agentHistoryRows, agentHistoryWindow, memoryLibraryAddress, memoryLibraryTarget, memoryLibraryNavigation, memoryLibraryWindow, createMemoryEditor, MemoryLibrary }
3699
3803
  } })