dsh-super-code 0.3.1 → 0.3.3

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/client/index.js CHANGED
@@ -15,10 +15,260 @@ const IconChevronDownOutline14 = icons.IconChevronDownOutlineRegular ?? icons.Ic
15
15
  const IconRefreshOutline16 = icons.IconRefreshOutlineRegular ?? icons.IconRefreshOutline16
16
16
  const { SessionEventStream } = require('@deepseek-ai/dsh-api-session-controller')
17
17
 
18
+ /* Shared controls use public React APIs without host-private dependencies. */
19
+ let selectControlSequence = 0
20
+ function selectControlPlacement(rect, count) {
21
+ const margin = 8, gap = 6, width = Math.min(Math.max(rect.width, 184), window.innerWidth - margin * 2)
22
+ const below = Math.max(0, window.innerHeight - rect.bottom - gap - margin)
23
+ const above = Math.max(0, rect.top - gap - margin)
24
+ const upwards = below < Math.min(count * 32 + 8, 256) && above > below
25
+ return {
26
+ left: Math.max(margin, Math.min(rect.left, window.innerWidth - width - margin)), width,
27
+ maxHeight: Math.min(256, upwards ? above : below),
28
+ ...(upwards ? { bottom: window.innerHeight - rect.top + gap } : { top: rect.bottom + gap }),
29
+ }
30
+ }
31
+ function SelectControl({ id, label, value, choices, onChange, disabled = false }) {
32
+ const identity = useRef('')
33
+ if (!identity.current) identity.current = id || `super-code-select-${++selectControlSequence}`
34
+ const controlId = identity.current, listId = `${controlId}-list`
35
+ const trigger = useRef(null), menu = useRef(null), search = useRef({ text: '', at: 0 })
36
+ const selected = Math.max(0, choices.findIndex(([choice]) => String(choice) === String(value)))
37
+ const [open, setOpen] = useState(false), [active, setActive] = useState(selected), [placement, setPlacement] = useState({})
38
+ const unavailable = disabled || choices.length === 0
39
+ const show = (index = selected) => {
40
+ if (unavailable) return
41
+ setActive(index)
42
+ setPlacement(selectControlPlacement(trigger.current.getBoundingClientRect(), choices.length))
43
+ search.current = { text: '', at: 0 }
44
+ setOpen(true)
45
+ }
46
+ const choose = index => {
47
+ onChange(choices[index][0])
48
+ setOpen(false)
49
+ trigger.current.focus({ preventScroll: true })
50
+ }
51
+ useLayoutEffect(() => {
52
+ if (!open) return
53
+ const place = () => setPlacement(selectControlPlacement(trigger.current.getBoundingClientRect(), choices.length))
54
+ window.addEventListener('resize', place)
55
+ window.addEventListener('scroll', place, true)
56
+ return () => { window.removeEventListener('resize', place); window.removeEventListener('scroll', place, true) }
57
+ }, [open, choices.length])
58
+ useLayoutEffect(() => {
59
+ if (open) menu.current.querySelector(`[data-option-index="${active}"]`)?.scrollIntoView({ block: 'nearest' })
60
+ }, [open, active])
61
+ useEffect(() => {
62
+ if (!open) return
63
+ const inside = target => Boolean(trigger.current?.contains(target) || menu.current?.contains(target))
64
+ let pointerInside = false
65
+ // Dock hosts focus their pane during pointer capture. Observe the pointer
66
+ // before that focus change so an option survives until its click commits.
67
+ const pointerDown = event => { pointerInside = inside(event.target); if (!pointerInside) setOpen(false) }
68
+ const pointerEnd = () => { pointerInside = false }
69
+ const outsideFocus = event => { if (!pointerInside && !inside(event.target)) setOpen(false) }
70
+ // Capture Escape before host shortcuts; Tab keeps its normal focus movement.
71
+ const escape = event => {
72
+ if (event.key !== 'Escape') return
73
+ event.preventDefault(); event.stopImmediatePropagation()
74
+ setOpen(false); trigger.current.focus({ preventScroll: true })
75
+ }
76
+ window.addEventListener('pointerdown', pointerDown, true)
77
+ window.addEventListener('pointerup', pointerEnd, true)
78
+ window.addEventListener('pointercancel', pointerEnd, true)
79
+ document.addEventListener('focusin', outsideFocus, true)
80
+ window.addEventListener('keydown', escape, true)
81
+ return () => {
82
+ window.removeEventListener('pointerdown', pointerDown, true)
83
+ window.removeEventListener('pointerup', pointerEnd, true)
84
+ window.removeEventListener('pointercancel', pointerEnd, true)
85
+ document.removeEventListener('focusin', outsideFocus, true)
86
+ window.removeEventListener('keydown', escape, true)
87
+ }
88
+ }, [open])
89
+ const keyDown = event => {
90
+ if (unavailable || event.isComposing) return
91
+ if (['ArrowDown', 'ArrowUp', 'Home', 'End'].includes(event.key)) {
92
+ event.preventDefault(); event.stopPropagation()
93
+ const next = event.key === 'Home' ? 0 : event.key === 'End' ? choices.length - 1
94
+ : Math.max(0, Math.min(choices.length - 1, active + (event.key === 'ArrowDown' ? 1 : -1)))
95
+ if (open) setActive(next)
96
+ else show(event.key === 'Home' || event.key === 'End' ? next : selected)
97
+ } else if (event.key === 'Enter' || event.key === ' ') {
98
+ event.preventDefault(); event.stopPropagation()
99
+ if (open) choose(active)
100
+ else show()
101
+ } else if (event.key === 'Tab') setOpen(false)
102
+ else if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
103
+ const now = Date.now(), previous = now - search.current.at < 700 ? search.current.text : ''
104
+ const query = (previous + event.key).toLocaleLowerCase()
105
+ const next = choices.findIndex(([, text]) => String(text).toLocaleLowerCase().startsWith(query))
106
+ if (next >= 0) {
107
+ event.preventDefault(); event.stopPropagation()
108
+ if (open) setActive(next)
109
+ else show(next)
110
+ }
111
+ search.current = { text: query, at: now }
112
+ }
113
+ }
114
+ return React.createElement('span', { className: 'dsh-super-code-select' },
115
+ React.createElement(ActionButton, {
116
+ ref: trigger, id: controlId, type: 'button', role: 'combobox', disabled: unavailable,
117
+ 'aria-label': label, 'aria-haspopup': 'listbox', 'aria-expanded': open, 'aria-controls': open ? listId : undefined,
118
+ 'aria-activedescendant': open ? `${listId}-${active}` : undefined, 'data-value': String(value),
119
+ className: 'dsh-super-code-select-trigger', onKeyDown: keyDown, onClick: () => { if (open) setOpen(false); else show() },
120
+ }, React.createElement('span', null, choices[selected]?.[1] || ''),
121
+ React.createElement('svg', { viewBox: '0 0 16 16', fill: 'none', stroke: 'currentColor', strokeWidth: 1.5, 'aria-hidden': true },
122
+ React.createElement('path', { d: 'm4 6 4 4 4-4', strokeLinecap: 'round', strokeLinejoin: 'round' }))),
123
+ open && React.createElement('div', { ref: menu, id: listId, role: 'listbox', 'aria-label': label,
124
+ className: 'dsh-super-code-select-menu', style: placement,
125
+ onPointerDown: event => event.preventDefault(),
126
+ }, choices.map(([choice, text], index) => React.createElement('div', {
127
+ key: choice, id: `${listId}-${index}`, role: 'option', 'aria-selected': String(choice) === String(value),
128
+ 'data-value': String(choice), 'data-option-index': index, 'data-active': index === active,
129
+ className: 'dsh-super-code-select-option', onPointerMove: () => setActive(index), onClick: () => choose(index),
130
+ }, React.createElement('span', null, text),
131
+ React.createElement('svg', { viewBox: '0 0 16 16', fill: 'none', stroke: 'currentColor', strokeWidth: 1.5, 'aria-hidden': true },
132
+ React.createElement('path', { d: 'm3.5 8 3 3 6-6', strokeLinecap: 'round', strokeLinejoin: 'round' }))))))
133
+ }
134
+
135
+
136
+ function Glyph({ type }) {
137
+ const paths = {
138
+ code: 'M8 5 3 10l5 5m8-10 5 5-5 5M14 3l-4 14',
139
+ branch: 'M5 3v8a4 4 0 0 0 4 4h6M5 7h10M5 3h0M15 4v6M15 12v6',
140
+ memory: 'M4 3h12a2 2 0 0 1 2 2v13H6a2 2 0 0 1-2-2V3Zm0 11h14M8 7h6M8 10h4',
141
+ search: 'M13 13l5 5M15 8a7 7 0 1 1-14 0 7 7 0 0 1 14 0Z',
142
+ folder: 'M2 6V4h6l2 2h8v10H2V6Z',
143
+ user: 'M10 10a3 3 0 1 0 0-6 3 3 0 0 0 0 6Zm-6 7a6 6 0 0 1 12 0',
144
+ agent: 'm10 2 2.2 5.8L18 10l-5.8 2.2L10 18l-2.2-5.8L2 10l5.8-2.2L10 2Z',
145
+ tool: 'm6 5-4 5 4 5m8-10 4 5-4 5M12 3 8 17',
146
+ context: 'M3 5h14M3 10h14M3 15h9',
147
+ error: 'M10 6v5m0 3h0M10 2l8 15H2L10 2Z',
148
+ chevron: 'm6 8 4 4 4-4',
149
+ arrow: 'M3 10h13m-5-5 5 5-5 5',
150
+ fit: 'M3 7V3h4m6 0h4v4m0 6v4h-4m-6 0H3v-4',
151
+ history: 'M3 4v5h5M3 9a7 7 0 1 1 2 6m5-10v5l3 2',
152
+ organize: 'M8 2h4v4H8zM2 14h4v4H2zm12 0h4v4h-4zM10 6v4m-6 4v-4h12v4'
153
+ }
154
+ 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
+ }
156
+
157
+ function AgentMessage({ record, saved, t, toolName }) {
158
+ const item = record.entry ? detailRecord(record.entry, t) : record
159
+ const eventType = record.entry?.event?.type
160
+ const kind = eventType === 'user/message' ? 'user' : eventType === 'assistant/message' ? 'agent'
161
+ : ['user', 'agent', 'tool', 'context', 'error'].includes(item.kind) ? item.kind : 'context'
162
+ const time = new Date(item.time).toLocaleTimeString(localeCode(t), { hour12: false })
163
+ const label = React.createElement('div', { className: 'dsh-super-code-detail-entry-label' },
164
+ React.createElement('span', null, item.label, toolName && !item.toolName ? ' · ' + toolName : ''), React.createElement('time', { dateTime: new Date(item.time).toISOString() }, time))
165
+ return React.createElement('article', { className: 'dsh-super-code-detail-entry ' + kind, 'data-event-type': eventType },
166
+ React.createElement('span', { className: 'dsh-super-code-detail-avatar', 'aria-hidden': true }, React.createElement(Glyph, { type: kind })),
167
+ React.createElement('div', { className: 'dsh-super-code-detail-message' }, item.collapsed
168
+ ? React.createElement('details', { open: saved.open.has(item.seq), onToggle: event => {
169
+ if (event.currentTarget.open) saved.open.add(item.seq); else saved.open.delete(item.seq)
170
+ } },
171
+ React.createElement('summary', null, label, React.createElement(Glyph, { type: 'chevron' })),
172
+ React.createElement(DetailText, { text: item.text, t }))
173
+ : React.createElement(React.Fragment, null, label, React.createElement(DetailText, { text: item.text, t }))))
174
+ }
175
+
176
+ /* Keep the native button and its refs/events; mount name bubbles outside clipped
177
+ * panels, or in the active dialog's top layer. No host-private UI is needed. */
178
+ let actionTooltipSequence = 0
179
+ let actionTooltipDismiss = () => {}
180
+ function actionButtonText(children) {
181
+ return React.Children.toArray(children).map(child => {
182
+ if (typeof child === 'string' || typeof child === 'number') return String(child)
183
+ if (!React.isValidElement(child) || child.props['aria-hidden']) return ''
184
+ return actionButtonText(child.props.children)
185
+ }).filter(Boolean).join(' ').replace(/\s+/g, ' ').trim()
186
+ }
187
+ const ActionButton = React.forwardRef(function ActionButton({ children, title, ...props }, forwardedRef) {
188
+ const button = useRef(null), pending = useRef(0), cleanup = useRef(() => {})
189
+ const name = props['aria-label'] || title || actionButtonText(children)
190
+ const attach = React.useCallback(node => {
191
+ button.current = node
192
+ if (typeof forwardedRef === 'function') forwardedRef(node)
193
+ else if (forwardedRef) forwardedRef.current = node
194
+ }, [forwardedRef])
195
+ // Event procedures deliberately return no value.
196
+ const hide = () => {
197
+ clearTimeout(pending.current)
198
+ pending.current = 0
199
+ cleanup.current()
200
+ cleanup.current = () => {}
201
+ if (actionTooltipDismiss === hide) actionTooltipDismiss = () => {}
202
+ }
203
+ const show = () => {
204
+ hide()
205
+ actionTooltipDismiss()
206
+ const anchor = button.current
207
+ if (!anchor || !name) return
208
+ const bubble = document.createElement('div'), id = `super-code-tooltip-${++actionTooltipSequence}`
209
+ bubble.id = id
210
+ bubble.className = 'dsh-super-code-tooltip'
211
+ bubble.setAttribute('role', 'tooltip')
212
+ bubble.textContent = name
213
+ bubble.style.visibility = 'hidden'
214
+ ;(anchor.closest('dialog[open]') || document.body).appendChild(bubble)
215
+ const rect = anchor.getBoundingClientRect(), bounds = bubble.getBoundingClientRect(), margin = 8, gap = 8
216
+ const left = Math.max(margin, Math.min(rect.left + rect.width / 2 - bounds.width / 2, window.innerWidth - bounds.width - margin))
217
+ const top = Math.max(margin, rect.top - bounds.height - gap)
218
+ bubble.dataset.side = 'top'
219
+ bubble.style.left = left + 'px'
220
+ bubble.style.top = top + 'px'
221
+ bubble.style.setProperty('--sc-tooltip-arrow-left', Math.max(8, Math.min(bounds.width - 8, rect.left + rect.width / 2 - left)) + 'px')
222
+ bubble.style.visibility = 'visible'
223
+ anchor.setAttribute('aria-describedby', [anchor.getAttribute('aria-describedby'), id].filter(Boolean).join(' '))
224
+ const escape = event => { if (event.key === 'Escape') hide() }
225
+ window.addEventListener('resize', hide)
226
+ window.addEventListener('scroll', hide, true)
227
+ window.addEventListener('keydown', escape, true)
228
+ document.addEventListener('pointerdown', hide, true)
229
+ cleanup.current = () => {
230
+ bubble.remove()
231
+ const remaining = (anchor.getAttribute('aria-describedby') || '').split(/\s+/).filter(value => value && value !== id).join(' ')
232
+ if (remaining) anchor.setAttribute('aria-describedby', remaining)
233
+ else anchor.removeAttribute('aria-describedby')
234
+ window.removeEventListener('resize', hide)
235
+ window.removeEventListener('scroll', hide, true)
236
+ window.removeEventListener('keydown', escape, true)
237
+ document.removeEventListener('pointerdown', hide, true)
238
+ }
239
+ actionTooltipDismiss = hide
240
+ }
241
+ useEffect(() => { hide() }, [name])
242
+ useEffect(() => () => hide(), [])
243
+ return React.createElement('button', {
244
+ ...props, ref: attach, 'data-tooltip-name': name,
245
+ onPointerEnter: event => {
246
+ props.onPointerEnter?.(event)
247
+ if (event.pointerType !== 'touch') { hide(); pending.current = setTimeout(show, 250) }
248
+ },
249
+ onPointerLeave: event => { hide(); props.onPointerLeave?.(event) },
250
+ onPointerCancel: event => { hide(); props.onPointerCancel?.(event) },
251
+ onFocus: event => { props.onFocus?.(event); if (event.currentTarget.matches(':focus-visible')) show() },
252
+ onBlur: event => { hide(); props.onBlur?.(event) },
253
+ onKeyDown: event => { hide(); props.onKeyDown?.(event) },
254
+ }, children)
255
+ })
256
+
18
257
  const LOCALE_NS = 'dshSuperCode'
