dsh-mnemon-source-runtime 0.5.10 → 0.5.12

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/lib/client.js CHANGED
@@ -11,29 +11,28 @@ window.__ModuleLoader__.load({
11
11
  var zh = {
12
12
  "nav.runtime": "运行时",
13
13
  "runtime.title": "运行时记忆",
14
- "runtime.description": "管理每轮随上下文加载的紧凑热记忆。结构化数据由统一控制层维护,并自动投影为 USER.md 与 MEMORY.md。",
15
- "runtime.total": "{count} 条热记忆",
14
+ "runtime.description": "每轮对话都会带上的紧凑记忆,保存为 USER.md 与 MEMORY.md。",
15
+ "runtime.total": "{count} 条记忆",
16
16
  "runtime.entriesAria": "运行时记忆列表",
17
17
  "runtime.scopeAria": "运行时记忆范围",
18
18
  "runtime.scopeAll": "全部",
19
19
  "runtime.filterAria": "筛选运行时记忆",
20
20
  "runtime.filterPlaceholder": "按内容筛选…",
21
- "runtime.noMatch": "没有符合当前范围与查询条件的热记忆。",
22
- "runtime.refresh": "刷新",
21
+ "runtime.noMatch": "没有符合当前范围与查询条件的记忆。",
23
22
  "runtime.hotContext": "每轮上下文",
24
- "runtime.addTitle": "添加热记忆",
25
- "runtime.addDescription": "稳定但仍需频繁使用的信息优先留在这里,长期归档由 Mnemon 记忆空间承接。",
23
+ "runtime.addTitle": "添加运行时记忆",
24
+ "runtime.addDescription": "每轮对话都会带上;长期内容请存入记忆空间。",
26
25
  "runtime.content": "运行时记忆内容",
27
26
  "runtime.placeholder": "输入一条简洁、独立、未来仍然有用的信息…",
28
- "runtime.target": "分类",
27
+ "runtime.target": "保存到",
29
28
  "runtime.importance": "重要性",
30
29
  "runtime.saving": "处理中…",
31
30
  "runtime.addButton": "添加记忆",
32
31
  "runtime.addAction": "添加",
33
32
  "runtime.target.user": "用户画像",
34
- "runtime.target.user.description": "身份、角色、习惯、表达偏好与明确的协作要求;容量整理始终留在本地,不进入记忆空间。",
33
+ "runtime.target.user.description": "身份、习惯与协作偏好;只保存在本地。",
35
34
  "runtime.target.memory": "工作记忆",
36
- "runtime.target.memory.description": "项目、环境、决策、约定、工具特性与可复用经验;容量达到上限时按主题归档到一个或多个记忆空间。",
35
+ "runtime.target.memory.description": "项目事实、约定与经验;写满时按主题归档到记忆空间。",
37
36
  "runtime.importance.critical": "关键",
38
37
  "runtime.importance.normal": "普通",
39
38
  "runtime.importance.low": "低",
@@ -52,35 +51,34 @@ window.__ModuleLoader__.load({
52
51
  "runtime.result.remove": "已从{target}移除 · 当前 {count} 条",
53
52
  "runtime.result.maintenance": "容量整理完成:已先归档到记忆空间 {spaces},再更新{target} · 当前 {count} 条",
54
53
  "runtime.result.localCompaction": "本地画像整理完成:未写入记忆空间,已更新{target} · 当前 {count} 条",
55
- "runtime.readOnly": "当前部署为只读模式;热记忆仍会进入上下文,但不能在此修改。",
54
+ "runtime.readOnly": "当前为只读模式;运行时记忆仍会进入上下文,但不能在此修改。",
56
55
  "runtime.footnote": "memories.json 是唯一事实源;两个 Markdown 文件由控制层生成,不应直接编辑。"
57
56
  };
58
57
  var en = {
59
58
  "nav.runtime": "Runtime",
60
59
  "runtime.title": "Runtime Memory",
61
- "runtime.description": "Manage compact hot memory loaded into every turn. A single control plane owns structured data and projects USER.md and MEMORY.md.",
62
- "runtime.total": "{count} hot memories",
60
+ "runtime.description": "Compact memory carried into every turn, kept as USER.md and MEMORY.md.",
61
+ "runtime.total": "{count} entries",
63
62
  "runtime.entriesAria": "Runtime memory list",
64
63
  "runtime.scopeAria": "Runtime memory scope",
65
64
  "runtime.scopeAll": "All",
66
65
  "runtime.filterAria": "Filter runtime memory",
67
66
  "runtime.filterPlaceholder": "Filter by content…",
68
- "runtime.noMatch": "No hot memory matches the current scope and query.",
69
- "runtime.refresh": "Refresh",
67
+ "runtime.noMatch": "No runtime memory matches the current scope and query.",
70
68
  "runtime.hotContext": "Every-turn context",
71
- "runtime.addTitle": "Add hot memory",
72
- "runtime.addDescription": "Keep stable, frequently useful information here; Mnemon Memory Spaces remain the durable archive.",
69
+ "runtime.addTitle": "Add runtime memory",
70
+ "runtime.addDescription": "Carried into every turn; keep long-term knowledge in Memory Spaces.",
73
71
  "runtime.content": "Runtime memory content",
74
72
  "runtime.placeholder": "Enter one compact, self-contained fact that will remain useful…",
75
- "runtime.target": "Target",
73
+ "runtime.target": "Save to",
76
74
  "runtime.importance": "Importance",
77
75
  "runtime.saving": "Working…",
78
76
  "runtime.addButton": "Add memory",
79
77
  "runtime.addAction": "Add",
80
78
  "runtime.target.user": "User Profile",
81
- "runtime.target.user.description": "Identity, role, habits, communication preferences, and explicit collaboration requirements. Capacity maintenance stays local and never enters a Memory Space.",
79
+ "runtime.target.user.description": "Identity, habits and working preferences; kept local only.",
82
80
  "runtime.target.memory": "Working Memory",
83
- "runtime.target.memory.description": "Projects, environment, decisions, conventions, tool behavior, and reusable lessons. At capacity, entries are routed into one or more topic-specific Memory Spaces.",
81
+ "runtime.target.memory.description": "Project facts, conventions and lessons; archived to Memory Spaces by topic when full.",
84
82
  "runtime.importance.critical": "Critical",
85
83
  "runtime.importance.normal": "Normal",
86
84
  "runtime.importance.low": "Low",
@@ -99,12 +97,12 @@ window.__ModuleLoader__.load({
99
97
  "runtime.result.remove": "Removed from {target} · {count} entries",
100
98
  "runtime.result.maintenance": "Capacity maintenance complete: archived to {spaces}, then updated {target} · {count} entries",
101
99
  "runtime.result.localCompaction": "Local profile compaction complete: no Memory Space write; updated {target} · {count} entries",
102
- "runtime.readOnly": "This deployment is read only. Hot memory still enters context but cannot be changed here.",
100
+ "runtime.readOnly": "Read only here: runtime memory still enters context but cannot be changed on this page.",
103
101
  "runtime.footnote": "memories.json is the only source of truth. The control plane generates both Markdown files; do not edit them directly."
104
102
  };
105
103
  //#endregion
106
104
  //#region \0source-css:/home/runner/work/dsh-mnemon/dsh-mnemon/plugins/dsh-mnemon-source-runtime/presentation/page.module.css.mjs
107
- const css$2 = ".IIa07q_runtimeComposer{border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-lg);margin-bottom:12px;padding:16px}.IIa07q_runtimeComposerHeading{justify-content:space-between;align-items:flex-start;gap:16px;margin-bottom:12px;display:flex}.IIa07q_runtimeComposerHeading h3{margin:0 0 2px;font-size:14px;font-weight:500;line-height:22px}.IIa07q_runtimeComposerHeading p{color:var(--mn-faint);margin:0;font-size:12px;line-height:18px}.IIa07q_runtimeComposerHeading>span{color:var(--mn-muted);background:var(--mn-fill);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.IIa07q_runtimeComposer>textarea,.IIa07q_runtimeEntry textarea{resize:vertical;border:.5px solid var(--mn-field-line);border-radius:var(--dsw-radius-md);width:100%;color:var(--mn-text);background:var(--mn-input);outline:0;padding:8px 10px;font-size:13px;line-height:20px}.IIa07q_runtimeComposer>textarea:focus,.IIa07q_runtimeEntry textarea:focus{border-color:var(--mn-accent)}.IIa07q_runtimeComposerActions{justify-content:flex-end;align-items:flex-end;gap:8px;margin-top:12px;display:flex}.IIa07q_runtimeComposerActions label{color:var(--mn-muted);gap:6px;font-size:12px;font-weight:500;line-height:18px;display:grid}.IIa07q_runtimeComposerActions select,.IIa07q_runtimeEntry select{border:.5px solid var(--mn-field-line);border-radius:var(--dsw-radius-md);min-width:136px;height:32px;color:var(--mn-text);background:var(--mn-input);outline:0;padding:0 10px;font-size:13px}.IIa07q_runtimeReadOnly{border-radius:var(--dsw-radius-md);color:var(--mn-muted);background:var(--mn-fill);margin-bottom:12px;padding:8px 12px;font-size:12px;line-height:18px}.IIa07q_runtimeSummaryGrid{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-bottom:12px;display:grid}.IIa07q_runtimeSummaryCard{border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-lg);min-width:0}.IIa07q_runtimeBrowser{border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-lg);overflow:hidden}.IIa07q_runtimeBrowserToolbar{border-bottom:.5px solid var(--mn-line);justify-content:space-between;align-items:center;gap:12px;padding:10px 12px;display:flex}.IIa07q_runtimeScopeFilter{border-radius:var(--dsw-radius-md);background:var(--mn-hover);flex-wrap:wrap;align-items:center;gap:2px;padding:3px;display:inline-flex}.IIa07q_runtimeScopeFilter button{border-radius:var(--dsw-radius-sm);min-height:28px;color:var(--mn-muted);cursor:pointer;background:0 0;border:0;padding:0 12px;font-size:13px;font-weight:500;line-height:20px}.IIa07q_runtimeScopeFilter button:hover{color:var(--mn-text)}.IIa07q_runtimeScopeFilter button[data-active]{color:var(--mn-text);background:var(--mn-layer-1);box-shadow:var(--dsw-elevation-soft)}.IIa07q_runtimeScopeFilter b{color:var(--mn-faint);font-variant-numeric:tabular-nums;margin-left:6px;font-size:12px;font-weight:400}.IIa07q_runtimeFilterQuery{border:.5px solid var(--mn-field-line);border-radius:var(--dsw-radius-md);background:var(--mn-input);align-items:center;gap:6px;width:min(320px,42%);min-width:210px;padding:0 10px;display:flex}.IIa07q_runtimeFilterQuery:focus-within{border-color:var(--mn-accent)}.IIa07q_runtimeFilterQuery>span{color:var(--mn-faint)}.IIa07q_runtimeFilterQuery input{width:100%;min-width:0;height:32px;color:var(--mn-text);background:0 0;border:0;outline:0;font-size:13px}.IIa07q_runtimeFilterQuery input::placeholder{color:var(--dsw-alias-label-dimmed)}.IIa07q_runtimeUnifiedList{grid-template-columns:1fr;gap:8px;padding:12px;display:grid}.IIa07q_runtimeEntryBadges{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.IIa07q_runtimeEntryMeta .IIa07q_runtimeEntryTarget{color:var(--mn-accent);background:color-mix(in srgb, var(--mn-accent) 10%, transparent)}.IIa07q_runtimeEntryMeta .IIa07q_runtimeEntryBranch{text-overflow:ellipsis;white-space:nowrap;max-width:140px;color:var(--mn-muted);background:var(--mn-fill);font-family:var(--mn-code);overflow:hidden}.IIa07q_runtimeComposerBranch{color:var(--mn-muted);gap:6px;font-size:12px;font-weight:500;line-height:18px;display:grid}.IIa07q_runtimeComposerBranch input{border:.5px solid var(--mn-field-line);border-radius:var(--dsw-radius-md);width:100%;height:32px;color:var(--mn-text);background:var(--mn-input);outline:0;padding:0 10px;font-size:13px;font-weight:400}.IIa07q_runtimeComposerBranch input:focus{border-color:var(--mn-accent)}.IIa07q_bodyEditBranch{color:var(--mn-muted);gap:6px;font-size:12px;font-weight:500;line-height:18px;display:grid}.IIa07q_bodyEditBranch input{border:.5px solid var(--mn-field-line);border-radius:var(--dsw-radius-md);width:100%;height:32px;color:var(--mn-text);background:var(--mn-input);outline:0;padding:0 10px;font-size:13px;font-weight:400}.IIa07q_bodyEditBranch input:focus{border-color:var(--mn-accent)}.IIa07q_bodyEditBranch small{color:var(--mn-faint);font-size:12px;font-weight:400}.IIa07q_runtimeTargetHeader{justify-content:space-between;align-items:center;gap:16px;padding:14px 16px 8px;display:flex}.IIa07q_runtimeTargetHeader>div{gap:0;display:grid}.IIa07q_runtimeTargetHeader span{color:var(--mn-faint);font-family:var(--mn-code);font-size:11px;line-height:16px}.IIa07q_runtimeTargetHeader h3{margin:0;font-size:14px;font-weight:500;line-height:22px}.IIa07q_runtimeTargetHeader>strong{color:var(--mn-muted);background:var(--mn-fill);font-variant-numeric:tabular-nums;border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.IIa07q_capacityLine{align-items:center;gap:10px;padding:0 16px;display:flex}.IIa07q_capacityLine>div{background:var(--mn-fill);border-radius:999px;flex:1;height:4px;overflow:hidden}.IIa07q_capacityLine i{border-radius:inherit;background:var(--dsw-alias-brand-primary);height:100%;transition:width .25s;display:block}.IIa07q_capacityLine>span{min-width:88px;color:var(--mn-faint);text-align:right;font-variant-numeric:tabular-nums;font-size:11px}.IIa07q_runtimeTargetDescription{min-height:36px;color:var(--mn-faint);margin:8px 16px 14px;font-size:12px;line-height:18px}.IIa07q_runtimeEntry{--mn-provider-color:var(--mn-accent);border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-md);padding:12px 14px 10px;position:relative}.IIa07q_runtimeEntry[data-importance=critical]{--mn-provider-color:var(--mn-priority)}.IIa07q_runtimeEntry[data-importance=low]{--mn-provider-color:var(--mn-faint)}.IIa07q_runtimeEntryMeta{justify-content:space-between;align-items:center;gap:12px;display:flex}.IIa07q_runtimeEntryMeta>span,.IIa07q_runtimeEntryBadges>span{color:var(--mn-muted);background:var(--mn-fill);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.IIa07q_runtimeEntry[data-importance=critical] .IIa07q_runtimeEntryMeta>span,.IIa07q_runtimeEntry[data-importance=critical] .IIa07q_runtimeEntryBadges>span:not(.IIa07q_runtimeEntryTarget){color:var(--mn-warn);background:color-mix(in srgb, var(--mn-warn) 12%, transparent)}.IIa07q_runtimeEntryMeta time{color:var(--mn-faint);text-overflow:ellipsis;white-space:nowrap;font-variant-numeric:tabular-nums;font-size:11px;overflow:hidden}.IIa07q_runtimeEntry>p{white-space:pre-wrap;overflow-wrap:anywhere;min-height:40px;margin:8px 0;font-size:14px;line-height:22px}.IIa07q_runtimeEntry>select{margin-top:8px}.IIa07q_runtimeEntry footer{border-top:.5px solid var(--mn-line);justify-content:flex-end;align-items:center;gap:8px;min-height:32px;margin-top:8px;padding-top:8px;display:flex}.IIa07q_runtimeEntry footer>span{color:var(--mn-danger);margin-right:auto;font-size:12px}.IIa07q_runtimeEmpty{min-height:128px;color:var(--mn-faint);text-align:center;align-content:center;place-items:center;gap:6px;display:grid}.IIa07q_runtimeEmpty>span{font-size:20px;line-height:1}.IIa07q_runtimeEmpty p{margin:0;font-size:13px;line-height:20px}@media (width<=1000px){.IIa07q_runtimeSummaryGrid{grid-template-columns:1fr}}@media (width<=760px){.IIa07q_runtimeComposerHeading,.IIa07q_runtimeComposerActions{flex-direction:column;align-items:stretch}.IIa07q_runtimeComposerActions select,.IIa07q_runtimeComposerActions button{width:100%}.IIa07q_runtimeBrowserToolbar{flex-direction:column;align-items:stretch}.IIa07q_runtimeFilterQuery{width:100%;min-width:0}}";
105
+ const css$2 = ".IIa07q_runtimeComposer{border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-lg);margin-bottom:12px;padding:16px}.IIa07q_runtimeComposerHeading{justify-content:space-between;align-items:flex-start;gap:16px;margin-bottom:12px;display:flex}.IIa07q_runtimeComposerHeading h3{margin:0 0 2px;font-size:14px;font-weight:500;line-height:22px}.IIa07q_runtimeComposerHeading p{color:var(--mn-faint);margin:0;font-size:12px;line-height:18px}.IIa07q_runtimeComposerHeading>span{color:var(--mn-muted);background:var(--mn-fill);border-radius:999px;flex:none;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.IIa07q_runtimeComposer>textarea,.IIa07q_runtimeEntry textarea{resize:vertical;border:.5px solid var(--mn-field-line);border-radius:var(--dsw-radius-md);width:100%;color:var(--mn-text);background:var(--mn-input);outline:0;padding:8px 10px;font-size:13px;line-height:20px}.IIa07q_runtimeComposer>textarea:focus,.IIa07q_runtimeEntry textarea:focus{border-color:var(--mn-accent)}.IIa07q_runtimeComposerActions{justify-content:flex-end;align-items:flex-end;gap:8px;margin-top:12px;display:flex}.IIa07q_runtimeComposerActions label{color:var(--mn-muted);gap:6px;font-size:12px;font-weight:500;line-height:18px;display:grid}.IIa07q_runtimeChoice button{min-width:136px}.IIa07q_runtimeReadOnly{border-radius:var(--dsw-radius-md);color:var(--mn-muted);background:var(--mn-fill);margin-bottom:12px;padding:8px 12px;font-size:12px;line-height:18px}.IIa07q_runtimeSummaryGrid{grid-template-columns:repeat(2,minmax(0,1fr));gap:12px;margin-bottom:12px;display:grid}.IIa07q_runtimeSummaryCard{border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-lg);min-width:0}.IIa07q_runtimeBrowser{border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-lg);overflow:hidden}.IIa07q_runtimeBrowserToolbar{border-bottom:.5px solid var(--mn-line);justify-content:space-between;align-items:center;gap:12px;padding:10px 12px;display:flex}.IIa07q_runtimeScopeFilter{border-radius:var(--dsw-radius-md);background:var(--mn-hover);flex-wrap:wrap;align-items:center;gap:2px;padding:3px;display:inline-flex}.IIa07q_runtimeScopeFilter button{border-radius:var(--dsw-radius-sm);min-height:28px;color:var(--mn-muted);cursor:pointer;background:0 0;border:0;padding:0 12px;font-size:13px;font-weight:500;line-height:20px}.IIa07q_runtimeScopeFilter button:hover{color:var(--mn-text)}.IIa07q_runtimeScopeFilter button[data-active]{color:var(--mn-text);background:var(--mn-layer-1);box-shadow:var(--dsw-elevation-soft)}.IIa07q_runtimeScopeFilter b{color:var(--mn-faint);font-variant-numeric:tabular-nums;margin-left:6px;font-size:12px;font-weight:400}.IIa07q_runtimeFilterQuery{width:min(320px,42%);min-width:210px}.IIa07q_runtimeUnifiedList{grid-template-columns:1fr;gap:8px;padding:12px;display:grid}.IIa07q_runtimeEntryBadges{flex-wrap:wrap;align-items:center;gap:6px;display:flex}.IIa07q_runtimeEntryMeta .IIa07q_runtimeEntryTarget{color:var(--mn-accent);background:color-mix(in srgb, var(--mn-accent) 10%, transparent)}.IIa07q_runtimeEntryMeta .IIa07q_runtimeEntryBranch{text-overflow:ellipsis;white-space:nowrap;max-width:140px;color:var(--mn-muted);background:var(--mn-fill);font-family:var(--mn-code);overflow:hidden}.IIa07q_runtimeComposerBranch{color:var(--mn-muted);gap:6px;font-size:12px;font-weight:500;line-height:18px;display:grid}.IIa07q_runtimeComposerBranch input{border:.5px solid var(--mn-field-line);border-radius:var(--dsw-radius-md);width:100%;height:36px;color:var(--mn-text);background:var(--mn-input);outline:0;padding:0 10px;font-size:13px;font-weight:400}.IIa07q_runtimeComposerBranch input:focus{border-color:var(--mn-accent)}.IIa07q_bodyEditBranch{color:var(--mn-muted);gap:6px;font-size:12px;font-weight:500;line-height:18px;display:grid}.IIa07q_bodyEditBranch input{border:.5px solid var(--mn-field-line);border-radius:var(--dsw-radius-md);width:100%;height:32px;color:var(--mn-text);background:var(--mn-input);outline:0;padding:0 10px;font-size:13px;font-weight:400}.IIa07q_bodyEditBranch input:focus{border-color:var(--mn-accent)}.IIa07q_bodyEditBranch small{color:var(--mn-faint);font-size:12px;font-weight:400}.IIa07q_runtimeTargetHeader{justify-content:space-between;align-items:center;gap:16px;padding:14px 16px 8px;display:flex}.IIa07q_runtimeTargetHeader>div{gap:0;display:grid}.IIa07q_runtimeTargetHeader span{color:var(--mn-faint);font-family:var(--mn-code);font-size:11px;line-height:16px}.IIa07q_runtimeTargetHeader h3{margin:0;font-size:14px;font-weight:500;line-height:22px}.IIa07q_runtimeTargetHeader>strong{color:var(--mn-muted);background:var(--mn-fill);font-variant-numeric:tabular-nums;border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.IIa07q_capacityLine{align-items:center;gap:10px;padding:0 16px;display:flex}.IIa07q_capacityLine>div{background:var(--mn-fill);border-radius:999px;flex:1;height:4px;overflow:hidden}.IIa07q_capacityLine i{border-radius:inherit;background:var(--dsw-alias-brand-primary);height:100%;transition:width .25s;display:block}.IIa07q_capacityLine>span{min-width:88px;color:var(--mn-faint);text-align:right;font-variant-numeric:tabular-nums;font-size:11px}.IIa07q_runtimeTargetDescription{min-height:36px;color:var(--mn-faint);margin:8px 16px 14px;font-size:12px;line-height:18px}.IIa07q_runtimeEntry{--mn-provider-color:var(--mn-accent);border:.5px solid var(--mn-card-line);border-radius:var(--dsw-radius-md);padding:12px 14px 10px;position:relative}.IIa07q_runtimeEntry[data-importance=critical]{--mn-provider-color:var(--mn-priority)}.IIa07q_runtimeEntry[data-importance=low]{--mn-provider-color:var(--mn-faint)}.IIa07q_runtimeEntry[data-focused]{border-color:color-mix(in srgb, var(--mn-accent) 60%, var(--mn-card-line));box-shadow:0 0 0 2px color-mix(in srgb, var(--mn-accent) 14%, transparent)}.IIa07q_runtimeEntryMeta{justify-content:space-between;align-items:center;gap:12px;display:flex}.IIa07q_runtimeEntryMeta>span,.IIa07q_runtimeEntryBadges>span{color:var(--mn-muted);background:var(--mn-fill);border-radius:999px;padding:1px 8px;font-size:11px;font-weight:500;line-height:17px}.IIa07q_runtimeEntry[data-importance=critical] .IIa07q_runtimeEntryMeta>span,.IIa07q_runtimeEntry[data-importance=critical] .IIa07q_runtimeEntryBadges>span:not(.IIa07q_runtimeEntryTarget){color:var(--mn-warn);background:color-mix(in srgb, var(--mn-warn) 12%, transparent)}.IIa07q_runtimeEntryMeta time{color:var(--mn-faint);text-overflow:ellipsis;white-space:nowrap;font-variant-numeric:tabular-nums;font-size:11px;overflow:hidden}.IIa07q_runtimeEntry>p{white-space:pre-wrap;overflow-wrap:anywhere;margin:8px 0;font-size:14px;line-height:22px}.IIa07q_runtimeEntry>select{margin-top:8px}.IIa07q_runtimeEntry footer{border-top:.5px solid var(--mn-line);justify-content:flex-end;align-items:center;gap:8px;min-height:32px;margin-top:8px;padding-top:8px;display:flex}.IIa07q_runtimeEntry footer>span{color:var(--mn-danger);margin-right:auto;font-size:12px}.IIa07q_runtimeEmpty{min-height:128px;color:var(--mn-faint);text-align:center;align-content:center;place-items:center;gap:6px;display:grid}.IIa07q_runtimeEmpty>span{font-size:20px;line-height:1}.IIa07q_runtimeEmpty p{margin:0;font-size:13px;line-height:20px}@media (width<=1000px){.IIa07q_runtimeSummaryGrid{grid-template-columns:1fr}}@media (width<=760px){.IIa07q_runtimeComposerHeading,.IIa07q_runtimeComposerActions{flex-direction:column;align-items:stretch}.IIa07q_runtimeComposerActions>*,.IIa07q_runtimeComposerActions button{width:100%}.IIa07q_runtimeBrowserToolbar{flex-direction:column;align-items:stretch}.IIa07q_runtimeFilterQuery{width:100%;min-width:0}}";
108
106
  const id$1 = "dsh-mnemon-source-runtime/presentation/page.module.css";
109
107
  if (typeof document !== "undefined") {
110
108
  let tag = document.querySelector("style[data-plugin-css=" + JSON.stringify(id$1) + "]");
@@ -120,6 +118,7 @@ window.__ModuleLoader__.load({
120
118
  "capacityLine": "IIa07q_capacityLine",
121
119
  "runtimeBrowser": "IIa07q_runtimeBrowser",
122
120
  "runtimeBrowserToolbar": "IIa07q_runtimeBrowserToolbar",
121
+ "runtimeChoice": "IIa07q_runtimeChoice",
123
122
  "runtimeComposer": "IIa07q_runtimeComposer",
124
123
  "runtimeComposerActions": "IIa07q_runtimeComposerActions",
125
124
  "runtimeComposerBranch": "IIa07q_runtimeComposerBranch",
@@ -178,6 +177,10 @@ window.__ModuleLoader__.load({
178
177
  }
179
178
  //#endregion
180
179
  //#region src/client/pages.tsx
180
+ /** Whitespace folded, as a conversation turn quotes an entry it wrote. */
181
+ function fold(text) {
182
+ return text.replace(/\s+/gu, " ").trim();
183
+ }
181
184
  function RuntimePage(props) {
182
185
  const t = useT();
183
186
  const locale = (0, dsh_mnemon_client.useLocale)();
@@ -203,6 +206,10 @@ window.__ModuleLoader__.load({
203
206
  const [filterTarget, setFilterTarget] = (0, react.useState)("all");
204
207
  const [filterQuery, setFilterQuery] = (0, react.useState)("");
205
208
  const [visibleLimit, setVisibleLimit] = (0, react.useState)(pageSize);
209
+ const listRef = (0, react.useRef)(null);
210
+ const revealed = (0, react.useRef)(false);
211
+ const focus = props.focusText === void 0 ? "" : fold(props.focusText).replace(/…$/u, "");
212
+ const focused = (entry) => focus !== "" && fold(entry.content).startsWith(focus);
206
213
  const load = (0, react.useCallback)(async () => {
207
214
  setLoading(true);
208
215
  setError(null);
@@ -220,6 +227,19 @@ window.__ModuleLoader__.load({
220
227
  (0, react.useEffect)(() => {
221
228
  setVisibleLimit(pageSize);
222
229
  }, [filterQuery, filterTarget]);
230
+ (0, react.useEffect)(() => {
231
+ if (focus === "" || snapshot === null) return;
232
+ const index = filteredEntries.findIndex(focused);
233
+ if (index >= visibleLimit) {
234
+ setVisibleLimit(Math.ceil((index + 1) / pageSize) * pageSize);
235
+ return;
236
+ }
237
+ const element = listRef.current?.querySelector("[data-focused]");
238
+ if (element === null || element === void 0 || revealed.current) return;
239
+ revealed.current = true;
240
+ if (props.onRevealElement !== void 0) props.onRevealElement(element);
241
+ else element.scrollIntoView?.({ block: "nearest" });
242
+ }, [snapshot, visibleLimit]);
223
243
  const entryKey = (entry) => `${entry.target}:${entry.created_at}:${entry.content}`;
224
244
  const mutate = async (request) => {
225
245
  setNotice(null);
@@ -315,6 +335,7 @@ window.__ModuleLoader__.load({
315
335
  className: css.runtimeEntry,
316
336
  "data-importance": entry.importance,
317
337
  "data-target": entry.target,
338
+ "data-focused": focused(entry) || void 0,
318
339
  children: [
319
340
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
320
341
  className: css.runtimeEntryMeta,
@@ -390,6 +411,14 @@ window.__ModuleLoader__.load({
390
411
  setContent("");
391
412
  setAdding(false);
392
413
  };
414
+ const importanceOptions = [
415
+ "critical",
416
+ "normal",
417
+ "low"
418
+ ].map((value) => ({
419
+ value,
420
+ label: t(`runtime.importance.${value}`)
421
+ }));
393
422
  const composer = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
394
423
  id: runtimeAddFormId,
395
424
  className: css.runtimeComposer,
@@ -409,35 +438,26 @@ window.__ModuleLoader__.load({
409
438
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
410
439
  className: css.runtimeComposerActions,
411
440
  children: [
412
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [t("runtime.target"), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
441
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.SelectField, {
442
+ className: css.runtimeChoice,
443
+ label: t("runtime.target"),
413
444
  value: target,
414
- onChange: (event) => setTarget(event.target.value),
415
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
445
+ options: [{
416
446
  value: "memory",
417
- children: t("runtime.target.memory")
418
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
447
+ label: t("runtime.target.memory")
448
+ }, {
419
449
  value: "user",
420
- children: t("runtime.target.user")
421
- })]
422
- })] }),
423
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [t("runtime.importance"), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
450
+ label: t("runtime.target.user")
451
+ }],
452
+ onChange: setTarget
453
+ }),
454
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.SelectField, {
455
+ className: css.runtimeChoice,
456
+ label: t("runtime.importance"),
424
457
  value: importance,
425
- onChange: (event) => setImportance(event.target.value),
426
- children: [
427
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
428
- value: "critical",
429
- children: t("runtime.importance.critical")
430
- }),
431
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
432
- value: "normal",
433
- children: t("runtime.importance.normal")
434
- }),
435
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
436
- value: "low",
437
- children: t("runtime.importance.low")
438
- })
439
- ]
440
- })] }),
458
+ options: importanceOptions,
459
+ onChange: setImportance
460
+ }),
441
461
  target === "memory" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
442
462
  className: css.runtimeComposerBranch,
443
463
  children: [t("runtime.branches"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
@@ -467,25 +487,13 @@ window.__ModuleLoader__.load({
467
487
  onChange: (event) => setEditContent(event.target.value),
468
488
  rows: 7
469
489
  })] }),
470
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [t("runtime.importance"), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
471
- "aria-label": t("runtime.importance"),
490
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.SelectField, {
491
+ className: css.runtimeChoice,
492
+ label: t("runtime.importance"),
472
493
  value: editImportance,
473
- onChange: (event) => setEditImportance(event.target.value),
474
- children: [
475
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
476
- value: "critical",
477
- children: t("runtime.importance.critical")
478
- }),
479
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
480
- value: "normal",
481
- children: t("runtime.importance.normal")
482
- }),
483
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
484
- value: "low",
485
- children: t("runtime.importance.low")
486
- })
487
- ]
488
- })] }),
494
+ options: importanceOptions,
495
+ onChange: setEditImportance
496
+ }),
489
497
  editingEntry.target === "memory" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
