@matamt-dbg/dsh-studio 0.2.2 → 0.2.7

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 (6) hide show
  1. package/README.md +9 -4
  2. package/client.js +281 -174
  3. package/index.js +193 -60
  4. package/package.json +1 -1
  5. package/policy.js +135 -12
  6. package/roles.js +25 -3
package/client.js CHANGED
@@ -93,6 +93,8 @@ function parsePreviewRequest(value) {
93
93
  if (row.providerConfigs !== void 0 && (!record2(row.providerConfigs) || Object.values(row.providerConfigs).some((v) => !record2(v)))) throw new Error("Invalid provider configs");
94
94
  if (row.configOverrides !== void 0) validateConfigOverrides(row.configOverrides);
95
95
  if (row.execution !== void 0) validateExecutionDefaults(row.execution);
96
+ const filter = row.subagentToolFilter;
97
+ if (filter !== void 0 && (!record2(filter) || !strings(filter.deny) || filter.deny.some((name) => !name))) throw new Error("Invalid subagent tool filter");
96
98
  return {
97
99
  ...row.configOverrides !== void 0 ? { configOverrides: row.configOverrides } : {},
98
100
  ...row.execution !== void 0 ? { execution: row.execution } : {},
@@ -104,7 +106,8 @@ function parsePreviewRequest(value) {
104
106
  ...row.persona !== void 0 ? { persona: row.persona } : {},
105
107
  ...row.sections !== void 0 ? { sections: row.sections } : {},
106
108
  ...row.toolOverrides !== void 0 ? { toolOverrides: row.toolOverrides } : {},
107
- ...row.providerConfigs !== void 0 ? { providerConfigs: row.providerConfigs } : {}
109
+ ...row.providerConfigs !== void 0 ? { providerConfigs: row.providerConfigs } : {},
110
+ ...filter !== void 0 && filter.deny.length ? { subagentToolFilter: { deny: [...new Set(filter.deny)] } } : {}
108
111
  };
109
112
  }
110
113
 
@@ -733,15 +736,76 @@ function DetailDialog({ open, title, subtitle, onClose, closeLabel, footer, wide
733
736
  }
734
737
 
735
738
  // src/role-editor.tsx
739
+ var import_react3 = __toESM(require("react"), 1);
740
+
741
+ // src/item-picker.tsx
736
742
  var import_react2 = __toESM(require("react"), 1);
737
743
  var import_jsx_runtime2 = require("react/jsx-runtime");
738
- function RoleEditor({ locale, roles, onChange, loadModels, defaultPersona = "" }) {
744
+ function ItemPicker({ label, items, selected, onChange, labels, renderDetails, isModified, hasDetails }) {
745
+ const [query, setQuery] = import_react2.default.useState("");
746
+ const [filter, setFilter] = import_react2.default.useState("all");
747
+ const [detail, setDetail] = import_react2.default.useState();
748
+ const chosen = new Set(selected);
749
+ const isOn = (item) => item.lockedReason !== void 0 || chosen.has(item.name);
750
+ const modified = (name) => chosen.has(name) && (isModified?.(name) ?? false);
751
+ const text = query.trim().toLowerCase();
752
+ const visible = items.filter((item) => (filter === "all" || (filter === "selected" ? isOn(item) : modified(item.name))) && (!text || `${item.name}
753
+ ${item.title ?? ""}
754
+ ${item.description}
755
+ ${item.searchText ?? ""}`.toLowerCase().includes(text)));
756
+ const counts = { all: items.length, selected: items.filter(isOn).length, modified: items.filter((item) => modified(item.name)).length };
757
+ const toggle = (name) => onChange(chosen.has(name) ? selected.filter((value) => value !== name) : [...selected, name]);
758
+ const open = items.find((item) => item.name === detail && chosen.has(item.name));
759
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "studio-picker", children: [
760
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "studio-picker-bar", children: [
761
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { type: "search", "aria-label": labels.search, placeholder: labels.searchHint, value: query, onChange: (event) => setQuery(event.target.value) }),
762
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "studio-picker-filters", role: "radiogroup", "aria-label": labels.filter, children: ["all", "selected", "modified"].map((value) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { type: "button", role: "radio", "aria-checked": filter === value, className: "studio-picker-filter", onClick: () => setFilter(value), children: [
763
+ labels[value],
764
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "studio-count", children: counts[value] })
765
+ ] }, value)) })
766
+ ] }),
767
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("ul", { className: "studio-picker-list", "aria-label": label, children: [
768
+ visible.map((item) => {
769
+ const locked = item.lockedReason !== void 0;
770
+ const on = locked || chosen.has(item.name);
771
+ const blocked = locked || !on && item.disabledReason !== void 0;
772
+ const details = on && renderDetails !== void 0 && (hasDetails?.(item.name) ?? true);
773
+ return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { className: "studio-picker-row", "data-selected": on, children: [
774
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("button", { type: "button", role: "switch", "aria-checked": on, disabled: blocked, className: "studio-picker-toggle", "aria-label": `${item.title ?? item.name}`, onClick: () => toggle(item.name), children: [
775
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "studio-picker-check", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 16 16", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M3.5 8.5l3 3 6-7", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
776
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "studio-picker-text", children: [
777
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "studio-picker-title", children: [
778
+ item.title ?? item.name,
779
+ item.subtitle && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "studio-picker-subtitle studio-mono", children: item.subtitle })
780
+ ] }),
781
+ (locked ? item.lockedReason : item.disabledReason && !on ? item.disabledReason : item.description) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "studio-picker-description", children: locked ? item.lockedReason : item.disabledReason && !on ? item.disabledReason : item.description })
782
+ ] })
783
+ ] }),
784
+ modified(item.name) && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "studio-badge", "data-tone": "info", "data-studio-modified": "true", children: labels.modifiedTag }),
785
+ details && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { small: true, "aria-label": `${labels.settings}: ${item.name}`, "aria-haspopup": "dialog", onClick: () => setDetail(item.name), children: labels.settings })
786
+ ] }, item.name);
787
+ }),
788
+ !visible.length && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("li", { className: "studio-picker-empty", role: "status", children: [
789
+ text ? labels.noResults : labels.empty,
790
+ (text || filter !== "all") && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { small: true, onClick: () => {
791
+ setQuery("");
792
+ setFilter("all");
793
+ }, children: labels.clear })
794
+ ] })
795
+ ] }),
796
+ renderDetails && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(DetailDialog, { open: open !== void 0, title: open?.title ?? open?.name, subtitle: open?.subtitle, closeLabel: labels.done, onClose: () => setDetail(void 0), children: open && renderDetails(open.name) })
797
+ ] });
798
+ }
799
+
800
+ // src/role-editor.tsx
801
+ var import_jsx_runtime3 = require("react/jsx-runtime");
802
+ function RoleEditor({ locale, roles, onChange, loadModels, defaultPersona = "", tools, hiddenTools = [], onHiddenToolsChange, delegates = true }) {
739
803
  const t = (ko2, en2, zh2) => locale.startsWith("ko") ? ko2 : locale.startsWith("zh") ? zh2 : en2;
740
- const [selected, setSelected] = import_react2.default.useState();
741
- const [catalog, setCatalog] = import_react2.default.useState();
742
- const [error, setError] = import_react2.default.useState("");
743
- const [loading, setLoading] = import_react2.default.useState(false);
744
- const refresh = import_react2.default.useCallback(async () => {
804
+ const [selected, setSelected] = import_react3.default.useState();
805
+ const [catalog, setCatalog] = import_react3.default.useState();
806
+ const [error, setError] = import_react3.default.useState("");
807
+ const [loading, setLoading] = import_react3.default.useState(false);
808
+ const refresh = import_react3.default.useCallback(async () => {
745
809
  if (!loadModels) return;
746
810
  setLoading(true);
747
811
  setError("");
@@ -753,120 +817,179 @@ function RoleEditor({ locale, roles, onChange, loadModels, defaultPersona = "" }
753
817
  setLoading(false);
754
818
  }
755
819
  }, [loadModels]);
756
- import_react2.default.useEffect(() => {
820
+ import_react3.default.useEffect(() => {
757
821
  void refresh();
758
822
  }, [refresh]);
759
823
  const models = (catalog?.groups ?? []).flatMap((group) => group.models.map((model2) => ({ ...model2, value: `${group.id}/${model2.id}`, label: `${group.name} \xB7 ${model2.name}` })));
760
824
  const role = selected === void 0 ? void 0 : roles[selected];
761
825
  const model = models.find((model2) => model2.value === role?.model);
762
- const update2 = (patch) => onChange(roles.map((role2, index) => index === selected ? { ...role2, ...patch } : role2));
763
- const field2 = (label, content) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("label", { className: "studio-field", children: [
764
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: label }),
826
+ const update2 = (patch) => onChange(roles.map((role2, index) => {
827
+ if (index !== selected) return role2;
828
+ const next = { ...role2, ...patch };
829
+ if (next.toolFilter === void 0) delete next.toolFilter;
830
+ return next;
831
+ }));
832
+ const field2 = (label, content) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "studio-field", children: [
833
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: label }),
765
834
  content
766
835
  ] });
767
836
  const close = () => setSelected(void 0);
768
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
769
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SectionHead, { title: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("h3", { className: "studio-panel-title", children: [
837
+ const defaultCount = hiddenTools.filter((name) => tools?.some((tool) => tool.name === name)).length;
838
+ const filterTitle = t("\uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8 Tool Filter", "Subagent Tool Filter", "\u5B50\u4EE3\u7406 Tool Filter");
839
+ const roleFilterLabel = t("\uC774 \uC5ED\uD560\uC758 Tool Filter", "Tool Filter for this role", "\u6B64\u89D2\u8272\u7684 Tool Filter");
840
+ const filterSummary = (item) => {
841
+ const own2 = item.toolFilter?.deny.filter((name) => tools?.some((tool) => tool.name === name) && !(item.toolFilter?.mode === "extend" && hiddenTools.includes(name))).length ?? 0;
842
+ return !item.toolFilter ? t("\uAE30\uBCF8\uAC12", "default", "\u9ED8\u8BA4") : item.toolFilter.mode === "extend" ? t(`\uAE30\uBCF8\uAC12 + ${own2}`, `default + ${own2}`, `\u9ED8\u8BA4 + ${own2}`) : t(`\uB530\uB85C ${own2}`, `own ${own2}`, `\u5355\u72EC ${own2}`);
843
+ };
844
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
845
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SectionHead, { title: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("h3", { className: "studio-panel-title", children: [
770
846
  t("\uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8", "Subagents", "\u5B50\u4EE3\u7406"),
771
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "studio-count", children: roles.length })
772
- ] }), description: t("\uBC14\uAFBC \uB0B4\uC6A9\uC740 \uD504\uB9AC\uC14B\uC744 \uC800\uC7A5\uD558\uACE0 DSH\uC5D0 \uB2E4\uC2DC \uBC18\uC601\uD574\uC57C \uC801\uC6A9\uB429\uB2C8\uB2E4.", "Save the preset and reapply it to DSH after changes.", "\u4FEE\u6539\u540E\u9700\u4FDD\u5B58\u9884\u8BBE\u5E76\u91CD\u65B0\u5E94\u7528\u5230 DSH\u3002"), actions: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
773
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { small: true, disabled: loading || !loadModels, onClick: () => void refresh(), children: loading ? t("\uBAA8\uB378 \uBD88\uB7EC\uC624\uB294 \uC911\u2026", "Loading models\u2026", "\u6B63\u5728\u52A0\u8F7D\u6A21\u578B\u2026") : t("\uBAA8\uB378 \uBAA9\uB85D \uC0C8\uB85C\uACE0\uCE68", "Refresh models", "\u5237\u65B0\u6A21\u578B\u5217\u8868") }),
774
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { small: true, onClick: () => {
847
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { className: "studio-count", children: roles.length })
848
+ ] }), description: t("\uBC14\uAFBC \uB0B4\uC6A9\uC740 \uD504\uB9AC\uC14B\uC744 \uC800\uC7A5\uD558\uACE0 DSH\uC5D0 \uB2E4\uC2DC \uBC18\uC601\uD574\uC57C \uC801\uC6A9\uB429\uB2C8\uB2E4.", "Save the preset and reapply it to DSH after changes.", "\u4FEE\u6539\u540E\u9700\u4FDD\u5B58\u9884\u8BBE\u5E76\u91CD\u65B0\u5E94\u7528\u5230 DSH\u3002"), actions: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
849
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { small: true, disabled: loading || !loadModels, onClick: () => void refresh(), children: loading ? t("\uBAA8\uB378 \uBD88\uB7EC\uC624\uB294 \uC911\u2026", "Loading models\u2026", "\u6B63\u5728\u52A0\u8F7D\u6A21\u578B\u2026") : t("\uBAA8\uB378 \uBAA9\uB85D \uC0C8\uB85C\uACE0\uCE68", "Refresh models", "\u5237\u65B0\u6A21\u578B\u5217\u8868") }),
850
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { small: true, onClick: () => {
775
851
  setSelected(roles.length);
776
852
  onChange([...roles, { name: "", role: "", model: "inherit", reasoning: "inherit", spawn: "fresh", persona: "" }]);
777
853
  }, children: t("\uC5ED\uD560 \uCD94\uAC00", "Add role", "\u6DFB\u52A0\u89D2\u8272") })
778
854
  ] }) }),