19
258
  const zh = {
259
+ 'memory.add': '新增记忆', 'memory.edit': '编辑', 'memory.cancel': '取消', 'memory.save': '保存', 'memory.delete': '删除', 'memory.deleting': '正在删除…', 'memory.saving': '正在保存…',
260
+ 'memory.topic': '主题', 'memory.kind': '类型', 'memory.summaryLabel': '标题', 'memory.detailLabel': '内容', 'memory.manual': '手动维护',
261
+ 'memory.topicHint': '字母、数字、点、下划线或短横线,最多 96 个字符。',
262
+ 'memory.deleteTitle': '删除记忆', 'memory.deleteHint': '确定删除“{summary}”吗?删除后无法恢复。',
263
+ 'memory.writeError': '操作失败,内容已保留,请重试。', 'memory.conflict': '这条记忆已在别处更改,请取消后刷新再编辑。',
264
+ 'memory.missingEdit': '这条记忆已被删除,输入内容已保留。', 'memory.full': '该主题或记忆库已满,请删除不再需要的条目。',
265
+ 'workspace.title': 'Super Code', 'workspace.description': 'Agent 执行树与记忆库', 'workspace.resize': '调整执行树与记忆库高度',
266
+ 'tree.collapsedLabel': '已收起', 'tree.organizeLabel': '自动整理',
267
+ 'detail.toolCall': '工具调用', 'detail.toolResult': '工具结果', 'detail.toolError': '工具失败',
268
+ 'detail.cache': '缓存', 'detail.info': '详情', 'tree.countCompact': '{shown}/{total} · 运行 {running}',
269
+ 'memory.loading': '正在读取记忆…', 'memory.topics': '知识主题', 'memory.allTopics': '全部主题', 'memory.related': '同主题知识', 'preset.configuration': '预设配置',
20
270
  'memory.title': '记忆库', 'memory.project': '当前项目', 'memory.global': '全局偏好', 'memory.search': '搜索主题或记忆',
21
- 'memory.description': '跨对话保留的经验与偏好。按需读取,不会整库塞进上下文。',
271
+ 'memory.description': '知识主题与条目',
22
272
  'memory.empty': '还没有保存的记忆。需要长期保留时,直接告诉 Agent 即可。', 'memory.noMatches': '没有匹配的记忆',
23
273
  'memory.selectSession': '先打开一个对话,查看它所在项目的记忆。', 'memory.error': '暂时无法读取记忆,请刷新重试。',
24
274
  'memory.refresh': '刷新记忆库', 'memory.count': '{count} 条记忆', 'memory.back': '返回列表', 'memory.missing': '这条记忆已删除或更新,请刷新列表。',
@@ -76,8 +326,19 @@ const zh = {
76
326
  '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': '[图片]'
77
327
  }
78
328
  const en = {
329
+ 'memory.add': 'Add memory', 'memory.edit': 'Edit', 'memory.cancel': 'Cancel', 'memory.save': 'Save', 'memory.delete': 'Delete', 'memory.deleting': 'Deleting…', 'memory.saving': 'Saving…',
330
+ 'memory.topic': 'Topic', 'memory.kind': 'Type', 'memory.summaryLabel': 'Title', 'memory.detailLabel': 'Content', 'memory.manual': 'Manually maintained',
331
+ 'memory.topicHint': 'Letters, digits, dots, underscores or hyphens; up to 96 characters.',
332
+ 'memory.deleteTitle': 'Delete memory', 'memory.deleteHint': 'Delete “{summary}”? This cannot be undone.',
333
+ 'memory.writeError': 'The operation failed. Your input is retained; try again.', 'memory.conflict': 'This memory changed elsewhere. Cancel and refresh before editing again.',
334
+ 'memory.missingEdit': 'This memory was deleted. Your input is retained.', 'memory.full': 'This topic or library is full. Remove entries you no longer need.',
335
+ 'workspace.title': 'Super Code', 'workspace.description': 'Agent tree and memory library', 'workspace.resize': 'Resize agent tree and memory library',
336
+ 'tree.collapsedLabel': 'Collapsed', 'tree.organizeLabel': 'Organize',
337
+ 'detail.toolCall': 'Tool call', 'detail.toolResult': 'Tool result', 'detail.toolError': 'Tool failed',
338
+ 'detail.cache': 'Cache', 'detail.info': 'Details', 'tree.countCompact': '{shown}/{total} · Running {running}',
339
+ 'memory.loading': 'Loading memories…', 'memory.topics': 'Knowledge topics', 'memory.allTopics': 'All topics', 'memory.related': 'More in this topic', 'preset.configuration': 'Preset configuration',
79
340
  'memory.title': 'Memory library', 'memory.project': 'This project', 'memory.global': 'Global preferences', 'memory.search': 'Search topics or memories',
80
- 'memory.description': 'Experience and preferences kept across conversations. Details are read on demand, never injected in bulk.',
341
+ 'memory.description': 'Knowledge topics and entries',
81
342
  'memory.empty': 'No saved memories yet. Tell the agent when something is worth keeping.', 'memory.noMatches': 'No matching memories',
82
343
  'memory.selectSession': 'Open a conversation to view memory for its project.', 'memory.error': 'Memory is unavailable. Refresh to try again.',
83
344
  'memory.refresh': 'Refresh memory', 'memory.count': '{count} memories', 'memory.back': 'Back to list', 'memory.missing': 'This memory was removed or changed. Refresh the list.',
@@ -364,9 +625,10 @@ function agentHistoryWindow(count, scrollTop, height) {
364
625
  }
365
626
 
366
627
  /** Local scroll state keeps the graph out of the scrolling render path. */
367
- function AgentHistory({ view, hidden, totals, open, t = key => zh[key] || key }) {
368
- const [filters, setFilters] = useState({ query: '', range: 'all', from: '', to: '', sort: 'time-desc' })
369
- const [scroll, setScroll] = useState({ top: 0, height: 168 })
628
+ function AgentHistory({ view, hidden, totals, open, saved, t = key => zh[key] || key }) {
629
+ const [filters, setFilters] = useState(saved.historyFilters || { query: '', range: 'all', from: '', to: '', sort: 'time-desc' })
630
+ const [scroll, setScroll] = useState({ top: saved.historyTop || 0, height: 168 })
631
+ const previousFilters = useRef(filters)
370
632
  const viewport = useRef(null), focusTarget = useRef('')
371
633
  const records = useMemo(() => agentHistoryRows(view, hidden, totals, { ...filters, t }), [view, hidden, totals, filters, t])
372
634
  const language = localeCode(t)
@@ -375,20 +637,25 @@ function AgentHistory({ view, hidden, totals, open, t = key => zh[key] || key })
375
637
  const range = agentHistoryRange(filters.range, filters.from, filters.to)
376
638
  const change = (key, value) => setFilters(previous => ({ ...previous, [key]: value }))
377
639
  useLayoutEffect(() => {
378
- viewport.current.scrollTop = 0
379
- setScroll(previous => ({ ...previous, top: 0 }))
380
- }, [filters])
640
+ saved.historyFilters = filters
641
+ if (previousFilters.current !== filters) {
642
+ viewport.current.scrollTop = 0; saved.historyTop = 0
643
+ setScroll(previous => ({ ...previous, top: 0 }))
644
+ }
645
+ previousFilters.current = filters
646
+ }, [filters, saved])
381
647
  useLayoutEffect(() => {
382
648
  const element = viewport.current
383
649
  const measure = () => setScroll(previous => previous.top === element.scrollTop && previous.height === element.clientHeight
384
650
  ? previous : { top: element.scrollTop, height: element.clientHeight })
651
+ element.scrollTop = saved.historyTop || 0
385
652
  measure()
386
653
  const observer = new ResizeObserver(measure)
387
654
  observer.observe(element)
388
655
  return () => observer.disconnect()
389
656
  }, [])
390
657
  useLayoutEffect(() => {
391
- viewport.current.scrollTop = window.top
658
+ viewport.current.scrollTop = window.top; saved.historyTop = window.top
392
659
  if (focusTarget.current) {
393
660
  const target = Array.from(viewport.current.querySelectorAll('button')).find(button => button.dataset.historyId === focusTarget.current)
394
661
  if (target) { target.focus({ preventScroll: true }); focusTarget.current = '' }
@@ -404,9 +671,9 @@ function AgentHistory({ view, hidden, totals, open, t = key => zh[key] || key })
404
671
  else if ((target + 1) * historyRowHeight > element.scrollTop + element.clientHeight) element.scrollTop = (target + 1) * historyRowHeight - element.clientHeight
405
672
  setScroll({ top: element.scrollTop, height: element.clientHeight })
406
673
  }
407
- const select = (key, label, choices) => React.createElement('label', null, label,
408
- React.createElement('select', { value: filters[key], 'aria-label': label, onChange: event => change(key, event.target.value) },
409
- choices.map(([value, text]) => React.createElement('option', { key: value, value }, text))))
674
+ const select = (key, label, choices) => React.createElement('div', { className: 'dsh-super-code-select-field' },
675
+ React.createElement('label', { htmlFor: 'super-code-history-' + key }, label),
676
+ React.createElement(SelectControl, { id: 'super-code-history-' + key, label, value: filters[key], choices, onChange: value => change(key, value) }))
410
677
  return React.createElement('section', { className: 'dsh-super-code-history', 'aria-label': text(t, 'history.aria') },
411
678
  React.createElement('input', { type: 'search', value: filters.query, 'aria-label': text(t, 'history.find'), placeholder: text(t, 'history.search'), onChange: event => change('query', event.target.value) }),
412
679
  React.createElement('div', { className: 'dsh-super-code-history-filters' },
@@ -423,7 +690,7 @@ function AgentHistory({ view, hidden, totals, open, t = key => zh[key] || key })
423
690
  const date = record.time < 0 ? text(t, 'history.unknownTime') : dateFormat.format(record.time)
424
691
  return React.createElement('div', { key: record.id, role: 'listitem', 'aria-posinset': index + 1, 'aria-setsize': records.length,
425
692
  style: { position: 'absolute', top: index * historyRowHeight, height: historyRowHeight, width: '100%' } },
426
- React.createElement('button', { type: 'button', 'data-history-id': record.id, onClick: () => open(record.node), onKeyDown: event => keyDown(event, index),
693
+ React.createElement(ActionButton, { type: 'button', 'data-history-id': record.id, onClick: () => open(record.node), onKeyDown: event => keyDown(event, index),
427
694
  title: `${record.title} · ${record.parent} · ${record.time < 0 ? date : new Date(record.time).toLocaleString(localeCode(t))} · ${record.tokens < 0 ? text(t, 'history.unknownUsage') : record.tokens + ' Token' + (record.partial ? ' (' + text(t, 'usage.partial') + ')' : '')}`,
428
695
  'aria-label': text(t, 'history.view', { title: record.title }) },
429
696
  React.createElement('i', { className: 'dsh-super-code-circle ' + status.tone, 'aria-hidden': true }),
@@ -433,7 +700,7 @@ function AgentHistory({ view, hidden, totals, open, t = key => zh[key] || key })
433
700
  !records.length && React.createElement('p', { className: 'dsh-super-code-history-empty' }, text(t, 'history.empty'))))
434
701
  }
435
702
 
436
- function AgentTree({ useSessions, useSessionStatus, sessionId, useTabInfo, treeStates, openDetail, refresh, watchCatalog, t = key => zh[key] || key }) {
703
+ function AgentTree({ useSessions, useSessionStatus, sessionId, useTabInfo, treeStates, openDetail, refresh, watchCatalog, onToggle, t = key => zh[key] || key }) {
437
704
  const catalog = useSessions(s => s)
438
705
  const statuses = useSessionStatus ? useSessionStatus(s => s) : undefined
439
706
  const state = useMemo(() => agentSessionState(catalog, sessionId, statuses), [catalog, sessionId, statuses])
@@ -447,7 +714,59 @@ function AgentTree({ useSessions, useSessionStatus, sessionId, useTabInfo, treeS
447
714
  }
448
715
  return value
449
716
  }, [treeStates, tab.signal, view.root])
450
- return React.createElement(AgentTreeBody, { key: view.root, state, view, saved, openDetail, refresh, watchCatalog, t })
717
+ return React.createElement(AgentTreeBody, { key: view.root, state, view, saved, openDetail, refresh, watchCatalog, onToggle, t })
718
+ }
719
+
720
+ function WorkspaceSectionToggle({ section, expanded, onToggle, children, t }) {
721
+ const label = text(t, section === 'tree' ? 'tree.title' : 'memory.title')
722
+ return React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-section-toggle',
723
+ 'data-workspace-section': section, 'aria-label': label, 'aria-expanded': expanded, onClick: onToggle },
724
+ React.createElement(Glyph, { type: 'chevron' }),
725
+ React.createElement(Glyph, { type: section === 'tree' ? 'branch' : 'memory' }),
726
+ React.createElement('strong', null, label), children)
727
+ }
728
+
729
+ /** One active section guarantees exactly one open view; tab state retains drafts. */
730
+ function SuperCodeWorkspace(props) {
731
+ const { tab } = props.useTabInfo()
732
+ const address = typeof tab.navigation?.params?.memory === 'string' ? tab.navigation.params.memory : tab.contentId
733
+ const navigationKey = `${address}/${tab.navigation?.revision || 0}`
734
+ const memoryTarget = memoryLibraryTarget(address, '')
735
+ const saved = useMemo(() => {
736
+ const value = props.workspaceStates.get(tab.signal) || { active: 'tree' }
737
+ if (value.navigationKey !== navigationKey) {
738
+ value.navigationKey = navigationKey
739
+ if (memoryTarget.id) value.active = 'memory'
740
+ }
741
+ props.workspaceStates.set(tab.signal, value)
742
+ return value
743
+ }, [props.workspaceStates, tab.signal])
744
+ const [active, setActive] = useState(saved.active === 'memory' ? 'memory' : 'tree')
745
+ const layout = useRef(null), focusSection = useRef('')
746
+ const toggle = () => {
747
+ const next = active === 'tree' ? 'memory' : 'tree'
748
+ saved.active = next; focusSection.current = next; setActive(next)
749
+ }
750
+ useLayoutEffect(() => {
751
+ if (saved.navigationKey === navigationKey) return
752
+ saved.navigationKey = navigationKey
753
+ if (memoryTarget.id) { saved.active = 'memory'; setActive('memory') }
754
+ }, [saved, navigationKey])
755
+ useLayoutEffect(() => {
756
+ if (!focusSection.current) return
757
+ layout.current.querySelector(`[data-workspace-section="${focusSection.current}"]`)?.focus({ preventScroll: true })
758
+ focusSection.current = ''
759
+ }, [active])
760
+ return React.createElement('section', { className: 'dsh-super-code-workspace', 'aria-label': text(props.t, 'workspace.title') },
761
+ React.createElement('div', { ref: layout, className: 'dsh-super-code-workspace-layout', 'data-active-section': active, style: {
762
+ gridTemplateRows: active === 'tree' ? 'minmax(280px, 1fr) 44px' : '44px minmax(280px, 1fr)',
763
+ } },
764
+ active === 'tree' ? React.createElement(AgentTree, { ...props, key: 'tree', onToggle: toggle })
765
+ : React.createElement('header', { key: 'tree-collapsed', className: 'dsh-super-code-workspace-collapsed' },
766
+ React.createElement(WorkspaceSectionToggle, { section: 'tree', expanded: false, onToggle: toggle, t: props.t })),
767
+ active === 'memory' ? React.createElement(MemoryLibrary, { ...props, key: 'memory', onToggle: toggle })
768
+ : React.createElement('header', { key: 'memory-collapsed', className: 'dsh-super-code-workspace-collapsed' },
769
+ React.createElement(WorkspaceSectionToggle, { section: 'memory', expanded: false, onToggle: toggle, t: props.t }))))
451
770
  }
452
771
 
453
772
  function AgentCatalogWatch({ id, watchCatalog }) {
@@ -458,6 +777,8 @@ function AgentCatalogWatch({ id, watchCatalog }) {
458
777
  return null
459
778
  }
460
779
 
780
+ // Keep connector anchors and canvas bounds in step with the node's text stack.
781
+ const agentTreeNodeHeight = 120, agentTreeLevelSpacing = 152
461
782
  function agentTreeLayout(view, limit) {
462
783
  const { rows, more } = visibleAgentRows(view, () => true, limit)
463
784
  const positions = new Map(), edges = []
@@ -466,14 +787,14 @@ function agentTreeLayout(view, limit) {
466
787
  const row = rows[i]
467
788
  const children = (view.children.get(row.id) || []).filter(id => positions.has(id) && positions.get(id).level === row.level + 1)
468
789
  const x = children.length ? children.reduce((sum, id) => sum + positions.get(id).x, 0) / children.length : 70 + leaves++ * 140
469
- positions.set(row.id, { ...row, x, y: 18 + (row.level - 1) * 128 })
790
+ positions.set(row.id, { ...row, x, y: 18 + (row.level - 1) * agentTreeLevelSpacing })
470
791
  for (const child of children) edges.push({ parent: row.id, child })
471
792
  }
472
793
  const width = Math.max(140, leaves * 140)
473
794
  // Reverse the postorder leaf allocation to preserve catalog order.
474
795
  for (const position of positions.values()) position.x = width - position.x
475
796
  return { rows: rows.map(row => positions.get(row.id)), edges, positions, more, width,
476
- height: Math.max(140, ...rows.map(row => row.level * 128)) }
797
+ height: Math.max(140, ...rows.map(row => row.level * agentTreeLevelSpacing)) }
477
798
  }
478
799
 
479
800
  function agentExecutionStatus(node, isRoot, t = key => zh[key] || key) {
@@ -482,7 +803,7 @@ function agentExecutionStatus(node, isRoot, t = key => zh[key] || key) {
482
803
  return isRoot || node.mode === 'continuable' ? { tone: 'idle', label: text(t, 'tree.legend.idle') } : { tone: 'stopped', label: text(t, 'tree.legend.stopped') }
483
804
  }
484
805
 
485
- function AgentTreeBody({ state, view, saved, openDetail, refresh, watchCatalog, t = key => zh[key] || key }) {
806
+ function AgentTreeBody({ state, view, saved, openDetail, refresh, watchCatalog, onToggle, t = key => zh[key] || key }) {
486
807
  const [pan, setPan] = useState(saved.pan || { x: 0, y: 0 })
487
808
  const [zoom, setZoom] = useState(saved.zoom || 1)
488
809
  const viewport = useRef(null), graph = useRef(null)
@@ -521,9 +842,9 @@ function AgentTreeBody({ state, view, saved, openDetail, refresh, watchCatalog,
521
842
  const [focused, setFocused] = useState(saved.focused)
522
843
  const [expanded, setExpanded] = useState(saved.expanded || new Set())
523
844
  const [collapsed, setCollapsed] = useState(saved.collapsed || new Set())
524
- const [historyOpen, setHistoryOpen] = useState(false)
845
+ const [historyOpen, setHistoryOpen] = useState(saved.historyOpen || false)
525
846
  const [compact, setCompact] = useState(false)
526
- useEffect(() => { Object.assign(saved, { limit, focused, expanded, collapsed }) }, [saved, limit, focused, expanded, collapsed])
847
+ useEffect(() => { Object.assign(saved, { limit, focused, expanded, collapsed, historyOpen }) }, [saved, limit, focused, expanded, collapsed, historyOpen])
527
848
  const catalogs = state.subagentsByParent || {}
528
849
  const display = useMemo(() => agentTreeDisplay(view, catalogs, { expanded, collapsed, focused, compact }), [view, catalogs, expanded, collapsed, focused, compact])
529
850
  const { rows, more, edges, positions, width, height } = useMemo(() => agentTreeLayout(display.view, limit), [display, limit])
@@ -597,24 +918,28 @@ function AgentTreeBody({ state, view, saved, openDetail, refresh, watchCatalog,
597
918
  return React.createElement('section', { className: 'dsh-super-code-tree', 'data-super-agent-tree': true },
598
919
  watched.map(id => React.createElement(AgentCatalogWatch, { key: id, id, watchCatalog })),
599
920
  React.createElement('header', { className: 'dsh-super-code-tree-header' },
600
- React.createElement('div', null,
601
- React.createElement('strong', null, text(t, 'tree.title')),
602
- React.createElement('span', { className: 'dsh-super-code-tree-count' }, text(t, 'tree.count', { shown: rows.length, total: view.nodes.size, running }))),
603
- React.createElement('button', { type: 'button', className: 'dsh-super-code-icon-button', disabled: busy || !view.root, onClick: reload, title: text(t, 'tree.refresh'), 'aria-label': text(t, 'tree.refresh') }, React.createElement(IconRefreshOutline16))),
921
+ React.createElement('div', { className: 'dsh-super-code-tree-heading' },
922
+ onToggle ? React.createElement(WorkspaceSectionToggle, { section: 'tree', expanded: true, onToggle, t },
923
+ React.createElement('span', { className: 'dsh-super-code-tree-count' }, text(t, 'tree.countCompact', { shown: rows.length, total: view.nodes.size, running })))
924
+ : React.createElement(React.Fragment, null,
925
+ React.createElement('div', { className: 'dsh-super-code-title-line' }, React.createElement(Glyph, { type: 'branch' }), React.createElement('strong', null, text(t, 'tree.title'))),
926
+ React.createElement('span', { className: 'dsh-super-code-tree-count', title: text(t, 'tree.count', { shown: rows.length, total: view.nodes.size, running }) }, text(t, 'tree.countCompact', { shown: rows.length, total: view.nodes.size, running })))),
927
+ React.createElement('div', { className: 'dsh-super-code-tree-toolbar' },
928
+ React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-icon-button', disabled: busy || !view.root, onClick: reload, title: text(t, 'tree.refresh'), 'aria-label': text(t, 'tree.refresh') }, React.createElement(IconRefreshOutline16)),
929
+ React.createElement('div', { className: 'dsh-super-code-graph-controls', 'aria-label': text(t, 'tree.canvas') },
930
+ React.createElement(ActionButton, { type: 'button', title: text(t, 'tree.zoom.out'), 'aria-label': text(t, 'tree.zoom.out'), disabled: zoom <= .4, onClick: () => zoomButton(1 / 1.2) }, '−'),
931
+ React.createElement('span', { 'aria-live': 'polite' }, `${Math.round(zoom * 100)}%`),
932
+ React.createElement(ActionButton, { type: 'button', title: text(t, 'tree.zoom.in'), 'aria-label': text(t, 'tree.zoom.in'), disabled: zoom >= 2, onClick: () => zoomButton(1.2) }, '+')),
933
+ React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-icon-button', title: text(t, 'tree.fit'), 'aria-label': text(t, 'tree.fit'), onClick: fit }, React.createElement(Glyph, { type: 'fit' })),
934
+ (display.hidden.length > 0 || expanded.size > 0 || collapsed.size > 0) && React.createElement('div', { className: 'dsh-super-code-history-controls' },
935
+ React.createElement(ActionButton, { type: 'button', title: text(t, 'tree.collapsed', { count: display.hidden.length }), 'aria-label': text(t, 'tree.collapsed', { count: display.hidden.length }), 'aria-expanded': historyOpen, onClick: () => setHistoryOpen(!historyOpen) }, React.createElement(Glyph, { type: 'history' }), React.createElement('span', { className: 'dsh-super-code-action-label' }, text(t, 'tree.collapsedLabel')), React.createElement('span', { className: 'dsh-super-code-action-count' }, display.hidden.length)),
936
+ (expanded.size > 0 || collapsed.size > 0) && React.createElement(ActionButton, { type: 'button', title: text(t, 'tree.organize'), 'aria-label': text(t, 'tree.organize'), onClick: () => { autoFit.current = true; setExpanded(new Set()); setCollapsed(new Set()); setHistoryOpen(false); setFocused(state.current) } }, React.createElement(Glyph, { type: 'organize' }), React.createElement('span', { className: 'dsh-super-code-action-label' }, text(t, 'tree.organizeLabel'))))),
937
+ React.createElement('div', { className: 'dsh-super-code-graph-legend', 'aria-label': text(t, 'tree.status') },
938
+ ['tree.legend.active', 'tree.legend.idle', 'tree.legend.stopped', 'tree.legend.unavailable'].map((key, index) => React.createElement('span', { key },
939
+ React.createElement('i', { className: 'dsh-super-code-circle ' + ['active', 'idle', 'stopped', 'unavailable'][index], 'aria-hidden': true }), text(t, key))))),
604
940
  (error || catalogError) && React.createElement('p', { role: 'alert', className: 'dsh-super-code-tree-error' }, text(t, error || 'tree.loadError')),
605
- React.createElement('div', { className: 'dsh-super-code-graph-legend', 'aria-label': text(t, 'tree.status') },
606
- ['tree.legend.active', 'tree.legend.idle', 'tree.legend.stopped', 'tree.legend.unavailable'].map((key, index) => React.createElement('span', { key },
607
- React.createElement('i', { className: 'dsh-super-code-circle ' + ['active', 'idle', 'stopped', 'unavailable'][index], 'aria-hidden': true }), text(t, key)))),
608
941
  !view.root && React.createElement('p', { className: 'dsh-super-code-tree-empty' }, text(t, 'tree.empty')),
609
- React.createElement('div', { className: 'dsh-super-code-graph-controls', 'aria-label': text(t, 'tree.canvas') },
610
- React.createElement('button', { type: 'button', 'aria-label': text(t, 'tree.zoom.out'), disabled: zoom <= .4, onClick: () => zoomButton(1 / 1.2) }, '−'),
611
- React.createElement('span', { 'aria-live': 'polite' }, `${Math.round(zoom * 100)}%`),
612
- React.createElement('button', { type: 'button', 'aria-label': text(t, 'tree.zoom.in'), disabled: zoom >= 2, onClick: () => zoomButton(1.2) }, '+'),
613
- React.createElement('button', { type: 'button', onClick: fit }, text(t, 'tree.fit'))),
614
- (display.hidden.length > 0 || expanded.size > 0 || collapsed.size > 0) && React.createElement('div', { className: 'dsh-super-code-history-controls' },
615
- React.createElement('button', { type: 'button', 'aria-expanded': historyOpen, onClick: () => setHistoryOpen(!historyOpen) }, text(t, 'tree.collapsed', { count: display.hidden.length })),
616
- (expanded.size > 0 || collapsed.size > 0) && React.createElement('button', { type: 'button', onClick: () => { autoFit.current = true; setExpanded(new Set()); setCollapsed(new Set()); setFocused(state.current) } }, text(t, 'tree.organize'))),
617
- historyOpen && React.createElement(AgentHistory, { view, hidden: display.hidden, totals, open, t }),
942
+ historyOpen && React.createElement(AgentHistory, { view, hidden: display.hidden, totals, open, saved, t }),
618
943
  React.createElement('div', { ref: viewport, className: 'dsh-super-code-graph-scroll',
619
944
  onPointerDown: event => {
620
945
  if (!event.isPrimary || event.button !== 0) return
@@ -639,7 +964,7 @@ function AgentTreeBody({ state, view, saved, openDetail, refresh, watchCatalog,
639
964
  React.createElement('div', { ref: graph, role: 'tree', 'aria-label': text(t, 'tree.aria'), className: 'dsh-super-code-graph', style: { width, height, transform: `translate(${pan.x}px, ${pan.y}px) scale(${zoom})` } },
640
965
  React.createElement('svg', { width, height, className: 'dsh-super-code-graph-edges', 'aria-hidden': true }, edges.map(edge => {
641
966
  const parent = positions.get(edge.parent), child = positions.get(edge.child)
642
- return React.createElement('path', { key: edge.child, d: `M ${parent.x} ${parent.y + 105} V ${child.y - 12} H ${child.x} V ${child.y}`, fill: 'none' })
967
+ return React.createElement('path', { key: edge.child, d: `M ${parent.x} ${parent.y + agentTreeNodeHeight} V ${child.y - 16} H ${child.x} V ${child.y - 10}`, fill: 'none' })
643
968
  })),
644
969
  rows.map(row => {
645
970
  const node = view.nodes.get(row.id)
@@ -650,7 +975,7 @@ function AgentTreeBody({ state, view, saved, openDetail, refresh, watchCatalog,
650
975
  const number = value => value.toLocaleString(localeCode(t), { notation: 'compact', maximumFractionDigits: 1 })
651
976
  const hasChildren = (view.children.get(row.id) || []).length > 0
652
977
  const isExpanded = (display.view.children.get(row.id) || []).length > 0
653
- return React.createElement(React.Fragment, { key: row.id }, React.createElement('button', {
978
+ return React.createElement(React.Fragment, { key: row.id }, React.createElement(ActionButton, {
654
979
  type: 'button',
655
980
  role: 'treeitem', tabIndex: row.id === focusId ? 0 : -1, 'data-agent-id': row.id,
656
981
  'aria-level': row.level, 'aria-selected': row.id === state.current,
@@ -664,16 +989,17 @@ function AgentTreeBody({ state, view, saved, openDetail, refresh, watchCatalog,
664
989
  React.createElement('span', { className: 'dsh-super-code-circle ' + tone, 'aria-hidden': true }, row.id === view.root ? text(t, 'main.agent').slice(0, 1) : String(rows.findIndex(item => item.id === row.id))),
665
990
  React.createElement('span', { className: 'dsh-super-code-tree-content' },
666
991
  React.createElement('span', { className: 'dsh-super-code-tree-title' }, title),
992
+ React.createElement('span', { className: 'dsh-super-code-node-status', 'data-tone': tone }, React.createElement('i', { 'aria-hidden': true }), status),
667
993
  React.createElement('span', { className: 'dsh-super-code-tree-usage', title: text(t, 'tree.usage', { partial: partial ? text(t, 'usage.incomplete') : '', tokens: usage.tokens.toLocaleString(localeCode(t)), cache: usage.cache.toLocaleString(localeCode(t)), agents: usage.agents }) },
668
994
  React.createElement('span', null, usage.known ? `${number(usage.tokens)} token` : text(t, 'usage.unknown')),
669
995
  React.createElement('span', null, usage.known ? text(t, 'usage.cache', { value: usage.input ? Math.round(usage.cache / usage.input * 100) : 0 }) + (partial ? ` · ${text(t, 'usage.partial')}` : '') : text(t, 'usage.cacheUnknown'))))),
670
- hasChildren && React.createElement('button', { type: 'button', className: 'dsh-super-code-branch-toggle',
996
+ hasChildren && React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-branch-toggle',
671
997
  style: { left: row.x + 21, top: row.y + 25 }, 'aria-label': `${collapsed.has(row.id) || !isExpanded ? text(t, 'tree.expand') : text(t, 'tree.collapse')} ${title}`,
672
998
  title: text(t, 'tree.organize'), onClick: () => toggleBranch(row.id) },
673
999
  React.createElement('svg', { width: 12, height: 12, viewBox: '0 0 12 12', 'aria-hidden': true, style: { transform: collapsed.has(row.id) || !isExpanded ? 'rotate(-90deg)' : undefined } },
674
1000
  React.createElement('path', { d: 'M3 4.5 6 7.5 9 4.5', fill: 'none', stroke: 'currentColor', strokeWidth: 1.5 }))))
675
1001
  }))),
676
- more && React.createElement('button', { type: 'button', className: 'dsh-super-code-tree-more', onClick: () => setLimit(limit + 200) }, text(t, 'tree.more')))
1002
+ more && React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-tree-more', onClick: () => setLimit(limit + 200) }, text(t, 'tree.more')))
677
1003
  }
678
1004
 
679
1005
  function agentDetailAddress(node) {
@@ -723,6 +1049,23 @@ function detailRecord(entry, t = key => zh[key] || key) {
723
1049
  return { ...base, kind: 'message', label: text(t, 'detail.task'), text: contentText(data.content, t) }
724
1050
  }
725
1051
  if (event.type === 'assistant/message') return { ...base, kind: 'message', label: data.interrupted ? text(t, 'detail.interrupted') : text(t, 'detail.agent'), text: contentText(data.message?.content, t) }
1052
+ if (event.type === 'tool/call' && typeof data.name === 'string' && data.name) {
1053
+ let value = typeof data.arguments === 'string' ? data.arguments : JSON.stringify(data.arguments ?? {})
1054
+ try { value = JSON.stringify(JSON.parse(value), null, 2) } catch { /* Incomplete arguments remain readable. */ }
1055
+ return { ...base, kind: 'tool', collapsed: true, toolName: data.name, callId: data.callId,
1056
+ label: text(t, 'detail.toolCall') + ' · ' + data.name, text: value }
1057
+ }
1058
+ if (event.type === 'tool/result') {
1059
+ const blocks = (data.message?.content || []).filter(block => block.type === 'tool-result')
1060
+ // Older journals store a direct tool message; newer ones nest its content.
1061
+ const direct = data.message?.role === 'tool'
1062
+ if (!blocks.length && !direct) return { kind: 'skip' }
1063
+ const failed = direct ? data.message.isError : blocks.some(block => block.isError)
1064
+ return { ...base, kind: failed ? 'error' : 'tool', collapsed: true,
1065
+ callId: direct ? data.message.toolCallId : blocks[0]?.toolCallId,
1066
+ label: text(t, failed ? 'detail.toolError' : 'detail.toolResult'),
1067
+ text: contentText(direct ? data.message.content : blocks.flatMap(block => block.content || []), t) }
1068
+ }
726
1069
  if (event.type === 'turn/error') return { ...base, kind: 'error', label: text(t, 'detail.error'), text: data.message || text(t, 'detail.incomplete') }
727
1070
  return { kind: 'skip' }
728
1071
  }
@@ -798,21 +1141,20 @@ function DetailText({ text: value, t = key => zh[key] || key }) {
798
1141
  const [full, setFull] = useState(false)
799
1142
  return React.createElement(React.Fragment, null,
800
1143
  React.createElement('pre', null, full ? value : value.slice(0, 12000)),
801
- !full && value.length > 12000 && React.createElement('button', { type: 'button', onClick: () => setFull(true) }, text(t, 'detail.open')))
1144
+ !full && value.length > 12000 && React.createElement(ActionButton, { type: 'button', onClick: () => setFull(true) }, text(t, 'detail.open')))
802
1145
  }
803
1146
 
804
1147
  function MemoryActivity({ usage, openMemory, sessionId, t }) {
805
1148
  const rows = [...(usage?.rows || [])].reverse()
806
1149
  return React.createElement('details', { className: 'dsh-super-code-memory-activity' },
807
1150
  React.createElement('summary', null, text(t, 'memory.agentUsage'), rows.length ? ` · ${rows.length}` : ''),
808
- React.createElement('p', { className: 'dsh-super-code-memory-muted' }, text(t, 'memory.usageHint')),
809
1151
  !rows.length && React.createElement('p', null, text(t, 'memory.usageEmpty')),
810
1152
  React.createElement('div', { className: 'dsh-super-code-memory-activity-list' }, rows.map(row =>
811
- React.createElement('button', { key: `${row.scope}/${row.topic}/${row.id}/${row.action}`, type: 'button',
1153
+ React.createElement(ActionButton, { key: `${row.scope}/${row.topic}/${row.id}/${row.action}`, type: 'button',
812
1154
  onClick: () => openMemory(sessionId, row), title: text(t, 'memory.open') },
813
1155
  React.createElement('span', { className: 'dsh-super-code-memory-action', 'data-action': row.action }, text(t, `memory.${row.action}`)),
814
1156
  React.createElement('span', null, row.summary || row.id),
815
- React.createElement('small', null, `${text(t, `memory.${row.scope}`)} · ${row.topic} · r${row.revision}`)))),
1157
+ React.createElement('small', null, `${text(t, `memory.${row.scope}`)} · ${row.topic}`)))),
816
1158
  usage?.omitted > 0 && React.createElement('p', { className: 'dsh-super-code-memory-muted' }, text(t, 'memory.omitted')))
817
1159
  }
818
1160
 
@@ -833,6 +1175,18 @@ function memoryLibraryTarget(address, current) {
833
1175
  return { sessionId: current, scope: 'project', topic: '', id: '' }
834
1176
  }
835
1177
 
1178
+ /** A repeated explicit navigation reopens its entry; ordinary remounts retain reading state. */
1179
+ function memoryLibraryNavigation(saved, tab, current) {
1180
+ const address = typeof tab.navigation?.params?.memory === 'string' ? tab.navigation.params.memory : tab.contentId
1181
+ const navigationKey = `${address}/${tab.navigation?.revision || 0}`
1182
+ if (saved.navigationKey === navigationKey) return saved
1183
+ const target = memoryLibraryTarget(address, current)
1184
+ return { ...saved, navigationKey, ...(target.id ? {
1185
+ scope: target.scope, selected: { topic: target.topic, id: target.id }, detailTop: 0,
1186
+ ...(saved.scope && saved.scope !== target.scope ? { topicFilter: '', top: 0 } : {}),
1187
+ } : {}) }
1188
+ }
1189
+
836
1190
  /** A fixed-height index keeps large libraries cheap; entry bodies load on click. */
837
1191
  function memoryLibraryWindow(items, query, top, height) {
838
1192
  const search = query.trim().toLocaleLowerCase()
@@ -842,22 +1196,119 @@ function memoryLibraryWindow(items, query, top, height) {
842
1196
  return { rows: matches.slice(start, end), count: matches.length, before: start * 76, after: (matches.length - end) * 76 }
843
1197
  }
844
1198
 
845
- function MemoryLibrary({ useTabInfo, useSessions, sessionId: scopeSessionId, api, memoryStates, t = key => zh[key] || key }) {
1199
+ /** Drafts and in-flight operations survive the host unmounting a hidden tab. */
1200
+ function createMemoryEditor(saved, api) {
1201
+ if (saved.editorStore) return saved.editorStore
1202
+ let snapshot = { draft: null, confirmation: null, busy: false, error: '', refresh: 0 }
1203
+ const listeners = new Set()
1204
+ const update = patch => { snapshot = { ...snapshot, ...patch }; for (const listener of listeners) listener() }
1205
+ const run = async (method, target) => {
1206
+ if (snapshot.busy) return { kind: 'busy' }
1207
+ update({ busy: true, error: '' })
1208
+ try {
1209
+ const response = method === 'save' ? await api.saveEntry(target.sessionId, target.scope, target.topic, target.id, JSON.stringify({
1210
+ expected: target.expected, kind: target.kind, summary: target.summary.trim(), detail: target.detail.trim(),
1211
+ })) : await api.deleteEntry(target.sessionId, target.scope, target.topic, target.id, target.expected)
1212
+ if (!response.ok) throw new Error('Remote unavailable')
1213
+ const result = response.value
1214
+ if (!['saved', 'removed'].includes(result.kind)) {
1215
+ update({ busy: false, error: { conflict: 'memory.conflict', missing: 'memory.missingEdit', full: 'memory.full' }[result.kind] || 'memory.writeError' })
1216
+ return result
1217
+ }
1218
+ saved.scope = target.scope
1219
+ saved.selected = result.kind === 'saved' ? { topic: target.topic, id: target.id } : null
1220
+ saved.detailTop = 0
1221
+ update({ draft: null, confirmation: null, busy: false, error: '', refresh: snapshot.refresh + 1 })
1222
+ return result
1223
+ } catch {
1224
+ update({ busy: false, error: 'memory.writeError' })
1225
+ return { kind: 'error' }
1226
+ }
1227
+ }
1228
+ saved.editorStore = { getSnapshot: () => snapshot, subscribe: listener => { listeners.add(listener); return () => listeners.delete(listener) },
1229
+ update, save: () => run('save', snapshot.draft), remove: () => run('remove', snapshot.confirmation) }
1230
+ return saved.editorStore
1231
+ }
1232
+
1233
+ function MemoryEditor({ store, state, t }) {
1234
+ const draft = state.draft
1235
+ const set = (key, value) => store.update({ draft: { ...draft, [key]: value }, error: '' })
1236
+ return React.createElement('form', { className: 'dsh-super-code-memory-editor', 'aria-label': text(t, draft.expected ? 'memory.edit' : 'memory.add'),
1237
+ onSubmit: event => { event.preventDefault(); void store.save() } },
1238
+ React.createElement('div', { className: 'dsh-super-code-memory-editor-heading' },
1239
+ React.createElement('strong', null, text(t, draft.expected ? 'memory.edit' : 'memory.add')),
1240
+ React.createElement('small', null, text(t, `memory.${draft.scope}`))),
1241
+ React.createElement('label', null, text(t, 'memory.topic'),
1242
+ React.createElement('input', { value: draft.topic, 'aria-label': text(t, 'memory.topic'), required: true, maxLength: 96,
1243
+ disabled: state.busy || Boolean(draft.expected) || draft.scope === 'global', onChange: event => set('topic', event.target.value) }),
1244
+ !draft.expected && draft.scope !== 'global' && React.createElement('small', null, text(t, 'memory.topicHint'))),
1245
+ React.createElement(SelectControl, { label: text(t, 'memory.kind'), value: draft.kind, disabled: state.busy || draft.scope === 'global',
1246
+ choices: ['constraint', 'fact', 'experience'].map(kind => [kind, text(t, `memory.${kind}`)]), onChange: kind => set('kind', kind) }),
1247
+ React.createElement('label', null, text(t, 'memory.summaryLabel'), React.createElement('small', null, `${Array.from(draft.summary).length}/30`),
1248
+ React.createElement('input', { value: draft.summary, 'aria-label': text(t, 'memory.summaryLabel'), required: true, disabled: state.busy, onChange: event => set('summary', event.target.value) })),
1249
+ React.createElement('label', null, text(t, 'memory.detailLabel'), React.createElement('small', null, `${draft.detail.length}/1000`),
1250
+ React.createElement('textarea', { value: draft.detail, 'aria-label': text(t, 'memory.detailLabel'), required: true, maxLength: 1000, rows: 5, disabled: state.busy, onChange: event => set('detail', event.target.value) })),
1251
+ state.error && React.createElement('p', { role: 'alert' }, text(t, state.error)),
1252
+ React.createElement('div', { className: 'dsh-super-code-memory-actions' },
1253
+ React.createElement(ActionButton, { type: 'button', disabled: state.busy, onClick: () => store.update({ draft: null, error: '' }) }, text(t, 'memory.cancel')),
1254
+ React.createElement(ActionButton, { type: 'submit', className: 'dsh-super-code-memory-primary', disabled: state.busy || !/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,95}$/.test(draft.topic) || !draft.summary.trim() || Array.from(draft.summary.trim()).length > 30 || !draft.detail.trim() }, text(t, state.busy ? 'memory.saving' : 'memory.save'))))
1255
+ }
1256
+
1257
+ function MemoryDeleteConfirmation({ store, state, t }) {
1258
+ const dialog = useRef(null), target = state.confirmation
1259
+ useLayoutEffect(() => {
1260
+ dialog.current.showModal()
1261
+ return () => { if (dialog.current?.open) dialog.current.close() }
1262
+ }, [])
1263
+ const cancel = () => { if (!store.getSnapshot().busy) store.update({ confirmation: null, error: '' }) }
1264
+ return React.createElement('dialog', { ref: dialog, className: 'dsh-super-code-confirm', 'aria-label': text(t, 'memory.deleteTitle'),
1265
+ onCancel: event => { event.preventDefault(); cancel() }, onKeyDown: event => {
1266
+ if (event.key === 'Escape') { event.preventDefault(); event.stopPropagation(); cancel() }
1267
+ } },
1268
+ React.createElement('h3', null, text(t, 'memory.deleteTitle')),
1269
+ React.createElement('p', null, text(t, 'memory.deleteHint', { summary: target.summary })),
1270
+ state.error && React.createElement('p', { role: 'alert' }, text(t, state.error)),
1271
+ React.createElement('div', { className: 'dsh-super-code-confirm-actions' },
1272
+ React.createElement(ActionButton, { type: 'button', disabled: state.busy, onClick: cancel }, text(t, 'memory.cancel')),
1273
+ React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-memory-danger', disabled: state.busy, onClick: () => { void store.remove() } }, text(t, state.busy ? 'memory.deleting' : 'memory.delete'))))
1274
+ }
1275
+
1276
+ function MemoryLibrary({ useTabInfo, useSessions, sessionId: scopeSessionId, api, memoryStates, onToggle, t = key => zh[key] || key }) {
846
1277
  const { tab } = useTabInfo(), current = useSessions(state => scopeSessionId || state.current)
847
- const target = memoryLibraryTarget(tab.contentId, current)
1278
+ const address = typeof tab.navigation?.params?.memory === 'string' ? tab.navigation.params.memory : tab.contentId
1279
+ const target = memoryLibraryTarget(address, current)
848
1280
  const saved = useMemo(() => {
849
- if (!memoryStates.has(tab.signal)) memoryStates.set(tab.signal, {})
850
- return memoryStates.get(tab.signal)
1281
+ const value = memoryStates.get(tab.signal) || {}
1282
+ Object.assign(value, memoryLibraryNavigation(value, tab, current))
1283
+ memoryStates.set(tab.signal, value)
1284
+ return value
851
1285
  }, [memoryStates, tab.signal])
1286
+ const editor = useMemo(() => createMemoryEditor(saved, api), [saved, api])
1287
+ const editing = useSyncExternalStore(editor.subscribe, editor.getSnapshot, editor.getSnapshot)
852
1288
  const [scope, setScope] = useState(saved.scope || target.scope)
853
1289
  const [query, setQuery] = useState(saved.query || '')
854
- const [selected, setSelected] = useState(saved.selected || (target.id ? { topic: target.topic, id: target.id } : null))
1290
+ const [topicFilter, setTopicFilter] = useState(saved.topicFilter || '')
1291
+ const [selected, setSelected] = useState(saved.selected || null)
855
1292
  const [state, setState] = useState({ key: '', items: [], loading: true, error: false })
856
1293
  const [detail, setDetail] = useState(null), [revision, setRevision] = useState(0)
857
1294
  const [viewport, setViewport] = useState({ top: saved.top || 0, height: 600 })
858
- const list = useRef(null), sessionId = target.sessionId
1295
+ const list = useRef(null), detailBody = useRef(null), sessionId = editing.draft?.sessionId || editing.confirmation?.sessionId || target.sessionId
859
1296
  const key = `${sessionId}/${scope}`, selectionKey = selected ? `${key}/${selected.topic}/${selected.id}` : ''
860
1297
  const visibleState = state.key === key ? state : { items: [], loading: true, error: false }
1298
+ useLayoutEffect(() => {
1299
+ if (editing.draft || editing.confirmation || editing.busy) return
1300
+ const next = memoryLibraryNavigation(saved, tab, current)
1301
+ if (next === saved) return
1302
+ Object.assign(saved, next)
1303
+ setScope(saved.scope || target.scope); setSelected(saved.selected || null)
1304
+ setTopicFilter(saved.topicFilter || '')
1305
+ setViewport(value => ({ ...value, top: saved.top || 0 }))
1306
+ if (detailBody.current) detailBody.current.scrollTop = 0
1307
+ }, [saved, address, tab.navigation?.revision, editing.draft, editing.confirmation, editing.busy])
1308
+ useLayoutEffect(() => {
1309
+ if (!editing.refresh) return
1310
+ setScope(saved.scope); setSelected(saved.selected); setRevision(value => value + 1)
1311
+ }, [editing.refresh])
861
1312
  useEffect(() => {
862
1313
  if (!tab.visible || !sessionId) return
863
1314
  let cancelled = false
@@ -884,40 +1335,80 @@ function MemoryLibrary({ useTabInfo, useSessions, sessionId: scopeSessionId, api
884
1335
  resize()
885
1336
  const observer = new ResizeObserver(resize); observer.observe(element)
886
1337
  return () => observer.disconnect()
887
- }, [selected, key, tab.visible])
1338
+ }, [selected, key, tab.visible, Boolean(editing.draft)])
1339
+ useLayoutEffect(() => {
1340
+ if (detailBody.current) detailBody.current.scrollTop = saved.detailTop || 0
1341
+ }, [selectionKey, detail?.key, tab.visible, Boolean(editing.draft)])
888
1342
  const resetScroll = () => { saved.top = 0; if (list.current) list.current.scrollTop = 0; setViewport(value => ({ ...value, top: 0 })) }
889
- const choose = value => { saved.selected = value; setSelected(value) }
890
- const page = useMemo(() => memoryLibraryWindow(visibleState.items, query, viewport.top, viewport.height), [visibleState.items, query, viewport])
1343
+ const choose = value => { saved.detailTop = 0; if (detailBody.current) detailBody.current.scrollTop = 0; saved.selected = value; setSelected(value) }
1344
+ const changeTopic = value => { saved.topicFilter = value; setTopicFilter(value); resetScroll() }
1345
+ const topics = useMemo(() => {
1346
+ const counts = new Map()
1347
+ for (const item of visibleState.items) counts.set(item.topic, (counts.get(item.topic) || 0) + 1)
1348
+ return [...counts].map(([topic, count]) => ({ topic, count })).sort((a, b) => a.topic.localeCompare(b.topic, localeCode(t)))
1349
+ }, [visibleState.items, t])
1350
+ const topicItems = useMemo(() => topicFilter ? visibleState.items.filter(item => item.topic === topicFilter) : visibleState.items, [visibleState.items, topicFilter])
1351
+ const page = useMemo(() => memoryLibraryWindow(topicItems, query, viewport.top, viewport.height), [topicItems, query, viewport])
891
1352
  const currentDetail = detail?.key === selectionKey ? detail : null
892
1353
  const entry = currentDetail?.kind === 'found' ? currentDetail.entry : null
1354
+ const related = entry ? visibleState.items.filter(item => item.topic === entry.topic && item.id !== entry.id).slice(0, 5) : []
893
1355
  return React.createElement('section', { className: 'dsh-super-code-memory', 'aria-label': text(t, 'memory.title') },
894
1356
  React.createElement('header', null,
895
- React.createElement('div', { className: 'dsh-super-code-memory-heading' }, React.createElement('h2', null, text(t, 'memory.title')),
896
- React.createElement('button', { type: 'button', className: 'dsh-super-code-icon-button', title: text(t, 'memory.refresh'), 'aria-label': text(t, 'memory.refresh'), onClick: () => setRevision(value => value + 1) }, React.createElement(IconRefreshOutline16))),
897
- React.createElement('p', { className: 'dsh-super-code-memory-muted' }, text(t, 'memory.description')),
1357
+ React.createElement('div', { className: 'dsh-super-code-memory-heading' },
1358
+ onToggle ? React.createElement(WorkspaceSectionToggle, { section: 'memory', expanded: true, onToggle, t })
1359
+ : React.createElement('div', { className: 'dsh-super-code-title-line' }, React.createElement(Glyph, { type: 'memory' }), React.createElement('h2', null, text(t, 'memory.title'))),
1360
+ React.createElement('div', { className: 'dsh-super-code-memory-header-actions' },
1361
+ React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-view-button', 'aria-label': text(t, 'memory.add'), disabled: !sessionId || editing.busy || Boolean(editing.draft), onClick: () => editor.update({ error: '', draft: {
1362
+ sessionId, scope, topic: scope === 'global' ? 'preferences' : topicFilter || 'notes', id: window.crypto.randomUUID(), expected: '', kind: 'constraint', summary: '', detail: '',
1363
+ } }) }, `+ ${text(t, 'memory.add')}`),
1364
+ React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-icon-button', title: text(t, 'memory.refresh'), 'aria-label': text(t, 'memory.refresh'), disabled: editing.busy || Boolean(editing.draft), onClick: () => { editor.update({ error: '' }); setRevision(value => value + 1) } }, React.createElement(IconRefreshOutline16)))),
898
1365
  React.createElement('div', { className: 'dsh-super-code-memory-scopes', role: 'group', 'aria-label': text(t, 'memory.title') },
899
- ['project', 'global'].map(value => React.createElement('button', { key: value, type: 'button', 'aria-pressed': scope === value, onClick: () => { saved.scope = value; setScope(value); choose(null); resetScroll() } }, text(t, `memory.${value}`)))),
900
- !selected && React.createElement('input', { type: 'search', 'aria-label': text(t, 'memory.search'), placeholder: text(t, 'memory.search'), value: query, onChange: event => { saved.query = event.target.value; setQuery(event.target.value); resetScroll() } }),
901
- !selected && React.createElement('small', null, text(t, 'memory.count', { count: page.count }))),
902
- !sessionId ? React.createElement('p', { className: 'dsh-super-code-memory-empty' }, text(t, 'memory.selectSession')) : selected
903
- ? React.createElement('div', { className: 'dsh-super-code-memory-body', 'aria-busy': !currentDetail },
904
- React.createElement('button', { type: 'button', className: 'dsh-super-code-view-button', onClick: () => choose(null) }, `← ${text(t, 'memory.back')}`),
1366
+ ['project', 'global'].map(value => React.createElement(ActionButton, { key: value, type: 'button', 'aria-pressed': scope === value, disabled: editing.busy || Boolean(editing.draft), onClick: () => {
1367
+ saved.scope = value; setScope(value); changeTopic(''); choose(null)
1368
+ } }, text(t, `memory.${value}`)))),
1369
+ !selected && !editing.draft && React.createElement('div', { className: 'dsh-super-code-memory-search' }, React.createElement(Glyph, { type: 'search' }),
1370
+ React.createElement('input', { type: 'search', 'aria-label': text(t, 'memory.search'), placeholder: text(t, 'memory.search'), value: query, onChange: event => { saved.query = event.target.value; setQuery(event.target.value); resetScroll() } }))),
1371
+ !sessionId ? React.createElement('p', { className: 'dsh-super-code-memory-empty' }, text(t, 'memory.selectSession')) : editing.draft ? React.createElement(MemoryEditor, { store: editor, state: editing, t }) : selected
1372
+ ? React.createElement('div', { ref: detailBody, className: 'dsh-super-code-memory-body', 'aria-busy': !currentDetail, onScroll: event => { saved.detailTop = event.currentTarget.scrollTop } },
1373
+ React.createElement('div', { className: 'dsh-super-code-memory-actions' },
1374
+ React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-view-button', onClick: () => choose(null) }, `← ${text(t, 'memory.back')}`),
1375
+ entry && React.createElement(React.Fragment, null,
1376
+ React.createElement(ActionButton, { type: 'button', onClick: () => editor.update({ error: '', draft: { sessionId, scope, topic: entry.topic, id: entry.id, expected: entry.token, kind: entry.kind, summary: entry.summary, detail: entry.detail } }) }, text(t, 'memory.edit')),
1377
+ React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-memory-danger', onClick: () => editor.update({ error: '', confirmation: { sessionId, scope, topic: entry.topic, id: entry.id, expected: entry.token, summary: entry.summary } }) }, text(t, 'memory.delete')))),
1378
+ !currentDetail && React.createElement('p', { role: 'status', className: 'dsh-super-code-memory-empty' }, text(t, 'memory.loading')),
905
1379
  currentDetail?.kind === 'error' && React.createElement('p', { role: 'alert' }, text(t, 'memory.error')),
906
1380
  currentDetail?.kind === 'missing' && React.createElement('p', null, text(t, 'memory.missing')),
907
- entry && React.createElement('article', null, React.createElement('small', null, `${entry.topic} · r${entry.revision} · ${text(t, `memory.${entry.kind}`)}`),
1381
+ entry && React.createElement('article', { 'data-kind': entry.kind },
1382
+ React.createElement('div', { className: 'dsh-super-code-memory-detail-meta' },
1383
+ React.createElement('span', null, React.createElement(Glyph, { type: 'folder' }), entry.topic),
1384
+ React.createElement('span', null, text(t, `memory.${entry.kind}`))),
908
1385
  React.createElement('h3', null, entry.summary), React.createElement('p', { className: 'dsh-super-code-memory-detail' }, entry.detail),
909
- React.createElement('p', { className: 'dsh-super-code-memory-hint' }, text(t, 'memory.historical')),
910
1386
  React.createElement('dl', null, React.createElement('dt', null, text(t, 'memory.source')),
911
- React.createElement('dd', null, `${text(t, `memory.${entry.source.kind}`)} · #${entry.source.eventSeq}`, React.createElement('br'), entry.source.sessionId),
912
- entry.sourceVersion && React.createElement(React.Fragment, null, React.createElement('dt', null, text(t, 'memory.version')), React.createElement('dd', null, entry.sourceVersion)))))
913
- : React.createElement('div', { ref: list, className: 'dsh-super-code-memory-list', role: 'list', 'aria-busy': visibleState.loading, onScroll: event => { saved.top = event.currentTarget.scrollTop; setViewport(value => ({ ...value, top: saved.top })) } },
914
- visibleState.error && React.createElement('p', { role: 'alert' }, text(t, 'memory.error')),
915
- !visibleState.error && !visibleState.loading && !page.count && React.createElement('p', { className: 'dsh-super-code-memory-empty' }, text(t, query ? 'memory.noMatches' : 'memory.empty')),
916
- React.createElement('div', { 'aria-hidden': true, style: { height: page.before } }),
917
- page.rows.map(item => React.createElement('div', { role: 'listitem', key: `${item.topic}/${item.id}` },
918
- React.createElement('button', { type: 'button', className: 'dsh-super-code-memory-row', onClick: () => choose({ topic: item.topic, id: item.id }) },
919
- React.createElement('strong', null, item.summary), React.createElement('span', null, `${item.topic} · ${text(t, `memory.${item.kind}`)}`)))),
920
- React.createElement('div', { 'aria-hidden': true, style: { height: page.after } })))
1387
+ React.createElement('dd', null, `${text(t, `memory.${entry.source.kind}`)}${entry.source.eventSeq === undefined ? '' : ` · #${entry.source.eventSeq}`}`, React.createElement('br'), entry.source.sessionId)),
1388
+ related.length > 0 && React.createElement('section', { className: 'dsh-super-code-memory-related' },
1389
+ React.createElement('h4', null, text(t, 'memory.related')),
1390
+ related.map(item => React.createElement(ActionButton, { key: item.id, type: 'button', onClick: () => choose({ topic: item.topic, id: item.id }) },
1391
+ React.createElement(Glyph, { type: 'memory' }), React.createElement('span', null, item.summary), React.createElement(Glyph, { type: 'arrow' }))))))
1392
+ : React.createElement('div', { className: 'dsh-super-code-memory-workspace' },
1393
+ React.createElement('nav', { className: 'dsh-super-code-memory-topic-index', 'aria-label': text(t, 'memory.topics') },
1394
+ React.createElement('div', { className: 'dsh-super-code-memory-topic-label' }, text(t, 'memory.topics'), React.createElement('span', null, topics.length)),
1395
+ React.createElement('div', { className: 'dsh-super-code-memory-topic-options' },
1396
+ [{ topic: '', count: visibleState.items.length }, ...topics].map(({ topic, count }) => React.createElement(ActionButton, { key: topic, type: 'button', title: topic || text(t, 'memory.allTopics'), 'data-topic': topic, 'aria-pressed': topicFilter === topic, onClick: () => changeTopic(topic) },
1397
+ React.createElement(Glyph, { type: topic ? 'folder' : 'memory' }), React.createElement('span', null, topic || text(t, 'memory.allTopics')), React.createElement('small', null, count))))),
1398
+ React.createElement('div', { className: 'dsh-super-code-memory-results' },
1399
+ React.createElement('div', { className: 'dsh-super-code-memory-list-heading' }, React.createElement('strong', null, topicFilter || text(t, 'memory.allTopics')), React.createElement('small', null, text(t, 'memory.count', { count: page.count }))),
1400
+ React.createElement('div', { ref: list, className: 'dsh-super-code-memory-list', role: 'list', 'aria-busy': visibleState.loading, onScroll: event => { saved.top = event.currentTarget.scrollTop; setViewport(value => ({ ...value, top: saved.top })) } },
1401
+ visibleState.loading && !visibleState.error && React.createElement('p', { role: 'status', className: 'dsh-super-code-memory-empty' }, text(t, 'memory.loading')),
1402
+ visibleState.error && React.createElement('p', { role: 'alert' }, text(t, 'memory.error')),
1403
+ !visibleState.error && !visibleState.loading && !page.count && React.createElement('p', { className: 'dsh-super-code-memory-empty' }, text(t, query || topicFilter ? 'memory.noMatches' : 'memory.empty')),
1404
+ React.createElement('div', { 'aria-hidden': true, style: { height: page.before } }),
1405
+ page.rows.map(item => React.createElement('div', { role: 'listitem', key: `${item.topic}/${item.id}` },
1406
+ React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-memory-row', 'data-topic': item.topic, 'data-kind': item.kind, onClick: () => choose({ topic: item.topic, id: item.id }) },
1407
+ React.createElement('span', { className: 'dsh-super-code-memory-row-heading' }, React.createElement(Glyph, { type: 'folder' }), React.createElement('span', { className: 'dsh-super-code-memory-row-topic' }, item.topic)),
1408
+ React.createElement('strong', null, item.summary),
1409
+ React.createElement('span', { className: 'dsh-super-code-memory-row-meta' }, React.createElement('span', { className: 'dsh-super-code-memory-row-kind' }, text(t, `memory.${item.kind}`)))))),
1410
+ React.createElement('div', { 'aria-hidden': true, style: { height: page.after } })))),
1411
+ editing.confirmation && React.createElement(MemoryDeleteConfirmation, { store: editor, state: editing, t }))
921
1412
  }
922
1413
 
923
1414
  function AgentDetail({ useTabInfo, useSessions, useSessionStatus, sessionId, createInspector, detailStates, openMemory, t = key => zh[key] || key }) {
@@ -970,6 +1461,7 @@ function AgentDetail({ useTabInfo, useSessions, useSessionStatus, sessionId, cre
970
1461
  const input = totals ? (totals.uncachedInputTokens || 0) + (totals.cacheReadTokens || 0) + (totals.cacheWriteTokens || 0) : 0
971
1462
  const format = value => value === undefined ? text(t, 'detail.unavailable') : value.toLocaleString(localeCode(t))
972
1463
  const tasks = projections.superCodeTasks
1464
+ const toolNames = new Map(snapshot.items.filter(item => item.toolName && item.callId).map(item => [item.callId, item.toolName]))
973
1465
  const task = tasks?.current?.kind === 'task' ? tasks.current : undefined
974
1466
  const title = node?.title || node?.displayTitle || text(t, 'detail.title')
975
1467
  const metrics = [
@@ -978,21 +1470,26 @@ function AgentDetail({ useTabInfo, useSessions, useSessionStatus, sessionId, cre
978
1470
  ]
979
1471
  return React.createElement('section', { className: 'dsh-super-code-detail', 'data-agent-detail': id },
980
1472
  React.createElement('header', { className: 'dsh-super-code-detail-header' },
981
- React.createElement('nav', { 'aria-label': text(t, 'detail.path') }, path.map((part, index) => React.createElement('span', { key: part.id }, index > 0 ? ' / ' : '', part.title))),
1473
+ path.length > 1 && React.createElement('nav', { 'aria-label': text(t, 'detail.path'), title: path.map(part => part.title).join(' / ') },
1474
+ path.slice(0, -1).map((part, index) => React.createElement('span', { key: part.id }, index > 0 ? ' / ' : '', part.title))),
982
1475
  React.createElement('div', { className: 'dsh-super-code-detail-heading' },
983
- React.createElement('div', null,
984
- React.createElement('h2', null, title),
985
- React.createElement('span', { className: 'dsh-super-code-detail-status' }, agentExecutionStatus(node, id === view.root, t).label)),
986
- React.createElement('button', { type: 'button', className: 'dsh-super-code-icon-button', title: text(t, 'detail.refresh'), 'aria-label': text(t, 'detail.refresh'), onClick: latest }, React.createElement(IconRefreshOutline16))),
987
- id !== view.root && task?.goal && task.goal !== title && React.createElement('p', { className: 'dsh-super-code-detail-task' }, task.goal),
988
- id === view.root && React.createElement(TaskMemoryPanel, { state: tasks, t }),
989
- React.createElement(MemoryActivity, { usage: projections.superCodeMemoryUsage, sessionId: id, openMemory, t }),
990
- React.createElement('dl', { className: 'dsh-super-code-detail-metrics' },
991
- React.createElement('div', null, React.createElement('dt', null, text(t, 'detail.total')), React.createElement('dd', null, format(totals ? input + (totals.outputTokens || 0) : undefined))),
992
- React.createElement('div', null, React.createElement('dt', null, text(t, 'detail.hitRate')), React.createElement('dd', null, totals ? (input ? Math.round((totals.cacheReadTokens || 0) / input * 100) : 0) + '%' : text(t, 'detail.unavailable')))),
993
- React.createElement('details', { className: 'dsh-super-code-usage-details', open: saved.open.has('usage'), onToggle: event => { if (event.currentTarget.open) saved.open.add('usage'); else saved.open.delete('usage') } },
994
- React.createElement('summary', null, text(t, 'detail.moreUsage')),
995
- React.createElement('dl', { className: 'dsh-super-code-detail-metrics' }, metrics.map(([label, value]) => React.createElement('div', { key: label }, React.createElement('dt', null, label), React.createElement('dd', null, format(value))))))),
1476
+ React.createElement('h2', { title }, title),
1477
+ React.createElement('span', { className: 'dsh-super-code-detail-status', 'data-tone': agentExecutionStatus(node, id === view.root, t).tone }, agentExecutionStatus(node, id === view.root, t).label),
1478
+ React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-icon-button', title: text(t, 'detail.refresh'), 'aria-label': text(t, 'detail.refresh'), onClick: latest }, React.createElement(IconRefreshOutline16))),
1479
+ React.createElement('details', { className: 'dsh-super-code-usage-details', open: saved.open.has('usage'), onToggle: event => {
1480
+ if (event.target !== event.currentTarget) return
1481
+ if (event.currentTarget.open) saved.open.add('usage'); else saved.open.delete('usage')
1482
+ } },
1483
+ React.createElement('summary', null,
1484
+ React.createElement('span', { className: 'dsh-super-code-detail-summary' },
1485
+ React.createElement('span', { title: text(t, 'detail.total') }, React.createElement('span', null, 'Token'), React.createElement('strong', null, format(totals ? input + (totals.outputTokens || 0) : undefined))),
1486
+ React.createElement('span', { title: text(t, 'detail.hitRate') }, React.createElement('span', null, text(t, 'detail.cache')), React.createElement('strong', null, totals ? (input ? Math.round((totals.cacheReadTokens || 0) / input * 100) : 0) + '%' : text(t, 'detail.unavailable')))),
1487
+ React.createElement('span', { className: 'dsh-super-code-detail-info-toggle' }, text(t, 'detail.info'), React.createElement(Glyph, { type: 'chevron' }))),
1488
+ React.createElement('div', { className: 'dsh-super-code-detail-info' },
1489
+ React.createElement('dl', { className: 'dsh-super-code-detail-metrics' }, metrics.map(([label, value]) => React.createElement('div', { key: label }, React.createElement('dt', null, label), React.createElement('dd', null, format(value))))),
1490
+ id !== view.root && task?.goal && task.goal !== title && React.createElement('p', { className: 'dsh-super-code-detail-task' }, task.goal),
1491
+ id === view.root && React.createElement(TaskMemoryPanel, { state: tasks, t }),
1492
+ React.createElement(MemoryActivity, { usage: projections.superCodeMemoryUsage, sessionId: id, openMemory, t })))),
996
1493
  React.createElement('div', { ref: log, className: 'dsh-super-code-detail-log', 'aria-label': text(t, 'tree.title'), onScroll: event => {
997
1494
  const element = event.currentTarget
998
1495
  saved.top = element.scrollTop
@@ -1001,21 +1498,11 @@ function AgentDetail({ useTabInfo, useSessions, useSessionStatus, sessionId, cre
1001
1498
  } },
1002
1499
  snapshot.error && React.createElement('p', { role: 'alert' }, text(t, snapshot.error)),
1003
1500
  snapshot.status === 'loading' && React.createElement('p', { role: 'status' }, text(t, 'detail.reading')),
1004
- snapshot.hasMore && React.createElement('button', { type: 'button', disabled: snapshot.status === 'paging', onClick: inspector.older }, snapshot.status === 'paging' ? text(t, 'detail.read') : text(t, 'detail.older')),
1005
- (snapshot.earlier || snapshot.truncated) && React.createElement('button', { type: 'button', onClick: latest }, text(t, 'detail.latest')),
1501
+ snapshot.hasMore && React.createElement(ActionButton, { type: 'button', disabled: snapshot.status === 'paging', onClick: inspector.older }, snapshot.status === 'paging' ? text(t, 'detail.read') : text(t, 'detail.older')),
1502
+ (snapshot.earlier || snapshot.truncated) && React.createElement(ActionButton, { type: 'button', onClick: latest }, text(t, 'detail.latest')),
1006
1503
  snapshot.status === 'ready' && !snapshot.items.length && React.createElement('p', null, text(t, 'detail.empty')),
1007
- snapshot.items.map(record => {
1008
- const item = record.entry ? detailRecord(record.entry, t) : record
1009
- return React.createElement('article', { key: item.seq, className: 'dsh-super-code-detail-entry ' + item.kind },
1010
- item.collapsed ? React.createElement('details', { open: saved.open.has(item.seq), onToggle: event => { if (event.currentTarget.open) saved.open.add(item.seq); else saved.open.delete(item.seq) } },
1011
- React.createElement('summary', null, item.label),
1012
- React.createElement(DetailText, { text: item.text, t }))
1013
- : React.createElement(React.Fragment, null,
1014
- React.createElement('div', { className: 'dsh-super-code-detail-entry-label' }, item.label,
1015
- React.createElement('time', null, new Date(item.time).toLocaleTimeString(localeCode(t), { hour12: false }))),
1016
- React.createElement(DetailText, { text: item.text, t })))
1017
- }) ),
1018
- unread && React.createElement('button', { type: 'button', className: 'dsh-super-code-new-content', onClick: () => {
1504
+ snapshot.items.map(record => React.createElement(AgentMessage, { key: record.seq, record, saved, t, toolName: toolNames.get(record.callId) }))),
1505
+ unread && React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-new-content', onClick: () => {
1019
1506
  saved.following = true; log.current.scrollTop = log.current.scrollHeight; markUnread(false)
1020
1507
  } }, text(t, 'detail.new')))
1021
1508
  }
@@ -1040,17 +1527,20 @@ const presetRemoteContribution = {
1040
1527
  })),
1041
1528
  }
1042
1529
  const memoryRemoteContribution = {
1043
- package: 'dsh-super-code', descriptors: ['list', 'read'].map(method => ({
1530
+ package: 'dsh-super-code', descriptors: ['list', 'read', 'saveEntry', 'deleteEntry'].map(method => ({
1044
1531
  id: `dsh-super-code:superCodeMemory/${method}`, service: 'superCodeMemory', namespace: 'superCodeMemory', method, invocation: { kind: 'direct' },
1045
- parameters: (method === 'list' ? ['sessionId', 'scope'] : ['sessionId', 'scope', 'topic', 'id']).map(name => ({ name, wire: name, source: 'json', codec: remoteStringCodec })), result: { mode: 'src-json' },
1532
+ parameters: (method === 'list' ? ['sessionId', 'scope'] : method === 'saveEntry' ? ['sessionId', 'scope', 'topic', 'id', 'content'] : method === 'deleteEntry' ? ['sessionId', 'scope', 'topic', 'id', 'expected'] : ['sessionId', 'scope', 'topic', 'id']).map(name => ({ name, wire: name, source: 'json', codec: remoteStringCodec })), result: { mode: 'src-json' },
1046
1533
  })),
1047
1534
  }
1048
1535
 
1049
1536
  // Old hosts render file metadata. Synchronize through our own Remote, then
1050
1537
  // reload their cached roster only when a managed field actually changed.
1051
- function synchronizePresetDisplay(api, locale, reload, onError) {
1538
+ function synchronizePresetDisplay(api, locale, reload, onError, preferenceScope) {
1052
1539
  let disposed = false, running = false, pending = '', last = '', needsReload = false
1053
1540
  const changed = () => {
1541
+ // A provisional browser locale can precede the host's saved preference.
1542
+ // Do not rewrite the preset or reload while that public scope is loading.
1543
+ if (preferenceScope?.getSnapshot().status === 'loading') return
1054
1544
  pending = locale.getSnapshot().active
1055
1545
  if (running || pending === last) return
1056
1546
  running = true
@@ -1069,8 +1559,9 @@ function synchronizePresetDisplay(api, locale, reload, onError) {
1069
1559
  })()
1070
1560
  }
1071
1561
  const unsubscribe = locale.subscribe(changed)
1562
+ const unsubscribePreference = preferenceScope ? preferenceScope.subscribe(changed) : () => {}
1072
1563
  changed()
1073
- return () => { disposed = true; unsubscribe() }
1564
+ return () => { disposed = true; unsubscribe(); unsubscribePreference() }
1074
1565
  }
1075
1566
 
1076
1567
  function PresetSettings({ api, t }) {
@@ -1140,38 +1631,46 @@ function PresetSettings({ api, t }) {
1140
1631
  const versionState = status?.presetVersion ? status.presetVersion === status.pluginVersion ? 'match' : 'mismatch' : 'unknown'
1141
1632
  return React.createElement('section', { className: 'dsh-super-code-settings' },
1142
1633
  React.createElement('header', { className: 'dsh-super-code-settings-header' },
1143
- React.createElement('span', { className: 'dsh-super-code-settings-head-text' },
1634
+ React.createElement('span', { className: 'dsh-super-code-settings-mark', 'aria-hidden': true }, React.createElement(Glyph, { type: 'code' })),
1635
+ React.createElement('div', { className: 'dsh-super-code-settings-head-text' },
1144
1636
  React.createElement('h2', { className: 'dsh-super-code-settings-name' }, t('preset.title')),
1145
- React.createElement('span', { className: 'dsh-super-code-settings-description' }, t('preset.description')))),
1637
+ React.createElement('p', { className: 'dsh-super-code-settings-description' }, t('preset.description')))),
1146
1638
  React.createElement('div', { className: 'dsh-super-code-settings-body' },
1147
- status && React.createElement('p', { className: 'dsh-super-code-preset-status', role: 'status', 'data-available': available },
1148
- React.createElement('span', { 'aria-hidden': true }, '●'), ' ', t(status.delivery === 'declaration' && status.state === 'installed' ? 'preset.state.declaredInstalled' : `preset.state.${status.state}`), ' · ', status.id),
1149
- React.createElement('div', { className: 'dsh-super-code-settings-actions' },
1150
- React.createElement('button', { type: 'button', disabled: busy, onClick: () => run(false), 'aria-label': t('preset.refresh') }, t('preset.refresh'))),
1151
- status && React.createElement('dl', { className: 'dsh-super-code-preset-versions' },
1152
- React.createElement('dt', null, t('preset.pluginVersion')),
1153
- React.createElement('dd', null, status.pluginVersion),
1154
- React.createElement('dt', null, t('preset.presetVersion')),
1155
- React.createElement('dd', null, status.state === 'missing' ? t('preset.versionMissing') : status.presetVersion || t('preset.versionUnknown'))),
1156
- status && status.state !== 'missing' && React.createElement('p', { className: 'dsh-super-code-version-hint', role: 'status', 'data-version-state': versionState },
1157
- t(versionState === 'match' ? 'preset.versionMatches' : versionState === 'mismatch' ? 'preset.versionMismatch' : 'preset.versionUnknownHint'),
1158
- versionState === 'mismatch' && ` ${t(reinstall && status.authorable ? 'preset.versionReinstallHint' : 'preset.versionReloadHint')}`),
1159
- status && React.createElement('p', null, t(available ? 'preset.availableHint' : status.authorable ? 'preset.installHint' : 'preset.unavailableHint')),
1160
- reinstall && React.createElement('p', null, t('preset.reinstallHint')),
1161
- status?.userConflict && status.state !== 'conflict' && React.createElement('p', null, t('preset.userConflict')),
1162
- status?.delivery === 'declaration' && React.createElement('p', { role: 'note' }, t(status.authorable ? 'preset.declaredHint' : 'preset.declaredReadonly')),
1163
- status?.delivery === 'directory' && !status.authorable && React.createElement('p', { role: 'note' }, t('preset.readonly')),
1639
+ React.createElement('div', { className: 'dsh-super-code-settings-summary' },
1640
+ React.createElement('div', { className: 'dsh-super-code-settings-status-row' },
1641
+ status ? React.createElement('p', { className: 'dsh-super-code-preset-status', role: 'status', 'data-available': available },
1642
+ React.createElement('i', { 'aria-hidden': true }),
1643
+ React.createElement('span', null, t(status.delivery === 'declaration' && status.state === 'installed' ? 'preset.state.declaredInstalled' : `preset.state.${status.state}`)),
1644
+ React.createElement('code', null, status.id))
1645
+ : React.createElement('p', { className: 'dsh-super-code-preset-status', role: 'status' }, busy ? t('preset.working') : t('preset.unavailableHint')),
1646
+ React.createElement('div', { className: 'dsh-super-code-settings-actions' },
1647
+ React.createElement(ActionButton, { type: 'button', disabled: busy, onClick: () => run(false), 'aria-label': t('preset.refresh') },
1648
+ React.createElement(IconRefreshOutline16), t('preset.refresh')))),
1649
+ status && React.createElement('dl', { className: 'dsh-super-code-preset-versions' },
1650
+ React.createElement('div', null, React.createElement('dt', null, t('preset.pluginVersion')), React.createElement('dd', null, status.pluginVersion)),
1651
+ React.createElement('div', null, React.createElement('dt', null, t('preset.presetVersion')), React.createElement('dd', null, status.state === 'missing' ? t('preset.versionMissing') : status.presetVersion || t('preset.versionUnknown')))),
1652
+ status && status.state !== 'missing' && React.createElement('p', { className: 'dsh-super-code-version-hint', role: 'status', 'data-version-state': versionState },
1653
+ t(versionState === 'match' ? 'preset.versionMatches' : versionState === 'mismatch' ? 'preset.versionMismatch' : 'preset.versionUnknownHint'),
1654
+ versionState === 'mismatch' && ` ${t(reinstall && status.authorable ? 'preset.versionReinstallHint' : 'preset.versionReloadHint')}`)),
1164
1655
  status?.authorable && React.createElement('form', { onSubmit: event => { event.preventDefault(); submit() } },
1165
- React.createElement('label', { htmlFor: 'super-code-display-name' }, t('preset.displayName')),
1166
- React.createElement('input', { id: 'super-code-display-name', value: displayName, maxLength: 120, required: true, disabled: busy, 'aria-describedby': 'super-code-display-name-hint', onChange: event => setCustomDisplayName(event.target.value) }),
1167
- React.createElement('small', { id: 'super-code-display-name-hint' }, t('preset.displayNameHint')),
1168
- React.createElement('label', { htmlFor: 'super-code-preset-name' }, t('preset.name')),
1169
- React.createElement('div', { className: 'dsh-super-code-install-row' },
1170
- React.createElement('input', { id: 'super-code-preset-name', value: name, maxLength: 64, disabled: busy,
1656
+ React.createElement('h3', null, t('preset.configuration')),
1657
+ React.createElement('div', { className: 'dsh-super-code-settings-field' },
1658
+ React.createElement('label', { htmlFor: 'super-code-display-name' }, t('preset.displayName')),
1659
+ React.createElement('input', { id: 'super-code-display-name', value: displayName, maxLength: 120, required: true, disabled: busy, 'aria-describedby': 'super-code-display-name-hint', onChange: event => setCustomDisplayName(event.target.value) }),
1660
+ React.createElement('small', { id: 'super-code-display-name-hint' }, t('preset.displayNameHint'))),
1661
+ React.createElement('div', { className: 'dsh-super-code-settings-field' },
1662
+ React.createElement('label', { htmlFor: 'super-code-preset-name' }, t('preset.name')),
1663
+ React.createElement('input', { id: 'super-code-preset-name', className: 'dsh-super-code-technical', value: name, maxLength: 64, disabled: busy,
1171
1664
  pattern: '[a-z0-9][a-z0-9\\-]{0,63}', required: true, autoComplete: 'off', spellCheck: false,
1172
1665
  'aria-describedby': 'super-code-preset-name-hint', onChange: event => setCustomId(event.target.value) }),
1173
- React.createElement('button', { type: 'submit', disabled: busy || !displayName.trim() || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name.trim()) }, t(busy ? 'preset.working' : reinstall ? 'preset.reinstall' : status?.delivery === 'declaration' ? 'preset.installDeclared' : 'preset.install'))),
1174
- React.createElement('small', { id: 'super-code-preset-name-hint' }, t(status?.delivery === 'declaration' ? 'preset.declaredNameHint' : 'preset.nameHint'))),
1666
+ React.createElement('small', { id: 'super-code-preset-name-hint' }, t(status?.delivery === 'declaration' ? 'preset.declaredNameHint' : 'preset.nameHint'))),
1667
+ React.createElement('div', { className: 'dsh-super-code-settings-form-actions' },
1668
+ React.createElement(ActionButton, { type: 'submit', className: 'dsh-super-code-primary-button', disabled: busy || !displayName.trim() || !/^[a-z0-9][a-z0-9-]{0,63}$/.test(name.trim()) }, t(busy ? 'preset.working' : reinstall ? 'preset.reinstall' : status?.delivery === 'declaration' ? 'preset.installDeclared' : 'preset.install')))),
1669
+ React.createElement('div', { className: 'dsh-super-code-settings-guidance' },
1670
+ status && !status.authorable && ['missing', 'broken'].includes(status.state) && React.createElement('p', { role: 'note' }, t('preset.unavailableHint')),
1671
+ status?.userConflict && status.state !== 'conflict' && React.createElement('p', null, t('preset.userConflict')),
1672
+ status?.delivery === 'declaration' && !status.authorable && React.createElement('p', { role: 'note' }, t('preset.declaredReadonly')),
1673
+ status?.delivery === 'directory' && !status.authorable && React.createElement('p', { role: 'note' }, t('preset.readonly'))),
1175
1674
  error && React.createElement('p', { role: 'alert' }, t(error))),
1176
1675
  confirmation && React.createElement('dialog', { ref: dialog, className: 'dsh-super-code-confirm',
1177
1676
  'aria-labelledby': 'super-code-confirm-title', 'aria-describedby': 'super-code-confirm-hint',
@@ -1181,13 +1680,15 @@ function PresetSettings({ api, t }) {
1181
1680
  React.createElement('p', { id: 'super-code-confirm-hint' }, t('preset.confirmHint')),
1182
1681
  confirmation.length ? React.createElement('ul', null, ...confirmation.map(item =>
1183
1682
  React.createElement('li', { key: item.previousId },
1184
- React.createElement('span', null, `${item.previousId} → ${item.label} · ${item.id}`),
1185
- React.createElement('button', { type: 'button', 'aria-label': `${t('preset.remove')}: ${item.previousId}`,
1683
+ React.createElement('div', { className: 'dsh-super-code-confirm-item-info' },
1684
+ React.createElement('span', { className: 'dsh-super-code-confirm-previous' }, React.createElement('code', null, item.previousId), ' →'),
1685
+ React.createElement('strong', null, item.label), React.createElement('code', { className: 'dsh-super-code-confirm-new-id' }, item.id)),
1686
+ React.createElement(ActionButton, { type: 'button', 'aria-label': `${t('preset.remove')}: ${item.previousId}`,
1186
1687
  onClick: () => setConfirmation(items => items.filter(row => row.previousId !== item.previousId)) }, t('preset.remove')))))
1187
- : React.createElement('p', { role: 'status' }, t('preset.confirmEmpty')),
1688
+ : React.createElement('p', { className: 'dsh-super-code-confirm-empty', role: 'status' }, t('preset.confirmEmpty')),
1188
1689
  React.createElement('div', { className: 'dsh-super-code-confirm-actions' },
1189
- React.createElement('button', { type: 'button', autoFocus: true, 'data-super-code-cancel': true, onClick: () => setConfirmation(null) }, t('preset.cancel')),
1190
- React.createElement('button', { type: 'button', disabled: busy || !confirmation.length,
1690
+ React.createElement(ActionButton, { type: 'button', autoFocus: true, 'data-super-code-cancel': true, onClick: () => setConfirmation(null) }, t('preset.cancel')),
1691
+ React.createElement(ActionButton, { type: 'button', className: 'dsh-super-code-primary-button', disabled: busy || !confirmation.length,
1191
1692
  onClick: () => {
1192
1693
  if (busy || pending.current || !confirmation.length) return
1193
1694
  const selected = confirmation[0]
@@ -1210,17 +1711,16 @@ function apply(ctx) {
1210
1711
  void ctx.remote.$mount({ package: 'dsh-super-code', descriptors: [
1211
1712
  ...presetRemoteContribution.descriptors, ...memoryRemoteContribution.descriptors,
1212
1713
  ] }).catch(error => console.warn('Super Code Remote:', error))
1213
- const memoryStates = new WeakMap()
1214
- ctx.inject(['remote.superCodeMemory'], ready => {
1215
- ready.slots.inject('sidebar.right.pane.tab', () => ready.slots.register({
1216
- name: 'sidebar.right.pane.tab', key: 'dsh-super-code-memory', locale: LOCALE_NS,
1217
- inject: () => ({ api: ready.remote.superCodeMemory, memoryStates }),
1218
- }, MemoryLibrary))
1219
- })
1220
- ctx.inject(['remote.superCodePresets'], ready => {
1221
- ready.effect(() => synchronizePresetDisplay(ready.remote.superCodePresets, locale,
1222
- () => window.location.reload(), error => console.warn('Super Code preset display:', error)), 'super-code: preset display')
1223
- ready.slots.inject('settings.section', () => ready.slots.register({
1714
+ const memoryStates = new WeakMap(), workspaceStates = new WeakMap()
1715
+ // Locale already requires its host's preference service. Declare that same
1716
+ // service here: Cordis rejects even optional reads without an injection.
1717
+ const preferenceService = 'configForms' in ctx ? 'configForms' : 'settingsScope'
1718
+ ctx.inject(['remote.superCodePresets', preferenceService], ready => {
1719
+ const preferenceScope = preferenceService === 'configForms'
1720
+ ? ready.configForms.get('locale') : ready.settingsScope.bind({ namespace: 'locale' })
1721
+ ready.effect(() => synchronizePresetDisplay(ready.remote.superCodePresets, locale,
1722
+ () => window.location.reload(), error => console.warn('Super Code preset display:', error), preferenceScope), 'super-code: preset display')
1723
+ ready.slots.inject('settings.section', () => ready.slots.register({
1224
1724
  name: 'settings.section', id: 'super-code', order: 120, label: () => t('preset.title'), locale: LOCALE_NS,
1225
1725
  inject: () => ({ api: ready.remote.superCodePresets }),
1226
1726
  }, PresetSettings))
@@ -1229,185 +1729,406 @@ function apply(ctx) {
1229
1729
  const style = document.createElement('style')
1230
1730
  style.dataset.dshSuperCode = 'true'
1231
1731
  style.textContent = `
1232
- .dsh-super-code-memory{height:100%;min-height:0;display:flex;flex-direction:column;font-size:13px;--agent-muted:var(--dsw-alias-label-secondary,#70757d);--agent-line:var(--dsw-alias-border-l1,#dedfe3)}
1233
- .dsh-super-code-memory>header{padding:18px 18px 12px;border-bottom:1px solid var(--agent-line)}
1234
- .dsh-super-code-memory-heading{display:flex;align-items:center;justify-content:space-between;gap:12px}.dsh-super-code-memory h2{margin:0;font-size:16px;font-weight:600}
1235
- .dsh-super-code-memory-muted{color:var(--agent-muted);font-size:12px;line-height:1.65;margin:10px 0}
1236
- .dsh-super-code-memory-scopes{display:flex;gap:4px;padding:3px;margin:14px 0;border-radius:8px;background:color-mix(in srgb,currentColor 5%,transparent)}
1237
- .dsh-super-code-memory-scopes button{flex:1;border:0;border-radius:6px;padding:7px;background:transparent;color:var(--agent-muted);font:inherit;cursor:pointer}
1238
- .dsh-super-code-memory-scopes button[aria-pressed=true]{background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-color-primary,#3276dc);box-shadow:0 1px 4px #0001}
1239
- .dsh-super-code-memory input{width:100%;box-sizing:border-box;border:1px solid var(--agent-line);border-radius:7px;background:transparent;color:inherit;font:inherit;padding:9px 10px;margin-bottom:10px}
1240
- .dsh-super-code-memory small{font-size:11px;color:var(--agent-muted);overflow-wrap:anywhere}
1241
- .dsh-super-code-memory-list{flex:1;min-height:0;overflow:auto;padding:0 12px}.dsh-super-code-memory-row{display:flex;flex-direction:column;justify-content:center;gap:7px;width:100%;height:76px;box-sizing:border-box;border:0;border-bottom:1px solid var(--agent-line);background:transparent;text-align:left;color:inherit;padding:12px 8px;cursor:pointer;font:inherit}
1242
- .dsh-super-code-memory-row:hover{background:color-mix(in srgb,var(--dsw-color-primary,#3276dc) 5%,transparent)}.dsh-super-code-memory-row strong,.dsh-super-code-memory-row span{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dsh-super-code-memory-row strong{font-weight:500}.dsh-super-code-memory-row span{font-size:11px;color:var(--agent-muted)}
1243
- .dsh-super-code-memory-body{overflow:auto;flex:1;min-height:0;padding:14px 18px 28px}.dsh-super-code-memory-body article{padding-top:18px}.dsh-super-code-memory-body h3{font-size:15px;line-height:1.6;margin:8px 0 14px;overflow-wrap:anywhere}
1244
- .dsh-super-code-memory-detail{white-space:pre-wrap;line-height:1.8;overflow-wrap:anywhere}.dsh-super-code-memory-hint{border-left:2px solid #b8ac82;padding:8px 12px;background:color-mix(in srgb,#b8ac82 8%,transparent);color:var(--agent-muted);font-size:12px;line-height:1.6;margin:22px 0}
1245
- .dsh-super-code-memory-body dt{font-size:11px;color:var(--agent-muted);margin-top:18px}.dsh-super-code-memory-body dd{margin:6px 0;line-height:1.6;overflow-wrap:anywhere;font-size:12px}.dsh-super-code-memory-empty{padding:20px 6px;line-height:1.8;color:var(--agent-muted)}
1246
- .dsh-super-code-memory-activity{margin-top:14px;font-size:12px}.dsh-super-code-memory-activity summary{cursor:pointer}.dsh-super-code-memory-activity-list{max-height:200px;overflow:auto}.dsh-super-code-memory-activity-list button{display:grid;grid-template-columns:auto 1fr;gap:5px 8px;width:100%;text-align:left;background:transparent;border:0;border-bottom:1px solid var(--agent-line);padding:10px 2px;color:inherit;font:inherit;cursor:pointer}.dsh-super-code-memory-activity-list small{grid-column:2;color:var(--agent-muted);overflow-wrap:anywhere}.dsh-super-code-memory-activity-list span{overflow-wrap:anywhere}
1247
- .dsh-super-code-memory-action{font-size:10px;color:#4d779f}.dsh-super-code-memory-action[data-action=read]{color:#14867b}.dsh-super-code-memory-action[data-action=remember]{color:#927247}.dsh-super-code-memory-action[data-action=forget]{color:var(--agent-muted)}
1248
- .dsh-super-code-memory button:focus-visible,.dsh-super-code-memory input:focus-visible{outline:2px solid var(--dsw-color-primary,#3276dc);outline-offset:2px}
1249
- .dsh-super-code-settings{list-style:none;border:.5px solid var(--dsw-alias-border-l4,#dedfe3);border-radius:16px;background:var(--dsw-alias-bg-layer-2,transparent);line-height:1.6;font-size:13px}
1250
- .dsh-super-code-settings-header{display:flex;align-items:center;gap:12px;padding:14px 16px}
1251
- .dsh-super-code-settings-head-text{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}.dsh-super-code-settings-name{margin:0;font-size:15px;font-weight:600;line-height:1.4;color:var(--dsw-alias-label-primary,inherit)}
1252
- .dsh-super-code-settings-description{font-size:13px;line-height:1.5;color:var(--dsw-alias-label-tertiary,#70757d)}
1253
- .dsh-super-code-preset-versions{display:grid;grid-template-columns:auto minmax(0,1fr);gap:6px 16px;margin:12px 0}.dsh-super-code-preset-versions dt{color:var(--dsw-alias-label-secondary,#70757d)}.dsh-super-code-preset-versions dd{margin:0;font-variant-numeric:tabular-nums;overflow-wrap:anywhere}
1254
- .dsh-super-code-settings .dsh-super-code-version-hint[data-version-state=mismatch],.dsh-super-code-settings .dsh-super-code-version-hint[data-version-state=unknown]{border-left:2px solid #b87716;padding:8px 12px;background:color-mix(in srgb,#b87716 8%,transparent)}
1255
- .dsh-super-code-confirm{box-sizing:border-box;width:min(560px,calc(100vw - 48px));max-height:80vh;overflow:auto;border:1px solid var(--dsw-alias-border-l2,#dedfe3);border-radius:8px;padding:24px;color:var(--dsw-alias-label-primary,#202126);background:var(--dsw-alias-bg-layer-1,#fff);font-size:13px;line-height:1.6}.dsh-super-code-confirm::backdrop{background:#0006}.dsh-super-code-confirm h3{font-size:16px;margin:0 0 12px}.dsh-super-code-confirm p{margin:0 0 14px}.dsh-super-code-confirm ul{padding:0;margin:0 0 18px;list-style:none}.dsh-super-code-confirm li{display:flex;align-items:center;justify-content:space-between;gap:16px;margin:12px 0;overflow-wrap:anywhere}.dsh-super-code-confirm-actions{display:flex;justify-content:flex-end;gap:8px}.dsh-super-code-confirm button{font:inherit;color:inherit;border:1px solid var(--dsw-alias-border-l1,#dedfe3);border-radius:6px;background:transparent;padding:7px 10px;min-height:34px;cursor:pointer}.dsh-super-code-confirm button:disabled{opacity:.45;cursor:default}.dsh-super-code-confirm button:focus-visible{outline:2px solid var(--dsw-color-primary,#3276dc);outline-offset:2px}
1256
- .dsh-super-code-settings-body{border-top:.5px solid var(--dsw-alias-border-l2,#dedfe3);margin:0 16px;padding:12px 0 14px}.dsh-super-code-settings-actions{display:flex;justify-content:flex-end}
1257
- .dsh-super-code-settings p{margin:8px 0;color:var(--dsw-alias-label-secondary,#70757d)}
1258
- .dsh-super-code-settings-body button,.dsh-super-code-settings input{font:inherit;color:inherit;border:1px solid var(--dsw-alias-border-l1,#dedfe3);border-radius:7px;background:transparent;padding:7px 10px;min-height:34px}
1259
- .dsh-super-code-settings button{cursor:pointer;white-space:nowrap}.dsh-super-code-settings button:disabled{opacity:.45;cursor:default}
1260
- .dsh-super-code-settings form{margin-top:16px}.dsh-super-code-settings label{display:block;margin-bottom:6px}
1261
- .dsh-super-code-install-row{display:flex;gap:8px;flex-wrap:wrap}.dsh-super-code-install-row input{flex:1;min-width:140px}
1262
- .dsh-super-code-settings small{display:block;margin-top:6px;color:var(--dsw-alias-label-secondary,#70757d)}
1263
- .dsh-super-code-settings .dsh-super-code-preset-status{color:inherit}.dsh-super-code-preset-status span{color:#b87716}.dsh-super-code-preset-status[data-available=true] span{color:#008b78}
1264
- .dsh-super-code-settings [role=alert]{color:var(--dsw-color-text-error,#bd423b)}.dsh-super-code-settings :focus-visible{outline:2px solid var(--dsw-color-primary,#3276dc);outline-offset:2px}
1732
+ /* Host aliases remain the source of theme colors. */
1733
+ :where(.dsh-super-code-workspace,.dsh-super-code-settings,.dsh-super-code-tree,.dsh-super-code-detail,.dsh-super-code-memory,.dsh-super-code-confirm,.dsh-super-code-select,.dsh-super-code-tooltip){
1734
+ --sc-text:var(--dsw-alias-label-primary,#242831);
1735
+ --sc-muted:var(--dsw-alias-label-secondary,#6a707a);
1736
+ --sc-faint:var(--dsw-alias-label-tertiary,#818793);
1737
+ --sc-bg:var(--dsw-alias-bg-layer-1,#fff);
1738
+ --sc-surface:var(--dsw-alias-bg-layer-2,#f5f6f8);
1739
+ --sc-line:var(--dsw-alias-border-l1,#e2e4e8);
1740
+ --sc-hover:color-mix(in srgb,var(--sc-text) 5%,var(--sc-bg));
1741
+ --sc-selected:color-mix(in srgb,var(--dsw-color-primary,#3e78c5) 7%,var(--sc-bg));
1742
+ --sc-accent:var(--dsw-color-primary,#3e78c5);
1743
+ --sc-success:var(--dsw-color-text-success,#197661);
1744
+ --sc-warning:var(--dsw-color-text-warning,#9c650c);
1745
+ --sc-error:var(--dsw-color-text-error,#bb4545);
1746
+ --sc-mono:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;
1747
+ --agent-muted:var(--sc-muted);--agent-line:var(--sc-line);
1748
+ color:var(--sc-text);font-size:14px;line-height:1.55;letter-spacing:0;
1749
+ box-sizing:border-box;min-width:0;
1750
+ }
1751
+ :where(.dsh-super-code-workspace,.dsh-super-code-settings,.dsh-super-code-tree,.dsh-super-code-detail,.dsh-super-code-memory,.dsh-super-code-confirm) *{box-sizing:border-box}
1752
+ :where(.dsh-super-code-workspace,.dsh-super-code-settings,.dsh-super-code-tree,.dsh-super-code-detail,.dsh-super-code-memory,.dsh-super-code-confirm) :is(button,input,select){font:inherit;color:inherit;min-width:0}
1753
+ :where(.dsh-super-code-workspace,.dsh-super-code-settings,.dsh-super-code-tree,.dsh-super-code-detail,.dsh-super-code-memory,.dsh-super-code-confirm) button{cursor:pointer;transition:background-color .12s,border-color .12s;color:inherit}
1754
+ :where(.dsh-super-code-workspace,.dsh-super-code-settings,.dsh-super-code-tree,.dsh-super-code-detail,.dsh-super-code-memory,.dsh-super-code-confirm) button:disabled{opacity:.45;cursor:default}
1755
+ :where(.dsh-super-code-workspace,.dsh-super-code-settings,.dsh-super-code-tree,.dsh-super-code-detail,.dsh-super-code-memory,.dsh-super-code-confirm) :is(button,input,select,summary):focus-visible{outline:2px solid var(--sc-accent);outline-offset:2px}
1756
+ :where(.dsh-super-code-workspace,.dsh-super-code-settings,.dsh-super-code-tree,.dsh-super-code-detail,.dsh-super-code-memory) :is(input,select){width:100%;height:36px;padding:7px 12px;border:1px solid var(--sc-line);border-radius:8px;background:var(--sc-bg);transition:border-color .12s;outline-offset:2px}
1757
+ :where(.dsh-super-code-workspace,.dsh-super-code-settings,.dsh-super-code-tree,.dsh-super-code-memory) input::placeholder{color:var(--sc-faint)}
1758
+ :where(.dsh-super-code-workspace,.dsh-super-code-settings,.dsh-super-code-tree,.dsh-super-code-memory) :is(input,select):hover{border-color:color-mix(in srgb,var(--sc-text) 25%,var(--sc-line))}
1759
+ .dsh-super-code-technical,.dsh-super-code-confirm code,.dsh-super-code-preset-status code{font-family:var(--sc-mono);font-size:12px}
1760
+ .dsh-super-code-title-line{display:flex;align-items:center;gap:8px;min-width:0}
1761
+ .dsh-super-code-glyph{width:18px;height:18px;flex:none;color:var(--sc-muted)}
1762
+ .dsh-super-code-icon-button{display:inline-flex;align-items:center;justify-content:center;flex:none;width:32px;height:32px;border:0;border-radius:8px;padding:0;background:transparent;color:var(--sc-muted)}
1763
+ .dsh-super-code-icon-button:hover,.dsh-super-code-view-button:hover{background:var(--sc-hover);color:var(--sc-text)}
1764
+ .dsh-super-code-icon-button svg{width:16px;height:16px}
1765
+ .dsh-super-code-view-button{display:inline-flex;align-items:center;gap:6px;border:0;border-radius:8px;padding:6px 8px;background:transparent;color:var(--sc-muted);font-size:13px}
1265
1766
 
1266
- .dsh-super-code-tree{--agent-muted:var(--dsw-alias-label-secondary,#70757d);--agent-line:var(--dsw-alias-border-l1,#dedfe3);height:100%;min-width:0;min-height:0;display:flex;flex-direction:column;overflow:auto;font-size:13px;letter-spacing:0;color:inherit}
1267
- .dsh-super-code-tree>header,.dsh-super-code-tree>.dsh-super-code-graph-controls,.dsh-super-code-tree>.dsh-super-code-graph-legend,.dsh-super-code-tree>.dsh-super-code-history-controls{flex-shrink:0}
1268
- .dsh-super-code-tree-header{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:20px 18px 16px}
1269
- .dsh-super-code-tree-header strong{display:block;font-size:14px;font-weight:600}
1270
- .dsh-super-code-tree-count{display:block;margin-top:5px;color:var(--agent-muted);font-size:12px}
1271
- .dsh-super-code-graph-controls{display:flex;align-items:center;gap:6px;padding:2px 18px 12px;color:var(--agent-muted);font-size:11px}
1272
- .dsh-super-code-graph-controls button{border:1px solid var(--agent-line);border-radius:5px;background:transparent;color:inherit;padding:3px 8px;min-height:28px;cursor:pointer;font:inherit}
1273
- .dsh-super-code-graph-controls button:disabled{opacity:.4;cursor:default}
1274
- .dsh-super-code-graph-controls span{min-width:38px;text-align:center;font-variant-numeric:tabular-nums}
1275
- .dsh-super-code-history-controls{display:flex;gap:8px;padding:0 18px 10px}
1276
- .dsh-super-code-history-controls button{border:1px solid var(--agent-line);border-radius:14px;background:transparent;color:var(--agent-muted);padding:5px 10px;font:inherit;font-size:11px;cursor:pointer}
1277
- .dsh-super-code-history-controls button[aria-expanded=true]{color:var(--dsw-color-primary,#3276dc);background:color-mix(in srgb,currentColor 5%,transparent)}
1278
- .dsh-super-code-history{display:flex;flex-direction:column;flex-shrink:0;box-sizing:border-box;height:46%;min-height:220px;max-height:400px;margin:0 12px 12px;padding:12px;border:1px solid var(--agent-line);border-radius:12px;background:color-mix(in srgb,var(--agent-muted) 3%,transparent)}
1279
- .dsh-super-code-history>p,.dsh-super-code-history>input,.dsh-super-code-history-filters{flex-shrink:0}
1280
- .dsh-super-code-history p{font-size:11px;color:var(--agent-muted);margin:0 0 10px;line-height:1.6}
1281
- .dsh-super-code-history input,.dsh-super-code-history select{box-sizing:border-box;min-width:0;width:100%;border:1px solid var(--agent-line);border-radius:7px;background:var(--dsw-alias-bg-base,#fff);color:var(--dsw-alias-text-primary,inherit);font:inherit;font-size:12px;padding:7px 8px}
1282
- .dsh-super-code-history>input{margin-bottom:8px}
1283
- .dsh-super-code-history-filters{display:grid;grid-template-columns:minmax(0,1fr) minmax(0,1fr);gap:8px;margin-bottom:8px}
1284
- .dsh-super-code-history-filters label{display:flex;flex-direction:column;gap:4px;min-width:0;font-size:10px;color:var(--agent-muted)}
1285
- .dsh-super-code-history-filters select{cursor:pointer}
1286
- .dsh-super-code-history input:focus-visible,.dsh-super-code-history select:focus-visible,.dsh-super-code-history-list button:focus-visible{outline:2px solid var(--dsw-color-primary,#3276dc);outline-offset:-2px}
1287
- .dsh-super-code-history p.dsh-super-code-history-summary{font-size:10px;margin-bottom:6px}
1288
- .dsh-super-code-history-list{flex:1;min-height:56px;overflow:auto;overflow-anchor:none;overscroll-behavior:contain;scrollbar-gutter:stable}
1289
- .dsh-super-code-history-list button{display:flex;align-items:center;box-sizing:border-box;gap:9px;width:100%;height:56px;text-align:left;border:0;border-radius:7px;padding:9px 5px;background:transparent;color:inherit;cursor:pointer;font:inherit}
1290
- .dsh-super-code-history-list button:hover{background:color-mix(in srgb,currentColor 5%,transparent)}
1291
- .dsh-super-code-history-list button>span{flex:1;min-width:0}.dsh-super-code-history-list strong{display:block;font-size:12px;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
1292
- .dsh-super-code-history-list small{font-size:10px;color:var(--agent-muted);line-height:1.6}.dsh-super-code-history-list button>small{white-space:nowrap;font-variant-numeric:tabular-nums}
1293
- .dsh-super-code-history-list button>span>small{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
1294
- .dsh-super-code-history-list .dsh-super-code-circle{width:7px;height:7px;box-shadow:none}
1295
- .dsh-super-code-history-empty{padding:14px 5px}
1296
- .dsh-super-code-branch-toggle{position:absolute;display:grid;place-items:center;width:22px;height:22px;padding:0;border:1px solid var(--agent-line);border-radius:50%;background:var(--dsw-alias-bg-base,#fff);color:var(--agent-muted);cursor:pointer;box-shadow:0 1px 3px #0000000a}
1297
- .dsh-super-code-branch-toggle:hover{color:var(--dsw-color-primary,#3276dc);border-color:currentColor}
1298
- .dsh-super-code-graph-scroll{overflow:hidden;padding:0 12px;min-height:180px;flex:1;touch-action:none;cursor:grab;user-select:none}
1299
- .dsh-super-code-graph-scroll.dragging,.dsh-super-code-graph-scroll.dragging *{cursor:grabbing!important}
1300
- .dsh-super-code-graph-legend{display:flex;flex-wrap:wrap;gap:6px 12px;padding:0 18px 8px;color:var(--agent-muted);font-size:10px}
1767
+ /* Settings. */
1768
+ .dsh-super-code-settings{container-type:inline-size;border:1px solid var(--sc-line);border-radius:12px;background:var(--sc-bg);overflow:hidden}
1769
+ .dsh-super-code-settings-header{display:flex;align-items:center;gap:12px;padding:20px 24px;border-bottom:1px solid var(--sc-line)}
1770
+ .dsh-super-code-settings-mark{display:grid;place-items:center;flex:none;width:40px;height:40px;background:var(--sc-surface);border:1px solid var(--sc-line);border-radius:10px}
1771
+ .dsh-super-code-settings-mark svg{width:22px;height:22px;color:var(--sc-text)}
1772
+ .dsh-super-code-settings-head-text{display:grid;gap:4px;min-width:0}
1773
+ .dsh-super-code-settings-name{font-size:16px;font-weight:600;line-height:1.4;margin:0}
1774
+ .dsh-super-code-settings-description{font-size:13px;color:var(--sc-muted);margin:0}
1775
+ .dsh-super-code-settings-body{padding:20px 24px 24px}
1776
+ .dsh-super-code-settings-summary{padding:16px;border-radius:12px;background:var(--sc-surface)}
1777
+ .dsh-super-code-settings-status-row{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;flex-wrap:wrap}
1778
+ .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}
1779
+ .dsh-super-code-preset-status>i{width:7px;height:7px;flex:none;border-radius:50%;background:var(--sc-warning)}
1780
+ .dsh-super-code-preset-status[data-available=true]>i{background:var(--sc-success)}
1781
+ .dsh-super-code-preset-status>span{font-weight:500}
1782
+ .dsh-super-code-preset-status code{color:var(--sc-muted);overflow-wrap:anywhere}
1783
+ .dsh-super-code-settings-actions{display:flex;flex:none;margin-left:auto}
1784
+ .dsh-super-code-settings-actions button,.dsh-super-code-settings-form-actions button,.dsh-super-code-confirm button{display:inline-flex;align-items:center;justify-content:center;gap:6px;min-height:32px;border:1px solid var(--sc-line);border-radius:8px;background:var(--sc-bg);padding:5px 10px;font-size:13px}
1785
+ .dsh-super-code-settings-actions button:hover,.dsh-super-code-confirm button:hover{background:var(--sc-hover)}
1786
+ .dsh-super-code-settings-actions svg{width:14px;height:14px}
1787
+ .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)}
1788
+ .dsh-super-code-preset-versions>div+div{border-left:1px solid var(--sc-line);padding-left:16px}
1789
+ .dsh-super-code-preset-versions dt{font-size:12px;color:var(--sc-muted)}
1790
+ .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}
1791
+ .dsh-super-code-version-hint{font-size:12px;color:var(--sc-muted);margin:12px 0 0;overflow-wrap:anywhere}
1792
+ .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)}
1793
+ .dsh-super-code-settings form{display:grid;gap:16px;margin-top:24px}
1794
+ .dsh-super-code-settings form>h3{margin:0;font-size:14px;font-weight:600}
1795
+ .dsh-super-code-settings-field{display:grid;gap:6px}
1796
+ .dsh-super-code-settings label{font-size:13px;font-weight:500}
1797
+ .dsh-super-code-settings small{display:block;font-size:12px;color:var(--sc-muted);line-height:1.6;overflow-wrap:anywhere}
1798
+ .dsh-super-code-settings-form-actions{display:flex;align-items:center;justify-content:flex-end;flex-wrap:wrap;gap:12px;padding-top:4px}
1799
+ .dsh-super-code-settings-form-actions>small{flex:1;min-width:220px}
1800
+ .dsh-super-code-settings-form-actions>button{margin-left:auto;flex:none}
1801
+ .dsh-super-code-settings .dsh-super-code-primary-button,.dsh-super-code-confirm .dsh-super-code-primary-button{background:var(--sc-text);border-color:var(--sc-text);color:var(--sc-bg);font-weight:500}
1802
+ .dsh-super-code-settings .dsh-super-code-primary-button:hover,.dsh-super-code-confirm .dsh-super-code-primary-button:hover{background:color-mix(in srgb,var(--sc-text) 85%,var(--sc-bg))}
1803
+ .dsh-super-code-settings-guidance:empty{display:none}
1804
+ .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}
1805
+ .dsh-super-code-settings-guidance p{margin:0 0 4px}
1806
+ .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}
1807
+ @container(max-width:420px){.dsh-super-code-settings-header{padding:16px}.dsh-super-code-settings-body{padding:16px}.dsh-super-code-settings-summary{padding:12px}.dsh-super-code-settings-status-row{gap:8px}.dsh-super-code-preset-status{flex-basis:100%}.dsh-super-code-settings-form-actions>small{min-width:0;flex-basis:100%}}
1808
+
1809
+ /* Confirmation. */
1810
+ .dsh-super-code-confirm{width:min(520px,calc(100vw - 32px));max-height:calc(100dvh - 48px);overflow:auto;border:1px solid var(--sc-line);border-radius:16px;padding:24px;background:var(--sc-bg);box-shadow:0 12px 48px #0003}
1811
+ .dsh-super-code-confirm::backdrop{background:#10182066}
1812
+ .dsh-super-code-confirm h3{font-size:16px;font-weight:600;margin:0 0 8px}
1813
+ .dsh-super-code-confirm>p{font-size:13px;color:var(--sc-muted);margin:0 0 16px;line-height:1.7}
1814
+ .dsh-super-code-confirm ul{padding:0;list-style:none;margin:20px 0;background:var(--sc-surface);border-radius:12px;overflow:hidden}
1815
+ .dsh-super-code-confirm li{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:16px;overflow-wrap:anywhere}
1816
+ .dsh-super-code-confirm li+li{border-top:1px solid var(--sc-line)}
1817
+ .dsh-super-code-confirm li>button{background:transparent;flex:none;font-size:12px}
1818
+ .dsh-super-code-confirm-item-info{display:grid;gap:3px;min-width:0}
1819
+ .dsh-super-code-confirm-item-info strong{font-size:14px;font-weight:500}
1820
+ .dsh-super-code-confirm-previous,.dsh-super-code-confirm-new-id{font-size:12px;color:var(--sc-muted)}
1821
+ .dsh-super-code-confirm-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:20px}
1822
+ .dsh-super-code-confirm .dsh-super-code-confirm-empty{padding:20px 16px;background:var(--sc-surface);border-radius:12px}
1823
+
1824
+ /* Exactly one section fills the pane; the other keeps its clickable heading. */
1825
+ .dsh-super-code-workspace{height:100%;min-height:0;overflow:auto;background:var(--sc-bg)}
1826
+ .dsh-super-code-workspace-layout{display:grid;height:100%;min-height:324px;min-width:0}
1827
+ .dsh-super-code-workspace-collapsed{display:flex;align-items:center;border-block:1px solid var(--sc-line);background:var(--sc-bg);padding:0 12px}
1828
+ .dsh-super-code-section-toggle{display:flex;align-items:center;gap:6px;flex:1;min-width:0;width:100%;min-height:36px;border:0;border-radius:6px;background:transparent;padding:6px 8px;text-align:left}
1829
+ .dsh-super-code-section-toggle>.dsh-super-code-tree-count{margin-left:auto}
1830
+ .dsh-super-code-section-toggle strong{font-size:14px;font-weight:600;white-space:nowrap}
1831
+ .dsh-super-code-section-toggle>.dsh-super-code-glyph{width:16px;height:16px}
1832
+ .dsh-super-code-section-toggle>.dsh-super-code-glyph:first-child{width:12px;height:12px;transition:transform .12s}
1833
+ .dsh-super-code-section-toggle[aria-expanded=false]>.dsh-super-code-glyph:first-child{transform:rotate(-90deg)}
1834
+ .dsh-super-code-section-toggle:hover{background:var(--sc-hover)}
1835
+ .dsh-super-code-workspace-collapsed>.dsh-super-code-section-toggle{width:100%;height:100%}
1836
+
1837
+ /* Memory library: geometry stays at 76px per row. */
1838
+ .dsh-super-code-memory{height:100%;min-height:0;display:flex;flex-direction:column;container-type:inline-size}
1839
+ .dsh-super-code-memory>header{padding:16px;border-bottom:1px solid var(--sc-line);flex:none}
1840
+ .dsh-super-code-memory-heading{display:flex;align-items:center;justify-content:space-between;gap:8px}
1841
+ .dsh-super-code-memory h2{font-size:16px;font-weight:600;margin:0}
1842
+ .dsh-super-code-memory-muted{font-size:13px;color:var(--sc-muted);line-height:1.65;margin:8px 0}
1843
+ .dsh-super-code-memory-scopes{display:flex;gap:2px;padding:3px;margin:16px 0 12px;border-radius:18px;background:var(--sc-surface)}
1844
+ .dsh-super-code-memory-scopes button{flex:1;min-height:28px;padding:3px 8px;border:0;border-radius:16px;font-size:13px;background:transparent;color:var(--sc-muted)}
1845
+ .dsh-super-code-memory-scopes button[aria-pressed=true]{background:var(--sc-bg);color:var(--sc-text);box-shadow:inset 0 0 0 1px var(--sc-line)}
1846
+ .dsh-super-code-memory-search{position:relative;margin-bottom:8px}
1847
+ .dsh-super-code-memory-search>svg{position:absolute;left:11px;top:9px;width:16px;height:16px;color:var(--sc-muted);pointer-events:none}
1848
+ .dsh-super-code-memory-search input{padding-left:34px}
1849
+ .dsh-super-code-memory small{font-size:12px;color:var(--sc-muted);overflow-wrap:anywhere}
1850
+ .dsh-super-code-memory-workspace{flex:1;display:flex;flex-direction:column;min-height:0;background:var(--sc-surface)}
1851
+ .dsh-super-code-memory-topic-index{display:flex;flex-direction:column;flex:none;gap:8px;min-width:0;padding:12px 16px;border-bottom:1px solid var(--sc-line);background:var(--sc-bg)}
1852
+ .dsh-super-code-memory-topic-label{display:flex;align-items:center;gap:8px;font-size:11px;font-weight:500;color:var(--sc-muted)}
1853
+ .dsh-super-code-memory-topic-label>span{padding:0 5px;border-radius:4px;background:var(--sc-surface);font-variant-numeric:tabular-nums}
1854
+ .dsh-super-code-memory-topic-options{display:flex;gap:6px;overflow:auto;min-width:0;padding:2px 0 5px}
1855
+ .dsh-super-code-memory-topic-index button{flex:none;display:inline-flex;align-items:center;gap:6px;min-height:30px;padding:5px 8px;border:1px solid var(--sc-line);border-radius:8px;background:var(--sc-bg);color:var(--sc-muted);font-size:12px;white-space:nowrap}
1856
+ .dsh-super-code-memory-topic-index button .dsh-super-code-glyph{width:14px;height:14px}
1857
+ .dsh-super-code-memory-topic-index button>span{min-width:0;overflow:hidden;text-overflow:ellipsis}
1858
+ .dsh-super-code-memory-topic-index button small{font-size:11px;line-height:1.3;min-width:16px;text-align:center;padding:1px 4px;border-radius:4px;background:var(--sc-surface);font-variant-numeric:tabular-nums}
1859
+ .dsh-super-code-memory-topic-index button:hover{background:var(--sc-hover);color:var(--sc-text)}
1860
+ .dsh-super-code-memory-topic-index button[aria-pressed=true]{border-color:var(--sc-accent);background:var(--sc-selected);color:var(--sc-text)}
1861
+ .dsh-super-code-memory-results{flex:1;display:flex;flex-direction:column;min-width:0;min-height:0}
1862
+ .dsh-super-code-memory-list-heading{display:flex;align-items:baseline;justify-content:space-between;gap:8px;padding:12px 16px 8px;flex:none}
1863
+ .dsh-super-code-memory-list-heading strong{font-size:12px;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
1864
+ .dsh-super-code-memory-list-heading small{font-size:11px;flex:none}
1865
+ .dsh-super-code-memory-list{flex:1;min-height:0;overflow:auto;padding:0 12px;background:var(--sc-surface)}
1866
+ .dsh-super-code-memory-list>[role=listitem]{height:76px;padding-bottom:6px}
1867
+ .dsh-super-code-memory-row{position:relative;display:flex;flex-direction:column;justify-content:center;gap:2px;width:100%;height:70px;border:1px solid var(--sc-line);border-radius:10px;padding:6px 12px 6px 16px;text-align:left;background:var(--sc-bg);box-shadow:0 1px 2px #00000008;overflow:hidden}
1868
+ .dsh-super-code-memory-row:before{content:"";position:absolute;left:0;top:10px;bottom:10px;width:3px;border-radius:0 3px 3px 0;background:var(--sc-accent)}
1869
+ .dsh-super-code-memory-row[data-kind=constraint]:before{background:var(--sc-warning)}
1870
+ .dsh-super-code-memory-row[data-kind=fact]:before{background:var(--sc-accent)}
1871
+ .dsh-super-code-memory-row[data-kind=experience]:before{background:var(--sc-success)}
1872
+ .dsh-super-code-memory-row:hover{background:var(--sc-hover);border-color:color-mix(in srgb,var(--sc-accent) 35%,var(--sc-line))}
1873
+ .dsh-super-code-memory-row-heading{display:flex;align-items:center;gap:6px;min-width:0;line-height:14px}
1874
+ .dsh-super-code-memory-row-heading .dsh-super-code-glyph{width:12px;height:12px;color:var(--sc-faint)}
1875
+ .dsh-super-code-memory-row-topic{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--sc-muted);font-size:11px}
1876
+ .dsh-super-code-memory-row-kind{color:var(--sc-muted);white-space:nowrap}
1877
+ .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}
1878
+ .dsh-super-code-memory-row-meta{display:flex;align-items:center;gap:8px;font-size:10px;color:var(--sc-muted);white-space:nowrap;line-height:12px}
1879
+ .dsh-super-code-memory-row-meta>span+span{border-left:1px solid var(--sc-line);padding-left:8px;font-family:var(--sc-mono)}
1880
+ .dsh-super-code-memory-empty{padding:24px 8px;color:var(--sc-muted);font-size:13px;line-height:1.8}
1881
+ .dsh-super-code-memory-body{flex:1;min-height:0;overflow:auto;padding:16px;background:var(--sc-surface)}
1882
+ .dsh-super-code-memory-body article{padding:16px;border:1px solid var(--sc-line);border-radius:12px;background:var(--sc-bg);box-shadow:0 1px 3px #0000000a}
1883
+ .dsh-super-code-memory-detail-meta{display:flex;flex-wrap:wrap;align-items:center;gap:6px;color:var(--sc-muted);font-size:11px}
1884
+ .dsh-super-code-memory-detail-meta>span{display:inline-flex;align-items:center;gap:5px;padding:3px 7px;border-radius:6px;background:var(--sc-surface)}
1885
+ .dsh-super-code-memory-detail-meta>span:first-child{background:var(--sc-selected);color:var(--sc-accent)}
1886
+ .dsh-super-code-memory-detail-meta .dsh-super-code-glyph{width:13px;height:13px;color:inherit}
1887
+ .dsh-super-code-memory-body h3{font-size:16px;font-weight:600;line-height:1.6;margin:12px 0 16px;overflow-wrap:anywhere}
1888
+ .dsh-super-code-memory-detail{font-size:14px;white-space:pre-wrap;line-height:1.8;overflow-wrap:anywhere}
1889
+ .dsh-super-code-memory-body dl{padding-top:8px;border-top:1px solid var(--sc-line)}
1890
+ .dsh-super-code-memory-body dt{font-size:12px;color:var(--sc-muted);margin-top:12px}
1891
+ .dsh-super-code-memory-body dd{margin:4px 0;font-size:12px;line-height:1.7;overflow-wrap:anywhere}
1892
+ .dsh-super-code-memory-related{border-top:1px solid var(--sc-line);margin-top:20px;padding-top:12px}
1893
+ .dsh-super-code-memory-related h4{font-size:12px;font-weight:500;color:var(--sc-muted);margin:0 0 6px}
1894
+ .dsh-super-code-memory-related button{display:flex;align-items:center;gap:8px;width:100%;padding:8px 4px;border:0;border-radius:6px;background:transparent;font-size:12px;text-align:left}
1895
+ .dsh-super-code-memory-related button:hover{background:var(--sc-hover)}
1896
+ .dsh-super-code-memory-related button>span{min-width:0;flex:1;overflow-wrap:anywhere}
1897
+ .dsh-super-code-memory-related .dsh-super-code-glyph{width:14px;height:14px}
1898
+ @container(min-width:520px){
1899
+ .dsh-super-code-memory-workspace{display:grid;grid-template-columns:170px minmax(0,1fr)}
1900
+ .dsh-super-code-memory-topic-index{min-height:0;padding:16px 10px;border-bottom:0;border-right:1px solid var(--sc-line)}
1901
+ .dsh-super-code-memory-topic-label{padding:0 6px}
1902
+ .dsh-super-code-memory-topic-options{flex-direction:column;gap:4px;padding:2px;min-height:0;overflow:auto}
1903
+ .dsh-super-code-memory-topic-index button{width:100%;justify-content:space-between;border-color:transparent;background:transparent}
1904
+ .dsh-super-code-memory-topic-index button>span{flex:1;text-align:left}
1905
+ }
1906
+ .dsh-super-code-memory-activity{margin-top:12px;font-size:13px}
1907
+ .dsh-super-code-memory-activity summary{cursor:pointer;color:var(--sc-muted)}
1908
+ .dsh-super-code-memory-activity-list{max-height:200px;overflow:auto}
1909
+ .dsh-super-code-memory-activity-list button{display:grid;grid-template-columns:auto minmax(0,1fr);gap:4px 8px;width:100%;border:0;border-bottom:1px solid var(--sc-line);background:transparent;padding:8px 0;text-align:left;font-size:12px}
1910
+ .dsh-super-code-memory-activity-list small{grid-column:2;color:var(--sc-muted);font-size:11px;overflow-wrap:anywhere}
1911
+ .dsh-super-code-memory-activity-list span{overflow-wrap:anywhere}
1912
+ .dsh-super-code-memory-action{color:var(--sc-muted)}
1913
+ .dsh-super-code-memory-action[data-action=read]{color:var(--sc-accent)}
1914
+ .dsh-super-code-memory-action[data-action=remember]{color:var(--sc-success)}
1915
+
1916
+ /* Direct memory editing keeps one current copy, with no version UI. */
1917
+ .dsh-super-code-memory-editor{display:grid;align-content:start;gap:12px;flex:1;min-height:0;overflow:auto;padding:12px 16px}
1918
+ .dsh-super-code-memory-editor-heading{display:flex;align-items:center;justify-content:space-between;gap:8px}
1919
+ .dsh-super-code-memory-editor label{display:grid;grid-template-columns:1fr auto;gap:6px;font-size:12px}
1920
+ .dsh-super-code-memory-editor label>:is(input,textarea),.dsh-super-code-memory-editor label>small:last-child{grid-column:1/-1}
1921
+ .dsh-super-code-memory-editor textarea{font:inherit;color:inherit;resize:vertical;min-height:100px;width:100%;padding:8px 12px;border:1px solid var(--sc-line);border-radius:8px;background:var(--sc-bg)}
1922
+ .dsh-super-code-memory-editor [role=alert]{margin:0;font-size:12px;color:var(--sc-error)}
1923
+ .dsh-super-code-memory-actions{display:flex;align-items:center;justify-content:flex-end;gap:6px;flex-wrap:wrap}
1924
+ .dsh-super-code-memory-actions>button{padding:5px 10px;font-size:12px;border:1px solid var(--sc-line);border-radius:7px;background:var(--sc-bg)}
1925
+ .dsh-super-code-memory-actions>.dsh-super-code-view-button{margin-right:auto;border:0;padding-left:0}
1926
+ .dsh-super-code-memory-actions>.dsh-super-code-memory-primary{background:var(--sc-text);color:var(--sc-bg);border-color:var(--sc-text)}
1927
+ .dsh-super-code-memory-danger{color:var(--sc-error)!important}
1928
+ .dsh-super-code-memory-editor textarea:focus-visible{outline:2px solid var(--sc-accent);outline-offset:2px}
1929
+
1930
+ /* Compact library header leaves room for entries in the shared pane. */
1931
+ .dsh-super-code-workspace .dsh-super-code-memory>header{display:grid;grid-template-columns:minmax(0,1fr) auto;gap:8px;padding:10px 12px}
1932
+ .dsh-super-code-workspace .dsh-super-code-memory-heading{display:contents}
1933
+ .dsh-super-code-workspace .dsh-super-code-memory h2{font-size:14px}
1934
+ .dsh-super-code-workspace .dsh-super-code-memory-header-actions{display:flex;align-items:center;gap:4px;grid-column:2;grid-row:1}
1935
+ .dsh-super-code-memory-header-actions>.dsh-super-code-view-button{font-size:12px;white-space:nowrap}
1936
+ .dsh-super-code-workspace .dsh-super-code-memory-scopes{grid-column:1/-1;margin:0;padding:2px}
1937
+ .dsh-super-code-workspace .dsh-super-code-memory-search{grid-column:1/-1;margin:0}
1938
+ .dsh-super-code-workspace .dsh-super-code-memory-topic-index{padding:8px 12px;gap:6px}
1939
+ .dsh-super-code-workspace .dsh-super-code-memory-list-heading{padding:8px 12px 6px}
1940
+
1941
+ /* Graph: reserve space for animated/selected rings before the text stack. */
1942
+ .dsh-super-code-tree{height:100%;min-height:0;display:flex;flex-direction:column;overflow:auto;container-type:inline-size}
1943
+ .dsh-super-code-tree>header,.dsh-super-code-graph-legend,.dsh-super-code-graph-controls,.dsh-super-code-history-controls{flex:none}
1944
+ .dsh-super-code-tree-header{display:flex;flex-direction:column;gap:8px;padding:12px}
1945
+ .dsh-super-code-tree-heading{display:flex;align-items:center;justify-content:space-between;gap:12px;min-width:0}
1946
+ .dsh-super-code-tree-header strong{font-size:15px;font-weight:600;white-space:nowrap}
1947
+ .dsh-super-code-tree-header .dsh-super-code-title-line{gap:6px;min-width:0}
1948
+ .dsh-super-code-tree-header .dsh-super-code-title-line>.dsh-super-code-glyph{width:16px;height:16px}
1949
+ .dsh-super-code-tree-count{font-size:11px;color:var(--sc-muted);white-space:nowrap;font-variant-numeric:tabular-nums}
1950
+ .dsh-super-code-tree-toolbar{display:flex;align-items:center;gap:6px;min-width:0}
1951
+ .dsh-super-code-tree-toolbar>.dsh-super-code-icon-button{width:28px;height:28px;border-radius:6px}
1952
+ .dsh-super-code-tree-toolbar>.dsh-super-code-icon-button svg{width:16px;height:16px}
1953
+ .dsh-super-code-graph-legend{display:flex;flex-wrap:wrap;gap:6px 12px;font-size:10px;color:var(--sc-muted)}
1301
1954
  .dsh-super-code-graph-legend>span{display:flex;align-items:center;gap:5px}
1302
- .dsh-super-code-graph-legend .dsh-super-code-circle{width:7px;height:7px;box-shadow:none}
1955
+ .dsh-super-code-circle.active{--state-color:#008b78}
1956
+ .dsh-super-code-circle.idle{--state-color:#3971de}
1957
+ .dsh-super-code-circle.stopped{--state-color:#777d87}
1958
+ .dsh-super-code-circle.unavailable{--state-color:#b87716}
1959
+ .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)}
1960
+ .dsh-super-code-graph-legend .dsh-super-code-circle.idle{background:transparent;border:1px solid var(--state-color)}
1961
+ .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}
1962
+ .dsh-super-code-graph-controls button,.dsh-super-code-history-controls button{display:inline-flex;align-items:center;justify-content:center;gap:5px;min-height:28px;min-width:28px;padding:3px 6px;border:0;border-radius:6px;background:transparent;font-size:12px}
1963
+ .dsh-super-code-graph-controls button:hover,.dsh-super-code-history-controls button:hover{background:var(--sc-hover)}
1964
+ .dsh-super-code-graph-controls span{min-width:36px;text-align:center;font-family:var(--sc-mono);font-size:11px}
1965
+ .dsh-super-code-history-controls{display:flex;align-items:center;gap:6px;border-left:1px solid var(--sc-line);padding-left:6px}
1966
+ .dsh-super-code-history-controls .dsh-super-code-glyph{width:16px;height:16px}
1967
+ .dsh-super-code-history-controls button{white-space:nowrap}
1968
+ .dsh-super-code-history-controls .dsh-super-code-action-count{font-family:var(--sc-mono);font-size:11px}
1969
+ .dsh-super-code-history-controls button[aria-expanded=true]{background:var(--sc-selected);border-color:var(--sc-accent)}
1970
+ @container(max-width:360px){
1971
+ .dsh-super-code-tree-toolbar{gap:3px}
1972
+ .dsh-super-code-graph-controls button{min-width:26px;padding:3px 4px}
1973
+ .dsh-super-code-graph-controls span{min-width:28px}
1974
+ .dsh-super-code-history-controls{gap:3px;padding-left:3px}
1975
+ .dsh-super-code-history-controls button{gap:3px;padding:3px;font-size:11px}
1976
+ .dsh-super-code-history-controls .dsh-super-code-glyph{display:none}
1977
+ }
1978
+ .dsh-super-code-graph-scroll{flex:1;min-height:180px;overflow:hidden;padding:0 12px;touch-action:none;cursor:grab;user-select:none;border-top:1px solid var(--sc-line);background:var(--sc-surface)}
1979
+ .dsh-super-code-graph-scroll.dragging,.dsh-super-code-graph-scroll.dragging *{cursor:grabbing!important}
1303
1980
  .dsh-super-code-graph{position:relative;transform-origin:0 0}
1304
- .dsh-super-code-graph-edges{position:absolute;inset:0;pointer-events:none;stroke:var(--agent-line);stroke-width:1.5}
1305
- .dsh-super-code-graph-node{position:absolute;width:128px;min-height:100px;display:flex;flex-direction:column;align-items:center;gap:6px;border:0;padding:0 4px;background:transparent;color:inherit;font:inherit;cursor:pointer;border-radius:8px}
1306
- .dsh-super-code-circle{position:relative;display:flex;align-items:center;justify-content:center;flex:none;width:40px;height:40px;border-radius:50%!important;corner-shape:round!important;font-size:13px;font-weight:600;background:var(--state-color);color:#fff}
1307
- .dsh-super-code-circle.active{--state-color:#008b78}.dsh-super-code-circle.idle{--state-color:#3971de}.dsh-super-code-circle.stopped{--state-color:#777d87}.dsh-super-code-circle.unavailable{--state-color:#b87716}
1308
- .dsh-super-code-graph-node .dsh-super-code-circle{background:linear-gradient(145deg,color-mix(in srgb,var(--state-color) 83%,white),var(--state-color));box-shadow:inset 0 1px 1px #ffffff40,0 2px 6px #00000012}
1309
- .dsh-super-code-graph-node .dsh-super-code-circle:after{content:"";position:absolute;inset:-5px;border:1px solid color-mix(in srgb,var(--state-color) 22%,transparent);border-radius:50%;corner-shape:round;pointer-events:none}
1310
- .dsh-super-code-graph-node .dsh-super-code-circle.idle:after{animation:super-agent-breathe 3s ease-in-out infinite}
1311
- .dsh-super-code-graph-node .dsh-super-code-circle.active:after{border-width:2px;border-top-color:var(--state-color);border-right-color:var(--state-color);animation:super-agent-process 1.6s linear infinite}
1312
- .dsh-super-code-graph-node .dsh-super-code-circle.stopped{background:linear-gradient(145deg,#9297a0,#747a84);box-shadow:inset 0 1px 1px #ffffff30}
1313
- .dsh-super-code-graph-node .dsh-super-code-circle.stopped:after{border-color:color-mix(in srgb,var(--state-color) 14%,transparent)}
1314
- .dsh-super-code-graph-node .dsh-super-code-circle.unavailable:after{border-style:dashed;border-color:var(--state-color)}
1315
- .dsh-super-code-graph-node:hover .dsh-super-code-circle{box-shadow:inset 0 1px 1px #ffffff40,0 3px 10px color-mix(in srgb,var(--state-color) 25%,transparent)}
1981
+ .dsh-super-code-graph-edges{position:absolute;inset:0;pointer-events:none;stroke:color-mix(in srgb,var(--sc-muted) 35%,var(--sc-surface));stroke-width:1.25}
1982
+ .dsh-super-code-graph-node{position:absolute;display:flex;align-items:center;flex-direction:column;width:128px;height:${agentTreeNodeHeight}px;gap:16px;padding:0 4px;border:0;border-radius:12px;background:transparent;cursor:pointer}
1983
+ .dsh-super-code-graph-node[aria-disabled]{cursor:default;opacity:.65}
1984
+ .dsh-super-code-graph-node>.dsh-super-code-circle{position:relative;display:grid;place-items:center;flex:none;width:40px;height:40px;border-radius:50%!important;corner-shape:round!important;background:linear-gradient(145deg,color-mix(in srgb,var(--state-color) 83%,white),var(--state-color));box-shadow:inset 0 1px 1px #ffffff40,0 2px 6px #00000012;color:#fff;font-size:13px;font-weight:600}
1985
+ .dsh-super-code-graph-node>.dsh-super-code-circle:after{content:"";position:absolute;inset:-5px;border:1px solid color-mix(in srgb,var(--state-color) 22%,transparent);border-radius:50%;corner-shape:round;pointer-events:none}
1986
+ .dsh-super-code-graph-node>.dsh-super-code-circle.idle:after{animation:super-agent-breathe 3s ease-in-out infinite}
1987
+ .dsh-super-code-graph-node>.dsh-super-code-circle.active:after{inset:-6px;border-width:3px;border-color:color-mix(in srgb,var(--state-color) 14%,transparent);border-top-color:var(--state-color);border-right-color:color-mix(in srgb,var(--state-color) 60%,transparent);animation:super-agent-process 1.2s linear infinite}
1988
+ .dsh-super-code-graph-node>.dsh-super-code-circle.stopped{background:linear-gradient(145deg,#9297a0,#747a84);box-shadow:inset 0 1px 1px #ffffff30}
1989
+ .dsh-super-code-graph-node>.dsh-super-code-circle.stopped:after{border-color:color-mix(in srgb,var(--state-color) 14%,transparent)}
1990
+ .dsh-super-code-graph-node>.dsh-super-code-circle.unavailable:after{border-style:dashed;border-color:var(--state-color)}
1991
+ .dsh-super-code-graph-node:hover>.dsh-super-code-circle{box-shadow:inset 0 1px 1px #ffffff40,0 3px 10px color-mix(in srgb,var(--state-color) 25%,transparent)}
1992
+ .dsh-super-code-graph-node.selected>.dsh-super-code-circle{outline:2px solid var(--sc-accent);outline-offset:7px}
1316
1993
  @keyframes super-agent-breathe{0%,100%{transform:scale(1);opacity:.35}50%{transform:scale(1.12);opacity:.85}}
1317
1994
  @keyframes super-agent-process{to{transform:rotate(360deg)}}
1318
- .dsh-super-code-graph-node:focus-visible{outline:2px solid var(--dsw-color-primary,#3276dc);outline-offset:4px}
1319
- .dsh-super-code-graph-node[aria-disabled]{cursor:default;opacity:.65}
1320
- .dsh-super-code-graph-node .dsh-super-code-tree-content{width:100%;text-align:center}
1321
- .dsh-super-code-graph-node .dsh-super-code-tree-title{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:18px;height:18px;font-size:12px}
1322
- .dsh-super-code-graph-node .dsh-super-code-tree-usage{justify-content:center;gap:1px 7px;font-size:10px}
1323
- .dsh-super-code-icon-button,.dsh-super-code-tree-toggle{display:inline-flex;align-items:center;justify-content:center;flex:none;width:28px;height:28px;padding:0;border:0;border-radius:4px;background:transparent;color:var(--agent-muted);cursor:pointer}
1324
- .dsh-super-code-icon-button:hover,.dsh-super-code-tree-toggle:hover{background:color-mix(in srgb,currentColor 9%,transparent)}
1325
- .dsh-super-code-icon-button:disabled{opacity:.45;cursor:default}
1326
- .dsh-super-code-view-button{flex:none;border:0;border-radius:4px;padding:6px 8px;background:transparent;color:var(--agent-muted);font:inherit;font-size:12px;cursor:pointer}
1327
- .dsh-super-code-view-button:hover{background:color-mix(in srgb,currentColor 7%,transparent);color:inherit}
1328
- .dsh-super-code-view-button:disabled{opacity:.45;cursor:default}
1329
- .dsh-super-code-tree-rows{padding:0 12px 20px}
1330
- .dsh-super-code-tree-row{position:relative;display:flex;align-items:center;gap:6px;min-width:0;min-height:64px;padding:10px 8px 10px calc(4px + var(--agent-depth)*14px);border-radius:6px;cursor:default;box-sizing:border-box}
1331
- .dsh-super-code-tree-row[aria-expanded]{cursor:pointer}
1332
- .dsh-super-code-tree-row[aria-level]:not([aria-level="1"]):before{content:"";position:absolute;left:15px;width:calc(var(--agent-depth)*14px);height:100%;top:0;background:repeating-linear-gradient(to right,var(--agent-line) 0,var(--agent-line) 1px,transparent 1px,transparent 14px);pointer-events:none}
1333
- .dsh-super-code-tree-row:hover{background:color-mix(in srgb,currentColor 5%,transparent)}
1334
- .dsh-super-code-tree-row.selected{background:color-mix(in srgb,var(--dsw-color-primary,#3276dc) 6%,transparent)}
1335
- .dsh-super-code-tree-row:focus-visible,.dsh-super-code-tree button:focus-visible{outline:2px solid var(--dsw-color-primary,#3276dc);outline-offset:-2px}
1336
- .dsh-super-code-tree-row[aria-disabled]{cursor:default;opacity:.7}
1337
- .dsh-super-code-tree-toggle{width:22px;height:26px;z-index:1}
1338
- .dsh-super-code-tree-toggle svg{transition:transform .12s}.dsh-super-code-tree-toggle.expanded svg{transform:rotate(90deg)}
1339
- .dsh-super-code-tree-connector{width:22px;flex:none}
1340
- .dsh-super-code-tree-content{display:grid;gap:4px;flex:1;min-width:0}
1341
- .dsh-super-code-tree-title{display:-webkit-box;-webkit-box-orient:vertical;-webkit-line-clamp:2;overflow:hidden;overflow-wrap:anywhere;line-height:1.4}
1342
- .dsh-super-code-tree-meta{color:var(--agent-muted);font-size:11px;line-height:1.4;overflow-wrap:anywhere}
1343
- .dsh-super-code-tree-usage{display:flex;flex-wrap:wrap;gap:3px 10px;font-size:10px;line-height:1.6;color:var(--agent-muted);font-variant-numeric:tabular-nums}
1344
- .dsh-super-code-tree-usage>span{white-space:nowrap}
1345
- .dsh-super-code-state{display:inline-flex;align-items:center;gap:5px;padding:2px 6px;border-radius:5px;color:var(--state-color);background:color-mix(in srgb,var(--state-color) 9%,transparent)}
1346
- .dsh-super-code-state:before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor}
1347
- .dsh-super-code-state.active{--state-color:#16877d}
1348
- .dsh-super-code-state.idle{--state-color:#5471bb}
1349
- .dsh-super-code-state.stopped{--state-color:#827299}
1350
- .dsh-super-code-state.unavailable{--state-color:#b77b29}
1351
- @media(prefers-color-scheme:dark){.dsh-super-code-state.active{--state-color:#6bc7b6}.dsh-super-code-state.idle{--state-color:#91b0f4}.dsh-super-code-state.stopped{--state-color:#b9a9cf}.dsh-super-code-state.unavailable{--state-color:#e8b971}}
1352
- .dsh-super-code-tree-status{width:6px;height:6px;border-radius:50%;background:var(--agent-line);flex:none}
1353
- .dsh-super-code-tree-row.running .dsh-super-code-tree-status{background:#168c78}
1354
- .dsh-super-code-tree-status.unavailable{background:#c17e1d}
1355
- .dsh-super-code-tree-note,.dsh-super-code-tree-empty{margin:10px 18px;color:var(--agent-muted);font-size:12px}
1356
- .dsh-super-code-tree-error{margin:12px 14px;color:var(--dsw-color-text-error,#bd423b);font-size:12px;overflow-wrap:anywhere}
1357
- .dsh-super-code-tree-more{display:block;margin:4px auto 14px;padding:6px 12px;border:1px solid var(--agent-line);border-radius:4px;background:transparent;color:inherit;cursor:pointer}
1358
- .dsh-super-code-detail{height:100%;min-width:0;display:flex;flex-direction:column;font-size:13px;letter-spacing:0;--agent-muted:var(--dsw-alias-label-secondary,#70757d);--agent-line:var(--dsw-alias-border-l1,#dedfe3)}
1359
- .dsh-super-code-detail-header{padding:20px 20px 18px;border-bottom:1px solid var(--agent-line);flex:none;max-height:45%;overflow:auto}
1360
- .dsh-super-code-detail-header nav{font-size:11px;line-height:1.5;color:var(--agent-muted);overflow-wrap:anywhere}
1361
- .dsh-super-code-detail-heading{display:flex;align-items:flex-start;justify-content:space-between;gap:12px;margin-top:14px}
1362
- .dsh-super-code-detail-heading>div{min-width:0}
1363
- .dsh-super-code-detail h2{font-size:16px;line-height:1.5;font-weight:600;margin:0;overflow-wrap:anywhere}
1364
- .dsh-super-code-detail-task{font-size:13px;line-height:1.7;margin:12px 0 0;overflow-wrap:anywhere}
1365
- .dsh-super-code-task-memory{margin-top:16px;padding-top:14px;border-top:1px solid var(--agent-line);font-size:12px;line-height:1.7;overflow-wrap:anywhere}
1995
+ .dsh-super-code-tree-content{display:grid;gap:2px;width:100%;min-width:0;text-align:center}
1996
+ .dsh-super-code-tree-title{height:16px;font-size:12px;line-height:16px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
1997
+ .dsh-super-code-node-status{display:flex;align-items:center;justify-content:center;gap:4px;font-size:11px;line-height:14px;color:var(--sc-muted)}
1998
+ .dsh-super-code-node-status>i{width:5px;height:5px;border-radius:50%;background:currentColor;flex:none}
1999
+ .dsh-super-code-node-status[data-tone=active]{color:var(--sc-accent)}
2000
+ .dsh-super-code-node-status[data-tone=unavailable]{color:var(--sc-warning)}
2001
+ .dsh-super-code-node-status[data-tone=idle]>i{background:transparent;border:1px solid currentColor}
2002
+ .dsh-super-code-tree-usage{display:flex;flex-direction:column;gap:0;font-size:10px;line-height:12px;color:var(--sc-muted);font-variant-numeric:tabular-nums}
2003
+ .dsh-super-code-tree-usage>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
2004
+ .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)}
2005
+ .dsh-super-code-branch-toggle:hover{color:var(--sc-accent);border-color:currentColor}
2006
+ .dsh-super-code-tree-empty,.dsh-super-code-tree-error{margin:12px 16px}
2007
+ .dsh-super-code-tree-more{align-self:center;margin:8px 16px;padding:5px 10px;border:1px solid var(--sc-line);border-radius:8px;background:var(--sc-bg);font-size:13px}
2008
+ .dsh-super-code-history{display:flex;flex-direction:column;flex:none;height:46%;min-height:220px;max-height:400px;margin:0 12px 12px;padding:12px;border:1px solid var(--sc-line);border-radius:12px;background:var(--sc-surface)}
2009
+ .dsh-super-code-history>input{flex:none;margin-bottom:8px}
2010
+ .dsh-super-code-history p{flex:none;font-size:12px;color:var(--sc-muted);margin:0 0 8px;line-height:1.6}
2011
+ .dsh-super-code-history-filters{display:grid;flex:none;grid-template-columns:repeat(2,minmax(0,1fr));gap:8px;margin-bottom:8px}
2012
+ .dsh-super-code-history-filters :is(label,.dsh-super-code-select-field){display:grid;gap:4px;min-width:0;font-size:12px;color:var(--sc-muted)}
2013
+ .dsh-super-code-history-list{flex:1;min-height:56px;overflow:auto;overflow-anchor:none;overscroll-behavior:contain}
2014
+ .dsh-super-code-history-list button{display:flex;align-items:center;gap:8px;width:100%;height:56px;padding:8px 4px;text-align:left;border:0;border-radius:8px;background:transparent}
2015
+ .dsh-super-code-history-list button:hover{background:var(--sc-hover)}
2016
+ .dsh-super-code-history-list button>span{flex:1;min-width:0}
2017
+ .dsh-super-code-history-list strong{display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:13px;font-weight:500}
2018
+ .dsh-super-code-history-list small{font-size:11px;color:var(--sc-muted);white-space:nowrap}
2019
+ .dsh-super-code-history-list button>span>small{display:block;overflow:hidden;text-overflow:ellipsis}
2020
+
2021
+ /* Agent details. */
2022
+ .dsh-super-code-detail{height:100%;min-height:0;display:flex;flex-direction:column}
2023
+ .dsh-super-code-detail-header{flex:none;max-height:40%;overflow:auto;padding:10px 12px;border-bottom:1px solid var(--sc-line)}
2024
+ .dsh-super-code-detail-header nav{font-size:11px;color:var(--sc-muted);line-height:16px;margin-bottom:4px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
2025
+ .dsh-super-code-detail-heading{display:flex;align-items:center;gap:8px;min-width:0}
2026
+ .dsh-super-code-detail-heading h2{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:14px;font-weight:600;line-height:20px;margin:0}
2027
+ .dsh-super-code-detail-heading .dsh-super-code-icon-button{width:28px;height:28px;border-radius:6px}
2028
+ .dsh-super-code-detail-status{display:inline-flex;align-items:center;flex:none;gap:5px;padding:2px 6px;border-radius:5px;font-size:11px;white-space:nowrap;background:var(--sc-surface);color:var(--sc-muted)}
2029
+ .dsh-super-code-detail-status:before{content:"";width:5px;height:5px;border-radius:50%;background:currentColor}
2030
+ .dsh-super-code-detail-status[data-tone=active]{color:var(--sc-accent)}
2031
+ .dsh-super-code-detail-status[data-tone=unavailable]{color:var(--sc-warning)}
2032
+ .dsh-super-code-detail-task{font-size:14px;line-height:1.7;margin:12px 0 0;overflow-wrap:anywhere}
2033
+ .dsh-super-code-task-memory{margin-top:16px;padding-top:12px;border-top:1px solid var(--sc-line);font-size:13px;line-height:1.7;overflow-wrap:anywhere}
1366
2034
  .dsh-super-code-task-heading{display:flex;flex-wrap:wrap;align-items:baseline;gap:4px 12px}
1367
- .dsh-super-code-task-heading strong{font-weight:500;color:inherit}
1368
- .dsh-super-code-task-heading span{color:var(--agent-muted);font-size:11px}
1369
- .dsh-super-code-task-memory p{margin:6px 0 0}
1370
- .dsh-super-code-task-memory details{margin-top:8px;color:var(--agent-muted)}
2035
+ .dsh-super-code-task-heading strong{font-weight:500}
2036
+ .dsh-super-code-task-heading span{font-size:12px;color:var(--sc-muted)}
2037
+ .dsh-super-code-task-memory p{margin:4px 0 0}
2038
+ .dsh-super-code-task-memory details{margin-top:8px;color:var(--sc-muted)}
1371
2039
  .dsh-super-code-task-memory summary{cursor:pointer}
1372
- .dsh-super-code-detail-metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:14px 16px;margin:16px 0 0}
1373
- .dsh-super-code-usage-details{margin-top:14px;font-size:12px;color:var(--agent-muted)}
1374
- .dsh-super-code-usage-details summary{cursor:pointer}
1375
- .dsh-super-code-new-content{align-self:center;flex:none;margin:8px 16px 12px;padding:7px 12px;border:1px solid var(--agent-line);border-radius:6px;background:transparent;color:inherit;font:inherit;font-size:12px;cursor:pointer}
1376
- .dsh-super-code-detail-metrics dt{font-size:11px;color:var(--agent-muted)}
1377
- .dsh-super-code-detail-metrics dd{margin:5px 0 0;font-variant-numeric:tabular-nums;font-size:14px;line-height:1.4;overflow-wrap:anywhere}
1378
- .dsh-super-code-detail-metrics>div:first-child dd{font-weight:600}
1379
- .dsh-super-code-detail-status{display:block;margin-top:5px;font-size:11px;color:var(--agent-muted)}
1380
- .dsh-super-code-detail-log{flex:1;min-height:0;overflow:auto;padding:4px 20px 24px}
1381
- .dsh-super-code-detail-log>button,.dsh-super-code-detail-entry button{border:1px solid var(--agent-line);border-radius:4px;background:transparent;color:inherit;padding:5px 8px;margin:10px 8px 4px 0;font-size:12px;cursor:pointer}
1382
- .dsh-super-code-detail-entry{padding:20px 0;min-width:0}
1383
- .dsh-super-code-detail-entry:has(>details){padding:10px 0;color:var(--agent-muted)}
1384
- .dsh-super-code-detail-entry details[open]{color:inherit;padding-bottom:8px}
1385
- .dsh-super-code-detail-entry-label{display:flex;justify-content:space-between;gap:10px;font-size:12px;font-weight:600}
1386
- .dsh-super-code-detail-entry time{color:var(--agent-muted);font-size:11px;font-weight:400;flex:none}
1387
- .dsh-super-code-detail-entry pre{font:inherit;line-height:1.7;white-space:pre-wrap;overflow-wrap:anywhere;margin:8px 0 0}
1388
- .dsh-super-code-detail-entry summary{cursor:pointer;font-size:12px;overflow-wrap:anywhere}
1389
- .dsh-super-code-detail-entry.context{color:var(--agent-muted)}
1390
- .dsh-super-code-detail-entry.error,.dsh-super-code-detail [role=alert]{color:var(--dsw-color-text-error,#bd423b)}
1391
- .dsh-super-code-detail button:focus-visible,.dsh-super-code-detail summary:focus-visible{outline:2px solid var(--dsw-color-primary,#3276dc);outline-offset:3px}
1392
- .dsh-super-code-detail-entry summary:hover{color:var(--dsw-alias-label-primary,inherit)}
1393
- @media(prefers-reduced-motion:reduce){.dsh-super-code-tree-toggle svg{transition:none}.dsh-super-code-graph-node .dsh-super-code-circle:after{animation:none!important}}
2040
+ .dsh-super-code-detail-metrics{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:6px 12px;margin:0;padding:10px;border-radius:8px;background:var(--sc-surface)}
2041
+ .dsh-super-code-detail-metrics>div{display:flex;align-items:baseline;justify-content:space-between;gap:6px;min-width:0}
2042
+ .dsh-super-code-detail-metrics dt{font-size:11px;color:var(--sc-muted)}
2043
+ .dsh-super-code-detail-metrics dd{font-size:12px;line-height:1.4;margin:0;font-variant-numeric:tabular-nums;overflow-wrap:anywhere;font-weight:500}
2044
+ .dsh-super-code-usage-details{margin-top:4px;color:var(--sc-muted);font-size:12px}
2045
+ .dsh-super-code-usage-details>summary{display:flex;align-items:center;justify-content:space-between;gap:8px;min-height:24px;border-radius:5px;cursor:pointer;list-style:none}
2046
+ .dsh-super-code-usage-details>summary::-webkit-details-marker{display:none}
2047
+ .dsh-super-code-usage-details>summary:hover{background:var(--sc-hover)}
2048
+ .dsh-super-code-detail-summary{display:flex;align-items:center;gap:16px;min-width:0}
2049
+ .dsh-super-code-detail-summary>span{display:inline-flex;align-items:baseline;gap:5px;font-size:11px;white-space:nowrap}
2050
+ .dsh-super-code-detail-summary strong{font-weight:500;font-size:12px;color:var(--sc-text);font-variant-numeric:tabular-nums}
2051
+ .dsh-super-code-detail-info-toggle{display:inline-flex;align-items:center;gap:3px;flex:none;font-size:11px}
2052
+ .dsh-super-code-detail-info-toggle .dsh-super-code-glyph{width:13px;height:13px;transition:transform .12s}
2053
+ .dsh-super-code-usage-details[open]>.dsh-super-code-detail-info-toggle .dsh-super-code-glyph,.dsh-super-code-usage-details[open]>summary .dsh-super-code-detail-info-toggle .dsh-super-code-glyph{transform:rotate(180deg)}
2054
+ .dsh-super-code-detail-info{padding-top:8px;padding-bottom:2px}
2055
+ .dsh-super-code-detail-info .dsh-super-code-memory-activity{margin-top:10px;font-size:12px}
2056
+ .dsh-super-code-detail-info .dsh-super-code-task-memory{margin-top:10px;font-size:12px}
2057
+ .dsh-super-code-detail-log{flex:1;min-height:0;overflow:auto;padding:14px 14px 24px;background:var(--sc-bg)}
2058
+ .dsh-super-code-detail-log>button,.dsh-super-code-detail-entry button{border:1px solid var(--sc-line);border-radius:8px;background:var(--sc-bg);padding:5px 8px;margin:0 8px 10px 0;font-size:12px}
2059
+ .dsh-super-code-detail-entry{display:flex;align-items:flex-start;gap:8px;min-width:0;margin:0 0 16px}
2060
+ .dsh-super-code-detail-avatar{display:grid;place-items:center;flex:none;width:26px;height:26px;margin-top:2px;border-radius:8px;background:var(--sc-surface);color:var(--sc-muted)}
2061
+ .dsh-super-code-detail-avatar .dsh-super-code-glyph{width:16px;height:16px;color:inherit}
2062
+ .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)}
2063
+ .dsh-super-code-detail-entry.user{flex-direction:row-reverse;margin-left:28px}
2064
+ .dsh-super-code-detail-entry.user .dsh-super-code-detail-avatar{background:var(--sc-accent);color:#fff}
2065
+ .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)}
2066
+ .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)}
2067
+ .dsh-super-code-detail-entry.tool{margin-bottom:12px}
2068
+ .dsh-super-code-detail-entry.tool .dsh-super-code-detail-message{padding:8px 10px;border-radius:8px;background:var(--sc-surface)}
2069
+ .dsh-super-code-detail-entry.context .dsh-super-code-detail-message{border-style:dotted;color:var(--sc-muted);background:var(--sc-surface)}
2070
+ .dsh-super-code-detail-entry.error .dsh-super-code-detail-avatar{color:var(--sc-error);background:color-mix(in srgb,var(--sc-error) 10%,var(--sc-bg))}
2071
+ .dsh-super-code-detail-entry.error .dsh-super-code-detail-message{border-color:color-mix(in srgb,var(--sc-error) 35%,var(--sc-line));color:var(--sc-error)}
2072
+ .dsh-super-code-detail-entry-label{display:flex;align-items:center;justify-content:space-between;gap:8px;min-width:0;font-size:11px;font-weight:500;color:var(--sc-muted)}
2073
+ .dsh-super-code-detail-entry-label>span{min-width:0;overflow-wrap:anywhere}
2074
+ .dsh-super-code-detail-entry.user .dsh-super-code-detail-entry-label{color:var(--sc-accent)}
2075
+ .dsh-super-code-detail-entry time{flex:none;font-family:var(--sc-mono);font-size:11px;font-weight:400;color:var(--sc-faint)}
2076
+ .dsh-super-code-detail-entry pre{min-width:0;font:inherit;font-size:14px;line-height:1.75;white-space:pre-wrap;overflow-wrap:anywhere;margin:6px 0 0}
2077
+ .dsh-super-code-detail-entry.tool pre{font-family:var(--sc-mono);font-size:12px;line-height:1.6;color:var(--sc-muted)}
2078
+ .dsh-super-code-detail-message>details{min-width:0;color:var(--sc-muted)}
2079
+ .dsh-super-code-detail-message>details[open]{color:var(--sc-text)}
2080
+ .dsh-super-code-detail-message summary{display:flex;align-items:center;gap:6px;cursor:pointer;overflow-wrap:anywhere;list-style:none}
2081
+ .dsh-super-code-detail-message summary::-webkit-details-marker{display:none}
2082
+ .dsh-super-code-detail-message summary .dsh-super-code-detail-entry-label{flex:1;min-width:0;font-size:12px}
2083
+ .dsh-super-code-detail-message summary>.dsh-super-code-glyph{width:14px;height:14px;transition:transform .12s}
2084
+ .dsh-super-code-detail-message details[open] summary>.dsh-super-code-glyph{transform:rotate(180deg)}
2085
+ .dsh-super-code-detail-message details pre{margin-top:10px;padding:8px 10px;border:1px solid var(--sc-line);border-radius:7px;background:var(--sc-bg)}
2086
+ .dsh-super-code-detail-entry button{margin:8px 0 0}
2087
+ .dsh-super-code-new-content{flex:none;align-self:center;margin:8px 16px 12px;border:1px solid var(--sc-line);border-radius:8px;padding:6px 12px;background:var(--sc-bg);font-size:13px}
2088
+ @media(hover:none) and (pointer:coarse){:where(.dsh-super-code-workspace,.dsh-super-code-settings,.dsh-super-code-memory,.dsh-super-code-tree) input{font-size:16px}}
2089
+ @media(prefers-reduced-motion:reduce){:where(.dsh-super-code-workspace,.dsh-super-code-settings,.dsh-super-code-tree,.dsh-super-code-detail,.dsh-super-code-memory,.dsh-super-code-confirm,.dsh-super-code-select) *{transition:none!important;animation:none!important}.dsh-super-code-graph-node>.dsh-super-code-circle:after{animation:none!important}}
2090
+
2091
+ /* Same custom trigger and option list for all six dropdowns. Fixed placement
2092
+ * keeps history menus visible outside the clipped graph/sidebar viewport. */
2093
+ .dsh-super-code-select{display:inline-block;min-width:0;width:100%;font-size:12px;vertical-align:middle}
2094
+ .dsh-super-code-select :is(button,div,span,svg){box-sizing:border-box}
2095
+ .dsh-super-code-select .dsh-super-code-select-trigger{display:flex;align-items:center;justify-content:space-between;gap:8px;width:100%;height:36px;min-width:0;padding:7px 10px;border:1px solid var(--sc-line);border-radius:8px;background:var(--sc-bg);color:var(--sc-text);font:inherit;text-align:left;cursor:pointer;transition:border-color .12s,background-color .12s}
2096
+ .dsh-super-code-select-trigger>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
2097
+ .dsh-super-code-select-trigger>svg{flex:none;width:14px;height:14px;color:var(--sc-muted);transition:transform .12s}
2098
+ .dsh-super-code-select-trigger[aria-expanded=true]>svg{transform:rotate(180deg)}
2099
+ .dsh-super-code-select .dsh-super-code-select-trigger:hover{background:var(--sc-hover);border-color:color-mix(in srgb,var(--sc-text) 25%,var(--sc-line))}
2100
+ .dsh-super-code-select .dsh-super-code-select-trigger[aria-expanded=true]{border-color:var(--sc-accent)}
2101
+ .dsh-super-code-select .dsh-super-code-select-trigger:focus-visible{outline:2px solid var(--sc-accent);outline-offset:2px}
2102
+ .dsh-super-code-select-trigger:disabled{opacity:.45;cursor:default}
2103
+ .dsh-super-code-select-menu{position:fixed;z-index:1200;overflow:auto;overscroll-behavior:contain;padding:4px;border:1px solid var(--sc-line);border-radius:10px;background:var(--sc-bg);color:var(--sc-text);box-shadow:0 6px 20px #0002;font-size:12px;line-height:1.5;text-align:left}
2104
+ .dsh-super-code-select-option{display:flex;align-items:center;justify-content:space-between;gap:12px;min-height:32px;padding:6px 8px;border-radius:6px;cursor:pointer}
2105
+ .dsh-super-code-select-option>span{min-width:0;overflow-wrap:anywhere}
2106
+ .dsh-super-code-select-option>svg{flex:none;width:14px;height:14px;color:var(--sc-accent);visibility:hidden}
2107
+ .dsh-super-code-select-option[aria-selected=true]{font-weight:500}
2108
+ .dsh-super-code-select-option[aria-selected=true]>svg{visibility:visible}
2109
+ .dsh-super-code-select-option[data-active=true]{background:var(--sc-selected)}
2110
+
2111
+ /* Shared action-name bubble. Fixed outside the panel avoids graph transforms
2112
+ * and scroll clipping; dialog bubbles remain in the modal's top layer. */
2113
+ .dsh-super-code-tooltip{position:fixed;z-index:1400;max-width:min(260px,calc(100vw - 16px));padding:5px 8px;border-radius:6px;background:var(--sc-text);color:var(--sc-bg);box-shadow:0 2px 8px #0002;font-size:12px;line-height:1.5;font-weight:400;text-align:left;overflow-wrap:anywhere;pointer-events:none}
2114
+ .dsh-super-code-tooltip:after{content:"";position:absolute;left:var(--sc-tooltip-arrow-left);width:6px;height:6px;background:inherit;transform:translateX(-50%) rotate(45deg)}
2115
+ .dsh-super-code-tooltip[data-side=top]:after{bottom:-3px}
1394
2116
  `
1395
2117
  document.head.appendChild(style)
1396
2118
  return () => { style.remove() }
1397
2119
  }, 'super-code: browser styles')
1398
- // Both the tree and read-only details stay in the current conversation's tabs.
2120
+ // Keep the original tree kind so restored tabs become the unified workspace.
1399
2121
  const treeId = 'dsh-super-code'
1400
2122
  const treeKind = 'super-agent-agents'
1401
2123
  const disposeTreeType = ctx.sidebarRightTabs.register({
1402
2124
  id: treeId, kind: treeKind,
1403
- title: () => t('tree.aria'),
1404
- guide: [{ order: 40, title: () => t('tree.aria'), description: () => t('tree.canvas') }],
2125
+ title: () => t('workspace.title'),
2126
+ guide: [{ order: 40, title: () => t('workspace.title'), description: () => t('workspace.description') }],
1405
2127
  })
1406
2128
  const disposeMemoryType = ctx.sidebarRightTabs.register({ id: 'dsh-super-code-memory', kind: 'super-code-memory',
1407
- patterns: ['dsh-resource://super-code-memory/**'], title: () => t('memory.title'),
1408
- guide: [{ order: 41, title: () => t('memory.title'), description: () => t('memory.description') }],
2129
+ patterns: ['dsh-resource://super-code-memory/**'], title: () => t('workspace.title'),
1409
2130
  })
1410
- const openMemory = (sessionId, row) => ctx.sidebarRight.openResource(memoryLibraryAddress(sessionId, row), { kind: 'super-code-memory' })
2131
+ const openMemory = (sessionId, row) => ctx.sidebarRight.openTab(treeKind, { params: { memory: memoryLibraryAddress(sessionId, row) } })
1411
2132
  const treeActions = {
1412
2133
  // The host unmounts hidden bodies; tab signals live until close/unload.
1413
2134
  treeStates: new WeakMap(),
@@ -1425,7 +2146,7 @@ function apply(ctx) {
1425
2146
  },
1426
2147
  })
1427
2148
  ctx.slots.inject('sidebar.right.pane.tab.title', function* () {
1428
- for (const [key, titleKey] of [[treeId, 'tree.aria'], ['dsh-super-code-memory', 'memory.title']]) {
2149
+ for (const [key, titleKey] of [[treeId, 'workspace.title'], ['dsh-super-code-memory', 'workspace.title']]) {
1429
2150
  yield ctx.slots.register({ name: 'sidebar.right.pane.tab.title', key, locale: LOCALE_NS,
1430
2151
  inject: () => ({ titleKey }),
1431
2152
  }, LocalizedTabTitle)
@@ -1438,16 +2159,19 @@ function apply(ctx) {
1438
2159
  ctx.slots.inject('sidebar.right.pane.tab', () => ctx.slots.register({
1439
2160
  name: 'sidebar.right.pane.tab', key: 'dsh-super-code-detail', locale: LOCALE_NS, inject: () => ({ ...detailActions }),
1440
2161
  }, AgentDetail))
1441
- ctx.slots.inject('sidebar.right.pane.tab', () => ctx.slots.register({
1442
- // Keyed tab bodies dispatch by the definition id, while `kind` is the
1443
- // page/content discriminator used by the Sidebar controller.
1444
- name: 'sidebar.right.pane.tab', key: treeId, locale: LOCALE_NS,
1445
- inject: () => ({ ...treeActions }),
1446
- }, AgentTree))
1447
- ctx.effect(() => disposeTreeType, 'super-code: Agent tree tab')
2162
+ ctx.inject(['remote.superCodeMemory'], ready => {
2163
+ ready.slots.inject('sidebar.right.pane.tab', function* () {
2164
+ // The hidden legacy key restores old memory tabs and resource URLs.
2165
+ for (const key of [treeId, 'dsh-super-code-memory']) yield ready.slots.register({
2166
+ name: 'sidebar.right.pane.tab', key, locale: LOCALE_NS,
2167
+ inject: () => ({ ...treeActions, api: ready.remote.superCodeMemory, memoryStates, workspaceStates }),
2168
+ }, SuperCodeWorkspace)
2169
+ })
2170
+ })
2171
+ ctx.effect(() => disposeTreeType, 'super-code: workspace tab')
1448
2172
  ctx.effect(() => disposeDetailType, 'super-code: Agent detail tab')
1449
2173
  ctx.effect(() => disposeMemoryType, 'super-code: memory library tab')
1450
2174
  }
1451
2175
 
1452
- return { inject, apply, synchronizePresetDisplay, agentSessionState, buildAgentView, visibleAgentRows, agentTreeDisplay, agentTreeTotals, agentTreeLayout, agentExecutionStatus, agentDetailAddress, agentDetailTarget, agentPath, detailRecord, createAgentInspector, agentHistoryRange, agentHistoryRows, agentHistoryWindow, memoryLibraryAddress, memoryLibraryTarget, memoryLibraryWindow }
2176
+ return { inject, apply, synchronizePresetDisplay, agentSessionState, buildAgentView, visibleAgentRows, agentTreeDisplay, agentTreeTotals, agentTreeLayout, agentExecutionStatus, agentDetailAddress, agentDetailTarget, agentPath, detailRecord, createAgentInspector, agentHistoryRange, agentHistoryRows, agentHistoryWindow, memoryLibraryAddress, memoryLibraryTarget, memoryLibraryNavigation, memoryLibraryWindow, createMemoryEditor }
1453
2177
  } })