dsh-super-code 0.1.3 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +43 -31
  2. package/client/index.js +253 -20
  3. package/cordis.patch.yml +63 -16
  4. package/docs/Changelog.md +38 -0
  5. package/docs/Compatibility.md +57 -0
  6. package/docs/EvaluationResults.md +66 -0
  7. package/docs/UsageGuide.md +110 -0
  8. package/docs/images/agent-tree-preview.png +0 -0
  9. package/docs/images/agent-tree.png +0 -0
  10. package/docs/images/preset-settings-preview.png +0 -0
  11. package/docs/images/preset-settings.png +0 -0
  12. package/lib/core/host-messages.d.ts +11 -0
  13. package/lib/core/host-messages.d.ts.map +1 -0
  14. package/lib/core/host-messages.js +13 -0
  15. package/lib/core/host-messages.js.map +1 -0
  16. package/lib/core/task-memory.d.ts +6 -0
  17. package/lib/core/task-memory.d.ts.map +1 -1
  18. package/lib/core/task-memory.js +13 -4
  19. package/lib/core/task-memory.js.map +1 -1
  20. package/lib/core/tool-evidence.d.ts.map +1 -1
  21. package/lib/core/tool-evidence.js +9 -9
  22. package/lib/core/tool-evidence.js.map +1 -1
  23. package/lib/dsh/index.d.ts +1 -1
  24. package/lib/dsh/index.d.ts.map +1 -1
  25. package/lib/dsh/index.js +23 -1
  26. package/lib/dsh/index.js.map +1 -1
  27. package/lib/dsh/memory-library.d.ts +45 -0
  28. package/lib/dsh/memory-library.d.ts.map +1 -0
  29. package/lib/dsh/memory-library.js +106 -0
  30. package/lib/dsh/memory-library.js.map +1 -0
  31. package/lib/dsh/preset-files.d.ts +26 -0
  32. package/lib/dsh/preset-files.d.ts.map +1 -0
  33. package/lib/dsh/preset-files.js +44 -0
  34. package/lib/dsh/preset-files.js.map +1 -0
  35. package/lib/dsh/preset-installation.d.ts +28 -3
  36. package/lib/dsh/preset-installation.d.ts.map +1 -1
  37. package/lib/dsh/preset-installation.js +28 -7
  38. package/lib/dsh/preset-installation.js.map +1 -1
  39. package/lib/dsh/preset-metadata.js +1 -1
  40. package/lib/dsh/preset-metadata.js.map +1 -1
  41. package/lib/dsh/super-code.d.ts.map +1 -1
  42. package/lib/dsh/super-code.js +159 -3
  43. package/lib/dsh/super-code.js.map +1 -1
  44. package/lib/index.d.ts +1 -0
  45. package/lib/index.d.ts.map +1 -1
  46. package/lib/index.js +2 -1
  47. package/lib/index.js.map +1 -1
  48. package/lib/long-memory.d.ts +75 -0
  49. package/lib/long-memory.d.ts.map +1 -0
  50. package/lib/long-memory.js +126 -0
  51. package/lib/long-memory.js.map +1 -0
  52. package/lib/memory-usage-projection.d.ts +46 -0
  53. package/lib/memory-usage-projection.d.ts.map +1 -0
  54. package/lib/memory-usage-projection.js +111 -0
  55. package/lib/memory-usage-projection.js.map +1 -0
  56. package/lib/task-memory-projection.d.ts +7 -0
  57. package/lib/task-memory-projection.d.ts.map +1 -1
  58. package/lib/task-memory-projection.js +4 -2
  59. package/lib/task-memory-projection.js.map +1 -1
  60. package/lib/task-memory-store.js +1 -1
  61. package/lib/task-memory-store.js.map +1 -1
  62. package/package.json +26 -12
package/README.md CHANGED
@@ -1,66 +1,78 @@
1
1
  # dsh-super-code
2
2
 
3
- 一个更快、更节省、更聪明的 DeepSeek Harness 编码插件。它会根据任务选择调研、设计、开发、验证和优化方法:简单任务直接完成,复杂任务按需组织工作。
3
+ 一个更快、更节省、更聪明的 DeepSeek Harness 编码插件。简单任务直接做,复杂任务按需组织专业 Agent;任务状态和有来源的经验可以留到后续对话,不必反复交代。
4
4
 
5
- A faster, more efficient, smarter coding plugin for DeepSeek Harness. It selects research, design, development, verification, and optimization methods to fit the task: straightforward work stays simple, while complex work is coordinated as needed.
5
+ A faster, more efficient coding plugin for DeepSeek Harness. It handles straightforward tasks directly, brings in specialist Agents when useful, and keeps sourced knowledge available for later conversations.
6
6
 
7
- 在选定的 SWE-bench Pro hard-100 评测中,`0.1.2` 相比 DSH minimal 平均回答耗时减少约 38%,每题输入 token 减少约 14%,正确率提高 8 个百分点。[评测方法与完整结果](docs/EvaluationResults.md)
7
+ 在同一组 SWE-bench Pro hard-100 的校正结果中,0.2.0 分层记忆候选相比官方 minimal,平均回答耗时减少 **41%**、每题总 token 减少 **20%**,通过率从 **44% 提高到 52%**。[完整结果与限制](docs/EvaluationResults.md)
8
8
 
9
- On the selected SWE-bench Pro hard-100 tasks, `0.1.2` reduced average response time by about 38% and input tokens per task by about 14% versus DSH minimal, while accuracy increased by 8 percentage points. [Methods and full results](docs/EvaluationResults.md)
9
+ On the same SWE-bench Pro hard-100 set, the corrected results for the 0.2.0 memory-hierarchy candidate show **41% less response time**, **20% fewer total tokens**, and a pass rate of **52% versus 44%** for official minimal. [Full results and limitations](docs/EvaluationResults.md)
10
+
11
+ ## 0.2.0 候选 · What's New
12
+
13
+ - **分层记忆:** 区分本次任务、当前项目和全局偏好;只自动带入少量相关摘要,需要时再读详情。
14
+ **Layered memory:** Separates task state, project knowledge, and global preferences. Only a few relevant summaries enter context; details are read when needed.
15
+ - **记忆库:** 在右侧新标签查看和搜索记忆;Agent 详情中能看到带入上下文、读取、保存和删除记录。
16
+ **Memory library:** Browse and search memories in a sidebar tab, and see each Agent's recorded context, reads, saves, and removals in its details.
17
+ - **宿主兼容:** 保留旧版目录预设,并适配新版声明式预设及消息格式。具体版本和验收范围见[兼容矩阵](docs/Compatibility.md)。
18
+ **Host compatibility:** Keeps directory presets on older hosts and supports newer declarative presets and message formats. See the [verified versions and scope](docs/Compatibility.md).
19
+
20
+ 0.2.0 当前为候选,尚未发布到 npm;发布前请使用候选安装包。效果数据来自已冻结的分层记忆实验,不是新增 UI 和兼容改动后的又一轮 100 题评测。
21
+
22
+ Version 0.2.0 is a candidate, not yet published to npm; use the candidate package before release. Its quality results belong to the frozen memory-hierarchy experiment, not a new 100-task run of the integrated UI and compatibility changes.
10
23
 
