@yolk_vat-y/dsh-project-memory 0.4.4 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/client/client.js CHANGED
@@ -49,7 +49,41 @@ window.__ModuleLoader__.load({
49
49
  "minibar.current": "当前任务",
50
50
  "minibar.click-expand": "点击展开并同步",
51
51
  "minibar.tasks": "个任务",
52
- "minibar.no-task": "暂无任务 · 点击查看"
52
+ "minibar.no-task": "暂无任务 · 点击查看",
53
+ "view.cycle": "切换视图:任务 / 项目记忆 / 全局记忆",
54
+ "view.task": "任务",
55
+ "view.project": "项目记忆",
56
+ "view.global": "全局记忆",
57
+ "mem.scope.task": "本任务草稿",
58
+ "mem.scope.project": "项目记忆",
59
+ "mem.scope.global": "全局记忆",
60
+ "mem.empty": "暂无记忆条目(反思或 save_lesson 后出现)",
61
+ "mem.confirm": "审核",
62
+ "mem.promote": "提升",
63
+ "mem.demote": "降级",
64
+ "mem.archive": "归档",
65
+ "mem.restore": "恢复",
66
+ "mem.delete": "删除",
67
+ "mem.draft": "草稿",
68
+ "mem.archived": "已归档",
69
+ "mem.loading": "加载中…",
70
+ "mem.error": "同步失败",
71
+ "mem.kind.lesson": "坑",
72
+ "mem.kind.decision": "权衡",
73
+ "mem.kind.procedure": "指南",
74
+ "mem.kind.experience": "经验",
75
+ "mem.needs-bound": "需绑定任务后可降级",
76
+ "mem.new": "新建",
77
+ "mem.save": "保存",
78
+ "mem.cancel": "取消",
79
+ "mem.f.title": "标题(教训模式/主题/指南名)",
80
+ "mem.f.kind": "类型",
81
+ "mem.f.body": "做法 / 理由 / 解法",
82
+ "mem.f.steps": "步骤(每行一步)",
83
+ "mem.f.trigger": "作为 Skill:触发关键词(逗号分隔)",
84
+ "mem.saved": "已保存",
85
+ "mem.edit": "编辑",
86
+ "mem.section-label": "任务记忆"
53
87
  };
54
88
  const en = {
55
89
  "panel.title": "Task Flow",
@@ -89,7 +123,41 @@ window.__ModuleLoader__.load({
89
123
  "minibar.current": "Current task",
90
124
  "minibar.click-expand": "Click to expand & sync",
91
125
  "minibar.tasks": "tasks",
92
- "minibar.no-task": "No tasks · click to view"
126
+ "minibar.no-task": "No tasks · click to view",
127
+ "view.cycle": "Switch view: tasks / project memory / global memory",
128
+ "view.task": "Tasks",
129
+ "view.project": "Project Memory",
130
+ "view.global": "Global Memory",
131
+ "mem.scope.task": "Task drafts",
132
+ "mem.scope.project": "Project memory",
133
+ "mem.scope.global": "Global memory",
134
+ "mem.empty": "No memory entries yet (created by reflection or save_lesson)",
135
+ "mem.confirm": "Approve",
136
+ "mem.promote": "Promote",
137
+ "mem.demote": "Demote",
138
+ "mem.archive": "Archive",
139
+ "mem.restore": "Restore",
140
+ "mem.delete": "Delete",
141
+ "mem.draft": "draft",
142
+ "mem.archived": "archived",
143
+ "mem.loading": "Loading…",
144
+ "mem.error": "Sync failed",
145
+ "mem.kind.lesson": "lesson",
146
+ "mem.kind.decision": "decision",
147
+ "mem.kind.procedure": "procedure",
148
+ "mem.kind.experience": "experience",
149
+ "mem.needs-bound": "Bind a task to demote",
150
+ "mem.new": "New",
151
+ "mem.save": "Save",
152
+ "mem.cancel": "Cancel",
153
+ "mem.f.title": "Title (pattern / topic / procedure name)",
154
+ "mem.f.kind": "Kind",
155
+ "mem.f.body": "Fix / reason / solution",
156
+ "mem.f.steps": "Steps (one per line)",
157
+ "mem.f.trigger": "As Skill: trigger keywords (comma separated)",
158
+ "mem.saved": "Saved",
159
+ "mem.edit": "Edit",
160
+ "mem.section-label": "Task memory"
93
161
  };
94
162
  function createTranslate(dict) {
95
163
  return (key, params) => {
@@ -136,7 +204,13 @@ window.__ModuleLoader__.load({
136
204
  };
137
205
  const dataListeners = /* @__PURE__ */ new Set();
138
206
  function setDataState(next) {
139
- dataState = next;
207
+ const patch = typeof next === "function" ? next(dataState) : next;
208
+ dataState = {
209
+ tasks: Array.isArray(patch?.tasks) ? patch.tasks : [],
210
+ boundTaskId: patch?.boundTaskId ?? null,
211
+ archivedCount: typeof patch?.archivedCount === "number" ? patch.archivedCount : 0,
212
+ lastUpdate: typeof patch?.lastUpdate === "number" ? patch.lastUpdate : 0
213
+ };
140
214
  for (const listener of dataListeners) listener();
141
215
  }
142
216
  function broadcastDataUpdate(tasks, archivedCount) {
@@ -144,7 +218,7 @@ window.__ModuleLoader__.load({
144
218
  SYNC_CHANNEL.postMessage({
145
219
  type: "PROJECT_TASKS_UPDATED",
146
220
  payload: {
147
- tasks,
221
+ tasks: Array.isArray(tasks) ? tasks : [],
148
222
  archivedCount
149
223
  }
150
224
  });
@@ -155,8 +229,8 @@ window.__ModuleLoader__.load({
155
229
  const { tasks, archivedCount } = msg.payload;
156
230
  setDataState((prev) => ({
157
231
  ...prev,
158
- tasks: tasks || [],
159
- archivedCount: archivedCount ?? 0,
232
+ tasks: Array.isArray(tasks) ? tasks : [],
233
+ archivedCount: typeof archivedCount === "number" ? archivedCount : prev.archivedCount,
160
234
  lastUpdate: Date.now()
161
235
  }));
162
236
  }
@@ -487,7 +561,7 @@ window.__ModuleLoader__.load({
487
561
  }
488
562
  //#endregion
489
563
  //#region \0dsh-css:/home/sxt/project/dsh-project-memory/src/client/TaskPanel.module.css.mjs
490
- const css$1 = ".vZSZnG_panel{pointer-events:auto;background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-base,#fff));border:1px solid var(--dsw-alias-border-l2,#7f7f7f4d);border-radius:14px;flex-direction:column;width:380px;max-width:calc(100vw - 24px);max-height:min(70vh,640px);font-family:inherit;animation:.18s ease-out vZSZnG_panelIn;display:flex;position:fixed;overflow:hidden;box-shadow:0 12px 32px #00000029,0 2px 8px #00000014}@keyframes vZSZnG_panelIn{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}.vZSZnG_dragHandle{cursor:grab;z-index:1;justify-content:center;align-items:center;height:12px;display:flex;position:absolute;top:0;left:0;right:0}.vZSZnG_dragHandle:active{cursor:grabbing}.vZSZnG_handleGrip{background:var(--dsw-alias-separator-primary,#7f7f7f59);opacity:.8;border-radius:2px;width:32px;height:3px}.vZSZnG_header{border-bottom:1px solid var(--dsw-alias-border-l1,#7f7f7f2e);-webkit-user-select:none;user-select:none;justify-content:space-between;align-items:center;gap:8px;padding:10px 10px 8px 14px;display:flex}.vZSZnG_headerLeft{align-items:center;gap:6px;min-width:0;display:flex}.vZSZnG_headerIcon{color:var(--dsw-alias-label-secondary);flex:none}.vZSZnG_headerTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;margin:0;font-size:13px;font-weight:600;line-height:20px}.vZSZnG_headerRight{align-items:center;gap:2px;margin-left:auto;display:flex}.vZSZnG_counts{color:var(--dsw-alias-label-tertiary);white-space:nowrap;margin-right:4px;font-size:11px;line-height:16px}.vZSZnG_boundBadge{color:var(--dsw-alias-label-primary-foreground,#fff);background:var(--dsw-alias-button-primary-fill,#3a6ef5);white-space:nowrap;border-radius:7px;flex:none;padding:0 6px;font-size:10px;line-height:14px}.vZSZnG_notice{color:var(--dsw-alias-state-warn-label,#b7791f);background:var(--dsw-alias-interactive-bg-hover,#7f7f7f1a);word-break:break-all;border-radius:8px;margin:8px 12px 0;padding:6px 10px;font-size:12px;line-height:18px}.vZSZnG_taskList{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,transparent) transparent;flex-direction:column;gap:6px;padding:8px;display:flex;overflow-y:auto}.vZSZnG_emptyState{text-align:center;color:var(--dsw-alias-label-secondary);padding:36px 24px 30px}.vZSZnG_emptyTitle{color:var(--dsw-alias-label-primary);margin:0 0 6px;font-size:13px;font-weight:600}.vZSZnG_emptyDesc{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:20px}.vZSZnG_syncHint{color:var(--dsw-alias-label-dimmed);justify-content:center;align-items:center;gap:6px;margin:10px 0 0;font-size:11px;display:flex}.vZSZnG_card{border:1px solid var(--dsw-alias-border-l1,#7f7f7f29);background:var(--dsw-alias-bg-base,transparent);border-radius:10px;transition:border-color .15s;overflow:hidden}.vZSZnG_cardBound{border-color:var(--dsw-alias-border-l3,#7f7f7f59);box-shadow:inset 0 0 0 .5px var(--dsw-alias-border-l3,transparent)}.vZSZnG_cardHead{cursor:pointer;text-align:left;background:0 0;border:none;justify-content:space-between;align-items:center;gap:8px;width:100%;padding:8px 10px 7px;display:flex}.vZSZnG_cardHead:hover{background:var(--dsw-alias-interactive-bg-hover,#7f7f7f14)}.vZSZnG_cardTitleRow{align-items:center;gap:6px;min-width:0;display:flex}.vZSZnG_cardTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;font-size:13px;font-weight:500;line-height:20px;overflow:hidden}.vZSZnG_cardMeta{color:var(--dsw-alias-label-tertiary);flex:none;align-items:center;gap:8px;display:flex}.vZSZnG_progressText{font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-secondary);font-size:11px;line-height:16px}.vZSZnG_updated{color:var(--dsw-alias-label-dimmed);font-size:10px;line-height:14px}.vZSZnG_chevron{color:var(--dsw-alias-label-tertiary);display:inline-flex}.vZSZnG_track{background:var(--dsw-alias-interactive-bg-hover,#7f7f7f1f);border-radius:1px;height:2px;margin:0 10px 6px;overflow:hidden}.vZSZnG_trackFill{background:var(--dsw-alias-label-primary-bluish,var(--dsw-alias-button-primary-fill,#3a6ef5));border-radius:1px;height:100%;transition:width .2s}.vZSZnG_cardBody{border-top:1px solid var(--dsw-alias-border-l1,#7f7f7f24);overscroll-behavior:contain;max-height:300px;padding:8px 10px 10px;overflow-y:auto}.vZSZnG_section{margin-bottom:8px}.vZSZnG_section:last-child{margin-bottom:0}.vZSZnG_sectionLabel{color:var(--dsw-alias-label-secondary);align-items:center;gap:6px;margin-bottom:4px;font-size:11px;line-height:16px;display:flex}.vZSZnG_sectionCount{background:var(--dsw-alias-interactive-bg-hover,#7f7f7f1a);color:var(--dsw-alias-label-tertiary);border-radius:6px;padding:0 5px;font-size:10px;line-height:14px}.vZSZnG_stepsList{flex-direction:column;gap:1px;margin:0;padding:0;list-style:none;display:flex}.vZSZnG_stepRow{align-items:flex-start;gap:7px;padding:3px 2px;display:flex}.vZSZnG_stepRow>svg{flex:none;margin-top:2px}.vZSZnG_stepDone{color:var(--dsw-alias-label-dimmed)}.vZSZnG_stepRun{color:var(--dsw-alias-label-primary-bluish,#3a6ef5)}.vZSZnG_stepPending{background:var(--dsw-alias-border-l3,#7f7f7f80);border-radius:50%;flex:none;width:8px;height:8px;margin:5px 3px}.vZSZnG_stepContent{color:var(--dsw-alias-label-secondary);word-break:break-word;font-size:12px;line-height:20px}.vZSZnG_stepContentDone{color:var(--dsw-alias-label-dimmed);text-decoration:line-through}.vZSZnG_stepContentRun{color:var(--dsw-alias-label-primary)}.vZSZnG_muted{color:var(--dsw-alias-label-dimmed);font-size:11px;line-height:18px}.vZSZnG_filesList{flex-direction:column;margin:0;padding:0;list-style:none;display:flex}.vZSZnG_fileRow{cursor:pointer;text-align:left;background:0 0;border:none;border-radius:6px;align-items:center;gap:6px;width:100%;padding:3px 4px;display:flex}.vZSZnG_fileRow:hover{background:var(--dsw-alias-interactive-bg-hover,#7f7f7f14)}.vZSZnG_fileDot{background:var(--dsw-alias-border-l3,#7f7f7f80);border-radius:50%;flex:none;width:5px;height:5px}.vZSZnG_filePath{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;text-align:left;direction:rtl;font-family:ui-monospace,SF Mono,Menlo,Consolas,monospace;font-size:11px;line-height:18px;overflow:hidden}.vZSZnG_fileLine{color:var(--dsw-alias-label-dimmed);flex:none;font-size:10px;line-height:18px}.vZSZnG_cardFooter{gap:6px;margin-top:8px;display:flex}@media (prefers-reduced-motion:reduce){.vZSZnG_panel{animation:none}.vZSZnG_trackFill,.vZSZnG_card{transition:none}}.vZSZnG_miniBar{border:1px solid var(--dsw-alias-border-l3,#7f7f7f4d);background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-base,#fff));max-width:min(46vw,340px);height:34px;color:var(--dsw-alias-label-primary);cursor:grab;-webkit-user-select:none;user-select:none;pointer-events:auto;border-radius:999px;align-items:center;gap:7px;padding:0 12px;font-size:12px;line-height:18px;transition:background .15s,border-color .15s;display:inline-flex;position:fixed;box-shadow:0 6px 20px #00000024,0 1px 4px #00000014}.vZSZnG_miniBar:active{cursor:grabbing}.vZSZnG_miniBar:hover{background:var(--dsw-alias-interactive-bg-hover,#7f7f7f14)}.vZSZnG_miniIcon{color:var(--dsw-alias-label-secondary);flex:none}.vZSZnG_miniText{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.vZSZnG_miniChevron{color:var(--dsw-alias-label-tertiary);flex:none}.vZSZnG_taskList{flex:auto;min-height:0}.vZSZnG_card{flex-direction:column;display:flex}.vZSZnG_boundaryFallback{border:1px solid var(--dsw-alias-border-l3,#7f7f7f4d);background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-secondary);cursor:pointer;pointer-events:auto;border-radius:999px;padding:4px 10px;font-size:12px;line-height:18px;position:fixed;top:64px;right:16px}.vZSZnG_stepToggle{cursor:pointer;background:0 0;border:none;border-radius:4px;flex:none;align-items:center;margin-top:2px;padding:0;display:inline-flex}.vZSZnG_stepToggle:hover{background:var(--dsw-alias-interactive-bg-hover,#7f7f7f1f)}.vZSZnG_stepToggle:disabled{cursor:default;opacity:.5}.vZSZnG_stepEditable{cursor:text;border-radius:3px}.vZSZnG_stepEditable:hover{outline:1px dashed var(--dsw-alias-border-l3,#7f7f7f66);outline-offset:1px}.vZSZnG_stepInput{box-sizing:border-box;width:auto;min-width:0;font:inherit;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base,transparent);border:1px solid var(--dsw-alias-border-l3,#7f7f7f73);border-radius:5px;flex:auto;padding:0 5px;font-size:12px;line-height:20px}.vZSZnG_stepDragging{opacity:.3;background:var(--dsw-alias-interactive-bg-hover,#7f7f7f14)}.vZSZnG_cardTitleEditable{cursor:text;border-radius:3px}.vZSZnG_cardTitleEditable:hover{outline:1px dashed var(--dsw-alias-border-l3,#7f7f7f66);outline-offset:1px}.vZSZnG_panel[data-theme=glass],.vZSZnG_miniBar[data-theme=glass]{background:color-mix(in srgb, var(--dsw-alias-bg-layer-2,#fff) 90%, transparent);-webkit-backdrop-filter:blur(18px)saturate(1.2);border:1px solid color-mix(in srgb, var(--dsw-alias-border-l2,#7f7f7f4d) 80%, transparent)}.vZSZnG_panel[data-theme=glass] .vZSZnG_card{background:color-mix(in srgb, var(--dsw-alias-bg-base,transparent) 84%, transparent);border-color:color-mix(in srgb, var(--dsw-alias-border-l1,#7f7f7f29) 60%, transparent)}.vZSZnG_panel[data-theme=glass] .vZSZnG_cardBody{border-top-color:color-mix(in srgb, var(--dsw-alias-border-l1,#7f7f7f24) 60%, transparent)}@media (prefers-reduced-transparency:reduce){.vZSZnG_panel[data-theme=glass],.vZSZnG_miniBar[data-theme=glass]{background:var(--dsw-alias-bg-layer-2,#fff);-webkit-backdrop-filter:none;backdrop-filter:none}.vZSZnG_panel[data-theme=glass] .vZSZnG_card{background:var(--dsw-alias-bg-base,transparent)}}@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){.vZSZnG_panel[data-theme=glass],.vZSZnG_miniBar[data-theme=glass]{background:var(--dsw-alias-bg-layer-2,#fff)}}.vZSZnG_panel[data-theme=brutal]{box-shadow:none;border-width:1px;border-radius:6px}.vZSZnG_panel[data-theme=brutal] .vZSZnG_card{border:1px solid var(--dsw-alias-border-l3,#7f7f7f6b);background:var(--dsw-alias-bg-base,transparent);box-shadow:none;border-radius:3px}.vZSZnG_panel[data-theme=brutal] .vZSZnG_cardHead{padding:7px 10px 6px}.vZSZnG_panel[data-theme=brutal] .vZSZnG_cardTitle{letter-spacing:.01em;font-weight:650}.vZSZnG_panel[data-theme=brutal] .vZSZnG_headerTitle{letter-spacing:.03em}.vZSZnG_panel[data-theme=brutal] .vZSZnG_boundBadge{border-radius:2px}.vZSZnG_panel[data-theme=brutal] .vZSZnG_track{border-radius:0;height:3px}.vZSZnG_panel[data-theme=brutal] .vZSZnG_trackFill{border-radius:0}.vZSZnG_panel[data-theme=brutal] .vZSZnG_cardBody{border-top:1px solid var(--dsw-alias-border-l2,#7f7f7f3d)}.vZSZnG_panel[data-theme=mono] .vZSZnG_headerTitle,.vZSZnG_panel[data-theme=mono] .vZSZnG_counts,.vZSZnG_panel[data-theme=mono] .vZSZnG_cardTitle,.vZSZnG_panel[data-theme=mono] .vZSZnG_progressText,.vZSZnG_panel[data-theme=mono] .vZSZnG_stepContent,.vZSZnG_panel[data-theme=mono] .vZSZnG_filePath{font-family:ui-monospace,SF Mono,Menlo,Consolas,Liberation Mono,monospace}.vZSZnG_panel[data-theme=mono] .vZSZnG_cardTitle{font-size:12px}.vZSZnG_panel[data-theme=mono] .vZSZnG_stepContent{font-size:11.5px}.vZSZnG_panel[data-theme=mono] .vZSZnG_card{border-radius:5px}.vZSZnG_panel[data-theme=mono] .vZSZnG_trackFill{border-radius:0}.vZSZnG_panel[data-theme=mono] .vZSZnG_stepPending{border-radius:1px}.vZSZnG_panel[data-theme=mono] .vZSZnG_updated{letter-spacing:.02em}.vZSZnG_headerIconBtn{color:inherit;cursor:pointer;background:0 0;border:none;border-radius:0;flex:none;justify-content:center;align-items:center;margin:0;padding:0;display:inline-flex}.vZSZnG_headerIcon{color:var(--dsw-alias-label-secondary);flex:none;display:block}.vZSZnG_headerLeft{min-width:0}.vZSZnG_headerTitle{text-overflow:ellipsis;flex:0 auto;min-width:0;overflow:hidden}.vZSZnG_headerRight{min-width:0}.vZSZnG_counts{text-overflow:ellipsis;flex:none;max-width:45%;margin-left:auto;overflow:hidden}.vZSZnG_dragGhost{pointer-events:none;z-index:9999;transition:left 50ms,top 50ms;position:fixed;transform:translate(-50%,-50%)}.vZSZnG_dragGhostCard{background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-base,#fff));border:1px solid var(--dsw-alias-border-l3,#7f7f7f59);color:var(--dsw-alias-label-primary);white-space:nowrap;border-radius:8px;align-items:center;gap:8px;max-width:280px;padding:8px 12px;font-size:12px;line-height:20px;display:inline-flex;transform:scale(.9);box-shadow:0 8px 24px #0000002e,0 2px 8px #0000001a}.vZSZnG_dragGhostContent{text-overflow:ellipsis;word-break:break-word;flex:1;min-width:0;overflow:hidden}.vZSZnG_dragGhostClose{width:20px;height:20px;color:var(--dsw-alias-label-tertiary);cursor:pointer;opacity:.6;background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;margin-left:8px;font-size:16px;line-height:1;transition:opacity .15s,background .15s,color .15s;display:inline-flex}.vZSZnG_dragGhostClose:hover{opacity:1;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover,#7f7f7f1f)}.vZSZnG_dropTargetBefore{position:relative}.vZSZnG_dropTargetBefore:before{content:\"\";background:var(--dsw-alias-button-primary-fill,#3a6ef5);height:2px;box-shadow:0 0 4px var(--dsw-alias-button-primary-fill,#3a6ef5);border-radius:1px;animation:.8s ease-in-out infinite vZSZnG_dropPulse;position:absolute;top:-1px;left:0;right:0}.vZSZnG_dropTargetAfter{position:relative}.vZSZnG_dropTargetAfter:after{content:\"\";background:var(--dsw-alias-button-primary-fill,#3a6ef5);height:2px;box-shadow:0 0 4px var(--dsw-alias-button-primary-fill,#3a6ef5);border-radius:1px;animation:.8s ease-in-out infinite vZSZnG_dropPulse;position:absolute;bottom:-1px;left:0;right:0}@keyframes vZSZnG_dropPulse{0%,to{opacity:.6}50%{opacity:1}}";
564
+ const css$1 = ".vZSZnG_panel{pointer-events:auto;background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-base,#fff));border:1px solid var(--dsw-alias-border-l2,#7f7f7f4d);border-radius:14px;flex-direction:column;width:380px;max-width:calc(100vw - 24px);max-height:min(70vh,640px);font-family:inherit;animation:.18s ease-out vZSZnG_panelIn;display:flex;position:fixed;overflow:hidden;box-shadow:0 12px 32px #00000029,0 2px 8px #00000014}@keyframes vZSZnG_panelIn{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}.vZSZnG_dragHandle{cursor:grab;z-index:1;justify-content:center;align-items:center;height:12px;display:flex;position:absolute;top:0;left:0;right:0}.vZSZnG_dragHandle:active{cursor:grabbing}.vZSZnG_handleGrip{background:var(--dsw-alias-separator-primary,#7f7f7f59);opacity:.8;border-radius:2px;width:32px;height:3px}.vZSZnG_header{border-bottom:1px solid var(--dsw-alias-border-l1,#7f7f7f2e);-webkit-user-select:none;user-select:none;justify-content:space-between;align-items:center;gap:8px;padding:10px 10px 8px 14px;display:flex}.vZSZnG_headerLeft{align-items:center;gap:6px;min-width:0;display:flex}.vZSZnG_headerIcon{color:var(--dsw-alias-label-secondary);flex:none}.vZSZnG_headerTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;margin:0;font-size:13px;font-weight:600;line-height:20px}.vZSZnG_headerRight{align-items:center;gap:2px;margin-left:auto;display:flex}.vZSZnG_counts{color:var(--dsw-alias-label-tertiary);white-space:nowrap;margin-right:4px;font-size:11px;line-height:16px}.vZSZnG_boundBadge{color:var(--dsw-alias-label-primary-foreground,#fff);background:var(--dsw-alias-button-primary-fill,#3a6ef5);white-space:nowrap;border-radius:7px;flex:none;padding:0 6px;font-size:10px;line-height:14px}.vZSZnG_notice{color:var(--dsw-alias-state-warn-label,#b7791f);background:var(--dsw-alias-interactive-bg-hover,#7f7f7f1a);word-break:break-all;border-radius:8px;margin:8px 12px 0;padding:6px 10px;font-size:12px;line-height:18px}.vZSZnG_taskList{scrollbar-width:thin;scrollbar-color:var(--dsw-alias-scrollbar-bg-l2,transparent) transparent;flex-direction:column;gap:6px;padding:8px;display:flex;overflow-y:auto}.vZSZnG_emptyState{text-align:center;color:var(--dsw-alias-label-secondary);padding:36px 24px 30px}.vZSZnG_emptyTitle{color:var(--dsw-alias-label-primary);margin:0 0 6px;font-size:13px;font-weight:600}.vZSZnG_emptyDesc{color:var(--dsw-alias-label-tertiary);margin:0;font-size:12px;line-height:20px}.vZSZnG_syncHint{color:var(--dsw-alias-label-dimmed);justify-content:center;align-items:center;gap:6px;margin:10px 0 0;font-size:11px;display:flex}.vZSZnG_card{border:1px solid var(--dsw-alias-border-l1,#7f7f7f29);background:var(--dsw-alias-bg-base,transparent);border-radius:10px;transition:border-color .15s;overflow:hidden}.vZSZnG_cardBound{border-color:var(--dsw-alias-border-l3,#7f7f7f59);box-shadow:inset 0 0 0 .5px var(--dsw-alias-border-l3,transparent)}.vZSZnG_cardHead{cursor:pointer;text-align:left;background:0 0;border:none;justify-content:space-between;align-items:center;gap:8px;width:100%;padding:8px 10px 7px;display:flex}.vZSZnG_cardHead:hover{background:var(--dsw-alias-interactive-bg-hover,#7f7f7f14)}.vZSZnG_cardTitleRow{align-items:center;gap:6px;min-width:0;display:flex}.vZSZnG_cardTitle{color:var(--dsw-alias-label-primary);white-space:nowrap;text-overflow:ellipsis;font-size:13px;font-weight:500;line-height:20px;overflow:hidden}.vZSZnG_cardMeta{color:var(--dsw-alias-label-tertiary);flex:none;align-items:center;gap:8px;display:flex}.vZSZnG_progressText{font-variant-numeric:tabular-nums;color:var(--dsw-alias-label-secondary);font-size:11px;line-height:16px}.vZSZnG_updated{color:var(--dsw-alias-label-dimmed);font-size:10px;line-height:14px}.vZSZnG_chevron{color:var(--dsw-alias-label-tertiary);display:inline-flex}.vZSZnG_track{background:var(--dsw-alias-interactive-bg-hover,#7f7f7f1f);border-radius:1px;height:2px;margin:0 10px 6px;overflow:hidden}.vZSZnG_trackFill{background:var(--dsw-alias-label-primary-bluish,var(--dsw-alias-button-primary-fill,#3a6ef5));border-radius:1px;height:100%;transition:width .2s}.vZSZnG_cardBody{border-top:1px solid var(--dsw-alias-border-l1,#7f7f7f24);overscroll-behavior:contain;max-height:300px;padding:8px 10px 10px;overflow-y:auto}.vZSZnG_section{margin-bottom:8px}.vZSZnG_section:last-child{margin-bottom:0}.vZSZnG_sectionLabel{color:var(--dsw-alias-label-secondary);align-items:center;gap:6px;margin-bottom:4px;font-size:11px;line-height:16px;display:flex}.vZSZnG_sectionCount{background:var(--dsw-alias-interactive-bg-hover,#7f7f7f1a);color:var(--dsw-alias-label-tertiary);border-radius:6px;padding:0 5px;font-size:10px;line-height:14px}.vZSZnG_stepsList{flex-direction:column;gap:1px;margin:0;padding:0;list-style:none;display:flex}.vZSZnG_stepRow{align-items:flex-start;gap:7px;padding:3px 2px;display:flex}.vZSZnG_stepRow>svg{flex:none;margin-top:2px}.vZSZnG_stepDone{color:var(--dsw-alias-label-dimmed)}.vZSZnG_stepRun{color:var(--dsw-alias-label-primary-bluish,#3a6ef5)}.vZSZnG_stepPending{background:var(--dsw-alias-border-l3,#7f7f7f80);border-radius:50%;flex:none;width:8px;height:8px;margin:5px 3px}.vZSZnG_stepContent{color:var(--dsw-alias-label-secondary);word-break:break-word;white-space:pre-wrap;font-size:12px;line-height:20px}.vZSZnG_stepContentDone{color:var(--dsw-alias-label-dimmed);text-decoration:line-through}.vZSZnG_stepContentRun{color:var(--dsw-alias-label-primary)}.vZSZnG_muted{color:var(--dsw-alias-label-dimmed);font-size:11px;line-height:18px}.vZSZnG_filesList{flex-direction:column;margin:0;padding:0;list-style:none;display:flex}.vZSZnG_fileRow{cursor:pointer;text-align:left;background:0 0;border:none;border-radius:6px;align-items:center;gap:6px;width:100%;padding:3px 4px;display:flex}.vZSZnG_fileRow:hover{background:var(--dsw-alias-interactive-bg-hover,#7f7f7f14)}.vZSZnG_fileDot{background:var(--dsw-alias-border-l3,#7f7f7f80);border-radius:50%;flex:none;width:5px;height:5px}.vZSZnG_filePath{color:var(--dsw-alias-label-secondary);white-space:nowrap;text-overflow:ellipsis;text-align:left;direction:rtl;font-family:ui-monospace,SF Mono,Menlo,Consolas,monospace;font-size:11px;line-height:18px;overflow:hidden}.vZSZnG_fileLine{color:var(--dsw-alias-label-dimmed);flex:none;font-size:10px;line-height:18px}.vZSZnG_cardFooter{gap:6px;margin-top:8px;display:flex}@media (prefers-reduced-motion:reduce){.vZSZnG_panel{animation:none}.vZSZnG_trackFill,.vZSZnG_card{transition:none}}.vZSZnG_miniBar{border:1px solid var(--dsw-alias-border-l3,#7f7f7f4d);background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-base,#fff));max-width:min(46vw,340px);height:34px;color:var(--dsw-alias-label-primary);cursor:grab;-webkit-user-select:none;user-select:none;pointer-events:auto;border-radius:999px;align-items:center;gap:7px;padding:0 12px;font-size:12px;line-height:18px;transition:background .15s,border-color .15s;display:inline-flex;position:fixed;box-shadow:0 6px 20px #00000024,0 1px 4px #00000014}.vZSZnG_miniBar:active{cursor:grabbing}.vZSZnG_miniBar:hover{background:var(--dsw-alias-interactive-bg-hover,#7f7f7f14)}.vZSZnG_miniIcon{color:var(--dsw-alias-label-secondary);flex:none}.vZSZnG_miniText{white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.vZSZnG_miniChevron{color:var(--dsw-alias-label-tertiary);flex:none}.vZSZnG_taskList{flex:auto;min-height:0}.vZSZnG_card{flex-direction:column;display:flex}.vZSZnG_boundaryFallback{border:1px solid var(--dsw-alias-border-l3,#7f7f7f4d);background:var(--dsw-alias-bg-layer-2,#fff);color:var(--dsw-alias-label-secondary);cursor:pointer;pointer-events:auto;border-radius:999px;padding:4px 10px;font-size:12px;line-height:18px;position:fixed;top:64px;right:16px}.vZSZnG_stepToggle{cursor:pointer;background:0 0;border:none;border-radius:4px;flex:none;align-items:center;margin-top:2px;padding:0;display:inline-flex}.vZSZnG_stepToggle:hover{background:var(--dsw-alias-interactive-bg-hover,#7f7f7f1f)}.vZSZnG_stepToggle:disabled{cursor:default;opacity:.5}.vZSZnG_stepEditable{cursor:text;border-radius:3px}.vZSZnG_stepEditable:hover{outline:1px dashed var(--dsw-alias-border-l3,#7f7f7f66);outline-offset:1px}.vZSZnG_stepInput{box-sizing:border-box;width:auto;min-width:0;font:inherit;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base,transparent);border:1px solid var(--dsw-alias-border-l3,#7f7f7f73);border-radius:5px;flex:auto;padding:0 5px;font-size:12px;line-height:20px}.vZSZnG_editorArea{box-sizing:border-box;min-width:0;color:var(--dsw-alias-label-primary);background:var(--dsw-alias-bg-base,transparent);border:1px solid var(--dsw-alias-border-l3,#7f7f7f73);resize:none;vertical-align:middle;cursor:text;white-space:pre-wrap;word-break:break-word;border-radius:5px;flex:1;margin:0;padding:2px 5px;font-family:inherit;font-size:12px;line-height:20px;overflow:hidden}.vZSZnG_editorArea:focus{border-color:var(--dsw-alias-border-l3,#7f7f7f99);outline:none}.vZSZnG_stepDragging{opacity:.3;background:var(--dsw-alias-interactive-bg-hover,#7f7f7f14)}.vZSZnG_cardTitleEditable{cursor:text;border-radius:3px}.vZSZnG_cardTitleEditable:hover{outline:1px dashed var(--dsw-alias-border-l3,#7f7f7f66);outline-offset:1px}.vZSZnG_panel[data-theme=glass],.vZSZnG_miniBar[data-theme=glass]{background:color-mix(in srgb, var(--dsw-alias-bg-layer-2,#fff) 90%, transparent);-webkit-backdrop-filter:blur(18px)saturate(1.2);border:1px solid color-mix(in srgb, var(--dsw-alias-border-l2,#7f7f7f4d) 80%, transparent)}.vZSZnG_panel[data-theme=glass] .vZSZnG_card{background:color-mix(in srgb, var(--dsw-alias-bg-base,transparent) 84%, transparent);border-color:color-mix(in srgb, var(--dsw-alias-border-l1,#7f7f7f29) 60%, transparent)}.vZSZnG_panel[data-theme=glass] .vZSZnG_cardBody{border-top-color:color-mix(in srgb, var(--dsw-alias-border-l1,#7f7f7f24) 60%, transparent)}@media (prefers-reduced-transparency:reduce){.vZSZnG_panel[data-theme=glass],.vZSZnG_miniBar[data-theme=glass]{background:var(--dsw-alias-bg-layer-2,#fff);-webkit-backdrop-filter:none;backdrop-filter:none}.vZSZnG_panel[data-theme=glass] .vZSZnG_card{background:var(--dsw-alias-bg-base,transparent)}}@supports not ((-webkit-backdrop-filter:blur(1px)) or (backdrop-filter:blur(1px))){.vZSZnG_panel[data-theme=glass],.vZSZnG_miniBar[data-theme=glass]{background:var(--dsw-alias-bg-layer-2,#fff)}}.vZSZnG_panel[data-theme=brutal]{box-shadow:none;border-width:1px;border-radius:6px}.vZSZnG_panel[data-theme=brutal] .vZSZnG_card{border:1px solid var(--dsw-alias-border-l3,#7f7f7f6b);background:var(--dsw-alias-bg-base,transparent);box-shadow:none;border-radius:3px}.vZSZnG_panel[data-theme=brutal] .vZSZnG_cardHead{padding:7px 10px 6px}.vZSZnG_panel[data-theme=brutal] .vZSZnG_cardTitle{letter-spacing:.01em;font-weight:650}.vZSZnG_panel[data-theme=brutal] .vZSZnG_headerTitle{letter-spacing:.03em}.vZSZnG_panel[data-theme=brutal] .vZSZnG_boundBadge{border-radius:2px}.vZSZnG_panel[data-theme=brutal] .vZSZnG_track{border-radius:0;height:3px}.vZSZnG_panel[data-theme=brutal] .vZSZnG_trackFill{border-radius:0}.vZSZnG_panel[data-theme=brutal] .vZSZnG_cardBody{border-top:1px solid var(--dsw-alias-border-l2,#7f7f7f3d)}.vZSZnG_panel[data-theme=mono] .vZSZnG_headerTitle,.vZSZnG_panel[data-theme=mono] .vZSZnG_counts,.vZSZnG_panel[data-theme=mono] .vZSZnG_cardTitle,.vZSZnG_panel[data-theme=mono] .vZSZnG_progressText,.vZSZnG_panel[data-theme=mono] .vZSZnG_stepContent,.vZSZnG_panel[data-theme=mono] .vZSZnG_filePath{font-family:ui-monospace,SF Mono,Menlo,Consolas,Liberation Mono,monospace}.vZSZnG_panel[data-theme=mono] .vZSZnG_cardTitle{font-size:12px}.vZSZnG_panel[data-theme=mono] .vZSZnG_stepContent{font-size:11.5px}.vZSZnG_panel[data-theme=mono] .vZSZnG_card{border-radius:5px}.vZSZnG_panel[data-theme=mono] .vZSZnG_trackFill{border-radius:0}.vZSZnG_panel[data-theme=mono] .vZSZnG_stepPending{border-radius:1px}.vZSZnG_panel[data-theme=mono] .vZSZnG_updated{letter-spacing:.02em}.vZSZnG_headerIconBtn{color:inherit;cursor:pointer;background:0 0;border:none;border-radius:0;flex:none;justify-content:center;align-items:center;margin:0;padding:0;display:inline-flex}.vZSZnG_headerIcon{color:var(--dsw-alias-label-secondary);flex:none;display:block}.vZSZnG_headerLeft{min-width:0}.vZSZnG_headerTitle{text-overflow:ellipsis;flex:0 auto;min-width:0;overflow:hidden}.vZSZnG_headerRight{min-width:0}.vZSZnG_counts{text-overflow:ellipsis;flex:none;max-width:45%;margin-left:auto;overflow:hidden}.vZSZnG_dragGhost{pointer-events:none;z-index:9999;transition:left 50ms,top 50ms;position:fixed;transform:translate(-50%,-50%)}.vZSZnG_dragGhostCard{background:var(--dsw-alias-bg-layer-2,var(--dsw-alias-bg-base,#fff));border:1px solid var(--dsw-alias-border-l3,#7f7f7f59);color:var(--dsw-alias-label-primary);white-space:nowrap;border-radius:8px;align-items:center;gap:8px;max-width:280px;padding:8px 12px;font-size:12px;line-height:20px;display:inline-flex;transform:scale(.9);box-shadow:0 8px 24px #0000002e,0 2px 8px #0000001a}.vZSZnG_dragGhostContent{text-overflow:ellipsis;word-break:break-word;flex:1;min-width:0;overflow:hidden}.vZSZnG_dragGhostClose{width:20px;height:20px;color:var(--dsw-alias-label-tertiary);cursor:pointer;opacity:.6;background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;margin-left:8px;font-size:16px;line-height:1;transition:opacity .15s,background .15s,color .15s;display:inline-flex}.vZSZnG_dragGhostClose:hover{opacity:1;color:var(--dsw-alias-label-secondary);background:var(--dsw-alias-interactive-bg-hover,#7f7f7f1f)}.vZSZnG_dropTargetBefore{position:relative}.vZSZnG_dropTargetBefore:before{content:\"\";background:var(--dsw-alias-button-primary-fill,#3a6ef5);height:2px;box-shadow:0 0 4px var(--dsw-alias-button-primary-fill,#3a6ef5);border-radius:1px;animation:.8s ease-in-out infinite vZSZnG_dropPulse;position:absolute;top:-1px;left:0;right:0}.vZSZnG_dropTargetAfter{position:relative}.vZSZnG_dropTargetAfter:after{content:\"\";background:var(--dsw-alias-button-primary-fill,#3a6ef5);height:2px;box-shadow:0 0 4px var(--dsw-alias-button-primary-fill,#3a6ef5);border-radius:1px;animation:.8s ease-in-out infinite vZSZnG_dropPulse;position:absolute;bottom:-1px;left:0;right:0}@keyframes vZSZnG_dropPulse{0%,to{opacity:.6}50%{opacity:1}}.vZSZnG_memoryPane{flex-direction:column;gap:6px;max-height:480px;padding:8px 10px 10px;display:flex;overflow:auto}.vZSZnG_memToolbar{justify-content:space-between;align-items:center;gap:8px;display:flex}.vZSZnG_memCount{opacity:.75;font-size:12px;font-weight:600}.vZSZnG_memList{flex-direction:column;gap:6px;display:flex}.vZSZnG_memRow{border:1px solid var(--dsw-border-weak,#80808040);background:color-mix(in srgb, var(--dsw-bg-secondary,#f5f5f5) 45%, transparent);border-radius:6px;flex-direction:column;gap:4px;padding:6px 8px;display:flex}.vZSZnG_memRowArchived{opacity:.55}.vZSZnG_memRowMain{flex-direction:column;gap:2px;display:flex}.vZSZnG_memTitle{word-break:break-word;align-items:flex-start;gap:6px;font-size:13px;line-height:1.35;display:flex}.vZSZnG_kindBadge{background:var(--dsw-accent-soft,#5078ff26);color:var(--dsw-accent,#4d6bfe);border-radius:4px;flex:none;padding:0 5px;font-size:11px;line-height:1.5}.vZSZnG_memMeta{flex-wrap:wrap;align-items:center;gap:4px;display:flex}.vZSZnG_badge{background:color-mix(in srgb, var(--dsw-fg,#222) 8%, transparent);border-radius:4px;padding:0 5px;font-size:11px;line-height:1.5}.vZSZnG_badgeDraft{color:#b26a00;background:#ffb40029}.vZSZnG_badgeArchived{opacity:.8}.vZSZnG_memBody{opacity:.8;word-break:break-word;font-size:12px}.vZSZnG_memActs{flex-wrap:wrap;gap:4px;display:flex}.vZSZnG_memToolbarActs{align-items:center;gap:6px;display:flex}.vZSZnG_memNew{border:1px solid var(--dsw-border-weak,#80808040);border-radius:6px;flex-direction:column;gap:6px;padding:8px;display:flex}.vZSZnG_memNewRow{align-items:center;gap:8px;display:flex}.vZSZnG_memLabel{opacity:.8;align-items:center;gap:6px;font-size:12px;display:inline-flex}.vZSZnG_memNew select,.vZSZnG_memNew textarea{box-sizing:border-box;width:100%}";
491
565
  const tagId$1 = "@yolk_vat-y/dsh-project-memory/TaskPanel.module.css";
492
566
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
493
567
  const tag = document.createElement("style");
@@ -497,71 +571,91 @@ window.__ModuleLoader__.load({
497
571
  document.head.appendChild(tag);
498
572
  }
499
573
  var TaskPanel_module_css_default = {
500
- "headerLeft": "vZSZnG_headerLeft",
574
+ "stepToggle": "vZSZnG_stepToggle",
575
+ "stepDone": "vZSZnG_stepDone",
576
+ "miniIcon": "vZSZnG_miniIcon",
577
+ "headerIconBtn": "vZSZnG_headerIconBtn",
578
+ "cardBody": "vZSZnG_cardBody",
579
+ "sectionCount": "vZSZnG_sectionCount",
580
+ "progressText": "vZSZnG_progressText",
581
+ "cardBound": "vZSZnG_cardBound",
582
+ "chevron": "vZSZnG_chevron",
583
+ "memList": "vZSZnG_memList",
584
+ "kindBadge": "vZSZnG_kindBadge",
585
+ "cardFooter": "vZSZnG_cardFooter",
586
+ "trackFill": "vZSZnG_trackFill",
587
+ "cardTitle": "vZSZnG_cardTitle",
588
+ "stepEditable": "vZSZnG_stepEditable",
501
589
  "counts": "vZSZnG_counts",
502
- "card": "vZSZnG_card",
503
- "filePath": "vZSZnG_filePath",
504
- "headerIcon": "vZSZnG_headerIcon",
505
- "fileDot": "vZSZnG_fileDot",
506
- "dropPulse": "vZSZnG_dropPulse",
507
- "stepContent": "vZSZnG_stepContent",
590
+ "section": "vZSZnG_section",
508
591
  "stepInput": "vZSZnG_stepInput",
509
- "track": "vZSZnG_track",
510
- "muted": "vZSZnG_muted",
511
- "cardMeta": "vZSZnG_cardMeta",
512
- "miniChevron": "vZSZnG_miniChevron",
513
- "stepRun": "vZSZnG_stepRun",
514
- "stepEditable": "vZSZnG_stepEditable",
592
+ "handleGrip": "vZSZnG_handleGrip",
593
+ "cardTitleEditable": "vZSZnG_cardTitleEditable",
515
594
  "dragGhostContent": "vZSZnG_dragGhostContent",
516
- "chevron": "vZSZnG_chevron",
517
- "dragGhostCard": "vZSZnG_dragGhostCard",
518
- "cardBound": "vZSZnG_cardBound",
519
- "boundaryFallback": "vZSZnG_boundaryFallback",
520
- "headerTitle": "vZSZnG_headerTitle",
521
- "stepContentDone": "vZSZnG_stepContentDone",
522
- "fileLine": "vZSZnG_fileLine",
523
- "sectionLabel": "vZSZnG_sectionLabel",
524
- "emptyTitle": "vZSZnG_emptyTitle",
595
+ "dragGhostClose": "vZSZnG_dragGhostClose",
596
+ "dropTargetBefore": "vZSZnG_dropTargetBefore",
525
597
  "stepDragging": "vZSZnG_stepDragging",
526
- "trackFill": "vZSZnG_trackFill",
527
- "miniIcon": "vZSZnG_miniIcon",
528
- "progressText": "vZSZnG_progressText",
529
- "cardTitle": "vZSZnG_cardTitle",
530
- "cardFooter": "vZSZnG_cardFooter",
531
- "headerIconBtn": "vZSZnG_headerIconBtn",
532
- "header": "vZSZnG_header",
533
- "miniBar": "vZSZnG_miniBar",
598
+ "cardMeta": "vZSZnG_cardMeta",
599
+ "panel": "vZSZnG_panel",
600
+ "dragGhost": "vZSZnG_dragGhost",
534
601
  "dropTargetAfter": "vZSZnG_dropTargetAfter",
602
+ "stepPending": "vZSZnG_stepPending",
603
+ "fileDot": "vZSZnG_fileDot",
604
+ "memTitle": "vZSZnG_memTitle",
605
+ "badge": "vZSZnG_badge",
606
+ "emptyTitle": "vZSZnG_emptyTitle",
607
+ "stepContentRun": "vZSZnG_stepContentRun",
608
+ "stepRun": "vZSZnG_stepRun",
609
+ "fileLine": "vZSZnG_fileLine",
610
+ "dropPulse": "vZSZnG_dropPulse",
611
+ "memRow": "vZSZnG_memRow",
535
612
  "filesList": "vZSZnG_filesList",
536
- "boundBadge": "vZSZnG_boundBadge",
537
- "cardTitleEditable": "vZSZnG_cardTitleEditable",
538
- "fileRow": "vZSZnG_fileRow",
539
- "dragGhost": "vZSZnG_dragGhost",
540
- "cardTitleRow": "vZSZnG_cardTitleRow",
613
+ "sectionLabel": "vZSZnG_sectionLabel",
541
614
  "cardHead": "vZSZnG_cardHead",
542
- "panel": "vZSZnG_panel",
543
- "stepRow": "vZSZnG_stepRow",
544
- "headerRight": "vZSZnG_headerRight",
545
- "handleGrip": "vZSZnG_handleGrip",
546
- "panelIn": "vZSZnG_panelIn",
547
- "stepToggle": "vZSZnG_stepToggle",
615
+ "fileRow": "vZSZnG_fileRow",
548
616
  "notice": "vZSZnG_notice",
549
- "emptyState": "vZSZnG_emptyState",
550
- "miniText": "vZSZnG_miniText",
617
+ "emptyDesc": "vZSZnG_emptyDesc",
618
+ "panelIn": "vZSZnG_panelIn",
619
+ "headerLeft": "vZSZnG_headerLeft",
620
+ "headerIcon": "vZSZnG_headerIcon",
621
+ "memNew": "vZSZnG_memNew",
622
+ "memToolbar": "vZSZnG_memToolbar",
623
+ "memActs": "vZSZnG_memActs",
624
+ "badgeDraft": "vZSZnG_badgeDraft",
625
+ "headerRight": "vZSZnG_headerRight",
626
+ "card": "vZSZnG_card",
627
+ "syncHint": "vZSZnG_syncHint",
551
628
  "updated": "vZSZnG_updated",
552
- "stepsList": "vZSZnG_stepsList",
629
+ "memBody": "vZSZnG_memBody",
630
+ "memLabel": "vZSZnG_memLabel",
553
631
  "dragHandle": "vZSZnG_dragHandle",
632
+ "track": "vZSZnG_track",
633
+ "memoryPane": "vZSZnG_memoryPane",
634
+ "badgeArchived": "vZSZnG_badgeArchived",
635
+ "muted": "vZSZnG_muted",
636
+ "editorArea": "vZSZnG_editorArea",
637
+ "memMeta": "vZSZnG_memMeta",
638
+ "boundBadge": "vZSZnG_boundBadge",
639
+ "stepRow": "vZSZnG_stepRow",
640
+ "miniBar": "vZSZnG_miniBar",
641
+ "stepContent": "vZSZnG_stepContent",
642
+ "filePath": "vZSZnG_filePath",
643
+ "memNewRow": "vZSZnG_memNewRow",
644
+ "emptyState": "vZSZnG_emptyState",
645
+ "memCount": "vZSZnG_memCount",
646
+ "memToolbarActs": "vZSZnG_memToolbarActs",
647
+ "headerTitle": "vZSZnG_headerTitle",
648
+ "memRowMain": "vZSZnG_memRowMain",
649
+ "stepContentDone": "vZSZnG_stepContentDone",
650
+ "miniChevron": "vZSZnG_miniChevron",
554
651
  "taskList": "vZSZnG_taskList",
555
- "sectionCount": "vZSZnG_sectionCount",
556
- "stepDone": "vZSZnG_stepDone",
557
- "syncHint": "vZSZnG_syncHint",
558
- "section": "vZSZnG_section",
559
- "stepContentRun": "vZSZnG_stepContentRun",
560
- "dragGhostClose": "vZSZnG_dragGhostClose",
561
- "emptyDesc": "vZSZnG_emptyDesc",
562
- "dropTargetBefore": "vZSZnG_dropTargetBefore",
563
- "stepPending": "vZSZnG_stepPending",
564
- "cardBody": "vZSZnG_cardBody"
652
+ "boundaryFallback": "vZSZnG_boundaryFallback",
653
+ "dragGhostCard": "vZSZnG_dragGhostCard",
654
+ "header": "vZSZnG_header",
655
+ "cardTitleRow": "vZSZnG_cardTitleRow",
656
+ "memRowArchived": "vZSZnG_memRowArchived",
657
+ "miniText": "vZSZnG_miniText",
658
+ "stepsList": "vZSZnG_stepsList"
565
659
  };
566
660
  //#endregion
567
661
  //#region src/client/TaskComponents.tsx
@@ -569,6 +663,14 @@ window.__ModuleLoader__.load({
569
663
  * Task Panel Presentational 组件 — MiniBar(折叠迷你条)与 TaskCard(任务卡)。
570
664
  * 纯渲染 + 卡片局部行内编辑/拖拽状态,动作经 props 回调交给容器(TaskPanel.tsx)。
571
665
  */
666
+ function insightKindLabel(kind, t) {
667
+ return {
668
+ lesson: t("mem.kind.lesson"),
669
+ decision: t("mem.kind.decision"),
670
+ procedure: t("mem.kind.procedure"),
671
+ experience: t("mem.kind.experience")
672
+ }[kind] ?? kind;
673
+ }
572
674
  function timeAgo(iso) {
573
675
  if (!iso) return "";
574
676
  const diff = Date.now() - new Date(iso).getTime();
@@ -584,6 +686,52 @@ window.__ModuleLoader__.load({
584
686
  if (status === "in_progress") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlayOutline16, { className: TaskPanel_module_css_default.stepRun });
585
687
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: TaskPanel_module_css_default.stepPending });
586
688
  }
689
+ /**
690
+ * 双击判定窗口(ms)。
691
+ * 单击(如卡片展开/收起)会延迟该时长执行:若期间收到第二次点击则按“双击”处理并取消单击,
692
+ * 从而避免“第一下先展开/收起、布局位移后第二下点不到目标”的问题。
693
+ * 数值是可感知与可靠性的折中:太小慢速双击会失效,太大单击会显“肉”。
694
+ */
695
+ const CLICK_SINGLE_DELAY_MS = 250;
696
+ function InlineEditor({ value, className, maxRows = 8, onValueChange, onCommit, onCancel }) {
697
+ const ref = (0, react.useRef)(null);
698
+ (0, react.useLayoutEffect)(() => {
699
+ const el = ref.current;
700
+ if (!el) return;
701
+ el.style.height = "auto";
702
+ const cs = getComputedStyle(el);
703
+ const lineHeight = parseFloat(cs.lineHeight) || 20;
704
+ const padV = (parseFloat(cs.paddingTop) || 0) + (parseFloat(cs.paddingBottom) || 0);
705
+ const borderV = (parseFloat(cs.borderTopWidth) || 0) + (parseFloat(cs.borderBottomWidth) || 0);
706
+ const cap = maxRows * lineHeight + padV + borderV;
707
+ const height = Math.min(el.scrollHeight, cap);
708
+ el.style.height = `${height}px`;
709
+ el.style.overflowY = el.scrollHeight > cap ? "auto" : "hidden";
710
+ }, [value, maxRows]);
711
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
712
+ ref,
713
+ className,
714
+ rows: 1,
715
+ value,
716
+ autoFocus: true,
717
+ spellCheck: false,
718
+ onChange: (e) => onValueChange(e.target.value),
719
+ onFocus: (e) => {
720
+ const len = e.target.value.length;
721
+ e.target.setSelectionRange(len, len);
722
+ },
723
+ onBlur: onCommit,
724
+ onKeyDown: (e) => {
725
+ if (e.key === "Enter" && !e.shiftKey) {
726
+ e.preventDefault();
727
+ onCommit();
728
+ } else if (e.key === "Escape") {
729
+ e.preventDefault();
730
+ onCancel();
731
+ }
732
+ }
733
+ });
734
+ }
587
735
  function MiniBar({ label, hint, position, theme, onMove, open }) {
588
736
  const barRef = (0, react.useRef)(null);
589
737
  const down = (0, react.useRef)(null);
@@ -643,7 +791,7 @@ window.__ModuleLoader__.load({
643
791
  ]
644
792
  });
645
793
  }
646
- function TaskCard({ task, isBound, expanded, onToggleExpand, onSwitch, onUnbind, onArchive, onRename, onEditStep, onCycleStatus, onReorderSteps, showHints, syncing, t }) {
794
+ function TaskCard({ task, isBound, expanded, onToggleExpand, onSwitch, onUnbind, onArchive, onRename, onEditStep, onCycleStatus, onReorderSteps, onInsightAction, showHints, syncing, t }) {
647
795
  const steps = task.steps || [];
648
796
  const { dragState, dropTargetIndex, startDrag, cancelDrag } = useTaskDrag(task.id, steps, isBound, onReorderSteps);
649
797
  const [stepEdit, setStepEdit] = (0, react.useState)(null);
@@ -662,33 +810,57 @@ window.__ModuleLoader__.load({
662
810
  setTitleEdit(null);
663
811
  onRename(value);
664
812
  };
813
+ const headClickTimer = (0, react.useRef)(null);
814
+ const suppressHeadClick = (0, react.useRef)(false);
815
+ (0, react.useEffect)(() => () => {
816
+ if (headClickTimer.current !== null) window.clearTimeout(headClickTimer.current);
817
+ }, []);
818
+ const handleHeadClick = (e) => {
819
+ if (suppressHeadClick.current) {
820
+ suppressHeadClick.current = false;
821
+ return;
822
+ }
823
+ if (titleEdit !== null) return;
824
+ const target = e.target;
825
+ const onTitle = isBound && target.closest("[data-card-title]") !== null;
826
+ if (headClickTimer.current !== null) {
827
+ window.clearTimeout(headClickTimer.current);
828
+ headClickTimer.current = null;
829
+ if (onTitle) setTitleEdit({ value: String(task.title ?? "") });
830
+ else onToggleExpand();
831
+ return;
832
+ }
833
+ headClickTimer.current = window.setTimeout(() => {
834
+ headClickTimer.current = null;
835
+ onToggleExpand();
836
+ }, CLICK_SINGLE_DELAY_MS);
837
+ };
665
838
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("article", {
666
839
  "data-task-id": task.id,
667
840
  className: `${TaskPanel_module_css_default.card}${isBound ? ` ${TaskPanel_module_css_default.cardBound}` : ""}`,
668
841
  children: [
669
842
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
670
843
  className: TaskPanel_module_css_default.cardHead,
671
- onClick: () => {
672
- if (titleEdit !== null) return;
673
- onToggleExpand();
844
+ onClick: handleHeadClick,
845
+ onMouseDownCapture: () => {
846
+ if (titleEdit !== null) suppressHeadClick.current = true;
674
847
  },
848
+ onDoubleClick: (e) => e.preventDefault(),
675
849
  "aria-expanded": expanded,
676
850
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
677
851
  className: TaskPanel_module_css_default.cardTitleRow,
678
852
  children: [isBound && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
679
853
  className: TaskPanel_module_css_default.boundBadge,
680
854
  children: t("task.current")
681
- }), isBound && titleEdit !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
682
- className: TaskPanel_module_css_default.stepInput,
855
+ }), isBound && titleEdit !== null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineEditor, {
856
+ className: TaskPanel_module_css_default.editorArea,
683
857
  value: titleEdit.value,
684
- autoFocus: true,
685
- onChange: (e) => setTitleEdit({ value: e.target.value }),
686
- onBlur: commitTitleEdit,
687
- onKeyDown: (e) => {
688
- if (e.key === "Enter") commitTitleEdit();
689
- else if (e.key === "Escape") setTitleEdit(null);
690
- }
858
+ maxRows: 4,
859
+ onValueChange: (value) => setTitleEdit({ value }),
860
+ onCommit: commitTitleEdit,
861
+ onCancel: () => setTitleEdit(null)
691
862
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
863
+ "data-card-title": true,
692
864
  className: `${TaskPanel_module_css_default.cardTitle}${isBound ? ` ${TaskPanel_module_css_default.cardTitleEditable}` : ""}`,
693
865
  title: isBound ? t("task.title-edit") : void 0,
694
866
  onDoubleClick: (e) => {
@@ -764,19 +936,16 @@ window.__ModuleLoader__.load({
764
936
  },
765
937
  title: `${t("step.completed")}/${t("step.in-progress")}/${t("step.pending")}`,
766
938
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepIcon, { status: step.status })
767
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepIcon, { status: step.status }), stepIsEditing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
768
- className: TaskPanel_module_css_default.stepInput,
939
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(StepIcon, { status: step.status }), stepIsEditing ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InlineEditor, {
940
+ className: TaskPanel_module_css_default.editorArea,
769
941
  value: stepEdit.value,
770
- autoFocus: true,
771
- onChange: (e) => setStepEdit({
942
+ maxRows: 10,
943
+ onValueChange: (value) => setStepEdit({
772
944
  index: i,
773
- value: e.target.value
945
+ value
774
946
  }),
775
- onBlur: () => commitStepEdit(i),
776
- onKeyDown: (e) => {
777
- if (e.key === "Enter") commitStepEdit(i);
778
- else if (e.key === "Escape") setStepEdit(null);
779
- }
947
+ onCommit: () => commitStepEdit(i),
948
+ onCancel: () => setStepEdit(null)
780
949
  }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
781
950
  className: `${TaskPanel_module_css_default.stepContent}${step.status === "completed" ? ` ${TaskPanel_module_css_default.stepContentDone}` : ""}${step.status === "in_progress" ? ` ${TaskPanel_module_css_default.stepContentRun}` : ""}${isBound ? ` ${TaskPanel_module_css_default.stepEditable}` : ""}`,
782
951
  title: isBound && showHints ? t("step.edit-hint") : void 0,
@@ -855,6 +1024,60 @@ window.__ModuleLoader__.load({
855
1024
  })]
856
1025
  })]
857
1026
  }),
1027
+ onInsightAction && Array.isArray(task.insights) && task.insights.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1028
+ className: TaskPanel_module_css_default.section,
1029
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1030
+ className: TaskPanel_module_css_default.sectionLabel,
1031
+ children: [t("mem.section-label"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1032
+ className: TaskPanel_module_css_default.sectionCount,
1033
+ children: task.insights.length
1034
+ })]
1035
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("ul", {
1036
+ className: TaskPanel_module_css_default.memList,
1037
+ children: task.insights.map((ins) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
1038
+ className: TaskPanel_module_css_default.memRow,
1039
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1040
+ className: TaskPanel_module_css_default.memTitle,
1041
+ children: [
1042
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1043
+ className: TaskPanel_module_css_default.kindBadge,
1044
+ children: insightKindLabel(ins.kind, t)
1045
+ }),
1046
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: ins.title || ins.id }),
1047
+ ins.draft && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1048
+ className: `${TaskPanel_module_css_default.badge} ${TaskPanel_module_css_default.badgeDraft}`,
1049
+ children: t("mem.draft")
1050
+ })
1051
+ ]
1052
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1053
+ className: TaskPanel_module_css_default.memActs,
1054
+ children: [
1055
+ ins.draft && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1056
+ variant: "outline",
1057
+ size: "sm",
1058
+ disabled: syncing,
1059
+ onClick: () => onInsightAction("confirm", ins.id),
1060
+ children: t("mem.confirm")
1061
+ }),
1062
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1063
+ variant: "outline",
1064
+ size: "sm",
1065
+ disabled: syncing,
1066
+ onClick: () => onInsightAction("promote", ins.id),
1067
+ children: t("mem.promote")
1068
+ }),
1069
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1070
+ variant: "outline",
1071
+ size: "sm",
1072
+ disabled: syncing,
1073
+ onClick: () => onInsightAction("delete", ins.id),
1074
+ children: t("mem.delete")
1075
+ })
1076
+ ]
1077
+ })]
1078
+ }, ins.id))
1079
+ })]
1080
+ }),
858
1081
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
859
1082
  className: TaskPanel_module_css_default.cardFooter,