779
- error && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Note, { children: error }),
780
- catalog?.failures.map((failure) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Note, { children: [
855
+ error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { children: error }),
856
+ catalog?.failures.map((failure) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Note, { children: [
781
857
  failure.name,
782
858
  ": ",
783
859
  failure.message
784
860
  ] }, failure.name)),
785
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Note, { children: t(
861
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { children: t(
786
862
  "DSH\uC758 \uAE30\uBCF8 \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8 \uB3C4\uAD6C(subagent, subagent_fork, list_subagent_models)\uB97C subagent_role \uD558\uB098\uB85C \uD1B5\uD569\uD574 \uC81C\uACF5\uD569\uB2C8\uB2E4. \uAE30\uBCF8 \uB3C4\uAD6C\uB294 \uC790\uB3D9\uC73C\uB85C \uBE60\uC9C0\uACE0, subagent_role\uC758 \uC124\uBA85\uACFC \uC778\uC790\uB294 \uD504\uB86C\uD504\uD2B8\xB7\uB3C4\uAD6C \uD0ED\uC758 \uB3C4\uAD6C \uBAA9\uB85D\uC5D0\uC11C \uD655\uC778\uD558\uACE0 \uC218\uC815\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
787
- "Studio provides the DSH default subagent tools (subagent, subagent_fork, list_subagent_models) as a single subagent_role tool. The default tools are removed automatically; review or edit subagent_role in the tool list on the Prompts & tools tab.",
863
+ "Studio replaces the DSH default subagent tools (subagent, subagent_fork, list_subagent_models) with a single subagent_role tool. The default tools are removed automatically; review or edit subagent_role in the tool list on the Prompts & tools tab.",
788
864
  "\u5C06 DSH \u9ED8\u8BA4\u5B50\u4EE3\u7406\u5DE5\u5177\uFF08subagent\u3001subagent_fork\u3001list_subagent_models\uFF09\u5408\u5E76\u4E3A\u4E00\u4E2A subagent_role \u5DE5\u5177\u63D0\u4F9B\u3002\u9ED8\u8BA4\u5DE5\u5177\u4F1A\u88AB\u81EA\u52A8\u79FB\u9664\uFF1B\u53EF\u5728\u201C\u63D0\u793A\u8BCD\u4E0E\u5DE5\u5177\u201D\u9875\u7684\u5DE5\u5177\u5217\u8868\u4E2D\u67E5\u770B\u6216\u7F16\u8F91 subagent_role\u3002"
789
865
  ) }),
790
- !roles.length && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "studio-muted", role: "status", children: t("\uC815\uC758\uB41C \uC5ED\uD560\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC774 \uC0C1\uD0DC\uC5D0\uC11C\uB294 subagent_role\uC774 \uBD80\uBAA8\uC640 \uAC19\uC740 \uBAA8\uB378\xB7\uCD94\uB860\xB7\uC9C0\uCE68\uC73C\uB85C \uC0C8 \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4.", "No roles defined. subagent_role then starts a new subagent with the same model, reasoning and instructions as the parent.", "\u5C1A\u672A\u5B9A\u4E49\u89D2\u8272\u3002\u6B64\u65F6 subagent_role \u4F1A\u4EE5\u4E0E\u7236\u4EE3\u7406\u76F8\u540C\u7684\u6A21\u578B\u3001\u63A8\u7406\u548C\u6307\u4EE4\u542F\u52A8\u65B0\u7684\u5B50\u4EE3\u7406\u3002") }),
791
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "studio-tool-cards studio-card-pair", children: roles.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("article", { className: "studio-role-card", children: [
792
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "studio-card-head", children: [
793
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h3", { children: item.name || t("\uC774\uB984 \uC5C6\uC74C", "Untitled", "\u672A\u547D\u540D") }),
794
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Badge, { tone: "outline", children: item.spawn === "fork" ? t("\uBD80\uBAA8 \uB300\uD654 \uC774\uC5B4\uBC1B\uAE30", "Continue parent", "\u7EE7\u627F\u7236\u5BF9\u8BDD") : t("\uC0C8 \uB300\uD654", "New conversation", "\u65B0\u5BF9\u8BDD") })
866
+ !roles.length && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "studio-muted", role: "status", children: t("\uC815\uC758\uB41C \uC5ED\uD560\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uC774 \uC0C1\uD0DC\uC5D0\uC11C\uB294 subagent_role\uC774 \uBD80\uBAA8\uC640 \uAC19\uC740 \uBAA8\uB378\xB7\uCD94\uB860\xB7\uC9C0\uCE68\uC73C\uB85C \uC0C8 \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8\uB97C \uC2DC\uC791\uD569\uB2C8\uB2E4.", "No roles defined. subagent_role then starts a new subagent with the same model, reasoning and instructions as the parent.", "\u5C1A\u672A\u5B9A\u4E49\u89D2\u8272\u3002\u6B64\u65F6 subagent_role \u4F1A\u4EE5\u4E0E\u7236\u4EE3\u7406\u76F8\u540C\u7684\u6A21\u578B\u3001\u63A8\u7406\u548C\u6307\u4EE4\u542F\u52A8\u65B0\u7684\u5B50\u4EE3\u7406\u3002") }),
867
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "studio-tool-cards studio-card-pair", children: roles.map((item, index) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("article", { className: "studio-role-card", children: [
868
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "studio-card-head", children: [
869
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("h3", { children: item.name || t("\uC774\uB984 \uC5C6\uC74C", "Untitled", "\u672A\u547D\u540D") }),
870
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Badge, { tone: "outline", children: item.spawn === "fork" ? t("\uBD80\uBAA8 \uB300\uD654 \uC774\uC5B4\uBC1B\uAE30", "Continue parent", "\u7EE7\u627F\u7236\u5BF9\u8BDD") : t("\uC0C8 \uB300\uD654", "New conversation", "\u65B0\u5BF9\u8BDD") })
795
871
  ] }),
796
- item.role && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "studio-card-text studio-mono", children: item.role }),
797
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("p", { className: "studio-card-meta", children: [
872
+ item.role && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "studio-card-text studio-mono", children: item.role }),
873
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("p", { className: "studio-card-meta", children: [
798
874
  item.model === "inherit" ? t("\uBD80\uBAA8 \uBAA8\uB378 \uC0AC\uC6A9", "Inherit parent model", "\u7EE7\u627F\u7236\u7EA7\u6A21\u578B") : models.find((model2) => model2.value === item.model)?.label ?? item.model,
799
875
  " \xB7 ",
800
876
  t("\uCD94\uB860", "Reasoning", "\u63A8\u7406"),
801
877
  " ",
802
- item.reasoning === "inherit" ? t("\uAE30\uBCF8", "inherit", "\u9ED8\u8BA4") : item.reasoning
878
+ item.reasoning === "inherit" ? t("\uAE30\uBCF8\uAC12", "default", "\u9ED8\u8BA4") : item.reasoning,
879
+ tools && delegates && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
880
+ " \xB7 Tool Filter: ",
881
+ filterSummary(item)
882
+ ] })
803
883
  ] }),
804
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "studio-card-footer", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { small: true, "aria-haspopup": "dialog", onClick: () => setSelected(index), children: t("\uD3B8\uC9D1", "Edit", "\u7F16\u8F91") }) })
884
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "studio-card-footer", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { small: true, "aria-haspopup": "dialog", onClick: () => setSelected(index), children: t("\uD3B8\uC9D1", "Edit", "\u7F16\u8F91") }) })
805
885
  ] }, index)) }),
806
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
886
+ tools && onHiddenToolsChange && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("section", { className: "studio-form-section", children: [
887
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(SectionHead, { title: filterTitle, description: t("Tool Filter\uC5D0 \uB4F1\uB85D\uD55C \uB3C4\uAD6C\uB294 \uC774 \uD504\uB9AC\uC14B\uC758 \uBAA8\uB4E0 \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8\uC5D0\uC11C \uBE60\uC9D1\uB2C8\uB2E4. \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8\uC758 \uC2DC\uC2A4\uD15C \uD504\uB86C\uD504\uD2B8\uC5D0\uC11C \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8\uC5D0\uAC8C \uD544\uC694 \uC5C6\uB294 \uB3C4\uAD6C\uB97C \uC81C\uAC70\uD574 \uCEE8\uD14D\uC2A4\uD2B8\uB97C \uAC00\uBCCD\uAC8C \uC720\uC9C0\uD574 \uBCF4\uC138\uC694. \uC5ED\uD560 \uD3B8\uC9D1\uC5D0\uC11C \uC5ED\uD560\uB9C8\uB2E4 \uB530\uB85C \uC815\uD560 \uC218\uB3C4 \uC788\uC2B5\uB2C8\uB2E4.", "Tools in the Tool Filter are removed from every subagent of this preset. Remove tools a subagent does not need from its system prompt to keep its context light. Each role can also set its own list in the role editor.", "\u52A0\u5165 Tool Filter \u7684\u5DE5\u5177\u4F1A\u4ECE\u6B64\u9884\u8BBE\u7684\u6240\u6709\u5B50\u4EE3\u7406\u4E2D\u79FB\u9664\u3002\u4ECE\u5B50\u4EE3\u7406\u7684\u7CFB\u7EDF\u63D0\u793A\u4E2D\u79FB\u9664\u5176\u4E0D\u9700\u8981\u7684\u5DE5\u5177\uFF0C\u8BA9\u4E0A\u4E0B\u6587\u4FDD\u6301\u7CBE\u7B80\u3002\u4E5F\u53EF\u4EE5\u5728\u89D2\u8272\u7F16\u8F91\u4E2D\u4E3A\u6BCF\u4E2A\u89D2\u8272\u5355\u72EC\u8BBE\u7F6E\u3002") }),
888
+ !delegates ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { children: t("\uD504\uB86C\uD504\uD2B8\xB7\uB3C4\uAD6C \uD0ED\uC5D0\uC11C subagent_role\uC744 \uC120\uD0DD\uD558\uBA74 \uC4F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Select subagent_role on the Prompts & tools tab to use the Tool Filter.", "\u5728\u201C\u63D0\u793A\u8BCD\u4E0E\u5DE5\u5177\u201D\u9875\u9009\u62E9 subagent_role \u540E\u5373\u53EF\u4F7F\u7528\u3002") }) : /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(ToolFilterPicker, { label: filterTitle, tools, selected: hiddenTools, onChange: onHiddenToolsChange, t })
889
+ ] }),
890
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
807
891
  DetailDialog,
808
892
  {
809
893
  open: role !== void 0,
810
894
  title: role?.name || t("\uC0C8 \uC5ED\uD560", "New role", "\u65B0\u89D2\u8272"),
811
895
  subtitle: t("\uC5ED\uD560 \uD3B8\uC9D1", "Edit role", "\u7F16\u8F91\u89D2\u8272"),
812
896
  onClose: close,
813
- footer: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
814
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { small: true, onClick: () => {
897
+ footer: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
898
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { small: true, onClick: () => {
815
899
  onChange(roles.filter((_, index) => index !== selected));
816
900
  close();
817
901
  }, children: t("\uC5ED\uD560 \uC0AD\uC81C", "Remove role", "\u79FB\u9664\u89D2\u8272") }),
818
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Button, { small: true, primary: true, onClick: close, children: t("\uC644\uB8CC", "Done", "\u5B8C\u6210") })
902
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { small: true, primary: true, onClick: close, children: t("\uC644\uB8CC", "Done", "\u5B8C\u6210") })
819
903
  ] }),
820
- children: role && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
821
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "studio-field-grid", children: [
822
- field2(t("\uC774\uB984", "Name", "\u540D\u79F0"), /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { value: role.name, onChange: (e) => update2({ name: e.target.value }) })),
823
- field2(t("\uC5ED\uD560 ID", "Role", "\u89D2\u8272"), /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { className: "studio-mono", value: role.role, onChange: (e) => update2({ role: e.target.value }) }))
904
+ children: role && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
905
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "studio-field-grid", children: [
906
+ field2(t("\uC774\uB984", "Name", "\u540D\u79F0"), /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { value: role.name, onChange: (e) => update2({ name: e.target.value }) })),
907
+ field2(t("\uC5ED\uD560 ID", "Role ID", "\u89D2\u8272 ID"), /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { className: "studio-mono", value: role.role, onChange: (e) => update2({ role: e.target.value }) }))
824
908
  ] }),
825
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "studio-field-grid", children: [
826
- field2(t("\uBAA8\uB378", "Model", "\u6A21\u578B"), /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { value: role.model, onChange: (e) => update2({ model: e.target.value, reasoning: "inherit" }), children: [
827
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "inherit", children: t("\uBD80\uBAA8 \uBAA8\uB378 \uC0AC\uC6A9", "Inherit parent model", "\u7EE7\u627F\u7236\u7EA7\u6A21\u578B") }),
828
- role.model !== "inherit" && !model && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("option", { value: role.model, disabled: true, children: [
909
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "studio-field-grid", children: [
910
+ field2(t("\uBAA8\uB378", "Model", "\u6A21\u578B"), /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("select", { value: role.model, onChange: (e) => update2({ model: e.target.value, reasoning: "inherit" }), children: [
911
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "inherit", children: t("\uBD80\uBAA8 \uBAA8\uB378 \uC0AC\uC6A9", "Inherit parent model", "\u7EE7\u627F\u7236\u7EA7\u6A21\u578B") }),
912
+ role.model !== "inherit" && !model && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("option", { value: role.model, disabled: true, children: [
829
913
  role.model,
830
914
  " \xB7 ",
831
- t("\uBAA9\uB85D\uC5D0 \uC5C6\uC74C \xB7 \uBC18\uC601\uD560 \uB54C \uD655\uC778", "Not confirmed in catalog \xB7 checked on apply", "\u76EE\u5F55\u4E2D\u672A\u786E\u8BA4 \xB7 \u5E94\u7528\u65F6\u9A8C\u8BC1")
915
+ t("\uBAA9\uB85D\uC5D0 \uC5C6\uC74C \xB7 \uBC18\uC601\uD560 \uB54C \uD655\uC778", "Not in list \xB7 checked on apply", "\u76EE\u5F55\u4E2D\u672A\u786E\u8BA4 \xB7 \u5E94\u7528\u65F6\u9A8C\u8BC1")
832
916
  ] }),
833
- models.map((model2) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: model2.value, children: model2.label }, model2.value))
917
+ models.map((model2) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: model2.value, children: model2.label }, model2.value))
834
918
  ] })),
835
- field2(t("\uCD94\uB860 \uC218\uC900", "Reasoning", "\u63A8\u7406\u7EA7\u522B"), /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { value: role.reasoning, disabled: !model, onChange: (e) => update2({ reasoning: e.target.value }), children: [
836
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "inherit", children: role.model === "inherit" ? t("\uBD80\uBAA8 \uC124\uC815 \uC0AC\uC6A9", "Inherit parent setting", "\u7EE7\u627F\u7236\u7EA7\u8BBE\u7F6E") : t("\uBAA8\uB378 \uAE30\uBCF8\uAC12", "Model default", "\u6A21\u578B\u9ED8\u8BA4\u503C") }),
837
- role.reasoning !== "inherit" && !model?.reasoning?.efforts.some((e) => e.id === role.reasoning) && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("option", { value: role.reasoning, disabled: true, children: [
919
+ field2(t("\uCD94\uB860 \uC218\uC900", "Reasoning", "\u63A8\u7406\u7EA7\u522B"), /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("select", { value: role.reasoning, disabled: !model, onChange: (e) => update2({ reasoning: e.target.value }), children: [
920
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "inherit", children: role.model === "inherit" ? t("\uBD80\uBAA8 \uC124\uC815 \uC0AC\uC6A9", "Inherit parent setting", "\u7EE7\u627F\u7236\u7EA7\u8BBE\u7F6E") : t("\uBAA8\uB378 \uAE30\uBCF8\uAC12", "Model default", "\u6A21\u578B\u9ED8\u8BA4\u503C") }),
921
+ role.reasoning !== "inherit" && !model?.reasoning?.efforts.some((e) => e.id === role.reasoning) && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("option", { value: role.reasoning, disabled: true, children: [
838
922
  role.reasoning,
839
923
  " \xB7 ",
840
- t("\uC9C0\uC6D0 \uC5EC\uBD80 \uD655\uC778 \uD544\uC694", "Check support", "\u9700\u786E\u8BA4\u652F\u6301")
924
+ t("\uC9C0\uC6D0 \uC5EC\uBD80 \uD655\uC778 \uD544\uC694", "Support unconfirmed", "\u9700\u786E\u8BA4\u652F\u6301")
841
925
  ] }),
842
- model?.reasoning?.efforts.map((e) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: e.id, children: e.name }, e.id))
926
+ model?.reasoning?.efforts.map((e) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: e.id, children: e.name }, e.id))
843
927
  ] })),