11
24
  ## 开始使用 · Get Started
12
25
 
13
- 需要 DeepSeek Harness 0.1.5-alpha.1 或更高版本。三步就能开始:
26
+ 需要 Node.js 22 或更高版本,以及[已验证的 Harness 版本](docs/Compatibility.md)。
14
27
 
15
- You'll need DeepSeek Harness 0.1.5-alpha.1 or later. To get started:
28
+ Use Node.js 22 or later and a [verified Harness version](docs/Compatibility.md).
16
29
 
17
- 1. **安装插件:** 在 `dsh-market` 搜索 `dsh-super-code`,或运行下面的命令。
30
+ 1. **安装:** 在插件市场搜索 `dsh-super-code`,或运行以下命令安装 npm 已发布版。
18
31
 
19
- **Install the plugin:** Search for `dsh-super-code` in `dsh-market`, or run:
32
+ **Install:** Search for `dsh-super-code` in the plugin marketplace, or install the published npm version:
20
33
 
21
34
  ```bash
22
35
  dsh plugin --profile web add dsh-super-code
23
36
  ```
24
37
 
25
- 2. **选中预设:** 打开 Harness“设置”→“Agent 预设”,选择 `super-code`。
38
+ 候选包可用 `dsh plugin --profile web add ./dsh-super-code-0.2.0.tgz` 安装。
39
+ For the candidate, use `dsh plugin --profile web add ./dsh-super-code-0.2.0.tgz`.
26
40
 
27
- **Select the preset:** In Harness, open “Settings” → “Agent Presets” and select `super-code`.
41
+ 2. **选中预设:** 打开“设置”→“Agent 预设”,选择 `super-code`。
28
42
 
29
- 3. **开始对话:** 新建会话,直接描述你要完成的编码任务。
43
+ **Select the preset:** Open “Settings” → “Agent Presets” and choose `super-code`.
30
44
 
31
- **Start a conversation:** Open a new conversation and describe the coding task you want done.
45
+ 3. **开始对话:** 新建会话,描述你要完成的编码任务。模型、推理等级、权限和工具沿用 Harness 的设置;子 Agent 默认继承父 Agent 的模型,不用另配模型池。
32
46
 
33
- 没看到 `super-code`?打开“设置”→“插件”→“插件配置”→ **Super Code** 查看状态并手动安装。标识符已被占用时可换一个,不会覆盖已有预设。[排查与预设管理](docs/UsageGuide.md)
47
+ **Start a conversation:** Open a new session and describe the task. Models, reasoning effort, permissions, and tools come from Harness; child Agents inherit the parent's model by default.
34
48
 
35
- Can't find `super-code`? Open “Settings” → “Plugins” → “Plugin configuration” → **Super Code** to check its status and install it manually. If the identifier is taken, choose another; existing presets are left untouched. [Troubleshooting and preset management](docs/UsageGuide.md)
49
+ 没看到预设?在“设置”→ **Super Code** 查看状态;旧插件版本的入口在“插件配置”中。[安装与排查](docs/UsageGuide.md)
36
50
 
37
- [![Super Code 配置入口 · Super Code settings](docs/images/preset-settings-preview.png)](docs/images/preset-settings.png)
38
-
39
- 模型、推理等级、权限和工具沿用 Harness 的设置;子 Agent 默认继承父 Agent 的模型选择,不用再配置一套。
51
+ Can't find the preset? Open “Settings” → **Super Code**. Older plugin versions place this under “Plugin configuration”. [Setup and troubleshooting](docs/UsageGuide.md)
40
52
 
41
- Models, reasoning effort, permissions, and tools come from Harness. Child Agents inherit the parent Agent's model choice by default, so there's no second set of settings to manage.
53
+ [![Super Code 配置入口 · Super Code settings](docs/images/preset-settings-preview.png)](docs/images/preset-settings.png)
42
54
 
43
- 任务开始后,可以在右侧 Agent 执行树查看每个 Agent 的状态与用量。拖动空白处平移,滚轮或按钮缩放;点一个节点,就能在侧栏标签中查看详情。[界面说明](docs/UsageGuide.md)
55
+ 右侧执行树显示各 Agent 的状态、用量和缓存率。拖动平移、滚轮缩放;点节点查看详情,不切换主对话。右侧新标签页中的“记忆库”可以查看当前项目和全局偏好。[界面与记忆说明](docs/UsageGuide.md)
44
56
 
45
- Once a task is running, the Agent tree on the right shows each Agent's status and usage. Drag empty space to pan, zoom with the wheel or buttons, and click a node to see its details in a sidebar tab. [Interface guide](docs/UsageGuide.md)
57
+ The Agent tree shows status, usage, and cache hit rate. Drag to pan, scroll to zoom, and click a node for details without leaving the main conversation. Open “Memory library” from the sidebar's new-tab page to view project knowledge and global preferences. [Interface and memory guide](docs/UsageGuide.md)
46
58
 
47
59
  [![Agent 执行树 · Agent execution tree](docs/images/agent-tree-preview.png)](docs/images/agent-tree.png)
48
60
 
49
61
  ## 效果 · Results
50
62
 
51
- 这组成绩来自选定的 SWE-bench Pro hard-100,使用 `deepseek-v4.1-flash`、`high` 推理等级、原生 DSH Web RPC 和官方评分器。两组都完成了 100/100 题评分。
63
+ 同一组 100 题,均完成官方评分;评分环境异常已使用原补丁复核。时间不含官方评分,token 包含缓存输入,并不等于费用。
52
64
 
