dsh-super-code 0.3.8 → 0.3.9
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 +144 -0
- package/README.md +89 -184
- package/client/index.js +540 -251
- package/cordis.patch.yml +1 -1
- package/docs/Acknowledgements.md +38 -67
- package/docs/Changelog.md +160 -88
- package/docs/Compatibility.md +98 -278
- package/docs/EvaluationResults.md +165 -155
- package/docs/UsageGuide.md +209 -231
- package/docs/en/Acknowledgements.md +76 -0
- package/docs/en/Changelog.md +160 -0
- package/docs/en/Compatibility.md +146 -0
- package/docs/en/EvaluationResults.md +224 -0
- package/docs/en/UsageGuide.md +304 -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/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/package.json +8 -1
- package/presets/super-code/agent.cordis.yml +1 -1
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
|
}
|
|
@@ -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': '任务记录',
|
|
@@ -303,13 +309,16 @@ const zh = {
|
|
|
303
309
|
"connection.rejectDirectory": "拒绝",
|
|
304
310
|
"connection.error.directory-limit": "最多允许选择 32 个目录。",
|
|
305
311
|
"connection.error.picker-unavailable": "无法打开目录选择器,请重新读取后重试。",
|
|
306
|
-
'home.
|
|
312
|
+
'home.configure': '配置', 'home.managePreset': '配置预设', 'home.details': '打开{title}详情', 'home.activeSessions': '{count} 个活跃对话',
|
|
313
|
+
'preset.versionBadge': '版本一致',
|
|
307
314
|
'home.connectedSessions': '正在连接的对话', 'home.historySessions': '历史对话',
|
|
308
315
|
'home.connections': '已连接客户端', 'home.noConnections': '暂无客户端连接', 'home.sessions': '关联会话', 'home.noSessions': '暂无关联会话',
|
|
309
316
|
'home.disconnect': '断开', 'home.openSession': '打开会话', 'home.connected': '已连接', 'home.enabled': '已开启', 'home.disabled': '已关闭',
|
|
310
317
|
'home.mcp': 'MCP 服务', 'home.connectionCount': '{count} / {max} 个连接', 'home.setupConnection': '配置并启用',
|
|
311
318
|
'home.lastSeen': '最近活动', 'home.refresh': '刷新概览', 'home.error': '状态读取或操作失败,请刷新后重试。',
|
|
312
319
|
'connection.maxConnections': '最大连接数', 'connection.connectionsHint': '按 MCP 客户端会话计数。断开或空闲 10 分钟后释放连接;已接收任务继续执行。',
|
|
320
|
+
'connection.allowNewConversations': '允许 MCP 新增对话', 'connection.allowNewConversationsHint': '关闭后不会创建新的 DSH 对话;MCP 仍可查看并继续已有对话。',
|
|
321
|
+
'connection.allowCallerApproval': '允许调用方审批', 'connection.allowCallerApprovalHint': '默认关闭。开启后,由 MCP 调用方批准或拒绝委派任务的单次操作;无法处理或超时后回到 DSH。新增目录仍需在 DSH 同意。',
|
|
313
322
|
'connection.addDirectory': '添加目录', 'connection.noDirectories': '暂无目录,请通过文件管理器添加。',
|
|
314
323
|
'connection.workspaceDirectory': 'DSH 工作区', 'connection.customDirectory': '添加的目录', 'connection.directoryUnavailable': '目录不可用',
|
|
315
324
|
'connection.removeDirectory': '移除目录', 'connection.directoryRefresh': '刷新目录',
|
|
@@ -327,10 +336,10 @@ const zh = {
|
|
|
327
336
|
'connection.directoriesHint': '勾选允许的目录,包含其子目录。每次打开设置会同步 DSH 工作区,保留已保存的选择。',
|
|
328
337
|
'connection.save': '保存连接', 'connection.cancel': '取消修改', 'connection.reload': '重新读取', 'connection.saved': '已保存连接设置。',
|
|
329
338
|
'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 <连接凭证>,凭证由我单独提供,请妥善保存在客户端。\
|
|
339
|
+
'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
340
|
'connection.tokenHint': '请将凭证安全保存在客户端。更换凭证后,旧凭证立即失效。',
|
|
332
341
|
'connection.rotated': '已更换凭证,请更新客户端。', 'connection.copied': '已复制。',
|
|
333
|
-
'connection.error.unavailable': '连接服务尚未就绪或当前配置目录不可写,请重新读取。', 'connection.error.invalid': '请检查端口、最大连接数和目录。启用连接至少需要一个有效目录。',
|
|
342
|
+
'connection.error.unavailable': '连接服务尚未就绪或当前配置目录不可写,请重新读取。', 'connection.error.invalid': '请检查端口、最大连接数和目录。启用连接至少需要一个有效目录。', 'connection.error.new-conversation-disabled': 'MCP 新增对话已关闭,请选择已有对话继续。',
|
|
334
343
|
'connection.error.conflict': '连接设置已在别处修改。草稿已保留,请重新读取。', 'connection.error.save-failed': '保存失败,草稿已保留。', 'connection.error.port-unavailable': '端口被占用或无法监听。请更换端口并保存。', 'connection.error.storage-unavailable': '任务状态保存失败,请检查配置目录。', 'connection.error.clipboard': '复制失败,请手动复制。',
|
|
335
344
|
'settings.contextTab': '上下文配置', 'settings.tabs': 'Super Code 配置',
|
|
336
345
|
'budget.common': '通用预算', 'budget.superCode': 'Super Code 专属预算',
|
|
@@ -339,11 +348,11 @@ const zh = {
|
|
|
339
348
|
'budget.defaultValue': '(默认:{value})', 'budget.off': '关闭', 'budget.managed': '宿主管理',
|
|
340
349
|
'delete.title': '删除保护', 'delete.mode': '保护模式', 'delete.off': '关闭', 'delete.relaxed': '宽松', 'delete.strict': '严格', 'delete.official': '同时应用到官方预设',
|
|
341
350
|
'delete.hint.off': '不添加删除保护提示,不额外拦截命令。宿主原有权限检查仍然有效。',
|
|
342
|
-
'delete.hint.relaxed': '默认使用 trash
|
|
351
|
+
'delete.hint.relaxed': '默认使用 trash(脚本中也建议);用户明确要求时可用 rm,无需额外确认。',
|
|
343
352
|
'delete.hint.strict': '默认使用 trash,脚本也禁止直接使用 rm。识别到永久删除命令时,仅清理临时文件或构建产物可经用户逐次二次确认放行。',
|
|
344
353
|
'delete.officialHint': '默认仅保护 Super Code。此开关独立于预算的官方预设开关;保存后立即作用于后续命令。',
|
|
345
354
|
'budget.title': '上下文配置', 'budget.scope': '预算保存后对新建 Agent 生效,运行中的任务保留原配置。',
|
|
346
|
-
'budget.defaults': '
|
|
355
|
+
'budget.defaults': '留空沿用默认值,各项下方显示默认值;通用预算随宿主版本变化。恢复默认会清除这里的覆盖,回到插件加载配置;未配置时跟随宿主。',
|
|
347
356
|
'budget.context': '上下文压缩', 'budget.execution': '批量工具执行', 'budget.advanced': '更多预算',
|
|
348
357
|
'budget.pressureBasis': '压缩预算基准', 'budget.inherit': '跟随默认', 'budget.host': '宿主策略', 'budget.window': '完整上下文窗口',
|
|
349
358
|
'budget.thresholdRatio': '压缩触发比例(%)', 'budget.retainRatio': '最近原文保留比例(%)', 'budget.summaryMaxTokens': '摘要输出上限(Token)',
|
|
@@ -360,6 +369,9 @@ const zh = {
|
|
|
360
369
|
'budget.error.conflict': '预算已在别处修改。草稿已保留,请重新读取后再修改。', 'budget.error.read-only': '当前宿主的设置只读,无法保存。',
|
|
361
370
|
'budget.error.ptc-unavailable': '此宿主不支持覆盖 PTC 总执行时限。', 'budget.error.ptc-ceiling': '执行时限超过了宿主允许的上限。',
|
|
362
371
|
'budget.error.save-failed': '保存失败,草稿已保留,请重试。',
|
|
372
|
+
'budget.defaultHint': '默认:{value}', 'budget.error.range': '超出允许范围或格式不正确。',
|
|
373
|
+
'budget.resetQuestion': '清除这里的所有覆盖?', 'budget.resetConfirm': '恢复默认', 'delete.scope': '适用范围',
|
|
374
|
+
'save.idle': '修改后自动保存', 'save.saving': '正在保存…', 'save.saved': '已自动保存', 'save.error': '保存失败', 'save.invalid': '有字段需要修正,暂未保存', 'save.retry': '重试',
|
|
363
375
|
'memory.add': '新增记忆', 'memory.edit': '编辑', 'memory.cancel': '取消', 'memory.save': '保存', 'memory.delete': '删除', 'memory.deleting': '正在删除…', 'memory.saving': '正在保存…',
|
|
364
376
|
'memory.topic': '主题', 'memory.kind': '类型', 'memory.summaryLabel': '标题', 'memory.detailLabel': '内容', 'memory.manual': '手动维护',
|
|
365
377
|
'memory.topicHint': '字母、数字、点、下划线或短横线,最多 96 个字符。',
|
|
@@ -371,7 +383,7 @@ const zh = {
|
|
|
371
383
|
'detail.toolCall': '工具调用', 'detail.toolResult': '工具结果', 'detail.toolError': '工具失败',
|
|
372
384
|
'detail.cache': '缓存', 'detail.info': '详情', 'tree.countCompact': '{shown}/{total} · 运行 {running}',
|
|
373
385
|
'memory.loading': '正在读取记忆…', 'memory.topics': '知识主题', 'memory.allTopics': '全部主题', 'memory.related': '同主题知识', 'preset.configuration': '预设配置',
|
|
374
|
-
'memory.title': '
|
|
386
|
+
'memory.title': '记忆', 'memory.project': '当前项目', 'memory.global': '全局偏好', 'memory.search': '搜索主题或记忆',
|
|
375
387
|
'memory.description': '知识主题与条目',
|
|
376
388
|
'memory.empty': '还没有保存的记忆。需要长期保留时,直接告诉 Agent 即可。', 'memory.noMatches': '没有匹配的记忆',
|
|
377
389
|
'memory.selectSession': '先打开一个对话,查看它所在项目的记忆。', 'memory.error': '暂时无法读取记忆,请刷新重试。',
|
|
@@ -430,7 +442,9 @@ const zh = {
|
|
|
430
442
|
'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
443
|
}
|
|
432
444
|
const en = {
|
|
433
|
-
'feedback.title': '
|
|
445
|
+
'feedback.title': 'Tasks',
|
|
446
|
+
'feedback.tools': 'Tool call summary',
|
|
447
|
+
'feedback.toolCount': '{tool}: {ok} succeeded, {failed} failed',
|
|
434
448
|
'feedback.refresh': 'Refresh task status',
|
|
435
449
|
'feedback.noGoal': 'No recorded objective',
|
|
436
450
|
'feedback.source.record': 'Recorded objective',
|
|
@@ -477,13 +491,16 @@ const en = {
|
|
|
477
491
|
"connection.rejectDirectory": "Reject",
|
|
478
492
|
"connection.error.directory-limit": "Select up to 32 directories.",
|
|
479
493
|
"connection.error.picker-unavailable": "Could not open the directory picker. Reload and try again.",
|
|
480
|
-
'home.
|
|
494
|
+
'home.configure': 'Configure', 'home.managePreset': 'Configure preset', 'home.details': 'Open {title} details', 'home.activeSessions': '{count} active conversations',
|
|
495
|
+
'preset.versionBadge': 'Up to date',
|
|
481
496
|
'home.connectedSessions': 'Connected conversations', 'home.historySessions': 'Past conversations',
|
|
482
497
|
'home.connections': 'Connected clients', 'home.noConnections': 'No clients connected', 'home.sessions': 'Linked sessions', 'home.noSessions': 'No linked sessions',
|
|
483
498
|
'home.disconnect': 'Disconnect', 'home.openSession': 'Open session', 'home.connected': 'Connected', 'home.enabled': 'On', 'home.disabled': 'Off',
|
|
484
499
|
'home.mcp': 'MCP service', 'home.connectionCount': '{count} / {max} connections', 'home.setupConnection': 'Set up connection',
|
|
485
500
|
'home.lastSeen': 'Last activity', 'home.refresh': 'Refresh overview', 'home.error': 'Could not read or update the status. Refresh and try again.',
|
|
486
501
|
'connection.maxConnections': 'Maximum connections', 'connection.connectionsHint': 'Counts MCP client sessions. Disconnect or 10 minutes of inactivity releases a connection; accepted tasks continue.',
|
|
502
|
+
'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.',
|
|
503
|
+
'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
504
|
'connection.addDirectory': 'Add directory', 'connection.noDirectories': 'No directories. Add one with the directory picker.',
|
|
488
505
|
'connection.workspaceDirectory': 'DSH workspace', 'connection.customDirectory': 'Added directory', 'connection.directoryUnavailable': 'Directory unavailable',
|
|
489
506
|
'connection.removeDirectory': 'Remove directory', 'connection.directoryRefresh': 'Refresh directories',
|
|
@@ -501,10 +518,10 @@ const en = {
|
|
|
501
518
|
'connection.directoriesHint': 'Select allowed directories, including their subdirectories. Reopening settings refreshes DSH workspaces and retains saved selections.',
|
|
502
519
|
'connection.save': 'Save connection', 'connection.cancel': 'Cancel changes', 'connection.reload': 'Reload', 'connection.saved': 'Connection settings saved.',
|
|
503
520
|
'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.\
|
|
521
|
+
'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
522
|
'connection.tokenHint': 'Store the token securely in the client. Rotation invalidates the previous token immediately.',
|
|
506
523
|
'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.',
|
|
524
|
+
'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
525
|
'connection.error.conflict': 'Connection settings changed elsewhere. Your draft is retained; reload to continue.', 'connection.error.save-failed': 'Save failed. Your draft is retained.', 'connection.error.port-unavailable': 'The port is occupied or cannot be opened. Save with another port.', 'connection.error.storage-unavailable': 'Task state could not be saved. Check the profile directory.', 'connection.error.clipboard': 'Copy failed. Copy the text manually.',
|
|
509
526
|
'settings.contextTab': 'Context settings', 'settings.tabs': 'Super Code settings',
|
|
510
527
|
'budget.common': 'Common budgets', 'budget.superCode': 'Super Code budgets',
|
|
@@ -517,7 +534,7 @@ const en = {
|
|
|
517
534
|
'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
535
|
'delete.officialHint': 'Protects Super Code by default. This switch is independent of official-preset budgets; saved changes apply to subsequent commands immediately.',
|
|
519
536
|
'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
|
|
537
|
+
'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
538
|
'budget.context': 'Context compression', 'budget.execution': 'Batched tool execution', 'budget.advanced': 'More budgets',
|
|
522
539
|
'budget.pressureBasis': 'Compression budget basis', 'budget.inherit': 'Inherit default', 'budget.host': 'Host policy', 'budget.window': 'Full context window',
|
|
523
540
|
'budget.thresholdRatio': 'Compress at (%)', 'budget.retainRatio': 'Keep recent context (%)', 'budget.summaryMaxTokens': 'Summary output limit (tokens)',
|
|
@@ -534,6 +551,9 @@ const en = {
|
|
|
534
551
|
'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
552
|
'budget.error.ptc-unavailable': 'This host cannot override PTC elapsed deadlines.', 'budget.error.ptc-ceiling': 'The deadline exceeds the host ceiling.',
|
|
536
553
|
'budget.error.save-failed': 'Save failed. Your draft is retained; try again.',
|
|
554
|
+
'budget.defaultHint': 'Default: {value}', 'budget.error.range': 'Out of range or not a valid number.',
|
|
555
|
+
'budget.resetQuestion': 'Clear all overrides here?', 'budget.resetConfirm': 'Reset', 'delete.scope': 'Scope',
|
|
556
|
+
'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
557
|
'memory.add': 'Add memory', 'memory.edit': 'Edit', 'memory.cancel': 'Cancel', 'memory.save': 'Save', 'memory.delete': 'Delete', 'memory.deleting': 'Deleting…', 'memory.saving': 'Saving…',
|
|
538
558
|
'memory.topic': 'Topic', 'memory.kind': 'Type', 'memory.summaryLabel': 'Title', 'memory.detailLabel': 'Content', 'memory.manual': 'Manually maintained',
|
|
539
559
|
'memory.topicHint': 'Letters, digits, dots, underscores or hyphens; up to 96 characters.',
|
|
@@ -545,7 +565,7 @@ const en = {
|
|
|
545
565
|
'detail.toolCall': 'Tool call', 'detail.toolResult': 'Tool result', 'detail.toolError': 'Tool failed',
|
|
546
566
|
'detail.cache': 'Cache', 'detail.info': 'Details', 'tree.countCompact': '{shown}/{total} · Running {running}',
|
|
547
567
|
'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
|
|
568
|
+
'memory.title': 'Memory', 'memory.project': 'This project', 'memory.global': 'Global preferences', 'memory.search': 'Search topics or memories',
|
|
549
569
|
'memory.description': 'Knowledge topics and entries',
|
|
550
570
|
'memory.empty': 'No saved memories yet. Tell the agent when something is worth keeping.', 'memory.noMatches': 'No matching memories',
|
|
551
571
|
'memory.selectSession': 'Open a conversation to view memory for its project.', 'memory.error': 'Memory is unavailable. Refresh to try again.',
|
|
@@ -964,19 +984,33 @@ function FeedbackMark({ tone, label }) {
|
|
|
964
984
|
React.createElement('path', { d: 'm3.5 8 3 3 6-6', strokeLinecap: 'round', strokeLinejoin: 'round' })),
|
|
965
985
|
tone === 'error' && React.createElement('span', { 'aria-hidden': true }, '!'))
|
|
966
986
|
}
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
987
|
+
/** Per-tool settled counts in first-use order; single calls stay in the execution log. */
|
|
988
|
+
function feedbackToolSummary(activities = []) {
|
|
989
|
+
const tools = new Map()
|
|
990
|
+
for (const { tool, status } of activities) {
|
|
991
|
+
const row = tools.get(tool) || { tool, succeeded: 0, failed: 0, running: false }
|
|
992
|
+
if (status === 'succeeded') row.succeeded++
|
|
993
|
+
else if (status === 'failed') row.failed++
|
|
994
|
+
else if (status === 'running') row.running = true
|
|
995
|
+
tools.set(tool, row)
|
|
996
|
+
}
|
|
997
|
+
return [...tools.values()]
|
|
998
|
+
}
|
|
999
|
+
function FeedbackTools({ tools, t }) {
|
|
1000
|
+
return React.createElement('ul', { className: 'dsh-super-code-feedback-tools', 'aria-label': text(t, 'feedback.tools') },
|
|
1001
|
+
tools.map(row => {
|
|
1002
|
+
const label = text(t, 'feedback.toolCount', { tool: row.tool, ok: row.succeeded, failed: row.failed })
|
|
1003
|
+
return React.createElement('li', { key: row.tool, title: label, 'aria-label': label, 'data-running': row.running || undefined },
|
|
1004
|
+
React.createElement('span', { 'aria-hidden': true }, row.tool),
|
|
1005
|
+
React.createElement('b', { className: 'dsh-super-code-tool-badge', 'data-tone': 'success', 'aria-hidden': true }, row.succeeded),
|
|
1006
|
+
React.createElement('b', { className: 'dsh-super-code-tool-badge', 'data-tone': 'warning', 'data-zero': row.failed === 0 || undefined, 'aria-hidden': true }, row.failed))
|
|
1007
|
+
}))
|
|
1008
|
+
}
|
|
1009
|
+
/** Flatten presentation rows only; tool calls fold into one per-task summary row. */
|
|
976
1010
|
function feedbackListItems(model, root, partial) {
|
|
977
1011
|
const items = []
|
|
978
1012
|
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.
|
|
1013
|
+
signature: JSON.stringify([kind, data.content, data.todo, data.tools, data.label, data.count,
|
|
980
1014
|
data.file && [data.file.name, data.file.directory, [...data.file.operations]], kind === 'task' &&
|
|
981
1015
|
[row.title, row.owner, row.done, row.total, row.complete, row.taskStatus, row.facts?.phase, row.node.running]]) })
|
|
982
1016
|
for (const row of model.tasks) {
|
|
@@ -985,8 +1019,9 @@ function feedbackListItems(model, root, partial) {
|
|
|
985
1019
|
if (row.goal && row.goal !== row.title) add('text', [row.id, 'goal'], { content: row.goal }, row)
|
|
986
1020
|
if (facts?.latestRequest && facts.latestRequest !== facts.request) add('request', [row.id, 'request'], { content: facts.latestRequest }, row)
|
|
987
1021
|
row.todos.forEach((todo, index) => add('step', [row.id, 'step', index], { todo }, row))
|
|
988
|
-
|
|
989
|
-
if (
|
|
1022
|
+
const tools = feedbackToolSummary(facts?.activities)
|
|
1023
|
+
if (tools.length) add('tools', [row.id, 'tools'], { tools }, row)
|
|
1024
|
+
if (!row.total && !tools.length) add('note', [row.id, 'empty'], { label: facts ? 'feedback.noSteps' : 'feedback.loading' }, row)
|
|
990
1025
|
if (facts?.omittedActivities) add('note', [row.id, 'recent'], { label: 'feedback.recentOnly' }, row)
|
|
991
1026
|
add('open', [row.id, 'open'], { focusable: !row.node.unavailable }, row)
|
|
992
1027
|
}
|
|
@@ -1002,7 +1037,7 @@ function feedbackListItems(model, root, partial) {
|
|
|
1002
1037
|
|
|
1003
1038
|
/** Prefix heights allow binary-search windows without mounting offscreen rows. */
|
|
1004
1039
|
function feedbackListLayout(items, heights = new Map()) {
|
|
1005
|
-
const estimates = { task: 64, text: 48, request: 70, step: 28,
|
|
1040
|
+
const estimates = { task: 64, text: 48, request: 70, step: 28, tools: 32, open: 34, files: 40, file: 30, note: 26 }
|
|
1006
1041
|
const offsets = [0], byKey = new Map()
|
|
1007
1042
|
items.forEach((item, index) => {
|
|
1008
1043
|
const measured = heights.get(item.key)
|
|
@@ -1050,7 +1085,7 @@ function FeedbackRowContent({ item, root, openDetail, t }) {
|
|
|
1050
1085
|
if (item.kind === 'step') return React.createElement('div', { className: 'dsh-super-code-feedback-step', 'data-step-state': item.todo.status },
|
|
1051
1086
|
React.createElement(FeedbackMark, { tone: item.todo.status === 'completed' ? 'success' : item.todo.status === 'in_progress' ? 'active' : 'pending', label: text(t, 'feedback.todo.' + item.todo.status) }),
|
|
1052
1087
|
React.createElement('span', null, item.todo.content))
|
|
1053
|
-
if (item.kind === '
|
|
1088
|
+
if (item.kind === 'tools') return React.createElement(FeedbackTools, { tools: item.tools, t })
|
|
1054
1089
|
if (item.kind === 'open') return React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-feedback-open', disabled: !item.focusable,
|
|
1055
1090
|
title: text(t, 'feedback.open'), onClick: () => openDetail(row.node) }, text(t, 'feedback.open'), React.createElement(Glyph, { type: 'arrow' }))
|
|
1056
1091
|
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 +1097,9 @@ function FeedbackRowContent({ item, root, openDetail, t }) {
|
|
|
1062
1097
|
file.directory && React.createElement('small', null, file.directory),
|
|
1063
1098
|
React.createElement('span', { className: 'dsh-super-code-feedback-file-operation' }, [...file.operations].map(operation => text(t, 'feedback.file.' + operation)).join(' · ')))
|
|
1064
1099
|
}
|
|
1065
|
-
if (item.
|
|
1100
|
+
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))
|
|
1101
|
+
if (item.label === 'tree.empty') return React.createElement('p', { className: 'dsh-super-code-state', 'data-tone': 'empty' }, React.createElement(Glyph, { type: 'context' }), text(t, item.label))
|
|
1102
|
+
if (item.kind === 'note') return React.createElement('p', { className: 'dsh-super-code-feedback-muted' }, text(t, item.label))
|
|
1066
1103
|
return React.createElement('p', { className: 'dsh-super-code-feedback-text' },
|
|
1067
1104
|
item.kind === 'request' && React.createElement('small', null, text(t, 'feedback.latest')), item.content)
|
|
1068
1105
|
}
|
|
@@ -1221,7 +1258,7 @@ function WorkspaceSectionToggle({ section, expanded, onToggle, children, t }) {
|
|
|
1221
1258
|
React.createElement('strong', null, label), children)
|
|
1222
1259
|
}
|
|
1223
1260
|
|
|
1224
|
-
/**
|
|
1261
|
+
/** Accordion: at most one open view; clicking the open heading collapses it. Tab state retains drafts. */
|
|
1225
1262
|
function SuperCodeWorkspace(props) {
|
|
1226
1263
|
const { tab } = props.useTabInfo()
|
|
1227
1264
|
const address = typeof tab.navigation?.params?.memory === 'string' ? tab.navigation.params.memory : tab.contentId
|
|
@@ -1236,11 +1273,11 @@ function SuperCodeWorkspace(props) {
|
|
|
1236
1273
|
props.workspaceStates.set(tab.signal, value)
|
|
1237
1274
|
return value
|
|
1238
1275
|
}, [props.workspaceStates, tab.signal])
|
|
1239
|
-
const [active, setActive] = useState(['tasks', 'tree', 'memory'].includes(saved.active) ? saved.active : 'tasks')
|
|
1276
|
+
const [active, setActive] = useState(['tasks', 'tree', 'memory', ''].includes(saved.active) ? saved.active : 'tasks')
|
|
1240
1277
|
const layout = useRef(null), focusSection = useRef('')
|
|
1241
1278
|
const toggle = section => {
|
|
1242
|
-
const next = active === section ?
|
|
1243
|
-
saved.active = next; focusSection.current =
|
|
1279
|
+
const next = active === section ? '' : section
|
|
1280
|
+
saved.active = next; focusSection.current = section; setActive(next)
|
|
1244
1281
|
}
|
|
1245
1282
|
useLayoutEffect(() => {
|
|
1246
1283
|
if (saved.navigationKey === navigationKey) return
|
|
@@ -2097,116 +2134,188 @@ function budgetConfiguration(draft) {
|
|
|
2097
2134
|
return { ok: true, configuration: config }
|
|
2098
2135
|
}
|
|
2099
2136
|
|
|
2137
|
+
/* Settings primitives. Every tab composes titled sections of label/control rows,
|
|
2138
|
+
* one callout style for notices, and one autosave indicator. */
|
|
2139
|
+
function SettingsSection({ id, title, description, actions, plain = false, children }) {
|
|
2140
|
+
const lines = [].concat(description ?? []).filter(Boolean)
|
|
2141
|
+
return React.createElement('section', { className: 'dsh-super-code-section', 'aria-labelledby': `${id}-title` },
|
|
2142
|
+
React.createElement('header', { className: 'dsh-super-code-section-head' },
|
|
2143
|
+
React.createElement('div', { className: 'dsh-super-code-section-heading' },
|
|
2144
|
+
React.createElement('h3', { id: `${id}-title` }, title),
|
|
2145
|
+
...lines.map((line, index) => React.createElement('p', { key: index }, line))),
|
|
2146
|
+
actions && React.createElement('div', { className: 'dsh-super-code-section-actions' }, actions)),
|
|
2147
|
+
React.createElement('div', { className: 'dsh-super-code-section-body', 'data-plain': plain || undefined }, children))
|
|
2148
|
+
}
|
|
2149
|
+
/** Label and hint on the left, control on the right; `children` may take the describedby ids. */
|
|
2150
|
+
function SettingRow({ id, label, hint, error, children }) {
|
|
2151
|
+
const described = [hint && `${id}-hint`, error && `${id}-error`].filter(Boolean).join(' ') || undefined
|
|
2152
|
+
return React.createElement('div', { className: 'dsh-super-code-setting-row', 'data-invalid': error ? true : undefined },
|
|
2153
|
+
React.createElement('div', { className: 'dsh-super-code-setting-row-text' },
|
|
2154
|
+
React.createElement('label', { htmlFor: id }, label),
|
|
2155
|
+
hint && React.createElement('p', { id: `${id}-hint` }, hint),
|
|
2156
|
+
error && React.createElement('p', { id: `${id}-error`, className: 'dsh-super-code-setting-row-error' }, error)),
|
|
2157
|
+
React.createElement('div', { className: 'dsh-super-code-setting-row-control' }, typeof children === 'function' ? children(described) : children))
|
|
2158
|
+
}
|
|
2159
|
+
function Callout({ tone = 'info', action, children }) {
|
|
2160
|
+
return React.createElement('div', { className: 'dsh-super-code-callout', 'data-tone': tone, role: tone === 'error' ? 'alert' : tone === 'success' ? 'status' : undefined },
|
|
2161
|
+
React.createElement(Glyph, { type: tone === 'success' ? 'check' : tone === 'info' ? 'info' : 'error' }),
|
|
2162
|
+
React.createElement('div', { className: 'dsh-super-code-callout-text' }, children),
|
|
2163
|
+
action || null)
|
|
2164
|
+
}
|
|
2165
|
+
function SaveIndicator({ state, t }) {
|
|
2166
|
+
return React.createElement('p', { className: 'dsh-super-code-save-indicator', role: 'status', 'data-save-state': state },
|
|
2167
|
+
React.createElement('i', { 'aria-hidden': true }), React.createElement('span', null, t(`save.${state}`)))
|
|
2168
|
+
}
|
|
2169
|
+
/** Exclusive choices that need a sentence each; native radios keep arrow-key behavior. */
|
|
2170
|
+
function ChoiceCards({ name, label, value, choices, onChange, disabled = false }) {
|
|
2171
|
+
return React.createElement('div', { className: 'dsh-super-code-choice-cards', role: 'radiogroup', 'aria-label': label },
|
|
2172
|
+
...choices.map(([choice, title, hint]) => React.createElement('label', { key: choice, className: 'dsh-super-code-choice-card', 'data-checked': choice === value || undefined },
|
|
2173
|
+
React.createElement('input', { type: 'radio', name, value: choice, checked: choice === value, disabled, 'aria-describedby': `${name}-${choice}-hint`,
|
|
2174
|
+
onChange: () => { if (choice !== value) onChange(choice) } }),
|
|
2175
|
+
React.createElement('i', { 'aria-hidden': true }),
|
|
2176
|
+
React.createElement('span', { className: 'dsh-super-code-choice-card-text' },
|
|
2177
|
+
React.createElement('strong', null, title), React.createElement('small', { id: `${name}-${choice}-hint` }, hint)))))
|
|
2178
|
+
}
|
|
2179
|
+
|
|
2180
|
+
/** Each budget tab writes only its own fields and carries the other tab's stored values through. */
|
|
2181
|
+
function budgetSectionConfiguration(section, draft, snapshot) {
|
|
2182
|
+
const parsed = budgetConfiguration(draft)
|
|
2183
|
+
if (!parsed.ok) return parsed
|
|
2184
|
+
const current = snapshot.configuration
|
|
2185
|
+
return { ok: true, configuration: section === 'protection'
|
|
2186
|
+
? { ...current, deletionProtection: draft.deletionProtection, deletionProtectionForOfficialPresets: draft.deletionProtectionForOfficialPresets }
|
|
2187
|
+
: { ...parsed.configuration, deletionProtection: current.deletionProtection, deletionProtectionForOfficialPresets: current.deletionProtectionForOfficialPresets } }
|
|
2188
|
+
}
|
|
2189
|
+
function createBudgetAutosave(api, section = 'context') {
|
|
2190
|
+
return createAutosave(api, { draft: budgetDraft({}), toDraft: budgetDraft,
|
|
2191
|
+
toConfiguration: (draft, snapshot) => budgetSectionConfiguration(section, draft, snapshot) })
|
|
2192
|
+
}
|
|
2193
|
+
function budgetFieldValid(field, input) {
|
|
2194
|
+
const value = String(input ?? '').trim()
|
|
2195
|
+
if (!value) return true
|
|
2196
|
+
const number = Number(value)
|
|
2197
|
+
if (!Number.isFinite(number) || number < field.min || (field.max !== undefined && number > field.max)) return false
|
|
2198
|
+
if (field.step === 'any') return true
|
|
2199
|
+
const scaled = number * field.factor, rounded = Math.round(scaled)
|
|
2200
|
+
return Math.abs(rounded - scaled) <= 1e-7 && Number.isSafeInteger(rounded)
|
|
2201
|
+
}
|
|
2202
|
+
const autosaveValidationErrors = ['invalid', 'retain', 'ptc-order']
|
|
2203
|
+
function autosaveState(editing) {
|
|
2204
|
+
return editing.saving ? 'saving' : autosaveValidationErrors.includes(editing.error) ? 'invalid'
|
|
2205
|
+
: editing.error ? 'error' : editing.notice === 'saved' ? 'saved' : 'idle'
|
|
2206
|
+
}
|
|
2207
|
+
|
|
2100
2208
|
function BudgetSettings({ api, t, active, section = 'context', onSaved = () => {} }) {
|
|
2101
|
-
const
|
|
2102
|
-
const
|
|
2103
|
-
const
|
|
2209
|
+
const protection = section === 'protection'
|
|
2210
|
+
const editor = useMemo(() => createBudgetAutosave(api, section), [api, section])
|
|
2211
|
+
const editing = useSyncExternalStore(editor.subscribe, editor.getSnapshot, editor.getSnapshot)
|
|
2212
|
+
const { snapshot, draft } = editing
|
|
2213
|
+
const [loading, setLoading] = useState(false), [failure, setFailure] = useState(''), [notice, setNotice] = useState('')
|
|
2214
|
+
const [confirmReset, setConfirmReset] = useState(false)
|
|
2104
2215
|
const alive = useRef(false), pending = useRef(false)
|
|
2105
|
-
const
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
pending.current = true; setBusy(true); setError(''); setNotice('')
|
|
2216
|
+
const load = async (discard = false) => {
|
|
2217
|
+
if (pending.current || (!discard && editor.hasChanges())) return
|
|
2218
|
+
pending.current = true; setLoading(true); setFailure('')
|
|
2109
2219
|
try {
|
|
2110
2220
|
const response = await api.readConfig()
|
|
2111
2221
|
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)
|
|
2222
|
+
if (alive.current) editor.receive(response.value)
|
|
2223
|
+
} catch { if (alive.current) setFailure('connection') }
|
|
2224
|
+
finally { pending.current = false; if (alive.current) setLoading(false) }
|
|
2115
2225
|
}
|
|
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
|
-
|
|
2226
|
+
useEffect(() => { alive.current = true; return () => { alive.current = false; void editor.flush() } }, [editor])
|
|
2227
|
+
useEffect(() => { if (editing.saveCount) onSaved() }, [editing.saveCount])
|
|
2228
|
+
// Other tabs write the same document, so reread on every visit; leaving flushes pending input.
|
|
2229
|
+
useEffect(() => { if (active) load(); else { setConfirmReset(false); void editor.flush() } }, [editor, active])
|
|
2230
|
+
const reset = async () => {
|
|
2231
|
+
setConfirmReset(false)
|
|
2232
|
+
if (pending.current) return
|
|
2233
|
+
await editor.flush()
|
|
2234
|
+
const current = editor.getSnapshot().snapshot
|
|
2235
|
+
if (!alive.current || !current?.writable) return
|
|
2236
|
+
const base = current.configuration
|
|
2237
|
+
const configuration = protection
|
|
2238
|
+
? { ...base, deletionProtection: 'relaxed', deletionProtectionForOfficialPresets: false }
|
|
2239
|
+
: { deletionProtection: base.deletionProtection, deletionProtectionForOfficialPresets: base.deletionProtectionForOfficialPresets }
|
|
2240
|
+
pending.current = true; setLoading(true); setFailure(''); setNotice('')
|
|
2130
2241
|
try {
|
|
2131
|
-
const response = await api.saveConfig(JSON.stringify(
|
|
2242
|
+
const response = await api.saveConfig(JSON.stringify(configuration), String(current.revision))
|
|
2132
2243
|
if (!response.ok) throw new Error('Remote unavailable')
|
|
2133
2244
|
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
|
-
}
|
|
2245
|
+
if (response.value.ok) { editor.receive(response.value.snapshot); onSaved(); setNotice('resetDone') }
|
|
2246
|
+
else setFailure(response.value.error)
|
|
2247
|
+
} catch { if (alive.current) setFailure('save-failed') }
|
|
2248
|
+
finally { pending.current = false; if (alive.current) setLoading(false) }
|
|
2249
|
+
}
|
|
2250
|
+
const disabled = loading || !snapshot?.writable
|
|
2251
|
+
const edit = (key, value, delay = 0) => { setNotice(''); setFailure(''); editor.change({ [key]: value }, delay) }
|
|
2252
|
+
const parsed = budgetConfiguration(draft)
|
|
2253
|
+
const fieldError = field => !budgetFieldValid(field, draft[field.key]) ? t('budget.error.range')
|
|
2254
|
+
: field.key === 'retainRatio' && parsed.error === 'retain' ? t('budget.error.retain')
|
|
2255
|
+
: field.key === 'ptcTimeoutMs' && parsed.error === 'ptc-order' ? t('budget.error.ptc-order') : ''
|
|
2256
|
+
const defaultOf = field => {
|
|
2257
|
+
const value = field.root ? snapshot?.defaults?.[field.key] : snapshot?.defaults?.budgets?.[field.key]
|
|
2258
|
+
return value === undefined ? '' : Number(value / field.factor).toLocaleString('en-US', { maximumFractionDigits: 3, useGrouping: false })
|
|
2259
|
+
}
|
|
2260
|
+
const numberRow = field => {
|
|
2261
|
+
const id = `super-code-budget-${field.key}`, execution = field.group === 'execution', fallback = defaultOf(field)
|
|
2262
|
+
return React.createElement(SettingRow, { key: field.key, id, label: t(`budget.${field.key}`), error: fieldError(field),
|
|
2263
|
+
hint: text(t, 'budget.defaultHint', { value: fallback || t('budget.managed') }) }, described =>
|
|
2264
|
+
React.createElement('input', { id, type: 'number', inputMode: 'decimal', value: draft[field.key], min: field.min,
|
|
2265
|
+
max: execution && snapshot?.ptcMaxTimeoutMs ? snapshot.ptcMaxTimeoutMs / 1000 : field.max, step: field.step,
|
|
2266
|
+
placeholder: fallback || t('budget.inherit'), 'aria-invalid': fieldError(field) ? true : undefined, 'aria-describedby': described,
|
|
2267
|
+
disabled: disabled || (execution && snapshot?.ptcMaxTimeoutMs === false),
|
|
2268
|
+
onChange: event => edit(field.key, event.target.value, 500), onBlur: () => { void editor.flush() } }))
|
|
2269
|
+
}
|
|
2270
|
+
const rows = group => budgetFields.filter(field => field.group === group).map(numberRow)
|
|
2271
|
+
const saveError = editing.error && !autosaveValidationErrors.includes(editing.error) ? editing.error : ''
|
|
2272
|
+
const problem = failure || saveError
|
|
2273
|
+
const button = (label, onClick, extra = {}) => React.createElement(ActionButton, { type: 'button', disabled: loading, onClick, ...extra }, label)
|
|
2274
|
+
const content = protection ? React.createElement(React.Fragment, null,
|
|
2275
|
+
React.createElement(SettingsSection, { id: 'super-code-deletion-mode', title: t('delete.mode'), plain: true },
|
|
2276
|
+
React.createElement(ChoiceCards, { name: 'super-code-deletion-mode', label: t('delete.mode'), value: draft.deletionProtection, disabled,
|
|
2277
|
+
choices: ['off', 'relaxed', 'strict'].map(mode => [mode, t(`delete.${mode}`), t(`delete.hint.${mode}`)]),
|
|
2278
|
+
onChange: value => edit('deletionProtection', value) })),
|
|
2279
|
+
React.createElement(SettingsSection, { id: 'super-code-deletion-scope', title: t('delete.scope') },
|
|
2280
|
+
React.createElement(SettingRow, { id: 'super-code-deletion-official', label: t('delete.official'), hint: t('delete.officialHint') }, described =>
|
|
2281
|
+
React.createElement(ConnectionSwitch, { id: 'super-code-deletion-official', checked: draft.deletionProtectionForOfficialPresets,
|
|
2282
|
+
disabled: disabled || draft.deletionProtection === 'off', 'aria-describedby': described,
|
|
2283
|
+
onChange: value => edit('deletionProtectionForOfficialPresets', value) }))))
|
|
2284
|
+
: React.createElement(React.Fragment, null,
|
|
2285
|
+
React.createElement(Callout, { tone: 'info' }, React.createElement('p', null, t('budget.scope')), React.createElement('p', null, t('budget.defaults'))),
|
|
2286
|
+
React.createElement(SettingsSection, { id: 'super-code-budget-common', title: t('budget.common') },
|
|
2287
|
+
React.createElement(SettingRow, { id: 'super-code-budget-official', label: t('budget.applyToOfficialPresets'), hint: t('budget.officialHint') }, described =>
|
|
2288
|
+
React.createElement(ConnectionSwitch, { id: 'super-code-budget-official', checked: draft.applyToOfficialPresets, disabled, 'aria-describedby': described,
|
|
2289
|
+
onChange: value => edit('applyToOfficialPresets', value) }))),
|
|
2290
|
+
React.createElement(SettingsSection, { id: 'super-code-budget-context', title: t('budget.context'), description: t('budget.contextHint') },
|
|
2291
|
+
React.createElement(SettingRow, { id: 'super-code-budget-basis', label: t('budget.pressureBasis'), hint: text(t, 'budget.defaultHint', { value: t('budget.host') }) },
|
|
2292
|
+
React.createElement(SelectControl, { id: 'super-code-budget-basis', label: t('budget.pressureBasis'), value: draft.pressureBasis, disabled,
|
|
2293
|
+
choices: [['', t('budget.inherit')], ['host', t('budget.host')], ['window', t('budget.window')]], onChange: value => edit('pressureBasis', value) })),
|
|
2294
|
+
...rows('context'),
|
|
2295
|
+
React.createElement('details', { className: 'dsh-super-code-section-more' },
|
|
2296
|
+
React.createElement('summary', null, React.createElement(Glyph, { type: 'chevron' }), t('budget.advanced')), ...rows('advanced'))),
|
|
2297
|
+
React.createElement(SettingsSection, { id: 'super-code-budget-execution', title: t('budget.execution'),
|
|
2298
|
+
description: [t(snapshot?.ptcMaxTimeoutMs === false ? 'budget.ptcUnavailable' : 'budget.ptcHint'),
|
|
2299
|
+
snapshot?.ptcMaxTimeoutMs && text(t, 'budget.ptcCeiling', { seconds: snapshot.ptcMaxTimeoutMs / 1000 })] }, ...rows('execution')),
|
|
2300
|
+
React.createElement(SettingsSection, { id: 'super-code-budget-exclusive', title: t('budget.superCode'), description: t('budget.superCodeHint') }, ...rows('superCode')))
|
|
2159
2301
|
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')))))
|
|
2302
|
+
React.createElement('form', { className: 'dsh-super-code-stack', 'aria-label': t(protection ? 'delete.title' : 'budget.title'), 'aria-busy': loading || editing.saving,
|
|
2303
|
+
onSubmit: event => { event.preventDefault(); void editor.flush() } },
|
|
2304
|
+
problem && React.createElement(Callout, { tone: 'error',
|
|
2305
|
+
action: failure === 'connection' || problem === 'conflict' ? button(t('budget.reload'), () => load(true))
|
|
2306
|
+
: saveError ? button(t('save.retry'), () => { void editor.retry() }) : null },
|
|
2307
|
+
React.createElement('p', null, t(`budget.error.${problem}`))),
|
|
2308
|
+
snapshot && !snapshot.writable && React.createElement(Callout, { tone: 'warning' }, React.createElement('p', null, t('budget.error.read-only'))),
|
|
2309
|
+
notice && React.createElement(Callout, { tone: 'success' }, React.createElement('p', null, t(`budget.${notice}`))),
|
|
2310
|
+
content,
|
|
2311
|
+
React.createElement('div', { className: 'dsh-super-code-settings-footer' },
|
|
2312
|
+
React.createElement(SaveIndicator, { state: autosaveState(editing), t }),
|
|
2313
|
+
React.createElement('div', { className: 'dsh-super-code-settings-footer-actions' },
|
|
2314
|
+
confirmReset ? React.createElement(React.Fragment, null,
|
|
2315
|
+
React.createElement('span', null, t('budget.resetQuestion')),
|
|
2316
|
+
button(t('preset.cancel'), () => setConfirmReset(false)),
|
|
2317
|
+
button(t('budget.resetConfirm'), reset, { className: 'dsh-super-code-danger-button', disabled }))
|
|
2318
|
+
: button(t('budget.reset'), () => setConfirmReset(true), { disabled })))))
|
|
2210
2319
|
}
|
|
2211
2320
|
|
|
2212
2321
|
// Old hosts render file metadata. Synchronize through our own Remote, then
|
|
@@ -2250,18 +2359,21 @@ function synchronizePresetDisplay(api, locale, reload, onError, preferenceScope)
|
|
|
2250
2359
|
}
|
|
2251
2360
|
|
|
2252
2361
|
function connectionDraft(config) {
|
|
2253
|
-
return { enabled: config.enabled, port: String(config.port), allowedDirectories: [...config.allowedDirectories], knownDirectories: [...config.knownDirectories ?? []],
|
|
2362
|
+
return { enabled: config.enabled, allowNewConversations: config.allowNewConversations !== false, allowCallerApproval: config.allowCallerApproval === true, port: String(config.port), allowedDirectories: [...config.allowedDirectories], knownDirectories: [...config.knownDirectories ?? []],
|
|
2254
2363
|
maxConcurrent: config.maxConnections ?? 3, maxConnections: String(config.maxConnections ?? 3), directoriesConfigured: config.directoriesConfigured ?? false }
|
|
2255
2364
|
}
|
|
2256
2365
|
function connectionConfiguration(draft) {
|
|
2257
2366
|
const port = Number(draft.port), maxConnections = Number(draft.maxConnections)
|
|
2258
2367
|
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 } }
|
|
2368
|
+
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 }
|
|
2369
|
+
return { ok: true, configuration: { enabled: draft.enabled, allowNewConversations: draft.allowNewConversations, allowCallerApproval: draft.allowCallerApproval, port, allowedDirectories, maxConcurrent: maxConnections, maxConnections, directoriesConfigured: true, knownDirectories: draft.knownDirectories } }
|
|
2261
2370
|
}
|
|
2262
|
-
/**
|
|
2263
|
-
|
|
2264
|
-
|
|
2371
|
+
/**
|
|
2372
|
+
* Serialize writes and retain newer edits while an earlier revision is being saved.
|
|
2373
|
+
* `toConfiguration` returns `{ ok, configuration }` or `{ ok: false, error? }`; invalid drafts never write.
|
|
2374
|
+
*/
|
|
2375
|
+
function createAutosave(api, { draft: initialDraft, toDraft, toConfiguration }) {
|
|
2376
|
+
let state = { snapshot: false, draft: initialDraft, saving: false, error: '', notice: '', saveCount: 0 }
|
|
2265
2377
|
let version = 0, acknowledged = 0, blocked = -1, timer = false, running = false
|
|
2266
2378
|
const listeners = new Set()
|
|
2267
2379
|
const update = patch => { state = { ...state, ...patch }; for (const listener of listeners) listener() }
|
|
@@ -2273,14 +2385,14 @@ function createConnectionAutosave(api) {
|
|
|
2273
2385
|
update({ saving: true, error: '', notice: '' })
|
|
2274
2386
|
try {
|
|
2275
2387
|
while (acknowledged < version) {
|
|
2276
|
-
const sent = version, parsed =
|
|
2277
|
-
if (!parsed.ok) { blocked = version; update({ error: 'invalid' }); break }
|
|
2388
|
+
const sent = version, parsed = toConfiguration(state.draft, state.snapshot)
|
|
2389
|
+
if (!parsed.ok) { blocked = version; update({ error: parsed.error || 'invalid' }); break }
|
|
2278
2390
|
const result = await api.saveConfig(JSON.stringify(parsed.configuration), String(state.snapshot.revision))
|
|
2279
2391
|
if (!result.ok) throw new Error('Remote unavailable')
|
|
2280
2392
|
if (!result.value.ok) { blocked = version; update({ error: result.value.error }); break }
|
|
2281
2393
|
acknowledged = sent
|
|
2282
2394
|
update({ snapshot: result.value.snapshot, saveCount: state.saveCount + 1,
|
|
2283
|
-
...(sent === version ? { draft:
|
|
2395
|
+
...(sent === version ? { draft: toDraft(result.value.snapshot.configuration), notice: 'saved' } : {}) })
|
|
2284
2396
|
}
|
|
2285
2397
|
} catch { blocked = version; update({ error: 'save-failed' }) }
|
|
2286
2398
|
finally { update({ saving: false }) }
|
|
@@ -2291,7 +2403,7 @@ function createConnectionAutosave(api) {
|
|
|
2291
2403
|
getSnapshot: () => state,
|
|
2292
2404
|
subscribe: listener => { listeners.add(listener); return () => listeners.delete(listener) },
|
|
2293
2405
|
hasChanges: () => version !== acknowledged || state.saving,
|
|
2294
|
-
receive: (snapshot, draft =
|
|
2406
|
+
receive: (snapshot, draft = toDraft(snapshot.configuration)) => {
|
|
2295
2407
|
acknowledged = ++version
|
|
2296
2408
|
update({ snapshot, draft, error: '', notice: '' })
|
|
2297
2409
|
},
|
|
@@ -2303,12 +2415,19 @@ function createConnectionAutosave(api) {
|
|
|
2303
2415
|
if (delay) timer = setTimeout(() => { timer = false; void flush() }, delay)
|
|
2304
2416
|
else void flush()
|
|
2305
2417
|
},
|
|
2418
|
+
/** Retry the last blocked or failed draft without requiring another edit. */
|
|
2419
|
+
retry: () => { blocked = -1; return flush() },
|
|
2306
2420
|
flush,
|
|
2307
2421
|
}
|
|
2308
2422
|
}
|
|
2309
|
-
function
|
|
2423
|
+
function createConnectionAutosave(api) {
|
|
2424
|
+
return createAutosave(api, { draft: connectionDraft({ enabled: false, port: 23457, allowedDirectories: [] }),
|
|
2425
|
+
toDraft: connectionDraft, toConfiguration: draft => connectionConfiguration(draft) })
|
|
2426
|
+
}
|
|
2427
|
+
/** The single switch control for every settings toggle; extra props go to the input. */
|
|
2428
|
+
function ConnectionSwitch({ checked, disabled, onChange, children, ...input }) {
|
|
2310
2429
|
return React.createElement('label', { className: 'dsh-super-code-connection-switch' },
|
|
2311
|
-
React.createElement('input', { type: 'checkbox', role: 'switch', checked, disabled, onChange: event => onChange(event.target.checked) }),
|
|
2430
|
+
React.createElement('input', { ...input, type: 'checkbox', role: 'switch', checked, disabled, onChange: event => onChange(event.target.checked) }),
|
|
2312
2431
|
React.createElement('span', { className: 'dsh-super-code-connection-track', 'aria-hidden': true }, React.createElement('i')), children)
|
|
2313
2432
|
}
|
|
2314
2433
|
function DirectoryBrowser({ api, t, onSelect, onClose }) {
|
|
@@ -2476,6 +2595,10 @@ function ConnectionSettings({ api, t, active, openSession, onSaved = () => {} })
|
|
|
2476
2595
|
React.createElement('form', { 'aria-label': t('connection.title'), 'aria-busy': saving, onSubmit: event => { event.preventDefault(); void editor.flush() } },
|
|
2477
2596
|
React.createElement(ConnectionSwitch, { checked: draft.enabled, disabled, onChange: value => edit('enabled', value) }, t('connection.enabled')),
|
|
2478
2597
|
React.createElement('p', { className: 'dsh-super-code-connection-hint' }, t('connection.scope')),
|
|
2598
|
+
React.createElement(ConnectionSwitch, { checked: draft.allowNewConversations, disabled, onChange: value => edit('allowNewConversations', value) }, t('connection.allowNewConversations')),
|
|
2599
|
+
React.createElement('small', null, t('connection.allowNewConversationsHint')),
|
|
2600
|
+
React.createElement(ConnectionSwitch, { checked: draft.allowCallerApproval, disabled, onChange: value => edit('allowCallerApproval', value) }, t('connection.allowCallerApproval')),
|
|
2601
|
+
React.createElement('small', null, t('connection.allowCallerApprovalHint')),
|
|
2479
2602
|
React.createElement('div', { className: 'dsh-super-code-connection-grid' },
|
|
2480
2603
|
...[['port', 1024, 65535], ['maxConnections', 1, 32]].map(([key, min, max]) => React.createElement('div', { key, className: 'dsh-super-code-settings-field' },
|
|
2481
2604
|
React.createElement('label', { htmlFor: `super-code-connection-${key}` }, t(`connection.${key}`)),
|
|
@@ -2515,52 +2638,94 @@ function ConnectionSettings({ api, t, active, openSession, onSaved = () => {} })
|
|
|
2515
2638
|
browser && React.createElement(DirectoryBrowser, { api, t, onSelect: choose, onClose: () => setBrowser(false) }))
|
|
2516
2639
|
}
|
|
2517
2640
|
|
|
2641
|
+
/* A few exclusive choices read faster as one visible radio group than as a menu. */
|
|
2642
|
+
function SegmentedControl({ label, value, choices, onChange, disabled = false, busy = false, describedBy }) {
|
|
2643
|
+
const selected = choices.findIndex(([choice]) => choice === value)
|
|
2644
|
+
const focusable = Math.max(0, selected)
|
|
2645
|
+
const pick = choice => { if (!disabled && !busy && choice !== value) onChange(choice) }
|
|
2646
|
+
return React.createElement('div', { className: 'dsh-super-code-segmented', role: 'radiogroup', 'aria-label': label, 'aria-describedby': describedBy,
|
|
2647
|
+
'aria-busy': busy || undefined, 'aria-disabled': disabled || undefined,
|
|
2648
|
+
onKeyDown: event => {
|
|
2649
|
+
const step = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 }[event.key]
|
|
2650
|
+
const next = event.key === 'Home' ? 0 : event.key === 'End' ? choices.length - 1
|
|
2651
|
+
: step === undefined ? -1 : (focusable + step + choices.length) % choices.length
|
|
2652
|
+
if (next < 0 || disabled || busy) return
|
|
2653
|
+
event.preventDefault()
|
|
2654
|
+
event.currentTarget.querySelectorAll('[role=radio]')[next]?.focus()
|
|
2655
|
+
pick(choices[next][0])
|
|
2656
|
+
} },
|
|
2657
|
+
...choices.map(([choice, text], index) => React.createElement('button', { key: choice, type: 'button', role: 'radio',
|
|
2658
|
+
'aria-checked': index === selected, tabIndex: index === focusable ? 0 : -1, disabled, onClick: () => pick(choice) }, text)))
|
|
2659
|
+
}
|
|
2518
2660
|
function SettingsHome({ budgetApi, connectionApi, t, active, revision, navigate, children }) {
|
|
2519
2661
|
const [budget, setBudget] = useState(null), [connection, setConnection] = useState(null), [overview, setOverview] = useState({ connections: [], sessions: [] })
|
|
2520
|
-
|
|
2521
|
-
const
|
|
2522
|
-
|
|
2523
|
-
|
|
2662
|
+
// `saving` keeps the chosen value on screen until the reread confirms it.
|
|
2663
|
+
const [saving, setSaving] = useState(null), [failure, setFailure] = useState('')
|
|
2664
|
+
const alive = useRef(false), request = useRef(0), loading = useRef(false), writing = useRef(false)
|
|
2665
|
+
const load = async (force = false) => {
|
|
2666
|
+
if (!force && (loading.current || writing.current)) return
|
|
2667
|
+
const sequence = ++request.current
|
|
2668
|
+
loading.current = true
|
|
2524
2669
|
try {
|
|
2525
2670
|
const [b, c, o] = await Promise.all([budgetApi.readConfig(), connectionApi.readConfig(), connectionApi.overview()])
|
|
2526
2671
|
if (!b.ok || !c.ok || !o.ok) throw new Error()
|
|
2527
|
-
if (alive.current
|
|
2528
|
-
|
|
2529
|
-
|
|
2672
|
+
if (alive.current && sequence === request.current) {
|
|
2673
|
+
setBudget(b.value); setConnection(c.value); setOverview(o.value); setFailure(value => value === 'load' ? '' : value)
|
|
2674
|
+
}
|
|
2675
|
+
} catch { if (alive.current && sequence === request.current) setFailure('load') }
|
|
2676
|
+
finally { if (sequence === request.current) loading.current = false }
|
|
2530
2677
|
}
|
|
2531
2678
|
useEffect(() => { alive.current = true; return () => { alive.current = false } }, [budgetApi, connectionApi])
|
|
2532
2679
|
useEffect(() => { if (!active) return; load(); const timer = setInterval(load, 2000); return () => clearInterval(timer) }, [active, revision, budgetApi, connectionApi])
|
|
2533
2680
|
const change = async (kind, value) => {
|
|
2534
|
-
|
|
2535
|
-
|
|
2681
|
+
const current = kind === 'protection' ? budget : connection
|
|
2682
|
+
if (writing.current || !current?.writable) return
|
|
2683
|
+
// A save supersedes any poll in flight, so a stale read cannot undo the choice.
|
|
2684
|
+
writing.current = true; request.current++; loading.current = false
|
|
2685
|
+
setSaving({ kind, value }); setFailure('')
|
|
2686
|
+
let saved = false
|
|
2536
2687
|
try {
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
if (alive.current)
|
|
2544
|
-
}
|
|
2545
|
-
const mode = budget ? budgetDraft(budget.configuration).deletionProtection : ''
|
|
2688
|
+
const configuration = kind === 'protection' ? { ...current.configuration, deletionProtection: value } : { ...current.configuration, enabled: value }
|
|
2689
|
+
const response = await (kind === 'protection' ? budgetApi : connectionApi).saveConfig(JSON.stringify(configuration), String(current.revision))
|
|
2690
|
+
saved = Boolean(response.ok && response.value.ok)
|
|
2691
|
+
} catch { /* Reported on the row below. */ }
|
|
2692
|
+
if (saved && alive.current) await load(true)
|
|
2693
|
+
writing.current = false
|
|
2694
|
+
if (alive.current) { setSaving(null); if (!saved) setFailure(kind) }
|
|
2695
|
+
}
|
|
2696
|
+
const mode = saving?.kind === 'protection' ? saving.value : budget ? budgetDraft(budget.configuration).deletionProtection : ''
|
|
2697
|
+
const enabled = saving?.kind === 'connection' ? saving.value : Boolean(connection?.configuration.enabled)
|
|
2698
|
+
const state = !connection || saving?.kind === 'connection' ? 'loading' : connection.state
|
|
2699
|
+
const listening = enabled && state === 'listening'
|
|
2700
|
+
const needsSetup = Boolean(connection) && !enabled && !connection.configuration.allowedDirectories.length
|
|
2701
|
+
const placeholder = kind => React.createElement('span', { className: 'dsh-super-code-skeleton', 'data-skeleton': kind, 'aria-hidden': true })
|
|
2702
|
+
const row = ({ key, icon, title, target, on, body, control }) => React.createElement('section', { className: 'dsh-super-code-home-row',
|
|
2703
|
+
'data-home-row': key, 'data-active': on || undefined, 'aria-label': title, 'aria-busy': saving?.kind === key || undefined },
|
|
2704
|
+
React.createElement('span', { className: 'dsh-super-code-home-row-icon', 'aria-hidden': true }, React.createElement(Glyph, { type: icon })),
|
|
2705
|
+
React.createElement('div', { className: 'dsh-super-code-home-row-text' },
|
|
2706
|
+
React.createElement('h3', { className: 'dsh-super-code-home-row-title' },
|
|
2707
|
+
React.createElement('button', { type: 'button', 'aria-label': t('home.details', { title }), onClick: () => navigate(target) }, title, React.createElement(Glyph, { type: 'chevron' }))),
|
|
2708
|
+
body),
|
|
2709
|
+
React.createElement('div', { className: 'dsh-super-code-home-row-control' }, control),
|
|
2710
|
+
failure === key && React.createElement('p', { role: 'alert' }, t('home.error')))
|
|
2546
2711
|
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
|
-
|
|
2712
|
+
failure === 'load' && React.createElement('p', { role: 'alert' }, t('home.error')),
|
|
2713
|
+
React.createElement('div', { className: 'dsh-super-code-home-list' },
|
|
2714
|
+
row({ key: 'protection', icon: 'shield', title: t('delete.title'), target: 'protection', on: Boolean(mode) && mode !== 'off',
|
|
2715
|
+
body: budget ? React.createElement('p', { id: 'super-code-home-protection-hint', className: 'dsh-super-code-home-row-hint' }, t(`delete.hint.${mode}`)) : placeholder('text'),
|
|
2716
|
+
control: budget ? React.createElement(SegmentedControl, { label: t('delete.mode'), value: mode, describedBy: 'super-code-home-protection-hint',
|
|
2717
|
+
choices: ['off', 'relaxed', 'strict'].map(value => [value, t(`delete.${value}`)]), disabled: !budget.writable, busy: saving?.kind === 'protection',
|
|
2718
|
+
onChange: value => change('protection', value) }) : placeholder('control') }),
|
|
2719
|
+
row({ key: 'connection', icon: 'plug', title: t('home.mcp'), target: 'connection', on: enabled,
|
|
2720
|
+
body: connection ? React.createElement('p', { className: 'dsh-super-code-home-row-status', 'data-tone': state === 'listening' ? 'success' : state === 'error' ? 'error' : 'idle' },
|
|
2721
|
+
React.createElement('i', { 'aria-hidden': true }),
|
|
2722
|
+
React.createElement('span', null, t(`connection.state.${state}`)),
|
|
2723
|
+
listening && React.createElement('span', null, t('home.connectionCount', { count: overview.connections.length, max: connection.configuration.maxConnections })),
|
|
2724
|
+
listening && React.createElement('span', null, t('home.activeSessions', { count: connectionSessions(overview).connected.length }))) : placeholder('text'),
|
|
2725
|
+
control: needsSetup ? React.createElement(ActionButton, { type: 'button', onClick: () => navigate('connection') }, t('home.setupConnection'))
|
|
2726
|
+
: connection ? React.createElement(ConnectionSwitch, { checked: enabled, disabled: !connection.writable, 'aria-label': t('home.mcp'),
|
|
2727
|
+
onChange: value => value && !connection.configuration.allowedDirectories.length ? navigate('connection') : change('connection', value) })
|
|
2728
|
+
: placeholder('control') })))
|
|
2564
2729
|
}
|
|
2565
2730
|
function ConnectionConsent({ api, t }) {
|
|
2566
2731
|
const [requests, setRequests] = useState([]), [busy, setBusy] = useState(false), [error, setError] = useState(false)
|
|
@@ -2671,6 +2836,8 @@ function PresetSettings({ api, budgetApi, connectionApi, openSession = () => {},
|
|
|
2671
2836
|
}
|
|
2672
2837
|
const available = status && ['available', 'installed'].includes(status.state)
|
|
2673
2838
|
const versionState = status?.presetVersion ? status.presetVersion === status.pluginVersion ? 'match' : 'mismatch' : 'unknown'
|
|
2839
|
+
const stateProblem = Boolean(status) && ['missing', 'broken', 'conflict'].includes(status.state)
|
|
2840
|
+
const versionProblem = Boolean(status) && status.state !== 'missing' && versionState !== 'match'
|
|
2674
2841
|
const [overviewRevision, setOverviewRevision] = useState(0)
|
|
2675
2842
|
const onSaved = () => setOverviewRevision(value => value + 1)
|
|
2676
2843
|
const tabs = ['home', 'preset', 'context', 'protection', 'connection']
|
|
@@ -2687,27 +2854,35 @@ function PresetSettings({ api, budgetApi, connectionApi, openSession = () => {},
|
|
|
2687
2854
|
React.createElement('div', { className: 'dsh-super-code-settings-body' },
|
|
2688
2855
|
React.createElement('div', { role: 'tabpanel', id: 'super-code-panel-home', 'aria-labelledby': 'super-code-tab-home', hidden: tab !== 'home' },
|
|
2689
2856
|
React.createElement(SettingsHome, { budgetApi, connectionApi, t, active: tab === 'home', revision: overviewRevision, navigate: setTab },
|
|
2857
|
+
// Healthy state collapses to one status line; problems expand into a notice with its fix.
|
|
2690
2858
|
React.createElement('header', { className: 'dsh-super-code-settings-header' },
|
|
2691
2859
|
React.createElement('span', { className: 'dsh-super-code-settings-mark', 'aria-hidden': true }, React.createElement(Glyph, { type: 'code' })),
|
|
2692
2860
|
React.createElement('div', { className: 'dsh-super-code-settings-head-text' },
|
|
2693
2861
|
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
|
-
|
|
2862
|
+
React.createElement('div', { className: 'dsh-super-code-settings-status-row' },
|
|
2863
|
+
status ? React.createElement('p', { className: 'dsh-super-code-preset-status', role: 'status', 'data-available': available },
|
|
2864
|
+
React.createElement('i', { 'aria-hidden': true }),
|
|
2865
|
+
React.createElement('span', null, t(status.delivery === 'declaration' && status.state === 'installed' ? 'preset.state.declaredInstalled' : `preset.state.${status.state}`)),
|
|
2866
|
+
React.createElement('code', null, status.id))
|
|
2867
|
+
: React.createElement('p', { className: 'dsh-super-code-preset-status', role: 'status' }, busy ? t('preset.working') : t('preset.unavailableHint')),
|
|
2868
|
+
status && React.createElement('dl', { className: 'dsh-super-code-preset-meta' },
|
|
2869
|
+
React.createElement('div', null, React.createElement('dt', null, t('preset.pluginVersion')), React.createElement('dd', null, status.pluginVersion)),
|
|
2870
|
+
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')))),
|
|
2871
|
+
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')))),
|
|
2872
|
+
React.createElement('div', { className: 'dsh-super-code-settings-actions' },
|
|
2873
|
+
React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-icon-button', disabled: busy, onClick: () => run(false), 'aria-label': t('preset.refresh') },
|
|
2874
|
+
React.createElement(IconRefreshOutline16, { 'aria-hidden': true })))),
|
|
2875
|
+
(stateProblem || versionProblem) && React.createElement('div', { className: 'dsh-super-code-preset-notice', 'data-tone': status.state === 'broken' ? 'error' : 'warning' },
|
|
2876
|
+
React.createElement(Glyph, { type: 'error' }),
|
|
2877
|
+
React.createElement('div', { className: 'dsh-super-code-preset-notice-text' },
|
|
2878
|
+
stateProblem && React.createElement('p', null, t(status.authorable ? 'preset.installHint' : 'preset.unavailableHint')),
|
|
2879
|
+
versionProblem && React.createElement('p', { 'data-version-state': versionState },
|
|
2880
|
+
t(versionState === 'mismatch' ? 'preset.versionMismatch' : 'preset.versionUnknownHint')),
|
|
2881
|
+
// The fix goes on its own line, so no locale-specific sentence joiner is needed.
|
|
2882
|
+
versionProblem && versionState === 'mismatch' && React.createElement('p', { className: 'dsh-super-code-preset-notice-fix' },
|
|
2883
|
+
t(reinstall && status.authorable ? 'preset.versionReinstallHint' : 'preset.versionReloadHint'))),
|
|
2884
|
+
status.authorable && React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-primary-button', onClick: () => setTab('preset') },
|
|
2885
|
+
t(status.state === 'missing' ? status.delivery === 'declaration' ? 'preset.installDeclared' : 'preset.install' : 'home.managePreset'))))),
|
|
2711
2886
|
React.createElement('div', { role: 'tabpanel', id: 'super-code-panel-preset', 'aria-labelledby': 'super-code-tab-preset', hidden: tab !== 'preset' },
|
|
2712
2887
|
status?.authorable && React.createElement('form', { onSubmit: event => { event.preventDefault(); submit() } },
|
|
2713
2888
|
React.createElement('div', { className: 'dsh-super-code-settings-field' },
|
|
@@ -2819,6 +2994,11 @@ function apply(ctx) {
|
|
|
2819
2994
|
--sc-success:var(--dsw-color-text-success,#197661);
|
|
2820
2995
|
--sc-warning:var(--dsw-color-text-warning,#9c650c);
|
|
2821
2996
|
--sc-error:var(--dsw-color-text-error,#bb4545);
|
|
2997
|
+
--sc-active:var(--sc-accent);
|
|
2998
|
+
--sc-idle:var(--dsw-alias-state-idle-primary,var(--sc-faint));
|
|
2999
|
+
--sc-on-accent:var(--dsw-alias-label-primary-foreground,var(--sc-bg));
|
|
3000
|
+
--sc-shadow:color-mix(in srgb,var(--sc-text) 14%,transparent);
|
|
3001
|
+
--sc-radius:6px;
|
|
2822
3002
|
--sc-mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
|
|
2823
3003
|
--agent-muted:var(--sc-muted);--agent-line:var(--sc-line);
|
|
2824
3004
|
color:var(--sc-text);font-size:14px;line-height:1.55;letter-spacing:0;
|
|
@@ -2847,9 +3027,7 @@ function apply(ctx) {
|
|
|
2847
3027
|
.dsh-super-code-settings-mark svg{width:22px;height:22px;color:var(--sc-text)}
|
|
2848
3028
|
.dsh-super-code-settings-head-text{display:grid;gap:4px;min-width:0}
|
|
2849
3029
|
.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
3030
|
.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
3031
|
.dsh-super-code-settings-status-row{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap}
|
|
2854
3032
|
.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
3033
|
.dsh-super-code-preset-status>i{width:7px;height:7px;flex:none;border-radius:50%;background:var(--sc-warning)}
|
|
@@ -2857,15 +3035,12 @@ function apply(ctx) {
|
|
|
2857
3035
|
.dsh-super-code-preset-status>span{font-weight:500}
|
|
2858
3036
|
.dsh-super-code-preset-status code{color:var(--sc-muted);overflow-wrap:anywhere}
|
|
2859
3037
|
.dsh-super-code-settings-actions{display:flex;flex:none;margin-left:auto}
|
|
2860
|
-
|
|
2861
|
-
.dsh-super-code-settings-actions button
|
|
3038
|
+
/* One button family: secondary by default, primary via class; 32px in forms, 28px in cards. */
|
|
3039
|
+
.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}
|
|
3040
|
+
.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))}
|
|
3041
|
+
:is(.dsh-super-code-settings,.dsh-super-code-confirm) button:focus-visible{outline:2px solid var(--sc-accent);outline-offset:2px}
|
|
3042
|
+
:is(.dsh-super-code-settings,.dsh-super-code-confirm) button:disabled{opacity:.5;cursor:default}
|
|
2862
3043
|
.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
3044
|
.dsh-super-code-settings form{display:grid;gap:16px;margin-top:24px}
|
|
2870
3045
|
.dsh-super-code-settings form>h3{margin:0;font-size:14px;font-weight:600}
|
|
2871
3046
|
.dsh-super-code-settings-field{display:grid;gap:6px}
|
|
@@ -2874,8 +3049,8 @@ function apply(ctx) {
|
|
|
2874
3049
|
.dsh-super-code-settings-form-actions{display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:12px;padding-top:4px}
|
|
2875
3050
|
.dsh-super-code-settings-form-actions>small{flex:1;min-width:220px}
|
|
2876
3051
|
.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)
|
|
3052
|
+
.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}
|
|
3053
|
+
.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
3054
|
.dsh-super-code-settings-guidance:empty{display:none}
|
|
2880
3055
|
.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
3056
|
.dsh-super-code-settings-guidance p{margin:0 0 4px}
|
|
@@ -2884,11 +3059,73 @@ function apply(ctx) {
|
|
|
2884
3059
|
.dsh-super-code-settings-tabs>[role=tab][aria-selected=true]{border-bottom-color:var(--sc-text);color:var(--sc-text);font-weight:600}
|
|
2885
3060
|
.dsh-super-code-settings-tabs>[role=tab]:focus-visible{outline:2px solid var(--sc-active);outline-offset:3px;border-radius:2px}
|
|
2886
3061
|
.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-
|
|
3062
|
+
/* Settings primitives: stacked sections of label/control rows, callouts, autosave status. */
|
|
3063
|
+
.dsh-super-code-settings form.dsh-super-code-stack,.dsh-super-code-stack{display:grid;gap:24px;margin:0;min-width:0}
|
|
3064
|
+
.dsh-super-code-section{display:grid;gap:12px;min-width:0}
|
|
3065
|
+
.dsh-super-code-section-head{display:flex;align-items:flex-end;justify-content:space-between;gap:12px}
|
|
3066
|
+
.dsh-super-code-section-heading{display:grid;gap:4px;min-width:0}
|
|
3067
|
+
.dsh-super-code-section-heading h3{margin:0;font-size:14px;font-weight:600;line-height:1.4}
|
|
3068
|
+
.dsh-super-code-section-heading p{margin:0;font-size:12px;line-height:1.6;color:var(--sc-muted);text-wrap:pretty}
|
|
3069
|
+
.dsh-super-code-section-actions{display:flex;flex:none;gap:8px}
|
|
3070
|
+
.dsh-super-code-section-body{border:1px solid var(--sc-line);border-radius:12px;background:var(--sc-bg);min-width:0}
|
|
3071
|
+
.dsh-super-code-section-body[data-plain]{border:0;border-radius:0;background:none}
|
|
3072
|
+
.dsh-super-code-setting-row{display:grid;grid-template-columns:minmax(0,1fr) auto;align-items:center;gap:8px 24px;padding:12px 16px}
|
|
3073
|
+
.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)}
|
|
3074
|
+
.dsh-super-code-setting-row-text{display:grid;gap:2px;min-width:0}
|
|
3075
|
+
.dsh-super-code-settings .dsh-super-code-setting-row-text>label{font-size:13px;font-weight:500;line-height:1.5}
|
|
3076
|
+
.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}
|
|
3077
|
+
.dsh-super-code-setting-row-text>.dsh-super-code-setting-row-error{color:var(--sc-error)}
|
|
3078
|
+
.dsh-super-code-setting-row-control{display:flex;justify-content:flex-end;min-width:0}
|
|
3079
|
+
.dsh-super-code-setting-row-control>:is(input,.dsh-super-code-select){width:180px}
|
|
3080
|
+
.dsh-super-code-setting-row-control>input{height:32px;padding:5px 10px;border-radius:8px;font-variant-numeric:tabular-nums;text-align:right}
|
|
3081
|
+
.dsh-super-code-setting-row[data-invalid] input{border-color:var(--sc-error)}
|
|
3082
|
+
.dsh-super-code-settings input[type=number]{appearance:textfield}
|
|
3083
|
+
.dsh-super-code-settings input::-webkit-inner-spin-button{appearance:none}
|
|
3084
|
+
.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)}
|
|
3085
|
+
.dsh-super-code-section-more>summary::-webkit-details-marker{display:none}
|
|
3086
|
+
.dsh-super-code-section-more>summary:hover{color:var(--sc-text)}
|
|
3087
|
+
.dsh-super-code-section-more>summary .dsh-super-code-glyph{width:14px;height:14px;transform:rotate(-90deg);transition:transform .15s}
|
|
3088
|
+
.dsh-super-code-section-more[open]>summary .dsh-super-code-glyph{transform:none}
|
|
3089
|
+
.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))}
|
|
3090
|
+
.dsh-super-code-callout[data-tone=warning]{--tone:var(--sc-warning)}
|
|
3091
|
+
.dsh-super-code-callout[data-tone=error]{--tone:var(--sc-error)}
|
|
3092
|
+
.dsh-super-code-callout[data-tone=success]{--tone:var(--sc-success)}
|
|
3093
|
+
.dsh-super-code-callout>.dsh-super-code-glyph{width:16px;height:16px;margin-top:2px;color:var(--tone)}
|
|
3094
|
+
.dsh-super-code-callout-text{display:grid;gap:4px;flex:1;min-width:0}
|
|
3095
|
+
.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}
|
|
3096
|
+
.dsh-super-code-callout-text p+p{color:var(--sc-muted)}
|
|
3097
|
+
.dsh-super-code-callout>button{flex:none;align-self:center;min-height:28px;padding:3px 12px;font-size:12px}
|
|
3098
|
+
.dsh-super-code-settings .dsh-super-code-callout[role=alert]{font-size:inherit;color:inherit}
|
|
3099
|
+
.dsh-super-code-save-indicator{display:inline-flex;align-items:center;gap:6px;margin:0;font-size:12px;color:var(--sc-muted)}
|
|
3100
|
+
.dsh-super-code-save-indicator>i{width:6px;height:6px;border-radius:50%;background:var(--sc-idle);transition:background .15s}
|
|
3101
|
+
.dsh-super-code-save-indicator[data-save-state=saving]>i{background:var(--sc-accent);animation:sc-pulse 1s ease-in-out infinite}
|
|
3102
|
+
.dsh-super-code-save-indicator[data-save-state=saved]>i{background:var(--sc-success)}
|
|
3103
|
+
.dsh-super-code-save-indicator[data-save-state=invalid]{color:var(--sc-warning)}
|
|
3104
|
+
.dsh-super-code-save-indicator[data-save-state=invalid]>i{background:var(--sc-warning)}
|
|
3105
|
+
.dsh-super-code-save-indicator[data-save-state=error]{color:var(--sc-error)}
|
|
3106
|
+
.dsh-super-code-save-indicator[data-save-state=error]>i{background:var(--sc-error)}
|
|
3107
|
+
@keyframes sc-pulse{50%{opacity:.35}}
|
|
3108
|
+
.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)}
|
|
3109
|
+
.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)}
|
|
3110
|
+
.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}
|
|
3111
|
+
.dsh-super-code-settings-footer-actions button:hover:not(:disabled){background:var(--sc-hover)}
|
|
3112
|
+
.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))}
|
|
3113
|
+
.dsh-super-code-settings .dsh-super-code-danger-button:hover:not(:disabled){background:color-mix(in srgb,var(--sc-error) 8%,var(--sc-bg))}
|
|
3114
|
+
.dsh-super-code-choice-cards{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:8px}
|
|
3115
|
+
.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}
|
|
3116
|
+
.dsh-super-code-choice-card:hover{border-color:color-mix(in srgb,var(--sc-text) 22%,var(--sc-line))}
|
|
3117
|
+
.dsh-super-code-choice-card[data-checked]{border-color:var(--sc-accent);background:var(--sc-selected)}
|
|
3118
|
+
.dsh-super-code-choice-card>input{position:absolute;opacity:0;inset:0;width:100%;height:100%;margin:0;cursor:pointer}
|
|
3119
|
+
.dsh-super-code-choice-card>input:disabled{cursor:default}
|
|
3120
|
+
.dsh-super-code-choice-card:has(input:disabled){opacity:.55;cursor:default}
|
|
3121
|
+
.dsh-super-code-choice-card:has(input:focus-visible){outline:2px solid var(--sc-accent);outline-offset:2px}
|
|
3122
|
+
.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}
|
|
3123
|
+
.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)}
|
|
3124
|
+
.dsh-super-code-choice-card-text{display:grid;gap:4px;min-width:0}
|
|
3125
|
+
.dsh-super-code-choice-card-text strong{font-size:13px;font-weight:600}
|
|
3126
|
+
.dsh-super-code-choice-card-text small{font-size:12px;line-height:1.6;color:var(--sc-muted);text-wrap:pretty}
|
|
3127
|
+
@container(max-width:560px){.dsh-super-code-choice-cards{grid-template-columns:1fr}}
|
|
3128
|
+
@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
3129
|
|
|
2893
3130
|
.dsh-super-code-connection{display:grid;gap:18px}
|
|
2894
3131
|
.dsh-super-code-connection form{display:grid;gap:16px}
|
|
@@ -2900,19 +3137,17 @@ function apply(ctx) {
|
|
|
2900
3137
|
.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
3138
|
.dsh-super-code-connection small{color:var(--sc-muted);font-size:12px;line-height:1.6}
|
|
2902
3139
|
.dsh-super-code-connection .dsh-super-code-settings-actions{flex-wrap:wrap;gap:8px}
|
|
2903
|
-
|
|
3140
|
+
.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
3141
|
.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
3142
|
.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
3143
|
.dsh-super-code-connection-track i{display:block;width:14px;height:14px;border-radius:50%;background:var(--sc-muted);transition:transform .15s}
|
|
2907
3144
|
.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
|
|
3145
|
+
.dsh-super-code-connection-switch input:checked+.dsh-super-code-connection-track i{transform:translateX(14px);background:var(--sc-on-accent)}
|
|
2909
3146
|
.dsh-super-code-connection-switch input:focus-visible+.dsh-super-code-connection-track{outline:2px solid var(--sc-accent);outline-offset:3px}
|
|
2910
3147
|
.dsh-super-code-connection-switch input:disabled+.dsh-super-code-connection-track{opacity:.5}
|
|
2911
3148
|
.dsh-super-code-connection input[type=number]{appearance:textfield}
|
|
2912
3149
|
.dsh-super-code-connection input::-webkit-inner-spin-button{appearance:none}
|
|
2913
3150
|
|
|
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
3151
|
.dsh-super-code-budget-default{color:var(--sc-muted);font-weight:400;font-size:12px}
|
|
2917
3152
|
.dsh-super-code-budgets fieldset{min-width:0;margin:0;border:0;padding:0}
|
|
2918
3153
|
.dsh-super-code-budgets legend{font-size:13px;font-weight:500;margin-bottom:12px;padding:0}
|
|
@@ -2923,37 +3158,82 @@ function apply(ctx) {
|
|
|
2923
3158
|
.dsh-super-code-budgets .dsh-super-code-settings-form-actions{border-top:1px solid var(--sc-line);padding-top:16px}
|
|
2924
3159
|
@container(max-width:420px){.dsh-super-code-budget-grid{grid-template-columns:1fr}.dsh-super-code-settings-tabs{padding:0 16px}}
|
|
2925
3160
|
.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-
|
|
3161
|
+
@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
3162
|
|
|
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}
|
|
3163
|
+
.dsh-super-code-connection-activity{display:grid;gap:10px;border:1px solid var(--sc-line);border-radius:var(--sc-radius);padding:14px}
|
|
2932
3164
|
.dsh-super-code-connection-activity h3{margin:0;font-size:13px;font-weight:600}
|
|
2933
3165
|
.dsh-super-code-connection-activity h3:not(:first-child){margin-top:6px}
|
|
2934
3166
|
.dsh-super-code-connection-activity h4{margin:0 0 6px;font-size:12px;color:var(--sc-muted);font-weight:500}
|
|
2935
3167
|
.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)}
|
|
3168
|
+
.dsh-super-code-connection-activity button{min-height:28px;padding:3px 10px;font-size:12px}
|
|
2938
3169
|
/* Settings overview and directory consent use the same host theme aliases. */
|
|
2939
3170
|
.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-
|
|
3171
|
+
/* Home: one status header, then a settings list whose rows act in place and open details. */
|
|
3172
|
+
.dsh-super-code-home{display:grid;gap:16px}
|
|
3173
|
+
.dsh-super-code-home .dsh-super-code-settings-header{align-items:flex-start;padding-bottom:16px;margin-bottom:0}
|
|
3174
|
+
.dsh-super-code-home .dsh-super-code-settings-head-text{flex:1}
|
|
3175
|
+
.dsh-super-code-settings-head-text .dsh-super-code-settings-status-row{justify-content:flex-start;align-items:center;gap:2px 10px}
|
|
3176
|
+
.dsh-super-code-settings-head-text .dsh-super-code-preset-status{flex:none;margin:0;font-size:12px;gap:6px}
|
|
3177
|
+
.dsh-super-code-settings-head-text .dsh-super-code-preset-status>span{font-weight:400;color:var(--sc-muted)}
|
|
3178
|
+
.dsh-super-code-settings-head-text .dsh-super-code-preset-status code{font:12px var(--sc-mono)}
|
|
3179
|
+
.dsh-super-code-preset-meta{display:flex;flex-wrap:wrap;gap:0 10px;margin:0;font-size:12px;color:var(--sc-muted)}
|
|
3180
|
+
.dsh-super-code-preset-meta>div{display:flex;gap:4px}
|
|
3181
|
+
.dsh-super-code-preset-meta>div:before{content:"·";color:var(--sc-faint);margin-right:6px}
|
|
3182
|
+
.dsh-super-code-preset-meta dd{margin:0;font-family:var(--sc-mono);font-variant-numeric:tabular-nums;color:var(--sc-text)}
|
|
3183
|
+
.dsh-super-code-preset-meta dd[data-stale]{color:var(--sc-warning);font-weight:600}
|
|
3184
|
+
.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)}
|
|
3185
|
+
.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)}
|
|
3186
|
+
.dsh-super-code-settings-actions>.dsh-super-code-icon-button:hover{background:var(--sc-hover);color:var(--sc-text)}
|
|
3187
|
+
.dsh-super-code-settings-actions>.dsh-super-code-icon-button svg{width:16px;height:16px}
|
|
3188
|
+
.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))}
|
|
3189
|
+
.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))}
|
|
3190
|
+
.dsh-super-code-preset-notice>.dsh-super-code-glyph{width:16px;height:16px;margin-top:2px;color:var(--sc-warning)}
|
|
3191
|
+
.dsh-super-code-preset-notice[data-tone=error]>.dsh-super-code-glyph{color:var(--sc-error)}
|
|
3192
|
+
.dsh-super-code-preset-notice-text{display:grid;gap:4px;flex:1;min-width:0}
|
|
3193
|
+
.dsh-super-code-preset-notice-text p{margin:0;font-size:12px;line-height:1.6;overflow-wrap:anywhere;text-wrap:pretty}
|
|
3194
|
+
.dsh-super-code-preset-notice-text .dsh-super-code-preset-notice-fix{color:var(--sc-muted)}
|
|
3195
|
+
.dsh-super-code-preset-notice>button{flex:none;align-self:center;min-height:28px;padding:3px 12px;font-size:12px}
|
|
3196
|
+
.dsh-super-code-home-list{border:1px solid var(--sc-line);border-radius:10px;background:var(--sc-bg)}
|
|
3197
|
+
.dsh-super-code-home-row{display:grid;grid-template-columns:auto minmax(0,1fr) auto;align-items:center;gap:4px 14px;padding:14px 16px}
|
|
3198
|
+
.dsh-super-code-home-row+.dsh-super-code-home-row{border-top:1px solid var(--sc-line)}
|
|
3199
|
+
.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}
|
|
3200
|
+
.dsh-super-code-home-row-icon .dsh-super-code-glyph{width:17px;height:17px;color:inherit}
|
|
3201
|
+
.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)}
|
|
3202
|
+
.dsh-super-code-home-row-text{display:grid;gap:2px;min-width:0}
|
|
3203
|
+
.dsh-super-code-home-row-title{margin:0;font-size:13px;font-weight:600;line-height:1.5}
|
|
3204
|
+
.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)}
|
|
3205
|
+
.dsh-super-code-home-row-title>button:hover{color:var(--sc-accent)}
|
|
3206
|
+
.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}
|
|
3207
|
+
.dsh-super-code-home-row-title>button:hover .dsh-super-code-glyph{color:currentColor;transform:translateX(2px) rotate(-90deg)}
|
|
3208
|
+
.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)}
|
|
3209
|
+
/* Avoid a lone trailing character on wrapped CJK hints. */
|
|
3210
|
+
.dsh-super-code-home-row-hint{text-wrap:pretty}
|
|
3211
|
+
.dsh-super-code-home-row-status{display:flex;flex-wrap:wrap;align-items:center;gap:0 6px}
|
|
3212
|
+
.dsh-super-code-home-row-status>i{width:6px;height:6px;flex:none;border-radius:50%;background:var(--sc-idle)}
|
|
3213
|
+
.dsh-super-code-home-row-status[data-tone=success]>i{background:var(--sc-success)}
|
|
3214
|
+
.dsh-super-code-home-row-status[data-tone=error]>i{background:var(--sc-error)}
|
|
3215
|
+
.dsh-super-code-home-row-status>span+span:before{content:"·";margin-right:6px;color:var(--sc-faint)}
|
|
3216
|
+
.dsh-super-code-home-row-control{display:flex;justify-content:flex-end}
|
|
3217
|
+
.dsh-super-code-home-row-control>button{min-height:28px;padding:3px 12px;font-size:12px}
|
|
3218
|
+
.dsh-super-code-home-row>[role=alert]{grid-column:2/-1;margin:2px 0 0;font-size:12px}
|
|
3219
|
+
@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}}
|
|
3220
|
+
.dsh-super-code-segmented{display:inline-flex;gap:2px;padding:2px;border:1px solid var(--sc-line);border-radius:8px;background:var(--sc-surface)}
|
|
3221
|
+
.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}
|
|
3222
|
+
.dsh-super-code-segmented>[role=radio]:hover:not(:disabled){color:var(--sc-text)}
|
|
3223
|
+
.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)}
|
|
3224
|
+
.dsh-super-code-segmented[aria-busy=true]{cursor:progress}
|
|
3225
|
+
.dsh-super-code-segmented[aria-busy=true]>[role=radio]{pointer-events:none}
|
|
3226
|
+
.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}
|
|
3227
|
+
.dsh-super-code-skeleton[data-skeleton=text]{width:min(60%,280px);height:12px;margin-top:5px}
|
|
3228
|
+
.dsh-super-code-skeleton[data-skeleton=control]{width:96px;height:28px;border-radius:8px}
|
|
3229
|
+
@keyframes sc-skeleton{to{background-position:-200% 0}}
|
|
2949
3230
|
.dsh-super-code-connection-list{list-style:none;padding:0;margin:0;max-height:280px;overflow:auto}
|
|
2950
3231
|
.dsh-super-code-connection-list li{display:flex;align-items:center;gap:10px;padding:9px 0;border-bottom:1px solid var(--sc-line)}
|
|
2951
3232
|
.dsh-super-code-connection-list li:last-child{border:0}
|
|
2952
3233
|
.dsh-super-code-connection-list li>span{display:grid;gap:2px;flex:1;min-width:0;overflow-wrap:anywhere}
|
|
2953
3234
|
.dsh-super-code-connection-list strong{font-size:12px;font-weight:500}
|
|
2954
|
-
.dsh-super-code-connection-list code{font:
|
|
3235
|
+
.dsh-super-code-connection-list code{font:11px/1.5 var(--sc-mono);color:var(--sc-muted)}
|
|
2955
3236
|
.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
3237
|
.dsh-super-code-directory-fieldset{border:0;padding:0;margin:0;min-width:0;display:grid;gap:10px}
|
|
2958
3238
|
.dsh-super-code-directory-fieldset legend{font-size:13px;font-weight:500;margin-bottom:10px}
|
|
2959
3239
|
.dsh-super-code-directory-list{border:1px solid var(--sc-line);border-radius:9px;max-height:330px;overflow:auto}
|
|
@@ -3048,10 +3328,16 @@ function apply(ctx) {
|
|
|
3048
3328
|
[data-feedback-live=false] .dsh-super-code-feedback-step .dsh-super-code-feedback-mark.active:before{animation:none}
|
|
3049
3329
|
@keyframes sc-feedback-spin{to{transform:rotate(360deg)}}
|
|
3050
3330
|
@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-
|
|
3331
|
+
.dsh-super-code-feedback-tools{display:flex;flex-wrap:wrap;gap:4px 10px;list-style:none;margin:4px 0;padding:0 5px}
|
|
3332
|
+
.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)}
|
|
3333
|
+
.dsh-super-code-feedback-tools>li[data-running]>span{color:var(--sc-active)}
|
|
3334
|
+
.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}
|
|
3335
|
+
.dsh-super-code-tool-badge[data-tone=success]{color:var(--sc-success);background:color-mix(in srgb,var(--sc-success) 10%,transparent)}
|
|
3336
|
+
.dsh-super-code-tool-badge[data-tone=warning]{color:var(--sc-warning);background:color-mix(in srgb,var(--sc-warning) 12%,transparent)}
|
|
3337
|
+
.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}
|
|
3338
|
+
.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)}
|
|
3339
|
+
.dsh-super-code-state>.dsh-super-code-glyph{flex:none;width:14px;height:14px}
|
|
3340
|
+
.dsh-super-code-state[data-tone=error]{color:var(--sc-error);background:color-mix(in srgb,var(--sc-error) 8%,transparent)}
|
|
3055
3341
|
.dsh-super-code-feedback-list>li[data-feedback-kind=open]{padding-bottom:8px}
|
|
3056
3342
|
.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
3343
|
.dsh-super-code-feedback-open>.dsh-super-code-glyph{width:12px;height:12px;transition:transform .15s}
|
|
@@ -3064,7 +3350,7 @@ function apply(ctx) {
|
|
|
3064
3350
|
.dsh-super-code-feedback-file>.dsh-super-code-glyph{flex:none;width:14px;height:14px;color:var(--sc-muted)}
|
|
3065
3351
|
.dsh-super-code-feedback-file strong{min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:12px;font-weight:400}
|
|
3066
3352
|
.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:
|
|
3353
|
+
.dsh-super-code-feedback-file-operation{flex:none;margin-left:auto;font-size:11px;color:var(--sc-success)}
|
|
3068
3354
|
.dsh-super-code-feedback button:focus-visible,.dsh-super-code-feedback-scroll:focus-visible{outline:2px solid var(--sc-accent);outline-offset:-2px}
|
|
3069
3355
|
|
|
3070
3356
|
/* Memory library: geometry stays at 76px per row. */
|
|
@@ -3108,7 +3394,7 @@ function apply(ctx) {
|
|
|
3108
3394
|
.dsh-super-code-memory-row-topic{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--sc-muted);font-size:11px}
|
|
3109
3395
|
.dsh-super-code-memory-row-kind{color:var(--sc-muted);white-space:nowrap}
|
|
3110
3396
|
.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:
|
|
3397
|
+
.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
3398
|
.dsh-super-code-memory-row-meta>span+span{border-left:1px solid var(--sc-line);padding-left:8px;font-family:var(--sc-mono)}
|
|
3113
3399
|
.dsh-super-code-memory-empty{padding:24px 8px;color:var(--sc-muted);font-size:13px;line-height:1.8}
|
|
3114
3400
|
.dsh-super-code-memory-body{flex:1;min-height:0;overflow:auto;padding:16px;background:var(--sc-surface)}
|
|
@@ -3146,7 +3432,10 @@ function apply(ctx) {
|
|
|
3146
3432
|
.dsh-super-code-memory-action[data-action=read]{color:var(--sc-accent)}
|
|
3147
3433
|
.dsh-super-code-memory-action[data-action=remember]{color:var(--sc-success)}
|
|
3148
3434
|
|
|
3149
|
-
|
|
3435
|
+
.dsh-super-code-memory-editor fieldset{display:grid;gap:8px;border:1px solid var(--sc-line);border-radius:6px;min-width:0}
|
|
3436
|
+
|
|
3437
|
+
|
|
3438
|
+
/* Legacy memory retains its original editor. */
|
|
3150
3439
|
.dsh-super-code-memory-editor{display:grid;align-content:start;gap:12px;flex:1;min-height:0;overflow:auto;padding:12px 16px}
|
|
3151
3440
|
.dsh-super-code-memory-editor-heading{display:flex;align-items:center;justify-content:space-between;gap:8px}
|
|
3152
3441
|
.dsh-super-code-memory-editor label{display:grid;grid-template-columns:1fr auto;gap:6px;font-size:12px}
|
|
@@ -3183,12 +3472,12 @@ function apply(ctx) {
|
|
|
3183
3472
|
.dsh-super-code-tree-toolbar{display:flex;align-items:center;gap:6px;min-width:0}
|
|
3184
3473
|
.dsh-super-code-tree-toolbar>.dsh-super-code-icon-button{width:28px;height:28px;border-radius:6px}
|
|
3185
3474
|
.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:
|
|
3475
|
+
.dsh-super-code-graph-legend{display:flex;flex-wrap:wrap;gap:6px 12px;font-size:11px;color:var(--sc-muted)}
|
|
3187
3476
|
.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
|
|
3477
|
+
.dsh-super-code-circle.active{--state-color:var(--sc-success)}
|
|
3478
|
+
.dsh-super-code-circle.idle{--state-color:var(--sc-accent)}
|
|
3479
|
+
.dsh-super-code-circle.stopped{--state-color:var(--sc-faint)}
|
|
3480
|
+
.dsh-super-code-circle.unavailable{--state-color:var(--sc-warning)}
|
|
3192
3481
|
.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
3482
|
.dsh-super-code-graph-legend .dsh-super-code-circle.idle{background:transparent;border:1px solid var(--state-color)}
|
|
3194
3483
|
.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 +3521,7 @@ function apply(ctx) {
|
|
|
3232
3521
|
.dsh-super-code-node-status[data-tone=active]{color:var(--sc-accent)}
|
|
3233
3522
|
.dsh-super-code-node-status[data-tone=unavailable]{color:var(--sc-warning)}
|
|
3234
3523
|
.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:
|
|
3524
|
+
.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
3525
|
.dsh-super-code-tree-usage>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
3237
3526
|
.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
3527
|
.dsh-super-code-branch-toggle:hover{color:var(--sc-accent);border-color:currentColor}
|
|
@@ -3294,7 +3583,7 @@ function apply(ctx) {
|
|
|
3294
3583
|
.dsh-super-code-detail-avatar .dsh-super-code-glyph{width:16px;height:16px;color:inherit}
|
|
3295
3584
|
.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
3585
|
.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
|
|
3586
|
+
.dsh-super-code-detail-entry.user .dsh-super-code-detail-avatar{background:var(--sc-accent);color:var(--sc-on-accent)}
|
|
3298
3587
|
.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
3588
|
.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
3589
|
.dsh-super-code-detail-entry.tool{margin-bottom:12px}
|
|
@@ -3406,5 +3695,5 @@ function apply(ctx) {
|
|
|
3406
3695
|
ctx.effect(() => disposeMemoryType, 'super-code: memory library tab')
|
|
3407
3696
|
}
|
|
3408
3697
|
|
|
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 }
|
|
3698
|
+
return { inject, apply, taskFeedbackRows, feedbackStatus, feedbackListItems, feedbackListLayout, feedbackListIndex, feedbackListWindow, feedbackListAnchor, connectionSessions, createConnectionAutosave, connectionDraft, connectionConfiguration, budgetDraft, budgetConfiguration, synchronizePresetDisplay, agentSessionState, buildAgentView, visibleAgentRows, agentTreeDisplay, agentTreeTotals, agentTreeLayout, agentExecutionStatus, agentDetailAddress, agentDetailTarget, agentPath, detailRecord, createAgentInspector, agentHistoryRange, agentHistoryRows, agentHistoryWindow, memoryLibraryAddress, memoryLibraryTarget, memoryLibraryNavigation, memoryLibraryWindow, createMemoryEditor, MemoryLibrary }
|
|
3410
3699
|
} })
|