dsh-session-conductor 0.0.0-stage → 1.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +165 -2
  2. package/cordis.patch.yml +48 -0
  3. package/lib/apply.js +1361 -0
  4. package/lib/client-parts/apply.js +43 -0
  5. package/lib/client-parts/components/compaction.js +124 -0
  6. package/lib/client-parts/components/conductor-settings.js +62 -0
  7. package/lib/client-parts/components/group.js +115 -0
  8. package/lib/client-parts/components/panel.js +1265 -0
  9. package/lib/client-parts/components/processing.js +98 -0
  10. package/lib/client-parts/components/session-icon.js +20 -0
  11. package/lib/client-parts/components/settings.js +415 -0
  12. package/lib/client-parts/foundation/bootstrap.js +48 -0
  13. package/lib/client-parts/foundation/i18n.js +74 -0
  14. package/lib/client-parts/foundation/list-cache.js +28 -0
  15. package/lib/client-parts/foundation/styles.js +236 -0
  16. package/lib/client.js +2534 -0
  17. package/lib/core/config.js +159 -0
  18. package/lib/core/domain.js +157 -0
  19. package/lib/core/lazy.js +20 -0
  20. package/lib/core/state.js +106 -0
  21. package/lib/core.js +82 -0
  22. package/lib/eio-repair.js +204 -0
  23. package/lib/features/context-usage/index.js +219 -0
  24. package/lib/features/continue/eligibility.js +49 -0
  25. package/lib/features/continue/scan.js +134 -0
  26. package/lib/features/continue/session.js +235 -0
  27. package/lib/features/inject/preset.js +20 -0
  28. package/lib/features/member-model/index.js +14 -0
  29. package/lib/features/member-model/locate.js +157 -0
  30. package/lib/features/member-model/override.js +76 -0
  31. package/lib/features/member-model/setup.js +55 -0
  32. package/lib/features/member-model/switch.js +186 -0
  33. package/lib/features/rename/analysis.js +303 -0
  34. package/lib/features/rename/title.js +158 -0
  35. package/lib/features/rename/value.js +77 -0
  36. package/lib/features/search.js +119 -0
  37. package/lib/features/session-ops-routes.js +218 -0
  38. package/lib/features/session-ops.js +414 -0
  39. package/lib/group.js +303 -0
  40. package/lib/guards.js +28 -0
  41. package/lib/http.js +24 -0
  42. package/lib/i18n/en.json +204 -0
  43. package/lib/i18n/zh.json +204 -0
  44. package/lib/index.js +78 -0
  45. package/lib/repair.js +398 -0
  46. package/lib/seq-gap-repair.js +224 -0
  47. package/lib/session-codec.js +37 -0
  48. package/lib/session-log.js +46 -0
  49. package/lib/sessions/detach.js +113 -0
  50. package/lib/sessions/events.js +73 -0
  51. package/lib/sessions/interruption.js +73 -0
  52. package/lib/sessions/list-cache.js +175 -0
  53. package/lib/sessions/list.js +187 -0
  54. package/lib/sessions/route.js +60 -0
  55. package/lib/sessions/turn.js +21 -0
  56. package/lib/shared/constants.js +20 -0
  57. package/lib/shared/log.js +17 -0
  58. package/lib/shared/settings.js +14 -0
  59. package/lib/shared/test-hooks.js +93 -0
  60. package/lib/shared/util.js +6 -0
  61. package/lib/template-inject.js +289 -0
  62. package/lib/value.js +430 -0
  63. package/lib/zstd-frames.js +177 -0
  64. package/package.json +65 -3
  65. package/skills/dsh-session-conductor-functions.md +197 -0
  66. package/skills/dsh-session-conductor.md +151 -0
  67. package/skills/dsh-session-official-doc.md +245 -0
  68. package/skills/task-completion-report.md +56 -0