860
1083
  children: [
@@ -888,6 +1111,469 @@ window.__ModuleLoader__.load({
888
1111
  });
889
1112
  }
890
1113
  //#endregion
1114
+ //#region src/client/MemoryView.tsx
1115
+ /**
1116
+ * Memory View — 记忆三作用域列表(Task 草稿 / Project / Global)
1117
+ * 数据通道与任务面板一致:remote.commands.execute 执行 /insight 命令,取 JSON 载荷。
1118
+ * 动作:confirm(草稿审核) / promote(向上提升) / demote(向下降级,需绑定任务) / archive / restore / delete
1119
+ */
1120
+ function parseInsightPayloadText(text) {
1121
+ if (!text) return null;
1122
+ let jsonBlock = null;
1123
+ const fenced = text.match(/```(?:json)?\s*\n([\s\S]*?)\n```/);
1124
+ if (fenced) jsonBlock = fenced[1];
1125
+ else {
1126
+ const lastBrace = text.lastIndexOf("{");
1127
+ if (lastBrace !== -1) jsonBlock = text.slice(lastBrace);
1128
+ }
1129
+ if (!jsonBlock) return null;
1130
+ try {
1131
+ const data = JSON.parse(jsonBlock);
1132
+ if (!Array.isArray(data.items)) return null;
1133
+ return {
1134
+ scope: data.scope ?? "project",
1135
+ count: data.count ?? data.items.length,
1136
+ items: data.items
1137
+ };
1138
+ } catch {
1139
+ return null;
1140
+ }
1141
+ }
1142
+ function kindText(kind, t) {
1143
+ return {
1144
+ lesson: t("mem.kind.lesson"),
1145
+ decision: t("mem.kind.decision"),
1146
+ procedure: t("mem.kind.procedure"),
1147
+ experience: t("mem.kind.experience")
1148
+ }[kind] ?? kind;
1149
+ }
1150
+ function MemoryView({ ctx, sessionId, scope, boundTaskId, t }) {
1151
+ const [payload, setPayload] = (0, react.useState)(null);
1152
+ const [error, setError] = (0, react.useState)(null);
1153
+ const [loading, setLoading] = (0, react.useState)(false);
1154
+ const [busy, setBusy] = (0, react.useState)(false);
1155
+ const [showNew, setShowNew] = (0, react.useState)(false);
1156
+ const [editingId, setEditingId] = (0, react.useState)(null);
1157
+ const [form, setForm] = (0, react.useState)({
1158
+ title: "",
1159
+ kind: "lesson",
1160
+ body: "",
1161
+ steps: "",
1162
+ trigger: ""
1163
+ });
1164
+ const [savedTip, setSavedTip] = (0, react.useState)(null);
1165
+ const runLine = (0, react.useCallback)(async (line) => {
1166
+ const commands = ctx?.remote?.commands;
1167
+ if (!sessionId || !commands || typeof commands.execute !== "function") return {
1168
+ ok: false,
1169
+ text: "no session / commands service"
1170
+ };
1171
+ try {
1172
+ const envelope = await commands.execute(sessionId, line, []);
1173
+ const execution = envelope && typeof envelope === "object" && "value" in envelope ? envelope.value : envelope;
1174
+ const result = execution?.result ?? execution;
1175
+ if (result?.kind === "error") return {
1176
+ ok: false,
1177
+ text: result.text ?? "command error"
1178
+ };
1179
+ return {
1180
+ ok: true,
1181
+ text: result?.text ?? ""
1182
+ };
1183
+ } catch (err) {
1184
+ return {
1185
+ ok: false,
1186
+ text: String(err?.message ?? err)
1187
+ };
1188
+ }
1189
+ }, [ctx, sessionId]);
1190
+ const inflightRef = (0, react.useRef)(false);
1191
+ const lastRunRef = (0, react.useRef)(0);
1192
+ const refresh = (0, react.useCallback)(async (force = false) => {
1193
+ if (inflightRef.current) return;
1194
+ const now = Date.now();
1195
+ if (!force && now - lastRunRef.current < 800) return;
1196
+ inflightRef.current = true;
1197
+ lastRunRef.current = now;
1198
+ setLoading(true);
1199
+ setError(null);
1200
+ try {
1201
+ const res = await runLine(`/insight list ${scope}`);
1202
+ if (!res.ok) {
1203
+ setError(res.text);
1204
+ setPayload(null);
1205
+ return;
1206
+ }
1207
+ const parsed = parseInsightPayloadText(res.text);
1208
+ setPayload(parsed);
1209
+ if (!parsed) setError("unparsable payload");
1210
+ } finally {
1211
+ inflightRef.current = false;
1212
+ setLoading(false);
1213
+ }
1214
+ }, [runLine, scope]);
1215
+ (0, react.useEffect)(() => {
1216
+ refresh();
1217
+ }, [refresh]);
1218
+ const act = async (action, id) => {
1219
+ if (busy) return;
1220
+ setBusy(true);
1221
+ setError(null);
1222
+ try {
1223
+ const line = `/insight ${action} ${scope} ${id}${action === "demote" && scope === "project" && boundTaskId ? ` ${boundTaskId}` : ""}`;
1224
+ const res = await runLine(line);
1225
+ if (!res.ok) setError(res.text);
1226
+ else refresh(true);
1227
+ } finally {
1228
+ setBusy(false);
1229
+ }
1230
+ };
1231
+ const rowToForm = (row) => {
1232
+ const main = row.kind === "lesson" ? row.fix : row.kind === "experience" ? row.solution : row.kind === "decision" ? row.reason : row.body;
1233
+ const body = main && main !== row.title ? main : "";
1234
+ return {
1235
+ title: row.title || "",
1236
+ kind: row.kind || "lesson",
1237
+ body,
1238
+ steps: Array.isArray(row.steps) ? row.steps.join("\n") : "",
1239
+ trigger: (row.trigger?.keywords || []).join(",")
1240
+ };
1241
+ };
1242
+ const startEdit = (row) => {
1243
+ setEditingId(row.id);
1244
+ setForm(rowToForm(row));
1245
+ setShowNew(true);
1246
+ setError(null);
1247
+ };
1248
+ const closeForm = () => {
1249
+ setShowNew(false);
1250
+ setEditingId(null);
1251
+ setForm({
1252
+ title: "",
1253
+ kind: "lesson",
1254
+ body: "",
1255
+ steps: "",
1256
+ trigger: ""
1257
+ });
1258
+ };
1259
+ const changeKind = (next) => {
1260
+ setForm((prev) => {
1261
+ if (prev.kind === next) return prev;
1262
+ const fromProc = prev.kind === "procedure";
1263
+ const toProc = next === "procedure";
1264
+ let body = prev.body;
1265
+ let steps = prev.steps;
1266
+ if (fromProc && !toProc && !body && steps.trim()) body = steps.trim();
1267
+ if (toProc && !fromProc && !steps.trim() && body.trim()) steps = body.trim();
1268
+ return {
1269
+ ...prev,
1270
+ kind: next,
1271
+ body,
1272
+ steps
1273
+ };
1274
+ });
1275
+ };
1276
+ const submitNew = async () => {
1277
+ if (scope === "task" && !editingId) return;
1278
+ if (busy) return;
1279
+ const title = form.title.trim();
1280
+ if (!title) return;
1281
+ setBusy(true);
1282
+ setError(null);
1283
+ try {
1284
+ const fields = {
1285
+ title,
1286
+ kind: form.kind
1287
+ };
1288
+ if (form.kind === "lesson") fields.pattern = title;
1289
+ if (form.kind === "decision") fields.choice = title;
1290
+ if (form.kind === "experience") fields.problem = title;
1291
+ if (form.body.trim()) {
1292
+ if (form.kind === "lesson") fields.fix = form.body.trim();
1293
+ else if (form.kind === "decision") fields.reason = form.body.trim();
1294
+ else if (form.kind === "experience") fields.solution = form.body.trim();
1295
+ else fields.body = form.body.trim();
1296
+ }
1297
+ if (form.kind === "procedure" && form.steps.trim()) fields.steps = form.steps.split("\n").map((s) => s.trim()).filter(Boolean);
1298
+ if (form.kind === "procedure" && form.trigger.trim()) fields.trigger = { keywords: form.trigger.split(/[,,]/).map((s) => s.trim()).filter(Boolean) };
1299
+ const line = editingId ? `/insight edit ${scope} ${editingId} ${JSON.stringify(fields)}` : `/insight save ${scope} ${JSON.stringify(fields)}`;
1300
+ const res = await runLine(line);
1301
+ if (!res.ok) setError(res.text);
1302
+ else {
1303
+ setSavedTip(t("mem.saved"));
1304
+ closeForm();
1305
+ window.setTimeout(() => setSavedTip(null), 2500);
1306
+ refresh(true);
1307
+ }
1308
+ } finally {
1309
+ setBusy(false);
1310
+ }
1311
+ };
1312
+ const items = payload?.items ?? [];
1313
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1314
+ className: TaskPanel_module_css_default.memoryPane,
1315
+ children: [
1316
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1317
+ className: TaskPanel_module_css_default.memToolbar,
1318
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1319
+ className: TaskPanel_module_css_default.memCount,
1320
+ children: [scope === "task" ? t("mem.scope.task") : scope === "global" ? t("mem.scope.global") : t("mem.scope.project"), payload ? ` · ${payload.count}` : ""]
1321
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1322
+ className: TaskPanel_module_css_default.memToolbarActs,
1323
+ children: [
1324
+ savedTip && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1325
+ className: TaskPanel_module_css_default.badge,
1326
+ children: savedTip
1327
+ }),
1328
+ scope !== "task" && !showNew && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1329
+ variant: "outline",
1330
+ size: "sm",
1331
+ disabled: busy,
1332
+ onClick: () => {
1333
+ setShowNew(true);
1334
+ setEditingId(null);
1335
+ setError(null);
1336
+ },
1337
+ children: t("mem.new")
1338
+ }),
1339
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1340
+ variant: "outline",
1341
+ size: "sm",
1342
+ onClick: () => void refresh(true),
1343
+ disabled: loading,
1344
+ title: t("panel.refresh"),
1345
+ "aria-label": t("panel.refresh"),
1346
+ children: "↻"
1347
+ })
1348
+ ]
1349
+ })]
1350
+ }),
1351
+ showNew && scope !== "task" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1352
+ className: TaskPanel_module_css_default.memNew,
1353
+ children: [
1354
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1355
+ className: TaskPanel_module_css_default.stepInput,
1356
+ placeholder: t("mem.f.title"),
1357
+ value: form.title,
1358
+ onChange: (e) => setForm({
1359
+ ...form,
1360
+ title: e.target.value
1361
+ }),
1362
+ autoFocus: true
1363
+ }),
1364
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1365
+ className: TaskPanel_module_css_default.memNewRow,
1366
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
1367
+ className: TaskPanel_module_css_default.memLabel,
1368
+ children: [t("mem.f.kind"), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
1369
+ className: TaskPanel_module_css_default.stepInput,
1370
+ value: form.kind,
1371
+ onChange: (e) => changeKind(e.target.value),
1372
+ children: [
1373
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1374
+ value: "lesson",
1375
+ children: "lesson"
1376
+ }),
1377
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1378
+ value: "decision",
1379
+ children: "decision"
1380
+ }),
1381
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1382
+ value: "procedure",
1383
+ children: "procedure"
1384
+ }),
1385
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
1386
+ value: "experience",
1387
+ children: "experience"
1388
+ })
1389
+ ]
1390
+ })]
1391
+ })
1392
+ }),
1393
+ form.kind !== "procedure" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1394
+ className: TaskPanel_module_css_default.stepInput,
1395
+ placeholder: t("mem.f.body"),
1396
+ rows: 2,
1397
+ value: form.body,
1398
+ onChange: (e) => setForm({
1399
+ ...form,
1400
+ body: e.target.value
1401
+ })
1402
+ }),
1403
+ form.kind === "procedure" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
1404
+ className: TaskPanel_module_css_default.stepInput,
1405
+ placeholder: t("mem.f.steps"),
1406
+ rows: 3,
1407
+ value: form.steps,
1408
+ onChange: (e) => setForm({
1409
+ ...form,
1410
+ steps: e.target.value
1411
+ })
1412
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
1413
+ className: TaskPanel_module_css_default.stepInput,
1414
+ placeholder: t("mem.f.trigger"),
1415
+ value: form.trigger,
1416
+ onChange: (e) => setForm({
1417
+ ...form,
1418
+ trigger: e.target.value
1419
+ })
1420
+ })] }),
1421
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1422
+ className: TaskPanel_module_css_default.memActs,
1423
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1424
+ variant: "outline",
1425
+ size: "sm",
1426
+ disabled: busy || !form.title.trim(),
1427
+ onClick: () => void submitNew(),
1428
+ children: t("mem.save")
1429
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1430
+ variant: "outline",
1431
+ size: "sm",
1432
+ onClick: closeForm,
1433
+ children: t("mem.cancel")
1434
+ })]
1435
+ })
1436
+ ]
1437
+ }),
1438
+ error && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1439
+ className: TaskPanel_module_css_default.notice,
1440
+ children: [
1441
+ t("mem.error"),
1442
+ ": ",
1443
+ error
1444
+ ]
1445
+ }),
1446
+ loading && !items.length && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1447
+ className: TaskPanel_module_css_default.muted,
1448
+ children: t("mem.loading")
1449
+ }),
1450
+ !loading && !error && items.length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1451
+ className: TaskPanel_module_css_default.muted,
1452
+ children: t("mem.empty")
1453
+ }),
1454
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1455
+ className: TaskPanel_module_css_default.memList,
1456
+ children: items.map((row) => {
1457
+ const canDemoteToTask = scope === "project" && !!boundTaskId;
1458
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1459
+ className: `${TaskPanel_module_css_default.memRow}${row.archived ? ` ${TaskPanel_module_css_default.memRowArchived}` : ""}`,
1460
+ children: [
1461
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1462
+ className: TaskPanel_module_css_default.memRowMain,
1463
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1464
+ className: TaskPanel_module_css_default.memTitle,
1465
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1466
+ className: TaskPanel_module_css_default.kindBadge,
1467
+ children: kindText(row.kind, t)
1468
+ }), row.title || row.body]
1469
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1470
+ className: TaskPanel_module_css_default.memMeta,
1471
+ children: [
1472
+ row.draft && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1473
+ className: `${TaskPanel_module_css_default.badge} ${TaskPanel_module_css_default.badgeDraft}`,
1474
+ children: t("mem.draft")
1475
+ }),
1476
+ row.archived && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1477
+ className: `${TaskPanel_module_css_default.badge} ${TaskPanel_module_css_default.badgeArchived}`,
1478
+ children: t("mem.archived")
1479
+ }),
1480
+ row.taskTitle && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1481
+ className: TaskPanel_module_css_default.badge,
1482
+ children: ["@", row.taskTitle]
1483
+ }),
1484
+ row.members !== void 0 && row.members > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1485
+ className: TaskPanel_module_css_default.badge,
1486
+ children: ["×", row.members]
1487
+ }),
1488
+ row.confidence != null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1489
+ className: TaskPanel_module_css_default.badge,
1490
+ children: [Math.round(row.confidence * 100), "%"]
1491
+ }),
1492
+ row.trigger && row.trigger.keywords.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1493
+ className: TaskPanel_module_css_default.badge,
1494
+ children: ["⚡", row.trigger.keywords.slice(0, 2).join(",")]
1495
+ })
1496
+ ]
1497
+ })]
1498
+ }),
1499
+ row.body && row.body !== row.title && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1500
+ className: TaskPanel_module_css_default.memBody,
1501
+ children: String(row.body).slice(0, 160)
1502
+ }),
1503
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1504
+ className: TaskPanel_module_css_default.memActs,
1505
+ children: [
1506
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1507
+ variant: "outline",
1508
+ size: "sm",
1509
+ disabled: busy,
1510
+ onClick: () => startEdit(row),
1511
+ children: t("mem.edit")
1512
+ }),
1513
+ scope === "task" && !row.archived && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [row.draft && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1514
+ variant: "outline",
1515
+ size: "sm",
1516
+ disabled: busy,
1517
+ onClick: () => void act("confirm", row.id),
1518
+ children: t("mem.confirm")
1519
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1520
+ variant: "outline",
1521
+ size: "sm",
1522
+ disabled: busy,
1523
+ onClick: () => void act("promote", row.id),
1524
+ children: t("mem.promote")
1525
+ })] }),
1526
+ scope === "project" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1527
+ variant: "outline",
1528
+ size: "sm",
1529
+ disabled: busy,
1530
+ onClick: () => void act("promote", row.id),
1531
+ children: t("mem.promote")
1532
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1533
+ variant: "outline",
1534
+ size: "sm",
1535
+ disabled: busy || !canDemoteToTask,
1536
+ title: !canDemoteToTask ? t("mem.needs-bound") : void 0,
1537
+ onClick: () => void act("demote", row.id),
1538
+ children: t("mem.demote")
1539
+ })] }),
1540
+ scope === "global" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1541
+ variant: "outline",
1542
+ size: "sm",
1543
+ disabled: busy,
1544
+ onClick: () => void act("demote", row.id),
1545
+ children: t("mem.demote")
1546
+ }),
1547
+ row.archived ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1548
+ variant: "outline",
1549
+ size: "sm",
1550
+ disabled: busy,
1551
+ onClick: () => void act("restore", row.id),
1552
+ children: t("mem.restore")
1553
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1554
+ variant: "outline",
1555
+ size: "sm",
1556
+ disabled: busy,
1557
+ onClick: () => void act("archive", row.id),
1558
+ children: t("mem.archive")
1559
+ }),
1560
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1561
+ variant: "outline",
1562
+ size: "sm",
1563
+ disabled: busy,
1564
+ onClick: () => void act("delete", row.id),
1565
+ children: t("mem.delete")
1566
+ })
1567
+ ]
1568
+ })
1569
+ ]
1570
+ }, row.id);
1571
+ })
1572
+ })
1573
+ ]
1574
+ });
1575
+ }
1576
+ //#endregion
891
1577
  //#region src/client/TaskPanel.tsx