53
- These results come from the selected SWE-bench Pro hard-100 tasks, using `deepseek-v4.1-flash`, `high` reasoning, native DSH Web RPC, and the official grader. Both runs received scores for all 100 tasks.
65
+ All four versions received official scores for the same 100 tasks. Grading anomalies were rechecked with the original patches. Time excludes grading; tokens include cache reads and are not a monetary cost estimate.
54
66
 
55
- | 指标 / Metric | DSH minimal | super-code 0.1.2 | 变化 / Change |
56
- |---|---:|---:|---:|
57
- | 正确率 / Accuracy | 41% | **49%** | **+8 个百分点 / +8 pp** |
58
- | 平均模型调用/题 / Model calls per task | 124.85 | 99.78 | -20.1% |
59
- | 平均输入 token/题 / Input tokens per task | 11,477,170 | 9,840,383 | -14.3% |
60
- | 平均回答耗时 / Response time | 25.69 分钟 / min | 16.01 分钟 / min | -37.7% |
67
+ | 指标 / Metric | 官方 minimal | 0.0.9 | 0.1.2 | 0.2.0 分层记忆 |
68
+ |---|---:|---:|---:|---:|
69
+ | 通过 / Passed | 44/100 | 48/100 | 52/100 | **52/100** |
70
+ | 平均耗时 / Minutes per task | 25.69 | 16.46 | 16.01 | **15.15** |
71
+ | 平均总 token / Tokens per task | 11,578,047 | 9,623,217 | 9,938,176 | **9,299,094** |
72
+ | 模型调用/题 / Model calls | 124.85 | 92.78 | 99.78 | 93.83 |
61
73
 
62
- 两次运行使用不同的 Harness 提交,不能将全部差异归因于插件。完整指标、回退题目、统计口径和逐题证据见[评测文档](docs/EvaluationResults.md)。
74
+ 0.2.0 与 0.1.2 通过数相同,但有 6 题改善、6 题回退,不代表每道题都更好。这是已用于诊断的历史题集,各轮宿主版本也不同,不能把全部差异归因于插件或记忆功能。[多维指标、逐题证据与统计口径](docs/EvaluationResults.md)
63
75
 
64
- The runs used different Harness commits, so not every difference can be attributed to the plugin. See the [evaluation details](docs/EvaluationResults.md) for all metrics, regressions, calculation methods, and per-task evidence.
76
+ Version 0.2.0 ties 0.1.2 overall, with six gains and six regressions—not an improvement on every task. This is a historically exposed diagnostic set, and host revisions differ between runs; the results do not isolate the effect of the plugin or memory alone. [Detailed metrics, per-task evidence, and methodology](docs/EvaluationResults.md)
65
77
 