490
498
  className: css.bodyEditBranch,
491
499
  children: [
@@ -508,18 +516,12 @@ window.__ModuleLoader__.load({
508
516
  title: t("runtime.title"),
509
517
  description: t("runtime.description"),
510
518
  meta: snapshot === null ? t("common.loading") : t("runtime.total", { count: snapshot.entries.length }),
511
- action: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
512
- type: "button",
513
- className: css.secondaryButton,
514
- disabled: loading,
515
- onClick: () => void load(),
516
- children: t("runtime.refresh")
517
- }), props.writeEnabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
519
+ ...props.writeEnabled ? { action: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
518
520
  type: "button",
519
521
  className: css.primaryButton,
520
522
  onClick: () => setAdding(true),
521
523
  children: t("runtime.addButton")
522
- })] })
524
+ }) } : {}
523
525
  }),
524
526
  error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
525
527
  className: css.inlineError,
@@ -580,20 +582,16 @@ window.__ModuleLoader__.load({
580
582
  ]
581
583
  })
582
584
  ]
583
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
585
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.SearchField, {
584
586
  className: css.runtimeFilterQuery,
585
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
586
- "aria-hidden": "true",
587
- children: "⌕"
588
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
589
- "aria-label": t("runtime.filterAria"),
590
- value: filterQuery,
591
- onChange: (event) => setFilterQuery(event.target.value),
592
- placeholder: t("runtime.filterPlaceholder")
593
- })]
587
+ label: t("runtime.filterAria"),
588
+ value: filterQuery,
589
+ onChange: (event) => setFilterQuery(event.target.value),
590
+ placeholder: t("runtime.filterPlaceholder")
594
591
  })]