892
1578
  /**
893
1579
  * Task Panel — dsh web `shell.overlay` 浮动任务面板。
@@ -899,8 +1585,13 @@ window.__ModuleLoader__.load({
899
1585
  "in_progress",
900
1586
  "completed"
901
1587
  ];
902
- function getT() {
903
- return createTranslate(typeof navigator !== "undefined" && navigator.language.startsWith("zh") ? zh : en);
1588
+ const VIEW_CYCLE = [
1589
+ "task",
1590
+ "project",
1591
+ "global"
1592
+ ];
1593
+ function getT(ctx) {
1594
+ return createTranslate(ctx?.locale?.getSnapshot?.()?.active === "zh" ? zh : en);
904
1595
  }
905
1596
  function useSessionId(ctx) {
906
1597
  const [, force] = (0, react.useState)(0);
@@ -936,7 +1627,7 @@ window.__ModuleLoader__.load({
936
1627
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PanelErrorBoundary, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TaskPanelView, { ctx }) });
937
1628
  }
938
1629
  function TaskPanelView({ ctx }) {
939
- const t = getT();
1630
+ const t = getT(ctx);
940
1631
  const data = useTaskData();
941
1632
  const ui = useTaskUI();
942
1633
  const sessionId = useSessionId(ctx);
@@ -944,10 +1635,17 @@ window.__ModuleLoader__.load({
944
1635
  const [syncedAt, setSyncedAt] = (0, react.useState)(0);
945
1636
  const [syncError, setSyncError] = (0, react.useState)(null);
946
1637
  const [showHints, setShowHints] = (0, react.useState)(true);
1638
+ const [view, setView] = (0, react.useState)("task");
1639
+ const cycleView = () => {
1640
+ const i = VIEW_CYCLE.indexOf(view);
1641
+ setView(VIEW_CYCLE[(i + 1) % VIEW_CYCLE.length]);
1642
+ };
1643
+ const viewTitle = view === "task" ? t("panel.title") : view === "global" ? t("view.global") : t("view.project");
947
1644
  const dataActions = useTaskDataActions();
948
1645
  const uiActions = useTaskUIActions();
949
- const activeTasks = data.tasks.filter((task) => !task.archived);
950
- const boundTask = data.boundTaskId ? data.tasks.find((task) => task.id === data.boundTaskId) ?? null : null;
1646
+ const tasks = Array.isArray(data.tasks) ? data.tasks : [];
1647
+ const activeTasks = tasks.filter((task) => !task.archived);
1648
+ const boundTask = data.boundTaskId ? tasks.find((task) => task.id === data.boundTaskId) ?? null : null;
951
1649
  const applyPayload = (text) => {
952
1650
  const parsed = parseTaskPayloadText(text);
953
1651
  if (!parsed) return false;
@@ -988,7 +1686,7 @@ window.__ModuleLoader__.load({
988
1686
  try {
989
1687
  const prevBoundId = data.boundTaskId;
990
1688
  await runLine("/tasks");
991
- const newBoundId = useTaskData.getSnapshot().boundTaskId;
1689
+ const newBoundId = taskDataStore.getSnapshot().boundTaskId;
992
1690
  if (newBoundId && newBoundId !== prevBoundId) await runLine(`/task switch ${newBoundId}`);
993
1691
  } finally {
994
1692
  setSyncing(false);
@@ -1003,6 +1701,16 @@ window.__ModuleLoader__.load({
1003
1701
  setSyncing(false);
1004
1702
  }
1005
1703
  };
1704
+ const handleInsightTask = async (action, id) => {
1705
+ if (syncing) return;
1706
+ setSyncing(true);
1707
+ try {
1708
+ await runLine(`/insight ${action} task ${id}`);
1709
+ await refresh();
1710
+ } finally {
1711
+ setSyncing(false);
1712
+ }
1713
+ };
1006
1714
  const pushSteps = (taskId, steps) => {
1007
1715
  runLine(`/task todos ${JSON.stringify(steps.map((s) => ({
1008
1716
  content: s.content,
@@ -1160,12 +1868,47 @@ window.__ModuleLoader__.load({
1160
1868
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutline16, { className: TaskPanel_module_css_default.headerIcon })
1161
1869
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
1162
1870
  className: TaskPanel_module_css_default.headerTitle,
1163
- children: t("panel.title")
1871
+ children: viewTitle
1164
1872
  })]
1165
1873
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1166
1874
  className: TaskPanel_module_css_default.headerRight,
1167
1875
  children: [
1168
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1876
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
1877
+ variant: "ghost",
1878
+ size: "sm",
1879
+ onClick: cycleView,
1880
+ "aria-label": t("view.cycle"),
1881
+ title: `${t("view.cycle")}(${view} → ${VIEW_CYCLE[(VIEW_CYCLE.indexOf(view) + 1) % VIEW_CYCLE.length]})`,
1882
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1883
+ width: "16",
1884
+ height: "16",
1885
+ viewBox: "0 0 24 24",
1886
+ fill: "none",
1887
+ stroke: "currentColor",
1888
+ strokeWidth: "2",
1889
+ strokeLinecap: "round",
1890
+ strokeLinejoin: "round",
1891
+ "aria-hidden": "true",
1892
+ children: [
1893
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2 6h4" }),
1894
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2 10h4" }),
1895
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2 14h4" }),
1896
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M2 18h4" }),
1897
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("rect", {
1898
+ width: "16",
1899
+ height: "20",
1900
+ x: "4",
1901
+ y: "2",
1902
+ rx: "2"
1903
+ }),
1904
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M15 2v20" }),
1905
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M15 7h5" }),
1906
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M15 12h5" }),
1907
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M15 17h5" })
1908
+ ]
1909
+ })
1910
+ }),
1911
+ view === "task" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1169
1912
  className: TaskPanel_module_css_default.counts,
1170
1913
  children: activeTasks.length > 0 ? `${t("panel.active")} ${activeTasks.length} · ${doneCount}/${activeTasks.length}` : ""
1171
1914
  }),
@@ -1208,7 +1951,13 @@ window.__ModuleLoader__.load({
1208
1951
  syncError
1209
1952
  ]
1210
1953
  }),
1211
- activeTasks.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1954
+ view !== "task" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(MemoryView, {
1955
+ ctx,
1956
+ sessionId,
1957
+ scope: view,
1958
+ boundTaskId: data.boundTaskId,
1959
+ t
1960
+ }) : activeTasks.length === 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1212
1961
  className: TaskPanel_module_css_default.emptyState,
1213
1962
  children: [
1214
1963
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
@@ -1242,6 +1991,7 @@ window.__ModuleLoader__.load({
1242
1991
  onEditStep: (index, value) => commitStepText(task.id, index, value),
1243
1992
  onCycleStatus: (index) => cycleStatus(task.id, index),
1244
1993
  onReorderSteps: (from, to) => reorderSteps(task.id, from, to),
1994
+ onInsightAction: (action, id) => void handleInsightTask(action, id),
1245
1995
  showHints,
1246
1996
  syncing,
1247
1997
  t
@@ -1266,14 +2016,15 @@ window.__ModuleLoader__.load({
1266
2016
  document.head.appendChild(tag);
1267
2017
  }
1268
2018
  var TaskCommandNode_module_css_default = {
1269
- "row": "TPe-xa_row",
1270
- "icon": "TPe-xa_icon"
2019
+ "icon": "TPe-xa_icon",
2020
+ "row": "TPe-xa_row"
1271
2021
  };
1272
2022
  //#endregion
1273
2023
  //#region src/client/TaskCommandNode.tsx
1274
2024
  /**
1275
- * /tasks、/task 命令在会话中的节点渲染器(conversation.chat.commandview,按命令名 key)。
1276
- * 列表型命令(/tasks、无动词 /task)同步数据并打开面板。
2025
+ * /tasks、/task、/insight 命令在会话中的节点渲染器(conversation.chat.commandview,按命令名 key)。
2026
+ * 列表型命令(/tasks、无动词 /task、/insight list)只显示一行摘要;/insight 的动作类只显示一句结果——
2027
+ * 目的:大 JSON 载荷绝不整段渲染进对话(否则切视图会刷屏)。
1277
2028
  */
