dsh-super-code 0.3.8 → 0.3.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/README.en.md +169 -0
  2. package/README.md +105 -175
  3. package/client/index.js +594 -260
  4. package/cordis.patch.yml +3 -7
  5. package/docs/Acknowledgements.md +38 -67
  6. package/docs/Changelog.md +176 -88
  7. package/docs/Compatibility.md +133 -278
  8. package/docs/EvaluationResults.md +176 -150
  9. package/docs/UsageGuide.md +218 -223
  10. package/docs/en/Acknowledgements.md +76 -0
  11. package/docs/en/Changelog.md +176 -0
  12. package/docs/en/Compatibility.md +181 -0
  13. package/docs/en/EvaluationResults.md +240 -0
  14. package/docs/en/UsageGuide.md +321 -0
  15. package/docs/images/agent-tree-preview.png +0 -0
  16. package/docs/images/agent-tree.png +0 -0
  17. package/docs/images/install-tgz-preview.png +0 -0
  18. package/docs/images/install-tgz.png +0 -0
  19. package/docs/images/preset-settings-preview.png +0 -0
  20. package/docs/images/preset-settings.png +0 -0
  21. package/docs/images/task-status-preview.png +0 -0
  22. package/docs/images/task-status.png +0 -0
  23. package/lib/connection/approvals.d.ts +21 -0
  24. package/lib/connection/approvals.d.ts.map +1 -0
  25. package/lib/connection/approvals.js +83 -0
  26. package/lib/connection/approvals.js.map +1 -0
  27. package/lib/connection/client.d.ts +8 -0
  28. package/lib/connection/client.d.ts.map +1 -0
  29. package/lib/connection/client.js +34 -0
  30. package/lib/connection/client.js.map +1 -0
  31. package/lib/connection/guidance.d.ts +10 -0
  32. package/lib/connection/guidance.d.ts.map +1 -0
  33. package/lib/connection/guidance.js +27 -0
  34. package/lib/connection/guidance.js.map +1 -0
  35. package/lib/connection/http.d.ts.map +1 -1
  36. package/lib/connection/http.js +83 -16
  37. package/lib/connection/http.js.map +1 -1
  38. package/lib/connection/service.d.ts +3 -1
  39. package/lib/connection/service.d.ts.map +1 -1
  40. package/lib/connection/service.js +8 -0
  41. package/lib/connection/service.js.map +1 -1
  42. package/lib/connection/store.d.ts.map +1 -1
  43. package/lib/connection/store.js +2 -0
  44. package/lib/connection/store.js.map +1 -1
  45. package/lib/connection/tasks.d.ts +41 -1
  46. package/lib/connection/tasks.d.ts.map +1 -1
  47. package/lib/connection/tasks.js +154 -31
  48. package/lib/connection/tasks.js.map +1 -1
  49. package/lib/connection/types.d.ts +71 -2
  50. package/lib/connection/types.d.ts.map +1 -1
  51. package/lib/connection/types.js +5 -3
  52. package/lib/connection/types.js.map +1 -1
  53. package/lib/connection-cli.d.ts +3 -0
  54. package/lib/connection-cli.d.ts.map +1 -0
  55. package/lib/connection-cli.js +40 -0
  56. package/lib/connection-cli.js.map +1 -0
  57. package/lib/core/deletion-command.d.ts.map +1 -1
  58. package/lib/core/deletion-command.js +2 -1
  59. package/lib/core/deletion-command.js.map +1 -1
  60. package/lib/core/windows-runtime.d.ts +16 -0
  61. package/lib/core/windows-runtime.d.ts.map +1 -0
  62. package/lib/core/windows-runtime.js +123 -0
  63. package/lib/core/windows-runtime.js.map +1 -0
  64. package/lib/dsh/budget-settings.d.ts +2 -0
  65. package/lib/dsh/budget-settings.d.ts.map +1 -1
  66. package/lib/dsh/budget-settings.js +9 -3
  67. package/lib/dsh/budget-settings.js.map +1 -1
  68. package/lib/dsh/budgets.d.ts +2 -0
  69. package/lib/dsh/budgets.d.ts.map +1 -1
  70. package/lib/dsh/budgets.js +6 -0
  71. package/lib/dsh/budgets.js.map +1 -1
  72. package/lib/dsh/connection-approval.d.ts +5 -0
  73. package/lib/dsh/connection-approval.d.ts.map +1 -0
  74. package/lib/dsh/connection-approval.js +72 -0
  75. package/lib/dsh/connection-approval.js.map +1 -0
  76. package/lib/dsh/connection-history.d.ts +6 -0
  77. package/lib/dsh/connection-history.d.ts.map +1 -0
  78. package/lib/dsh/connection-history.js +52 -0
  79. package/lib/dsh/connection-history.js.map +1 -0
  80. package/lib/dsh/connection-host.d.ts +36 -3
  81. package/lib/dsh/connection-host.d.ts.map +1 -1
  82. package/lib/dsh/connection-host.js +97 -19
  83. package/lib/dsh/connection-host.js.map +1 -1
  84. package/lib/dsh/connection.d.ts.map +1 -1
  85. package/lib/dsh/connection.js +4 -1
  86. package/lib/dsh/connection.js.map +1 -1
  87. package/lib/dsh/index.d.ts.map +1 -1
  88. package/lib/dsh/index.js +4 -0
  89. package/lib/dsh/index.js.map +1 -1
  90. package/lib/dsh/official-windows-shell.d.ts +4 -0
  91. package/lib/dsh/official-windows-shell.d.ts.map +1 -0
  92. package/lib/dsh/official-windows-shell.js +128 -0
  93. package/lib/dsh/official-windows-shell.js.map +1 -0
  94. package/lib/dsh/windows-shell.d.ts +53 -0
  95. package/lib/dsh/windows-shell.d.ts.map +1 -0
  96. package/lib/dsh/windows-shell.js +182 -0
  97. package/lib/dsh/windows-shell.js.map +1 -0
  98. package/package.json +28 -16
  99. package/presets/super-code/agent.cordis.yml +3 -7
  100. package/runtime/windows/README.md +45 -0
  101. package/runtime/windows/arm64-busybox.exe.gz +0 -0
  102. package/runtime/windows/bash.exe.gz +0 -0
  103. package/runtime/windows/grep.exe.gz +0 -0
  104. package/runtime/windows/licenses/BusyBox-LICENSE.txt +348 -0
  105. package/runtime/windows/licenses/GPL-3.0.txt +674 -0
  106. package/runtime/windows/licenses/LGPL-3.0.txt +165 -0
  107. package/runtime/windows/licenses/MSYS-COPYING.LIB +165 -0
  108. package/runtime/windows/licenses/MSYS-COPYING.RUNTIME +674 -0
  109. package/runtime/windows/licenses/PCRE-LICENCE.txt +93 -0
  110. package/runtime/windows/licenses/ncurses-COPYING.txt +29 -0
  111. package/runtime/windows/manifest.json +236 -0
  112. package/runtime/windows/msys-2.0.dll.gz +0 -0
  113. package/runtime/windows/msys-iconv-2.dll.gz +0 -0
  114. package/runtime/windows/msys-intl-8.dll.gz +0 -0
  115. package/runtime/windows/msys-pcre-1.dll.gz +0 -0
  116. package/runtime/windows/sources/busybox-w32-FRP-6354-g5f09fb446.tgz +0 -0
  117. package/runtime/windows/sources.json +45 -0
  118. package/runtime/windows/x64-busybox.exe.gz +0 -0
package/client/index.js CHANGED
@@ -149,7 +149,11 @@ function Glyph({ type }) {
149
149
  arrow: 'M3 10h13m-5-5 5 5-5 5',
150
150
  fit: 'M3 7V3h4m6 0h4v4m0 6v4h-4m-6 0H3v-4',
151
151
  history: 'M3 4v5h5M3 9a7 7 0 1 1 2 6m5-10v5l3 2',
152
- organize: 'M8 2h4v4H8zM2 14h4v4H2zm12 0h4v4h-4zM10 6v4m-6 4v-4h12v4'
152
+ organize: 'M8 2h4v4H8zM2 14h4v4H2zm12 0h4v4h-4zM10 6v4m-6 4v-4h12v4',
153
+ info: 'M10 9v5m0-8h0M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16Z',
154
+ shield: 'M10 2 3 5v5c0 4 3 7 7 8 4-1 7-4 7-8V5l-7-3Z',
155
+ plug: 'M7 2v4m6-4v4M5 6h10v3a5 5 0 0 1-10 0V6Zm5 8v4',
156
+ check: 'm4 10 4 4 8-8'
153
157
  }
154
158
  return React.createElement('svg', { className: 'dsh-super-code-glyph', viewBox: type === 'code' ? '0 0 24 20' : '0 0 20 20', fill: 'none', stroke: 'currentColor', strokeWidth: 1.5, strokeLinecap: 'round', strokeLinejoin: 'round', 'aria-hidden': true }, React.createElement('path', { d: paths[type] || paths.code }))
155
159
  }
@@ -173,7 +177,7 @@ function AgentMessage({ record, saved, t, toolName }) {
173
177
  : React.createElement(React.Fragment, null, label, React.createElement(DetailText, { text: item.text, t }))))
174
178
  }
175
179
 
176
- /* 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
177
181
  * panels, or in the active dialog's top layer. No host-private UI is needed. */
178
182
  let actionTooltipSequence = 0
179
183
  let actionTooltipDismiss = () => {}
@@ -184,7 +188,7 @@ function actionButtonText(children) {
184
188
  return actionButtonText(child.props.children)
185
189
  }).filter(Boolean).join(' ').replace(/\s+/g, ' ').trim()
186
190
  }