@@ -0,0 +1,43 @@
1
+ function apply(ctx) {
2
+ // 插槽排序(slots 顺序权重,小在前):设置左侧栏「会话管理」页 vs 侧边栏底部入口
3
+ const SETTINGS_SECTION_ORDER = 40;
4
+ const SIDEBAR_ACTION_ORDER = 90;
5
+ ctx.effect(() => ctx.locale.register(NS, { zh, en }), "session-conductor: dictionaries");
6
+ const slots = ctx.get("slots");
7
+ if (slots !== undefined) {
8
+ slots.inject("settings.section", () => slots.register(
9
+ { name: "settings.section", id: "session-conductor", order: SETTINGS_SECTION_ORDER, label: () => trSettings("settings.nav") },
10
+ () => h(ConductorSettingsPage, null),
11
+ ));
12
+ }
13
+ ctx.slots.inject("sidebar.footer.action", () => ctx.slots.register({
14
+ name: "sidebar.footer.action",
15
+ id: "session-conductor",
16
+ order: SIDEBAR_ACTION_ORDER,
17
+ locale: NS,
18
+ inject: () => ({
19
+ onOpenSession: (sessionId) => {
20
+ try {
21
+ ctx.get("sessions")?.open?.(sessionId);
22
+ } catch {
23
+ // 打开失败不阻塞面板
24
+ }
25
+ },
26
+ }),
27
+ }, SessionManagerPanel));
28
+ }
29
+
30
+ exports.apply = apply;
31
+ exports.inject = inject;
32
+
33
+
34
+ /**
35
+ * dsh-session-conductor — 「会话分组」精简卡(裁剪后版本)
36
+ *
37
+ * 分组管理(创建/重命名/删除/移动会话)已移除,回归 DSH 官方 workspace 机制。
38
+ * 本卡只保留:
39
+ * · 分组列表(GET /api/session-conductor/group/list,只读展示)
40
+ * · 每行「在分组下新建会话」(POST /api/session-conductor/group/new-session {workspaceId})
41
+ * · 「新建会话(上次会话工作区)」(new-session 不带 workspaceId = 最近活跃会话 cwd 归属分组)
42
+ */
43
+
@@ -0,0 +1,124 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "dsh-session-conductor-compaction-model",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+ let react = require("react");
8
+ let react_jsx_runtime = require("react/jsx-runtime");
9
+
10
+ const NS = "sessionConductorCompaction";
11
+ const zh = {};
12
+ const en = {};
13
+ __scFillI18nDict("sessionConductorCompaction", zh, en);
14
+
15
+ /** 自定义模式下 provider / model 输入框宽度(px)。 */
16
+ const PROVIDER_INPUT_WIDTH = 110;
17
+ const MODEL_INPUT_WIDTH = 160;
18
+
19
+ const css = `
20
+ .cm_card { border:1px solid var(--dsw-alias-border-l1,rgba(128,128,128,.2)); border-radius:10px; padding:12px; margin-top:8px; background:var(--dsw-alias-bg-base,#141518); }
21
+ .cm_hint { color:var(--dsw-alias-label-tertiary,#888); font-size:12px; margin:2px 0 10px; line-height:1.5; }
22
+ .cm_row { display:flex; gap:8px; align-items:center; margin-bottom:8px; flex-wrap:wrap; }
23
+ .cm_input { height:28px; border-radius:6px; border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3)); background:var(--dsw-alias-bg-base,#141518); color:var(--dsw-alias-label-primary,#eee); padding:0 10px; font-size:12.5px; }
24
+ .cm_btn { height:28px; border-radius:6px; border:1px solid var(--dsw-alias-border-l2,rgba(128,128,128,.3)); background:var(--dsw-alias-interactive-bg-hover,rgba(128,128,128,.15)); color:var(--dsw-alias-label-primary,#eee); cursor:pointer; padding:0 14px; font-size:12.5px; }
25
+ .cm_btn:hover { background:rgba(128,128,128,.25); }
26
+ .cm_msg { font-size:12px; margin-top:6px; }
27
+ `;
28
+ const styleId = "sm-compaction-css";
29
+ if (typeof document !== "undefined" && !document.getElementById(styleId)) {
30
+ const s = document.createElement("style");
31
+ s.id = styleId;
32
+ s.textContent = css;
33
+ document.head.appendChild(s);
34
+ }
35
+
36
+ function CompactionModelCard({ t }) {
37
+ const [mode, setMode] = react.useState("follow"); // follow | custom
38
+ const [provider, setProvider] = react.useState("llm-pi-ai");
39
+ const [model, setModel] = react.useState("agnes-2.5-flash");
40
+ const [msg, setMsg] = react.useState(null);
41
+ const [busy, setBusy] = react.useState(false);
42
+
43
+ react.useEffect(() => {
44
+ (async () => {
45
+ try {
46
+ const r = await window.__scFetch("/api/session-conductor/compaction-model", { headers: { accept: "application/json" } });
47
+ const payload = await r.json();
48
+ if (payload?.ok && payload.compactionModel) {
49
+ setMode("custom");
50
+ setProvider(payload.compactionModel.provider || "");
51
+ setModel(payload.compactionModel.model || "");
52
+ } else if (payload?.ok) setMode("follow");
53
+ } catch { /* 初始加载失败忽略 */ }
54
+ })();
55
+ }, []);
56
+
57
+ const save = async () => {
58
+ setBusy(true); setMsg(null);
59
+ try {
60
+ const body = mode === "follow"
61
+ ? { follow: true }
62
+ : { provider, model };
63
+ const r = await window.__scFetch("/api/session-conductor/compaction-model", {
64
+ method: "POST",
65
+ headers: { "Content-Type": "application/json" },
66
+ body: JSON.stringify(body),
67
+ });
68
+ const payload = await r.json();
69
+ setMsg(payload?.ok ? t("saved") : (payload?.error?.message || t("error")));
70
+ } catch { setMsg(t("error")); }
71
+ setBusy(false);
72
+ };
73
+
74
+ return react_jsx_runtime.jsxs("div", { className: "cm_card", children: [
75
+ react_jsx_runtime.jsx("div", { className: "cm_hint", children: t("desc") }),
76
+ react_jsx_runtime.jsxs("div", { className: "cm_row", children: [
77
+ react_jsx_runtime.jsx("label", { children: react_jsx_runtime.jsx("input", { type: "radio", name: "cm-mode", checked: mode === "follow", onChange: () => setMode("follow") }) }),
78
+ react_jsx_runtime.jsx("span", { children: t("follow") }),
79
+ react_jsx_runtime.jsx("label", { children: react_jsx_runtime.jsx("input", { type: "radio", name: "cm-mode", checked: mode === "custom", onChange: () => setMode("custom") }) }),
80
+ react_jsx_runtime.jsx("span", { children: t("custom") }),
81
+ ]}),
82
+ mode === "custom" && react_jsx_runtime.jsxs("div", { className: "cm_row", children: [
83
+ react_jsx_runtime.jsx("span", { children: t("provider") }),
84
+ react_jsx_runtime.jsx("input", { className: "cm_input", value: provider, onChange: (e) => setProvider(e.target.value), style: { width: PROVIDER_INPUT_WIDTH } }),
85
+ react_jsx_runtime.jsx("span", { children: t("model") }),
86
+ react_jsx_runtime.jsx("input", { className: "cm_input", value: model, onChange: (e) => setModel(e.target.value), style: { width: MODEL_INPUT_WIDTH } }),
87
+ ]}),
88
+ mode === "follow" && react_jsx_runtime.jsx("div", { className: "cm_hint", children: t("followNote") }),
89
+ react_jsx_runtime.jsxs("div", { className: "cm_row", children: [
90
+ react_jsx_runtime.jsx("button", { className: "cm_btn", disabled: busy, onClick: save, children: t("save") }),
91
+ msg && react_jsx_runtime.jsx("span", { className: "cm_msg", children: msg }),
92
+ ]}),
93
+ ]});
94
+ }
95
+
96
+ function apply(ctx) {
97
+ ctx.effect(() => ctx.locale.register(NS, { zh, en }), "dsh-session-conductor-compaction-model: dictionaries");
98
+ ctx.slots.inject("settings.plugin.item", () => ctx.slots.register({
99
+ name: "settings.plugin.item",
100
+ key: "session-conductor-compaction",
101
+ locale: NS,
102
+ }, function WrappedCard(props) {
103
+ const t = ctx.locale.bind(NS);
104
+ return react_jsx_runtime.jsxs("div", { children: [
105
+ react_jsx_runtime.jsx("div", { children: t("title") }),
106
+ react_jsx_runtime.jsx(CompactionModelCard, { t }),
107
+ ] });
108
+ }));
109
+ }
110
+
111
+ const inject = ["slots", "locale"];
112
+ exports.apply = apply;
113
+ exports.inject = inject;
114
+ return module.exports;
115
+ }
116
+ });
117
+ /**
118
+ * dsh-session-conductor — 「会话管理」设置侧边栏页( 新增)
119
+ *
120
+ * 注册 settings.section 侧边栏导航(设置左栏出现「会话管理」条目),
121
+ * 点开是完整聚合页——会话管理说明 + 模板注入。
122
+ * UI 组件 scs_* = 页面级。
123
+ */
124
+
@@ -0,0 +1,62 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "dsh-session-conductor-settings",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+
8
+ let react = require("react");
9
+ let react_jsx_runtime = require("react/jsx-runtime");
10
+
11
+ const NS = "sessionConductorSettings";
12
+ const zh = {};
13
+ const en = {};
14
+ __scFillI18nDict("sessionConductorSettings", zh, en);
15
+
16
+ const css = `
17
+ .scs_page { display:flex; flex-direction:column; gap:16px; }
18
+ .scs_hero { display:flex; flex-direction:column; gap:6px; }
19
+ .scs_title { font-size:20px; font-weight:650; color:var(--dsw-alias-label-primary); }
20
+ .scs_desc { font-size:13px; line-height:1.6; color:var(--dsw-alias-label-tertiary); max-width:72ch; }
21
+ .scs_hint { font-size:11px; line-height:16px; color:var(--dsw-alias-label-tertiary); }
22
+ .scs_card { display:flex; flex-direction:column; gap:12px; padding:16px; border:.5px solid var(--dsw-alias-border-l4); border-radius:16px; background:var(--dsw-alias-bg-layer-3); }
23
+ .scs_cardtitle { font-size:15px; font-weight:600; color:var(--dsw-alias-label-primary); }
24
+ .scs_note { font-size:12px; line-height:1.7; color:var(--dsw-alias-label-secondary); padding:10px 12px; border:1px dashed var(--dsw-alias-border-l2); border-radius:10px; }
25
+ `;
26
+ const styleId = "scs-css";
27
+ if (typeof document !== "undefined" && !document.getElementById(styleId)) {
28
+ const s = document.createElement("style");
29
+ s.id = styleId;
30
+ s.textContent = css;
31
+ document.head.appendChild(s);
32
+ }
33
+
34
+
35
+
36
+ // ── 设置侧边栏页(settings.section,仿 skill-scoreboard)───────────────
37
+ function ScsPage({ t }) {
38
+ return react_jsx_runtime.jsxs("div", { className: "scs_page", children: [
39
+ react_jsx_runtime.jsxs("div", { className: "scs_hero", children: [
40
+ react_jsx_runtime.jsx("div", { className: "scs_title", children: t("title") }),
41
+ react_jsx_runtime.jsx("div", { className: "scs_desc", children: t("desc") }),
42
+ react_jsx_runtime.jsx("div", { className: "scs_hint", children: t("scopeHint") }),
43
+ ] }),
44
+ react_jsx_runtime.jsxs("div", { className: "scs_note", children: [
45
+ react_jsx_runtime.jsx("b", { children: t("noteTitle") + ":" }),
46
+ t("noteBody"),
47
+ ] }),
48
+ ] });
49
+ }
50
+
51
+ function apply(ctx) {
52
+ // 设置页只在主入口 dsh-session-conductor 注册。这里再挂 settings.section
53
+ // 会用 jsx-runtime 把页面打成空白。
54
+ ctx.effect(() => ctx.locale.register(NS, { zh, en }), "session-conductor-settings: dictionaries");
55
+ }
56
+
57
+ const inject = ["slots", "locale"];
58
+ exports.apply = apply;
59
+ exports.inject = inject;
60
+ return module.exports;
61
+ },
62
+ });
@@ -0,0 +1,115 @@
1
+ window.__ModuleLoader__.load({
2
+ id: "dsh-session-conductor-group",
3
+ factory: (require) => {
4
+ var module = { exports: {} };
5
+ var exports = module.exports;
6
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
7
+
8
+ let react = require("react");
9
+ let react_jsx_runtime = require("react/jsx-runtime");
10
+
11
+ const NS = "sessionGroup";
12
+ const zh = {};
13
+ const en = {};
14
+ __scFillI18nDict("sessionGroup", zh, en);
15
+
16
+ const css = `
17
+ .sg2_card { display:flex; flex-direction:column; gap:10px; }
18
+ .sg2_row { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
19
+ .sg2_btn { cursor:pointer; border:1px solid var(--dsw-alias-border-l1, rgba(128,128,128,.35)); background:var(--dsw-specific-tip, transparent); color:var(--dsw-alias-label-secondary, inherit); border-radius:8px; height:28px; padding:0 12px; font-size:12px; line-height:26px; display:inline-flex; align-items:center; gap:4px; white-space:nowrap; }
20
+ .sg2_btn:hover { background:var(--dsw-alias-interactive-bg-hover, rgba(128,128,128,.15)); }
21
+ .sg2_btn:disabled { opacity:.45; cursor:default; }
22
+ .sg2_hint { color:var(--dsw-alias-label-tertiary, #888); font-size:11px; line-height:16px; }
23
+ .sg2_listTitle { font-size:12px; color:var(--dsw-alias-label-secondary, inherit); margin-top:4px; }
24
+ .sg2_item { display:flex; align-items:center; gap:8px; padding:6px 8px; border-radius:8px; font-size:12px; border:1px solid var(--dsw-alias-border-l1, rgba(128,128,128,.2)); }
25
+ .sg2_item .sg2_name { flex:1; min-width:0; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; }
26
+ .sg2_item .sg2_meta { color:var(--dsw-alias-label-tertiary, #888); font-size:11px; flex:none; }
27
+ .sg2_msg { font-size:12px; line-height:18px; }
28
+ .sg2_msg.err { color:var(--dsw-state-error-primary, #d9534f); }
29
+ .sg2_msg.ok { color:var(--dsw-state-success-primary, #4caf50); }
30
+ `;
31
+ const styleId = "dsh-session-group-css";
32
+ if (typeof document !== "undefined" && !document.getElementById(styleId)) {
33
+ const s = document.createElement("style");
34
+ s.id = styleId;
35
+ s.textContent = css;
36
+ document.head.appendChild(s);
37
+ }
38
+
39
+ function SessionGroupCard({ t }) {
40
+ const [workspaces, setWorkspaces] = react.useState(null);
41
+ const [busy, setBusy] = react.useState(false);
42
+ const [msg, setMsg] = react.useState(null);
43
+ const load = () => {
44
+ window.__scFetch("/api/session-conductor/group/list").then((r) => r.json()).then((b) => {
45
+ if (b.ok) setWorkspaces(b.workspaces ?? []);
46
+ }).catch(() => setWorkspaces([]));
47
+ };
48
+ react.useEffect(() => { load(); }, []);
49
+ const createIn = async (workspaceId) => {
50
+ if (busy) return;
51
+ setBusy(true); setMsg(null);
52
+ try {
53
+ const r = await window.__scFetch("/api/session-conductor/group/new-session", {
54
+ method: "POST",
55
+ headers: { "Content-Type": "application/json" },
56
+ body: JSON.stringify(workspaceId ? { workspaceId } : {}),
57
+ });
58
+ const b = await r.json();
59
+ if (!b.ok) throw new Error(b.error || ("HTTP " + r.status));
60
+ setMsg({ kind: "ok", text: t("ok") });
61
+ load();
62
+ } catch (e) {
63
+ setMsg({ kind: "err", text: t("fail", { message: (e && e.message) || String(e) }) });
64
+ } finally { setBusy(false); }
65
+ };
66
+ return react_jsx_runtime.jsxs("div", { className: "sg2_card", children: [
67
+ react_jsx_runtime.jsx("div", { className: "sg2_hint", children: t("desc") }),
68
+ react_jsx_runtime.jsxs("div", { className: "sg2_row", children: [
69
+ react_jsx_runtime.jsx("button", { className: "sg2_btn", disabled: busy, onClick: () => createIn(""), children: busy ? t("busy") : t("newDefault") }),
70
+ react_jsx_runtime.jsx("button", { className: "sg2_btn", disabled: busy, onClick: load, children: t("refresh") }),
71
+ ] }),
72
+ react_jsx_runtime.jsx("div", { className: "sg2_listTitle", children: t("listTitle") }),
73
+ !workspaces
74
+ ? react_jsx_runtime.jsx("div", { className: "sg2_hint", children: t("listEmpty") })
75
+ : workspaces.map((w) => react_jsx_runtime.jsxs("div", { className: "sg2_item", key: w.workspaceId, children: [
76
+ react_jsx_runtime.jsx("span", { className: "sg2_name", children: w.title || w.path }),
77
+ react_jsx_runtime.jsx("span", { className: "sg2_meta", children: __SC_TR__("sessionCount", { n: w.sessionIds?.length ?? 0 }) }),
78
+ react_jsx_runtime.jsx("button", { className: "sg2_btn", disabled: busy, onClick: () => createIn(w.workspaceId), children: busy ? t("busy") : t("newIn") }),
79
+ ] })),
80
+ msg && react_jsx_runtime.jsx("div", { className: "sg2_msg " + (msg.kind === "err" ? "err" : "ok"), children: msg.text }),
81
+ ] });
82
+ }
83
+
84
+ function apply(ctx) {
85
+ ctx.effect(() => ctx.locale.register(NS, { zh, en }), "dsh-session-group: dictionaries");
86
+ ctx.slots.inject("settings.plugin.item", () => ctx.slots.register({
87
+ name: "settings.plugin.item",
88
+ key: "session-conductor-group",
89
+ locale: NS,
90
+ }, function WrappedCard(props) {
91
+ const t = ctx.locale.bind(NS);
92
+ return react_jsx_runtime.jsxs("div", { children: [
93
+ react_jsx_runtime.jsx("div", { children: t("title") }),
94
+ react_jsx_runtime.jsx(SessionGroupCard, { t }),
95
+ ] });
96
+ }));
97
+ }
98
+
99
+ const inject = ["slots", "locale"];
100
+ exports.apply = apply;
101
+ exports.inject = inject;
102
+ return module.exports;
103
+ }
104
+ });
105
+
106
+ /**
107
+ * dsh-session-conductor — 「第一条正在处理」队列条目(client 附加模块, 改写)
108
+ *
109
+ * DSH 原生排队逻辑:第一条消息(claimed)立即执行、从 host inbox 移除,因此
110
+ * 原生排队 dock 只显示「后续排队消息」,执行中的第一条不可见。
111
+ * 本模块在原生 dock 区域**上方**渲染一条与原生 QueueDock 同风格的条目:
112
+ * 「⚙️ {第一条消息摘要}」——第一条也显示在排队列表里,回合结束(执行完)自动消失。
113
+ * 排队消息列表仍由原生 dock 负责(不重复渲染)。不改 DSH 原生源码。
114
+ */
115
+