1278
2029
  function TaskCommandNode({ node }) {
1279
2030
  const name = node?.name ?? "task";
@@ -1281,14 +2032,15 @@ window.__ModuleLoader__.load({
1281
2032
  const verb = (typeof node?.args === "string" ? node.args : "").trim().split(/\s+/)[0] ?? "";
1282
2033
  const isList = name === "tasks" || !verb;
1283
2034
  const text = outcome?.text ?? "";
1284
- const parsed = parseTaskPayloadText(text);
2035
+ const parsedTasks = name !== "insight" ? parseTaskPayloadText(text) : null;
2036
+ const parsedInsights = name === "insight" ? parseInsightPayloadText(text) : null;
1285
2037
  const live = (0, react.useRef)(outcome === null);
1286
2038
  (0, react.useEffect)(() => {
1287
- if (!parsed || !live.current) return;
2039
+ if (!parsedTasks || !live.current) return;
1288
2040
  taskDataStore.actions.setTasks({
1289
- tasks: parsed.tasks,
1290
- boundTaskId: parsed.boundId,
1291
- archivedCount: parsed.archived
2041
+ tasks: parsedTasks.tasks,
2042
+ boundTaskId: parsedTasks.boundId,
2043
+ archivedCount: parsedTasks.archived
1292
2044
  });
1293
2045
  if (isList) taskUIStore.actions.open();
1294
2046
  }, [text]);
@@ -1314,6 +2066,34 @@ window.__ModuleLoader__.load({
1314
2066
  ]
1315
2067
  });
1316
2068
  }
2069
+ if (name === "insight") {
2070
+ if (verb === "list" && parsedInsights) {
2071
+ const scope = parsedInsights.scope;
2072
+ const count = parsedInsights.count ?? parsedInsights.items.length;
2073
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2074
+ className: TaskCommandNode_module_css_default.row,
2075
+ "data-variant": "ok",
2076
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconFolderOpenOutline16, { className: TaskCommandNode_module_css_default.icon }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", { children: [
2077
+ "记忆 ",
2078
+ scope,
2079
+ " · ",
2080
+ count,
2081
+ " 条 · 已同步到记忆视图"
2082
+ ] })]
2083
+ });
2084
+ }
2085
+ const note = String(text ?? "").split("\n")[0].slice(0, 120);
2086
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2087
+ className: TaskCommandNode_module_css_default.row,
2088
+ "data-variant": "ok",
2089
+ children: [
2090
+ "/insight ",
2091
+ verb,
2092
+ " ",
2093
+ note || "已完成"
2094
+ ]
2095
+ });
2096
+ }
1317
2097
  if (!isList) {
1318
2098
  const note = String(text ?? "").split(/\n{2,}/)[0].replace(/```.*$/s, "").trim().slice(0, 200);
1319
2099
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
@@ -1327,9 +2107,9 @@ window.__ModuleLoader__.load({
1327
2107
  ]
1328
2108
  });
1329
2109
  }
1330
- const count = parsed ? parsed.tasks.length : 0;
1331
- const archived = parsed ? parsed.archived : 0;
1332
- const label = parsed ? `任务 ${count} 套${archived ? `(归档 ${archived})` : ""} · 已同步到任务面板` : `/${name} 已执行`;
2110
+ const count = parsedTasks ? parsedTasks.tasks.length : 0;
2111
+ const archived = parsedTasks ? parsedTasks.archived : 0;
2112
+ const label = parsedTasks ? `任务 ${count} 套${archived ? `(归档 ${archived})` : ""} · 已同步到任务面板` : `/${name} 已执行`;
1333
2113
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1334
2114
  className: TaskCommandNode_module_css_default.row,
1335
2115
  "data-variant": "ok",
@@ -1358,7 +2138,8 @@ window.__ModuleLoader__.load({
1358
2138
  "slots",
1359
2139
  "sessions",
1360
2140
  "remote",
1361
- "remote.commands"
2141
+ "remote.commands",
2142
+ "locale"
1362
2143
  ];
1363
2144
  function apply(ctx) {
1364
2145
  const slots = ctx?.slots;
@@ -1372,7 +2153,11 @@ window.__ModuleLoader__.load({
1372
2153
  id: "dsh-project-memory-task-panel",
1373
2154
  order: 100
1374
2155
  }, () => (0, react.createElement)(TaskPanelEntry, { ctx })));
1375
- for (const key of ["tasks", "task"]) slots.inject("conversation.chat.commandview", () => slots.register({
2156
+ for (const key of [
2157
+ "tasks",
2158
+ "task",
2159
+ "insight"
2160
+ ]) slots.inject("conversation.chat.commandview", () => slots.register({
1376
2161
  name: "conversation.chat.commandview",
1377
2162
  key
1378
2163
  }, TaskCommandNode));