187
- const ActionButton = React.forwardRef(function ActionButton({ children, title, ...props }, forwardedRef) {
191
+ const ActionButton = React.forwardRef(function ActionButton({ as: Tag = 'button', children, title, ...props }, forwardedRef) {
188
192
  const button = useRef(null), pending = useRef(0), cleanup = useRef(() => {})
189
193
  const name = props['aria-label'] || title || actionButtonText(children)
190
194
  const attach = React.useCallback(node => {
@@ -240,7 +244,7 @@ const ActionButton = React.forwardRef(function ActionButton({ children, title, .
240
244
  }
241
245
  useEffect(() => { hide() }, [name])
242
246
  useEffect(() => () => hide(), [])
243
- return React.createElement('button', {
247
+ return React.createElement(Tag, {
244
248
  ...props, ref: attach, 'data-tooltip-name': name,
245
249
  onPointerEnter: event => {
246
250
  props.onPointerEnter?.(event)
@@ -256,7 +260,9 @@ const ActionButton = React.forwardRef(function ActionButton({ children, title, .
256
260
 
257
261
  const LOCALE_NS = 'dshSuperCode'
258
262
  const zh = {
259
- 'feedback.title': '任务状态',
263
+ 'feedback.title': '任务',
264
+ 'feedback.tools': '工具调用汇总',
265
+ 'feedback.toolCount': '{tool} 成功 {ok} 次,失败 {failed} 次',
260
266
  'feedback.refresh': '刷新任务状态',
261
267
  'feedback.noGoal': '尚无目标记录',
262
268
  'feedback.source.record': '任务记录',
@@ -293,6 +299,13 @@ const zh = {
293
299
  'status.blocked': '受阻',
294
300
 
295
301
  'settings.homeTab': '首页', 'settings.presetTab': '预设配置', 'settings.protectionTab': '删除保护',
302
+ 'shell.title': '命令环境', 'shell.enabled': '使用内置 Bash(Windows)',
303
+ 'shell.hint': '无需安装 Git。新启动的会话生效,子 Agent 继承。Windows 限权模式下需由 DSH 逐条审批,不自动修改会话权限。',
304
+ 'shell.official': '同时应用到官方预设',
305
+ 'shell.officialHint': '用于标准、PTC、创建模式,默认关闭。极简模式保留原有持久终端;自定义预设不受影响。',
306
+ 'shell.windowsOnly': '仅 Windows 生效',
307
+ 'shell.host': '使用宿主命令环境', 'shell.pending': '首次使用时自动准备', 'shell.ready': '内置 Bash 已就绪',
308
+ 'shell.error': '内置 Bash 不可用,请关闭此开关使用宿主环境。', 'shell.otherPlatform': '当前宿主沿用系统命令环境,无需启用。',
296
309
  "connection.requestTitle": "请求访问工作目录",
297
310
  "connection.requestHint": "外部 MCP 客户端申请访问以下目录及其子目录。同意后会加入允许列表,后续委派仍使用 DSH 的权限设置。",
298
311
  "connection.requestClient": "请求客户端",
@@ -303,13 +316,16 @@ const zh = {
303
316
  "connection.rejectDirectory": "拒绝",
304
317
  "connection.error.directory-limit": "最多允许选择 32 个目录。",
305
318
  "connection.error.picker-unavailable": "无法打开目录选择器,请重新读取后重试。",
306
- 'home.protection': '保护', 'home.extensions': '扩展', 'home.configure': '配置', 'home.managePreset': '配置预设',
319
+ 'home.configure': '配置', 'home.managePreset': '配置预设', 'home.details': '打开{title}详情', 'home.activeSessions': '{count} 个活跃对话',
320
+ 'preset.versionBadge': '版本一致',
307
321
  'home.connectedSessions': '正在连接的对话', 'home.historySessions': '历史对话',
308
322
  'home.connections': '已连接客户端', 'home.noConnections': '暂无客户端连接', 'home.sessions': '关联会话', 'home.noSessions': '暂无关联会话',
309
323
  'home.disconnect': '断开', 'home.openSession': '打开会话', 'home.connected': '已连接', 'home.enabled': '已开启', 'home.disabled': '已关闭',
310
324
  'home.mcp': 'MCP 服务', 'home.connectionCount': '{count} / {max} 个连接', 'home.setupConnection': '配置并启用',
311
325
  'home.lastSeen': '最近活动', 'home.refresh': '刷新概览', 'home.error': '状态读取或操作失败,请刷新后重试。',
312
326
  'connection.maxConnections': '最大连接数', 'connection.connectionsHint': '按 MCP 客户端会话计数。断开或空闲 10 分钟后释放连接;已接收任务继续执行。',
327
+ 'connection.allowNewConversations': '允许 MCP 新增对话', 'connection.allowNewConversationsHint': '关闭后不会创建新的 DSH 对话;MCP 仍可查看并继续已有对话。',
328
+ 'connection.allowCallerApproval': '允许调用方审批', 'connection.allowCallerApprovalHint': '默认关闭。开启后,由 MCP 调用方批准或拒绝委派任务的单次操作;无法处理或超时后回到 DSH。新增目录仍需在 DSH 同意。',
313
329
  'connection.addDirectory': '添加目录', 'connection.noDirectories': '暂无目录,请通过文件管理器添加。',
314
330
  'connection.workspaceDirectory': 'DSH 工作区', 'connection.customDirectory': '添加的目录', 'connection.directoryUnavailable': '目录不可用',
315
331
  'connection.removeDirectory': '移除目录', 'connection.directoryRefresh': '刷新目录',
@@ -327,10 +343,10 @@ const zh = {
327
343
  'connection.directoriesHint': '勾选允许的目录,包含其子目录。每次打开设置会同步 DSH 工作区,保留已保存的选择。',
328
344
  'connection.save': '保存连接', 'connection.cancel': '取消修改', 'connection.reload': '重新读取', 'connection.saved': '已保存连接设置。',
329
345
  'connection.client': '连接 Prompt', 'connection.copyCommand': '复制连接 Prompt', 'connection.showToken': '显示凭证', 'connection.hideToken': '隐藏凭证', 'connection.copyToken': '复制凭证', 'connection.token': '连接凭证', 'connection.rotate': '更换凭证',
330
- 'connection.prompt': '请配置并连接 DSH Super Code MCP 服务:\n地址:{url}\n传输:Streamable HTTP\n认证:Authorization: Bearer <连接凭证>,凭证由我单独提供,请妥善保存在客户端。\n连接后先使用 dsh_sessions 按工作目录查看最近对话、状态和连接额度,由调用方选择传 taskId 复用历史,或传 newConversation: true 新建;不要默认复用最新对话。然后使用 dsh_run 委派任务、dsh_wait 查询状态或找回任务、dsh_send 补充要求、dsh_cancel 取消任务。使用稳定的 requestId 避免重复提交,只使用允许的绝对工作目录;新增目录请用 dsh_request_directory 提交申请,并等待用户在 DSH 中同意。权限确认需在 DSH 中处理;finished 仅表示执行结束,仍需验证结果。',
346
+ 'connection.prompt': '请配置并连接 DSH Super Code MCP 服务:\n地址:{url}\n传输:Streamable HTTP\n认证:Authorization: Bearer <连接凭证>,凭证由我单独提供,请妥善保存在客户端。\nDSH 仅作为任务执行器,待开发或验收的对象是指定目录中的项目/候选产物;不要为排查委派任务而操作、重装、重启或改配提供服务的 DSH/NEXT。连接后先用 dsh_status 查看允许目录、连接额度和阻塞任务,再使用 dsh_sessions 按工作目录查看最近对话和状态,由调用方选择传 taskId 复用历史,或传 newConversation: true 新建;不要默认复用最新对话。如果 DSH 关闭了“允许 MCP 新增对话”,必须传已有 taskId 复用,不能创建新对话。调用 dsh_models 查看可用模型及思考强度,再在 dsh_run 或 dsh_send 中按需传 provider、model、reasoningEffort;省略时沿用 DSH 当前/默认选择。然后使用 dsh_run 委派任务、dsh_wait 查询状态或找回任务、dsh_send 补充要求、dsh_cancel 取消任务。使用稳定的 requestId 避免重复提交,只使用允许的绝对工作目录;新增目录请用 dsh_request_directory 提交申请,并等待用户在 DSH 中同意。通过 dsh_wait 的返回游标长轮询(waitMs: 30000);空输出、失败或截断时使用 dsh_read 分页读取公开对话和工具结果。忙碌/额度错误时查看阻塞任务、等待并保留原 requestId 和输入,不重复新建或清理其他连接。复用一个 MCP 会话,用完以 DELETE 释放;SDK 需先 transport.terminateSession() 再 client.close()。原生工具未加载时可用随包的 super-code-mcp 命令,凭证通过私密环境变量提供,不读取 DSH profile 搜寻凭证。dsh_status 返回 allowCallerApproval;默认关闭,权限确认请用户在 DSH 中处理。开启后通过 dsh_wait 接收交互审批请求或 callerApproval.pending,检查具体工具、参数和原因后,用 dsh_approve 传 taskId、approvalId、decision(approve/reject)作单次决定;目录申请仍需用户在 DSH 同意。不自动点击界面批准。finished 仅表示执行结束,仍需验证结果。',
331
347
  'connection.tokenHint': '请将凭证安全保存在客户端。更换凭证后,旧凭证立即失效。',
332
348
  'connection.rotated': '已更换凭证,请更新客户端。', 'connection.copied': '已复制。',
333
- 'connection.error.unavailable': '连接服务尚未就绪或当前配置目录不可写,请重新读取。', 'connection.error.invalid': '请检查端口、最大连接数和目录。启用连接至少需要一个有效目录。',
349
+ 'connection.error.unavailable': '连接服务尚未就绪或当前配置目录不可写,请重新读取。', 'connection.error.invalid': '请检查端口、最大连接数和目录。启用连接至少需要一个有效目录。', 'connection.error.new-conversation-disabled': 'MCP 新增对话已关闭,请选择已有对话继续。',
334
350
  'connection.error.conflict': '连接设置已在别处修改。草稿已保留,请重新读取。', 'connection.error.save-failed': '保存失败,草稿已保留。', 'connection.error.port-unavailable': '端口被占用或无法监听。请更换端口并保存。', 'connection.error.storage-unavailable': '任务状态保存失败,请检查配置目录。', 'connection.error.clipboard': '复制失败,请手动复制。',
335
351
  'settings.contextTab': '上下文配置', 'settings.tabs': 'Super Code 配置',
336
352
  'budget.common': '通用预算', 'budget.superCode': 'Super Code 专属预算',
@@ -339,11 +355,11 @@ const zh = {
339
355
  'budget.defaultValue': '(默认:{value})', 'budget.off': '关闭', 'budget.managed': '宿主管理',
340
356
  'delete.title': '删除保护', 'delete.mode': '保护模式', 'delete.off': '关闭', 'delete.relaxed': '宽松', 'delete.strict': '严格', 'delete.official': '同时应用到官方预设',
341
357
  'delete.hint.off': '不添加删除保护提示,不额外拦截命令。宿主原有权限检查仍然有效。',
342
- 'delete.hint.relaxed': '默认使用 trash,脚本中也建议使用;用户明确要求时可以使用 rm,无需插件额外确认。',
358
+ 'delete.hint.relaxed': '默认使用 trash(脚本中也建议);用户明确要求时可用 rm,无需额外确认。',
343
359
  'delete.hint.strict': '默认使用 trash,脚本也禁止直接使用 rm。识别到永久删除命令时,仅清理临时文件或构建产物可经用户逐次二次确认放行。',
344
360
  'delete.officialHint': '默认仅保护 Super Code。此开关独立于预算的官方预设开关;保存后立即作用于后续命令。',
345
361
  'budget.title': '上下文配置', 'budget.scope': '预算保存后对新建 Agent 生效,运行中的任务保留原配置。',
346
- 'budget.defaults': '留空沿用默认值,括号内显示默认值;通用预算随宿主版本变化。恢复默认会清除这里的覆盖,回到插件加载配置;未配置时跟随宿主。',
362
+ 'budget.defaults': '留空沿用默认值,各项下方显示默认值;通用预算随宿主版本变化。恢复默认会清除这里的覆盖,回到插件加载配置;未配置时跟随宿主。',
347
363
  'budget.context': '上下文压缩', 'budget.execution': '批量工具执行', 'budget.advanced': '更多预算',
348
364
  'budget.pressureBasis': '压缩预算基准', 'budget.inherit': '跟随默认', 'budget.host': '宿主策略', 'budget.window': '完整上下文窗口',
349
365
  'budget.thresholdRatio': '压缩触发比例(%)', 'budget.retainRatio': '最近原文保留比例(%)', 'budget.summaryMaxTokens': '摘要输出上限(Token)',
@@ -360,6 +376,9 @@ const zh = {
360
376
  'budget.error.conflict': '预算已在别处修改。草稿已保留,请重新读取后再修改。', 'budget.error.read-only': '当前宿主的设置只读,无法保存。',
361
377
  'budget.error.ptc-unavailable': '此宿主不支持覆盖 PTC 总执行时限。', 'budget.error.ptc-ceiling': '执行时限超过了宿主允许的上限。',
362
378
  'budget.error.save-failed': '保存失败,草稿已保留,请重试。',
379
+ 'budget.defaultHint': '默认:{value}', 'budget.error.range': '超出允许范围或格式不正确。',
380
+ 'budget.resetQuestion': '清除这里的所有覆盖?', 'budget.resetConfirm': '恢复默认', 'delete.scope': '适用范围',
381
+ 'save.idle': '修改后自动保存', 'save.saving': '正在保存…', 'save.saved': '已自动保存', 'save.error': '保存失败', 'save.invalid': '有字段需要修正,暂未保存', 'save.retry': '重试',
363
382
  'memory.add': '新增记忆', 'memory.edit': '编辑', 'memory.cancel': '取消', 'memory.save': '保存', 'memory.delete': '删除', 'memory.deleting': '正在删除…', 'memory.saving': '正在保存…',
364
383
  'memory.topic': '主题', 'memory.kind': '类型', 'memory.summaryLabel': '标题', 'memory.detailLabel': '内容', 'memory.manual': '手动维护',
365
384
  'memory.topicHint': '字母、数字、点、下划线或短横线,最多 96 个字符。',
@@ -371,7 +390,7 @@ const zh = {
371
390
  'detail.toolCall': '工具调用', 'detail.toolResult': '工具结果', 'detail.toolError': '工具失败',
372
391
  'detail.cache': '缓存', 'detail.info': '详情', 'tree.countCompact': '{shown}/{total} · 运行 {running}',
373
392
  'memory.loading': '正在读取记忆…', 'memory.topics': '知识主题', 'memory.allTopics': '全部主题', 'memory.related': '同主题知识', 'preset.configuration': '预设配置',
374
- 'memory.title': '记忆库', 'memory.project': '当前项目', 'memory.global': '全局偏好', 'memory.search': '搜索主题或记忆',
393
+ 'memory.title': '记忆', 'memory.project': '当前项目', 'memory.global': '全局偏好', 'memory.search': '搜索主题或记忆',
375
394
  'memory.description': '知识主题与条目',
376
395
  'memory.empty': '还没有保存的记忆。需要长期保留时,直接告诉 Agent 即可。', 'memory.noMatches': '没有匹配的记忆',
377
396
  'memory.selectSession': '先打开一个对话,查看它所在项目的记忆。', 'memory.error': '暂时无法读取记忆,请刷新重试。',
@@ -430,7 +449,9 @@ const zh = {
430
449
  'detail.path': 'Agent 路径', 'detail.title': 'Agent 详情', 'detail.refresh': '刷新对话详情', 'detail.task': '任务', 'detail.agent': 'Agent', 'detail.interrupted': 'Agent · 已中断', 'detail.error': '执行错误', 'detail.incomplete': '执行未完成,请稍后重试。', 'detail.input': '输入', 'detail.output': '输出', 'detail.cacheRead': '缓存读取', 'detail.cacheWrite': '缓存写入', 'detail.total': 'Token 总量', 'detail.hitRate': '缓存命中率', 'detail.moreUsage': '用量详情', 'detail.unavailable': '未提供', 'detail.reading': '正在读取对话…', 'detail.read': '读取中…', 'detail.older': '加载更早记录', 'detail.latest': '回到最新', 'detail.empty': '暂无执行内容', 'detail.new': '有新内容 · 查看最新', 'detail.loadError': '对话详情读取失败', 'detail.connection': '连接中断,正在重连', 'detail.historyError': '历史记录读取失败', 'detail.open': '展开全文', 'detail.noAccess': '无法打开详情,请重试', 'tree.loadError': '部分执行记录读取失败,请刷新重试', 'detail.unknown': '用量未知', 'main.agent': '主 Agent', 'tree.open': '点击查看详情', 'tree.expand': '展开', 'tree.collapse': '收起', 'image': '[图片]'
431
450
  }
432
451
  const en = {
433
- 'feedback.title': 'Task status',
452
+ 'feedback.title': 'Tasks',
453
+ 'feedback.tools': 'Tool call summary',
454
+ 'feedback.toolCount': '{tool}: {ok} succeeded, {failed} failed',
434
455
  'feedback.refresh': 'Refresh task status',
435
456
  'feedback.noGoal': 'No recorded objective',
436
457
  'feedback.source.record': 'Recorded objective',
@@ -467,6 +488,13 @@ const en = {
467
488
  'status.blocked': 'Blocked',
468
489
 
469
490
  'settings.homeTab': 'Home', 'settings.presetTab': 'Preset configuration', 'settings.protectionTab': 'Deletion protection',
491
+ 'shell.title': 'Command environment', 'shell.enabled': 'Use bundled Bash (Windows)',
492
+ '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.',
493
+ 'shell.official': 'Also apply to official presets',
494
+ 'shell.officialHint': 'Applies to Standard, PTC and Create; off by default. Minimal keeps its persistent terminal. Custom presets are unaffected.',
495
+ 'shell.windowsOnly': 'Only available on Windows',
496
+ 'shell.host': 'Using the host command environment', 'shell.pending': 'Prepared automatically on first use', 'shell.ready': 'Bundled Bash is ready',
497
+ 'shell.error': 'Bundled Bash is unavailable. Turn this off to use the host environment.', 'shell.otherPlatform': 'This host uses its existing command environment.',
470
498
  "connection.requestTitle": "Working directory access request",
471
499
  "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.",
472
500
  "connection.requestClient": "Requesting client",
@@ -477,13 +505,16 @@ const en = {
477
505
  "connection.rejectDirectory": "Reject",
478
506
  "connection.error.directory-limit": "Select up to 32 directories.",
479
507
  "connection.error.picker-unavailable": "Could not open the directory picker. Reload and try again.",
480
- 'home.protection': 'Protection', 'home.extensions': 'Extensions', 'home.configure': 'Configure', 'home.managePreset': 'Configure preset',
508
+ 'home.configure': 'Configure', 'home.managePreset': 'Configure preset', 'home.details': 'Open {title} details', 'home.activeSessions': '{count} active conversations',
509
+ 'preset.versionBadge': 'Up to date',
481
510
  'home.connectedSessions': 'Connected conversations', 'home.historySessions': 'Past conversations',
482
511
  'home.connections': 'Connected clients', 'home.noConnections': 'No clients connected', 'home.sessions': 'Linked sessions', 'home.noSessions': 'No linked sessions',
483
512
  'home.disconnect': 'Disconnect', 'home.openSession': 'Open session', 'home.connected': 'Connected', 'home.enabled': 'On', 'home.disabled': 'Off',
484
513
  'home.mcp': 'MCP service', 'home.connectionCount': '{count} / {max} connections', 'home.setupConnection': 'Set up connection',
485
514
  'home.lastSeen': 'Last activity', 'home.refresh': 'Refresh overview', 'home.error': 'Could not read or update the status. Refresh and try again.',
486
515
  'connection.maxConnections': 'Maximum connections', 'connection.connectionsHint': 'Counts MCP client sessions. Disconnect or 10 minutes of inactivity releases a connection; accepted tasks continue.',
516
+ 'connection.allowNewConversations': 'Allow MCP to create conversations', 'connection.allowNewConversationsHint': 'When off, MCP cannot create new DSH conversations; it can still inspect and continue existing ones.',
517
+ 'connection.allowCallerApproval': 'Allow caller approval', 'connection.allowCallerApprovalHint': 'Off by default. MCP callers may approve or reject one-time task operations; unhandled or expired requests return to DSH. New directory access still requires consent in DSH.',
487
518
  'connection.addDirectory': 'Add directory', 'connection.noDirectories': 'No directories. Add one with the directory picker.',
488
519
  'connection.workspaceDirectory': 'DSH workspace', 'connection.customDirectory': 'Added directory', 'connection.directoryUnavailable': 'Directory unavailable',
489
520
  'connection.removeDirectory': 'Remove directory', 'connection.directoryRefresh': 'Refresh directories',
@@ -501,10 +532,10 @@ const en = {
501
532
  'connection.directoriesHint': 'Select allowed directories, including their subdirectories. Reopening settings refreshes DSH workspaces and retains saved selections.',
502
533
  'connection.save': 'Save connection', 'connection.cancel': 'Cancel changes', 'connection.reload': 'Reload', 'connection.saved': 'Connection settings saved.',
503
534
  'connection.client': 'Connection Prompt', 'connection.copyCommand': 'Copy connection prompt', 'connection.showToken': 'Show token', 'connection.hideToken': 'Hide token', 'connection.copyToken': 'Copy token', 'connection.token': 'Connection token', 'connection.rotate': 'Rotate token',
504
- 'connection.prompt': 'Configure and connect to the DSH Super Code MCP service:\nURL: {url}\nTransport: Streamable HTTP\nAuthentication: Authorization: Bearer <connection token>. I will supply the token separately; store it securely in the client.\nAfter connecting, call dsh_sessions for the working directory to show recent conversations, statuses and connection capacity. Let the caller choose whether to pass taskId to reuse history or newConversation: true to create a new root; never default to the latest conversation. Then use dsh_run to delegate, dsh_wait to observe or recover, dsh_send for follow-ups, and dsh_cancel to cancel. Use stable requestId values to avoid duplicate submissions and only allowed absolute working directories. Request additional access with dsh_request_directory and wait for user approval in DSH. Resolve permissions in DSH. A finished task still requires result verification.',
535
+ 'connection.prompt': 'Configure and connect to the DSH Super Code MCP service:\nURL: {url}\nTransport: Streamable HTTP\nAuthentication: Authorization: Bearer <connection token>. I will supply the token separately; store it securely in the client.\nDSH is the task executor; the project/candidate in the chosen cwd is the target. Do not control, reinstall, restart or reconfigure the serving DSH/NEXT app to investigate delegated work. After connecting, call dsh_status for directory grants, capacity and blocking tasks, then dsh_sessions for recent conversations and statuses. Let the caller choose whether to pass taskId to reuse history or newConversation: true to create a new root; never default to the latest conversation. If DSH has “Allow MCP to create conversations” disabled, pass an existing taskId and never create a new conversation. Call dsh_models to inspect available models and reasoning efforts, then optionally pass provider, model and reasoningEffort to dsh_run or dsh_send; omit them to keep the current DSH model selection. Use dsh_run to delegate, dsh_wait to observe or recover, dsh_send for follow-ups, and dsh_cancel to cancel. Use stable requestId values to avoid duplicate submissions and only allowed absolute working directories. Request additional access with dsh_request_directory and wait for user approval in DSH. Long-poll dsh_wait with its returned cursor and waitMs: 30000. Use dsh_read to page through public messages/tool results when output is empty, failed or truncated. On busy/limit errors, inspect blockers, wait and retain the original requestId/input; do not repeatedly initialize or clear other connections. Reuse one MCP session and release it with DELETE when done; with the SDK call transport.terminateSession() before client.close(). If native tools are unavailable, use the packaged super-code-mcp command with private environment credentials rather than searching DSH profile files. Check allowCallerApproval in dsh_status (off by default). When off, ask the user to resolve permissions in DSH. When on, dsh_wait delivers interactive approvals or callerApproval.pending; inspect the tool, arguments and reason, then use dsh_approve with taskId, approvalId and decision (approve/reject) for that exact operation. Directory access still requires consent in DSH. Never click UI approval controls. A finished task still requires result verification.',
505
536
  'connection.tokenHint': 'Store the token securely in the client. Rotation invalidates the previous token immediately.',
506
537
  'connection.rotated': 'Token rotated. Update your client.', 'connection.copied': 'Copied.',
507
- '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.',
538
+ '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.',
508
539
  '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.',
509
540
  'settings.contextTab': 'Context settings', 'settings.tabs': 'Super Code settings',
510
541
  'budget.common': 'Common budgets', 'budget.superCode': 'Super Code budgets',
@@ -517,7 +548,7 @@ const en = {
517
548
  'delete.hint.strict': 'Prefer trash; scripts must not directly use rm. Recognized permanent deletion requires separate approval for each temporary-file or build-artifact cleanup.',
518
549
  'delete.officialHint': 'Protects Super Code by default. This switch is independent of official-preset budgets; saved changes apply to subsequent commands immediately.',
519
550
  'budget.title': 'Context settings', 'budget.scope': 'Budget changes apply to new Agents. Running tasks keep their current settings.',
520
- 'budget.defaults': 'Leave fields blank to inherit defaults. Parentheses show defaults; common budgets follow the host version. Reset clears overrides and restores the plugin configuration, or host defaults when unconfigured.',
551
+ 'budget.defaults': 'Leave fields blank to inherit defaults, shown below each field; common budgets follow the host version. Reset clears overrides and restores the plugin configuration, or host defaults when unconfigured.',
521
552
  'budget.context': 'Context compression', 'budget.execution': 'Batched tool execution', 'budget.advanced': 'More budgets',
522
553
  'budget.pressureBasis': 'Compression budget basis', 'budget.inherit': 'Inherit default', 'budget.host': 'Host policy', 'budget.window': 'Full context window',
523
554
  'budget.thresholdRatio': 'Compress at (%)', 'budget.retainRatio': 'Keep recent context (%)', 'budget.summaryMaxTokens': 'Summary output limit (tokens)',
@@ -534,6 +565,9 @@ const en = {
534
565
  'budget.error.conflict': 'Budgets changed elsewhere. Your draft is retained; reload before editing again.', 'budget.error.read-only': 'This host has read-only settings.',
535
566
  'budget.error.ptc-unavailable': 'This host cannot override PTC elapsed deadlines.', 'budget.error.ptc-ceiling': 'The deadline exceeds the host ceiling.',
536
567
  'budget.error.save-failed': 'Save failed. Your draft is retained; try again.',
568
+ 'budget.defaultHint': 'Default: {value}', 'budget.error.range': 'Out of range or not a valid number.',
569
+ 'budget.resetQuestion': 'Clear all overrides here?', 'budget.resetConfirm': 'Reset', 'delete.scope': 'Scope',
570
+ 'save.idle': 'Changes save automatically', 'save.saving': 'Saving…', 'save.saved': 'Saved automatically', 'save.error': 'Save failed', 'save.invalid': 'Fix the highlighted fields to save', 'save.retry': 'Retry',
537
571
  'memory.add': 'Add memory', 'memory.edit': 'Edit', 'memory.cancel': 'Cancel', 'memory.save': 'Save', 'memory.delete': 'Delete', 'memory.deleting': 'Deleting…', 'memory.saving': 'Saving…',
538
572
  'memory.topic': 'Topic', 'memory.kind': 'Type', 'memory.summaryLabel': 'Title', 'memory.detailLabel': 'Content', 'memory.manual': 'Manually maintained',
539
573
  'memory.topicHint': 'Letters, digits, dots, underscores or hyphens; up to 96 characters.',
@@ -545,7 +579,7 @@ const en = {
545
579
  'detail.toolCall': 'Tool call', 'detail.toolResult': 'Tool result', 'detail.toolError': 'Tool failed',
546
580
  'detail.cache': 'Cache', 'detail.info': 'Details', 'tree.countCompact': '{shown}/{total} · Running {running}',
547
581
  'memory.loading': 'Loading memories…', 'memory.topics': 'Knowledge topics', 'memory.allTopics': 'All topics', 'memory.related': 'More in this topic', 'preset.configuration': 'Preset configuration',
548
- 'memory.title': 'Memory library', 'memory.project': 'This project', 'memory.global': 'Global preferences', 'memory.search': 'Search topics or memories',
582
+ 'memory.title': 'Memory', 'memory.project': 'This project', 'memory.global': 'Global preferences', 'memory.search': 'Search topics or memories',
549
583
  'memory.description': 'Knowledge topics and entries',
550
584
  'memory.empty': 'No saved memories yet. Tell the agent when something is worth keeping.', 'memory.noMatches': 'No matching memories',
551
585
  'memory.selectSession': 'Open a conversation to view memory for its project.', 'memory.error': 'Memory is unavailable. Refresh to try again.',
@@ -964,19 +998,33 @@ function FeedbackMark({ tone, label }) {
964
998
  React.createElement('path', { d: 'm3.5 8 3 3 6-6', strokeLinecap: 'round', strokeLinejoin: 'round' })),
965
999
  tone === 'error' && React.createElement('span', { 'aria-hidden': true }, '!'))
966
1000
  }
967
- function FeedbackActivity({ activity, t }) {
968
- const tone = { running: 'active', failed: 'error', succeeded: 'success', interrupted: 'idle' }[activity.status] || 'idle'
969
- return React.createElement('div', { className: 'dsh-super-code-feedback-activity', 'data-activity-state': activity.status },
970
- React.createElement(FeedbackMark, { tone, label: text(t, 'feedback.activity.' + activity.status) }),
971
- React.createElement('span', { className: 'dsh-super-code-feedback-activity-text', title: activity.description || activity.tool }, activity.description || activity.tool),
972
- activity.description && React.createElement('small', { className: 'dsh-super-code-feedback-tool', title: activity.tool }, activity.tool),
973
- ['failed', 'interrupted'].includes(activity.status) && React.createElement('small', null, text(t, 'feedback.activity.' + activity.status)))
974
- }
975
- /** Flatten presentation rows only; no task, step, or loaded activity is folded. */
1001
+ /** Per-tool settled counts in first-use order; single calls stay in the execution log. */
1002
+ function feedbackToolSummary(activities = []) {
1003
+ const tools = new Map()
1004
+ for (const { tool, status } of activities) {
1005
+ const row = tools.get(tool) || { tool, succeeded: 0, failed: 0, running: false }
1006
+ if (status === 'succeeded') row.succeeded++
1007
+ else if (status === 'failed') row.failed++
1008
+ else if (status === 'running') row.running = true
1009
+ tools.set(tool, row)
1010
+ }
1011
+ return [...tools.values()]
1012
+ }
1013
+ function FeedbackTools({ tools, t }) {
1014
+ return React.createElement('ul', { className: 'dsh-super-code-feedback-tools', 'aria-label': text(t, 'feedback.tools') },
1015
+ tools.map(row => {
1016
+ const label = text(t, 'feedback.toolCount', { tool: row.tool, ok: row.succeeded, failed: row.failed })
1017
+ return React.createElement('li', { key: row.tool, title: label, 'aria-label': label, 'data-running': row.running || undefined },
1018
+ React.createElement('span', { 'aria-hidden': true }, row.tool),
1019
+ React.createElement('b', { className: 'dsh-super-code-tool-badge', 'data-tone': 'success', 'aria-hidden': true }, row.succeeded),
1020
+ React.createElement('b', { className: 'dsh-super-code-tool-badge', 'data-tone': 'warning', 'data-zero': row.failed === 0 || undefined, 'aria-hidden': true }, row.failed))
1021
+ }))
1022
+ }
1023
+ /** Flatten presentation rows only; tool calls fold into one per-task summary row. */
976
1024
  function feedbackListItems(model, root, partial) {
977
1025
  const items = []
978
1026
  const add = (kind, key, data = {}, row) => items.push({ kind, key: JSON.stringify(key), row, ...data,
979
- signature: JSON.stringify([kind, data.content, data.todo, data.activity, data.label, data.count,
1027
+ signature: JSON.stringify([kind, data.content, data.todo, data.tools, data.label, data.count,
980
1028
  data.file && [data.file.name, data.file.directory, [...data.file.operations]], kind === 'task' &&
981
1029
  [row.title, row.owner, row.done, row.total, row.complete, row.taskStatus, row.facts?.phase, row.node.running]]) })
982
1030
  for (const row of model.tasks) {
@@ -985,8 +1033,9 @@ function feedbackListItems(model, root, partial) {
985
1033
  if (row.goal && row.goal !== row.title) add('text', [row.id, 'goal'], { content: row.goal }, row)
986
1034
  if (facts?.latestRequest && facts.latestRequest !== facts.request) add('request', [row.id, 'request'], { content: facts.latestRequest }, row)
987
1035
  row.todos.forEach((todo, index) => add('step', [row.id, 'step', index], { todo }, row))
988
- for (const activity of facts?.activities || []) add('activity', [row.id, 'activity', activity.callId, activity.seq], { activity }, row)
989
- if (!row.total && !facts?.activities?.length) add('note', [row.id, 'empty'], { label: facts ? 'feedback.noSteps' : 'feedback.loading' }, row)
1036
+ const tools = feedbackToolSummary(facts?.activities)
1037
+ if (tools.length) add('tools', [row.id, 'tools'], { tools }, row)
1038
+ if (!row.total && !tools.length) add('note', [row.id, 'empty'], { label: facts ? 'feedback.noSteps' : 'feedback.loading' }, row)
990
1039
  if (facts?.omittedActivities) add('note', [row.id, 'recent'], { label: 'feedback.recentOnly' }, row)
991
1040
  add('open', [row.id, 'open'], { focusable: !row.node.unavailable }, row)
992
1041
  }
@@ -1002,7 +1051,7 @@ function feedbackListItems(model, root, partial) {
1002
1051
 
1003
1052
  /** Prefix heights allow binary-search windows without mounting offscreen rows. */
1004
1053
  function feedbackListLayout(items, heights = new Map()) {
1005
- const estimates = { task: 64, text: 48, request: 70, step: 28, activity: 30, open: 34, files: 40, file: 30, note: 26 }
1054
+ const estimates = { task: 64, text: 48, request: 70, step: 28, tools: 32, open: 34, files: 40, file: 30, note: 26 }
1006
1055
  const offsets = [0], byKey = new Map()
1007
1056
  items.forEach((item, index) => {
1008
1057
  const measured = heights.get(item.key)
@@ -1050,7 +1099,7 @@ function FeedbackRowContent({ item, root, openDetail, t }) {
1050
1099
  if (item.kind === 'step') return React.createElement('div', { className: 'dsh-super-code-feedback-step', 'data-step-state': item.todo.status },
1051
1100
  React.createElement(FeedbackMark, { tone: item.todo.status === 'completed' ? 'success' : item.todo.status === 'in_progress' ? 'active' : 'pending', label: text(t, 'feedback.todo.' + item.todo.status) }),
1052
1101
  React.createElement('span', null, item.todo.content))
1053
- if (item.kind === 'activity') return React.createElement(FeedbackActivity, { activity: item.activity, t })
1102
+ if (item.kind === 'tools') return React.createElement(FeedbackTools, { tools: item.tools, t })
1054
1103
  if (item.kind === 'open') return React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-feedback-open', disabled: !item.focusable,
1055
1104
  title: text(t, 'feedback.open'), onClick: () => openDetail(row.node) }, text(t, 'feedback.open'), React.createElement(Glyph, { type: 'arrow' }))
1056
1105
  if (item.kind === 'files') return React.createElement('h3', { className: 'dsh-super-code-feedback-files-heading' }, text(t, 'feedback.files'), React.createElement('span', null, item.count))
@@ -1062,7 +1111,9 @@ function FeedbackRowContent({ item, root, openDetail, t }) {
1062
1111
  file.directory && React.createElement('small', null, file.directory),
1063
1112
  React.createElement('span', { className: 'dsh-super-code-feedback-file-operation' }, [...file.operations].map(operation => text(t, 'feedback.file.' + operation)).join(' · ')))
1064
1113
  }
1065
- if (item.kind === 'note') return React.createElement('p', { className: 'dsh-super-code-feedback-muted', role: item.label === 'tree.loadError' ? 'alert' : undefined }, text(t, item.label))
1114
+ if (item.label === 'tree.loadError') return React.createElement('p', { className: 'dsh-super-code-state', 'data-tone': 'error', role: 'alert' }, React.createElement(Glyph, { type: 'error' }), text(t, item.label))
1115
+ 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))
1116
+ if (item.kind === 'note') return React.createElement('p', { className: 'dsh-super-code-feedback-muted' }, text(t, item.label))
1066
1117
  return React.createElement('p', { className: 'dsh-super-code-feedback-text' },
1067
1118
  item.kind === 'request' && React.createElement('small', null, text(t, 'feedback.latest')), item.content)
1068
1119
  }
@@ -1221,7 +1272,7 @@ function WorkspaceSectionToggle({ section, expanded, onToggle, children, t }) {
1221
1272
  React.createElement('strong', null, label), children)
1222
1273
  }
1223
1274
 
1224
- /** One active section guarantees exactly one open view; tab state retains drafts. */
1275
+ /** Accordion: at most one open view; clicking the open heading collapses it. Tab state retains drafts. */
1225
1276
  function SuperCodeWorkspace(props) {
1226
1277
  const { tab } = props.useTabInfo()
1227
1278
  const address = typeof tab.navigation?.params?.memory === 'string' ? tab.navigation.params.memory : tab.contentId
@@ -1236,11 +1287,11 @@ function SuperCodeWorkspace(props) {
1236
1287
  props.workspaceStates.set(tab.signal, value)
1237
1288
  return value
1238
1289
  }, [props.workspaceStates, tab.signal])
1239
- const [active, setActive] = useState(['tasks', 'tree', 'memory'].includes(saved.active) ? saved.active : 'tasks')
1290
+ const [active, setActive] = useState(['tasks', 'tree', 'memory', ''].includes(saved.active) ? saved.active : 'tasks')
1240
1291
  const layout = useRef(null), focusSection = useRef('')
1241
1292
  const toggle = section => {
1242
- const next = active === section ? section === 'tasks' ? 'tree' : 'tasks' : section
1243
- saved.active = next; focusSection.current = next; setActive(next)
1293
+ const next = active === section ? '' : section
1294
+ saved.active = next; focusSection.current = section; setActive(next)
1244
1295
  }
1245
1296
  useLayoutEffect(() => {
1246
1297
  if (saved.navigationKey === navigationKey) return
@@ -2057,7 +2108,7 @@ const budgetFields = [
2057
2108
  ]
2058
2109
  function budgetDraft(configuration) {
2059
2110
  const deletion = configuration.deletionProtection
2060
- return Object.fromEntries([['deletionProtection', deletion === true ? 'strict' : deletion === false ? 'off' : deletion ?? 'relaxed'], ['deletionProtectionForOfficialPresets', configuration.deletionProtectionForOfficialPresets ?? false], ['applyToOfficialPresets', configuration.applyToOfficialPresets ?? false], ['pressureBasis', configuration.budgets?.pressureBasis ?? ''],
2111
+ 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 ?? ''],
2061
2112
  ...budgetFields.map(field => {
2062
2113
  const value = field.root ? configuration[field.key] : configuration.budgets?.[field.key]
2063
2114
  return [field.key, value === undefined ? '' : String(value / field.factor)]
@@ -2097,116 +2148,210 @@ function budgetConfiguration(draft) {
2097
2148
  return { ok: true, configuration: config }
2098
2149
  }
2099
2150
 
2151
+ /* Settings primitives. Every tab composes titled sections of label/control rows,
2152
+ * one callout style for notices, and one autosave indicator. */
2153
+ function SettingsSection({ id, title, description, actions, plain = false, children }) {
2154
+ const lines = [].concat(description ?? []).filter(Boolean)
2155
+ return React.createElement('section', { id, className: 'dsh-super-code-section', 'aria-labelledby': `${id}-title` },
2156
+ React.createElement('header', { className: 'dsh-super-code-section-head' },
2157
+ React.createElement('div', { className: 'dsh-super-code-section-heading' },
2158
+ React.createElement('h3', { id: `${id}-title` }, title),
2159
+ ...lines.map((line, index) => React.createElement('p', { key: index }, line))),
2160
+ actions && React.createElement('div', { className: 'dsh-super-code-section-actions' }, actions)),
2161
+ React.createElement('div', { className: 'dsh-super-code-section-body', 'data-plain': plain || undefined }, children))
2162
+ }
2163
+ /** Label and hint on the left, control on the right; `children` may take the describedby ids. */
2164
+ function SettingRow({ id, label, hint, error, children }) {
2165
+ const described = [hint && `${id}-hint`, error && `${id}-error`].filter(Boolean).join(' ') || undefined
2166
+ return React.createElement('div', { className: 'dsh-super-code-setting-row', 'data-invalid': error ? true : undefined },
2167
+ React.createElement('div', { className: 'dsh-super-code-setting-row-text' },
2168
+ React.createElement('label', { htmlFor: id }, label),
2169
+ hint && React.createElement('p', { id: `${id}-hint` }, hint),
2170
+ error && React.createElement('p', { id: `${id}-error`, className: 'dsh-super-code-setting-row-error' }, error)),
2171
+ React.createElement('div', { className: 'dsh-super-code-setting-row-control' }, typeof children === 'function' ? children(described) : children))
2172
+ }
2173
+ function Callout({ tone = 'info', action, children }) {
2174
+ return React.createElement('div', { className: 'dsh-super-code-callout', 'data-tone': tone, role: tone === 'error' ? 'alert' : tone === 'success' ? 'status' : undefined },
2175
+ React.createElement(Glyph, { type: tone === 'success' ? 'check' : tone === 'info' ? 'info' : 'error' }),
2176
+ React.createElement('div', { className: 'dsh-super-code-callout-text' }, children),
2177
+ action || null)
2178
+ }
2179
+ function SaveIndicator({ state, t }) {
2180
+ return React.createElement('p', { className: 'dsh-super-code-save-indicator', role: 'status', 'data-save-state': state },
2181
+ React.createElement('i', { 'aria-hidden': true }), React.createElement('span', null, t(`save.${state}`)))
2182
+ }
2183
+ /** Exclusive choices that need a sentence each; native radios keep arrow-key behavior. */
2184
+ function ChoiceCards({ name, label, value, choices, onChange, disabled = false }) {
2185
+ return React.createElement('div', { className: 'dsh-super-code-choice-cards', role: 'radiogroup', 'aria-label': label },
2186
+ ...choices.map(([choice, title, hint]) => React.createElement('label', { key: choice, className: 'dsh-super-code-choice-card', 'data-checked': choice === value || undefined },
2187
+ React.createElement('input', { type: 'radio', name, value: choice, checked: choice === value, disabled, 'aria-describedby': `${name}-${choice}-hint`,
2188
+ onChange: () => { if (choice !== value) onChange(choice) } }),
2189
+ React.createElement('i', { 'aria-hidden': true }),
2190
+ React.createElement('span', { className: 'dsh-super-code-choice-card-text' },
2191
+ React.createElement('strong', null, title), React.createElement('small', { id: `${name}-${choice}-hint` }, hint)))))
2192
+ }
2193
+
2194
+ /** Each budget tab writes only its own fields and carries the other tab's stored values through. */
2195
+ function budgetSectionConfiguration(section, draft, snapshot) {
2196
+ if (section === 'shell') return typeof draft.windowsBash === 'boolean' && typeof draft.windowsBashForOfficialPresets === 'boolean'
2197
+ ? { ok: true, configuration: { ...snapshot.configuration, windowsBash: draft.windowsBash, windowsBashForOfficialPresets: draft.windowsBashForOfficialPresets } }
2198
+ : { ok: false, error: 'invalid' }
2199
+ const parsed = budgetConfiguration(draft)
2200
+ if (!parsed.ok) return parsed
2201
+ const current = snapshot.configuration
2202
+ return { ok: true, configuration: section === 'protection'
2203
+ ? { ...current, deletionProtection: draft.deletionProtection, deletionProtectionForOfficialPresets: draft.deletionProtectionForOfficialPresets }
2204
+ : { ...parsed.configuration, windowsBash: current.windowsBash, windowsBashForOfficialPresets: current.windowsBashForOfficialPresets, deletionProtection: current.deletionProtection, deletionProtectionForOfficialPresets: current.deletionProtectionForOfficialPresets } }
2205
+ }
2206
+ function createBudgetAutosave(api, section = 'context') {
2207
+ return createAutosave(api, { draft: budgetDraft({}), toDraft: budgetDraft,
2208
+ toConfiguration: (draft, snapshot) => budgetSectionConfiguration(section, draft, snapshot) })
2209
+ }
2210
+ function budgetFieldValid(field, input) {
2211
+ const value = String(input ?? '').trim()
2212
+ if (!value) return true
2213
+ const number = Number(value)
2214
+ if (!Number.isFinite(number) || number < field.min || (field.max !== undefined && number > field.max)) return false
2215
+ if (field.step === 'any') return true
2216
+ const scaled = number * field.factor, rounded = Math.round(scaled)
2217
+ return Math.abs(rounded - scaled) <= 1e-7 && Number.isSafeInteger(rounded)
2218
+ }
2219
+ const autosaveValidationErrors = ['invalid', 'retain', 'ptc-order']
2220
+ function autosaveState(editing) {
2221
+ return editing.saving ? 'saving' : autosaveValidationErrors.includes(editing.error) ? 'invalid'
2222
+ : editing.error ? 'error' : editing.notice === 'saved' ? 'saved' : 'idle'
2223
+ }
2224
+
2100
2225
  function BudgetSettings({ api, t, active, section = 'context', onSaved = () => {} }) {
2101
- const [snapshot, setSnapshot] = useState(null)
2102
- const [draft, setDraft] = useState(() => budgetDraft({})), [busy, setBusy] = useState(false)
2103
- const [error, setError] = useState(''), [notice, setNotice] = useState('')
2226
+ const protection = section === 'protection'
2227
+ const shell = section === 'shell'
2228
+ const editor = useMemo(() => createBudgetAutosave(api, section), [api, section])
2229
+ const editing = useSyncExternalStore(editor.subscribe, editor.getSnapshot, editor.getSnapshot)
2230
+ const { snapshot, draft } = editing
2231
+ const [loading, setLoading] = useState(false), [failure, setFailure] = useState(''), [notice, setNotice] = useState('')
2232
+ const [confirmReset, setConfirmReset] = useState(false)
2104
2233
  const alive = useRef(false), pending = useRef(false)
2105
- const receive = value => { setSnapshot(value); setDraft(budgetDraft(value.configuration)) }
2106
- const read = async () => {
2107
- if (pending.current) return
2108
- pending.current = true; setBusy(true); setError(''); setNotice('')
2234
+ const load = async (discard = false) => {
2235
+ if (pending.current || (!discard && editor.hasChanges())) return
2236
+ pending.current = true; setLoading(true); setFailure('')
2109
2237
  try {
2110
2238
  const response = await api.readConfig()
2111
2239
  if (!response.ok) throw new Error('Remote unavailable')
2112
- if (alive.current) receive(response.value)
2113
- } catch { if (alive.current) setError('connection') }
2114
- finally { pending.current = false; if (alive.current) setBusy(false) }
2240
+ if (alive.current) editor.receive(response.value)
2241
+ } catch { if (alive.current) setFailure('connection') }
2242
+ finally { pending.current = false; if (alive.current) setLoading(false) }
2115
2243
  }
2116
- useEffect(() => { alive.current = true; return () => { alive.current = false } }, [api])
2117
- useEffect(() => { if (active && (!snapshot || !dirty) && !error) read() }, [api, active])
2118
- const save = async reset => {
2119
- if (pending.current || !snapshot?.writable) return
2120
- const protection = section === 'protection'
2121
- const parsed = budgetConfiguration(draft)
2122
- if (parsed.ok) {
2123
- const selected = protection
2124
- ? { ...snapshot.configuration, deletionProtection: reset ? 'relaxed' : draft.deletionProtection, deletionProtectionForOfficialPresets: reset ? false : draft.deletionProtectionForOfficialPresets }
2125
- : { ...(reset ? {} : parsed.configuration), deletionProtection: snapshot.configuration.deletionProtection, deletionProtectionForOfficialPresets: snapshot.configuration.deletionProtectionForOfficialPresets }
2126
- parsed.configuration = selected
2127
- }
2128
- if (!parsed.ok) { setError(parsed.error); setNotice(''); return }
2129
- pending.current = true; setBusy(true); setError(''); setNotice('')
2244
+ useEffect(() => { alive.current = true; return () => { alive.current = false; void editor.flush() } }, [editor])
2245
+ useEffect(() => { if (editing.saveCount) onSaved() }, [editing.saveCount])
2246
+ // Other tabs write the same document, so reread on every visit; leaving flushes pending input.
2247
+ useEffect(() => { if (active) load(); else { setConfirmReset(false); void editor.flush() } }, [editor, active])
2248
+ const reset = async () => {
2249
+ setConfirmReset(false)
2250
+ if (pending.current) return
2251
+ await editor.flush()
2252
+ const current = editor.getSnapshot().snapshot
2253
+ if (!alive.current || !current?.writable) return
2254
+ const base = current.configuration
2255
+ const configuration = protection
2256
+ ? { ...base, deletionProtection: 'relaxed', deletionProtectionForOfficialPresets: false }
2257
+ : { windowsBash: base.windowsBash, windowsBashForOfficialPresets: base.windowsBashForOfficialPresets, deletionProtection: base.deletionProtection, deletionProtectionForOfficialPresets: base.deletionProtectionForOfficialPresets }
2258
+ pending.current = true; setLoading(true); setFailure(''); setNotice('')
2130
2259
  try {
2131
- const response = await api.saveConfig(JSON.stringify(parsed.configuration), String(snapshot.revision))
2260
+ const response = await api.saveConfig(JSON.stringify(configuration), String(current.revision))
2132
2261
  if (!response.ok) throw new Error('Remote unavailable')
2133
2262
  if (!alive.current) return
2134
- if (response.value.ok) { receive(response.value.snapshot); onSaved(); setNotice(reset ? 'resetDone' : 'saved') }
2135
- else setError(response.value.error)
2136
- } catch { if (alive.current) setError('save-failed') }
2137
- finally { pending.current = false; if (alive.current) setBusy(false) }
2138
- }
2139
- const disabled = busy || !snapshot?.writable
2140
- const sectionDraft = value => section === 'protection'
2141
- ? [value.deletionProtection, value.deletionProtectionForOfficialPresets]
2142
- : Object.fromEntries(Object.entries(value).filter(([key]) => !key.startsWith('deletionProtection')))
2143
- const dirty = snapshot && JSON.stringify(sectionDraft(draft)) !== JSON.stringify(sectionDraft(budgetDraft(snapshot.configuration)))
2144
- const edit = (key, value) => { setDraft(current => ({ ...current, [key]: value })); setError(''); setNotice('') }
2145
- const defaultLabel = (key, field) => {
2146
- const value = field?.root ? snapshot?.defaults?.[key] : snapshot?.defaults?.budgets?.[key]
2147
- const shown = key === 'pressureBasis' ? t('budget.host') : value === undefined ? t('budget.managed') : Number(value / field.factor).toLocaleString('en-US', { maximumFractionDigits: 3 })
2148
- return React.createElement('span', { className: 'dsh-super-code-budget-default' }, text(t, 'budget.defaultValue', { value: shown }))
2149
- }
2150
- const fields = group => budgetFields.filter(field => field.group === group).map(field => {
2151
- const id = `super-code-budget-${field.key}`
2152
- return React.createElement('div', { className: 'dsh-super-code-settings-field', key: field.key },
2153
- React.createElement('label', { htmlFor: id }, t(`budget.${field.key}`), ' ', defaultLabel(field.key, field)),
2154
- React.createElement('input', { id, type: 'number', inputMode: 'decimal', value: draft[field.key],
2155
- min: field.min, max: group === 'execution' && snapshot?.ptcMaxTimeoutMs ? snapshot.ptcMaxTimeoutMs / 1000 : field.max,
2156
- step: field.step, placeholder: t('budget.inherit'), disabled: disabled || (group === 'execution' && snapshot?.ptcMaxTimeoutMs === false),
2157
- onChange: event => edit(field.key, event.target.value) }))
2158
- })
2263
+ if (response.value.ok) { editor.receive(response.value.snapshot); onSaved(); setNotice('resetDone') }
2264
+ else setFailure(response.value.error)
2265
+ } catch { if (alive.current) setFailure('save-failed') }
2266
+ finally { pending.current = false; if (alive.current) setLoading(false) }
2267
+ }
2268
+ const disabled = loading || !snapshot?.writable
2269
+ const edit = (key, value, delay = 0) => { setNotice(''); setFailure(''); editor.change({ [key]: value }, delay) }
2270
+ const parsed = budgetConfiguration(draft)
2271
+ const fieldError = field => !budgetFieldValid(field, draft[field.key]) ? t('budget.error.range')
2272
+ : field.key === 'retainRatio' && parsed.error === 'retain' ? t('budget.error.retain')
2273
+ : field.key === 'ptcTimeoutMs' && parsed.error === 'ptc-order' ? t('budget.error.ptc-order') : ''
2274
+ const defaultOf = field => {
2275
+ const value = field.root ? snapshot?.defaults?.[field.key] : snapshot?.defaults?.budgets?.[field.key]
2276
+ return value === undefined ? '' : Number(value / field.factor).toLocaleString('en-US', { maximumFractionDigits: 3, useGrouping: false })
2277
+ }
2278
+ const numberRow = field => {
2279
+ const id = `super-code-budget-${field.key}`, execution = field.group === 'execution', fallback = defaultOf(field)
2280
+ return React.createElement(SettingRow, { key: field.key, id, label: t(`budget.${field.key}`), error: fieldError(field),
2281
+ hint: text(t, 'budget.defaultHint', { value: fallback || t('budget.managed') }) }, described =>
2282
+ React.createElement('input', { id, type: 'number', inputMode: 'decimal', value: draft[field.key], min: field.min,
2283
+ max: execution && snapshot?.ptcMaxTimeoutMs ? snapshot.ptcMaxTimeoutMs / 1000 : field.max, step: field.step,
2284
+ placeholder: fallback || t('budget.inherit'), 'aria-invalid': fieldError(field) ? true : undefined, 'aria-describedby': described,
2285
+ disabled: disabled || (execution && snapshot?.ptcMaxTimeoutMs === false),
2286
+ onChange: event => edit(field.key, event.target.value, 500), onBlur: () => { void editor.flush() } }))
2287
+ }
2288
+ const rows = group => budgetFields.filter(field => field.group === group).map(numberRow)
2289
+ const saveError = editing.error && !autosaveValidationErrors.includes(editing.error) ? editing.error : ''
2290
+ const problem = failure || saveError
2291
+ const button = (label, onClick, extra = {}) => React.createElement(ActionButton, { type: 'button', disabled: loading, onClick, ...extra }, label)
2292
+ const shellStatus = snapshot?.shell
2293
+ const windowsHost = shellStatus?.platform === 'win32'
2294
+ const shellTooltip = shellStatus && !windowsHost ? t('shell.windowsOnly') : undefined
2295
+ const content = shell ? React.createElement(SettingsSection, { id: 'super-code-shell', title: t('shell.title') },
2296
+ React.createElement(SettingRow, { id: 'super-code-windows-bash', label: t('shell.enabled'),
2297
+ hint: !windowsHost ? t('shell.otherPlatform') : t('shell.hint') }, described =>
2298
+ React.createElement(ConnectionSwitch, { id: 'super-code-windows-bash', checked: draft.windowsBash,
2299
+ disabled: disabled || !windowsHost, tooltip: shellTooltip, 'aria-describedby': described,
2300
+ onChange: value => edit('windowsBash', value) })),
2301
+ React.createElement(SettingRow, { id: 'super-code-windows-bash-official', label: t('shell.official'), hint: t('shell.officialHint') }, described =>
2302
+ React.createElement(ConnectionSwitch, { id: 'super-code-windows-bash-official', checked: draft.windowsBashForOfficialPresets,
2303
+ disabled: disabled || !windowsHost || !draft.windowsBash, tooltip: shellTooltip, 'aria-describedby': described,
2304
+ onChange: value => edit('windowsBashForOfficialPresets', value) })),
2305
+ windowsHost && React.createElement('p', { className: 'dsh-super-code-shell-status', role: 'status' },
2306
+ React.createElement('span', null, t(!draft.windowsBash ? 'shell.host' : `shell.${shellStatus.state}`)),
2307
+ shellStatus.version && draft.windowsBash && React.createElement('code', null, shellStatus.version)),
2308
+ shellStatus?.state === 'error' && draft.windowsBash && React.createElement(Callout, { tone: 'error' },
2309
+ React.createElement('p', null, shellStatus.error)))
2310
+ : protection ? React.createElement(React.Fragment, null,
2311
+ React.createElement(SettingsSection, { id: 'super-code-deletion-mode', title: t('delete.mode'), plain: true },
2312
+ React.createElement(ChoiceCards, { name: 'super-code-deletion-mode', label: t('delete.mode'), value: draft.deletionProtection, disabled,
2313
+ choices: ['off', 'relaxed', 'strict'].map(mode => [mode, t(`delete.${mode}`), t(`delete.hint.${mode}`)]),
2314
+ onChange: value => edit('deletionProtection', value) })),
2315
+ React.createElement(SettingsSection, { id: 'super-code-deletion-scope', title: t('delete.scope') },
2316
+ React.createElement(SettingRow, { id: 'super-code-deletion-official', label: t('delete.official'), hint: t('delete.officialHint') }, described =>
2317
+ React.createElement(ConnectionSwitch, { id: 'super-code-deletion-official', checked: draft.deletionProtectionForOfficialPresets,
2318
+ disabled: disabled || draft.deletionProtection === 'off', 'aria-describedby': described,
2319
+ onChange: value => edit('deletionProtectionForOfficialPresets', value) }))))
2320
+ : React.createElement(React.Fragment, null,
2321
+ React.createElement(Callout, { tone: 'info' }, React.createElement('p', null, t('budget.scope')), React.createElement('p', null, t('budget.defaults'))),
2322
+ React.createElement(SettingsSection, { id: 'super-code-budget-common', title: t('budget.common') },
2323
+ React.createElement(SettingRow, { id: 'super-code-budget-official', label: t('budget.applyToOfficialPresets'), hint: t('budget.officialHint') }, described =>
2324
+ React.createElement(ConnectionSwitch, { id: 'super-code-budget-official', checked: draft.applyToOfficialPresets, disabled, 'aria-describedby': described,
2325
+ onChange: value => edit('applyToOfficialPresets', value) }))),
2326
+ React.createElement(SettingsSection, { id: 'super-code-budget-context', title: t('budget.context'), description: t('budget.contextHint') },
2327
+ React.createElement(SettingRow, { id: 'super-code-budget-basis', label: t('budget.pressureBasis'), hint: text(t, 'budget.defaultHint', { value: t('budget.host') }) },
2328
+ React.createElement(SelectControl, { id: 'super-code-budget-basis', label: t('budget.pressureBasis'), value: draft.pressureBasis, disabled,
2329
+ choices: [['', t('budget.inherit')], ['host', t('budget.host')], ['window', t('budget.window')]], onChange: value => edit('pressureBasis', value) })),
2330
+ ...rows('context'),
2331
+ React.createElement('details', { className: 'dsh-super-code-section-more' },
2332
+ React.createElement('summary', null, React.createElement(Glyph, { type: 'chevron' }), t('budget.advanced')), ...rows('advanced'))),
2333
+ React.createElement(SettingsSection, { id: 'super-code-budget-execution', title: t('budget.execution'),
2334
+ description: [t(snapshot?.ptcMaxTimeoutMs === false ? 'budget.ptcUnavailable' : 'budget.ptcHint'),
2335
+ snapshot?.ptcMaxTimeoutMs && text(t, 'budget.ptcCeiling', { seconds: snapshot.ptcMaxTimeoutMs / 1000 })] }, ...rows('execution')),
2336
+ React.createElement(SettingsSection, { id: 'super-code-budget-exclusive', title: t('budget.superCode'), description: t('budget.superCodeHint') }, ...rows('superCode')))
2159
2337
  return React.createElement('section', { className: 'dsh-super-code-budgets' },
2160
- React.createElement('form', { 'aria-label': t(section === 'protection' ? 'delete.title' : 'budget.title'), 'aria-busy': busy, onSubmit: event => { event.preventDefault(); save(false) } },
2161
- section === 'protection' && React.createElement('section', { className: 'dsh-super-code-budget-group', 'aria-labelledby': 'super-code-deletion-title' },
2162
- React.createElement('h3', { id: 'super-code-deletion-title' }, t('delete.title')),
2163
- React.createElement('div', { className: 'dsh-super-code-settings-field' },
2164
- React.createElement('label', { id: 'super-code-deletion-mode-label' }, t('delete.mode')),
2165
- React.createElement(SelectControl, { id: 'super-code-deletion-protection', label: t('delete.mode'), value: draft.deletionProtection,
2166
- choices: ['off', 'relaxed', 'strict'].map(mode => [mode, t(`delete.${mode}`)]), disabled,
2167
- onChange: value => edit('deletionProtection', value) })),
2168
- React.createElement('p', { id: 'super-code-deletion-hint', className: 'dsh-super-code-budget-hint' }, t(`delete.hint.${draft.deletionProtection}`)),
2169
- React.createElement('label', { className: 'dsh-super-code-budget-switch' },
2170
- React.createElement('input', { id: 'super-code-deletion-official', type: 'checkbox', role: 'switch', checked: draft.deletionProtectionForOfficialPresets, disabled: disabled || draft.deletionProtection === 'off',
2171
- 'aria-describedby': 'super-code-deletion-official-hint', onChange: event => edit('deletionProtectionForOfficialPresets', event.target.checked) }),
2172
- React.createElement('span', null, t('delete.official'))),
2173
- React.createElement('p', { id: 'super-code-deletion-official-hint', className: 'dsh-super-code-budget-hint' }, t('delete.officialHint'))),
2174
- section !== 'protection' && React.createElement(React.Fragment, null,
2175
- React.createElement('p', { className: 'dsh-super-code-budget-hint' }, t('budget.scope')),
2176
- React.createElement('section', { className: 'dsh-super-code-budget-group', 'aria-labelledby': 'super-code-common-title' },
2177
- React.createElement('h3', { id: 'super-code-common-title' }, t('budget.common')),
2178
- React.createElement('label', { className: 'dsh-super-code-budget-switch' },
2179
- React.createElement('input', { type: 'checkbox', role: 'switch', checked: draft.applyToOfficialPresets, disabled,
2180
- 'aria-describedby': 'super-code-official-hint', onChange: event => edit('applyToOfficialPresets', event.target.checked) }),
2181
- React.createElement('span', null, t('budget.applyToOfficialPresets'), ' ', React.createElement('span', { className: 'dsh-super-code-budget-default' }, text(t, 'budget.defaultValue', { value: t('budget.off') })))),
2182
- React.createElement('p', { id: 'super-code-official-hint', className: 'dsh-super-code-budget-hint' }, t('budget.officialHint')),
2183
- React.createElement('p', { className: 'dsh-super-code-budget-hint' }, t('budget.defaults')),
2184
- React.createElement('fieldset', null, React.createElement('legend', null, t('budget.context')),
2185
- React.createElement('div', { className: 'dsh-super-code-budget-grid' },
2186
- React.createElement('div', { className: 'dsh-super-code-settings-field' },
2187
- React.createElement('label', { id: 'super-code-budget-basis-label' }, t('budget.pressureBasis'), ' ', defaultLabel('pressureBasis')),
2188
- React.createElement(SelectControl, { id: 'super-code-budget-basis', label: t('budget.pressureBasis'), value: draft.pressureBasis,
2189
- choices: [['', t('budget.inherit')], ['host', t('budget.host')], ['window', t('budget.window')]], disabled,
2190
- onChange: value => edit('pressureBasis', value) })), fields('context')),
2191
- React.createElement('small', null, t('budget.contextHint'))),
2192
- React.createElement('fieldset', null, React.createElement('legend', null, t('budget.execution')),
2193
- React.createElement('div', { className: 'dsh-super-code-budget-grid' }, fields('execution')),
2194
- React.createElement('small', null, t(snapshot?.ptcMaxTimeoutMs === false ? 'budget.ptcUnavailable' : 'budget.ptcHint')),
2195
- snapshot?.ptcMaxTimeoutMs && React.createElement('small', null, text(t, 'budget.ptcCeiling', { seconds: snapshot.ptcMaxTimeoutMs / 1000 }))),
2196
- React.createElement('details', { className: 'dsh-super-code-budget-more' },
2197
- React.createElement('summary', null, t('budget.advanced')),
2198
- React.createElement('div', { className: 'dsh-super-code-budget-grid' }, fields('advanced')))),
2199
- React.createElement('section', { className: 'dsh-super-code-budget-group dsh-super-code-budget-exclusive', 'aria-labelledby': 'super-code-exclusive-title' },
2200
- React.createElement('h3', { id: 'super-code-exclusive-title' }, t('budget.superCode')),
2201
- React.createElement('p', { className: 'dsh-super-code-budget-hint' }, t('budget.superCodeHint')),
2202
- React.createElement('div', { className: 'dsh-super-code-budget-grid' }, fields('superCode')))),
2203
- !busy && snapshot && !snapshot.writable && React.createElement('small', null, t('budget.error.read-only')),
2204
- error && React.createElement('p', { role: 'alert' }, t(`budget.error.${error}`)),
2205
- notice && React.createElement('p', { role: 'status', className: 'dsh-super-code-budget-hint' }, t(`budget.${notice}`)),
2206
- React.createElement('div', { className: 'dsh-super-code-settings-form-actions' },
2207
- error && React.createElement(ActionButton, { type: 'button', disabled: busy, onClick: read }, t('budget.reload')),
2208
- React.createElement(ActionButton, { type: 'button', disabled, onClick: () => save(true) }, t('budget.reset')),
2209
- React.createElement(ActionButton, { type: 'submit', className: 'dsh-super-code-primary-button', disabled: disabled || !dirty }, t(busy ? 'budget.saving' : 'budget.save')))))
2338
+ React.createElement('form', { className: 'dsh-super-code-stack', 'aria-label': t(shell ? 'shell.title' : protection ? 'delete.title' : 'budget.title'), 'aria-busy': loading || editing.saving,
2339
+ onSubmit: event => { event.preventDefault(); void editor.flush() } },
2340
+ problem && React.createElement(Callout, { tone: 'error',
2341
+ action: failure === 'connection' || problem === 'conflict' ? button(t('budget.reload'), () => load(true))
2342
+ : saveError ? button(t('save.retry'), () => { void editor.retry() }) : null },
2343
+ React.createElement('p', null, t(`budget.error.${problem}`))),
2344
+ snapshot && !snapshot.writable && React.createElement(Callout, { tone: 'warning' }, React.createElement('p', null, t('budget.error.read-only'))),
2345
+ notice && React.createElement(Callout, { tone: 'success' }, React.createElement('p', null, t(`budget.${notice}`))),
2346
+ content,
2347
+ React.createElement('div', { className: 'dsh-super-code-settings-footer' },
2348
+ React.createElement(SaveIndicator, { state: autosaveState(editing), t }),
2349
+ !shell && React.createElement('div', { className: 'dsh-super-code-settings-footer-actions' },
2350
+ confirmReset ? React.createElement(React.Fragment, null,
2351
+ React.createElement('span', null, t('budget.resetQuestion')),
2352
+ button(t('preset.cancel'), () => setConfirmReset(false)),
2353
+ button(t('budget.resetConfirm'), reset, { className: 'dsh-super-code-danger-button', disabled }))
2354
+ : button(t('budget.reset'), () => setConfirmReset(true), { disabled })))))
2210
2355
  }
2211
2356
 
2212
2357
  // Old hosts render file metadata. Synchronize through our own Remote, then
@@ -2250,18 +2395,21 @@ function synchronizePresetDisplay(api, locale, reload, onError, preferenceScope)
2250
2395
  }
2251
2396
 
2252
2397
  function connectionDraft(config) {
2253
- return { enabled: config.enabled, port: String(config.port), allowedDirectories: [...config.allowedDirectories], knownDirectories: [...config.knownDirectories ?? []],
2398
+ return { enabled: config.enabled, allowNewConversations: config.allowNewConversations !== false, allowCallerApproval: config.allowCallerApproval === true, port: String(config.port), allowedDirectories: [...config.allowedDirectories], knownDirectories: [...config.knownDirectories ?? []],
2254
2399
  maxConcurrent: config.maxConnections ?? 3, maxConnections: String(config.maxConnections ?? 3), directoriesConfigured: config.directoriesConfigured ?? false }
2255
2400
  }
2256
2401
  function connectionConfiguration(draft) {
2257
2402
  const port = Number(draft.port), maxConnections = Number(draft.maxConnections)
2258
2403
  const allowedDirectories = [...new Set(draft.allowedDirectories)]
2259
- if (typeof draft.enabled !== 'boolean' || !Number.isInteger(port) || port < 1024 || port > 65535 || !Number.isInteger(maxConnections) || maxConnections < 1 || maxConnections > 32 || allowedDirectories.length > 32 || allowedDirectories.some(path => typeof path !== 'string' || !path) || (draft.enabled && !allowedDirectories.length)) return { ok: false }
2260
- return { ok: true, configuration: { enabled: draft.enabled, port, allowedDirectories, maxConcurrent: maxConnections, maxConnections, directoriesConfigured: true, knownDirectories: draft.knownDirectories } }
2404
+ if (typeof draft.enabled !== 'boolean' || typeof draft.allowNewConversations !== 'boolean' || typeof draft.allowCallerApproval !== 'boolean' || !Number.isInteger(port) || port < 1024 || port > 65535 || !Number.isInteger(maxConnections) || maxConnections < 1 || maxConnections > 32 || allowedDirectories.length > 32 || allowedDirectories.some(path => typeof path !== 'string' || !path) || (draft.enabled && !allowedDirectories.length)) return { ok: false }
2405
+ return { ok: true, configuration: { enabled: draft.enabled, allowNewConversations: draft.allowNewConversations, allowCallerApproval: draft.allowCallerApproval, port, allowedDirectories, maxConcurrent: maxConnections, maxConnections, directoriesConfigured: true, knownDirectories: draft.knownDirectories } }
2261
2406
  }
2262
- /** Serialize writes and retain newer edits while an earlier revision is being saved. */
2263
- function createConnectionAutosave(api) {
2264
- let state = { snapshot: false, draft: connectionDraft({ enabled: false, port: 23457, allowedDirectories: [] }), saving: false, error: '', notice: '', saveCount: 0 }
2407
+ /**
2408
+ * Serialize writes and retain newer edits while an earlier revision is being saved.
2409
+ * `toConfiguration` returns `{ ok, configuration }` or `{ ok: false, error? }`; invalid drafts never write.
2410
+ */
2411
+ function createAutosave(api, { draft: initialDraft, toDraft, toConfiguration }) {
2412
+ let state = { snapshot: false, draft: initialDraft, saving: false, error: '', notice: '', saveCount: 0 }
2265
2413
  let version = 0, acknowledged = 0, blocked = -1, timer = false, running = false
2266
2414
  const listeners = new Set()
2267
2415
  const update = patch => { state = { ...state, ...patch }; for (const listener of listeners) listener() }
@@ -2273,14 +2421,14 @@ function createConnectionAutosave(api) {
2273
2421
  update({ saving: true, error: '', notice: '' })
2274
2422
  try {
2275
2423
  while (acknowledged < version) {
2276
- const sent = version, parsed = connectionConfiguration(state.draft)
2277
- if (!parsed.ok) { blocked = version; update({ error: 'invalid' }); break }
2424
+ const sent = version, parsed = toConfiguration(state.draft, state.snapshot)
2425
+ if (!parsed.ok) { blocked = version; update({ error: parsed.error || 'invalid' }); break }
2278
2426
  const result = await api.saveConfig(JSON.stringify(parsed.configuration), String(state.snapshot.revision))
2279
2427
  if (!result.ok) throw new Error('Remote unavailable')
2280
2428
  if (!result.value.ok) { blocked = version; update({ error: result.value.error }); break }
2281
2429
  acknowledged = sent
2282
2430
  update({ snapshot: result.value.snapshot, saveCount: state.saveCount + 1,
2283
- ...(sent === version ? { draft: connectionDraft(result.value.snapshot.configuration), notice: 'saved' } : {}) })
2431
+ ...(sent === version ? { draft: toDraft(result.value.snapshot.configuration), notice: 'saved' } : {}) })
2284
2432
  }
2285
2433
  } catch { blocked = version; update({ error: 'save-failed' }) }
2286
2434
  finally { update({ saving: false }) }
@@ -2291,7 +2439,7 @@ function createConnectionAutosave(api) {
2291
2439
  getSnapshot: () => state,
2292
2440
  subscribe: listener => { listeners.add(listener); return () => listeners.delete(listener) },
2293
2441
  hasChanges: () => version !== acknowledged || state.saving,
2294
- receive: (snapshot, draft = connectionDraft(snapshot.configuration)) => {
2442
+ receive: (snapshot, draft = toDraft(snapshot.configuration)) => {
2295
2443
  acknowledged = ++version
2296
2444
  update({ snapshot, draft, error: '', notice: '' })
2297
2445
  },
@@ -2303,12 +2451,21 @@ function createConnectionAutosave(api) {
2303
2451
  if (delay) timer = setTimeout(() => { timer = false; void flush() }, delay)
2304
2452
  else void flush()
2305
2453
  },
2454
+ /** Retry the last blocked or failed draft without requiring another edit. */
2455
+ retry: () => { blocked = -1; return flush() },
2306
2456
  flush,
2307
2457
  }
2308
2458
  }
2309
- function ConnectionSwitch({ checked, disabled, onChange, children }) {
2310
- return React.createElement('label', { className: 'dsh-super-code-connection-switch' },
2311
- React.createElement('input', { type: 'checkbox', role: 'switch', checked, disabled, onChange: event => onChange(event.target.checked) }),
2459
+ function createConnectionAutosave(api) {
2460
+ return createAutosave(api, { draft: connectionDraft({ enabled: false, port: 23457, allowedDirectories: [] }),
2461
+ toDraft: connectionDraft, toConfiguration: draft => connectionConfiguration(draft) })
2462
+ }
2463
+ /** Disabled inputs do not receive hover; their label hosts the shared top-side tooltip. */
2464
+ function ConnectionSwitch({ checked, disabled, onChange, children, tooltip, ...input }) {
2465
+ return React.createElement(tooltip ? ActionButton : 'label', {
2466
+ className: 'dsh-super-code-connection-switch', ...(tooltip ? { as: 'label', title: tooltip } : {}),
2467
+ },
2468
+ React.createElement('input', { ...input, type: 'checkbox', role: 'switch', checked, disabled, onChange: event => onChange(event.target.checked) }),
2312
2469
  React.createElement('span', { className: 'dsh-super-code-connection-track', 'aria-hidden': true }, React.createElement('i')), children)
2313
2470
  }
2314
2471
  function DirectoryBrowser({ api, t, onSelect, onClose }) {
@@ -2476,6 +2633,10 @@ function ConnectionSettings({ api, t, active, openSession, onSaved = () => {} })
2476
2633
  React.createElement('form', { 'aria-label': t('connection.title'), 'aria-busy': saving, onSubmit: event => { event.preventDefault(); void editor.flush() } },
2477
2634
  React.createElement(ConnectionSwitch, { checked: draft.enabled, disabled, onChange: value => edit('enabled', value) }, t('connection.enabled')),
2478
2635
  React.createElement('p', { className: 'dsh-super-code-connection-hint' }, t('connection.scope')),
2636
+ React.createElement(ConnectionSwitch, { checked: draft.allowNewConversations, disabled, onChange: value => edit('allowNewConversations', value) }, t('connection.allowNewConversations')),
2637
+ React.createElement('small', null, t('connection.allowNewConversationsHint')),
2638
+ React.createElement(ConnectionSwitch, { checked: draft.allowCallerApproval, disabled, onChange: value => edit('allowCallerApproval', value) }, t('connection.allowCallerApproval')),
2639
+ React.createElement('small', null, t('connection.allowCallerApprovalHint')),
2479
2640
  React.createElement('div', { className: 'dsh-super-code-connection-grid' },
2480
2641
  ...[['port', 1024, 65535], ['maxConnections', 1, 32]].map(([key, min, max]) => React.createElement('div', { key, className: 'dsh-super-code-settings-field' },
2481
2642
  React.createElement('label', { htmlFor: `super-code-connection-${key}` }, t(`connection.${key}`)),
@@ -2515,52 +2676,94 @@ function ConnectionSettings({ api, t, active, openSession, onSaved = () => {} })
2515
2676
  browser && React.createElement(DirectoryBrowser, { api, t, onSelect: choose, onClose: () => setBrowser(false) }))
2516
2677
  }
2517
2678
 
2679
+ /* A few exclusive choices read faster as one visible radio group than as a menu. */
2680
+ function SegmentedControl({ label, value, choices, onChange, disabled = false, busy = false, describedBy }) {
2681
+ const selected = choices.findIndex(([choice]) => choice === value)
2682
+ const focusable = Math.max(0, selected)
2683
+ const pick = choice => { if (!disabled && !busy && choice !== value) onChange(choice) }
2684
+ return React.createElement('div', { className: 'dsh-super-code-segmented', role: 'radiogroup', 'aria-label': label, 'aria-describedby': describedBy,
2685
+ 'aria-busy': busy || undefined, 'aria-disabled': disabled || undefined,
2686
+ onKeyDown: event => {
2687
+ const step = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[event.key]
2688
+ const next = event.key === 'Home' ? 0 : event.key === 'End' ? choices.length - 1
2689
+ : step === undefined ? -1 : (focusable + step + choices.length) % choices.length
2690
+ if (next < 0 || disabled || busy) return
2691
+ event.preventDefault()
2692
+ event.currentTarget.querySelectorAll('[role=radio]')[next]?.focus()
2693
+ pick(choices[next][0])
2694
+ } },
2695
+ ...choices.map(([choice, text], index) => React.createElement('button', { key: choice, type: 'button', role: 'radio',
2696
+ 'aria-checked': index === selected, tabIndex: index === focusable ? 0 : -1, disabled, onClick: () => pick(choice) }, text)))
2697
+ }
2518
2698
  function SettingsHome({ budgetApi, connectionApi, t, active, revision, navigate, children }) {
2519
2699
  const [budget, setBudget] = useState(null), [connection, setConnection] = useState(null), [overview, setOverview] = useState({ connections: [], sessions: [] })
2520
- const [busy, setBusy] = useState(false), [error, setError] = useState(false), alive = useRef(false), pending = useRef(false)
2521
- const load = async () => {
2522
- if (pending.current) return
2523
- pending.current = true
2700
+ // `saving` keeps the chosen value on screen until the reread confirms it.
2701
+ const [saving, setSaving] = useState(null), [failure, setFailure] = useState('')
2702
+ const alive = useRef(false), request = useRef(0), loading = useRef(false), writing = useRef(false)
2703
+ const load = async (force = false) => {
2704
+ if (!force && (loading.current || writing.current)) return
2705
+ const sequence = ++request.current
2706
+ loading.current = true
2524
2707
  try {
2525
2708
  const [b, c, o] = await Promise.all([budgetApi.readConfig(), connectionApi.readConfig(), connectionApi.overview()])
2526
2709
  if (!b.ok || !c.ok || !o.ok) throw new Error()
2527
- if (alive.current) { setBudget(b.value); setConnection(c.value); setOverview(o.value); setError(false) }
2528
- } catch { if (alive.current) setError(true) }
2529
- finally { pending.current = false }
2710
+ if (alive.current && sequence === request.current) {
2711
+ setBudget(b.value); setConnection(c.value); setOverview(o.value); setFailure(value => value === 'load' ? '' : value)
2712
+ }
2713
+ } catch { if (alive.current && sequence === request.current) setFailure('load') }
2714
+ finally { if (sequence === request.current) loading.current = false }
2530
2715
  }
2531
2716
  useEffect(() => { alive.current = true; return () => { alive.current = false } }, [budgetApi, connectionApi])
2532
2717
  useEffect(() => { if (!active) return; load(); const timer = setInterval(load, 2000); return () => clearInterval(timer) }, [active, revision, budgetApi, connectionApi])
2533
2718
  const change = async (kind, value) => {
2534
- if (busy || pending.current) return
2535
- pending.current = true; setBusy(true)
2719
+ const current = kind === 'protection' ? budget : connection
2720
+ if (writing.current || !current?.writable) return
2721
+ // A save supersedes any poll in flight, so a stale read cannot undo the choice.
2722
+ writing.current = true; request.current++; loading.current = false
2723
+ setSaving({ kind, value }); setFailure('')
2724
+ let saved = false
2536
2725
  try {
2537
- let response
2538
- if (kind === 'protection') response = await budgetApi.saveConfig(JSON.stringify({ ...budget.configuration, deletionProtection: value }), String(budget.revision))
2539
- else response = await connectionApi.saveConfig(JSON.stringify({ ...connection.configuration, enabled: value }), String(connection.revision))
2540
- if (!response.ok || !response.value.ok) throw new Error()
2541
- } catch { if (alive.current) setError(true); return }
2542
- finally { pending.current = false; if (alive.current) setBusy(false) }
2543
- if (alive.current) load()
2544
- }
2545
- const mode = budget ? budgetDraft(budget.configuration).deletionProtection : ''
2726
+ const configuration = kind === 'protection' ? { ...current.configuration, deletionProtection: value } : { ...current.configuration, enabled: value }
2727
+ const response = await (kind === 'protection' ? budgetApi : connectionApi).saveConfig(JSON.stringify(configuration), String(current.revision))
2728
+ saved = Boolean(response.ok && response.value.ok)
2729
+ } catch { /* Reported on the row below. */ }
2730
+ if (saved && alive.current) await load(true)
2731
+ writing.current = false
2732
+ if (alive.current) { setSaving(null); if (!saved) setFailure(kind) }
2733
+ }
2734
+ const mode = saving?.kind === 'protection' ? saving.value : budget ? budgetDraft(budget.configuration).deletionProtection : ''
2735
+ const enabled = saving?.kind === 'connection' ? saving.value : Boolean(connection?.configuration.enabled)
2736
+ const state = !connection || saving?.kind === 'connection' ? 'loading' : connection.state
2737
+ const listening = enabled && state === 'listening'
2738
+ const needsSetup = Boolean(connection) && !enabled && !connection.configuration.allowedDirectories.length
2739
+ const placeholder = kind => React.createElement('span', { className: 'dsh-super-code-skeleton', 'data-skeleton': kind, 'aria-hidden': true })
2740
+ const row = ({ key, icon, title, target, on, body, control }) => React.createElement('section', { className: 'dsh-super-code-home-row',
2741
+ 'data-home-row': key, 'data-active': on || undefined, 'aria-label': title, 'aria-busy': saving?.kind === key || undefined },
2742
+ React.createElement('span', { className: 'dsh-super-code-home-row-icon', 'aria-hidden': true }, React.createElement(Glyph, { type: icon })),
2743
+ React.createElement('div', { className: 'dsh-super-code-home-row-text' },
2744
+ React.createElement('h3', { className: 'dsh-super-code-home-row-title' },
2745
+ React.createElement('button', { type: 'button', 'aria-label': t('home.details', { title }), onClick: () => navigate(target) }, title, React.createElement(Glyph, { type: 'chevron' }))),
2746
+ body),
2747
+ React.createElement('div', { className: 'dsh-super-code-home-row-control' }, control),
2748
+ failure === key && React.createElement('p', { role: 'alert' }, t('home.error')))
2546
2749
  return React.createElement('section', { className: 'dsh-super-code-home' }, children,
2547
- React.createElement('div', { className: 'dsh-super-code-settings-actions' }, React.createElement(ActionButton, { type: 'button', onClick: () => navigate('preset') }, t('home.managePreset'))),
2548
- React.createElement('h3', { className: 'dsh-super-code-home-category' }, t('home.protection')),
2549
- React.createElement('div', { className: 'dsh-super-code-home-card' },
2550
- React.createElement('div', { className: 'dsh-super-code-home-heading' }, React.createElement('strong', null, t('delete.title')),
2551
- React.createElement(ActionButton, { type: 'button', onClick: () => navigate('protection') }, t('home.configure'))),
2552
- budget && React.createElement(SelectControl, { label: t('delete.mode'), value: mode, choices: ['off', 'relaxed', 'strict'].map(value => [value, t(`delete.${value}`)]), disabled: busy || !budget.writable, onChange: value => change('protection', value) })),
2553
- React.createElement('h3', { className: 'dsh-super-code-home-category' }, t('home.extensions')),
2554
- React.createElement('div', { className: 'dsh-super-code-home-card' },
2555
- React.createElement('div', { className: 'dsh-super-code-home-heading' }, React.createElement('strong', null, t('home.mcp')),
2556
- React.createElement(ActionButton, { type: 'button', onClick: () => navigate('connection') }, t('home.configure'))),
2557
- connection && React.createElement(ConnectionSwitch, { checked: connection.configuration.enabled, disabled: busy || !connection.writable,
2558
- onChange: value => value && !connection.configuration.allowedDirectories.length ? navigate('connection') : change('connection', value) }, t(`connection.state.${connection.state}`)),
2559
- connection && React.createElement('small', null, t('home.connectionCount', { count: overview.connections.length, max: connection.configuration.maxConnections })),
2560
- React.createElement('dl', { className: 'dsh-super-code-session-counts' }, ...['connected', 'history'].map(kind => React.createElement('div', { key: kind, 'data-session-count': kind },
2561
- React.createElement('dt', null, t(kind === 'connected' ? 'home.connectedSessions' : 'home.historySessions')),
2562
- React.createElement('dd', null, connection ? connectionSessions(overview)[kind].length : '—'))))),
2563
- error && React.createElement('p', { role: 'alert' }, t('home.error')))
2750
+ failure === 'load' && React.createElement('p', { role: 'alert' }, t('home.error')),
2751
+ React.createElement('div', { className: 'dsh-super-code-home-list' },
2752
+ row({ key: 'protection', icon: 'shield', title: t('delete.title'), target: 'protection', on: Boolean(mode) && mode !== 'off',
2753
+ body: budget ? React.createElement('p', { id: 'super-code-home-protection-hint', className: 'dsh-super-code-home-row-hint' }, t(`delete.hint.${mode}`)) : placeholder('text'),
2754
+ control: budget ? React.createElement(SegmentedControl, { label: t('delete.mode'), value: mode, describedBy: 'super-code-home-protection-hint',
2755
+ choices: ['off', 'relaxed', 'strict'].map(value => [value, t(`delete.${value}`)]), disabled: !budget.writable, busy: saving?.kind === 'protection',
2756
+ onChange: value => change('protection', value) }) : placeholder('control') }),
2757
+ row({ key: 'connection', icon: 'plug', title: t('home.mcp'), target: 'connection', on: enabled,
2758
+ body: connection ? React.createElement('p', { className: 'dsh-super-code-home-row-status', 'data-tone': state === 'listening' ? 'success' : state === 'error' ? 'error' : 'idle' },
2759
+ React.createElement('i', { 'aria-hidden': true }),
2760
+ React.createElement('span', null, t(`connection.state.${state}`)),
2761
+ listening && React.createElement('span', null, t('home.connectionCount', { count: overview.connections.length, max: connection.configuration.maxConnections })),
2762
+ listening && React.createElement('span', null, t('home.activeSessions', { count: connectionSessions(overview).connected.length }))) : placeholder('text'),
2763
+ control: needsSetup ? React.createElement(ActionButton, { type: 'button', onClick: () => navigate('connection') }, t('home.setupConnection'))
2764
+ : connection ? React.createElement(ConnectionSwitch, { checked: enabled, disabled: !connection.writable, 'aria-label': t('home.mcp'),
2765
+ onChange: value => value && !connection.configuration.allowedDirectories.length ? navigate('connection') : change('connection', value) })
2766
+ : placeholder('control') })))
2564
2767
  }
2565
2768
  function ConnectionConsent({ api, t }) {
2566
2769
  const [requests, setRequests] = useState([]), [busy, setBusy] = useState(false), [error, setError] = useState(false)
@@ -2671,6 +2874,8 @@ function PresetSettings({ api, budgetApi, connectionApi, openSession = () => {},
2671
2874
  }
2672
2875
  const available = status && ['available', 'installed'].includes(status.state)
2673
2876
  const versionState = status?.presetVersion ? status.presetVersion === status.pluginVersion ? 'match' : 'mismatch' : 'unknown'
2877
+ const stateProblem = Boolean(status) && ['missing', 'broken', 'conflict'].includes(status.state)
2878
+ const versionProblem = Boolean(status) && status.state !== 'missing' && versionState !== 'match'
2674
2879
  const [overviewRevision, setOverviewRevision] = useState(0)
2675
2880
  const onSaved = () => setOverviewRevision(value => value + 1)
2676
2881
  const tabs = ['home', 'preset', 'context', 'protection', 'connection']
@@ -2687,27 +2892,35 @@ function PresetSettings({ api, budgetApi, connectionApi, openSession = () => {},
2687
2892
  React.createElement('div', { className: 'dsh-super-code-settings-body' },
2688
2893
  React.createElement('div', { role: 'tabpanel', id: 'super-code-panel-home', 'aria-labelledby': 'super-code-tab-home', hidden: tab !== 'home' },
2689
2894
  React.createElement(SettingsHome, { budgetApi, connectionApi, t, active: tab === 'home', revision: overviewRevision, navigate: setTab },
2895
+ // Healthy state collapses to one status line; problems expand into a notice with its fix.
2690
2896
  React.createElement('header', { className: 'dsh-super-code-settings-header' },
2691
2897
  React.createElement('span', { className: 'dsh-super-code-settings-mark', 'aria-hidden': true }, React.createElement(Glyph, { type: 'code' })),
2692
2898
  React.createElement('div', { className: 'dsh-super-code-settings-head-text' },
2693
2899
  React.createElement('h2', { className: 'dsh-super-code-settings-name' }, t('preset.title')),
2694
- React.createElement('p', { className: 'dsh-super-code-settings-description' }, t('preset.description')))),
2695
- React.createElement('div', { className: 'dsh-super-code-settings-summary' },
2696
- React.createElement('div', { className: 'dsh-super-code-settings-status-row' },
2697
- status ? React.createElement('p', { className: 'dsh-super-code-preset-status', role: 'status', 'data-available': available },
2698
- React.createElement('i', { 'aria-hidden': true }),
2699
- React.createElement('span', null, t(status.delivery === 'declaration' && status.state === 'installed' ? 'preset.state.declaredInstalled' : `preset.state.${status.state}`)),
2700
- React.createElement('code', null, status.id))
2701
- : React.createElement('p', { className: 'dsh-super-code-preset-status', role: 'status' }, busy ? t('preset.working') : t('preset.unavailableHint')),
2702
- React.createElement('div', { className: 'dsh-super-code-settings-actions' },
2703
- React.createElement(ActionButton, { type: 'button', disabled: busy, onClick: () => run(false), 'aria-label': t('preset.refresh') },
2704
- React.createElement(IconRefreshOutline16), t('preset.refresh')))),
2705
- status && React.createElement('dl', { className: 'dsh-super-code-preset-versions' },
2706
- React.createElement('div', null, React.createElement('dt', null, t('preset.pluginVersion')), React.createElement('dd', null, status.pluginVersion)),
2707
- React.createElement('div', null, React.createElement('dt', null, t('preset.presetVersion')), React.createElement('dd', null, status.state === 'missing' ? t('preset.versionMissing') : status.presetVersion || t('preset.versionUnknown')))),
2708
- status && status.state !== 'missing' && React.createElement('p', { className: 'dsh-super-code-version-hint', role: 'status', 'data-version-state': versionState },
2709
- t(versionState === 'match' ? 'preset.versionMatches' : versionState === 'mismatch' ? 'preset.versionMismatch' : 'preset.versionUnknownHint'),
2710
- versionState === 'mismatch' && ` ${t(reinstall && status.authorable ? 'preset.versionReinstallHint' : 'preset.versionReloadHint')}`)))),
2900
+ React.createElement('div', { className: 'dsh-super-code-settings-status-row' },
2901
+ status ? React.createElement('p', { className: 'dsh-super-code-preset-status', role: 'status', 'data-available': available },
2902
+ React.createElement('i', { 'aria-hidden': true }),
2903
+ React.createElement('span', null, t(status.delivery === 'declaration' && status.state === 'installed' ? 'preset.state.declaredInstalled' : `preset.state.${status.state}`)),
2904
+ React.createElement('code', null, status.id))
2905
+ : React.createElement('p', { className: 'dsh-super-code-preset-status', role: 'status' }, busy ? t('preset.working') : t('preset.unavailableHint')),
2906
+ status && React.createElement('dl', { className: 'dsh-super-code-preset-meta' },
2907
+ React.createElement('div', null, React.createElement('dt', null, t('preset.pluginVersion')), React.createElement('dd', null, status.pluginVersion)),
2908
+ React.createElement('div', null, React.createElement('dt', null, t('preset.presetVersion')), React.createElement('dd', { 'data-stale': status.state !== 'missing' && versionState !== 'match' || undefined }, status.state === 'missing' ? t('preset.versionMissing') : status.presetVersion || t('preset.versionUnknown')))),
2909
+ status && status.state !== 'missing' && versionState === 'match' && React.createElement('span', { className: 'dsh-super-code-version-badge', 'data-version-state': 'match', title: t('preset.versionMatches') }, t('preset.versionBadge')))),
2910
+ React.createElement('div', { className: 'dsh-super-code-settings-actions' },
2911
+ React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-icon-button', disabled: busy, onClick: () => run(false), 'aria-label': t('preset.refresh') },
2912
+ React.createElement(IconRefreshOutline16, { 'aria-hidden': true })))),
2913
+ (stateProblem || versionProblem) && React.createElement('div', { className: 'dsh-super-code-preset-notice', 'data-tone': status.state === 'broken' ? 'error' : 'warning' },
2914
+ React.createElement(Glyph, { type: 'error' }),
2915
+ React.createElement('div', { className: 'dsh-super-code-preset-notice-text' },
2916
+ stateProblem && React.createElement('p', null, t(status.authorable ? 'preset.installHint' : 'preset.unavailableHint')),
2917
+ versionProblem && React.createElement('p', { 'data-version-state': versionState },
2918
+ t(versionState === 'mismatch' ? 'preset.versionMismatch' : 'preset.versionUnknownHint')),
2919
+ // The fix goes on its own line, so no locale-specific sentence joiner is needed.
2920
+ versionProblem && versionState === 'mismatch' && React.createElement('p', { className: 'dsh-super-code-preset-notice-fix' },
2921
+ t(reinstall && status.authorable ? 'preset.versionReinstallHint' : 'preset.versionReloadHint'))),
2922
+ status.authorable && React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-primary-button', onClick: () => setTab('preset') },
2923
+ t(status.state === 'missing' ? status.delivery === 'declaration' ? 'preset.installDeclared' : 'preset.install' : 'home.managePreset'))))),
2711
2924
  React.createElement('div', { role: 'tabpanel', id: 'super-code-panel-preset', 'aria-labelledby': 'super-code-tab-preset', hidden: tab !== 'preset' },
2712
2925
  status?.authorable && React.createElement('form', { onSubmit: event => { event.preventDefault(); submit() } },
2713
2926
  React.createElement('div', { className: 'dsh-super-code-settings-field' },
@@ -2727,7 +2940,8 @@ function PresetSettings({ api, budgetApi, connectionApi, openSession = () => {},
2727
2940
  status?.userConflict && status.state !== 'conflict' && React.createElement('p', null, t('preset.userConflict')),
2728
2941
  status?.delivery === 'declaration' && !status.authorable && React.createElement('p', { role: 'note' }, t('preset.declaredReadonly')),
2729
2942
  status?.delivery === 'directory' && !status.authorable && React.createElement('p', { role: 'note' }, t('preset.readonly'))),
2730
- error && React.createElement('p', { role: 'alert' }, t(error))),
2943
+ error && React.createElement('p', { role: 'alert' }, t(error)),
2944
+ React.createElement(BudgetSettings, { api: budgetApi, t, section: 'shell', active: tab === 'preset', onSaved })),
2731
2945
  React.createElement('div', { role: 'tabpanel', id: 'super-code-panel-context', 'aria-labelledby': 'super-code-tab-context', hidden: tab !== 'context' },
2732
2946
  React.createElement(BudgetSettings, { api: budgetApi, t, active: tab === 'context', onSaved })),
2733
2947
  React.createElement('div', { role: 'tabpanel', id: 'super-code-panel-protection', 'aria-labelledby': 'super-code-tab-protection', hidden: tab !== 'protection' },
@@ -2819,6 +3033,11 @@ function apply(ctx) {
2819
3033
  --sc-success:var(--dsw-color-text-success,#197661);
2820
3034
  --sc-warning:var(--dsw-color-text-warning,#9c650c);
2821
3035
  --sc-error:var(--dsw-color-text-error,#bb4545);
3036
+ --sc-active:var(--sc-accent);
3037
+ --sc-idle:var(--dsw-alias-state-idle-primary,var(--sc-faint));
3038
+ --sc-on-accent:var(--dsw-alias-label-primary-foreground,var(--sc-bg));
3039
+ --sc-shadow:color-mix(in srgb,var(--sc-text) 14%,transparent);
3040
+ --sc-radius:6px;
2822
3041
  --sc-mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
2823
3042
  --agent-muted:var(--sc-muted);--agent-line:var(--sc-line);
2824
3043
  color:var(--sc-text);font-size:14px;line-height:1.55;letter-spacing:0;
@@ -2847,9 +3066,7 @@ function apply(ctx) {
2847
3066
  .dsh-super-code-settings-mark svg{width:22px;height:22px;color:var(--sc-text)}
2848
3067
  .dsh-super-code-settings-head-text{display:grid;gap:4px;min-width:0}
2849
3068
  .dsh-super-code-settings-name{font-size:16px;font-weight:600;line-height:1.4;margin:0}
2850
- .dsh-super-code-settings-description{font-size:13px;color:var(--sc-muted);margin:0}
2851
3069
  .dsh-super-code-settings-body{padding:20px 24px 24px}
2852
- .dsh-super-code-settings-summary{padding:16px;border-radius:12px;background:var(--sc-surface)}
2853
3070
  .dsh-super-code-settings-status-row{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap}
2854
3071
  .dsh-super-code-preset-status{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin:4px 0;font-size:13px;min-width:0;flex:1}
2855
3072
  .dsh-super-code-preset-status>i{width:7px;height:7px;flex:none;border-radius:50%;background:var(--sc-warning)}
@@ -2857,15 +3074,12 @@ function apply(ctx) {
2857
3074
  .dsh-super-code-preset-status>span{font-weight:500}
2858
3075
  .dsh-super-code-preset-status code{color:var(--sc-muted);overflow-wrap:anywhere}
2859
3076
  .dsh-super-code-settings-actions{display:flex;flex:none;margin-left:auto}
2860
- .dsh-super-code-settings-actions button,.dsh-super-code-settings-form-actions button,.dsh-super-code-confirm button{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:32px;border:1px solid var(--sc-line);border-radius:8px;background:var(--sc-bg);padding:5px 10px;font-size:13px}
2861
- .dsh-super-code-settings-actions button:hover,.dsh-super-code-confirm button:hover{background:var(--sc-hover)}
3077
+ /* One button family: secondary by default, primary via class; 32px in forms, 28px in cards. */
3078
+ .dsh-super-code-settings-actions button,.dsh-super-code-settings-form-actions button,.dsh-super-code-confirm button,.dsh-super-code-home-row-control>button,.dsh-super-code-preset-notice>button,.dsh-super-code-connection-activity button{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:32px;border:1px solid var(--sc-line);border-radius:var(--sc-radius);background:var(--sc-bg);color:var(--sc-text);padding:5px 12px;font:inherit;font-size:13px;cursor:pointer;transition:background .12s,border-color .12s}
3079
+ .dsh-super-code-settings-actions button:hover,.dsh-super-code-settings-form-actions button:hover,.dsh-super-code-confirm button:hover,.dsh-super-code-home-row-control>button:hover,.dsh-super-code-preset-notice>button:hover,.dsh-super-code-connection-activity button:hover{background:var(--sc-hover);border-color:color-mix(in srgb,var(--sc-text) 22%,var(--sc-line))}
3080
+ :is(.dsh-super-code-settings,.dsh-super-code-confirm) button:focus-visible{outline:2px solid var(--sc-accent);outline-offset:2px}
3081
+ :is(.dsh-super-code-settings,.dsh-super-code-confirm) button:disabled{opacity:.5;cursor:default}
2862
3082
  .dsh-super-code-settings-actions svg{width:14px;height:14px}
2863
- .dsh-super-code-preset-versions{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;margin:16px 0 0;padding-top:16px;border-top:1px solid var(--sc-line)}
2864
- .dsh-super-code-preset-versions>div+div{border-left:1px solid var(--sc-line);padding-left:16px}
2865
- .dsh-super-code-preset-versions dt{font-size:12px;color:var(--sc-muted)}
2866
- .dsh-super-code-preset-versions dd{font-family:var(--sc-mono);font-variant-numeric:tabular-nums;font-size:15px;margin:4px 0 0;overflow-wrap:anywhere}
2867
- .dsh-super-code-version-hint{font-size:12px;color:var(--sc-muted);margin:12px 0 0;overflow-wrap:anywhere}
2868
- .dsh-super-code-version-hint[data-version-state=mismatch],.dsh-super-code-version-hint[data-version-state=unknown]{padding:10px 12px;background:color-mix(in srgb,var(--sc-warning) 8%,var(--sc-bg));border-left:2px solid var(--sc-warning);border-radius:0 6px 6px 0;color:var(--sc-text)}
2869
3083
  .dsh-super-code-settings form{display:grid;gap:16px;margin-top:24px}
2870
3084
  .dsh-super-code-settings form>h3{margin:0;font-size:14px;font-weight:600}
2871
3085
  .dsh-super-code-settings-field{display:grid;gap:6px}
@@ -2874,8 +3088,8 @@ function apply(ctx) {
2874
3088
  .dsh-super-code-settings-form-actions{display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:12px;padding-top:4px}
2875
3089
  .dsh-super-code-settings-form-actions>small{flex:1;min-width:220px}
2876
3090
  .dsh-super-code-settings-form-actions>button{margin-left:auto;flex:none}
2877
- .dsh-super-code-settings .dsh-super-code-primary-button,.dsh-super-code-confirm .dsh-super-code-primary-button{background:var(--sc-text);border-color:var(--sc-text);color:var(--sc-bg);font-weight:500}
2878
- .dsh-super-code-settings .dsh-super-code-primary-button:hover,.dsh-super-code-confirm .dsh-super-code-primary-button:hover{background:color-mix(in srgb,var(--sc-text) 85%,var(--sc-bg))}
3091
+ .dsh-super-code-settings .dsh-super-code-primary-button,.dsh-super-code-confirm .dsh-super-code-primary-button{background:var(--sc-accent);border-color:var(--sc-accent);color:var(--sc-on-accent);font-weight:500}
3092
+ .dsh-super-code-settings .dsh-super-code-primary-button:hover:not(:disabled),.dsh-super-code-confirm .dsh-super-code-primary-button:hover:not(:disabled){background:color-mix(in srgb,var(--sc-accent) 86%,var(--sc-text));border-color:color-mix(in srgb,var(--sc-accent) 86%,var(--sc-text))}
2879
3093
  .dsh-super-code-settings-guidance:empty{display:none}
2880
3094
  .dsh-super-code-settings-guidance{margin-top:20px;padding-top:12px;border-top:1px solid var(--sc-line);color:var(--sc-muted);font-size:12px}
2881
3095
  .dsh-super-code-settings-guidance p{margin:0 0 4px}
@@ -2884,11 +3098,79 @@ function apply(ctx) {
2884
3098
  .dsh-super-code-settings-tabs>[role=tab][aria-selected=true]{border-bottom-color:var(--sc-text);color:var(--sc-text);font-weight:600}
2885
3099
  .dsh-super-code-settings-tabs>[role=tab]:focus-visible{outline:2px solid var(--sc-active);outline-offset:3px;border-radius:2px}
2886
3100
  .dsh-super-code-settings [role=tabpanel][hidden]{display:none}
2887
- .dsh-super-code-budgets form{gap:24px}
2888
- .dsh-super-code-budget-hint{margin:0;color:var(--sc-muted);font-size:12px;line-height:1.65}
2889
- .dsh-super-code-budget-group{display:flex;flex-direction:column;gap:16px;min-width:0}
2890
- .dsh-super-code-budget-group h3{margin:0;font-size:14px;font-weight:600}
2891
- .dsh-super-code-budget-exclusive{border-top:1px solid var(--sc-line);padding-top:24px}
3101
+ /* Settings primitives: stacked sections of label/control rows, callouts, autosave status. */
3102
+ .dsh-super-code-settings form.dsh-super-code-stack,.dsh-super-code-stack{display:grid;gap:24px;margin:0;min-width:0}
3103
+ .dsh-super-code-section{display:grid;gap:12px;min-width:0}
3104
+ .dsh-super-code-section-head{display:flex;align-items:flex-end;justify-content:space-between;gap:12px}
3105
+ .dsh-super-code-section-heading{display:grid;gap:4px;min-width:0}
3106
+ .dsh-super-code-section-heading h3{margin:0;font-size:14px;font-weight:600;line-height:1.4}
3107
+ .dsh-super-code-section-heading p{margin:0;font-size:12px;line-height:1.6;color:var(--sc-muted);text-wrap:pretty}
3108
+ .dsh-super-code-section-actions{display:flex;flex:none;gap:8px}
3109
+ .dsh-super-code-section-body{border:1px solid var(--sc-line);border-radius:12px;background:var(--sc-bg);min-width:0}
3110
+ .dsh-super-code-section-body[data-plain]{border:0;border-radius:0;background:none}
3111
+ .dsh-super-code-setting-row{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:8px 24px;padding:12px 16px}
3112
+ .dsh-super-code-section-body>*+.dsh-super-code-setting-row,.dsh-super-code-section-body>*+.dsh-super-code-section-more,.dsh-super-code-section-more>.dsh-super-code-setting-row{border-top:1px solid var(--sc-line)}
3113
+ .dsh-super-code-setting-row-text{display:grid;gap:2px;min-width:0}
3114
+ .dsh-super-code-settings .dsh-super-code-setting-row-text>label{font-size:13px;font-weight:500;line-height:1.5}
3115
+ .dsh-super-code-setting-row-text>p{margin:0;font-size:12px;line-height:1.6;color:var(--sc-muted);overflow-wrap:anywhere;text-wrap:pretty}
3116
+ .dsh-super-code-setting-row-text>.dsh-super-code-setting-row-error{color:var(--sc-error)}
3117
+ .dsh-super-code-setting-row-control{display:flex;justify-content:flex-end;min-width:0}
3118
+ .dsh-super-code-setting-row-control>:is(input,.dsh-super-code-select){width:180px}
3119
+ .dsh-super-code-setting-row-control>input{height:32px;padding:5px 10px;border-radius:8px;font-variant-numeric:tabular-nums;text-align:right}
3120
+ .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}
3121
+ .dsh-super-code-shell-status code{max-width:100%;font-size:11px}
3122
+ #super-code-shell .dsh-super-code-connection-switch:has(input:disabled){cursor:not-allowed}
3123
+ #super-code-shell .dsh-super-code-connection-switch input:disabled{pointer-events:none}
3124
+ #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}
3125
+ #super-code-shell .dsh-super-code-connection-switch input:disabled+.dsh-super-code-connection-track i{background:var(--sc-muted)}
3126
+ .dsh-super-code-setting-row[data-invalid] input{border-color:var(--sc-error)}
3127
+ .dsh-super-code-settings input[type=number]{appearance:textfield}
3128
+ .dsh-super-code-settings input::-webkit-inner-spin-button{appearance:none}
3129
+ .dsh-super-code-section-more>summary{display:flex;align-items:center;gap:6px;padding:10px 16px;list-style:none;cursor:pointer;font-size:13px;color:var(--sc-muted)}
3130
+ .dsh-super-code-section-more>summary::-webkit-details-marker{display:none}
3131
+ .dsh-super-code-section-more>summary:hover{color:var(--sc-text)}
3132
+ .dsh-super-code-section-more>summary .dsh-super-code-glyph{width:14px;height:14px;transform:rotate(-90deg);transition:transform .15s}
3133
+ .dsh-super-code-section-more[open]>summary .dsh-super-code-glyph{transform:none}
3134
+ .dsh-super-code-callout{--tone:var(--sc-accent);display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border:1px solid color-mix(in srgb,var(--tone) 26%,var(--sc-line));border-radius:8px;background:color-mix(in srgb,var(--tone) 6%,var(--sc-bg))}
3135
+ .dsh-super-code-callout[data-tone=warning]{--tone:var(--sc-warning)}
3136
+ .dsh-super-code-callout[data-tone=error]{--tone:var(--sc-error)}
3137
+ .dsh-super-code-callout[data-tone=success]{--tone:var(--sc-success)}
3138
+ .dsh-super-code-callout>.dsh-super-code-glyph{width:16px;height:16px;margin-top:2px;color:var(--tone)}
3139
+ .dsh-super-code-callout-text{display:grid;gap:4px;flex:1;min-width:0}
3140
+ .dsh-super-code-callout-text p{margin:0;font-size:12px;line-height:1.6;color:var(--sc-text);overflow-wrap:anywhere;text-wrap:pretty}
3141
+ .dsh-super-code-callout-text p+p{color:var(--sc-muted)}
3142
+ .dsh-super-code-callout>button{flex:none;align-self:center;min-height:28px;padding:3px 12px;font-size:12px}
3143
+ .dsh-super-code-settings .dsh-super-code-callout[role=alert]{font-size:inherit;color:inherit}
3144
+ .dsh-super-code-save-indicator{display:inline-flex;align-items:center;gap:6px;margin:0;font-size:12px;color:var(--sc-muted)}
3145
+ .dsh-super-code-save-indicator>i{width:6px;height:6px;border-radius:50%;background:var(--sc-idle);transition:background .15s}
3146
+ .dsh-super-code-save-indicator[data-save-state=saving]>i{background:var(--sc-accent);animation:sc-pulse 1s ease-in-out infinite}
3147
+ .dsh-super-code-save-indicator[data-save-state=saved]>i{background:var(--sc-success)}
3148
+ .dsh-super-code-save-indicator[data-save-state=invalid]{color:var(--sc-warning)}
3149
+ .dsh-super-code-save-indicator[data-save-state=invalid]>i{background:var(--sc-warning)}
3150
+ .dsh-super-code-save-indicator[data-save-state=error]{color:var(--sc-error)}
3151
+ .dsh-super-code-save-indicator[data-save-state=error]>i{background:var(--sc-error)}
3152
+ @keyframes sc-pulse{50%{opacity:.35}}
3153
+ .dsh-super-code-settings-footer{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px 12px;padding-top:16px;border-top:1px solid var(--sc-line)}
3154
+ .dsh-super-code-settings-footer-actions{display:flex;align-items:center;flex-wrap:wrap;gap:8px;margin-left:auto;font-size:12px;color:var(--sc-muted)}
3155
+ .dsh-super-code-settings-footer-actions button{display:inline-flex;align-items:center;min-height:28px;border:1px solid var(--sc-line);border-radius:var(--sc-radius);background:var(--sc-bg);padding:3px 12px;font-size:12px}
3156
+ .dsh-super-code-settings-footer-actions button:hover:not(:disabled){background:var(--sc-hover)}
3157
+ .dsh-super-code-settings .dsh-super-code-danger-button{color:var(--sc-error);border-color:color-mix(in srgb,var(--sc-error) 35%,var(--sc-line))}
3158
+ .dsh-super-code-settings .dsh-super-code-danger-button:hover:not(:disabled){background:color-mix(in srgb,var(--sc-error) 8%,var(--sc-bg))}
3159
+ .dsh-super-code-choice-cards{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
3160
+ .dsh-super-code-settings .dsh-super-code-choice-card{position:relative;display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border:1px solid var(--sc-line);border-radius:12px;background:var(--sc-bg);cursor:pointer;font-weight:400;transition:border-color .12s,background .12s}
3161
+ .dsh-super-code-choice-card:hover{border-color:color-mix(in srgb,var(--sc-text) 22%,var(--sc-line))}
3162
+ .dsh-super-code-choice-card[data-checked]{border-color:var(--sc-accent);background:var(--sc-selected)}
3163
+ .dsh-super-code-choice-card>input{position:absolute;opacity:0;inset:0;width:100%;height:100%;margin:0;cursor:pointer}
3164
+ .dsh-super-code-choice-card>input:disabled{cursor:default}
3165
+ .dsh-super-code-choice-card:has(input:disabled){opacity:.55;cursor:default}
3166
+ .dsh-super-code-choice-card:has(input:focus-visible){outline:2px solid var(--sc-accent);outline-offset:2px}
3167
+ .dsh-super-code-choice-card>i{flex:none;width:16px;height:16px;margin-top:2px;border:1.5px solid var(--sc-line);border-radius:50%;background:var(--sc-bg);transition:border-color .12s,box-shadow .12s}
3168
+ .dsh-super-code-choice-card[data-checked]>i{border-color:var(--sc-accent);box-shadow:inset 0 0 0 3px var(--sc-bg),inset 0 0 0 8px var(--sc-accent)}
3169
+ .dsh-super-code-choice-card-text{display:grid;gap:4px;min-width:0}
3170
+ .dsh-super-code-choice-card-text strong{font-size:13px;font-weight:600}
3171
+ .dsh-super-code-choice-card-text small{font-size:12px;line-height:1.6;color:var(--sc-muted);text-wrap:pretty}
3172
+ @container(max-width:560px){.dsh-super-code-choice-cards{grid-template-columns:1fr}}
3173
+ @container(max-width:480px){.dsh-super-code-setting-row:not(:has(.dsh-super-code-connection-switch)){grid-template-columns:minmax(0,1fr)}.dsh-super-code-setting-row:not(:has(.dsh-super-code-connection-switch)) .dsh-super-code-setting-row-control{justify-content:flex-start}.dsh-super-code-setting-row-control>:is(input,.dsh-super-code-select){width:100%;text-align:left}}
2892
3174
 
2893
3175
  .dsh-super-code-connection{display:grid;gap:18px}
2894
3176
  .dsh-super-code-connection form{display:grid;gap:16px}
@@ -2900,19 +3182,17 @@ function apply(ctx) {
2900
3182
  .dsh-super-code-connection-client pre{white-space:pre-wrap;overflow-wrap:anywhere;font:12px/1.7 ui-monospace,monospace;background:var(--sc-surface);padding:12px;border-radius:8px;margin:0}
2901
3183
  .dsh-super-code-connection small{color:var(--sc-muted);font-size:12px;line-height:1.6}
2902
3184
  .dsh-super-code-connection .dsh-super-code-settings-actions{flex-wrap:wrap;gap:8px}
2903
- .dsh-super-code-connection-switch{position:relative;display:inline-flex;align-items:center;gap:10px;cursor:pointer;font-size:13px;font-weight:500;width:fit-content}
3185
+ .dsh-super-code-connection-switch{position:relative;display:inline-flex;align-items:center;gap:10px;cursor:pointer;font-size:13px;font-weight:500;width:fit-content}
2904
3186
  .dsh-super-code-connection-switch input[role=switch]{position:absolute;opacity:0;width:34px;height:20px;margin:0;padding:0;left:0;top:50%;transform:translateY(-50%);z-index:1;cursor:pointer}
2905
3187
  .dsh-super-code-connection-track{display:inline-flex;align-items:center;flex:none;width:34px;height:20px;border:1px solid var(--sc-line);border-radius:20px;padding:2px;background:var(--sc-surface);transition:background .15s}
2906
3188
  .dsh-super-code-connection-track i{display:block;width:14px;height:14px;border-radius:50%;background:var(--sc-muted);transition:transform .15s}
2907
3189
  .dsh-super-code-connection-switch input:checked+.dsh-super-code-connection-track{background:var(--sc-accent);border-color:var(--sc-accent)}
2908
- .dsh-super-code-connection-switch input:checked+.dsh-super-code-connection-track i{transform:translateX(14px);background:#fff}
3190
+ .dsh-super-code-connection-switch input:checked+.dsh-super-code-connection-track i{transform:translateX(14px);background:var(--sc-on-accent)}
2909
3191
  .dsh-super-code-connection-switch input:focus-visible+.dsh-super-code-connection-track{outline:2px solid var(--sc-accent);outline-offset:3px}
2910
3192
  .dsh-super-code-connection-switch input:disabled+.dsh-super-code-connection-track{opacity:.5}
2911
3193
  .dsh-super-code-connection input[type=number]{appearance:textfield}
2912
3194
  .dsh-super-code-connection input::-webkit-inner-spin-button{appearance:none}
2913
3195
 
2914
- .dsh-super-code-budget-switch{display:flex;align-items:center;gap:10px;font-size:13px;cursor:pointer}
2915
- .dsh-super-code-budget-switch input{width:30px;height:17px;flex:none;accent-color:var(--sc-active);cursor:pointer}
2916
3196
  .dsh-super-code-budget-default{color:var(--sc-muted);font-weight:400;font-size:12px}
2917
3197
  .dsh-super-code-budgets fieldset{min-width:0;margin:0;border:0;padding:0}
2918
3198
  .dsh-super-code-budgets legend{font-size:13px;font-weight:500;margin-bottom:12px;padding:0}
@@ -2923,37 +3203,82 @@ function apply(ctx) {
2923
3203
  .dsh-super-code-budgets .dsh-super-code-settings-form-actions{border-top:1px solid var(--sc-line);padding-top:16px}
2924
3204
  @container(max-width:420px){.dsh-super-code-budget-grid{grid-template-columns:1fr}.dsh-super-code-settings-tabs{padding:0 16px}}
2925
3205
  .dsh-super-code-settings [role=alert],.dsh-super-code-detail [role=alert],.dsh-super-code-tree-error{font-size:13px;color:var(--sc-error);overflow-wrap:anywhere}
2926
- @container(max-width:420px){.dsh-super-code-settings-header{padding-bottom:16px;margin-bottom:16px}.dsh-super-code-settings-body{padding:16px}.dsh-super-code-settings-summary{padding:12px}.dsh-super-code-settings-status-row{gap:8px}.dsh-super-code-preset-status{flex-basis:100%}.dsh-super-code-settings-form-actions>small{min-width:0;flex-basis:100%}}
3206
+ @container(max-width:420px){.dsh-super-code-settings-header{padding-bottom:16px;margin-bottom:16px}.dsh-super-code-settings-body{padding:16px}.dsh-super-code-settings-status-row{gap:8px}.dsh-super-code-preset-status{flex-basis:100%}.dsh-super-code-settings-form-actions>small{min-width:0;flex-basis:100%}}
2927
3207
 
2928
- .dsh-super-code-session-counts{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;margin:4px 0 0;padding-top:12px;border-top:1px solid var(--sc-line)}
2929
- .dsh-super-code-session-counts dt{font-size:12px;color:var(--sc-muted)}
2930
- .dsh-super-code-session-counts dd{font-size:22px;font-variant-numeric:tabular-nums;font-weight:600;margin:3px 0 0}
2931
- .dsh-super-code-connection-activity{display:grid;gap:10px;border:1px solid var(--sc-line);border-radius:10px;padding:14px}
3208
+ .dsh-super-code-connection-activity{display:grid;gap:10px;border:1px solid var(--sc-line);border-radius:var(--sc-radius);padding:14px}
2932
3209
  .dsh-super-code-connection-activity h3{margin:0;font-size:13px;font-weight:600}
2933
3210
  .dsh-super-code-connection-activity h3:not(:first-child){margin-top:6px}
2934
3211
  .dsh-super-code-connection-activity h4{margin:0 0 6px;font-size:12px;color:var(--sc-muted);font-weight:500}
2935
3212
  .dsh-super-code-connection-activity p{margin:0;font-size:12px;color:var(--sc-muted)}
2936
- .dsh-super-code-connection-activity button{border:1px solid var(--sc-line);border-radius:7px;background:var(--sc-bg);padding:4px 8px;font-size:12px}
2937
- .dsh-super-code-connection-activity button:hover{background:var(--sc-hover)}
3213
+ .dsh-super-code-connection-activity button{min-height:28px;padding:3px 10px;font-size:12px}
2938
3214
  /* Settings overview and directory consent use the same host theme aliases. */
2939
3215
  .dsh-super-code-settings-tabs{gap:20px;overflow-x:auto;white-space:nowrap}
2940
- .dsh-super-code-home{display:grid;gap:12px}
2941
- .dsh-super-code-home-category{font-size:11px;letter-spacing:.06em;color:var(--sc-muted);margin:12px 0 0}
2942
- .dsh-super-code-home-card{display:grid;gap:12px;border:1px solid var(--sc-line);border-radius:10px;padding:14px}
2943
- .dsh-super-code-home-heading{display:flex;justify-content:space-between;align-items:center;gap:12px}
2944
- .dsh-super-code-home-heading strong{font-size:13px;font-weight:600}
2945
- .dsh-super-code-home-card :is(p,small){margin:0;font-size:12px;color:var(--sc-muted)}
2946
- .dsh-super-code-home-card h4{font-size:12px;font-weight:500;margin:6px 0 0}
2947
- .dsh-super-code-home-card button,.dsh-super-code-home>.dsh-super-code-settings-actions button{border:1px solid var(--sc-line);border-radius:7px;background:var(--sc-bg);padding:4px 8px;font-size:12px}
2948
- .dsh-super-code-home-card button:hover{background:var(--sc-hover)}
3216
+ /* Home: one status header, then a settings list whose rows act in place and open details. */
3217
+ .dsh-super-code-home{display:grid;gap:16px}
3218
+ .dsh-super-code-home .dsh-super-code-settings-header{align-items:flex-start;padding-bottom:16px;margin-bottom:0}
3219
+ .dsh-super-code-home .dsh-super-code-settings-head-text{flex:1}
3220
+ .dsh-super-code-settings-head-text .dsh-super-code-settings-status-row{justify-content:flex-start;align-items:center;gap:2px 10px}
3221
+ .dsh-super-code-settings-head-text .dsh-super-code-preset-status{flex:none;margin:0;font-size:12px;gap:6px}
3222
+ .dsh-super-code-settings-head-text .dsh-super-code-preset-status>span{font-weight:400;color:var(--sc-muted)}
3223
+ .dsh-super-code-settings-head-text .dsh-super-code-preset-status code{font:12px var(--sc-mono)}
3224
+ .dsh-super-code-preset-meta{display:flex;flex-wrap:wrap;gap:0 10px;margin:0;font-size:12px;color:var(--sc-muted)}
3225
+ .dsh-super-code-preset-meta>div{display:flex;gap:4px}
3226
+ .dsh-super-code-preset-meta>div:before{content:"·";color:var(--sc-faint);margin-right:6px}
3227
+ .dsh-super-code-preset-meta dd{margin:0;font-family:var(--sc-mono);font-variant-numeric:tabular-nums;color:var(--sc-text)}
3228
+ .dsh-super-code-preset-meta dd[data-stale]{color:var(--sc-warning);font-weight:600}
3229
+ .dsh-super-code-version-badge{display:inline-flex;align-items:center;height:18px;padding:0 7px;border-radius:9px;font-size:11px;font-weight:500;color:var(--sc-success);background:color-mix(in srgb,var(--sc-success) 10%,transparent)}
3230
+ .dsh-super-code-settings-actions>.dsh-super-code-icon-button{min-height:0;width:30px;height:30px;padding:0;border:0;background:transparent;color:var(--sc-muted)}
3231
+ .dsh-super-code-settings-actions>.dsh-super-code-icon-button:hover{background:var(--sc-hover);color:var(--sc-text)}
3232
+ .dsh-super-code-settings-actions>.dsh-super-code-icon-button svg{width:16px;height:16px}
3233
+ .dsh-super-code-preset-notice{display:flex;align-items:flex-start;gap:10px;padding:12px 14px;border:1px solid color-mix(in srgb,var(--sc-warning) 28%,var(--sc-line));border-radius:8px;background:color-mix(in srgb,var(--sc-warning) 7%,var(--sc-bg))}
3234
+ .dsh-super-code-preset-notice[data-tone=error]{border-color:color-mix(in srgb,var(--sc-error) 28%,var(--sc-line));background:color-mix(in srgb,var(--sc-error) 6%,var(--sc-bg))}
3235
+ .dsh-super-code-preset-notice>.dsh-super-code-glyph{width:16px;height:16px;margin-top:2px;color:var(--sc-warning)}
3236
+ .dsh-super-code-preset-notice[data-tone=error]>.dsh-super-code-glyph{color:var(--sc-error)}
3237
+ .dsh-super-code-preset-notice-text{display:grid;gap:4px;flex:1;min-width:0}
3238
+ .dsh-super-code-preset-notice-text p{margin:0;font-size:12px;line-height:1.6;overflow-wrap:anywhere;text-wrap:pretty}
3239
+ .dsh-super-code-preset-notice-text .dsh-super-code-preset-notice-fix{color:var(--sc-muted)}
3240
+ .dsh-super-code-preset-notice>button{flex:none;align-self:center;min-height:28px;padding:3px 12px;font-size:12px}
3241
+ .dsh-super-code-home-list{border:1px solid var(--sc-line);border-radius:10px;background:var(--sc-bg)}
3242
+ .dsh-super-code-home-row{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:4px 14px;padding:14px 16px}
3243
+ .dsh-super-code-home-row+.dsh-super-code-home-row{border-top:1px solid var(--sc-line)}
3244
+ .dsh-super-code-home-row-icon{display:grid;place-items:center;align-self:start;width:32px;height:32px;border-radius:8px;background:var(--sc-surface);color:var(--sc-muted);transition:background .15s,color .15s}
3245
+ .dsh-super-code-home-row-icon .dsh-super-code-glyph{width:17px;height:17px;color:inherit}
3246
+ .dsh-super-code-home-row[data-active] .dsh-super-code-home-row-icon{background:color-mix(in srgb,var(--sc-accent) 10%,var(--sc-bg));color:var(--sc-accent)}
3247
+ .dsh-super-code-home-row-text{display:grid;gap:2px;min-width:0}
3248
+ .dsh-super-code-home-row-title{margin:0;font-size:13px;font-weight:600;line-height:1.5}
3249
+ .dsh-super-code-home-row-title>button{display:inline-flex;align-items:center;gap:2px;border:0;border-radius:4px;background:none;padding:0;font:inherit;color:var(--sc-text)}
3250
+ .dsh-super-code-home-row-title>button:hover{color:var(--sc-accent)}
3251
+ .dsh-super-code-home-row-title .dsh-super-code-glyph{width:14px;height:14px;color:var(--sc-faint);transform:rotate(-90deg);transition:transform .12s,color .12s}
3252
+ .dsh-super-code-home-row-title>button:hover .dsh-super-code-glyph{color:currentColor;transform:translateX(2px) rotate(-90deg)}
3253
+ .dsh-super-code-home-row :is(.dsh-super-code-home-row-hint,.dsh-super-code-home-row-status){margin:0;font-size:12px;line-height:1.55;color:var(--sc-muted)}
3254
+ /* Avoid a lone trailing character on wrapped CJK hints. */
3255
+ .dsh-super-code-home-row-hint{text-wrap:pretty}
3256
+ .dsh-super-code-home-row-status{display:flex;flex-wrap:wrap;align-items:center;gap:0 6px}
3257
+ .dsh-super-code-home-row-status>i{width:6px;height:6px;flex:none;border-radius:50%;background:var(--sc-idle)}
3258
+ .dsh-super-code-home-row-status[data-tone=success]>i{background:var(--sc-success)}
3259
+ .dsh-super-code-home-row-status[data-tone=error]>i{background:var(--sc-error)}
3260
+ .dsh-super-code-home-row-status>span+span:before{content:"·";margin-right:6px;color:var(--sc-faint)}
3261
+ .dsh-super-code-home-row-control{display:flex;justify-content:flex-end}
3262
+ .dsh-super-code-home-row-control>button{min-height:28px;padding:3px 12px;font-size:12px}
3263
+ .dsh-super-code-home-row>[role=alert]{grid-column:2/-1;margin:2px 0 0;font-size:12px}
3264
+ @container(max-width:560px){.dsh-super-code-home-row[data-home-row=protection]{grid-template-columns:auto minmax(0,1fr)}.dsh-super-code-home-row[data-home-row=protection]>.dsh-super-code-home-row-control{grid-column:2;justify-content:flex-start;margin-top:6px}}
3265
+ .dsh-super-code-segmented{display:inline-flex;gap:2px;padding:2px;border:1px solid var(--sc-line);border-radius:8px;background:var(--sc-surface)}
3266
+ .dsh-super-code-segmented>[role=radio]{min-height:26px;border:0;border-radius:6px;background:transparent;padding:3px 12px;font-size:12px;color:var(--sc-muted);white-space:nowrap}
3267
+ .dsh-super-code-segmented>[role=radio]:hover:not(:disabled){color:var(--sc-text)}
3268
+ .dsh-super-code-segmented>[role=radio][aria-checked=true]{background:var(--sc-bg);color:var(--sc-text);font-weight:500;box-shadow:0 1px 2px var(--sc-shadow)}
3269
+ .dsh-super-code-segmented[aria-busy=true]{cursor:progress}
3270
+ .dsh-super-code-segmented[aria-busy=true]>[role=radio]{pointer-events:none}
3271
+ .dsh-super-code-skeleton{display:block;border-radius:4px;background:linear-gradient(90deg,var(--sc-surface) 25%,var(--sc-hover) 50%,var(--sc-surface) 75%);background-size:200% 100%;animation:sc-skeleton 1.2s ease-in-out infinite}
3272
+ .dsh-super-code-skeleton[data-skeleton=text]{width:min(60%,280px);height:12px;margin-top:5px}
3273
+ .dsh-super-code-skeleton[data-skeleton=control]{width:96px;height:28px;border-radius:8px}
3274
+ @keyframes sc-skeleton{to{background-position:-200% 0}}
2949
3275
  .dsh-super-code-connection-list{list-style:none;padding:0;margin:0;max-height:280px;overflow:auto}
2950
3276
  .dsh-super-code-connection-list li{display:flex;align-items:center;gap:10px;padding:9px 0;border-bottom:1px solid var(--sc-line)}
2951
3277
  .dsh-super-code-connection-list li:last-child{border:0}
2952
3278
  .dsh-super-code-connection-list li>span{display:grid;gap:2px;flex:1;min-width:0;overflow-wrap:anywhere}
2953
3279
  .dsh-super-code-connection-list strong{font-size:12px;font-weight:500}
2954
- .dsh-super-code-connection-list code{font:10px/1.5 var(--sc-mono);color:var(--sc-muted)}
3280
+ .dsh-super-code-connection-list code{font:11px/1.5 var(--sc-mono);color:var(--sc-muted)}
2955
3281
  .dsh-super-code-connection-list button{flex:none}
2956
- .dsh-super-code-home .dsh-super-code-settings-header{padding-bottom:12px;margin-bottom:0}
2957
3282
  .dsh-super-code-directory-fieldset{border:0;padding:0;margin:0;min-width:0;display:grid;gap:10px}
2958
3283
  .dsh-super-code-directory-fieldset legend{font-size:13px;font-weight:500;margin-bottom:10px}
2959
3284
  .dsh-super-code-directory-list{border:1px solid var(--sc-line);border-radius:9px;max-height:330px;overflow:auto}
@@ -3048,10 +3373,16 @@ function apply(ctx) {
3048
3373
  [data-feedback-live=false] .dsh-super-code-feedback-step .dsh-super-code-feedback-mark.active:before{animation:none}
3049
3374
  @keyframes sc-feedback-spin{to{transform:rotate(360deg)}}
3050
3375
  @media(prefers-reduced-motion:reduce){.dsh-super-code-feedback-mark.active:before{animation:none!important}}
3051
- .dsh-super-code-feedback-activity{display:flex;gap:7px;align-items:flex-start;min-height:28px;padding:4px 0;line-height:20px}
3052
- .dsh-super-code-feedback-activity-text{min-width:0;flex:1;overflow-wrap:anywhere;white-space:pre-wrap}
3053
- .dsh-super-code-feedback-activity>small{flex:none;font-size:10px;line-height:20px}
3054
- .dsh-super-code-feedback-tool{max-width:84px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}
3376
+ .dsh-super-code-feedback-tools{display:flex;flex-wrap:wrap;gap:4px 10px;list-style:none;margin:4px 0;padding:0 5px}
3377
+ .dsh-super-code-feedback-tools>li{display:inline-flex;align-items:center;gap:3px;min-height:22px;font-family:var(--sc-mono);font-size:11px;line-height:18px;color:var(--sc-muted)}
3378
+ .dsh-super-code-feedback-tools>li[data-running]>span{color:var(--sc-active)}
3379
+ .dsh-super-code-tool-badge{display:inline-flex;align-items:center;justify-content:center;min-width:18px;height:18px;padding:0 4px;border:1px solid currentColor;border-radius:9px;font-family:inherit;font-size:11px;font-weight:600;font-variant-numeric:tabular-nums;line-height:16px}
3380
+ .dsh-super-code-tool-badge[data-tone=success]{color:var(--sc-success);background:color-mix(in srgb,var(--sc-success) 10%,transparent)}
3381
+ .dsh-super-code-tool-badge[data-tone=warning]{color:var(--sc-warning);background:color-mix(in srgb,var(--sc-warning) 12%,transparent)}
3382
+ .dsh-super-code-tool-badge[data-zero]{color:var(--sc-faint);background:transparent;border-color:color-mix(in srgb,var(--sc-faint) 40%,transparent);font-weight:400}
3383
+ .dsh-super-code-state{display:flex;align-items:center;gap:6px;margin:6px 0;padding:6px 8px;border-radius:var(--sc-radius);font-size:12px;line-height:18px;color:var(--sc-muted);background:color-mix(in srgb,var(--sc-line) 40%,transparent)}
3384
+ .dsh-super-code-state>.dsh-super-code-glyph{flex:none;width:14px;height:14px}
3385
+ .dsh-super-code-state[data-tone=error]{color:var(--sc-error);background:color-mix(in srgb,var(--sc-error) 8%,transparent)}
3055
3386
  .dsh-super-code-feedback-list>li[data-feedback-kind=open]{padding-bottom:8px}
3056
3387
  .dsh-super-code-feedback-open{display:inline-flex;align-items:center;gap:4px;min-height:24px;border:0;border-radius:4px;background:transparent;color:var(--sc-muted);font:inherit;font-size:11px;padding:2px 4px}
3057
3388
  .dsh-super-code-feedback-open>.dsh-super-code-glyph{width:12px;height:12px;transition:transform .15s}
@@ -3064,7 +3395,7 @@ function apply(ctx) {
3064
3395
  .dsh-super-code-feedback-file>.dsh-super-code-glyph{flex:none;width:14px;height:14px;color:var(--sc-muted)}
3065
3396
  .dsh-super-code-feedback-file strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:400}
3066
3397
  .dsh-super-code-feedback-file small{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
3067
- .dsh-super-code-feedback-file-operation{flex:none;margin-left:auto;font-size:10px;color:var(--sc-success)}
3398
+ .dsh-super-code-feedback-file-operation{flex:none;margin-left:auto;font-size:11px;color:var(--sc-success)}
3068
3399
  .dsh-super-code-feedback button:focus-visible,.dsh-super-code-feedback-scroll:focus-visible{outline:2px solid var(--sc-accent);outline-offset:-2px}
3069
3400
 
3070
3401
  /* Memory library: geometry stays at 76px per row. */
@@ -3108,7 +3439,7 @@ function apply(ctx) {
3108
3439
  .dsh-super-code-memory-row-topic{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--sc-muted);font-size:11px}
3109
3440
  .dsh-super-code-memory-row-kind{color:var(--sc-muted);white-space:nowrap}
3110
3441
  .dsh-super-code-memory-row strong{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:500;line-height:16px}
3111
- .dsh-super-code-memory-row-meta{display:flex;align-items:center;gap:8px;font-size:10px;color:var(--sc-muted);white-space:nowrap;line-height:12px}
3442
+ .dsh-super-code-memory-row-meta{display:flex;align-items:center;gap:8px;font-size:11px;color:var(--sc-muted);white-space:nowrap;line-height:12px}
3112
3443
  .dsh-super-code-memory-row-meta>span+span{border-left:1px solid var(--sc-line);padding-left:8px;font-family:var(--sc-mono)}
3113
3444
  .dsh-super-code-memory-empty{padding:24px 8px;color:var(--sc-muted);font-size:13px;line-height:1.8}
3114
3445
  .dsh-super-code-memory-body{flex:1;min-height:0;overflow:auto;padding:16px;background:var(--sc-surface)}
@@ -3146,7 +3477,10 @@ function apply(ctx) {
3146
3477
  .dsh-super-code-memory-action[data-action=read]{color:var(--sc-accent)}
3147
3478
  .dsh-super-code-memory-action[data-action=remember]{color:var(--sc-success)}
3148
3479
 
3149
- /* Direct memory editing keeps one current copy, with no version UI. */
3480
+ .dsh-super-code-memory-editor fieldset{display:grid;gap:8px;border:1px solid var(--sc-line);border-radius:6px;min-width:0}
3481
+
3482
+
3483
+ /* Legacy memory retains its original editor. */
3150
3484
  .dsh-super-code-memory-editor{display:grid;align-content:start;gap:12px;flex:1;min-height:0;overflow:auto;padding:12px 16px}
3151
3485
  .dsh-super-code-memory-editor-heading{display:flex;align-items:center;justify-content:space-between;gap:8px}
3152
3486
  .dsh-super-code-memory-editor label{display:grid;grid-template-columns:1fr auto;gap:6px;font-size:12px}
@@ -3183,12 +3517,12 @@ function apply(ctx) {
3183
3517
  .dsh-super-code-tree-toolbar{display:flex;align-items:center;gap:6px;min-width:0}
3184
3518
  .dsh-super-code-tree-toolbar>.dsh-super-code-icon-button{width:28px;height:28px;border-radius:6px}
3185
3519
  .dsh-super-code-tree-toolbar>.dsh-super-code-icon-button svg{width:16px;height:16px}
3186
- .dsh-super-code-graph-legend{display:flex;flex-wrap:wrap;gap:6px 12px;font-size:10px;color:var(--sc-muted)}
3520
+ .dsh-super-code-graph-legend{display:flex;flex-wrap:wrap;gap:6px 12px;font-size:11px;color:var(--sc-muted)}
3187
3521
  .dsh-super-code-graph-legend>span{display:flex;align-items:center;gap:5px}
3188
- .dsh-super-code-circle.active{--state-color:#008b78}
3189
- .dsh-super-code-circle.idle{--state-color:#3971de}
3190
- .dsh-super-code-circle.stopped{--state-color:#777d87}
3191
- .dsh-super-code-circle.unavailable{--state-color:#b87716}
3522
+ .dsh-super-code-circle.active{--state-color:var(--sc-success)}
3523
+ .dsh-super-code-circle.idle{--state-color:var(--sc-accent)}
3524
+ .dsh-super-code-circle.stopped{--state-color:var(--sc-faint)}
3525
+ .dsh-super-code-circle.unavailable{--state-color:var(--sc-warning)}
3192
3526
  .dsh-super-code-graph-legend .dsh-super-code-circle,.dsh-super-code-history-list .dsh-super-code-circle{display:block;width:7px;height:7px;flex:none;border-radius:50%;background:var(--state-color)}
3193
3527
  .dsh-super-code-graph-legend .dsh-super-code-circle.idle{background:transparent;border:1px solid var(--state-color)}
3194
3528
  .dsh-super-code-graph-controls{display:flex;align-items:center;gap:0;padding:0;border:1px solid var(--sc-line);border-radius:7px;color:var(--sc-muted);font-size:12px;flex:none}
@@ -3232,7 +3566,7 @@ function apply(ctx) {
3232
3566
  .dsh-super-code-node-status[data-tone=active]{color:var(--sc-accent)}
3233
3567
  .dsh-super-code-node-status[data-tone=unavailable]{color:var(--sc-warning)}
3234
3568
  .dsh-super-code-node-status[data-tone=idle]>i{background:transparent;border:1px solid currentColor}
3235
- .dsh-super-code-tree-usage{display:flex;flex-direction:column;gap:0;font-size:10px;line-height:12px;color:var(--sc-muted);font-variant-numeric:tabular-nums}
3569
+ .dsh-super-code-tree-usage{display:flex;flex-direction:column;gap:0;font-size:11px;line-height:12px;color:var(--sc-muted);font-variant-numeric:tabular-nums}
3236
3570
  .dsh-super-code-tree-usage>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
3237
3571
  .dsh-super-code-branch-toggle{position:absolute;display:grid;place-items:center;width:22px;height:22px;border:1px solid var(--sc-line);border-radius:50%;padding:0;background:var(--sc-bg);color:var(--sc-muted)}
3238
3572
  .dsh-super-code-branch-toggle:hover{color:var(--sc-accent);border-color:currentColor}
@@ -3294,7 +3628,7 @@ function apply(ctx) {
3294
3628
  .dsh-super-code-detail-avatar .dsh-super-code-glyph{width:16px;height:16px;color:inherit}
3295
3629
  .dsh-super-code-detail-message{flex:1;min-width:0;padding:10px 12px;border:1px solid var(--sc-line);border-radius:4px 12px 12px 12px;background:var(--sc-bg)}
3296
3630
  .dsh-super-code-detail-entry.user{flex-direction:row-reverse;margin-left:28px}
3297
- .dsh-super-code-detail-entry.user .dsh-super-code-detail-avatar{background:var(--sc-accent);color:#fff}
3631
+ .dsh-super-code-detail-entry.user .dsh-super-code-detail-avatar{background:var(--sc-accent);color:var(--sc-on-accent)}
3298
3632
  .dsh-super-code-detail-entry.user .dsh-super-code-detail-message{border-color:color-mix(in srgb,var(--sc-accent) 22%,var(--sc-line));border-radius:12px 4px 12px 12px;background:var(--sc-selected)}
3299
3633
  .dsh-super-code-detail-entry.agent .dsh-super-code-detail-avatar{background:color-mix(in srgb,var(--sc-success) 10%,var(--sc-bg));color:var(--sc-success)}
3300
3634
  .dsh-super-code-detail-entry.tool{margin-bottom:12px}
@@ -3343,9 +3677,9 @@ function apply(ctx) {
3343
3677
 
3344
3678
  /* Shared action-name bubble. Fixed outside the panel avoids graph transforms
3345
3679
  * and scroll clipping; dialog bubbles remain in the modal's top layer. */
3346
- .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}
3347
- .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)}
3348
- .dsh-super-code-tooltip[data-side=top]:after{bottom:-3px}
3680
+ .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}
3681
+ .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)}
3682
+ .dsh-super-code-tooltip[data-side=top]:after{bottom:-4px}
3349
3683
  `
3350
3684
  document.head.appendChild(style)
3351
3685
  return () => { style.remove() }
@@ -3406,5 +3740,5 @@ function apply(ctx) {
3406
3740
  ctx.effect(() => disposeMemoryType, 'super-code: memory library tab')
3407
3741
  }
3408
3742
 
3409
- 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 }
3743
+ 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 }
3410
3744
  } })