844
- field2(t("\uC2DC\uC791 \uBC29\uC2DD", "Spawn mode", "\u751F\u6210\u65B9\u5F0F"), /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("select", { value: role.spawn, onChange: (e) => update2({ spawn: e.target.value }), children: [
845
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "fresh", children: t("\uC0C8 \uB300\uD654 (Fresh)", "New conversation (Fresh)", "\u65B0\u5BF9\u8BDD\uFF08Fresh\uFF09") }),
846
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: "fork", children: t("\uBD80\uBAA8 \uB300\uD654 \uC774\uC5B4\uBC1B\uAE30 (Fork)", "Continue parent (Fork)", "\u7EE7\u627F\u7236\u5BF9\u8BDD\uFF08Fork\uFF09") })
928
+ field2(t("\uC2DC\uC791 \uBC29\uC2DD", "Spawn mode", "\u751F\u6210\u65B9\u5F0F"), /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("select", { value: role.spawn, onChange: (e) => update2({ spawn: e.target.value }), children: [
929
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "fresh", children: t("\uC0C8 \uB300\uD654 (Fresh)", "New conversation (Fresh)", "\u65B0\u5BF9\u8BDD\uFF08Fresh\uFF09") }),
930
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "fork", children: t("\uBD80\uBAA8 \uB300\uD654 \uC774\uC5B4\uBC1B\uAE30 (Fork)", "Continue parent (Fork)", "\u7EE7\u627F\u7236\u5BF9\u8BDD\uFF08Fork\uFF09") })
847
931
  ] }))
848
932
  ] }),
849
- field2(t("\uC5ED\uD560 \uC9C0\uCE68 (persona)", "User instructions (persona)", "\u7528\u6237\u6307\u4EE4\uFF08persona\uFF09"), /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("textarea", { rows: 6, value: role.persona, placeholder: defaultPersona, onChange: (e) => update2({ persona: e.target.value }) })),
850
- !role.persona && defaultPersona && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { className: "studio-muted studio-hint", children: t("\uD750\uB9B0 \uAE00\uC528\uB294 \uD504\uB9AC\uC14B\uC758 \uAE30\uBCF8 persona\uC785\uB2C8\uB2E4. \uBE44\uC6CC \uB450\uBA74 \uC774 \uB0B4\uC6A9\uC774 \uADF8\uB300\uB85C \uC4F0\uC785\uB2C8\uB2E4.", "The dimmed text is the preset default persona; it is used while this field is empty.", "\u6D45\u8272\u6587\u5B57\u662F\u9884\u8BBE\u7684\u9ED8\u8BA4 persona\uFF0C\u7559\u7A7A\u65F6\u4F7F\u7528\u8BE5\u5185\u5BB9\u3002") })
933
+ tools && delegates && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "studio-field", children: [
934
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: filterTitle }),
935
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("select", { "aria-label": roleFilterLabel, value: role.toolFilter?.mode ?? "default", onChange: (e) => {
936
+ const mode = e.target.value;
937
+ update2({ toolFilter: mode === "extend" || mode === "replace" ? { mode, deny: [] } : void 0 });
938
+ }, children: [
939
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "default", children: t(`\uD504\uB9AC\uC14B \uAE30\uBCF8\uAC12 \uC0AC\uC6A9 (${defaultCount}\uAC1C)`, `Use preset default (${defaultCount})`, `\u4F7F\u7528\u9884\u8BBE\u9ED8\u8BA4\u503C\uFF08${defaultCount} \u4E2A\uFF09`) }),
940
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "extend", children: t("\uAE30\uBCF8\uAC12\uC5D0 \uCD94\uAC00", "Add to preset default", "\u5728\u9ED8\u8BA4\u503C\u57FA\u7840\u4E0A\u6DFB\u52A0") }),
941
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: "replace", children: t("\uC774 \uC5ED\uD560\uB9CC \uB530\uB85C (\uAE30\uBCF8\uAC12 \uBB34\uC2DC)", "This role only (ignore default)", "\u4EC5\u6B64\u89D2\u8272\uFF08\u5FFD\u7565\u9ED8\u8BA4\u503C\uFF09") })
942
+ ] }),
943
+ role.toolFilter?.mode === "extend" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "studio-muted studio-hint", children: t("\uD504\uB9AC\uC14B \uAE30\uBCF8\uAC12\uC758 \uB3C4\uAD6C\uB294 \uC7A0\uAE34 \uCC44\uB85C \uD568\uAED8 \uBE60\uC9D1\uB2C8\uB2E4. \uC774 \uC5ED\uD560\uC5D0\uC11C \uCD94\uAC00\uB85C \uBE84 \uB3C4\uAD6C\uB97C \uACE0\uB974\uC138\uC694. \uAE30\uBCF8\uAC12\uC744 \uBC14\uAFB8\uBA74 \uC774 \uC5ED\uD560\uC5D0\uB3C4 \uBC18\uC601\uB429\uB2C8\uB2E4.", "Preset default tools are locked and stay filtered. Choose the tools this role filters in addition. Changes to the default apply to this role too.", "\u9884\u8BBE\u9ED8\u8BA4\u503C\u4E2D\u7684\u5DE5\u5177\u5DF2\u9501\u5B9A\u5E76\u4E00\u5E76\u6392\u9664\u3002\u8BF7\u9009\u62E9\u6B64\u89D2\u8272\u989D\u5916\u6392\u9664\u7684\u5DE5\u5177\u3002\u9ED8\u8BA4\u503C\u7684\u66F4\u6539\u4E5F\u4F1A\u5E94\u7528\u5230\u6B64\u89D2\u8272\u3002") }),
944
+ role.toolFilter?.mode === "replace" && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "studio-muted studio-hint", children: t("\uD504\uB9AC\uC14B \uAE30\uBCF8\uAC12\uC774 \uC774 \uC5ED\uD560\uC5D0\uB294 \uC801\uC6A9\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. \uC774 \uC5ED\uD560\uC5D0\uC11C \uBE84 \uB3C4\uAD6C\uB9CC \uACE0\uB974\uC138\uC694.", "The preset default does not apply to this role. Choose only the tools this role filters.", "\u9884\u8BBE\u9ED8\u8BA4\u503C\u4E0D\u9002\u7528\u4E8E\u6B64\u89D2\u8272\u3002\u8BF7\u4EC5\u9009\u62E9\u6B64\u89D2\u8272\u6392\u9664\u7684\u5DE5\u5177\u3002") }),
945
+ role.toolFilter && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
946
+ ToolFilterPicker,
947
+ {
948
+ label: roleFilterLabel,
949
+ tools,
950
+ selected: role.toolFilter.deny,
951
+ locked: role.toolFilter.mode === "extend" ? hiddenTools : [],
952
+ lockedReason: t("\uD504\uB9AC\uC14B \uAE30\uBCF8\uAC12", "Preset default", "\u9884\u8BBE\u9ED8\u8BA4\u503C"),
953
+ onChange: (deny) => update2({ toolFilter: { mode: role.toolFilter.mode, deny } }),
954
+ t
955
+ }
956
+ )
957
+ ] }),
958
+ field2(t("\uC5ED\uD560 \uC9C0\uCE68 (persona)", "Role instructions (persona)", "\u89D2\u8272\u6307\u4EE4\uFF08persona\uFF09"), /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("textarea", { rows: 6, value: role.persona, placeholder: defaultPersona, onChange: (e) => update2({ persona: e.target.value }) })),
959
+ !role.persona && defaultPersona && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "studio-muted studio-hint", children: t("\uD750\uB9B0 \uAE00\uC528\uB294 \uD504\uB9AC\uC14B\uC758 \uAE30\uBCF8 persona\uC785\uB2C8\uB2E4. \uBE44\uC6CC \uB450\uBA74 \uC774 \uB0B4\uC6A9\uC774 \uADF8\uB300\uB85C \uC4F0\uC785\uB2C8\uB2E4.", "The dimmed text is the preset default persona; it is used while this field is empty.", "\u6D45\u8272\u6587\u5B57\u662F\u9884\u8BBE\u7684\u9ED8\u8BA4 persona\uFF0C\u7559\u7A7A\u65F6\u4F7F\u7528\u8BE5\u5185\u5BB9\u3002") })
851
960
  ] })
852
961
  }
853
962
  )
854
963
  ] });
855
964
  }
965
+ function ToolFilterPicker({ label, tools, selected, onChange, t, locked = [], lockedReason }) {
966
+ const items = tools.map((tool) => locked.includes(tool.name) && lockedReason ? { ...tool, lockedReason } : tool);
967
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
968
+ ItemPicker,
969
+ {
970
+ label,
971
+ items,
972
+ selected: selected.filter((name) => tools.some((tool) => tool.name === name) && !locked.includes(name)),
973
+ onChange: (names2) => onChange(names2.filter((name) => !locked.includes(name))),
974
+ hasDetails: () => false,
975
+ labels: { filter: t("\uBCF4\uAE30", "Show", "\u663E\u793A"), search: t("\uB3C4\uAD6C \uAC80\uC0C9", "Search tools", "\u641C\u7D22\u5DE5\u5177"), searchHint: t("\uC774\uB984, \uC124\uBA85\uC73C\uB85C \uAC80\uC0C9", "Search names or descriptions", "\u6309\u540D\u79F0\u6216\u63CF\u8FF0\u641C\u7D22"), all: t("\uC804\uCCB4", "All", "\u5168\u90E8"), selected: t("\uC81C\uC678\uB428", "Filtered", "\u5DF2\u6392\u9664"), modified: t("\uBCC0\uACBD\uB428", "Modified", "\u5DF2\u4FEE\u6539"), settings: t("\uC124\uC815", "Details", "\u8BBE\u7F6E"), done: t("\uC644\uB8CC", "Close", "\u5B8C\u6210"), empty: t("\uC774 \uD504\uB9AC\uC14B\uC5D0\uC11C \uC120\uD0DD\uD55C \uB3C4\uAD6C\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.", "This preset selects no tools.", "\u6B64\u9884\u8BBE\u672A\u9009\u62E9\u4EFB\u4F55\u5DE5\u5177\u3002"), noResults: t("\uAC80\uC0C9 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.", "No matching results.", "\u6CA1\u6709\u5339\u914D\u7ED3\u679C\u3002"), modifiedTag: t("\uBCC0\uACBD\uB428", "Modified", "\u5DF2\u4FEE\u6539"), clear: t("\uC804\uCCB4 \uBCF4\uAE30", "Show all", "\u663E\u793A\u5168\u90E8") }
976
+ }
977
+ );
978
+ }
856
979
 
857
980
  // src/optimization-prototype.tsx
858
981
  var import_react9 = __toESM(require("react"), 1);
859
982
 
860
983
  // src/master-extensions-editor.tsx
