dsh-archify-projects 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +13 -0
- package/dist/client.js +255 -14
- package/dist/client.js.map +1 -1
- package/docs/DESIGN.md +81 -0
- package/docs/HANDOVER.md +111 -4
- package/lib/host/context.js.map +1 -1
- package/lib/host/index.js +4 -2
- package/lib/host/index.js.map +1 -1
- package/lib/host/models.js +137 -0
- package/lib/host/models.js.map +1 -0
- package/lib/host/routes.js +43 -0
- package/lib/host/routes.js.map +1 -1
- package/lib/host/runner.js +140 -16
- package/lib/host/runner.js.map +1 -1
- package/lib/host/settings.js +83 -0
- package/lib/host/settings.js.map +1 -0
- package/lib/shared/model-key.js +12 -0
- package/lib/shared/model-key.js.map +1 -0
- package/lib/shared/protocol.js +2 -0
- package/lib/shared/protocol.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -98,6 +98,8 @@ pnpm add link:/absolute/path/to/dsh-archify-projects # 或在 package.json 里
|
|
|
98
98
|
3. 首次添加会自动跑一次 `create`:结构图 + 领域图各一张,通常几分钟。
|
|
99
99
|
4. 之后随时「更新」:切回记录的分支 → 快进到最新 → 重画两张图。
|
|
100
100
|
5. 图是可以直接看的 HTML(archify 产物:可搜索、可缩放、可导出),不是截图。
|
|
101
|
+
6. 右上角**齿轮**是设置:只有一个「分析模型」下拉,选项就是你在 DSH 里已经配好、
|
|
102
|
+
当前真能路由的模型;不选=跟随宿主默认。改完对下一次运行生效。
|
|
101
103
|
|
|
102
104
|
---
|
|
103
105
|
|
|
@@ -126,6 +128,16 @@ pnpm add link:/absolute/path/to/dsh-archify-projects # 或在 package.json 里
|
|
|
126
128
|
`restrict` 只能装在 scoped ctx(`agent.ctx`)上,写在 preset 行里会直接抛 ——
|
|
127
129
|
所以白名单与守卫在 `src/host/policy.ts` 里,运行开始时对当次会话安装。
|
|
128
130
|
|
|
131
|
+
### 分析跑在子代理会话里,不占你的会话列表
|
|
132
|
+
|
|
133
|
+
每次出图 / 提问都用一个 **`origin: 'subagent'` 的会话**(`ctx.agents.create` +
|
|
134
|
+
`agentPresets.mount`),所以:
|
|
135
|
+
|
|
136
|
+
- DSH 左侧会话列表按 origin 过滤子代理会话 —— 分析不会往你的对话列表里塞新条目;
|
|
137
|
+
- 会话的模型走 `agentOptions`,**只影响这一次运行**,不会改掉 DSH 里你的默认模型;
|
|
138
|
+
- 宿主版本没有这条路(缺 `agents.create` / `agentPresets`)时安静退回普通会话,
|
|
139
|
+
工具白名单、preset、产物回收都不变。
|
|
140
|
+
|
|
129
141
|
### 深浅色
|
|
130
142
|
|
|
131
143
|
页面只用 DSH 的主题令牌(`--dsw-alias-*` / `--dsw-specific-*` / `--dsw-radius-*` /
|
|
@@ -217,6 +229,7 @@ scripts/ artifact 门禁
|
|
|
217
229
|
| 位置 | 内容 |
|
|
218
230
|
| ------------------------------------------------------------ | --------------------------------------------------------------------------------------- |
|
|
219
231
|
| `~/.dsh/archify-projects/projects.json`(可用 `dataDir` 改) | 台账:项目、Git 快照、两张图的状态、运行历史(保留最近 20 条) |
|
|
232
|
+
| 同目录 `settings.json` | 插件设置:分析用哪个模型(`{ provider, model }`,null = 跟随宿主默认) |
|
|
220
233
|
| `~/.dsh/archify-projects/workspace/<projectId>/` | 每个项目的工作目录;`.archify/<kind>-<slug>-<stamp>/` 里是 `candidate.json` 与成品 HTML |
|
|
221
234
|
| `<插件目录>/skills/archify/` | 内嵌的 archify skill(不进 git:见 `.gitignore`;npm 包用 `files` 带上) |
|
|
222
235
|
|
package/dist/client.js
CHANGED
|
@@ -28,6 +28,8 @@ const ROUTES = {
|
|
|
28
28
|
mergeQa: (id, qaId) => `${ROUTE_PREFIX}/projects/${encodeURIComponent(id)}/qa/${encodeURIComponent(qaId)}/merge`,
|
|
29
29
|
childQa: (id, qaId) => `${ROUTE_PREFIX}/projects/${encodeURIComponent(id)}/qa/${encodeURIComponent(qaId)}/child`,
|
|
30
30
|
runs: (id) => `${ROUTE_PREFIX}/projects/${encodeURIComponent(id)}/runs`,
|
|
31
|
+
/** 插件级设置(目前只有「分析用哪个模型」)。 */
|
|
32
|
+
settings: `${ROUTE_PREFIX}/settings`,
|
|
31
33
|
artifact: (relativePath) => `${ROUTE_PREFIX}/artifact/${relativePath.split(/[\\/]+/).map((part) => encodeURIComponent(part)).join("/")}`
|
|
32
34
|
};
|
|
33
35
|
|
|
@@ -163,7 +165,7 @@ async function api(path, init) {
|
|
|
163
165
|
const message = result.error?.message ?? "未知错误";
|
|
164
166
|
throw new ApiError(code, message);
|
|
165
167
|
}
|
|
166
|
-
/** POST/PATCH 的便捷封装。 */
|
|
168
|
+
/** POST/PUT/PATCH/DELETE 的便捷封装。 */
|
|
167
169
|
function send(path, method, body) {
|
|
168
170
|
return api(path, {
|
|
169
171
|
method,
|
|
@@ -171,6 +173,12 @@ function send(path, method, body) {
|
|
|
171
173
|
});
|
|
172
174
|
}
|
|
173
175
|
|
|
176
|
+
// src/shared/model-key.ts
|
|
177
|
+
/** 生成路由键。 */
|
|
178
|
+
function modelKey(ref) {
|
|
179
|
+
return `${ref.provider}::${ref.model}`;
|
|
180
|
+
}
|
|
181
|
+
|
|
174
182
|
// src/client/components.tsx
|
|
175
183
|
/**
|
|
176
184
|
* 页面里可复用的小组件:标签、状态点、两个对话框。
|
|
@@ -531,6 +539,136 @@ function NewDiagramDialog({ t, project, selectedId, busy, onClose, onSubmit }) {
|
|
|
531
539
|
})
|
|
532
540
|
});
|
|
533
541
|
}
|
|
542
|
+
/** 齿轮图标(设置入口)。尺寸跟随字号,颜色跟随按钮。 */
|
|
543
|
+
function GearIcon({ size = 13 }) {
|
|
544
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
|
|
545
|
+
width: size,
|
|
546
|
+
height: size,
|
|
547
|
+
viewBox: "0 0 24 24",
|
|
548
|
+
fill: "none",
|
|
549
|
+
stroke: "currentColor",
|
|
550
|
+
strokeWidth: 1.7,
|
|
551
|
+
strokeLinecap: "round",
|
|
552
|
+
strokeLinejoin: "round",
|
|
553
|
+
"aria-hidden": "true",
|
|
554
|
+
focusable: "false",
|
|
555
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
|
|
556
|
+
cx: "12",
|
|
557
|
+
cy: "12",
|
|
558
|
+
r: "3.1"
|
|
559
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", { d: "M19.4 15a1.6 1.6 0 0 0 .32 1.77l.06.06a1.9 1.9 0 1 1-2.7 2.7l-.06-.06a1.6 1.6 0 0 0-1.77-.32 1.6 1.6 0 0 0-.97 1.47V21a1.9 1.9 0 1 1-3.8 0v-.1a1.6 1.6 0 0 0-1.05-1.47 1.6 1.6 0 0 0-1.77.32l-.06.06a1.9 1.9 0 1 1-2.7-2.7l.06-.06A1.6 1.6 0 0 0 4.6 15a1.6 1.6 0 0 0-1.47-.97H3a1.9 1.9 0 1 1 0-3.8h.1a1.6 1.6 0 0 0 1.47-1.05 1.6 1.6 0 0 0-.32-1.77l-.06-.06a1.9 1.9 0 1 1 2.7-2.7l.06.06A1.6 1.6 0 0 0 9 4.6a1.6 1.6 0 0 0 .97-1.47V3a1.9 1.9 0 1 1 3.8 0v.1a1.6 1.6 0 0 0 .97 1.47 1.6 1.6 0 0 0 1.77-.32l.06-.06a1.9 1.9 0 1 1 2.7 2.7l-.06.06a1.6 1.6 0 0 0-.32 1.77V9a1.6 1.6 0 0 0 1.47.97H21a1.9 1.9 0 1 1 0 3.8h-.1a1.6 1.6 0 0 0-1.47.97z" })]
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* 设置对话框:**只有一个字段**——分析用哪个模型。
|
|
564
|
+
*
|
|
565
|
+
* 模型选项不是插件编的,是宿主 `modelCatalog()` 列出来的(用户在 DSH 里
|
|
566
|
+
* 配好、当前真的能路由到的那些)。目录拿不到时只留「跟随宿主默认」一项,
|
|
567
|
+
* 并且把原因写在提示里,不假装能选。
|
|
568
|
+
*/
|
|
569
|
+
function SettingsDialog({ t, settings, busy, onClose, onSubmit }) {
|
|
570
|
+
const catalog = settings?.catalog ?? null;
|
|
571
|
+
const current = settings?.model ?? null;
|
|
572
|
+
const [chosen, setChosen] = (0, react.useState)(current === null ? "" : modelKey(current));
|
|
573
|
+
const options = catalog?.options ?? [];
|
|
574
|
+
const selectedOption = options.find((option) => option.key === chosen) ?? null;
|
|
575
|
+
const submit = () => {
|
|
576
|
+
onSubmit(selectedOption === null ? null : {
|
|
577
|
+
provider: selectedOption.provider,
|
|
578
|
+
model: selectedOption.model
|
|
579
|
+
});
|
|
580
|
+
};
|
|
581
|
+
const fallbackText = catalog !== null && catalog.fallback !== null ? `${catalog.fallback.provider} / ${catalog.fallback.model}` : null;
|
|
582
|
+
return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
|
|
583
|
+
className: "dap-mask",
|
|
584
|
+
role: "presentation",
|
|
585
|
+
onClick: (e) => e.target === e.currentTarget && onClose(),
|
|
586
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
587
|
+
className: "dap-dialog",
|
|
588
|
+
role: "dialog",
|
|
589
|
+
"aria-modal": "true",
|
|
590
|
+
"aria-label": t("dialog.settings"),
|
|
591
|
+
children: [
|
|
592
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
|
|
593
|
+
className: "dap-dialog__title",
|
|
594
|
+
children: t("dialog.settings")
|
|
595
|
+
}),
|
|
596
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
597
|
+
className: "dap-dialog__sub",
|
|
598
|
+
children: t("dialog.settingsSub")
|
|
599
|
+
}),
|
|
600
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
601
|
+
className: "dap-dialog__row",
|
|
602
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
603
|
+
className: "dap-field__label",
|
|
604
|
+
children: t("field.model")
|
|
605
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
|
|
606
|
+
className: "dap-select",
|
|
607
|
+
value: chosen,
|
|
608
|
+
onChange: (e) => setChosen(e.target.value),
|
|
609
|
+
"aria-label": t("field.model"),
|
|
610
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
|
|
611
|
+
value: "",
|
|
612
|
+
children: fallbackText === null ? t("model.followDefault") : t("model.followDefaultNamed", { model: fallbackText })
|
|
613
|
+
}), options.map((option) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
|
|
614
|
+
value: option.key,
|
|
615
|
+
children: [
|
|
616
|
+
option.providerName,
|
|
617
|
+
" · ",
|
|
618
|
+
option.name
|
|
619
|
+
]
|
|
620
|
+
}, option.key))]
|
|
621
|
+
})]
|
|
622
|
+
}),
|
|
623
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
624
|
+
className: "dap-hint",
|
|
625
|
+
children: catalog === null || catalog.source === "unavailable" ? t("settings.unavailable") : options.length === 0 ? t("settings.noModels") : t("field.modelHint")
|
|
626
|
+
}),
|
|
627
|
+
selectedOption?.description != null ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
628
|
+
className: "dap-hint",
|
|
629
|
+
children: selectedOption.description
|
|
630
|
+
}) : null,
|
|
631
|
+
catalog !== null && catalog.failures.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
|
|
632
|
+
className: "dap-hint dap-hint--warn",
|
|
633
|
+
children: t("settings.providerFailed", { list: catalog.failures.map((f) => f.providerName).join("、") })
|
|
634
|
+
}) : null,
|
|
635
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
636
|
+
className: "dap-dialog__row",
|
|
637
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
638
|
+
className: "dap-field__label",
|
|
639
|
+
children: t("field.sessionMode")
|
|
640
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
641
|
+
className: "dap-hint",
|
|
642
|
+
children: settings?.subagentSessions === true ? t("settings.sessionSubagent") : t("settings.sessionPlain")
|
|
643
|
+
})]
|
|
644
|
+
}),
|
|
645
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
646
|
+
className: "dap-dialog__foot",
|
|
647
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
|
|
648
|
+
className: "dap-hint",
|
|
649
|
+
children: t("settings.scopeHint")
|
|
650
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
651
|
+
style: {
|
|
652
|
+
display: "flex",
|
|
653
|
+
gap: 6
|
|
654
|
+
},
|
|
655
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
656
|
+
className: "dap-btn dap-btn--sm",
|
|
657
|
+
onClick: onClose,
|
|
658
|
+
disabled: busy,
|
|
659
|
+
children: t("action.cancel")
|
|
660
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
661
|
+
className: "dap-btn dap-btn--sm dap-btn--primary",
|
|
662
|
+
onClick: submit,
|
|
663
|
+
disabled: busy,
|
|
664
|
+
children: t("action.save")
|
|
665
|
+
})]
|
|
666
|
+
})]
|
|
667
|
+
})
|
|
668
|
+
]
|
|
669
|
+
})
|
|
670
|
+
});
|
|
671
|
+
}
|
|
534
672
|
|
|
535
673
|
// src/client/page.tsx
|
|
536
674
|
/**
|
|
@@ -557,6 +695,7 @@ function StudioPage({ t }) {
|
|
|
557
695
|
const [diagramId, setDiagramId] = (0, react.useState)(null);
|
|
558
696
|
const [tab, setTab] = (0, react.useState)("info");
|
|
559
697
|
const [dialog, setDialog] = (0, react.useState)(null);
|
|
698
|
+
const [settings, setSettings] = (0, react.useState)(null);
|
|
560
699
|
const [busy, setBusy] = (0, react.useState)(null);
|
|
561
700
|
const [notice, setNotice] = (0, react.useState)(null);
|
|
562
701
|
const [question, setQuestion] = (0, react.useState)("");
|
|
@@ -590,6 +729,18 @@ function StudioPage({ t }) {
|
|
|
590
729
|
(0, react.useEffect)(() => {
|
|
591
730
|
load();
|
|
592
731
|
}, [load]);
|
|
732
|
+
(0, react.useEffect)(() => {
|
|
733
|
+
let alive = true;
|
|
734
|
+
(async () => {
|
|
735
|
+
try {
|
|
736
|
+
const value = await api(ROUTES.settings);
|
|
737
|
+
if (alive) setSettings(value);
|
|
738
|
+
} catch {}
|
|
739
|
+
})();
|
|
740
|
+
return () => {
|
|
741
|
+
alive = false;
|
|
742
|
+
};
|
|
743
|
+
}, []);
|
|
593
744
|
const running = state.projects.some((project) => isRunning(project));
|
|
594
745
|
(0, react.useEffect)(() => {
|
|
595
746
|
if (!running) return void 0;
|
|
@@ -634,6 +785,19 @@ function StudioPage({ t }) {
|
|
|
634
785
|
setBusy(null);
|
|
635
786
|
}
|
|
636
787
|
};
|
|
788
|
+
const saveSettings = async (model) => {
|
|
789
|
+
setBusy("settings");
|
|
790
|
+
setNotice(null);
|
|
791
|
+
try {
|
|
792
|
+
const value = await send(ROUTES.settings, "PUT", { model });
|
|
793
|
+
if (mounted.current) setSettings(value);
|
|
794
|
+
setDialog(null);
|
|
795
|
+
} catch (err) {
|
|
796
|
+
fail(err);
|
|
797
|
+
} finally {
|
|
798
|
+
setBusy(null);
|
|
799
|
+
}
|
|
800
|
+
};
|
|
637
801
|
const updateAll = async () => {
|
|
638
802
|
for (const item of state.projects) {
|
|
639
803
|
if (isRunning(item)) continue;
|
|
@@ -783,14 +947,20 @@ function StudioPage({ t }) {
|
|
|
783
947
|
className: "dap-head__sub",
|
|
784
948
|
children: project.repoPath
|
|
785
949
|
})
|
|
786
|
-
] }), /* @__PURE__ */ (0, react_jsx_runtime.
|
|
950
|
+
] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
787
951
|
className: "dap-head__actions",
|
|
788
|
-
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
952
|
+
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
953
|
+
className: "dap-iconbtn",
|
|
954
|
+
onClick: () => setDialog("settings"),
|
|
955
|
+
title: t("action.settings"),
|
|
956
|
+
"aria-label": t("action.settings"),
|
|
957
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GearIcon, {})
|
|
958
|
+
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
789
959
|
className: "dap-btn dap-btn--sm dap-btn--primary",
|
|
790
960
|
onClick: () => void runUpdate(project),
|
|
791
961
|
disabled: busy !== null || isRunning(project),
|
|
792
962
|
children: t("action.update")
|
|
793
|
-
})
|
|
963
|
+
})]
|
|
794
964
|
})]
|
|
795
965
|
}),
|
|
796
966
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -818,6 +988,13 @@ function StudioPage({ t }) {
|
|
|
818
988
|
onNewDiagram: () => setDialog("diagram")
|
|
819
989
|
})]
|
|
820
990
|
}),
|
|
991
|
+
dialog === "settings" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsDialog, {
|
|
992
|
+
t,
|
|
993
|
+
settings,
|
|
994
|
+
busy: busy !== null,
|
|
995
|
+
onClose: () => setDialog(null),
|
|
996
|
+
onSubmit: (model) => void saveSettings(model)
|
|
997
|
+
}) : null,
|
|
821
998
|
dialog === "diagram" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NewDiagramDialog, {
|
|
822
999
|
t,
|
|
823
1000
|
project,
|
|
@@ -841,16 +1018,26 @@ function StudioPage({ t }) {
|
|
|
841
1018
|
children: t("page.subtitle")
|
|
842
1019
|
})] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
843
1020
|
className: "dap-head__actions",
|
|
844
|
-
children: [
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
1021
|
+
children: [
|
|
1022
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1023
|
+
className: "dap-iconbtn",
|
|
1024
|
+
onClick: () => setDialog("settings"),
|
|
1025
|
+
title: t("action.settings"),
|
|
1026
|
+
"aria-label": t("action.settings"),
|
|
1027
|
+
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GearIcon, {})
|
|
1028
|
+
}),
|
|
1029
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
|
|
1030
|
+
className: "dap-btn dap-btn--sm",
|
|
1031
|
+
onClick: () => void updateAll(),
|
|
1032
|
+
disabled: busy !== null || state.projects.length === 0,
|
|
1033
|
+
children: t("action.updateAll")
|
|
1034
|
+
}),
|
|
1035
|
+
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
|
|
1036
|
+
className: "dap-btn dap-btn--sm dap-btn--primary",
|
|
1037
|
+
onClick: () => setDialog("project"),
|
|
1038
|
+
children: ["+ ", t("action.add")]
|
|
1039
|
+
})
|
|
1040
|
+
]
|
|
854
1041
|
})]
|
|
855
1042
|
}),
|
|
856
1043
|
/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
|
|
@@ -938,6 +1125,13 @@ function StudioPage({ t }) {
|
|
|
938
1125
|
})] })
|
|
939
1126
|
]
|
|
940
1127
|
}),
|
|
1128
|
+
dialog === "settings" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsDialog, {
|
|
1129
|
+
t,
|
|
1130
|
+
settings,
|
|
1131
|
+
busy: busy !== null,
|
|
1132
|
+
onClose: () => setDialog(null),
|
|
1133
|
+
onSubmit: (model) => void saveSettings(model)
|
|
1134
|
+
}) : null,
|
|
941
1135
|
dialog === "project" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(NewProjectDialog, {
|
|
942
1136
|
t,
|
|
943
1137
|
busy: busy !== null,
|
|
@@ -1638,6 +1832,20 @@ const zh = {
|
|
|
1638
1832
|
"action.delete": "删除",
|
|
1639
1833
|
"action.openSession": "查看会话",
|
|
1640
1834
|
"action.cancel": "取消",
|
|
1835
|
+
"action.settings": "设置",
|
|
1836
|
+
"dialog.settings": "设置",
|
|
1837
|
+
"dialog.settingsSub": "只影响这个插件的分析会话,不动 DSH 里你自己的默认模型。",
|
|
1838
|
+
"field.model": "分析模型",
|
|
1839
|
+
"field.modelHint": "选项来自你在 DSH 里已经配好、当前能路由的模型。",
|
|
1840
|
+
"field.sessionMode": "会话形态",
|
|
1841
|
+
"model.followDefault": "跟随宿主默认",
|
|
1842
|
+
"model.followDefaultNamed": "跟随宿主默认({model})",
|
|
1843
|
+
"settings.noModels": "宿主的模型目录是空的:去 DSH 设置里配一个模型,这里才有得选。",
|
|
1844
|
+
"settings.unavailable": "这个宿主版本没有提供模型目录,只能跟随宿主默认。",
|
|
1845
|
+
"settings.providerFailed": "{list} 的模型列表取不到(网络或凭据),暂时不能选。",
|
|
1846
|
+
"settings.sessionSubagent": "子代理会话(不占用左侧会话列表)",
|
|
1847
|
+
"settings.sessionPlain": "普通会话(宿主不支持子代理会话)",
|
|
1848
|
+
"settings.scopeHint": "保存后对下一次运行生效",
|
|
1641
1849
|
"action.submit": "创建并分析",
|
|
1642
1850
|
"action.close": "关闭",
|
|
1643
1851
|
"action.back": "返回图册",
|
|
@@ -1799,6 +2007,20 @@ const en = {
|
|
|
1799
2007
|
"action.delete": "Delete",
|
|
1800
2008
|
"action.openSession": "Open session",
|
|
1801
2009
|
"action.cancel": "Cancel",
|
|
2010
|
+
"action.settings": "Settings",
|
|
2011
|
+
"dialog.settings": "Settings",
|
|
2012
|
+
"dialog.settingsSub": "Only affects this plugin's analysis sessions; your own default model in DSH stays untouched.",
|
|
2013
|
+
"field.model": "Analysis model",
|
|
2014
|
+
"field.modelHint": "Options are the models already configured in DSH and currently routable.",
|
|
2015
|
+
"field.sessionMode": "Session",
|
|
2016
|
+
"model.followDefault": "Follow the host default",
|
|
2017
|
+
"model.followDefaultNamed": "Follow the host default ({model})",
|
|
2018
|
+
"settings.noModels": "The host catalog is empty. Configure a model in DSH settings to pick one here.",
|
|
2019
|
+
"settings.unavailable": "This host version exposes no model catalog; the host default is used.",
|
|
2020
|
+
"settings.providerFailed": "Could not list models for {list} (network or credentials).",
|
|
2021
|
+
"settings.sessionSubagent": "Subagent session (kept out of the sidebar list)",
|
|
2022
|
+
"settings.sessionPlain": "Plain session (this host lacks subagent sessions)",
|
|
2023
|
+
"settings.scopeHint": "Applies to the next run",
|
|
1802
2024
|
"action.submit": "Create and analyse",
|
|
1803
2025
|
"action.close": "Close",
|
|
1804
2026
|
"action.back": "Back to atlas",
|
|
@@ -2190,6 +2412,25 @@ const PAGE_CSS = `
|
|
|
2190
2412
|
|
|
2191
2413
|
|
|
2192
2414
|
.dap-dialog--wide { width: 680px; }
|
|
2415
|
+
|
|
2416
|
+
/* 头部图标按钮(设置齿轮):与 dap-btn--sm 同高,窄一点 */
|
|
2417
|
+
.dap-iconbtn {
|
|
2418
|
+
display: inline-flex; align-items: center; justify-content: center;
|
|
2419
|
+
width: 26px; height: 26px; border-radius: var(--dsw-radius-md);
|
|
2420
|
+
border: 1px solid var(--dsw-alias-border-l1); background: var(--dsw-alias-bg-layer-2);
|
|
2421
|
+
color: var(--dsw-alias-label-secondary); cursor: pointer;
|
|
2422
|
+
}
|
|
2423
|
+
.dap-iconbtn:hover { color: var(--dsw-alias-label-primary); border-color: var(--dsw-alias-border-l2); }
|
|
2424
|
+
|
|
2425
|
+
/* 设置弹窗的模型下拉:原生 select 最省事,长列表也能滚动 */
|
|
2426
|
+
.dap-select {
|
|
2427
|
+
min-width: 240px; max-width: 380px; height: 28px; padding: 0 8px;
|
|
2428
|
+
border: 1px solid var(--dsw-alias-border-l2); border-radius: var(--dsw-radius-md);
|
|
2429
|
+
background: var(--dsw-alias-bg-layer-2); color: var(--dsw-alias-label-primary);
|
|
2430
|
+
font: inherit; font-size: 12px; outline: none; cursor: pointer;
|
|
2431
|
+
}
|
|
2432
|
+
.dap-select:focus { border-color: var(--dsw-alias-border-l3); }
|
|
2433
|
+
.dap-hint--warn { color: var(--dsw-alias-state-warning-primary, var(--dsw-alias-label-tertiary)); }
|
|
2193
2434
|
.dap-typebar { display: flex; flex-wrap: wrap; gap: 5px; margin: 6px 0 8px; }
|
|
2194
2435
|
.dap-type-tag {
|
|
2195
2436
|
display: inline-flex; align-items: center; gap: 5px; height: 27px; padding: 0 9px;
|