66
- [使用说明 · Usage guide](docs/UsageGuide.md) · [评测详情 · Evaluation details](docs/EvaluationResults.md) · [版本记录 · Changelog](docs/Changelog.md)
78
+ [使用说明 · Usage](docs/UsageGuide.md) · [兼容性 · Compatibility](docs/Compatibility.md) · [版本记录 · Changelog](docs/Changelog.md)
package/client/index.js CHANGED
@@ -9,11 +9,24 @@
9
9
  ;(globalThis.window || globalThis).__ModuleLoader__.load({ id: 'dsh-super-code', factory: (require) => {
10
10
  const React = require('react')
11
11
  const { useEffect, useLayoutEffect, useRef, useMemo, useState, useSyncExternalStore } = React
12
- const { IconChevronDownOutline14, IconRefreshOutline16 } = require('@deepseek-ai/dsh-client-ui-primitives')
12
+ const icons = require('@deepseek-ai/dsh-client-ui-primitives')
13
+ // Harness 0.2 names shared artwork by weight instead of its nominal size.
14
+ const IconChevronDownOutline14 = icons.IconChevronDownOutlineRegular ?? icons.IconChevronDownOutline14
15
+ const IconRefreshOutline16 = icons.IconRefreshOutlineRegular ?? icons.IconRefreshOutline16
13
16
  const { SessionEventStream } = require('@deepseek-ai/dsh-api-session-controller')
14
17
 
15
18
  const LOCALE_NS = 'dshSuperCode'
16
19
  const zh = {
20
+ 'memory.title': '记忆库', 'memory.project': '当前项目', 'memory.global': '全局偏好', 'memory.search': '搜索主题或记忆',
21
+ 'memory.description': '跨对话保留的经验与偏好。按需读取,不会整库塞进上下文。',
22
+ 'memory.empty': '还没有保存的记忆。需要长期保留时,直接告诉 Agent 即可。', 'memory.noMatches': '没有匹配的记忆',
23
+ 'memory.selectSession': '先打开一个对话,查看它所在项目的记忆。', 'memory.error': '暂时无法读取记忆,请刷新重试。',
24
+ 'memory.refresh': '刷新记忆库', 'memory.count': '{count} 条记忆', 'memory.back': '返回列表', 'memory.missing': '这条记忆已删除或更新,请刷新列表。',
25
+ 'memory.historical': '历史记录,不代表当前代码仍然如此;以本次需求和实际验证为准。',
26
+ 'memory.constraint': '用户约定', 'memory.fact': '项目事实', 'memory.experience': '实践经验', 'memory.source': '来源', 'memory.version': '记录时版本',
27
+ 'memory.user': '用户消息', 'memory.tool': '工具结果', 'memory.agentUsage': '记忆使用记录', 'memory.usageHint': '只展示已记录的上下文与工具动作,不代表模型已理解或遵守。',
28
+ 'memory.usageEmpty': '尚无记忆读取记录', 'memory.context': '带入上下文', 'memory.read': '读取详情', 'memory.summary': '读取摘要',
29
+ 'memory.remember': '保存', 'memory.forget': '删除', 'memory.omitted': '仅展示最近 100 条不同动作,完整记录保留在会话中。', 'memory.open': '查看记忆库',
17
30
  'preset.title': 'Super Code 模式', 'usage.cacheUnknown': '缓存 —',
18
31
  'preset.description': '更快、更省、更聪明的编码模式。', 'preset.refresh': '刷新状态', 'preset.expand': '展开设置', 'preset.collapse': '收起设置',
19
32
  'preset.state.available': '预设可用', 'preset.state.installed': '用户预设已安装', 'preset.state.conflict': '已有同名预设',
@@ -49,6 +62,16 @@ const zh = {
49
62
  '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': '[图片]'
50
63
  }
51
64
  const en = {
65
+ 'memory.title': 'Memory library', 'memory.project': 'This project', 'memory.global': 'Global preferences', 'memory.search': 'Search topics or memories',
66
+ 'memory.description': 'Experience and preferences kept across conversations. Details are read on demand, never injected in bulk.',
67
+ 'memory.empty': 'No saved memories yet. Tell the agent when something is worth keeping.', 'memory.noMatches': 'No matching memories',
68
+ 'memory.selectSession': 'Open a conversation to view memory for its project.', 'memory.error': 'Memory is unavailable. Refresh to try again.',
69
+ 'memory.refresh': 'Refresh memory', 'memory.count': '{count} memories', 'memory.back': 'Back to list', 'memory.missing': 'This memory was removed or changed. Refresh the list.',
70
+ 'memory.historical': 'A historical record, not proof of the current code. Follow the current request and verify changing facts.',
71
+ 'memory.constraint': 'User agreement', 'memory.fact': 'Project fact', 'memory.experience': 'Experience', 'memory.source': 'Source', 'memory.version': 'Recorded version',
72
+ 'memory.user': 'User message', 'memory.tool': 'Tool result', 'memory.agentUsage': 'Memory activity', 'memory.usageHint': 'Recorded context and tool actions only; not proof the model understood or followed them.',
73
+ 'memory.usageEmpty': 'No memory reads recorded yet', 'memory.context': 'Added to context', 'memory.read': 'Read details', 'memory.summary': 'Read summary',
74
+ 'memory.remember': 'Saved', 'memory.forget': 'Removed', 'memory.omitted': 'Showing the latest 100 distinct actions. Full records remain in the conversation.', 'memory.open': 'Open memory library',
52
75
  'preset.title': 'Super Code', 'usage.cacheUnknown': 'Cache —',
53
76
  'preset.description': 'A faster, more efficient, smarter coding mode.', 'preset.refresh': 'Refresh status', 'preset.expand': 'Show settings', 'preset.collapse': 'Hide settings',
54
77
  'preset.state.available': 'Preset available', 'preset.state.installed': 'User preset installed', 'preset.state.conflict': 'Preset name already exists',
@@ -80,6 +103,21 @@ function formatText(template, values = {}) { return template.replace(/\{(\w+)\}/
80
103
  function text(t, key, values) { return formatText(t(key), values) }
81
104
  function localeCode(t) { return text(t, 'status.active') === en['status.active'] ? 'en-US' : 'zh-CN' }
82
105
 
106
+ // The registry captures a fallback title when a tab opens. Title slots receive
107
+ // live locale updates, including for tabs whose bodies are not currently shown.
108
+ function LocalizedTabTitle({ titleKey, t }) { return t(titleKey) }
109
+
110
+ function agentTabTitle(state, address, t) {
111
+ const target = agentDetailTarget(address), id = target.childSessionId || target.sessionId
112
+ const node = buildAgentView(agentSessionState(state, id)).nodes.get(id)
113
+ return node?.title || node?.displayTitle || t('detail.title')
114
+ }
115
+
116
+ function AgentDetailTitle({ useTabInfo, useSessions, t }) {
117
+ const { tab } = useTabInfo(), state = useSessions(value => value)
118
+ return agentTabTitle(state, tab.contentId, t)
119
+ }
120
+
83
121
  function TaskMemoryPanel({ state, t = key => zh[key] || key }) {
84
122
  const tasks = state?.tasks || []
85
123
  if (!tasks.length) return null
@@ -98,6 +136,29 @@ function TaskMemoryPanel({ state, t = key => zh[key] || key }) {
98
136
  )
99
137
  }
100
138
 
139
+ /** Normalize the two published host catalog shapes, without opening Agents. */
140
+ function agentSessionState(state, sessionId, statuses) {
141
+ const current = sessionId || state.current
142
+ if (state.subagentsByParent) return { ...state, current }
143
+ const snapshots = state.projectionsBySession || {}, byId = { ...state.byId }, catalogs = {}
144
+ for (const [id, snapshot] of Object.entries(snapshots)) {
145
+ byId[id] = { ...byId[id], id, projectionValues: snapshot.values,
146
+ running: statuses?.get(id)?.running ?? byId[id]?.running }
147
+ }
148
+ for (const [parentId, snapshot] of Object.entries(snapshots)) {
149
+ const entries = snapshot.values.subagentCatalog || []
150
+ catalogs[parentId] = { state: snapshot.state === 'idle' ? snapshot.values.subagentCatalog === undefined ? 'loading' : 'ready' : snapshot.state,
151
+ entries: entries.map(entry => {
152
+ const child = byId[entry.id], children = snapshots[entry.id]?.values.subagentCatalog
153
+ const running = statuses?.get(entry.id)?.running ?? child?.running
154
+ return { ...entry, hasChildren: children === undefined || children.length > 0,
155
+ kind: entry.mode === 'unknown' ? 'diagnostic' : 'child',
156
+ ...(typeof running === 'boolean' ? { activity: running ? 'running' : 'inactive' } : {}) }
157
+ }) }
158
+ }
159
+ return { ...state, current, byId, subagentsByParent: catalogs }
160
+ }
161
+
101
162
  /** Join host catalogs without leaking agents from unrelated conversations. */
102
163
  function buildAgentView(state) {
103
164
  const nodes = new Map(Object.values(state.byId || {}).map(node => [node.id, { ...node }]))
@@ -109,7 +170,7 @@ function buildAgentView(state) {
109
170
  nodes.set(entry.id, { ...summary, id: entry.id, parentId,
110
171
  title: entry.label || summary?.title || summary?.displayTitle || entry.id,
111
172
  mode: entry.mode, hasChildren: entry.hasChildren, createdAt: created.get(entry.id),
112
- running: summary?.running ?? entry.activity === 'running',
173
+ running: summary?.running ?? (entry.activity === undefined ? undefined : entry.activity === 'running'),
113
174
  unavailable: entry.kind === 'diagnostic',
114
175
  })
115
176
  }
@@ -344,8 +405,10 @@ function AgentHistory({ view, hidden, totals, open, t = key => zh[key] || key })
344
405
  !records.length && React.createElement('p', { className: 'dsh-super-code-history-empty' }, text(t, 'history.empty'))))
345
406
  }
346
407
 
347
- function AgentTree({ useSessions, useTabInfo, treeStates, openDetail, refresh, watchCatalog, t = key => zh[key] || key }) {
348
- const state = useSessions(s => s)
408
+ function AgentTree({ useSessions, useSessionStatus, sessionId, useTabInfo, treeStates, openDetail, refresh, watchCatalog, t = key => zh[key] || key }) {
409
+ const catalog = useSessions(s => s)
410
+ const statuses = useSessionStatus ? useSessionStatus(s => s) : undefined
411
+ const state = useMemo(() => agentSessionState(catalog, sessionId, statuses), [catalog, sessionId, statuses])
349
412
  const { tab } = useTabInfo()
350
413
  const view = useMemo(() => buildAgentView(state), [state.byId, state.subagentsByParent, state.current, state.currentAddress])
351
414
  const saved = useMemo(() => {
@@ -710,9 +773,130 @@ function DetailText({ text: value, t = key => zh[key] || key }) {
710
773
  !full && value.length > 12000 && React.createElement('button', { type: 'button', onClick: () => setFull(true) }, text(t, 'detail.open')))
711
774
  }
712
775
 
713
- function AgentDetail({ useTabInfo, useSessions, createInspector, detailStates, t = key => zh[key] || key }) {
776
+ function MemoryActivity({ usage, openMemory, sessionId, t }) {
777
+ const rows = [...(usage?.rows || [])].reverse()
778
+ return React.createElement('details', { className: 'dsh-super-code-memory-activity' },
779
+ React.createElement('summary', null, text(t, 'memory.agentUsage'), rows.length ? ` · ${rows.length}` : ''),
780
+ React.createElement('p', { className: 'dsh-super-code-memory-muted' }, text(t, 'memory.usageHint')),
781
+ !rows.length && React.createElement('p', null, text(t, 'memory.usageEmpty')),
782
+ React.createElement('div', { className: 'dsh-super-code-memory-activity-list' }, rows.map(row =>
783
+ React.createElement('button', { key: `${row.scope}/${row.topic}/${row.id}/${row.action}`, type: 'button',
784
+ onClick: () => openMemory(sessionId, row), title: text(t, 'memory.open') },
785
+ React.createElement('span', { className: 'dsh-super-code-memory-action', 'data-action': row.action }, text(t, `memory.${row.action}`)),
786
+ React.createElement('span', null, row.summary || row.id),
787
+ React.createElement('small', null, `${text(t, `memory.${row.scope}`)} · ${row.topic} · r${row.revision}`)))),
788
+ usage?.omitted > 0 && React.createElement('p', { className: 'dsh-super-code-memory-muted' }, text(t, 'memory.omitted')))
789
+ }
790
+
791
+ function memoryLibraryAddress(sessionId, row = {}) {
792
+ const url = new URL(`dsh-resource://super-code-memory/${encodeURIComponent(sessionId)}`)
793
+ for (const key of ['scope', 'topic', 'id']) if (row[key]) url.searchParams.set(key, row[key])
794
+ return url.href
795
+ }
796
+
797
+ function memoryLibraryTarget(address, current) {
798
+ try {
799
+ const url = new URL(address)
800
+ if (url.protocol === 'dsh-resource:' && url.host === 'super-code-memory') return {
801
+ sessionId: decodeURIComponent(url.pathname.slice(1)) || current, scope: url.searchParams.get('scope') === 'global' ? 'global' : 'project',
802
+ topic: url.searchParams.get('topic') || '', id: url.searchParams.get('id') || '',
803
+ }
804
+ } catch {}
805
+ return { sessionId: current, scope: 'project', topic: '', id: '' }
806
+ }
807
+
808
+ /** A fixed-height index keeps large libraries cheap; entry bodies load on click. */
809
+ function memoryLibraryWindow(items, query, top, height) {
810
+ const search = query.trim().toLocaleLowerCase()
811
+ const matches = items.filter(item => !search || `${item.topic} ${item.id} ${item.summary}`.toLocaleLowerCase().includes(search))
812
+ const start = Math.min(Math.max(0, Math.floor(top / 76) - 3), Math.max(0, matches.length - 1))
813
+ const end = Math.min(matches.length, start + Math.ceil(height / 76) + 7)
814
+ return { rows: matches.slice(start, end), count: matches.length, before: start * 76, after: (matches.length - end) * 76 }
815
+ }
816
+
817
+ function MemoryLibrary({ useTabInfo, useSessions, sessionId: scopeSessionId, api, memoryStates, t = key => zh[key] || key }) {
818
+ const { tab } = useTabInfo(), current = useSessions(state => scopeSessionId || state.current)
819
+ const target = memoryLibraryTarget(tab.contentId, current)
820
+ const saved = useMemo(() => {
821
+ if (!memoryStates.has(tab.signal)) memoryStates.set(tab.signal, {})
822
+ return memoryStates.get(tab.signal)
823
+ }, [memoryStates, tab.signal])
824
+ const [scope, setScope] = useState(saved.scope || target.scope)
825
+ const [query, setQuery] = useState(saved.query || '')
826
+ const [selected, setSelected] = useState(saved.selected || (target.id ? { topic: target.topic, id: target.id } : null))
827
+ const [state, setState] = useState({ key: '', items: [], loading: true, error: false })
828
+ const [detail, setDetail] = useState(null), [revision, setRevision] = useState(0)
829
+ const [viewport, setViewport] = useState({ top: saved.top || 0, height: 600 })
830
+ const list = useRef(null), sessionId = target.sessionId
831
+ const key = `${sessionId}/${scope}`, selectionKey = selected ? `${key}/${selected.topic}/${selected.id}` : ''
832
+ const visibleState = state.key === key ? state : { items: [], loading: true, error: false }
833
+ useEffect(() => {
834
+ if (!tab.visible || !sessionId) return
835
+ let cancelled = false
836
+ setState(previous => ({ ...previous, loading: true, error: false }))
837
+ api.list(sessionId, scope).then(result => {
838
+ if (!cancelled) setState({ key, items: result.ok ? result.value.items : [], loading: false, error: !result.ok })
839
+ }).catch(() => { if (!cancelled) setState({ key, items: [], loading: false, error: true }) })
840
+ return () => { cancelled = true }
841
+ }, [api, tab.visible, sessionId, scope, revision])
842
+ useEffect(() => {
843
+ if (!tab.visible || !sessionId || !selected) return
844
+ let cancelled = false
845
+ setDetail(null)
846
+ api.read(sessionId, scope, selected.topic, selected.id).then(result => {
847
+ if (!cancelled) setDetail({ key: selectionKey, ...(result.ok ? result.value : { kind: 'error' }) })
848
+ }).catch(() => { if (!cancelled) setDetail({ key: selectionKey, kind: 'error' }) })
849
+ return () => { cancelled = true }
850
+ }, [api, tab.visible, sessionId, scope, selectionKey, revision])
851
+ useLayoutEffect(() => {
852
+ const element = list.current
853
+ if (!element) return
854
+ element.scrollTop = saved.top || 0
855
+ const resize = () => setViewport({ top: element.scrollTop, height: element.clientHeight || 600 })
856
+ resize()
857
+ const observer = new ResizeObserver(resize); observer.observe(element)
858
+ return () => observer.disconnect()
859
+ }, [selected, key, tab.visible])
860
+ const resetScroll = () => { saved.top = 0; if (list.current) list.current.scrollTop = 0; setViewport(value => ({ ...value, top: 0 })) }
861
+ const choose = value => { saved.selected = value; setSelected(value) }
862
+ const page = useMemo(() => memoryLibraryWindow(visibleState.items, query, viewport.top, viewport.height), [visibleState.items, query, viewport])
863
+ const currentDetail = detail?.key === selectionKey ? detail : null
864
+ const entry = currentDetail?.kind === 'found' ? currentDetail.entry : null
865
+ return React.createElement('section', { className: 'dsh-super-code-memory', 'aria-label': text(t, 'memory.title') },
866
+ React.createElement('header', null,
867
+ React.createElement('div', { className: 'dsh-super-code-memory-heading' }, React.createElement('h2', null, text(t, 'memory.title')),
868
+ 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))),
869
+ React.createElement('p', { className: 'dsh-super-code-memory-muted' }, text(t, 'memory.description')),
870
+ React.createElement('div', { className: 'dsh-super-code-memory-scopes', role: 'group', 'aria-label': text(t, 'memory.title') },
871
+ ['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}`)))),
872
+ !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() } }),
873
+ !selected && React.createElement('small', null, text(t, 'memory.count', { count: page.count }))),
874
+ !sessionId ? React.createElement('p', { className: 'dsh-super-code-memory-empty' }, text(t, 'memory.selectSession')) : selected
875
+ ? React.createElement('div', { className: 'dsh-super-code-memory-body', 'aria-busy': !currentDetail },
876
+ React.createElement('button', { type: 'button', className: 'dsh-super-code-view-button', onClick: () => choose(null) }, `← ${text(t, 'memory.back')}`),
877
+ currentDetail?.kind === 'error' && React.createElement('p', { role: 'alert' }, text(t, 'memory.error')),
878
+ currentDetail?.kind === 'missing' && React.createElement('p', null, text(t, 'memory.missing')),
879
+ entry && React.createElement('article', null, React.createElement('small', null, `${entry.topic} · r${entry.revision} · ${text(t, `memory.${entry.kind}`)}`),
880
+ React.createElement('h3', null, entry.summary), React.createElement('p', { className: 'dsh-super-code-memory-detail' }, entry.detail),
881
+ React.createElement('p', { className: 'dsh-super-code-memory-hint' }, text(t, 'memory.historical')),
882
+ React.createElement('dl', null, React.createElement('dt', null, text(t, 'memory.source')),
883
+ React.createElement('dd', null, `${text(t, `memory.${entry.source.kind}`)} · #${entry.source.eventSeq}`, React.createElement('br'), entry.source.sessionId),
884
+ entry.sourceVersion && React.createElement(React.Fragment, null, React.createElement('dt', null, text(t, 'memory.version')), React.createElement('dd', null, entry.sourceVersion)))))
885
+ : 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 })) } },
886
+ visibleState.error && React.createElement('p', { role: 'alert' }, text(t, 'memory.error')),
887
+ !visibleState.error && !visibleState.loading && !page.count && React.createElement('p', { className: 'dsh-super-code-memory-empty' }, text(t, query ? 'memory.noMatches' : 'memory.empty')),
888
+ React.createElement('div', { 'aria-hidden': true, style: { height: page.before } }),
889
+ page.rows.map(item => React.createElement('div', { role: 'listitem', key: `${item.topic}/${item.id}` },
890
+ React.createElement('button', { type: 'button', className: 'dsh-super-code-memory-row', onClick: () => choose({ topic: item.topic, id: item.id }) },
891
+ React.createElement('strong', null, item.summary), React.createElement('span', null, `${item.topic} · ${text(t, `memory.${item.kind}`)}`)))),
892
+ React.createElement('div', { 'aria-hidden': true, style: { height: page.after } })))
893
+ }
894
+
895
+ function AgentDetail({ useTabInfo, useSessions, useSessionStatus, sessionId, createInspector, detailStates, openMemory, t = key => zh[key] || key }) {
714
896
  const { tab } = useTabInfo()
715
- const state = useSessions(s => s)
897
+ const catalog = useSessions(s => s)
898
+ const statuses = useSessionStatus ? useSessionStatus(s => s) : undefined
899
+ const state = useMemo(() => agentSessionState(catalog, sessionId, statuses), [catalog, sessionId, statuses])
716
900
  const saved = useMemo(() => {
717
901
  if (!detailStates.has(tab.signal)) detailStates.set(tab.signal, { top: 0, following: true, open: new Set(), snapshot: undefined })
718
902
  return detailStates.get(tab.signal)
@@ -753,7 +937,7 @@ function AgentDetail({ useTabInfo, useSessions, createInspector, detailStates, t
753
937
  const target = agentDetailTarget(tab.contentId), id = target.childSessionId || target.sessionId
754
938
  const view = buildAgentView(state), node = view.nodes.get(id)
755
939
  const path = agentPath(view, id)
756
- const projections = state.byId[id]?.projectionValues || snapshot.projections
940
+ const projections = { ...snapshot.projections, ...state.byId[id]?.projectionValues }
757
941
  const totals = projections.superAgentUsage?.totals || projections.tokenUsage
758
942
  const input = totals ? (totals.uncachedInputTokens || 0) + (totals.cacheReadTokens || 0) + (totals.cacheWriteTokens || 0) : 0
759
943
  const format = value => value === undefined ? text(t, 'detail.unavailable') : value.toLocaleString(localeCode(t))
@@ -774,6 +958,7 @@ function AgentDetail({ useTabInfo, useSessions, createInspector, detailStates, t
774
958
  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))),
775
959
  id !== view.root && task?.goal && task.goal !== title && React.createElement('p', { className: 'dsh-super-code-detail-task' }, task.goal),
776
960
  id === view.root && React.createElement(TaskMemoryPanel, { state: tasks, t }),
961
+ React.createElement(MemoryActivity, { usage: projections.superCodeMemoryUsage, sessionId: id, openMemory, t }),
777
962
  React.createElement('dl', { className: 'dsh-super-code-detail-metrics' },
778
963
  React.createElement('div', null, React.createElement('dt', null, text(t, 'detail.total')), React.createElement('dd', null, format(totals ? input + (totals.outputTokens || 0) : undefined))),
779
964
  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')))),
@@ -808,12 +993,13 @@ function AgentDetail({ useTabInfo, useSessions, createInspector, detailStates, t
808
993
  }
809
994
 
810
995
  // Explicit public Remote contribution; no model tools or private transport hooks.
811
- const remoteStringCodec = { mode: 'strict', typeSymbol: 'string', schema: {
996
+ const remoteStringSchema = {
812
997
  parse(value) {
813
998
  if (typeof value !== 'string') throw new TypeError('Expected a string')
814
999
  return value
815
1000
  },
816
- } }
1001
+ }
1002
+ const remoteStringCodec = { mode: 'strict', typeSymbol: 'string', schema: remoteStringSchema, create: () => remoteStringSchema }
817
1003
  const presetRemoteContribution = {
818
1004
  package: 'dsh-super-code',
819
1005
  descriptors: ['status', 'installPreset', 'reinstallPreset', 'synchronize'].map(method => ({
@@ -825,6 +1011,12 @@ const presetRemoteContribution = {
825
1011
  result: { mode: 'src-json' },
826
1012
  })),
827
1013
  }
1014
+ const memoryRemoteContribution = {
1015
+ package: 'dsh-super-code', descriptors: ['list', 'read'].map(method => ({
1016
+ id: `dsh-super-code:superCodeMemory/${method}`, service: 'superCodeMemory', namespace: 'superCodeMemory', method, invocation: { kind: 'direct' },
1017
+ parameters: (method === 'list' ? ['sessionId', 'scope'] : ['sessionId', 'scope', 'topic', 'id']).map(name => ({ name, wire: name, source: 'json', codec: remoteStringCodec })), result: { mode: 'src-json' },
1018
+ })),
1019
+ }
828
1020
 
829
1021
  // Old hosts render file metadata. Synchronize through our own Remote, then
830
1022
  // reload their cached roster only when a managed field actually changed.
@@ -903,7 +1095,7 @@ function PresetSettings({ api, t }) {
903
1095
  } else run(true)
904
1096
  }
905
1097
  const available = status && ['available', 'installed'].includes(status.state)
906
- return React.createElement('li', { className: `dsh-super-code-settings${open ? ' dsh-super-code-settings-open' : ''}` },
1098
+ return React.createElement('section', { className: `dsh-super-code-settings${open ? ' dsh-super-code-settings-open' : ''}` },
907
1099
  React.createElement('button', { type: 'button', className: 'dsh-super-code-settings-header', 'aria-expanded': open,
908
1100
  'aria-label': `${t(open ? 'preset.collapse' : 'preset.expand')}: ${t('preset.title')}`, onClick: () => setOpen(!open) },
909
1101
  React.createElement('span', { className: 'dsh-super-code-settings-head-text' },
@@ -965,12 +1157,21 @@ function apply(ctx) {
965
1157
  const t = locale.bind(LOCALE_NS)
966
1158
  // $mount creates a lifecycle effect on this same fiber; awaiting it from
967
1159
  // another effect would stall the namespace and the settings contribution.
968
- void ctx.remote.$mount(presetRemoteContribution).catch(error => console.warn('Super Code preset Remote:', error))
1160
+ void ctx.remote.$mount({ package: 'dsh-super-code', descriptors: [
1161
+ ...presetRemoteContribution.descriptors, ...memoryRemoteContribution.descriptors,
1162
+ ] }).catch(error => console.warn('Super Code Remote:', error))
1163
+ const memoryStates = new WeakMap()
1164
+ ctx.inject(['remote.superCodeMemory'], ready => {
1165
+ ready.slots.inject('sidebar.right.pane.tab', () => ready.slots.register({
1166
+ name: 'sidebar.right.pane.tab', key: 'dsh-super-code-memory', locale: LOCALE_NS,
1167
+ inject: () => ({ api: ready.remote.superCodeMemory, memoryStates }),
1168
+ }, MemoryLibrary))
1169
+ })
969
1170
  ctx.inject(['remote.superCodePresets'], ready => {
970
1171
  ready.effect(() => synchronizePresetDisplay(ready.remote.superCodePresets, locale,
971
1172
  () => window.location.reload(), error => console.warn('Super Code preset display:', error)), 'super-code: preset display')
972
- return ready.slots.inject('settings.plugin.item', () => ready.slots.register({
973
- name: 'settings.plugin.item', key: 'super-code', locale: LOCALE_NS,
1173
+ ready.slots.inject('settings.section', () => ready.slots.register({
1174
+ name: 'settings.section', id: 'super-code', order: 120, label: () => t('preset.title'), locale: LOCALE_NS,
974
1175
  inject: () => ({ api: ready.remote.superCodePresets }),
975
1176
  }, PresetSettings))
976
1177
  })
@@ -978,6 +1179,23 @@ function apply(ctx) {
978
1179
  const style = document.createElement('style')
979
1180
  style.dataset.dshSuperCode = 'true'
980
1181
  style.textContent = `
1182
+ .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)}
1183
+ .dsh-super-code-memory>header{padding:18px 18px 12px;border-bottom:1px solid var(--agent-line)}
1184
+ .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}
1185
+ .dsh-super-code-memory-muted{color:var(--agent-muted);font-size:12px;line-height:1.65;margin:10px 0}
1186
+ .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)}
1187
+ .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}
1188
+ .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}
1189
+ .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}
1190
+ .dsh-super-code-memory small{font-size:11px;color:var(--agent-muted);overflow-wrap:anywhere}
1191
+ .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}
1192
+ .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)}
1193
+ .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}
1194
+ .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}
1195
+ .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)}
1196
+ .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}
1197
+ .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)}
1198
+ .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}
981
1199
  .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-3,transparent);line-height:1.6;font-size:13px;transition:border-color .16s,background .16s}
982
1200
  .dsh-super-code-settings:hover{border-color:var(--dsw-alias-label-dimmed,#a8abb2)}.dsh-super-code-settings-open{background:var(--dsw-alias-bg-layer-2,transparent);border-color:var(--dsw-alias-label-dimmed,#a8abb2)}
983
1201
  .dsh-super-code-settings-header{width:100%;appearance:none;border:0;background:none;font:inherit;color:inherit;text-align:left;cursor:pointer;display:flex;align-items:center;gap:12px;padding:14px 16px;border-radius:12px}
@@ -1134,22 +1352,36 @@ function apply(ctx) {
1134
1352
  title: () => t('tree.aria'),
1135
1353
  guide: [{ order: 40, title: () => t('tree.aria'), description: () => t('tree.canvas') }],
1136
1354
  })
1355
+ const disposeMemoryType = ctx.sidebarRightTabs.register({ id: 'dsh-super-code-memory', kind: 'super-code-memory',
1356
+ patterns: ['dsh-resource://super-code-memory/**'], title: () => t('memory.title'),
1357
+ guide: [{ order: 41, title: () => t('memory.title'), description: () => t('memory.description') }],
1358
+ })
1359
+ const openMemory = (sessionId, row) => ctx.sidebarRight.openResource(memoryLibraryAddress(sessionId, row), { kind: 'super-code-memory' })
1137
1360
  const treeActions = {
1138
1361
  // The host unmounts hidden bodies; tab signals live until close/unload.
1139
1362
  treeStates: new WeakMap(),
1140
- refresh: id => ctx.sessions.refreshSubagents(id),
1141
- watchCatalog: (id, open) => ctx.sessions.setSubagentCatalogOpen(id, open),
1363
+ refresh: id => ctx.sessions.refreshSubagents ? ctx.sessions.refreshSubagents(id) : ctx.sessions.refreshProjections(id),
1364
+ watchCatalog: (id, open) => {
1365
+ if (ctx.sessions.setSubagentCatalogOpen) ctx.sessions.setSubagentCatalogOpen(id, open)
1366
+ else if (open) void ctx.sessions.refreshProjections(id).catch(error => console.warn('Super Code projections:', error))
1367
+ },
1142
1368
  openDetail: child => ctx.sidebarRight.openResource(agentDetailAddress(child), { kind: 'super-agent-detail' }),
1143
1369
  }
1144
1370
  const disposeDetailType = ctx.sidebarRightTabs.register({
1145
1371
  id: 'dsh-super-code-detail', kind: 'super-agent-detail', patterns: ['dsh-resource://super-agent/**'],
1146
1372
  title: address => {
1147
- const target = agentDetailTarget(address), state = ctx.sessions.list.getSnapshot()
1148
- const node = buildAgentView(state).nodes.get(target.childSessionId || target.sessionId)
1149
- return node?.title || node?.displayTitle || t('detail.title')
1373
+ return agentTabTitle(ctx.sessions.list.getSnapshot(), address, t)
1150
1374
  },
1151
1375
  })
1152
- const detailActions = { detailStates: new WeakMap(), createInspector: (address, initial) => createAgentInspector(
1376
+ ctx.slots.inject('sidebar.right.pane.tab.title', function* () {
1377
+ for (const [key, titleKey] of [[treeId, 'tree.aria'], ['dsh-super-code-memory', 'memory.title']]) {
1378
+ yield ctx.slots.register({ name: 'sidebar.right.pane.tab.title', key, locale: LOCALE_NS,
1379
+ inject: () => ({ titleKey }),
1380
+ }, LocalizedTabTitle)
1381
+ }
1382
+ yield ctx.slots.register({ name: 'sidebar.right.pane.tab.title', key: 'dsh-super-code-detail', locale: LOCALE_NS }, AgentDetailTitle)
1383
+ })
1384
+ const detailActions = { openMemory, detailStates: new WeakMap(), createInspector: (address, initial) => createAgentInspector(
1153
1385
  (target, options) => new SessionEventStream(ctx.remote, target, options), address,
1154
1386
  (request, signal) => ctx.remote.session.page(request, signal), initial, t) }
1155
1387
  ctx.slots.inject('sidebar.right.pane.tab', () => ctx.slots.register({
@@ -1163,7 +1395,8 @@ function apply(ctx) {
1163
1395
  }, AgentTree))
1164
1396
  ctx.effect(() => disposeTreeType, 'super-code: Agent tree tab')
1165
1397
  ctx.effect(() => disposeDetailType, 'super-code: Agent detail tab')
1398
+ ctx.effect(() => disposeMemoryType, 'super-code: memory library tab')
1166
1399
  }
1167
1400
 
1168
- return { inject, apply, synchronizePresetDisplay, buildAgentView, visibleAgentRows, agentTreeDisplay, agentTreeTotals, agentTreeLayout, agentExecutionStatus, agentDetailAddress, agentDetailTarget, agentPath, detailRecord, createAgentInspector, agentHistoryRange, agentHistoryRows, agentHistoryWindow }
1401
+ return { inject, apply, synchronizePresetDisplay, agentSessionState, buildAgentView, visibleAgentRows, agentTreeDisplay, agentTreeTotals, agentTreeLayout, agentExecutionStatus, agentDetailAddress, agentDetailTarget, agentPath, detailRecord, createAgentInspector, agentHistoryRange, agentHistoryRows, agentHistoryWindow, memoryLibraryAddress, memoryLibraryTarget, memoryLibraryWindow }
1169
1402
  } })