861
- var import_react3 = __toESM(require("react"), 1);
862
- var import_jsx_runtime3 = require("react/jsx-runtime");
984
+ var import_react4 = __toESM(require("react"), 1);
985
+ var import_jsx_runtime4 = require("react/jsx-runtime");
863
986
  function MasterExtensionsEditor({ locale, actions }) {
864
987
  const t = (ko2, en2, zh2) => locale.startsWith("ko") ? ko2 : locale.startsWith("zh") ? zh2 : en2;
865
- const [text, setText] = import_react3.default.useState("[]");
866
- const [error, setError] = import_react3.default.useState("");
867
- const [busy, setBusy] = import_react3.default.useState(false);
868
- const [loaded, setLoaded] = import_react3.default.useState(false);
869
- import_react3.default.useEffect(() => {
988
+ const [text, setText] = import_react4.default.useState("[]");
989
+ const [error, setError] = import_react4.default.useState("");
990
+ const [busy, setBusy] = import_react4.default.useState(false);
991
+ const [loaded, setLoaded] = import_react4.default.useState(false);
992
+ import_react4.default.useEffect(() => {
870
993
  let active = true;
871
994
  if (actions) actions.read().then((value) => {
872
995
  if (active) {
@@ -880,22 +1003,22 @@ function MasterExtensionsEditor({ locale, actions }) {
880
1003
  active = false;
881
1004
  };
882
1005
  }, [actions]);
883
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "studio-page-stack", children: [
884
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PageHead, { title: t("\uB3C4\uAD6C \uC81C\uACF5\uC790", "Tool providers", "\u5DE5\u5177\u63D0\u4F9B\u8005"), description: t("\uC124\uCE58\uB41C \uD50C\uB7EC\uADF8\uC778\uC758 \uB3C4\uAD6C\uB97C Studio \uB3C4\uAD6C \uBAA9\uB85D\uC5D0 \uB4F1\uB85D\uD569\uB2C8\uB2E4. \uB4F1\uB85D\uD55C \uB3C4\uAD6C\uB294 \uD504\uB9AC\uC14B \uB9CC\uB4E4\uAE30\uC5D0\uC11C \uACE0\uB97C \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Register installed plugin tools in the Studio tool list so presets can select them.", "\u5C06\u5DF2\u5B89\u88C5\u63D2\u4EF6\u7684\u5DE5\u5177\u6CE8\u518C\u5230 Studio \u5DE5\u5177\u5217\u8868\uFF0C\u4F9B\u9884\u8BBE\u9009\u62E9") }),
885
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { children: t("\uB4F1\uB85D\uD558\uBA74 \uD50C\uB7EC\uADF8\uC778 \uCF54\uB4DC\uAC00 \uC2E4\uD589\uB418\uBBC0\uB85C \uC2E0\uB8B0\uD558\uB294 \uD50C\uB7EC\uADF8\uC778\uB9CC \uCD94\uAC00\uD558\uC138\uC694. \uD328\uD0A4\uC9C0\uB97C \uC124\uCE58\uD558\uC9C0\uB294 \uC54A\uC73C\uBA70, \uC124\uC815\uC740 \uC774 \uCEF4\uD4E8\uD130\uC5D0 \uD3C9\uBB38\uC73C\uB85C \uC800\uC7A5\uB429\uB2C8\uB2E4.", "Register installed provider compositions as JSON. This does not install packages or generate tool code. Registration executes plugin code: add trusted providers only. Settings are stored locally as plaintext. Applied presets are not automatically changed.", "\u4EE5 JSON \u6CE8\u518C\u5DF2\u5B89\u88C5\u7684\u63D0\u4F9B\u8005\u914D\u7F6E\u3002\u4E0D\u5B89\u88C5\u8F6F\u4EF6\u5305\u6216\u751F\u6210\u5DE5\u5177\u4EE3\u7801\u3002\u6CE8\u518C\u4F1A\u6267\u884C\u63D2\u4EF6\u4EE3\u7801\uFF0C\u8BF7\u4EC5\u6DFB\u52A0\u53EF\u4FE1\u63D0\u4F9B\u8005\u3002\u8BBE\u7F6E\u4EE5\u660E\u6587\u4FDD\u5B58\u5728\u672C\u5730\u3002\u5DF2\u5E94\u7528\u7684\u9884\u8BBE\u4E0D\u4F1A\u81EA\u52A8\u6539\u53D8\u3002") }),
886
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("ol", { className: "studio-steps", children: [
887
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { children: t("\uD50C\uB7EC\uADF8\uC778\uC774 \uD604\uC7AC DSH \uD504\uB85C\uD544\uC5D0 \uC124\uCE58\uB418\uC5B4 \uC788\uB294\uC9C0 \uD655\uC778\uD569\uB2C8\uB2E4.", "Ensure the plugin is installed in this DSH profile. Packages are not installed automatically.", "\u786E\u8BA4\u63D2\u4EF6\u5DF2\u5B89\u88C5\u5728\u5F53\u524D DSH \u914D\u7F6E\u4E2D\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u5B89\u88C5\u3002") }),
888
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { children: t("\uC544\uB798 \uBC30\uC5F4\uC5D0 id(\uACE0\uC720\uD55C \uC18C\uBB38\uC790 \uC2DD\uBCC4\uC790), name(\uD328\uD0A4\uC9C0 \uC774\uB984), config(\uD50C\uB7EC\uADF8\uC778 \uC124\uC815)\uB97C \uC785\uB825\uD569\uB2C8\uB2E4.", "Add an entry with id (unique lowercase identifier), name (exact package name), and config (public plugin settings).", "\u5728\u6570\u7EC4\u4E2D\u586B\u5199 id\uFF08\u552F\u4E00\u5C0F\u5199\u6807\u8BC6\u7B26\uFF09\u3001name\uFF08\u51C6\u786E\u7684\u8F6F\u4EF6\u5305\u540D\uFF09\u548C config\uFF08\u63D2\u4EF6\u516C\u5F00\u8BBE\u7F6E\uFF09\u3002") }),
889
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("li", { children: t("\uD655\uC778 \uD6C4 \uB4F1\uB85D\uC744 \uB204\uB974\uBA74 \uB3C4\uAD6C \uBAA9\uB85D\uC774 \uAC31\uC2E0\uB429\uB2C8\uB2E4. \uD544\uC694\uD55C \uB3C4\uAD6C\uB97C \uACE8\uB77C \uD504\uB9AC\uC14B\uC744 \uC800\uC7A5\uD558\uC138\uC694.", "Validate and update master to refresh the tool list, then select the tools and save your preset.", "\u9A8C\u8BC1\u5E76\u66F4\u65B0\u4E3B\u9884\u8BBE\u540E\uFF0C\u9009\u62E9\u6240\u9700\u5DE5\u5177\u5E76\u4FDD\u5B58\u9884\u8BBE\u3002") })
1006
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "studio-page-stack", children: [
1007
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PageHead, { title: t("\uB3C4\uAD6C \uC81C\uACF5\uC790", "Tool providers", "\u5DE5\u5177\u63D0\u4F9B\u8005"), description: t("\uC124\uCE58\uB41C \uD50C\uB7EC\uADF8\uC778\uC758 \uB3C4\uAD6C\uB97C Studio \uB3C4\uAD6C \uBAA9\uB85D\uC5D0 \uB4F1\uB85D\uD569\uB2C8\uB2E4. \uB4F1\uB85D\uD55C \uB3C4\uAD6C\uB294 \uD504\uB9AC\uC14B \uB9CC\uB4E4\uAE30\uC5D0\uC11C \uACE0\uB97C \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Register installed plugin tools in the Studio tool list so presets can select them.", "\u5C06\u5DF2\u5B89\u88C5\u63D2\u4EF6\u7684\u5DE5\u5177\u6CE8\u518C\u5230 Studio \u5DE5\u5177\u5217\u8868\uFF0C\u4F9B\u9884\u8BBE\u9009\u62E9") }),
1008
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Note, { children: t("\uB4F1\uB85D\uD558\uBA74 \uD50C\uB7EC\uADF8\uC778 \uCF54\uB4DC\uAC00 \uC2E4\uD589\uB418\uBBC0\uB85C \uC2E0\uB8B0\uD558\uB294 \uD50C\uB7EC\uADF8\uC778\uB9CC \uCD94\uAC00\uD558\uC138\uC694. \uD328\uD0A4\uC9C0\uB97C \uC124\uCE58\uD558\uC9C0\uB294 \uC54A\uC73C\uBA70, \uC124\uC815\uC740 \uC774 \uCEF4\uD4E8\uD130\uC5D0 \uD3C9\uBB38\uC73C\uB85C \uC800\uC7A5\uB429\uB2C8\uB2E4. \uC774\uBBF8 \uBC18\uC601\uD55C \uD504\uB9AC\uC14B\uC740 \uC790\uB3D9\uC73C\uB85C \uBC14\uB00C\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.", "Registering runs the plugin\u2019s code, so add only plugins you trust. Studio does not install packages, and these settings are stored on this computer in plain text. Presets you already applied do not change automatically.", "\u6CE8\u518C\u4F1A\u6267\u884C\u63D2\u4EF6\u4EE3\u7801\uFF0C\u8BF7\u4EC5\u6DFB\u52A0\u53EF\u4FE1\u63D2\u4EF6\u3002Studio \u4E0D\u4F1A\u5B89\u88C5\u8F6F\u4EF6\u5305\uFF0C\u8BBE\u7F6E\u4EE5\u660E\u6587\u4FDD\u5B58\u5728\u672C\u673A\u3002\u5DF2\u5E94\u7528\u7684\u9884\u8BBE\u4E0D\u4F1A\u81EA\u52A8\u6539\u53D8\u3002") }),
1009
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("ol", { className: "studio-steps", children: [
1010
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: t("\uD50C\uB7EC\uADF8\uC778\uC774 \uD604\uC7AC DSH \uD504\uB85C\uD544\uC5D0 \uC124\uCE58\uB418\uC5B4 \uC788\uB294\uC9C0 \uD655\uC778\uD569\uB2C8\uB2E4.", "Check that the plugin is installed in this DSH profile.", "\u786E\u8BA4\u63D2\u4EF6\u5DF2\u5B89\u88C5\u5728\u5F53\u524D DSH \u914D\u7F6E\u4E2D\uFF0C\u4E0D\u4F1A\u81EA\u52A8\u5B89\u88C5\u3002") }),
1011
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: t("\uC544\uB798 \uBC30\uC5F4\uC5D0 id(\uACE0\uC720\uD55C \uC18C\uBB38\uC790 \uC2DD\uBCC4\uC790), name(\uD328\uD0A4\uC9C0 \uC774\uB984), config(\uD50C\uB7EC\uADF8\uC778 \uC124\uC815)\uB97C \uC785\uB825\uD569\uB2C8\uB2E4.", "Add an entry with id (unique lowercase identifier), name (exact package name), and config (public plugin settings).", "\u5728\u6570\u7EC4\u4E2D\u586B\u5199 id\uFF08\u552F\u4E00\u5C0F\u5199\u6807\u8BC6\u7B26\uFF09\u3001name\uFF08\u51C6\u786E\u7684\u8F6F\u4EF6\u5305\u540D\uFF09\u548C config\uFF08\u63D2\u4EF6\u516C\u5F00\u8BBE\u7F6E\uFF09\u3002") }),
1012
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: t("\uD655\uC778 \uD6C4 \uB4F1\uB85D\uC744 \uB204\uB974\uBA74 \uB3C4\uAD6C \uBAA9\uB85D\uC774 \uAC31\uC2E0\uB429\uB2C8\uB2E4. \uD544\uC694\uD55C \uB3C4\uAD6C\uB97C \uACE8\uB77C \uD504\uB9AC\uC14B\uC744 \uC800\uC7A5\uD558\uC138\uC694.", "Select Validate and update master to refresh the tool list, then choose the tools and save your preset.", "\u9A8C\u8BC1\u5E76\u66F4\u65B0\u4E3B\u9884\u8BBE\u540E\uFF0C\u9009\u62E9\u6240\u9700\u5DE5\u5177\u5E76\u4FDD\u5B58\u9884\u8BBE\u3002") })
890
1013
  ] }),
891
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { className: "studio-muted", children: t("\uC608\uC2DC: \uC124\uCE58\uB41C subagent \uD50C\uB7EC\uADF8\uC778\uC744 \uB2E4\uB978 \uB3C4\uAD6C \uC774\uB984\uC73C\uB85C \uB4F1\uB85D", "Example: register the installed subagent provider under a distinct tool name", "\u793A\u4F8B\uFF1A\u4F7F\u7528\u4E0D\u540C\u5DE5\u5177\u540D\u6CE8\u518C\u5DF2\u5B89\u88C5\u7684 subagent \u63D0\u4F9B\u8005") }),
892
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("pre", { children: JSON.stringify([{ id: "extra-agent", name: "@deepseek-ai/dsh-tool-subagent", config: { provider: "spawn", toolName: "studio_extra_agent" } }], null, 2) }),
893
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Note, { children: t("\uBAA9\uB85D \uC804\uCCB4\uAC00 \uC0C8 \uB0B4\uC6A9\uC73C\uB85C \uBC14\uB01D\uB2C8\uB2E4. \uAE30\uC874 \uD56D\uBAA9\uC744 \uC720\uC9C0\uD558\uB824\uBA74 \uBC30\uC5F4\uC5D0 \uB0A8\uACA8 \uB450\uACE0, \uBAA8\uB450 \uC9C0\uC6B0\uB824\uBA74 []\uB97C \uB4F1\uB85D\uD558\uC138\uC694. \uB3C4\uAD6C \uC774\uB984\uC774 \uACB9\uCE58\uC9C0 \uC54A\uAC8C \uD558\uC138\uC694.", "Saving replaces the entire extension list. Keep existing entries to retain them; [] removes all added providers only. Avoid existing tool names. Missing plugin service dependencies can prevent activation.", "\u4FDD\u5B58\u4F1A\u66FF\u6362\u6574\u4E2A\u9644\u52A0\u63D0\u4F9B\u8005\u5217\u8868\u3002\u4FDD\u7559\u5DF2\u6709\u6761\u76EE\u4EE5\u514D\u5220\u9664\uFF1B\u4FDD\u5B58 [] \u4EC5\u79FB\u9664\u5168\u90E8\u9644\u52A0\u63D0\u4F9B\u8005\u3002\u907F\u514D\u5DE5\u5177\u91CD\u540D\uFF1B\u7F3A\u5C11\u4F9D\u8D56\u670D\u52A1\u53EF\u80FD\u5BFC\u81F4\u6FC0\u6D3B\u5931\u8D25\u3002") }),
894
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { className: "studio-field", children: [
895
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: t("\uB4F1\uB85D \uBAA9\uB85D (JSON)", "Provider composition", "\u63D0\u4F9B\u8005\u914D\u7F6E") }),
896
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("textarea", { rows: 6, className: "studio-mono", value: text, disabled: !loaded || busy, onChange: (event) => setText(event.target.value) })
1014
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { className: "studio-muted", children: t("\uC608\uC2DC: \uC124\uCE58\uB41C subagent \uD50C\uB7EC\uADF8\uC778\uC744 \uB2E4\uB978 \uB3C4\uAD6C \uC774\uB984\uC73C\uB85C \uB4F1\uB85D", "Example: register the installed subagent provider under a distinct tool name", "\u793A\u4F8B\uFF1A\u4F7F\u7528\u4E0D\u540C\u5DE5\u5177\u540D\u6CE8\u518C\u5DF2\u5B89\u88C5\u7684 subagent \u63D0\u4F9B\u8005") }),
1015
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("pre", { children: JSON.stringify([{ id: "extra-agent", name: "@deepseek-ai/dsh-tool-subagent", config: { provider: "spawn", toolName: "studio_extra_agent" } }], null, 2) }),
1016
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Note, { children: t("\uBAA9\uB85D \uC804\uCCB4\uAC00 \uC0C8 \uB0B4\uC6A9\uC73C\uB85C \uBC14\uB01D\uB2C8\uB2E4. \uAE30\uC874 \uD56D\uBAA9\uC744 \uC720\uC9C0\uD558\uB824\uBA74 \uBC30\uC5F4\uC5D0 \uB0A8\uACA8 \uB450\uACE0, \uBAA8\uB450 \uC9C0\uC6B0\uB824\uBA74 []\uB97C \uB4F1\uB85D\uD558\uC138\uC694. \uB3C4\uAD6C \uC774\uB984\uC774 \uACB9\uCE58\uC9C0 \uC54A\uAC8C \uD558\uC138\uC694. \uD544\uC694\uD55C \uC11C\uBE44\uC2A4\uAC00 \uC5C6\uB294 \uD50C\uB7EC\uADF8\uC778\uC740 \uD65C\uC131\uD654\uB418\uC9C0 \uC54A\uC744 \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Registering replaces the whole list. Keep existing entries in the array to retain them, or register [] to remove them all. Avoid tool names that already exist. A plugin whose required services are missing may fail to activate.", "\u6CE8\u518C\u4F1A\u66FF\u6362\u6574\u4E2A\u5217\u8868\u3002\u4FDD\u7559\u5DF2\u6709\u6761\u76EE\u4EE5\u514D\u5220\u9664\uFF1B\u6CE8\u518C [] \u4F1A\u79FB\u9664\u5168\u90E8\u6761\u76EE\u3002\u907F\u514D\u5DE5\u5177\u91CD\u540D\uFF1B\u7F3A\u5C11\u4F9D\u8D56\u670D\u52A1\u7684\u63D2\u4EF6\u53EF\u80FD\u65E0\u6CD5\u6FC0\u6D3B\u3002") }),
1017
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("label", { className: "studio-field", children: [
1018
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: t("\uB4F1\uB85D \uBAA9\uB85D (JSON)", "Provider list (JSON)", "\u63D0\u4F9B\u8005\u5217\u8868\uFF08JSON\uFF09") }),
1019
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("textarea", { rows: 6, className: "studio-mono", value: text, disabled: !loaded || busy, onChange: (event) => setText(event.target.value) })
897
1020
  ] }),
