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.
- package/README.en.md +169 -0
- package/README.md +105 -175
- package/client/index.js +594 -260
- package/cordis.patch.yml +3 -7
- package/docs/Acknowledgements.md +38 -67
- package/docs/Changelog.md +176 -88
- package/docs/Compatibility.md +133 -278
- package/docs/EvaluationResults.md +176 -150
- package/docs/UsageGuide.md +218 -223
- package/docs/en/Acknowledgements.md +76 -0
- package/docs/en/Changelog.md +176 -0
- package/docs/en/Compatibility.md +181 -0
- package/docs/en/EvaluationResults.md +240 -0
- package/docs/en/UsageGuide.md +321 -0
- package/docs/images/agent-tree-preview.png +0 -0
- package/docs/images/agent-tree.png +0 -0
- package/docs/images/install-tgz-preview.png +0 -0
- package/docs/images/install-tgz.png +0 -0
- package/docs/images/preset-settings-preview.png +0 -0
- package/docs/images/preset-settings.png +0 -0
- package/docs/images/task-status-preview.png +0 -0
- package/docs/images/task-status.png +0 -0
- package/lib/connection/approvals.d.ts +21 -0
- package/lib/connection/approvals.d.ts.map +1 -0
- package/lib/connection/approvals.js +83 -0
- package/lib/connection/approvals.js.map +1 -0
- package/lib/connection/client.d.ts +8 -0
- package/lib/connection/client.d.ts.map +1 -0
- package/lib/connection/client.js +34 -0
- package/lib/connection/client.js.map +1 -0
- package/lib/connection/guidance.d.ts +10 -0
- package/lib/connection/guidance.d.ts.map +1 -0
- package/lib/connection/guidance.js +27 -0
- package/lib/connection/guidance.js.map +1 -0
- package/lib/connection/http.d.ts.map +1 -1
- package/lib/connection/http.js +83 -16
- package/lib/connection/http.js.map +1 -1
- package/lib/connection/service.d.ts +3 -1
- package/lib/connection/service.d.ts.map +1 -1
- package/lib/connection/service.js +8 -0
- package/lib/connection/service.js.map +1 -1
- package/lib/connection/store.d.ts.map +1 -1
- package/lib/connection/store.js +2 -0
- package/lib/connection/store.js.map +1 -1
- package/lib/connection/tasks.d.ts +41 -1
- package/lib/connection/tasks.d.ts.map +1 -1
- package/lib/connection/tasks.js +154 -31
- package/lib/connection/tasks.js.map +1 -1
- package/lib/connection/types.d.ts +71 -2
- package/lib/connection/types.d.ts.map +1 -1
- package/lib/connection/types.js +5 -3
- package/lib/connection/types.js.map +1 -1
- package/lib/connection-cli.d.ts +3 -0
- package/lib/connection-cli.d.ts.map +1 -0
- package/lib/connection-cli.js +40 -0
- package/lib/connection-cli.js.map +1 -0
- package/lib/core/deletion-command.d.ts.map +1 -1
- package/lib/core/deletion-command.js +2 -1
- package/lib/core/deletion-command.js.map +1 -1
- package/lib/core/windows-runtime.d.ts +16 -0
- package/lib/core/windows-runtime.d.ts.map +1 -0
- package/lib/core/windows-runtime.js +123 -0
- package/lib/core/windows-runtime.js.map +1 -0
- package/lib/dsh/budget-settings.d.ts +2 -0
- package/lib/dsh/budget-settings.d.ts.map +1 -1
- package/lib/dsh/budget-settings.js +9 -3
- package/lib/dsh/budget-settings.js.map +1 -1
- package/lib/dsh/budgets.d.ts +2 -0
- package/lib/dsh/budgets.d.ts.map +1 -1
- package/lib/dsh/budgets.js +6 -0
- package/lib/dsh/budgets.js.map +1 -1
- package/lib/dsh/connection-approval.d.ts +5 -0
- package/lib/dsh/connection-approval.d.ts.map +1 -0
- package/lib/dsh/connection-approval.js +72 -0
- package/lib/dsh/connection-approval.js.map +1 -0
- package/lib/dsh/connection-history.d.ts +6 -0
- package/lib/dsh/connection-history.d.ts.map +1 -0
- package/lib/dsh/connection-history.js +52 -0
- package/lib/dsh/connection-history.js.map +1 -0
- package/lib/dsh/connection-host.d.ts +36 -3
- package/lib/dsh/connection-host.d.ts.map +1 -1
- package/lib/dsh/connection-host.js +97 -19
- package/lib/dsh/connection-host.js.map +1 -1
- package/lib/dsh/connection.d.ts.map +1 -1
- package/lib/dsh/connection.js +4 -1
- package/lib/dsh/connection.js.map +1 -1
- package/lib/dsh/index.d.ts.map +1 -1
- package/lib/dsh/index.js +4 -0
- package/lib/dsh/index.js.map +1 -1
- package/lib/dsh/official-windows-shell.d.ts +4 -0
- package/lib/dsh/official-windows-shell.d.ts.map +1 -0
- package/lib/dsh/official-windows-shell.js +128 -0
- package/lib/dsh/official-windows-shell.js.map +1 -0
- package/lib/dsh/windows-shell.d.ts +53 -0
- package/lib/dsh/windows-shell.d.ts.map +1 -0
- package/lib/dsh/windows-shell.js +182 -0
- package/lib/dsh/windows-shell.js.map +1 -0
- package/package.json +28 -16
- package/presets/super-code/agent.cordis.yml +3 -7
- package/runtime/windows/README.md +45 -0
- package/runtime/windows/arm64-busybox.exe.gz +0 -0
- package/runtime/windows/bash.exe.gz +0 -0
- package/runtime/windows/grep.exe.gz +0 -0
- package/runtime/windows/licenses/BusyBox-LICENSE.txt +348 -0
- package/runtime/windows/licenses/GPL-3.0.txt +674 -0
- package/runtime/windows/licenses/LGPL-3.0.txt +165 -0
- package/runtime/windows/licenses/MSYS-COPYING.LIB +165 -0
- package/runtime/windows/licenses/MSYS-COPYING.RUNTIME +674 -0
- package/runtime/windows/licenses/PCRE-LICENCE.txt +93 -0
- package/runtime/windows/licenses/ncurses-COPYING.txt +29 -0
- package/runtime/windows/manifest.json +236 -0
- package/runtime/windows/msys-2.0.dll.gz +0 -0
- package/runtime/windows/msys-iconv-2.dll.gz +0 -0
- package/runtime/windows/msys-intl-8.dll.gz +0 -0
- package/runtime/windows/msys-pcre-1.dll.gz +0 -0
- package/runtime/windows/sources/busybox-w32-FRP-6354-g5f09fb446.tgz +0 -0
- package/runtime/windows/sources.json +45 -0
- 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
|
|
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(
|
|
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.
|
|
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 <连接凭证>,凭证由我单独提供,请妥善保存在客户端。\
|
|
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
|
|
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': '
|
|
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': '
|
|
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.
|
|
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.\
|
|
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
|
|
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
|
|
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
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
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.
|
|
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
|
-
|
|
989
|
-
if (
|
|
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,
|
|
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 === '
|
|
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.
|
|
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
|
-
/**
|
|
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 ?
|
|
1243
|
-
saved.active = next; focusSection.current =
|
|
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
|
|
2102
|
-
const
|
|
2103
|
-
const
|
|
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
|
|
2106
|
-
|
|
2107
|
-
|
|
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)
|
|
2114
|
-
finally { pending.current = false; if (alive.current)
|
|
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 } }, [
|
|
2117
|
-
useEffect(() => { if (
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
if (
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
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(
|
|
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(
|
|
2135
|
-
else
|
|
2136
|
-
} catch { if (alive.current)
|
|
2137
|
-
finally { pending.current = false; if (alive.current)
|
|
2138
|
-
}
|
|
2139
|
-
const disabled =
|
|
2140
|
-
const
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
const
|
|
2146
|
-
const value = field
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
React.createElement('
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
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(
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
React.createElement(
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
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
|
-
/**
|
|
2263
|
-
|
|
2264
|
-
|
|
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 =
|
|
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:
|
|
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 =
|
|
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
|
|
2310
|
-
return
|
|
2311
|
-
|
|
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
|
-
|
|
2521
|
-
const
|
|
2522
|
-
|
|
2523
|
-
|
|
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
|
|
2528
|
-
|
|
2529
|
-
|
|
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
|
-
|
|
2535
|
-
|
|
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
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
if (alive.current)
|
|
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
|
-
|
|
2548
|
-
React.createElement('
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
React.createElement(
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
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('
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
React.createElement('
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
React.createElement(
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
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
|
-
|
|
2861
|
-
.dsh-super-code-settings-actions button
|
|
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-
|
|
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)
|
|
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
|
-
.
|
|
2888
|
-
.dsh-super-code-
|
|
2889
|
-
.dsh-super-code-
|
|
2890
|
-
.dsh-super-code-
|
|
2891
|
-
.dsh-super-code-
|
|
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
|
-
|
|
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
|
|
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-
|
|
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-
|
|
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{
|
|
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
|
-
.
|
|
2941
|
-
.dsh-super-code-home
|
|
2942
|
-
.dsh-super-code-home-
|
|
2943
|
-
.dsh-super-code-home-
|
|
2944
|
-
.dsh-super-code-
|
|
2945
|
-
.dsh-super-code-
|
|
2946
|
-
.dsh-super-code-
|
|
2947
|
-
.dsh-super-code-
|
|
2948
|
-
.dsh-super-code-
|
|
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:
|
|
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-
|
|
3052
|
-
.dsh-super-code-feedback-
|
|
3053
|
-
.dsh-super-code-feedback-
|
|
3054
|
-
.dsh-super-code-
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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:
|
|
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
|
|
3189
|
-
.dsh-super-code-circle.idle{--state-color
|
|
3190
|
-
.dsh-super-code-circle.stopped{--state-color
|
|
3191
|
-
.dsh-super-code-circle.unavailable{--state-color
|
|
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:
|
|
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
|
|
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-
|
|
3347
|
-
.dsh-super-code-tooltip:after{content:"";position:absolute;left:var(--sc-tooltip-arrow-left);width:
|
|
3348
|
-
.dsh-super-code-tooltip[data-side=top]:after{bottom:-
|
|
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
|
} })
|