595
592
  }),
596
593
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
594
+ ref: listRef,
597
595
  className: css.runtimeUnifiedList,
598
596
  children: [visibleEntries.map((entry) => runtimeEntry(entry, true)), !loading && filteredEntries.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
599
597
  className: css.runtimeEmpty,
@@ -622,7 +620,7 @@ window.__ModuleLoader__.load({
622
620
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
623
621
  type: "button",
624
622
  "data-dialog-close": true,
625
- className: css.ghostButton,
623
+ className: css.secondaryButton,
626
624
  disabled: saving,
627
625
  onClick: closeComposer,
628
626
  children: t("common.cancel")
@@ -646,7 +644,7 @@ window.__ModuleLoader__.load({
646
644
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
647
645
  type: "button",
648
646
  "data-dialog-close": true,
649
- className: css.ghostButton,
647
+ className: css.secondaryButton,
650
648
  disabled: saving,
651
649
  onClick: () => setEditing(null),
652
650
  children: t("common.cancel")
@@ -671,7 +669,7 @@ window.__ModuleLoader__.load({
671
669
  type: "button",
672
670
  "data-dialog-close": true,
673
671
  "data-autofocus": true,
674
- className: css.ghostButton,
672
+ className: css.secondaryButton,
675
673
  disabled: saving,
676
674
  onClick: () => setRemoving(null),
677
675
  children: t("common.cancel")
@@ -712,8 +710,18 @@ window.__ModuleLoader__.load({
712
710
  function RuntimeSourceView(props) {
713
711
  const client = (0, react.useMemo)(() => props.management === void 0 ? void 0 : runtimePageClient(props.management), [props.management]);
714
712
  const [revision, setRevision] = (0, react.useState)(0);
713
+ const refreshKey = (0, react.useRef)(props.refreshKey);
714
+ (0, react.useEffect)(() => {
715
+ if (refreshKey.current === props.refreshKey) return;
716
+ refreshKey.current = props.refreshKey;
717
+ setRevision((value) => value + 1);
718
+ }, [props.refreshKey]);
715
719
  if (client === void 0) return null;
720
+ const navigation = props.navigationInput;
721
+ const focus = typeof navigation === "object" && navigation !== null && !Array.isArray(navigation) && typeof navigation.seed === "string" && navigation.seed !== "" ? navigation : void 0;
716
722
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RuntimePage, {
723
+ ...focus === void 0 ? {} : { focusText: focus.seed },
724
+ ...props.onRevealElement === void 0 ? {} : { onRevealElement: props.onRevealElement },
717
725
  client,
718
726
  revision,
719
727
  writeEnabled: props.writable === true,
@@ -721,7 +729,7 @@ window.__ModuleLoader__.load({
721
729
  setRevision((value) => value + 1);
722
730
  props.onRefresh?.();
723
731
  }
724
- });
732
+ }, typeof focus?.nonce === "number" ? focus.nonce : 0);
725
733
  }
726
734
  function RuntimeSourcePage(props) {
727
735
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(dsh_mnemon_client.MemorySourcePageFrame, {
package/lib/index.js CHANGED
@@ -267,12 +267,14 @@ function prepareMutation(before, request, now) {
267
267
  }
268
268
  function compactionCandidates(compacted, existing, target, now) {
269
269
  const seen = /* @__PURE__ */ new Set();
270
+ const existingByContent = /* @__PURE__ */ new Map();
271
+ for (const entry of existing) if (!existingByContent.has(entry.content)) existingByContent.set(entry.content, entry);
270
272
  return compacted.map((entry) => {
271
273
  const content = normalizeContent(entry.content, "compacted content");
272
274
  if (!isImportance(entry.importance)) throw new Error("compacted importance must be critical, normal, or low");
273
275
  if (seen.has(content)) throw new Error("compacted runtime memory contains duplicate entries");
274
276
  seen.add(content);
275
- const unchanged = existing.find((current) => current.content === content);
277
+ const unchanged = existingByContent.get(content);
276
278
  const inheritedBranches = entry.branches ?? unchanged?.branches;
277
279
  return {
278
280
  content,
@@ -285,21 +287,28 @@ function compactionCandidates(compacted, existing, target, now) {
285
287
  });
286
288
  }
287
289
  function packCompactionCandidates(replacements, target, maxBytes) {
288
- const priority = {
289
- critical: 0,
290
- normal: 1,
291
- low: 2
290
+ const ranked = {
291
+ critical: [],
292
+ normal: [],
293
+ low: []
292
294
  };
293
- const ranked = replacements.map((entry, index) => ({
294
- entry,
295
- index
296
- })).sort((left, right) => priority[left.entry.importance] - priority[right.entry.importance] || left.index - right.index);
295
+ replacements.forEach((entry, index) => ranked[entry.importance].push(index));
297
296
  const selected = /* @__PURE__ */ new Set();
298
- const packed = [];
299
- for (const candidate of ranked) {
300
- if (byteCount([...packed, candidate.entry], target) > maxBytes) continue;
301
- packed.push(candidate.entry);
302
- selected.add(candidate.index);
297
+ const delimiterBytes = Buffer.byteLength(RUNTIME_ENTRY_DELIMITER, "utf8");
298
+ let used = 0;
299
+ let count = 0;
300
+ for (const importance of [
301
+ "critical",
302
+ "normal",
303
+ "low"
304
+ ]) for (const index of ranked[importance]) {
305
+ const entry = replacements[index];
306
+ const matchesTarget = entry.target === target;
307
+ const added = matchesTarget ? Buffer.byteLength(entry.content, "utf8") + (count === 0 ? 0 : delimiterBytes) : 0;
308
+ if (used + added > maxBytes) continue;
309
+ used += added;
310
+ if (matchesTarget) count += 1;
311
+ selected.add(index);
303
312
  }
304
313
  return replacements.filter((_, index) => selected.has(index));
305
314
  }
@@ -4,5 +4,7 @@ export declare function RuntimePage(props: {
4
4
  client: RuntimePageClient;
5
5
  revision: number;
6
6
  writeEnabled: boolean;
7
+ focusText?: string;
8
+ onRevealElement?(element: HTMLElement): void;
7
9
  onMutate: () => void;
8
10
  }): JSX.Element;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-mnemon-source-runtime",
3
- "version": "0.5.10",
3
+ "version": "0.5.12",
4
4
  "description": "Self-contained runtime Source for Composable View Memory.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -51,7 +51,7 @@
51
51
  },
52
52
  "peerDependencies": {
53
53
  "@deepseek-ai/cordis": "^4.0.1",
54
- "dsh-mnemon": "^0.5.1",
54
+ "dsh-mnemon": "^0.5.19",
55
55
  "react": "^18.2.0"
56
56
  },
57
57
  "devDependencies": {
@@ -60,7 +60,7 @@
60
60
  "@types/node": "^22.0.0",
61
61
  "@types/react": "^18.3.0",
62
62
  "@types/react-dom": "^18.3.0",
63
- "dsh-mnemon": "^0.5.17",
63
+ "dsh-mnemon": "^0.5.23",
64
64
  "jsdom": "^26.0.0",
65
65
  "react": "^18.2.0",
66
66
  "react-dom": "^18.2.0",
@@ -2,29 +2,28 @@
2
2
  "zh": {
3
3
  "nav.runtime": "运行时",
4
4
  "runtime.title": "运行时记忆",
5
- "runtime.description": "管理每轮随上下文加载的紧凑热记忆。结构化数据由统一控制层维护,并自动投影为 USER.md 与 MEMORY.md。",
6
- "runtime.total": "{count} 条热记忆",
5
+ "runtime.description": "每轮对话都会带上的紧凑记忆,保存为 USER.md 与 MEMORY.md。",
6
+ "runtime.total": "{count} 条记忆",
7
7
  "runtime.entriesAria": "运行时记忆列表",
8
8
  "runtime.scopeAria": "运行时记忆范围",
9
9
  "runtime.scopeAll": "全部",
10
10
  "runtime.filterAria": "筛选运行时记忆",
11
11
  "runtime.filterPlaceholder": "按内容筛选…",
12
- "runtime.noMatch": "没有符合当前范围与查询条件的热记忆。",
13
- "runtime.refresh": "刷新",
12
+ "runtime.noMatch": "没有符合当前范围与查询条件的记忆。",
14
13
  "runtime.hotContext": "每轮上下文",
15
- "runtime.addTitle": "添加热记忆",
16
- "runtime.addDescription": "稳定但仍需频繁使用的信息优先留在这里,长期归档由 Mnemon 记忆空间承接。",
14
+ "runtime.addTitle": "添加运行时记忆",
15
+ "runtime.addDescription": "每轮对话都会带上;长期内容请存入记忆空间。",
17
16
  "runtime.content": "运行时记忆内容",
18
17
  "runtime.placeholder": "输入一条简洁、独立、未来仍然有用的信息…",
19
- "runtime.target": "分类",
18
+ "runtime.target": "保存到",
20
19
  "runtime.importance": "重要性",
21
20
  "runtime.saving": "处理中…",
22
21
  "runtime.addButton": "添加记忆",
23
22
  "runtime.addAction": "添加",
24
23
  "runtime.target.user": "用户画像",
25
- "runtime.target.user.description": "身份、角色、习惯、表达偏好与明确的协作要求;容量整理始终留在本地,不进入记忆空间。",
24
+ "runtime.target.user.description": "身份、习惯与协作偏好;只保存在本地。",
26
25
  "runtime.target.memory": "工作记忆",
27
- "runtime.target.memory.description": "项目、环境、决策、约定、工具特性与可复用经验;容量达到上限时按主题归档到一个或多个记忆空间。",
26
+ "runtime.target.memory.description": "项目事实、约定与经验;写满时按主题归档到记忆空间。",
28
27
  "runtime.importance.critical": "关键",
29
28
  "runtime.importance.normal": "普通",
30
29
  "runtime.importance.low": "低",
@@ -43,35 +42,34 @@
43
42
  "runtime.result.remove": "已从{target}移除 · 当前 {count} 条",
44
43
  "runtime.result.maintenance": "容量整理完成:已先归档到记忆空间 {spaces},再更新{target} · 当前 {count} 条",
45
44
  "runtime.result.localCompaction": "本地画像整理完成:未写入记忆空间,已更新{target} · 当前 {count} 条",
46
- "runtime.readOnly": "当前部署为只读模式;热记忆仍会进入上下文,但不能在此修改。",
45
+ "runtime.readOnly": "当前为只读模式;运行时记忆仍会进入上下文,但不能在此修改。",
47
46
  "runtime.footnote": "memories.json 是唯一事实源;两个 Markdown 文件由控制层生成,不应直接编辑。"
48
47
  },
49
48
  "en": {
50
49
  "nav.runtime": "Runtime",
51
50
  "runtime.title": "Runtime Memory",
52
- "runtime.description": "Manage compact hot memory loaded into every turn. A single control plane owns structured data and projects USER.md and MEMORY.md.",
53
- "runtime.total": "{count} hot memories",
51
+ "runtime.description": "Compact memory carried into every turn, kept as USER.md and MEMORY.md.",
52
+ "runtime.total": "{count} entries",
54
53
  "runtime.entriesAria": "Runtime memory list",
55
54
  "runtime.scopeAria": "Runtime memory scope",
56
55
  "runtime.scopeAll": "All",
57
56
  "runtime.filterAria": "Filter runtime memory",
58
57
  "runtime.filterPlaceholder": "Filter by content…",
59
- "runtime.noMatch": "No hot memory matches the current scope and query.",
60
- "runtime.refresh": "Refresh",
58
+ "runtime.noMatch": "No runtime memory matches the current scope and query.",
61
59
  "runtime.hotContext": "Every-turn context",
62
- "runtime.addTitle": "Add hot memory",
63
- "runtime.addDescription": "Keep stable, frequently useful information here; Mnemon Memory Spaces remain the durable archive.",
60
+ "runtime.addTitle": "Add runtime memory",
61
+ "runtime.addDescription": "Carried into every turn; keep long-term knowledge in Memory Spaces.",
64
62
  "runtime.content": "Runtime memory content",
65
63
  "runtime.placeholder": "Enter one compact, self-contained fact that will remain useful…",
66
- "runtime.target": "Target",
64
+ "runtime.target": "Save to",
67
65
  "runtime.importance": "Importance",
68
66
  "runtime.saving": "Working…",
69
67
  "runtime.addButton": "Add memory",
70
68
  "runtime.addAction": "Add",
71
69
  "runtime.target.user": "User Profile",
72
- "runtime.target.user.description": "Identity, role, habits, communication preferences, and explicit collaboration requirements. Capacity maintenance stays local and never enters a Memory Space.",
70
+ "runtime.target.user.description": "Identity, habits and working preferences; kept local only.",
73
71
  "runtime.target.memory": "Working Memory",
74
- "runtime.target.memory.description": "Projects, environment, decisions, conventions, tool behavior, and reusable lessons. At capacity, entries are routed into one or more topic-specific Memory Spaces.",
72
+ "runtime.target.memory.description": "Project facts, conventions and lessons; archived to Memory Spaces by topic when full.",
75
73
  "runtime.importance.critical": "Critical",
76
74
  "runtime.importance.normal": "Normal",
77
75
  "runtime.importance.low": "Low",
@@ -90,7 +88,7 @@
90
88
  "runtime.result.remove": "Removed from {target} · {count} entries",
91
89
  "runtime.result.maintenance": "Capacity maintenance complete: archived to {spaces}, then updated {target} · {count} entries",
92
90
  "runtime.result.localCompaction": "Local profile compaction complete: no Memory Space write; updated {target} · {count} entries",
93
- "runtime.readOnly": "This deployment is read only. Hot memory still enters context but cannot be changed here.",
91
+ "runtime.readOnly": "Read only here: runtime memory still enters context but cannot be changed on this page.",
94
92
  "runtime.footnote": "memories.json is the only source of truth. The control plane generates both Markdown files; do not edit them directly."
95
93
  }
96
94
  }
@@ -10,8 +10,7 @@
10
10
  .runtimeEntry textarea:focus { border-color: var(--mn-accent); }
11
11
  .runtimeComposerActions { display: flex; align-items: flex-end; justify-content: flex-end; gap: 8px; margin-top: 12px; }
12
12
  .runtimeComposerActions label { display: grid; gap: 6px; color: var(--mn-muted); font-size: 12px; font-weight: 500; line-height: 18px; }
13
- .runtimeComposerActions select,
14
- .runtimeEntry select { min-width: 136px; height: 32px; border: .5px solid var(--mn-field-line); border-radius: var(--dsw-radius-md); outline: 0; padding: 0 10px; color: var(--mn-text); background: var(--mn-input); font-size: 13px; }
13
+ .runtimeChoice button { min-width: 136px; }
15
14
  .runtimeReadOnly { margin-bottom: 12px; padding: 8px 12px; border-radius: var(--dsw-radius-md); color: var(--mn-muted); background: var(--mn-fill); font-size: 12px; line-height: 18px; }
16
15
  .runtimeSummaryGrid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; margin-bottom: 12px; }
17
16
  .runtimeSummaryCard { min-width: 0; border: .5px solid var(--mn-card-line); border-radius: var(--dsw-radius-lg); }
@@ -23,17 +22,13 @@
23
22
  .runtimeScopeFilter button:hover { color: var(--mn-text); }
24
23
  .runtimeScopeFilter button[data-active] { color: var(--mn-text); background: var(--mn-layer-1); box-shadow: var(--dsw-elevation-soft); }
25
24
  .runtimeScopeFilter b { margin-left: 6px; color: var(--mn-faint); font-size: 12px; font-weight: 400; font-variant-numeric: tabular-nums; }
26
- .runtimeFilterQuery { display: flex; width: min(320px, 42%); min-width: 210px; align-items: center; gap: 6px; border: .5px solid var(--mn-field-line); border-radius: var(--dsw-radius-md); padding: 0 10px; background: var(--mn-input); }
27
- .runtimeFilterQuery:focus-within { border-color: var(--mn-accent); }
28
- .runtimeFilterQuery > span { color: var(--mn-faint); }
29
- .runtimeFilterQuery input { width: 100%; min-width: 0; height: 32px; border: 0; outline: 0; color: var(--mn-text); background: transparent; font-size: 13px; }
30
- .runtimeFilterQuery input::placeholder { color: var(--dsw-alias-label-dimmed); }
25
+ .runtimeFilterQuery { width: min(320px, 42%); min-width: 210px; }
31
26
  .runtimeUnifiedList { display: grid; grid-template-columns: 1fr; gap: 8px; padding: 12px; }
32
27
  .runtimeEntryBadges { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
33
28
  .runtimeEntryMeta .runtimeEntryTarget { color: var(--mn-accent); background: color-mix(in srgb, var(--mn-accent) 10%, transparent); }
34
29
  .runtimeEntryMeta .runtimeEntryBranch { max-width: 140px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--mn-muted); background: var(--mn-fill); font-family: var(--mn-code); }
35
30
  .runtimeComposerBranch { display: grid; gap: 6px; color: var(--mn-muted); font-size: 12px; font-weight: 500; line-height: 18px; }
36
- .runtimeComposerBranch input { width: 100%; height: 32px; border: .5px solid var(--mn-field-line); border-radius: var(--dsw-radius-md); outline: 0; padding: 0 10px; color: var(--mn-text); background: var(--mn-input); font-size: 13px; font-weight: 400; }
31
+ .runtimeComposerBranch input { width: 100%; height: 36px; border: .5px solid var(--mn-field-line); border-radius: var(--dsw-radius-md); outline: 0; padding: 0 10px; color: var(--mn-text); background: var(--mn-input); font-size: 13px; font-weight: 400; }
37
32
  .runtimeComposerBranch input:focus { border-color: var(--mn-accent); }
38
33
  .bodyEditBranch { display: grid; gap: 6px; color: var(--mn-muted); font-size: 12px; font-weight: 500; line-height: 18px; }
39
34
  .bodyEditBranch input { width: 100%; height: 32px; border: .5px solid var(--mn-field-line); border-radius: var(--dsw-radius-md); outline: 0; padding: 0 10px; color: var(--mn-text); background: var(--mn-input); font-size: 13px; font-weight: 400; }
@@ -52,13 +47,15 @@
52
47
  .runtimeEntry { --mn-provider-color: var(--mn-accent); position: relative; padding: 12px 14px 10px; border: .5px solid var(--mn-card-line); border-radius: var(--dsw-radius-md); }
53
48
  .runtimeEntry[data-importance="critical"] { --mn-provider-color: var(--mn-priority); }
54
49
  .runtimeEntry[data-importance="low"] { --mn-provider-color: var(--mn-faint); }
50
+ /* The entry a conversation turn wrote, when the turn opened this page. */
51
+ .runtimeEntry[data-focused] { border-color: color-mix(in srgb, var(--mn-accent) 60%, var(--mn-card-line)); box-shadow: 0 0 0 2px color-mix(in srgb, var(--mn-accent) 14%, transparent); }
55
52
  .runtimeEntryMeta { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
56
53
  .runtimeEntryMeta > span,
57
54
  .runtimeEntryBadges > span { padding: 1px 8px; border-radius: 999px; color: var(--mn-muted); background: var(--mn-fill); font-size: 11px; font-weight: 500; line-height: 17px; }
58
55
  .runtimeEntry[data-importance="critical"] .runtimeEntryMeta > span,
59
56
  .runtimeEntry[data-importance="critical"] .runtimeEntryBadges > span:not(.runtimeEntryTarget) { color: var(--mn-warn); background: color-mix(in srgb, var(--mn-warn) 12%, transparent); }
60
57
  .runtimeEntryMeta time { overflow: hidden; color: var(--mn-faint); font-size: 11px; text-overflow: ellipsis; white-space: nowrap; font-variant-numeric: tabular-nums; }
61
- .runtimeEntry > p { min-height: 40px; margin: 8px 0; white-space: pre-wrap; overflow-wrap: anywhere; font-size: 14px; line-height: 22px; }
58
+ .runtimeEntry > p { margin: 8px 0; white-space: pre-wrap; overflow-wrap: anywhere; font-size: 14px; line-height: 22px; }
62
59
  .runtimeEntry > select { margin-top: 8px; }
63
60
  .runtimeEntry footer { display: flex; min-height: 32px; align-items: center; justify-content: flex-end; gap: 8px; margin-top: 8px; padding-top: 8px; border-top: .5px solid var(--mn-line); }
64
61
  .runtimeEntry footer > span { margin-right: auto; color: var(--mn-danger); font-size: 12px; }
@@ -73,7 +70,7 @@
73
70
  @media (max-width: 760px) {
74
71
  .runtimeComposerHeading,
75
72
  .runtimeComposerActions { align-items: stretch; flex-direction: column; }
76
- .runtimeComposerActions select,
73
+ .runtimeComposerActions > *,
77
74
  .runtimeComposerActions button { width: 100%; }
78
75
  .runtimeBrowserToolbar { align-items: stretch; flex-direction: column; }
79
76
  .runtimeFilterQuery { width: 100%; min-width: 0; }