898
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { className: "studio-inline-actions", children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Button, { disabled: !loaded || busy, onClick: async () => {
1021
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "studio-inline-actions", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { disabled: !loaded || busy, onClick: async () => {
899
1022
  if (!actions) return;
900
1023
  setBusy(true);
901
1024
  setError("");
@@ -907,10 +1030,34 @@ function MasterExtensionsEditor({ locale, actions }) {
907
1030
  setBusy(false);
908
1031
  }
909
1032
  }, children: t("\uD655\uC778 \uD6C4 \uB4F1\uB85D", "Validate and update master", "\u9A8C\u8BC1\u5E76\u66F4\u65B0\u4E3B\u9884\u8BBE") }) }),
910
- error && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("p", { role: "alert", children: error })
1033
+ error && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { role: "alert", children: error })
911
1034
  ] });
912
1035
  }
913
1036
 
1037
+ // src/package-name.ts
1038
+ var PACKAGE_NAME = "@matamt-dbg/dsh-studio";
1039
+ var POLICY_PLUGIN = `${PACKAGE_NAME}/policy`;
1040
+ var ROLE_PLUGIN = `${PACKAGE_NAME}/roles`;
1041
+ var BATCH_PLUGIN = `${PACKAGE_NAME}/batch`;
1042
+
1043
+ // src/delegation.ts
1044
+ var ROLE_TOOL = "subagent_role";
1045
+ var LEGACY_ROLE_TOOL = "studio_role";
1046
+ var GENERIC_DELEGATION_TOOLS = ["subagent", "subagent_fork", "list_subagent_models"];
1047
+ var SUBAGENT_PLUGIN = "@deepseek-ai/dsh-tool-subagent";
1048
+ var isDelegationPlugin = (name) => name === SUBAGENT_PLUGIN || name === ROLE_PLUGIN;
1049
+ var WITHDRAWN_TOOLS = ["task_run"];
1050
+ function delegationTools(tools, hasRoles = false) {
1051
+ const delegates = hasRoles || tools.some((name) => name === ROLE_TOOL || name === LEGACY_ROLE_TOOL || GENERIC_DELEGATION_TOOLS.includes(name));
1052
+ const rest = tools.filter((name) => name !== ROLE_TOOL && name !== LEGACY_ROLE_TOOL && !GENERIC_DELEGATION_TOOLS.includes(name) && !WITHDRAWN_TOOLS.includes(name));
1053
+ return delegates ? [...rest, ROLE_TOOL] : rest;
1054
+ }
1055
+ function renameLegacyRoleKey(entries) {
1056
+ if (!entries || !Object.hasOwn(entries, LEGACY_ROLE_TOOL)) return entries;
1057
+ const { [LEGACY_ROLE_TOOL]: legacy, ...rest } = entries;
1058
+ return Object.hasOwn(rest, ROLE_TOOL) ? rest : { ...rest, [ROLE_TOOL]: legacy };
1059
+ }
1060
+
914
1061
  // src/config-editor.tsx
915
1062
  var import_react5 = __toESM(require("react"), 1);
916
1063
 
@@ -924,63 +1071,6 @@ function hasChangedOverride(base, override) {
924
1071
  return JSON.stringify(base) !== JSON.stringify(override);
925
1072
  }
926
1073
 
927
- // src/item-picker.tsx
928
- var import_react4 = __toESM(require("react"), 1);
929
- var import_jsx_runtime4 = require("react/jsx-runtime");
930
- function ItemPicker({ label, items, selected, onChange, labels, renderDetails, isModified, hasDetails }) {
931
- const [query, setQuery] = import_react4.default.useState("");
932
- const [filter, setFilter] = import_react4.default.useState("all");
933
- const [detail, setDetail] = import_react4.default.useState();
934
- const chosen = new Set(selected);
935
- const modified = (name) => chosen.has(name) && (isModified?.(name) ?? false);
936
- const text = query.trim().toLowerCase();
937
- const visible = items.filter((item) => (filter === "all" || (filter === "selected" ? chosen.has(item.name) : modified(item.name))) && (!text || `${item.name}
938
- ${item.title ?? ""}
939
- ${item.description}
940
- ${item.searchText ?? ""}`.toLowerCase().includes(text)));
941
- const counts = { all: items.length, selected: items.filter((item) => chosen.has(item.name)).length, modified: items.filter((item) => modified(item.name)).length };
942
- const toggle = (name) => onChange(chosen.has(name) ? selected.filter((value) => value !== name) : [...selected, name]);
943
- const open = items.find((item) => item.name === detail && chosen.has(item.name));
944
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "studio-picker", children: [
945
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "studio-picker-bar", children: [
946
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("input", { type: "search", "aria-label": labels.search, placeholder: labels.searchHint, value: query, onChange: (event) => setQuery(event.target.value) }),
947
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "studio-picker-filters", role: "radiogroup", "aria-label": labels.filter, children: ["all", "selected", "modified"].map((value) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", role: "radio", "aria-checked": filter === value, className: "studio-picker-filter", onClick: () => setFilter(value), children: [
948
- labels[value],
949
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "studio-count", children: counts[value] })
950
- ] }, value)) })
951
- ] }),
952
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("ul", { className: "studio-picker-list", "aria-label": label, children: [
953
- visible.map((item) => {
954
- const on = chosen.has(item.name);
955
- const blocked = !on && item.disabledReason !== void 0;
956
- const details = on && renderDetails !== void 0 && (hasDetails?.(item.name) ?? true);
957
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("li", { className: "studio-picker-row", "data-selected": on, children: [
958
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("button", { type: "button", role: "switch", "aria-checked": on, disabled: blocked, className: "studio-picker-toggle", "aria-label": `${item.title ?? item.name}`, onClick: () => toggle(item.name), children: [
959
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "studio-picker-check", "aria-hidden": "true", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("svg", { width: "12", height: "12", viewBox: "0 0 16 16", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("path", { d: "M3.5 8.5l3 3 6-7", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round" }) }) }),
960
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "studio-picker-text", children: [
961
- /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "studio-picker-title", children: [
962
- item.title ?? item.name,
963
- item.subtitle && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "studio-picker-subtitle studio-mono", children: item.subtitle })
964
- ] }),
965
- (item.disabledReason && !on ? item.disabledReason : item.description) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "studio-picker-description", children: item.disabledReason && !on ? item.disabledReason : item.description })
966
- ] })
967
- ] }),
968
- modified(item.name) && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "studio-badge", "data-tone": "info", "data-studio-modified": "true", children: labels.modifiedTag }),
969
- details && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { small: true, "aria-label": `${labels.settings}: ${item.name}`, "aria-haspopup": "dialog", onClick: () => setDetail(item.name), children: labels.settings })
970
- ] }, item.name);
971
- }),
972
- !visible.length && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("li", { className: "studio-picker-empty", role: "status", children: [
973
- text ? labels.noResults : labels.empty,
974
- (text || filter !== "all") && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(Button, { small: true, onClick: () => {
975
- setQuery("");
976
- setFilter("all");
977
- }, children: labels.clear })
978
- ] })
979
- ] }),
980
- renderDetails && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(DetailDialog, { open: open !== void 0, title: open?.title ?? open?.name, subtitle: open?.subtitle, closeLabel: labels.done, onClose: () => setDetail(void 0), children: open && renderDetails(open.name) })
981
- ] });
982
- }
983
-
984
1074
  // src/config-editor.tsx
985
1075
  var import_jsx_runtime5 = require("react/jsx-runtime");
986
1076
  var copy = {
@@ -988,10 +1078,11 @@ var copy = {
988
1078
  list: "Configs",
989
1079
  reset: "Reset override",
990
1080
  unavailable: "Schema unavailable; editing is disabled.",
1081
+ delegated: "Merged into subagent_role. Configure subagents in the Subagent settings tab.",
991
1082
  inherited: "Base value (not overridden)",
992
1083
  overridden: "Override",
993
1084
  unset: "Not set",
994
- unsupported: "This schema type is not yet supported by the form. Existing values are preserved; remove the Config to reset them.",
1085
+ unsupported: "This schema type is not yet supported by the form. Existing values are preserved; turn off the Config to reset them.",
995
1086
  json: "Config",
996
1087
  invalid: "Enter valid JSON.",
997
1088
  object: "Enter a JSON object.",
@@ -1003,6 +1094,7 @@ var copy = {
1003
1094
  list: "Config",
1004
1095
  reset: "\uAE30\uBCF8\uAC12\uC73C\uB85C",
1005
1096
  unavailable: "\uC2A4\uD0A4\uB9C8\uB97C \uC77D\uC744 \uC218 \uC5C6\uC5B4 \uD3B8\uC9D1\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
1097
+ delegated: "subagent_role\uB85C \uD1B5\uD569\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8 \uD0ED\uC5D0\uC11C \uC124\uC815\uD558\uC138\uC694.",
1006
1098
  inherited: "\uAE30\uBCF8\uAC12",
1007
1099
  overridden: "\uBCC0\uACBD\uB428",
1008
1100
  unset: "\uBBF8\uC124\uC815",
@@ -1018,6 +1110,7 @@ var copy = {
1018
1110
  list: "Config",
1019
1111
  reset: "\u91CD\u7F6E\u8986\u76D6",
1020
1112
  unavailable: "\u67B6\u6784\u4E0D\u53EF\u7528\uFF0C\u65E0\u6CD5\u7F16\u8F91",
1113
+ delegated: "\u5DF2\u5408\u5E76\u5230 subagent_role\u3002\u8BF7\u5728\u5B50\u4EE3\u7406\u8BBE\u7F6E\u9875\u4E2D\u914D\u7F6E\u3002",
1021
1114
  inherited: "\u57FA\u7840\u503C\uFF08\u672A\u8986\u76D6\uFF09",
1022
1115
  overridden: "\u8986\u76D6",
1023
1116
  unset: "\u672A\u8BBE\u7F6E",
@@ -1339,7 +1432,7 @@ function ConfigEditor({ entries, value, onChange, locale }) {
1339
1432
  subtitle: entry.id,
1340
1433
  description: "",
1341
1434
  searchText: JSON.stringify(entry.schema ?? {}),
1342
- ...entry.error || !entry.schema ? { disabledReason: entry.error || labels.unavailable } : {}
1435
+ ...isDelegationPlugin(entry.name) ? { disabledReason: labels.delegated } : entry.error || !entry.schema ? { disabledReason: entry.error || labels.unavailable } : {}
1343
1436
  })),
1344
1437
  ...Object.keys(value).filter((id) => !entries.some((entry) => entry.id === id)).map((id) => ({ name: id, title: id, description: labels.unavailable }))
1345
1438
  ];
@@ -1419,7 +1512,7 @@ function PresetList({ locale, api, revision, onEdit, onCopy }) {
1419
1512
  const warnings = [...items.reduce((groups, item) => item.applyWarning ? groups.set(item.applyWarning, [...groups.get(item.applyWarning) ?? [], item.name]) : groups, /* @__PURE__ */ new Map())];
1420
1513
  const retry = /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { small: true, disabled: load.phase === "loading", onClick: () => void refresh(), children: t("\uB2E4\uC2DC \uC2DC\uB3C4", "Retry", "\u91CD\u8BD5") });
1421
1514
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(import_jsx_runtime6.Fragment, { children: [
1422
- /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PageHead, { title: t("\uD504\uB9AC\uC14B \uBAA9\uB85D", "Preset list", "\u9884\u8BBE\u5217\u8868"), description: t("\uC800\uC7A5\uD55C \uD504\uB9AC\uC14B\uC744 DSH\uC5D0 \uBC18\uC601\uD558\uBA74 \uC0C8 \uC138\uC158\uC5D0\uC11C \uC120\uD0DD\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Apply saved configurations to DSH agent presets or delete them.", "\u5C06\u5DF2\u4FDD\u5B58\u7684\u914D\u7F6E\u5E94\u7528\u5230 DSH \u4EE3\u7406\u9884\u8BBE\u6216\u5220\u9664\u3002"), actions: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { disabled: busy || !api || load.phase === "loading", onClick: () => void refresh(), children: load.phase === "loading" && load.items ? t("\uC0C8\uB85C\uACE0\uCE68 \uC911\u2026", "Refreshing\u2026", "\u5237\u65B0\u4E2D\u2026") : t("\uC0C8\uB85C\uACE0\uCE68", "Refresh", "\u5237\u65B0") }) }),
1515
+ /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(PageHead, { title: t("\uD504\uB9AC\uC14B \uBAA9\uB85D", "Preset list", "\u9884\u8BBE\u5217\u8868"), description: t("\uC0C8 \uC138\uC158\uC5D0 \uC801\uC6A9\uD558\uB824\uBA74 DSH\uC5D0 \uBC18\uC601\uD574 \uC8FC\uC138\uC694. \uC774\uBBF8 \uC2E4\uD589 \uC911\uC778 \uC138\uC158\uC5D0\uB294 \uBCC0\uACBD \uC0AC\uD56D\uC774 \uC801\uC6A9\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.", "Apply to DSH to use these settings in new sessions. Changes do not affect sessions that are already running.", "\u8BF7\u5E94\u7528\u5230 DSH\uFF0C\u4EE5\u4FBF\u5728\u65B0\u4F1A\u8BDD\u4E2D\u4F7F\u7528\u8FD9\u4E9B\u8BBE\u7F6E\u3002\u66F4\u6539\u4E0D\u4F1A\u5F71\u54CD\u6B63\u5728\u8FD0\u884C\u7684\u4F1A\u8BDD\u3002"), actions: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { disabled: busy || !api || load.phase === "loading", onClick: () => void refresh(), children: load.phase === "loading" && load.items ? t("\uC0C8\uB85C\uACE0\uCE68 \uC911\u2026", "Refreshing\u2026", "\u5237\u65B0\u4E2D\u2026") : t("\uC0C8\uB85C\uACE0\uCE68", "Refresh", "\u5237\u65B0") }) }),
1423
1516
  !api && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Notice, { children: t("Studio \uC11C\uBC84\uC5D0 \uC5F0\uACB0\uB418\uC9C0 \uC54A\uC544 \uD504\uB9AC\uC14B\uC744 \uBD88\uB7EC\uC62C \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", "Presets are unavailable because the Studio Host API is not connected.", "Studio Host API \u672A\u8FDE\u63A5\uFF0C\u65E0\u6CD5\u52A0\u8F7D\u9884\u8BBE") }),
1424
1517
  api && load.phase === "loading" && !load.items && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "status", className: "studio-muted", children: t("\uD504\uB9AC\uC14B\uC744 \uBD88\uB7EC\uC624\uB294 \uC911\u2026", "Loading presets\u2026", "\u6B63\u5728\u52A0\u8F7D\u9884\u8BBE\u2026") }),
1425
1518
  load.phase === "failed" && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Notice, { action: retry, children: load.items ? t(`\uBAA9\uB85D\uC744 \uC0C8\uB85C \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD574 \uC774\uC804 \uBAA9\uB85D\uC744 \uD45C\uC2DC\uD569\uB2C8\uB2E4. (${load.error})`, `Could not reload the list. Showing the last loaded list. (${load.error})`, `\u65E0\u6CD5\u91CD\u65B0\u52A0\u8F7D\u5217\u8868\uFF0C\u6B63\u5728\u663E\u793A\u4E0A\u6B21\u52A0\u8F7D\u7684\u5217\u8868\uFF08${load.error}\uFF09`) : t(`\uD504\uB9AC\uC14B \uBAA9\uB85D\uC744 \uBD88\uB7EC\uC624\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uC800\uC7A5\uB41C \uD504\uB9AC\uC14B\uC5D0\uB294 \uC601\uD5A5\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. (${load.error})`, `Could not load presets. Saved presets were not changed. (${load.error})`, `\u65E0\u6CD5\u52A0\u8F7D\u9884\u8BBE\uFF0C\u5DF2\u4FDD\u5B58\u7684\u9884\u8BBE\u672A\u88AB\u66F4\u6539\uFF08${load.error}\uFF09`) }),
@@ -1429,7 +1522,7 @@ function PresetList({ locale, api, revision, onEdit, onCopy }) {
1429
1522
  action.error,
1430
1523
  ")"
1431
1524
  ] }),
1432
- load.phase === "ready" && !items.length && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "status", className: "studio-muted", children: t("\uC800\uC7A5\uB41C \uD504\uB9AC\uC14B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uD504\uB9AC\uC14B \uB9CC\uB4E4\uAE30\uC5D0\uC11C \uC0C8\uB85C \uB9CC\uB4E4\uC5B4 \uBCF4\uC138\uC694.", "No saved presets. Create one from Create preset.", "\u6CA1\u6709\u5DF2\u4FDD\u5B58\u7684\u9884\u8BBE\u3002\u8BF7\u4ECE\u521B\u5EFA\u9884\u8BBE\u83DC\u5355\u5F00\u59CB\u3002") }),
1525
+ load.phase === "ready" && !items.length && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { role: "status", className: "studio-muted", children: t("\uC800\uC7A5\uB41C \uD504\uB9AC\uC14B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uD504\uB9AC\uC14B \uB9CC\uB4E4\uAE30\uC5D0\uC11C \uC0C8\uB85C \uB9CC\uB4E4\uC5B4 \uBCF4\uC138\uC694.", "No saved presets. Use Create preset to make one.", "\u6CA1\u6709\u5DF2\u4FDD\u5B58\u7684\u9884\u8BBE\u3002\u8BF7\u4ECE\u521B\u5EFA\u9884\u8BBE\u83DC\u5355\u5F00\u59CB\u3002") }),
1433
1526
  warnings.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { className: "studio-preset-warnings", "aria-label": t("\uC8FC\uC758\uC0AC\uD56D", "Notices", "\u6CE8\u610F\u4E8B\u9879"), children: warnings.map(([text, names2]) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("li", { children: [
1434
1527
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Badge, { tone: "warning", children: t("\uC8FC\uC758", "Notice", "\u6CE8\u610F") }),
1435
1528
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { children: [
@@ -1437,7 +1530,7 @@ function PresetList({ locale, api, revision, onEdit, onCopy }) {
1437
1530
  " ",
1438
1531
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "studio-card-meta", children: [
1439
1532
  "(",
1440
- t("\uD574\uB2F9", "Affects", "\u6D89\u53CA"),
1533
+ t("\uB300\uC0C1", "Affects", "\u6D89\u53CA"),
1441
1534
  ": ",
1442
1535
  names2.join(", "),
1443
1536
  ")"
@@ -1451,7 +1544,7 @@ function PresetList({ locale, api, revision, onEdit, onCopy }) {
1451
1544
  item.template && !item.readOnly && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Badge, { tone: "info", children: t("\uAE30\uBCF8 \uC81C\uACF5", "Built-in", "\u5185\u7F6E") }),
1452
1545
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Badge, { tone: tone[item.status], children: status(item) })
1453
1546
  ] }),
1454
- item.template ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "studio-card-text", children: t("Studio\uAC00 \uAD8C\uC7A5\uD558\uB294 \uCF54\uB529 \uC5D0\uC774\uC804\uD2B8\uC6A9 \uAE30\uBCF8 \uAD6C\uC131\uC785\uB2C8\uB2E4. \uACE0\uCE58\uB824\uBA74 \uBCF5\uC0AC\uD574\uC11C \uC4F0\uC138\uC694.", "Studio optimized default for coding agents. Create a copy to customize it.", "Studio \u63A8\u8350\u7684\u7F16\u7801\u4EE3\u7406\u9ED8\u8BA4\u914D\u7F6E\u3002\u5982\u9700\u4FEE\u6539\uFF0C\u8BF7\u521B\u5EFA\u526F\u672C") }) : item.description && !item.readOnly && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "studio-card-text", children: item.description }),
1547
+ item.template ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "studio-card-text", children: t("Studio\uAC00 \uAD8C\uC7A5\uD558\uB294 \uCF54\uB529 \uC5D0\uC774\uC804\uD2B8\uC6A9 \uAD6C\uC131\uC785\uB2C8\uB2E4. \uACE0\uCE58\uB824\uBA74 \uBCF5\uC0AC\uD574\uC11C \uC4F0\uC138\uC694.", "Studio\u2019s recommended setup for coding agents. Create a copy to customize it.", "Studio \u63A8\u8350\u7684\u7F16\u7801\u4EE3\u7406\u914D\u7F6E\u3002\u5982\u9700\u4FEE\u6539\uFF0C\u8BF7\u521B\u5EFA\u526F\u672C") }) : item.description && !item.readOnly && /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "studio-card-text", children: item.description }),
1455
1548
  /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("p", { className: "studio-card-meta", children: [
1456
1549
  t("\uB3C4\uAD6C", "Tools", "\u5DE5\u5177"),
1457
1550
  " ",
@@ -1461,7 +1554,7 @@ function PresetList({ locale, api, revision, onEdit, onCopy }) {
1461
1554
  " ",
1462
1555
  Array.isArray(item.agents) ? item.agents.length : 0
1463
1556
  ] }),
1464
- item.readOnly ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "studio-card-meta studio-card-note", children: t("DSH\uC5D0 \uC124\uCE58\uB41C \uBAA8\uB4E0 \uB3C4\uAD6C\uB97C \uB2F4\uC740 \uAE30\uC900 \uD504\uB9AC\uC14B\uC785\uB2C8\uB2E4. \uD3B8\uC9D1\uD558\uAC70\uB098 \uC0AD\uC81C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", "Reference preset with every installed DSH tool. It cannot be edited or deleted.", "\u5305\u542B\u6240\u6709\u5DF2\u5B89\u88C5 DSH \u5DE5\u5177\u7684\u57FA\u51C6\u9884\u8BBE\uFF0C\u65E0\u6CD5\u7F16\u8F91\u6216\u5220\u9664") }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "studio-card-footer", children: [
1557
+ item.readOnly ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "studio-card-meta studio-card-note", children: t("\uC774 \uD504\uB85C\uD544\uC5D0\uC11C \uC4F8 \uC218 \uC788\uB294 \uBAA8\uB4E0 \uB3C4\uAD6C\uB97C \uB2F4\uC740 \uAE30\uC900 \uD504\uB9AC\uC14B\uC785\uB2C8\uB2E4. \uD3B8\uC9D1\uD558\uAC70\uB098 \uC0AD\uC81C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", "Reference preset with every tool available in this profile. It cannot be edited or deleted.", "\u5305\u542B\u6B64\u914D\u7F6E\u6587\u4EF6\u4E2D\u6240\u6709\u53EF\u7528\u5DE5\u5177\u7684\u57FA\u51C6\u9884\u8BBE\uFF0C\u65E0\u6CD5\u7F16\u8F91\u6216\u5220\u9664") }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "studio-card-footer", children: [
1465
1558
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { small: true, disabled: busy || item.readOnly || item.template || !onEdit, title: item.template ? t("\uAE30\uBCF8 \uC81C\uACF5 \uD504\uB9AC\uC14B\uC740 \uD3B8\uC9D1\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4. \uBCF5\uC0AC\uD574\uC11C \uACE0\uCCD0 \uC4F0\uC138\uC694.", "Built-in presets cannot be edited. Create a copy to customize it.", "\u5185\u7F6E\u9884\u8BBE\u65E0\u6CD5\u7F16\u8F91\uFF0C\u8BF7\u521B\u5EFA\u526F\u672C\u540E\u4FEE\u6539") : void 0, onClick: () => onEdit?.(item), children: t("\uD3B8\uC9D1", "Edit", "\u7F16\u8F91") }),
1466
1559
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { small: true, disabled: busy || !onCopy, onClick: () => onCopy?.(item), children: t("\uBCF5\uC0AC", "Create copy", "\u521B\u5EFA\u526F\u672C") }),
1467
1560
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Button, { small: true, disabled: busy || !api || item.readOnly || item.nonDeletable, title: item.nonDeletable ? t("\uAE30\uBCF8 \uC81C\uACF5 \uD504\uB9AC\uC14B\uC740 \uC0AD\uC81C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", "Built-in presets cannot be deleted.", "\u5185\u7F6E\u9884\u8BBE\u65E0\u6CD5\u5220\u9664") : void 0, onClick: () => {
@@ -1497,36 +1590,39 @@ function PresetList({ locale, api, revision, onEdit, onCopy }) {
1497
1590
  void run(target.id, "delete", () => api.delete(target.id)).then(() => setDeleting(void 0));
1498
1591
  }, children: t("\uC0AD\uC81C \uD655\uC778", "Confirm delete", "\u786E\u8BA4\u5220\u9664") })
1499
1592
  ] }),
1500
- children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "studio-muted", children: t("\uC800\uC7A5\uB41C \uD504\uB9AC\uC14B\uACFC DSH\uC5D0 \uBC18\uC601\uB41C \uD504\uB9AC\uC14B\uC744 \uD568\uAED8 \uC0AD\uC81C\uD569\uB2C8\uB2E4. \uAE30\uC874 \uB300\uD654\uB294 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4.", "Delete the saved preset and its Studio-owned DSH registration. Existing conversations are not deleted.", "\u5220\u9664\u5DF2\u4FDD\u5B58\u9884\u8BBE\u53CA Studio \u6CE8\u518C\u7684 DSH \u9884\u8BBE\uFF0C\u4E0D\u5220\u9664\u73B0\u6709\u5BF9\u8BDD\u3002") })
1593
+ children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("p", { className: "studio-muted", children: t("\uC800\uC7A5\uB41C \uD504\uB9AC\uC14B\uACFC DSH\uC5D0 \uBC18\uC601\uB41C \uD504\uB9AC\uC14B\uC744 \uD568\uAED8 \uC0AD\uC81C\uD569\uB2C8\uB2E4. \uAE30\uC874 \uB300\uD654\uB294 \uB0A8\uC544 \uC788\uC2B5\uB2C8\uB2E4.", "Deletes the saved preset and removes it from DSH. Existing conversations are kept.", "\u5220\u9664\u5DF2\u4FDD\u5B58\u9884\u8BBE\u53CA Studio \u6CE8\u518C\u7684 DSH \u9884\u8BBE\uFF0C\u4E0D\u5220\u9664\u73B0\u6709\u5BF9\u8BDD\u3002") })
1501
1594
  }
1502
1595
  )
1503
1596
  ] });
1504
1597
  }
1505
1598
 
1506
- // src/package-name.ts
1507
- var PACKAGE_NAME = "@matamt-dbg/dsh-studio";
1508
- var POLICY_PLUGIN = `${PACKAGE_NAME}/policy`;
1509
- var ROLE_PLUGIN = `${PACKAGE_NAME}/roles`;
1510
- var BATCH_PLUGIN = `${PACKAGE_NAME}/batch`;
1511
-
1512
- // src/delegation.ts
1513
- var ROLE_TOOL = "subagent_role";
1514
- var LEGACY_ROLE_TOOL = "studio_role";
1515
- var GENERIC_DELEGATION_TOOLS = ["subagent", "subagent_fork", "list_subagent_models"];
1516
- var WITHDRAWN_TOOLS = ["task_run"];
1517
- function delegationTools(tools, hasRoles = false) {
1518
- const delegates = hasRoles || tools.some((name) => name === ROLE_TOOL || name === LEGACY_ROLE_TOOL || GENERIC_DELEGATION_TOOLS.includes(name));
1519
- const rest = tools.filter((name) => name !== ROLE_TOOL && name !== LEGACY_ROLE_TOOL && !GENERIC_DELEGATION_TOOLS.includes(name) && !WITHDRAWN_TOOLS.includes(name));
1520
- return delegates ? [...rest, ROLE_TOOL] : rest;
1521
- }
1522
- function renameLegacyRoleKey(entries) {
1523
- if (!entries || !Object.hasOwn(entries, LEGACY_ROLE_TOOL)) return entries;
1524
- const { [LEGACY_ROLE_TOOL]: legacy, ...rest } = entries;
1525
- return Object.hasOwn(rest, ROLE_TOOL) ? rest : { ...rest, [ROLE_TOOL]: legacy };
1526
- }
1527
-
1528
1599
  // src/optimized-preset.ts
1529
1600
  var BUILTIN_TOOL_PRESETS = ["standard", "ptc", "minimal", "cordis"];
1601
+ var OPTIMIZED_TOOLS = [
1602
+ "read_batch",
1603
+ "read",
1604
+ "write",
1605
+ "edit",
1606
+ "glob",
1607
+ "grep",
1608
+ "job_output",
1609
+ "job_list",
1610
+ "job_kill",
1611
+ "skill",
1612
+ "ask_user_question",
1613
+ "web_search",
1614
+ "web_fetch",
1615
+ "present",
1616
+ "bash",
1617
+ "read_image",
1618
+ "exit_plan_mode",
1619
+ "send_message",
1620
+ "interrupt_agent",
1621
+ "list_agents",
1622
+ "workflow",
1623
+ "subagent_role"
1624
+ ];
1625
+ var ALLOWED_TOOLS = /* @__PURE__ */ new Set([...OPTIMIZED_TOOLS, ...GENERIC_DELEGATION_TOOLS, LEGACY_ROLE_TOOL]);
1530
1626
 
1531
1627
  // src/prompt-tools-prototype.tsx
1532
1628
  var import_react7 = __toESM(require("react"), 1);
@@ -1568,7 +1664,8 @@ function PromptToolsPrototype({ locale, prompt, onPromptChange, provided, onProv
1568
1664
  onRequestChange?.(request);
1569
1665
  }, [requestKey, onRequestChange]);
1570
1666
  const labels = { filter: t("\uBCF4\uAE30", "Show", "\u663E\u793A"), search: t("\uB3C4\uAD6C \uAC80\uC0C9", "Search tools", "\u641C\u7D22\u5DE5\u5177"), searchHint: t("\uC774\uB984, \uC124\uBA85, \uC778\uC790\uB85C \uAC80\uC0C9", "Search names, descriptions or parameters", "\u6309\u540D\u79F0\u3001\u63CF\u8FF0\u6216\u53C2\u6570\u641C\u7D22"), all: t("\uC804\uCCB4", "All", "\u5168\u90E8"), selected: t("\uC120\uD0DD\uB428", "Selected", "\u5DF2\u9009"), modified: t("\uBCC0\uACBD\uB428", "Modified", "\u5DF2\u4FEE\u6539"), settings: t("\uC124\uC815", "Details", "\u8BE6\u60C5"), done: t("\uC644\uB8CC", "Close", "\u5173\u95ED"), empty: t("\uD56D\uBAA9\uC774 \uC5C6\uC2B5\uB2C8\uB2E4.", "No items", "\u65E0\u9879\u76EE"), noResults: t("\uAC80\uC0C9 \uACB0\uACFC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.", "No matching results.", "\u6CA1\u6709\u5339\u914D\u7ED3\u679C\u3002"), modifiedTag: t("\uBCC0\uACBD\uB428", "Modified", "\u5DF2\u4FEE\u6539"), clear: t("\uC804\uCCB4 \uBCF4\uAE30", "Show all", "\u663E\u793A\u5168\u90E8") };
1571
- const presetTools = (presetId) => delegationTools(presets.find((p) => p.id === presetId)?.tools.map((tool) => tool.name) ?? []);
1667
+ const unsupportedToolReason = t("\uD604\uC7AC Studio\uC5D0\uC11C run_code\uB294 \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4. PTC\uB97C \uC0AC\uC6A9\uD558\uB824\uBA74 DSH\uC758 PTC \uD504\uB9AC\uC14B\uC73C\uB85C \uC0C8 \uC138\uC158\uC744 \uC2DC\uC791\uD574 \uC8FC\uC138\uC694. \uC774\uBBF8 \uC120\uD0DD\uB41C \uACBD\uC6B0\uC5D0\uB294 \uD574\uC81C\uD574 \uC8FC\uC138\uC694.", "Studio does not currently support run_code. To use PTC, start a new session with DSH\u2019s PTC preset. If run_code is already selected, deselect it.", "Studio \u76EE\u524D\u4E0D\u652F\u6301 run_code\u3002\u5982\u9700\u4F7F\u7528 PTC\uFF0C\u8BF7\u4F7F\u7528 DSH \u7684 PTC \u9884\u8BBE\u542F\u52A8\u65B0\u4F1A\u8BDD\u3002\u82E5\u5DF2\u9009\u62E9 run_code\uFF0C\u8BF7\u53D6\u6D88\u9009\u62E9\u3002");
1668
+ const presetTools = (presetId) => delegationTools(presets.find((p) => p.id === presetId)?.tools.map((tool) => tool.name) ?? []).filter((name) => name !== "run_code");
1572
1669
  const togglePreset = (presetId) => {
1573
1670
  const names2 = presetTools(presetId);
1574
1671
  onProvidedChange(includesPreset(presetId) ? provided.filter((name) => !names2.includes(name)) : [.../* @__PURE__ */ new Set([...provided, ...names2])]);
@@ -1600,7 +1697,7 @@ function PromptToolsPrototype({ locale, prompt, onPromptChange, provided, onProv
1600
1697
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_react7.default.Fragment, { children: [
1601
1698
  catalogError ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Note, { children: catalogError }) : !catalog ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Note, { children: t("\uBD88\uB7EC\uC624\uB294 \uC911\u2026", "Loading\u2026", "\u6B63\u5728\u52A0\u8F7D\u2026") }) : null,
1602
1699
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "studio-form-section", children: [
1603
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SectionHead, { title: t("\uD504\uB86C\uD504\uD2B8", "Prompt composition", "\u63D0\u793A\u8BCD\u7EC4\u88C5"), description: t("\uC5D0\uC774\uC804\uD2B8\uC5D0\uAC8C \uC804\uB2EC\uD560 \uC9C0\uCE68\uC744 \uD3B8\uC9D1\uD569\uB2C8\uB2E4. \uBBF8\uB9AC\uBCF4\uAE30\uB85C \uC870\uB9BD \uACB0\uACFC\uB97C \uD655\uC778\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Edit Persona and Studio instructions, then preview the assembled result.", "\u7F16\u8F91 Persona \u4E0E Studio \u4E13\u7528\u6307\u4EE4\uFF0C\u5E76\u9884\u89C8\u7EC4\u88C5\u7ED3\u679C\u3002"), actions: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { small: true, disabled: !onPreview || !current || busy, onClick: () => void preview(), children: busy ? t("\uC870\uB9BD \uC911\u2026", "Assembling\u2026", "\u7EC4\u88C5\u4E2D\u2026") : t("\uD504\uB86C\uD504\uD2B8 \uBBF8\uB9AC\uBCF4\uAE30", "Preview prompt", "\u9884\u89C8\u63D0\u793A\u8BCD") }) }),
1700
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SectionHead, { title: t("\uD504\uB86C\uD504\uD2B8", "Prompt composition", "\u63D0\u793A\u8BCD\u7EC4\u88C5"), description: t("\uC5D0\uC774\uC804\uD2B8\uC5D0\uAC8C \uC804\uB2EC\uD560 \uC9C0\uCE68\uC744 \uD3B8\uC9D1\uD569\uB2C8\uB2E4. \uBBF8\uB9AC\uBCF4\uAE30\uB85C \uC870\uB9BD \uACB0\uACFC\uB97C \uD655\uC778\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Edit the instructions the agent receives, then preview the assembled result.", "\u7F16\u8F91 Persona \u4E0E Studio \u4E13\u7528\u6307\u4EE4\uFF0C\u5E76\u9884\u89C8\u7EC4\u88C5\u7ED3\u679C\u3002"), actions: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { small: true, disabled: !onPreview || !current || busy, onClick: () => void preview(), children: busy ? t("\uC870\uB9BD \uC911\u2026", "Assembling\u2026", "\u7EC4\u88C5\u4E2D\u2026") : t("\uD504\uB86C\uD504\uD2B8 \uBBF8\uB9AC\uBCF4\uAE30", "Preview prompt", "\u9884\u89C8\u63D0\u793A\u8BCD") }) }),
1604
1701
  ["prefix", "suffix"].map((key) => {
1605
1702
  const name = providers[0];
1606
1703
  const config = providerConfigs[name] ?? {};
@@ -1625,12 +1722,12 @@ function PromptToolsPrototype({ locale, prompt, onPromptChange, provided, onProv
1625
1722
  ] })
1626
1723
  ] }),
1627
1724
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("section", { className: "studio-form-section", children: [
1628
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SectionHead, { title: t("\uB3C4\uAD6C", "Provided tools", "\u63D0\u4F9B\u7684\u5DE5\u5177"), description: t("\uC5D0\uC774\uC804\uD2B8\uAC00 \uC4F8 \uB3C4\uAD6C\uB97C \uACE0\uB985\uB2C8\uB2E4. \uC124\uC815\uC5D0\uC11C \uBAA8\uB378\uC5D0 \uBCF4\uC774\uB294 \uC124\uBA85\uC744 \uBC14\uAFC0 \uC218 \uC788\uC73C\uBA70, \uB3C4\uAD6C \uB3D9\uC791\uC740 \uBC14\uB00C\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.", "Choose tools. Details edits model-facing descriptions only; tool behavior is unchanged.", "\u9009\u62E9\u5DE5\u5177\u3002\u8BE6\u60C5\u53EA\u7F16\u8F91\u6A21\u578B\u53EF\u89C1\u7684\u63CF\u8FF0\uFF0C\u5DE5\u5177\u884C\u4E3A\u4E0D\u53D8\u3002") }),
1725
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(SectionHead, { title: t("\uB3C4\uAD6C", "Provided tools", "\u63D0\u4F9B\u7684\u5DE5\u5177"), description: t("\uC5D0\uC774\uC804\uD2B8\uAC00 \uC4F8 \uB3C4\uAD6C\uB97C \uACE0\uB985\uB2C8\uB2E4. \uC124\uC815\uC5D0\uC11C \uBAA8\uB378\uC5D0 \uBCF4\uC774\uB294 \uC124\uBA85\uC744 \uBC14\uAFC0 \uC218 \uC788\uC73C\uBA70, \uB3C4\uAD6C \uB3D9\uC791\uC740 \uBC14\uB00C\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.", "Choose the tools the agent can use. Details changes only the descriptions the model sees; tool behavior stays the same.", "\u9009\u62E9\u5DE5\u5177\u3002\u8BE6\u60C5\u53EA\u7F16\u8F91\u6A21\u578B\u53EF\u89C1\u7684\u63CF\u8FF0\uFF0C\u5DE5\u5177\u884C\u4E3A\u4E0D\u53D8\u3002") }),
1629
1726
  /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "studio-field", children: [
1630
1727
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { children: t("\uAE30\uBCF8 \uD504\uB9AC\uC14B\uC5D0\uC11C \uD55C \uBC88\uC5D0 \uCD94\uAC00", "Include a built-in preset tool set", "\u5F15\u5165\u5185\u7F6E\u9884\u8BBE\u5DE5\u5177\u96C6") }),
1631
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "studio-inline-actions", children: toolSources.map((p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { small: true, disabled: !!p.error, "aria-pressed": includesPreset(p.id), onClick: () => togglePreset(p.id), children: p.id === "cordis" ? "creator (cordis)" : p.id }, p.id)) })
1728
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { className: "studio-inline-actions", children: toolSources.map((p) => /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { small: true, disabled: !!p.error || !presetTools(p.id).length, "aria-pressed": includesPreset(p.id), onClick: () => togglePreset(p.id), children: p.id === "cordis" ? "creator (cordis)" : p.id }, p.id)) })
1632
1729
  ] }),
1633
- /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ItemPicker, { label: t("\uB3C4\uAD6C", "Provided tools", "\u63D0\u4F9B\u7684\u5DE5\u5177"), items: [...tools.map((tool) => ({ ...tool, searchText: JSON.stringify(tool.parameters), ...GENERIC_DELEGATION_TOOLS.includes(tool.name) ? { disabledReason: t(`${ROLE_TOOL}\uB85C \uD1B5\uD569\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8 \uC704\uC784\uC740 ${ROLE_TOOL}\uC744 \uC120\uD0DD\uD558\uC138\uC694.`, `Merged into ${ROLE_TOOL}. Select ${ROLE_TOOL} for subagent delegation.`, `\u5DF2\u5408\u5E76\u5230 ${ROLE_TOOL}\u3002\u8BF7\u9009\u62E9 ${ROLE_TOOL} \u8FDB\u884C\u5B50\u4EE3\u7406\u59D4\u6D3E\u3002`) } : {} })), ...provided.filter((name) => !tools.some((tool) => tool.name === name)).map((name) => ({ name, description: t("\uD604\uC7AC \uC124\uCE58\uB41C \uB3C4\uAD6C \uBAA9\uB85D\uC5D0 \uC5C6\uC2B5\uB2C8\uB2E4.", "Absent from current catalog", "\u4E0D\u5728\u5F53\u524D\u76EE\u5F55\u4E2D") }))], selected: provided, onChange: changeTools, labels, isModified: (name) => {
1730
+ /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(ItemPicker, { label: t("\uB3C4\uAD6C", "Provided tools", "\u63D0\u4F9B\u7684\u5DE5\u5177"), items: [...tools.map((tool) => ({ ...tool, searchText: JSON.stringify(tool.parameters), ...tool.name === "run_code" ? { description: unsupportedToolReason, disabledReason: unsupportedToolReason } : {}, ...GENERIC_DELEGATION_TOOLS.includes(tool.name) ? { disabledReason: t(`${ROLE_TOOL}\uB85C \uD1B5\uD569\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8 \uC704\uC784\uC740 ${ROLE_TOOL}\uC744 \uC120\uD0DD\uD558\uC138\uC694.`, `Merged into ${ROLE_TOOL}. Select ${ROLE_TOOL} for subagent delegation.`, `\u5DF2\u5408\u5E76\u5230 ${ROLE_TOOL}\u3002\u8BF7\u9009\u62E9 ${ROLE_TOOL} \u8FDB\u884C\u5B50\u4EE3\u7406\u59D4\u6D3E\u3002`) } : {} })), ...provided.filter((name) => !tools.some((tool) => tool.name === name)).map((name) => ({ name, description: name === "run_code" ? unsupportedToolReason : t("\uD604\uC7AC \uD504\uB85C\uD544\uC5D0 \uC5C6\uB294 \uB3C4\uAD6C\uC785\uB2C8\uB2E4. \uC774\uB300\uB85C \uBC18\uC601\uD558\uBA74 \uC2E4\uD328\uD569\uB2C8\uB2E4.", "Not available in this profile. Applying will fail.", "\u5F53\u524D\u914D\u7F6E\u6587\u4EF6\u4E2D\u6CA1\u6709\u6B64\u5DE5\u5177\uFF0C\u76F4\u63A5\u5E94\u7528\u4F1A\u5931\u8D25\u3002"), ...name === "run_code" ? { disabledReason: unsupportedToolReason } : {} }))], selected: provided, onChange: changeTools, labels, hasDetails: (name) => name !== "run_code", isModified: (name) => {
1634
1731
  const tool = tools.find((item) => item.name === name);
1635
1732
  const override = toolOverrides[name];
1636
1733
  const parameters = parameterFields(tool?.parameters);
@@ -1676,7 +1773,7 @@ function PromptToolsPrototype({ locale, prompt, onPromptChange, provided, onProv
1676
1773
  const next = { ...toolOverrides };
1677
1774
  delete next[name];
1678
1775
  setToolOverrides(next);
1679
- }, children: t("\uC124\uBA85 \uBAA8\uB450 \uC6D0\uB798\uB300\uB85C", "Use original", "\u4F7F\u7528\u539F\u59CB\u503C") })
1776
+ }, children: t("\uC124\uBA85 \uBAA8\uB450 \uC6D0\uB798\uB300\uB85C", "Reset all descriptions", "\u5168\u90E8\u6062\u590D\u539F\u59CB\u63CF\u8FF0") })
1680
1777
  ] });
1681
1778
  } })
1682
1779
  ] }),
@@ -1685,7 +1782,7 @@ function PromptToolsPrototype({ locale, prompt, onPromptChange, provided, onProv
1685
1782
  {
1686
1783
  wide: true,
1687
1784
  open: previewOpen,
1688
- title: t("\uD504\uB86C\uD504\uD2B8 \uBBF8\uB9AC\uBCF4\uAE30", "Prompt result preview", "\u63D0\u793A\u8BCD\u7ED3\u679C\u9884\u89C8"),
1785
+ title: t("\uD504\uB86C\uD504\uD2B8 \uBBF8\uB9AC\uBCF4\uAE30", "Prompt preview", "\u63D0\u793A\u8BCD\u7ED3\u679C\u9884\u89C8"),
1689
1786
  closeLabel: t("\uB2EB\uAE30", "Close preview", "\u5173\u95ED\u9884\u89C8"),
1690
1787
  onClose: closePreview,
1691
1788
  subtitle: result ? t(`\uC139\uC158 ${result.sections.length}\uAC1C \xB7 \uB3C4\uAD6C ${result.tools.length}\uAC1C`, `${result.sections.length} sections \xB7 ${result.tools.length} tools`, `${result.sections.length} \u4E2A\u7AE0\u8282 \xB7 ${result.tools.length} \u4E2A\u5DE5\u5177`) : void 0,
@@ -1786,6 +1883,10 @@ function DetailLayout({ title, subtitle, navigation, pages, selected, onSelect }
1786
1883
 
1787
1884
  // src/optimization-prototype.tsx
1788
1885
  var import_jsx_runtime9 = require("react/jsx-runtime");
1886
+ var withoutSubagentFilter = (request) => {
1887
+ const { subagentToolFilter: _filter, ...rest } = request;
1888
+ return rest;
1889
+ };
1789
1890
  var initial = { prompt: "Report evidence, uncertainty and remaining work.", tools: "read / grep / glob", spill: "2048", wait: "60000" };
1790
1891
  var seeds = [
1791
1892
  { name: "Researcher", role: "research", model: "inherit", reasoning: "inherit", spawn: "fresh", persona: "Investigate primary sources and cite the evidence." },
@@ -1807,6 +1908,8 @@ function OptimizationPrototype({ locale, catalog, catalogError, onPreview, prese
1807
1908
  const [configDraft, setConfigDraft] = import_react9.default.useState();
1808
1909
  const configOverrides = configDraft ?? defaults;
1809
1910
  const [request, setRequest] = import_react9.default.useState();
1911
+ const [hiddenFromSubagents, setHiddenFromSubagents] = import_react9.default.useState([]);
1912
+ const selectable = (names2) => names2.filter((name2) => provided.includes(name2) && name2 !== ROLE_TOOL);
1810
1913
  const [saving, setSaving] = import_react9.default.useState(false);
1811
1914
  const [saveError, setSaveError] = import_react9.default.useState("");
1812
1915
  const save = async () => {
@@ -1814,7 +1917,7 @@ function OptimizationPrototype({ locale, catalog, catalogError, onPreview, prese
1814
1917
  setSaving(true);
1815
1918
  setSaveError("");
1816
1919
  try {
1817
- await presetActions.save(JSON.stringify({ ...editing?.id ? { id: editing.id } : {}, name: name.trim(), description, request: { ...request, configOverrides }, conveniences: { spill: common.spill }, agents }));
1920
+ await presetActions.save(JSON.stringify({ ...editing?.id ? { id: editing.id } : {}, name: name.trim(), description, request: { ...withoutSubagentFilter(request), configOverrides, ...selectable(hiddenFromSubagents).length ? { subagentToolFilter: { deny: selectable(hiddenFromSubagents) } } : {} }, conveniences: { spill: common.spill }, agents: agents.map((role) => role.toolFilter ? { ...role, toolFilter: { ...role.toolFilter, deny: selectable(role.toolFilter.deny) } } : role) }));
1818
1921
  setRevision((n) => n + 1);
1819
1922
  setPage("list");
1820
1923
  setName("");
@@ -1823,6 +1926,7 @@ function OptimizationPrototype({ locale, catalog, catalogError, onPreview, prese
1823
1926
  setCommon({ ...initial });
1824
1927
  setProvided([]);
1825
1928
  setAgents(seeds.map((a) => ({ ...a })));
1929
+ setHiddenFromSubagents([]);
1826
1930
  setEditing(void 0);
1827
1931
  setTab("tools");
1828
1932
  setDraftKey((n) => n + 1);
@@ -1841,6 +1945,7 @@ function OptimizationPrototype({ locale, catalog, catalogError, onPreview, prese
1841
1945
  setConfigDraft(item.request.configOverrides ?? {});
1842
1946
  setAgents(item.agents.map((role) => ({ ...role })));
1843
1947
  setRequest(item.request);
1948
+ setHiddenFromSubagents([...item.request.subagentToolFilter?.deny ?? []]);
1844
1949
  setDraftKey((n) => n + 1);
1845
1950
  setPage("create");
1846
1951
  };
@@ -1848,7 +1953,9 @@ function OptimizationPrototype({ locale, catalog, catalogError, onPreview, prese
1848
1953
  const presetPersona = request?.providerConfigs?.[persona]?.prefix;
1849
1954
  const masterPersona = catalog?.presets?.find((p) => p.id === (request?.preset ?? "studio-master"))?.promptProviders?.find((p) => p.name === persona)?.fields?.find((f) => f.key === "prefix")?.value;
1850
1955
  const defaultPersona = typeof presetPersona === "string" ? presetPersona : typeof masterPersona === "string" ? masterPersona : "";
1851
- const agentPage = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RoleEditor, { locale, roles: agents, onChange: setAgents, loadModels: presetActions?.models, defaultPersona }, draftKey);
1956
+ const toolChoices = (catalog?.tools ?? []).filter((tool) => provided.includes(tool.name) && tool.name !== ROLE_TOOL).map((tool) => ({ name: tool.name, description: tool.description }));
1957
+ const delegates = provided.some((name2) => name2 === ROLE_TOOL || GENERIC_DELEGATION_TOOLS.includes(name2));
1958
+ const agentPage = /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(RoleEditor, { locale, roles: agents, onChange: setAgents, loadModels: presetActions?.models, defaultPersona, tools: toolChoices, hiddenTools: hiddenFromSubagents, onHiddenToolsChange: setHiddenFromSubagents, delegates }, draftKey);
1852
1959
  const tabs = [
1853
1960
  { id: "tools", label: t("\uD504\uB86C\uD504\uD2B8\xB7\uB3C4\uAD6C", "Prompts & tools", "\u63D0\u793A\u8BCD\u4E0E\u5DE5\u5177"), content: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PromptToolsPrototype, { initialRequest: editing?.request, locale, catalog, catalogError, onPreview: onPreview ? (request2) => onPreview({ ...request2, configOverrides }) : void 0, onRequestChange: setRequest, prompt: common.prompt, onPromptChange: (value) => setCommon((c) => ({ ...c, prompt: value })), provided, onProvidedChange: setProvided }, draftKey) },
1854
1961
  { id: "convenience", label: t("\uC2E4\uD589 \uC124\uC815", "Execution settings", "\u6267\u884C\u8BBE\u7F6E"), content: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(import_jsx_runtime9.Fragment, { children: [
@@ -1858,7 +1965,7 @@ function OptimizationPrototype({ locale, catalog, catalogError, onPreview, prese
1858
1965
  { id: "agents", label: t("\uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8", "Subagent settings", "\u5B50\u4EE3\u7406\u8BBE\u7F6E"), content: agentPage }
1859
1966
  ];
1860
1967
  const tabId = import_react9.default.useId();
1861
- return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DetailLayout, { title: "DSH Studio", subtitle: t("\uC5D0\uC774\uC804\uD2B8 \uD504\uB9AC\uC14B \uD3B8\uC9D1\uAE30", "Agent preset editor", "\u4EE3\u7406\u9884\u8BBE\u7F16\u8F91\u5668"), navigation: t("Studio \uBA54\uB274", "Preset navigation", "\u9884\u8BBE\u5BFC\u822A"), selected: page, onSelect: (next) => {
1968
+ return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(DetailLayout, { title: "DSH Studio", subtitle: t("\uC5D0\uC774\uC804\uD2B8 \uD504\uB9AC\uC14B \uD3B8\uC9D1\uAE30", "Agent preset editor", "\u4EE3\u7406\u9884\u8BBE\u7F16\u8F91\u5668"), navigation: t("Studio \uBA54\uB274", "Studio menu", "\u9884\u8BBE\u5BFC\u822A"), selected: page, onSelect: (next) => {
1862
1969
  if (next === "create" && editing) {
1863
1970
  setEditing(void 0);
1864
1971
  setName("");
@@ -1873,7 +1980,7 @@ function OptimizationPrototype({ locale, catalog, catalogError, onPreview, prese
1873
1980
  }, pages: [
1874
1981
  { id: "list", group: t("\uD504\uB9AC\uC14B", "Presets", "\u9884\u8BBE"), label: t("\uD504\uB9AC\uC14B \uBAA9\uB85D", "Preset list", "\u9884\u8BBE\u5217\u8868"), content: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PresetList, { locale, api: presetActions, revision, onEdit: (item) => editPreset(item), onCopy: (item) => editPreset(item, true) }) },
1875
1982
  { id: "create", group: t("\uD504\uB9AC\uC14B", "Presets", "\u9884\u8BBE"), label: editing ? t("\uD504\uB9AC\uC14B \uD3B8\uC9D1", "Edit preset", "\u7F16\u8F91\u9884\u8BBE") : t("\uD504\uB9AC\uC14B \uB9CC\uB4E4\uAE30", "Create preset", "\u521B\u5EFA\u9884\u8BBE"), content: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "studio-page-stack", children: [
1876
- /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PageHead, { title: editing ? t("\uD504\uB9AC\uC14B \uD3B8\uC9D1", "Edit preset", "\u7F16\u8F91\u9884\u8BBE") : t("\uD504\uB9AC\uC14B \uB9CC\uB4E4\uAE30", "Create preset", "\u521B\u5EFA\u9884\u8BBE"), description: editing ? t("\uC800\uC7A5\uD55C \uB4A4 \uD504\uB9AC\uC14B \uBAA9\uB85D\uC5D0\uC11C \uB2E4\uC2DC \uBC18\uC601\uD574\uC57C DSH\uC5D0 \uC801\uC6A9\uB429\uB2C8\uB2E4.", "Saving updates this preset. If it was applied, reapply it from the list to update DSH.", "\u4FDD\u5B58\u4F1A\u66F4\u65B0\u6B64\u9884\u8BBE\u3002\u82E5\u5DF2\u5E94\u7528\uFF0C\u9700\u8981\u5728\u5217\u8868\u4E2D\u91CD\u65B0\u5E94\u7528\u624D\u4F1A\u66F4\u65B0 DSH") : t("\uD504\uB86C\uD504\uD2B8, \uB3C4\uAD6C, \uC2E4\uD589 \uC124\uC815, \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8\uB97C \uAD6C\uC131\uD574 \uC0C8 \uD504\uB9AC\uC14B\uC73C\uB85C \uC800\uC7A5\uD569\uB2C8\uB2E4.", "Configure tools, execution settings and subagent roles, then save a new preset.", "\u914D\u7F6E\u5DE5\u5177\u3001\u6267\u884C\u8BBE\u7F6E\u548C\u5B50\u4EE3\u7406\u89D2\u8272\uFF0C\u5E76\u4FDD\u5B58\u4E3A\u65B0\u9884\u8BBE"), actions: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Button, { primary: true, disabled: saving || !presetActions || !request || !name.trim(), onClick: () => void save(), children: saving ? t("\uC800\uC7A5 \uC911\u2026", "Saving\u2026", "\u4FDD\u5B58\u4E2D\u2026") : t("\uD504\uB9AC\uC14B \uC800\uC7A5", "Save preset", "\u4FDD\u5B58\u9884\u8BBE") }) }),
1983
+ /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(PageHead, { title: editing ? t("\uD504\uB9AC\uC14B \uD3B8\uC9D1", "Edit preset", "\u7F16\u8F91\u9884\u8BBE") : t("\uD504\uB9AC\uC14B \uB9CC\uB4E4\uAE30", "Create preset", "\u521B\u5EFA\u9884\u8BBE"), description: editing ? t("\uC800\uC7A5 \uD6C4 \uC0C8 \uC138\uC158\uC5D0 \uC801\uC6A9\uD558\uB824\uBA74 \uD504\uB9AC\uC14B \uBAA9\uB85D\uC5D0\uC11C DSH\uC5D0 \uBC18\uC601\uD574 \uC8FC\uC138\uC694. \uC774\uBBF8 \uC2E4\uD589 \uC911\uC778 \uC138\uC158\uC5D0\uB294 \uBCC0\uACBD \uC0AC\uD56D\uC774 \uC801\uC6A9\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.", "After saving, apply to DSH from the preset list to use these settings in new sessions. Changes do not affect sessions that are already running.", "\u4FDD\u5B58\u540E\uFF0C\u8BF7\u5728\u9884\u8BBE\u5217\u8868\u4E2D\u5E94\u7528\u5230 DSH\uFF0C\u4EE5\u4FBF\u5728\u65B0\u4F1A\u8BDD\u4E2D\u4F7F\u7528\u8FD9\u4E9B\u8BBE\u7F6E\u3002\u66F4\u6539\u4E0D\u4F1A\u5F71\u54CD\u6B63\u5728\u8FD0\u884C\u7684\u4F1A\u8BDD\u3002") : t("\uD504\uB86C\uD504\uD2B8, \uB3C4\uAD6C, \uC2E4\uD589 \uC124\uC815, \uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8\uB97C \uAD6C\uC131\uD574 \uC0C8 \uD504\uB9AC\uC14B\uC73C\uB85C \uC800\uC7A5\uD569\uB2C8\uB2E4.", "Configure prompts, tools, execution settings and subagents, then save a new preset.", "\u914D\u7F6E\u5DE5\u5177\u3001\u6267\u884C\u8BBE\u7F6E\u548C\u5B50\u4EE3\u7406\u89D2\u8272\uFF0C\u5E76\u4FDD\u5B58\u4E3A\u65B0\u9884\u8BBE"), actions: /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Button, { primary: true, disabled: saving || !presetActions || !request || !name.trim(), onClick: () => void save(), children: saving ? t("\uC800\uC7A5 \uC911\u2026", "Saving\u2026", "\u4FDD\u5B58\u4E2D\u2026") : t("\uD504\uB9AC\uC14B \uC800\uC7A5", "Save preset", "\u4FDD\u5B58\u9884\u8BBE") }) }),
1877
1984
  saveError && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(Notice, { children: t(`\uD504\uB9AC\uC14B\uC744 \uC800\uC7A5\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4. \uD3B8\uC9D1\uD55C \uB0B4\uC6A9\uC740 \uD654\uBA74\uC5D0 \uADF8\uB300\uB85C \uC788\uC2B5\uB2C8\uB2E4. (${saveError})`, `Could not save the preset. Your edits remain on this screen. (${saveError})`, `\u65E0\u6CD5\u4FDD\u5B58\u9884\u8BBE\uFF0C\u7F16\u8F91\u5185\u5BB9\u4ECD\u4FDD\u7559\u5728\u6B64\u9875\u9762\uFF08${saveError}\uFF09`) }),
1878
1985
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "studio-identity", children: [
1879
1986
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("label", { className: "studio-field studio-identity-name", children: [