@matamt-dbg/dsh-studio 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/client.js CHANGED
@@ -97,16 +97,16 @@ function parsePreviewRequest(value) {
97
97
  const row = value;
98
98
  const strings = (input) => Array.isArray(input) && input.every((item) => typeof item === "string");
99
99
  if (typeof row.preset !== "string" || !strings(row.providers) || !strings(row.tools) || typeof row.prompt !== "string" || typeof row.model !== "string") throw new Error("Invalid preview request");
100
- const record2 = (value2) => value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
100
+ const record3 = (value2) => value2 !== null && typeof value2 === "object" && !Array.isArray(value2);
101
101
  if (row.persona !== void 0 && typeof row.persona !== "string") throw new Error("Invalid persona");
102
- if (row.sections !== void 0 && (!record2(row.sections) || Object.values(row.sections).some((v) => typeof v !== "string"))) throw new Error("Invalid section overrides");
103
- if (row.toolOverrides !== void 0 && (!record2(row.toolOverrides) || Object.values(row.toolOverrides).some((v) => !record2(v) || Object.keys(v).some((k) => !["description", "parameters"].includes(k)) || v.description !== void 0 && typeof v.description !== "string" || v.parameters !== void 0 && (!record2(v.parameters) || Object.values(v.parameters).some((p) => typeof p !== "string"))))) throw new Error("Invalid tool overrides");
104
- if (row.providerConfigs !== void 0 && (!record2(row.providerConfigs) || Object.values(row.providerConfigs).some((v) => !record2(v)))) throw new Error("Invalid provider configs");
102
+ if (row.sections !== void 0 && (!record3(row.sections) || Object.values(row.sections).some((v) => typeof v !== "string"))) throw new Error("Invalid section overrides");
103
+ if (row.toolOverrides !== void 0 && (!record3(row.toolOverrides) || Object.values(row.toolOverrides).some((v) => !record3(v) || Object.keys(v).some((k) => !["description", "parameters"].includes(k)) || v.description !== void 0 && typeof v.description !== "string" || v.parameters !== void 0 && (!record3(v.parameters) || Object.values(v.parameters).some((p) => typeof p !== "string"))))) throw new Error("Invalid tool overrides");
104
+ if (row.providerConfigs !== void 0 && (!record3(row.providerConfigs) || Object.values(row.providerConfigs).some((v) => !record3(v)))) throw new Error("Invalid provider configs");
105
105
  if (row.configOverrides !== void 0) validateConfigOverrides(row.configOverrides);
106
106
  if (row.execution !== void 0) validateExecutionDefaults(row.execution);
107
107
  if (row.configExclusions !== void 0 && (!strings(row.configExclusions) || row.configExclusions.some((id) => !id))) throw new Error("Invalid Config exclusions");
108
108
  const filter = row.subagentToolFilter;
109
- if (filter !== void 0 && (!record2(filter) || !strings(filter.deny) || filter.deny.some((name) => !name))) throw new Error("Invalid subagent tool filter");
109
+ if (filter !== void 0 && (!record3(filter) || !strings(filter.deny) || filter.deny.some((name) => !name))) throw new Error("Invalid subagent tool filter");
110
110
  return {
111
111
  ...row.configOverrides !== void 0 ? { configOverrides: row.configOverrides } : {},
112
112
  ...row.execution !== void 0 ? { execution: row.execution } : {},
@@ -706,6 +706,7 @@ ${adapter}.studio-ui *, .studio-ui *::before, .studio-ui *::after { box-sizing:
706
706
  .studio-ui .studio-pixie-turn { display: grid; gap: 4px; margin: 0; padding-bottom: 10px; border-bottom: .5px solid var(--studio-line); }
707
707
  .studio-ui .studio-pixie-question { justify-self: end; max-width: 85%; margin: 0; padding: 4px 10px; border-radius: var(--studio-control-radius); background: var(--studio-hover); white-space: pre-wrap; }
708
708
  .studio-ui .studio-pixie-answer { margin: 0; white-space: pre-wrap; }
709
+ .studio-ui .studio-markdown { white-space: normal; min-width: 0; overflow-wrap: anywhere; }
709
710
  .studio-ui .studio-pixie-turn-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; }
710
711
  .studio-ui .studio-pixie-turn-meta:empty { display: none; }
711
712
  .studio-ui .studio-pixie-detail > p { margin: 0; }
@@ -785,6 +786,13 @@ ${adapter}.studio-ui *, .studio-ui *::before, .studio-ui *::after { box-sizing:
785
786
  .studio-ui .studio-gate-facts dt { color: var(--studio-muted); font-size: 12px; }
786
787
  .studio-ui .studio-gate-facts dd { margin: 0; min-width: 0; overflow-wrap: anywhere; }
787
788
  .studio-ui .studio-gate-block { display: grid; gap: 6px; padding-top: 10px; border-top: .5px solid var(--studio-line); }
789
+ .studio-ui .studio-gate-session-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 6px; }
790
+ .studio-ui .studio-gate-session-row { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-width: 0; }
791
+ .studio-ui .studio-gate-session-name { display: grid; gap: 2px; min-width: 0; overflow-wrap: anywhere; }
792
+ .studio-ui.studio-gate-tail { margin: 6px 0 2px; }
793
+ .studio-ui .studio-gate-tail-body { display: grid; gap: 6px; padding: 10px 12px; border: .5px solid var(--studio-line); border-radius: 8px; }
794
+ .studio-ui .studio-gate-tail-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 8px; min-width: 0; }
795
+ .studio-ui .studio-gate-tail-head .studio-inline-actions { margin-left: auto; }
788
796
  .studio-ui .studio-gate-block > .studio-section-head, .studio-ui .studio-gate-block h3 { margin: 0; }
789
797
  .studio-ui .studio-gate-text { max-height: 168px; overflow: auto; padding: 8px 10px; border-radius: var(--studio-small-radius); background: var(--studio-hover); font-size: 12px; overflow-wrap: anywhere; }
790
798
  .studio-ui .studio-gate-compact { display: grid; gap: 10px; }
@@ -893,6 +901,16 @@ function TabBar({ label, items, value, onChange, trailing }) {
893
901
  function TabPanel({ children }) {
894
902
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { role: "tabpanel", className: "studio-tab-panel", children });
895
903
  }
904
+ var markdownContext;
905
+ var markdown = () => markdownContext ??= import_react.default.createContext(void 0);
906
+ function MarkdownProvider({ value, children }) {
907
+ const Context = markdown();
908
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Context.Provider, { value, children });
909
+ }
910
+ function ModelText({ text, locale, streaming = false }) {
911
+ const Render = import_react.default.useContext(markdown());
912
+ return Render ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "studio-pixie-answer studio-markdown", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Render, { text, streaming, locale }) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", { className: "studio-pixie-answer", children: text });
913
+ }
896
914
  function Badge({ tone = "neutral", children }) {
897
915
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: "studio-badge", "data-tone": tone, children });
898
916
  }
@@ -1245,7 +1263,8 @@ var PACKAGE_NAME = "@matamt-dbg/dsh-studio";
1245
1263
  var POLICY_PLUGIN = `${PACKAGE_NAME}/policy`;
1246
1264
  var ROLE_PLUGIN = `${PACKAGE_NAME}/roles`;
1247
1265
  var BATCH_PLUGIN = `${PACKAGE_NAME}/batch`;
1248
- var STUDIO_VERSION = "0.3.0";
1266
+ var JUDGE_PLUGIN = `${PACKAGE_NAME}/judge`;
1267
+ var STUDIO_VERSION = "0.5.0";
1249
1268
 
1250
1269
  // src/delegation.ts
1251
1270
  var ROLE_TOOL = "subagent_role";
@@ -2104,7 +2123,7 @@ function PresetList({ locale, api, revision, onEdit, onCopy, changes }) {
2104
2123
  item.template && !item.readOnly && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Badge, { tone: "info", children: t("\uAE30\uBCF8 \uC81C\uACF5", "Built-in", "\u5185\u7F6E") }),
2105
2124
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Badge, { tone: tone[item.status], children: status(item) })
2106
2125
  ] }),
2107
- item.template ? /* @__PURE__ */ (0, import_jsx_runtime7.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_runtime7.jsx)("p", { className: "studio-card-text", children: item.description }),
2126
+ item.template ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "studio-card-text", children: t("\uCF54\uB529 \uC5D0\uC774\uC804\uD2B8\uB97C \uC704\uD55C \uCD5C\uC18C\uD55C\uC758 \uB3C4\uAD6C\uB9CC \uBAA8\uC544\uB193\uC740 \uD504\uB9AC\uC14B\uC785\uB2C8\uB2E4.", "A preset with only the minimum tools a coding agent needs.", "\u4EC5\u5305\u542B\u7F16\u7801\u4EE3\u7406\u6240\u9700\u6700\u5C11\u5DE5\u5177\u7684\u9884\u8BBE") }) : item.description && !item.readOnly && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "studio-card-text", children: item.description }),
2108
2127
  item.missingFeatures && item.missingFeatures.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "studio-inline-actions", children: [
2109
2128
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Badge, { tone: "warning", children: t("\uAE30\uB2A5 \uB204\uB77D", "Missing features", "\u7F3A\u5C11\u529F\u80FD") }),
2110
2129
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "studio-card-meta", children: item.missingFeatures.map((name) => featureLabel(name, locale)).join(", ") }),
@@ -2119,7 +2138,7 @@ function PresetList({ locale, api, revision, onEdit, onCopy, changes }) {
2119
2138
  " ",
2120
2139
  Array.isArray(item.agents) ? item.agents.length : 0
2121
2140
  ] }),
2122
- item.readOnly ? /* @__PURE__ */ (0, import_jsx_runtime7.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_runtime7.jsxs)("div", { className: "studio-card-footer", children: [
2141
+ item.readOnly ? /* @__PURE__ */ (0, import_jsx_runtime7.jsx)("p", { className: "studio-card-meta studio-card-note", children: t("DSH standard \uD504\uB9AC\uC14B\uC5D0 Studio \uD50C\uB7EC\uADF8\uC778\uACFC \uC9C1\uC811 \uCD94\uAC00\uD55C \uD50C\uB7EC\uADF8\uC778\uC744 \uB354\uD55C \uAE30\uC900 \uD504\uB9AC\uC14B\uC785\uB2C8\uB2E4. \uD3B8\uC9D1\uD558\uAC70\uB098 \uC0AD\uC81C\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.", "Reference preset: DSH standard plus Studio plugins and the ones you added. It cannot be edited or deleted.", "\u57FA\u51C6\u9884\u8BBE\uFF1ADSH standard \u52A0\u4E0A Studio \u63D2\u4EF6\u548C\u60A8\u6DFB\u52A0\u7684\u63D2\u4EF6\uFF0C\u65E0\u6CD5\u7F16\u8F91\u6216\u5220\u9664") }) : /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "studio-card-footer", children: [
2123
2142
  /* @__PURE__ */ (0, import_jsx_runtime7.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") }),
2124
2143
  /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Button, { small: true, disabled: busy || !onCopy, onClick: () => onCopy?.(item), children: t("\uBCF5\uC0AC", "Create copy", "\u521B\u5EFA\u526F\u672C") }),
2125
2144
  /* @__PURE__ */ (0, import_jsx_runtime7.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: () => {
@@ -2737,6 +2756,7 @@ function OptimizationPrototype({ locale, catalog, catalogError, onPreview, prese
2737
2756
  setConfigDraft(next.overrides);
2738
2757
  setConfigExclusions(next.excluded);
2739
2758
  } }),
2759
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SectionHead, { title: t("Config \uB36E\uC5B4\uC4F0\uAE30", "Config overrides", "Config \u8986\u76D6"), description: t("\uD3EC\uD568\uB41C \uD50C\uB7EC\uADF8\uC778\uC758 \uC124\uC815\uAC12\uC744 \uC774 \uD504\uB9AC\uC14B\uC5D0\uC11C\uB9CC \uBC14\uAFC9\uB2C8\uB2E4. \uD56D\uBAA9\uC744 \uCF1C\uACE0 \uC124\uC815\uC5D0\uC11C \uBC14\uAFBC \uD544\uB4DC\uB9CC \uC800\uC7A5\uB418\uBA70, \uB044\uBA74 \uAE30\uBCF8\uAC12\uC73C\uB85C \uB3CC\uC544\uAC11\uB2C8\uB2E4.", "Change settings of included plugins for this preset only. Check an entry and edit it; only changed fields are saved, and unchecking returns to the defaults.", "\u4EC5\u4E3A\u6B64\u9884\u8BBE\u4FEE\u6539\u5DF2\u5305\u542B\u63D2\u4EF6\u7684\u8BBE\u7F6E\u3002\u542F\u7528\u6761\u76EE\u5E76\u7F16\u8F91\uFF0C\u53EA\u4FDD\u5B58\u4FEE\u6539\u7684\u5B57\u6BB5\uFF1B\u5173\u95ED\u5373\u6062\u590D\u9ED8\u8BA4\u503C") }),
2740
2760
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(ConfigEditor, { locale, entries: (catalog?.plugins ?? []).filter((entry) => !configExclusions.includes(entry.id)), value: configOverrides, onChange: setConfigDraft })
2741
2761
  ] }) },
2742
2762
  { id: "agents", label: t("\uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8", "Subagent settings", "\u5B50\u4EE3\u7406\u8BBE\u7F6E"), content: agentPage }
@@ -2783,7 +2803,7 @@ function OptimizationPrototype({ locale, catalog, catalogError, onPreview, prese
2783
2803
  }
2784
2804
 
2785
2805
  // src/shell.tsx
2786
- var import_react18 = __toESM(require("react"), 1);
2806
+ var import_react20 = __toESM(require("react"), 1);
2787
2807
  var import_dsh_client_ui_slots = require("@deepseek-ai/dsh-client-ui-slots");
2788
2808
 
2789
2809
  // src/service-layout.tsx
@@ -2965,7 +2985,7 @@ function SidebarIcon({ size = 20, store, locale }) {
2965
2985
  }
2966
2986
 
2967
2987
  // src/pixie-client.tsx
2968
- var import_react17 = __toESM(require("react"), 1);
2988
+ var import_react18 = __toESM(require("react"), 1);
2969
2989
 
2970
2990
  // src/pixie-tab.tsx
2971
2991
  var import_react14 = __toESM(require("react"), 1);
@@ -2975,6 +2995,23 @@ var import_react13 = __toESM(require("react"), 1);
2975
2995
 
2976
2996
  // src/pixie-gate-locale.ts
2977
2997
  var en3 = {
2998
+ sessionGates: "Gates in this session",
2999
+ sessionGatesHint: "Switch a gate off for this session only. The gate and other sessions stay unchanged.",
3000
+ sessionGatesEmpty: "No gate applies to this session's preset.",
3001
+ sessionGateOff: "Off in this session",
3002
+ sessionGateToggle: "Run {name} in this session",
3003
+ sessionGateFailed: "Could not change the gate for this session.",
3004
+ tailTitle: "Pixie \xB7 {name}",
3005
+ tailUnverified: "not verified",
3006
+ tailHide: "Hide",
3007
+ tailShow: "Show",
3008
+ tailOpen: "Open in Pixie tab",
3009
+ tailOff: "Turn off in this session",
3010
+ tailOffDone: "Off in this session. Turn it back on in the Pixie tab \u2192 Gates.",
3011
+ concludedBy: "Concluded by",
3012
+ concludedPixie: "Pixie",
3013
+ concludedScript: "Hook script",
3014
+ concludedSkipped: "Skipped by hook",
2978
3015
  gates: "Gates",
2979
3016
  emptyRuns: "No gate runs yet",
2980
3017
  applied: "Applied",
@@ -3025,6 +3062,9 @@ var en3 = {
3025
3062
  milliseconds: "{value} ms",
3026
3063
  seconds: "{value} s",
3027
3064
  output: "Pixie output",
3065
+ scriptOutput: "Script output",
3066
+ helperLabel: "{type} \u2192 {label} \xB7 {engine}",
3067
+ helperConfidence: "confidence {confidence}",
3028
3068
  notes: "Notes",
3029
3069
  helperCalls: "Helper calls",
3030
3070
  helperNoul: "Yes probability {noul} \xB7 threshold {threshold}",
@@ -3036,6 +3076,23 @@ var en3 = {
3036
3076
  stop: "Stopped"
3037
3077
  };
3038
3078
  var ko3 = {
3079
+ sessionGates: "\uC774 \uC138\uC158\uC758 \uAC8C\uC774\uD2B8",
3080
+ sessionGatesHint: "\uC774 \uC138\uC158\uC5D0\uC11C\uB9CC \uAC8C\uC774\uD2B8\uB97C \uB055\uB2C8\uB2E4. \uAC8C\uC774\uD2B8 \uC124\uC815\uACFC \uB2E4\uB978 \uC138\uC158\uC740 \uBC14\uB00C\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
3081
+ sessionGatesEmpty: "\uC774 \uC138\uC158 \uD504\uB9AC\uC14B\uC5D0 \uC801\uC6A9\uB418\uB294 \uAC8C\uC774\uD2B8\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.",
3082
+ sessionGateOff: "\uC774 \uC138\uC158\uC5D0\uC11C \uAEBC\uC9D0",
3083
+ sessionGateToggle: "\uC774 \uC138\uC158\uC5D0\uC11C {name} \uC2E4\uD589",
3084
+ sessionGateFailed: "\uC774 \uC138\uC158\uC758 \uAC8C\uC774\uD2B8\uB97C \uBC14\uAFB8\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
3085
+ tailTitle: "Pixie \xB7 {name}",
3086
+ tailUnverified: "\uD655\uC778 \uC548 \uB428",
3087
+ tailHide: "\uC811\uAE30",
3088
+ tailShow: "\uD3BC\uCE58\uAE30",
3089
+ tailOpen: "Pixie \uD0ED\uC5D0\uC11C \uBCF4\uAE30",
3090
+ tailOff: "\uC774 \uC138\uC158\uC5D0\uC11C \uB044\uAE30",
3091
+ tailOffDone: "\uC774 \uC138\uC158\uC5D0\uC11C \uAED0\uC2B5\uB2C8\uB2E4. Pixie \uD0ED \u2192 \uAC8C\uC774\uD2B8\uC5D0\uC11C \uB2E4\uC2DC \uCF24 \uC218 \uC788\uC2B5\uB2C8\uB2E4.",
3092
+ concludedBy: "\uACB0\uB860",
3093
+ concludedPixie: "Pixie",
3094
+ concludedScript: "\uD6C5 \uC2A4\uD06C\uB9BD\uD2B8",
3095
+ concludedSkipped: "\uD6C5\uC774 \uAC74\uB108\uB700",
3039
3096
  gates: "\uAC8C\uC774\uD2B8",
3040
3097
  emptyRuns: "\uAC8C\uC774\uD2B8 \uC2E4\uD589 \uAE30\uB85D\uC774 \uC5C6\uC2B5\uB2C8\uB2E4",
3041
3098
  applied: "\uC801\uC6A9",
@@ -3086,6 +3143,9 @@ var ko3 = {
3086
3143
  milliseconds: "{value} ms",
3087
3144
  seconds: "{value}\uCD08",
3088
3145
  output: "Pixie \uCD9C\uB825",
3146
+ scriptOutput: "\uC2A4\uD06C\uB9BD\uD2B8 \uCD9C\uB825",
3147
+ helperLabel: "{type} \u2192 {label} \xB7 {engine}",
3148
+ helperConfidence: "\uD655\uC2E0\uB3C4 {confidence}",
3089
3149
  notes: "\uBA54\uBAA8",
3090
3150
  helperCalls: "\uD5EC\uD37C \uD638\uCD9C",
3091
3151
  helperNoul: "\uC608 \uD655\uB960 {noul} \xB7 \uAE30\uC900 {threshold}",
@@ -3097,6 +3157,23 @@ var ko3 = {
3097
3157
  stop: "\uB9C9\uC74C"
3098
3158
  };
3099
3159
  var zh3 = {
3160
+ sessionGates: "\u672C\u4F1A\u8BDD\u7684\u95E8\u63A7",
3161
+ sessionGatesHint: "\u4EC5\u5728\u672C\u4F1A\u8BDD\u4E2D\u5173\u95ED\u95E8\u63A7\u3002\u95E8\u63A7\u8BBE\u7F6E\u548C\u5176\u4ED6\u4F1A\u8BDD\u4FDD\u6301\u4E0D\u53D8",
3162
+ sessionGatesEmpty: "\u6CA1\u6709\u9002\u7528\u4E8E\u672C\u4F1A\u8BDD\u9884\u8BBE\u7684\u95E8\u63A7",
3163
+ sessionGateOff: "\u672C\u4F1A\u8BDD\u5DF2\u5173\u95ED",
3164
+ sessionGateToggle: "\u5728\u672C\u4F1A\u8BDD\u4E2D\u8FD0\u884C {name}",
3165
+ sessionGateFailed: "\u65E0\u6CD5\u66F4\u6539\u672C\u4F1A\u8BDD\u7684\u95E8\u63A7",
3166
+ tailTitle: "Pixie \xB7 {name}",
3167
+ tailUnverified: "\u672A\u786E\u8BA4",
3168
+ tailHide: "\u6536\u8D77",
3169
+ tailShow: "\u5C55\u5F00",
3170
+ tailOpen: "\u5728 Pixie \u6807\u7B7E\u9875\u4E2D\u67E5\u770B",
3171
+ tailOff: "\u5728\u672C\u4F1A\u8BDD\u4E2D\u5173\u95ED",
3172
+ tailOffDone: "\u5DF2\u5728\u672C\u4F1A\u8BDD\u4E2D\u5173\u95ED\u3002\u53EF\u5728 Pixie \u6807\u7B7E\u9875 \u2192 \u95E8\u63A7\u4E2D\u91CD\u65B0\u5F00\u542F",
3173
+ concludedBy: "\u7ED3\u8BBA\u6765\u6E90",
3174
+ concludedPixie: "Pixie",
3175
+ concludedScript: "\u94A9\u5B50\u811A\u672C",
3176
+ concludedSkipped: "\u94A9\u5B50\u8DF3\u8FC7",
3100
3177
  gates: "\u95E8\u63A7",
3101
3178
  emptyRuns: "\u6682\u65E0\u95E8\u63A7\u8FD0\u884C\u8BB0\u5F55",
3102
3179
  applied: "\u5E94\u7528",
@@ -3147,6 +3224,9 @@ var zh3 = {
3147
3224
  milliseconds: "{value} ms",
3148
3225
  seconds: "{value} \u79D2",
3149
3226
  output: "Pixie \u8F93\u51FA",
3227
+ scriptOutput: "\u811A\u672C\u8F93\u51FA",
3228
+ helperLabel: "{type} \u2192 {label} \xB7 {engine}",
3229
+ helperConfidence: "\u7F6E\u4FE1\u5EA6 {confidence}",
3150
3230
  notes: "\u5907\u6CE8",
3151
3231
  helperCalls: "\u8F85\u52A9\u8C03\u7528",
3152
3232
  helperNoul: "\u201C\u662F\u201D\u7684\u6982\u7387 {noul} \xB7 \u9608\u503C {threshold}",
@@ -3231,8 +3311,39 @@ function judgeText(locale, key) {
3231
3311
  return messages[key][locale.startsWith("ko") ? 0 : locale.startsWith("zh") ? 2 : 1];
3232
3312
  }
3233
3313
 
3314
+ // src/pixie-contracts.ts
3315
+ function judgeQuestionText(question) {
3316
+ if (!question || typeof question !== "object") return void 0;
3317
+ const value = question;
3318
+ const text = typeof value.instructions === "string" ? value.instructions : value.question;
3319
+ return typeof text === "string" && text ? text : void 0;
3320
+ }
3321
+ function judgeCriterionText(question, key) {
3322
+ if (!question || typeof question !== "object") return void 0;
3323
+ const value = question;
3324
+ const source = value.criteria ?? (value.type === "choice" ? value.options : value.levels);
3325
+ const text = source && typeof source === "object" ? source[key] : void 0;
3326
+ return typeof text === "string" && text ? text : void 0;
3327
+ }
3328
+ var DEFAULT_JUDGE_SYSTEM_PROMPT = [
3329
+ "You are a judgment component. Evaluate the given state against each question independently.",
3330
+ 'Reply with exactly one JSON object and nothing else: {"answers": {<question id>: <answer>}}.',
3331
+ "Each question has instructions (what to decide) and criteria: choice criteria map option names to descriptions; score criteria list ordered level descriptions; noul criteria optionally describe what true and false mean.",
3332
+ 'choice answer: {"choice": <option name>, "probabilities": {<every option name>: number}} \u2014 probabilities sum to 1.',
3333
+ 'score answer: {"score": number from 0 to levels-1 (fractional allowed), "probabilities": [one number per level, in order]} \u2014 probabilities sum to 1.',
3334
+ 'noul answer: {"noul": probability from 0 to 1 that the answer is yes}.'
3335
+ ].join("\n");
3336
+
3234
3337
  // src/pixie-gate-result.tsx
3235
3338
  var import_jsx_runtime14 = require("react/jsx-runtime");
3339
+ function helperSummary(data, t) {
3340
+ if (!data || typeof data !== "object") return void 0;
3341
+ const value = data;
3342
+ if (typeof value.type !== "string" || typeof value.label !== "string") return void 0;
3343
+ const line = t("helperLabel").replace("{type}", value.type).replace("{label}", value.label).replace("{engine}", typeof value.engine === "string" ? value.engine : "?");
3344
+ const confidence = value.answer?.confidence;
3345
+ return typeof confidence === "number" ? `${line} \xB7 ${t("helperConfidence").replace("{confidence}", `${Math.round(confidence * 100)}%`)}` : line;
3346
+ }
3236
3347
  function wasSkipped(result) {
3237
3348
  return !!result.data && typeof result.data === "object" && "skipped" in result.data && result.data.skipped === true;
3238
3349
  }
@@ -3246,15 +3357,15 @@ function GateResultDetails({ result, locale, durations = {}, skipped = [], compa
3246
3357
  const failures = value.data && typeof value.data === "object" && "failedConditions" in value.data && Array.isArray(value.data.failedConditions) ? value.data.failedConditions : [];
3247
3358
  const reason = failures.length ? failures.map((condition) => {
3248
3359
  const q = questions[condition.question];
3249
- const question = q?.type === "noul" ? q.question || condition.question : condition.question;
3250
- const actual = condition.type === "choice" && q?.type === "choice" ? q.options[condition.actual] ?? condition.actual : condition.type === "score" && q?.type === "score" ? q.levels[condition.actual] ?? condition.actual : condition.actual;
3360
+ const question = condition.type === "noul" ? judgeQuestionText(q) ?? condition.question : condition.question;
3361
+ const actual = condition.type === "noul" ? condition.actual : judgeCriterionText(q, condition.actual) ?? condition.actual;
3251
3362
  const text = judgeText(locale, condition.type === "noul" ? "failedNoul" : condition.type === "score" ? "failedScore" : "failedChoice");
3252
- const values = { question, actual, threshold: condition.type === "noul" ? condition.threshold : "", min: condition.type === "score" ? q?.type === "score" ? q.levels[condition.min] ?? condition.min : condition.min : "" };
3363
+ const values = { question, actual, threshold: condition.type === "noul" ? condition.threshold : "", min: condition.type === "score" ? judgeCriterionText(q, condition.min) ?? condition.min : "" };
3253
3364
  return text.replace(/\{(question|actual|threshold|min)\}/g, (_, key) => String(values[key]));
3254
3365
  }).join("; ") : value.reason;
3255
3366
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("section", { className: "studio-pixie-turn", "data-gate-stage": id, children: [
3256
3367
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SectionHead, { title: label, actions: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Badge, { tone: !omitted && (value.verdict === "error" || value.verdict === "fail") ? "warning" : "neutral", children: t(omitted ? "skipped" : value.verdict) }) }),
3257
- value.text !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "studio-pixie-answer", children: value.text }),
3368
+ value.text !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ModelText, { text: value.text, locale }),
3258
3369
  (reason || omitted) && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("p", { className: "studio-pixie-answer", children: [
3259
3370
  t("reason"),
3260
3371
  ": ",
@@ -3267,10 +3378,10 @@ function GateResultDetails({ result, locale, durations = {}, skipped = [], compa
3267
3378
  if (!answer || !["choice", "score", "noul"].includes(answer.type)) return null;
3268
3379
  const percent = (number) => `${Math.round(number * 100)}%`;
3269
3380
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("p", { className: "studio-pixie-answer", children: [
3270
- q?.type === "noul" ? q.question || questionId : questionId,
3381
+ answer.type === "noul" ? judgeQuestionText(q) ?? questionId : questionId,
3271
3382
  ": ",
3272
3383
  answer.type === "noul" ? answer.noul : answer.type === "choice" ? /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3273
- q?.type === "choice" ? q.options[answer.choice] || answer.choice : answer.choice,
3384
+ judgeCriterionText(q, answer.choice) ?? answer.choice,
3274
3385
  " \xB7 ",
3275
3386
  judgeText(locale, "probability"),
3276
3387
  ": ",
@@ -3280,7 +3391,7 @@ function GateResultDetails({ result, locale, durations = {}, skipped = [], compa
3280
3391
  ": ",
3281
3392
  percent(answer.confidence)
3282
3393
  ] }) : /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(import_jsx_runtime14.Fragment, { children: [
3283
- q?.type === "score" ? q.levels[answer.score] || answer.score : answer.score,
3394
+ judgeCriterionText(q, answer.score) ?? answer.score,
3284
3395
  " \xB7 ",
3285
3396
  judgeText(locale, "confidence"),
3286
3397
  ": ",
@@ -3289,6 +3400,7 @@ function GateResultDetails({ result, locale, durations = {}, skipped = [], compa
3289
3400
  ] }, questionId);
3290
3401
  })
3291
3402
  ] }),
3403
+ helperSummary(value.data, t) && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "studio-card-meta", children: helperSummary(value.data, t) }),
3292
3404
  !!value.data && typeof value.data === "object" && "noul" in value.data && "threshold" in value.data && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "studio-card-meta", children: t("helperNoul").replace("{noul}", String(value.data.noul)).replace("{threshold}", String(value.data.threshold)) }),
3293
3405
  value.error && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Notice, { children: [
3294
3406
  t("error"),
@@ -3321,11 +3433,11 @@ function GateResultDetails({ result, locale, durations = {}, skipped = [], compa
3321
3433
  ] }),
3322
3434
  result.notes.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("section", { className: "studio-gate-block", "aria-label": t("notes"), children: [
3323
3435
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SectionHead, { title: t("notes") }),
3324
- result.notes.map((note, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "studio-pixie-answer", children: note }, index))
3436
+ result.notes.map((note, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ModelText, { text: note, locale }, index))
3325
3437
  ] }),
3326
3438
  result.records.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("section", { className: "studio-gate-block", "aria-label": t("helperCalls"), children: [
3327
3439
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SectionHead, { title: t("helperCalls") }),
3328
- result.records.map((record2) => stage(record2.id, record2.result))
3440
+ result.records.map((record3) => stage(record3.id, record3.result))
3329
3441
  ] }),
3330
3442
  result.forwardError?.verdict === "error" && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(Notice, { children: [
3331
3443
  t("error"),
@@ -3353,11 +3465,11 @@ function GateResultDetails({ result, locale, durations = {}, skipped = [], compa
3353
3465
  skipped.filter((id) => !id.startsWith("hooks.") && !result.stages[id]).map((id) => stage(id, { verdict: "pass" })),
3354
3466
  result.notes.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("section", { "aria-label": t("notes"), children: [
3355
3467
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SectionHead, { title: t("notes") }),
3356
- result.notes.map((note, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "studio-pixie-answer", children: note }, index))
3468
+ result.notes.map((note, index) => /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(ModelText, { text: note, locale }, index))
3357
3469
  ] }),
3358
3470
  result.records.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)("section", { "aria-label": t("helperCalls"), children: [
3359
3471
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SectionHead, { title: t("helperCalls") }),
3360
- result.records.map((record2) => stage(record2.id, record2.result))
3472
+ result.records.map((record3) => stage(record3.id, record3.result))
3361
3473
  ] }),
3362
3474
  /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(SectionHead, { title: t("forward"), actions: /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(Badge, { children: t(result.forward.kind) }) }),
3363
3475
  result.forward.kind !== "none" && /* @__PURE__ */ (0, import_jsx_runtime14.jsx)("p", { className: "studio-pixie-answer", children: result.forward.text }),
@@ -3370,8 +3482,225 @@ function GateResultDetails({ result, locale, durations = {}, skipped = [], compa
3370
3482
  ] });
3371
3483
  }
3372
3484
 
3485
+ // src/pixie-gate-task-locale.ts
3486
+ var messages2 = {
3487
+ composition: ["\uAC8C\uC774\uD2B8 \uAD6C\uC131", "Gate composition", "\u95E8\u63A7\u6784\u6210"],
3488
+ scope: ["\uC801\uC6A9 \uBC94\uC704", "Scope", "\u9002\u7528\u8303\u56F4"],
3489
+ scopeDescription: ["\uAC8C\uC774\uD2B8\uB97C \uCF1C\uACE0, \uC5B4\uB5A4 \uD504\uB9AC\uC14B\uC5D0 \uC801\uC6A9\uD560\uC9C0 \uC815\uD569\uB2C8\uB2E4.", "Turn gates on and choose the presets they apply to.", "\u542F\u7528\u95E8\u63A7\u5E76\u9009\u62E9\u9002\u7528\u7684\u9884\u8BBE\u3002"],
3490
+ loading: ["\uAC8C\uC774\uD2B8\uB97C \uBD88\uB7EC\uC624\uB294 \uC911\u2026", "Loading gates\u2026", "\u6B63\u5728\u52A0\u8F7D\u95E8\u63A7\u2026"],
3491
+ retry: ["\uB2E4\uC2DC \uC2DC\uB3C4", "Retry", "\u91CD\u8BD5"],
3492
+ save: ["\uC800\uC7A5", "Save", "\u4FDD\u5B58"],
3493
+ saving: ["\uC800\uC7A5 \uC911\u2026", "Saving\u2026", "\u6B63\u5728\u4FDD\u5B58\u2026"],
3494
+ saved: ["\uC800\uC7A5\uB428", "Saved", "\u5DF2\u4FDD\u5B58"],
3495
+ saveFailed: ["\uC800\uC7A5\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4", "Could not save", "\u65E0\u6CD5\u4FDD\u5B58"],
3496
+ dismiss: ["\uB2EB\uAE30", "Dismiss", "\u5173\u95ED"],
3497
+ unsaved: ["\uC800\uC7A5\uD558\uC9C0 \uC54A\uC740 \uBCC0\uACBD\uC774 \uC788\uC2B5\uB2C8\uB2E4. \uC800\uC7A5\uD574\uC57C \uC2E4\uD589\uC5D0 \uC801\uC6A9\uB429\uB2C8\uB2E4.", "Unsaved changes. Save to apply them to runs.", "\u6709\u672A\u4FDD\u5B58\u7684\u66F4\u6539\u3002\u4FDD\u5B58\u540E\u624D\u4F1A\u5E94\u7528\u4E8E\u8FD0\u884C\u3002"],
3498
+ invalid: ["\uC77D\uC744 \uC218 \uC5C6\uB294 \uAC8C\uC774\uD2B8 {count}\uAC1C\uB294 \uD30C\uC77C\uC5D0 \uADF8\uB300\uB85C \uB450\uC5C8\uC2B5\uB2C8\uB2E4. \uC800\uC7A5\uD558\uBA74 \uC774 \uD56D\uBAA9\uC740 \uBE60\uC9D1\uB2C8\uB2E4: {reasons}", "{count} unreadable gates were left in the file. Saving drops them: {reasons}", "\u6709 {count} \u4E2A\u65E0\u6CD5\u8BFB\u53D6\u7684\u95E8\u63A7\u4FDD\u7559\u5728\u6587\u4EF6\u4E2D\u3002\u4FDD\u5B58\u540E\u5C06\u79FB\u9664\uFF1A{reasons}"],
3499
+ newGate: ["\uC0C8 \uAC8C\uC774\uD2B8", "New gate", "\u65B0\u5EFA\u95E8\u63A7"],
3500
+ empty: ["\uC544\uC9C1 \uAC8C\uC774\uD2B8\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uD15C\uD50C\uB9BF\uC5D0\uC11C \uC2DC\uC791\uD574 \uBCF4\uC138\uC694.", "No gates yet. Start from a template.", "\u5C1A\u65E0\u95E8\u63A7\u3002\u8BF7\u4ECE\u6A21\u677F\u5F00\u59CB\u3002"],
3501
+ pickTemplate: ["\uBB34\uC5C7\uC744 \uD558\uACE0 \uC2F6\uB098\uC694?", "What should the gate do?", "\u4F60\u60F3\u8BA9\u95E8\u63A7\u505A\u4EC0\u4E48\uFF1F"],
3502
+ pickHint: ["\uD15C\uD50C\uB9BF\uC744 \uACE8\uB77C \uBB38\uAD6C\uB97C \uC218\uC815\uD569\uB2C8\uB2E4.", "Pick a template, then adjust the wording.", "\u9009\u62E9\u6A21\u677F\u540E\u4FEE\u6539\u6587\u5B57\u5373\u53EF\u3002"],
3503
+ blank: ["\uBE48 \uAC8C\uC774\uD2B8", "Blank gate", "\u7A7A\u767D\u95E8\u63A7"],
3504
+ blankDescription: ["\uC5B8\uC81C \uC2E4\uD589\uD560\uC9C0\uC640 \uD560 \uC77C\uC744 \uC9C1\uC811 \uC815\uD569\uB2C8\uB2E4.", "Write when and what yourself.", "\u81EA\u884C\u586B\u5199\u65F6\u673A\u548C\u4EFB\u52A1\u3002"],
3505
+ edit: ["\uD3B8\uC9D1", "Edit", "\u7F16\u8F91"],
3506
+ duplicate: ["\uBCF5\uC81C", "Duplicate", "\u590D\u5236"],
3507
+ delete: ["\uC0AD\uC81C", "Delete", "\u5220\u9664"],
3508
+ close: ["\uB2EB\uAE30", "Close", "\u5173\u95ED"],
3509
+ cancel: ["\uCDE8\uC18C", "Cancel", "\u53D6\u6D88"],
3510
+ back: ["\uB4A4\uB85C", "Back", "\u8FD4\u56DE"],
3511
+ apply: ["\uC801\uC6A9", "Apply", "\u5E94\u7528"],
3512
+ applyHint: ["\uC801\uC6A9 \uD6C4 \uD398\uC774\uC9C0\uC5D0\uC11C \uC800\uC7A5\uD574\uC57C \uC2E4\uD589\uC5D0 \uBC18\uC601\uB429\uB2C8\uB2E4.", "After applying, press Save on the page to use it in runs.", "\u5E94\u7528\u540E\u9700\u5728\u9875\u9762\u4E0A\u70B9\u51FB\u4FDD\u5B58\u624D\u4F1A\u7528\u4E8E\u8FD0\u884C\u3002"],
3513
+ on: ["\uCF1C\uC9D0", "On", "\u5F00\u542F"],
3514
+ off: ["\uAEBC\uC9D0", "Off", "\u5173\u95ED"],
3515
+ presetCount: ["\uD504\uB9AC\uC14B {count}\uAC1C", "{count} presets", "{count} \u4E2A\u9884\u8BBE"],
3516
+ noPreset: ["\uD504\uB9AC\uC14B \uC5C6\uC74C", "No preset", "\u65E0\u9884\u8BBE"],
3517
+ sentence: ["{when} \u2192 {what}", "{when} \u2192 {what}", "{when} \u2192 {what}"],
3518
+ name: ["\uC774\uB984", "Name", "\u540D\u79F0"],
3519
+ when: ["\uC5B8\uC81C", "When", "\u4F55\u65F6"],
3520
+ what: ["Pixie\uC5D0\uAC8C \uBCF4\uB0BC \uB0B4\uC6A9", "What to send Pixie", "\u53D1\u9001\u7ED9 Pixie \u7684\u5185\u5BB9"],
3521
+ whatHint: ["Pixie\uAC00 \uC774 \uB0B4\uC6A9\uC744 \uBCF4\uACE0 \uAC8C\uC774\uD2B8 \uACB0\uACFC\uB97C \uC815\uD569\uB2C8\uB2E4. \uACB0\uACFC \uC885\uB958\uB294 \uAC00\uC774\uB4DC\uB97C \uCC38\uACE0\uD558\uC138\uC694.", "Pixie checks the content and decides the gate result. See the guide for details on results.", "Pixie \u68C0\u67E5\u5185\u5BB9\u5E76\u51B3\u5B9A\u95E8\u63A7\u7ED3\u679C\u3002\u7ED3\u679C\u8BE6\u60C5\u8BF7\u53C2\u9605\u6307\u5357\u3002"],
3522
+ "out-verdict": ["\uACB0\uB860", "Verdict", "\u7ED3\u8BBA"],
3523
+ "out-reason": ["\uC774\uC720", "Reason", "\u539F\u56E0"],
3524
+ "out-replace": ["\uBC14\uAFC0 \uB0B4\uC6A9", "Replacement", "\u66FF\u6362\u5185\u5BB9"],
3525
+ "out-append": ["\uB367\uBD99\uC77C \uB0B4\uC6A9", "Addition", "\u8FFD\u52A0\u5185\u5BB9"],
3526
+ "out-note": ["\uBA54\uBAA8", "Note", "\u5907\u6CE8"],
3527
+ // when options
3528
+ "when-user-message": ["\uC0AC\uC6A9\uC790\uAC00 \uC9C0\uC2DC\uB97C \uBCF4\uB0BC \uB54C", "When you send an instruction", "\u5F53\u4F60\u53D1\u9001\u6307\u4EE4\u65F6"],
3529
+ "when-agent-message": ["\uC5D0\uC774\uC804\uD2B8\uB07C\uB9AC \uBA54\uC2DC\uC9C0\uB97C \uC8FC\uACE0\uBC1B\uC744 \uB54C", "When agents message each other", "\u5F53\u4EE3\u7406\u4E4B\u95F4\u4E92\u53D1\u6D88\u606F\u65F6"],
3530
+ "when-tool-before": ["\uB3C4\uAD6C\uB97C \uC2E4\uD589\uD558\uAE30 \uC804", "Before a tool runs", "\u5DE5\u5177\u8FD0\u884C\u524D"],
3531
+ "when-tool-after": ["\uB3C4\uAD6C \uACB0\uACFC\uAC00 \uB098\uC654\uC744 \uB54C", "When a tool result arrives", "\u5DE5\u5177\u7ED3\u679C\u8FD4\u56DE\u65F6"],
3532
+ "when-turn-end": ["\uC5D0\uC774\uC804\uD2B8 \uB2F5\uBCC0\uC774 \uB05D\uB0AC\uC744 \uB54C", "When the agent finishes its answer", "\u4EE3\u7406\u5B8C\u6210\u56DE\u7B54\u65F6"],
3533
+ "target-user-message": ["\uBCF4\uB0B8 \uC9C0\uC2DC", "your instruction", "\u4F60\u53D1\u9001\u7684\u6307\u4EE4"],
3534
+ "target-agent-message": ["\uC8FC\uACE0\uBC1B\uB294 \uBA54\uC2DC\uC9C0", "the message between agents", "\u4EE3\u7406\u4E4B\u95F4\u7684\u6D88\u606F"],
3535
+ "target-tool-before": ["\uB3C4\uAD6C \uD638\uCD9C \uB0B4\uC6A9", "the tool call", "\u5DE5\u5177\u8C03\u7528\u5185\u5BB9"],
3536
+ "target-tool-after": ["\uB3C4\uAD6C \uACB0\uACFC", "the tool result", "\u5DE5\u5177\u7ED3\u679C"],
3537
+ "target-turn-end": ["\uB9C8\uC9C0\uB9C9 \uB2F5\uBCC0", "the final answer", "\u6700\u540E\u7684\u56DE\u7B54"],
3538
+ // advanced
3539
+ advanced: ["\uACE0\uAE09", "Advanced", "\u9AD8\u7EA7"],
3540
+ script: ["Pixie \uD6C5 \uC2A4\uD06C\uB9BD\uD2B8", "Pixie hook script", "Pixie \u94A9\u5B50\u811A\u672C"],
3541
+ scriptHint: ["Pixie \uAC8C\uC774\uD2B8 \uC9C4\uD589 \uC804\uC5D0 \uD638\uCD9C\uD560 \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uC120\uD0DD\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4. \uC2A4\uD06C\uB9BD\uD2B8 \uCD9C\uB825 \uACB0\uACFC\uC5D0 \uB530\uB77C Pixie \uAC8C\uC774\uD2B8\uB97C \uAC74\uB108\uB6F8 \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Choose a script to call before the Pixie gate runs. Depending on the script output, the Pixie gate can be skipped.", "\u53EF\u9009\u62E9\u5728 Pixie \u95E8\u63A7\u8FD0\u884C\u524D\u8C03\u7528\u7684\u811A\u672C\u3002\u6839\u636E\u811A\u672C\u8F93\u51FA\u7ED3\u679C\uFF0C\u53EF\u4EE5\u8DF3\u8FC7 Pixie \u95E8\u63A7\u3002"],
3542
+ guideLink: ["\uC2A4\uD06C\uB9BD\uD2B8 \uC791\uC131 \uAC00\uC774\uB4DC", "script guide", "\u811A\u672C\u7F16\u5199\u6307\u5357"],
3543
+ resultGuide: ["\uAC00\uC774\uB4DC", "Guide", "\u6307\u5357"],
3544
+ scriptEnv: ["DSH\uC5D0\uC11C bash \uD504\uB85C\uD544\uC744 \uC9C0\uC6D0\uD560 \uB54C\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Available only when DSH runs with a bash profile.", "\u4EC5\u5728 DSH \u652F\u6301 bash \u914D\u7F6E\u6587\u4EF6\u65F6\u53EF\u7528\u3002"],
3545
+ noScript: ["\uC0AC\uC6A9 \uC548 \uD568", "None", "\u4E0D\u4F7F\u7528"],
3546
+ scriptDir: ["\uC2A4\uD06C\uB9BD\uD2B8 \uD3F4\uB354", "Script folder", "\u811A\u672C\u6587\u4EF6\u5939"],
3547
+ copyPath: ["\uACBD\uB85C \uBCF5\uC0AC", "Copy path", "\u590D\u5236\u8DEF\u5F84"],
3548
+ refresh: ["\uBAA9\uB85D \uC0C8\uB85C\uACE0\uCE68", "Refresh list", "\u5237\u65B0\u5217\u8868"],
3549
+ openFolder: ["\uD3F4\uB354 \uC5F4\uAE30", "Open folder", "\u6253\u5F00\u6587\u4EF6\u5939"],
3550
+ openFailed: ["\uD3F4\uB354\uB97C \uC5F4\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4", "Could not open the folder", "\u65E0\u6CD5\u6253\u5F00\u6587\u4EF6\u5939"],
3551
+ presetsTitle: ["Studio \uD504\uB9AC\uC14B", "Studio presets", "Studio \u9884\u8BBE"],
3552
+ presetsTitleHint: ["Studio \uD504\uB9AC\uC14B\uB9C8\uB2E4 \uC801\uC6A9\uD560 \uAC8C\uC774\uD2B8\uB97C \uACE0\uB985\uB2C8\uB2E4. \uAC19\uC740 \uAC8C\uC774\uD2B8\uB97C \uC5EC\uB7EC \uD504\uB9AC\uC14B\uC5D0 \uC801\uC6A9\uD558\uACE0 \uAC01\uAC01 \uCF1C\uAC70\uB098 \uB04C \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Choose the gates for each preset made in Studio. A gate can be added to several presets, and each preset switches it on or off on its own.", "\u4E3A Studio \u521B\u5EFA\u7684\u6BCF\u4E2A\u9884\u8BBE\u9009\u62E9\u95E8\u63A7\u3002\u540C\u4E00\u95E8\u63A7\u53EF\u52A0\u5165\u591A\u4E2A\u9884\u8BBE\uFF0C\u5404\u9884\u8BBE\u5355\u72EC\u5F00\u5173\u3002"],
3553
+ noStudioPresets: ["Studio\uC5D0\uC11C \uB9CC\uB4E0 \uD504\uB9AC\uC14B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uD504\uB9AC\uC14B \uBA54\uB274\uC5D0\uC11C \uBA3C\uC800 \uB9CC\uB4DC\uC138\uC694.", "No presets made in Studio yet. Create one under Presets first.", "\u5C1A\u65E0 Studio \u521B\u5EFA\u7684\u9884\u8BBE\u3002\u8BF7\u5148\u5728\u9884\u8BBE\u83DC\u5355\u4E2D\u521B\u5EFA\u3002"],
3554
+ addGate: ["\uAC8C\uC774\uD2B8 \uCD94\uAC00", "Add gate", "\u6DFB\u52A0\u95E8\u63A7"],
3555
+ addGateTo: ["{preset}\uC5D0 \uAC8C\uC774\uD2B8 \uCD94\uAC00", "Add a gate to {preset}", "\u5411 {preset} \u6DFB\u52A0\u95E8\u63A7"],
3556
+ noGateToAdd: ["\uCD94\uAC00\uD560 \uAC8C\uC774\uD2B8\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uAC8C\uC774\uD2B8 \uAD6C\uC131\uC5D0\uC11C \uBA3C\uC800 \uB9CC\uB4DC\uC138\uC694.", "No gate to add. Create one in Gate composition first.", "\u6CA1\u6709\u53EF\u6DFB\u52A0\u7684\u95E8\u63A7\u3002\u8BF7\u5148\u5728\u95E8\u63A7\u6784\u6210\u4E2D\u521B\u5EFA\u3002"],
3557
+ noGatesInPreset: ["\uC774 \uD504\uB9AC\uC14B\uC5D0 \uAC74 \uAC8C\uC774\uD2B8\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.", "No gates on this preset.", "\u6B64\u9884\u8BBE\u6CA1\u6709\u95E8\u63A7\u3002"],
3558
+ removeFromPreset: ["\uD504\uB9AC\uC14B\uC5D0\uC11C \uBE7C\uAE30", "Remove from preset", "\u4ECE\u9884\u8BBE\u79FB\u9664"],
3559
+ gateOff: ["\uC804\uCCB4 \uAEBC\uC9D0 \xB7 \uAC8C\uC774\uD2B8 \uAD6C\uC131\uC5D0\uC11C \uCF1C\uAE30", "The gate is off everywhere (turn it on in Gate composition)", "\u8BE5\u95E8\u63A7\u5DF2\u5168\u5C40\u5173\u95ED\uFF08\u5728\u95E8\u63A7\u6784\u6210\u4E2D\u5F00\u542F\uFF09"],
3560
+ gateEnabled: ["\uAC8C\uC774\uD2B8 \uCF1C\uC9D0", "Gate on", "\u95E8\u63A7\u5F00\u542F"],
3561
+ gateEnabledHint: ["\uB044\uBA74 \uBAA8\uB4E0 \uD504\uB9AC\uC14B\uC5D0\uC11C \uBA48\uCDA5\uB2C8\uB2E4. \uC801\uC6A9 \uBC94\uC704\uC5D0\uC11C \uD504\uB9AC\uC14B\uBCC4\uB85C \uCF1C\uAC70\uB098 \uB055\uB2C8\uB2E4.", "Off stops it on every preset. Switch it per preset under Scope.", "\u5173\u95ED\u540E\u5728\u6240\u6709\u9884\u8BBE\u4E0A\u505C\u6B62\u3002\u6309\u9884\u8BBE\u5F00\u5173\u8BF7\u5728\u9002\u7528\u8303\u56F4\u4E2D\u8BBE\u7F6E\u3002"],
3562
+ folderTitle: ["\uC2A4\uD06C\uB9BD\uD2B8 \uD3F4\uB354", "Script folder", "\u811A\u672C\u6587\u4EF6\u5939"],
3563
+ folderHint: ["\uD6C5 \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uCC3E\uB294 \uD3F4\uB354\uC785\uB2C8\uB2E4. \uC808\uB300 \uACBD\uB85C\uB098 ~/ \uACBD\uB85C\uB97C \uC4F0\uACE0, \uBE44\uC6B0\uBA74 \uAE30\uBCF8 \uD3F4\uB354\uB97C \uC501\uB2C8\uB2E4.", "The folder hook scripts are found in. Use an absolute or ~/ path; leave empty for the default.", "\u67E5\u627E\u94A9\u5B50\u811A\u672C\u7684\u6587\u4EF6\u5939\u3002\u8BF7\u4F7F\u7528\u7EDD\u5BF9\u8DEF\u5F84\u6216 ~/ \u8DEF\u5F84\uFF0C\u7559\u7A7A\u5219\u4F7F\u7528\u9ED8\u8BA4\u6587\u4EF6\u5939\u3002"],
3564
+ folderDefault: ["\uAE30\uBCF8 \uD3F4\uB354", "Default folder", "\u9ED8\u8BA4\u6587\u4EF6\u5939"],
3565
+ folderCurrent: ["\uD604\uC7AC \uD3F4\uB354", "Current folder", "\u5F53\u524D\u6587\u4EF6\u5939"],
3566
+ folderCount: ["\uC2A4\uD06C\uB9BD\uD2B8 {count}\uAC1C", "{count} scripts", "{count} \u4E2A\u811A\u672C"],
3567
+ folderApply: ["\uD3F4\uB354 \uC801\uC6A9", "Use folder", "\u4F7F\u7528\u6587\u4EF6\u5939"],
3568
+ folderReset: ["\uAE30\uBCF8\uAC12\uC73C\uB85C", "Use default", "\u6062\u590D\u9ED8\u8BA4"],
3569
+ folderFailed: ["\uD3F4\uB354\uB97C \uBC14\uAFB8\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4", "Could not change the folder", "\u65E0\u6CD5\u66F4\u6539\u6587\u4EF6\u5939"],
3570
+ gateCount: ["\uAC8C\uC774\uD2B8 {count}\uAC1C \xB7 \uCF1C\uC9D0 {on}\uAC1C", "{count} gates \xB7 {on} on", "{count} \u4E2A\u95E8\u63A7 \xB7 \u542F\u7528 {on} \u4E2A"],
3571
+ unknownPreset: ["(\uC5C6\uB294 \uD504\uB9AC\uC14B)", "(missing preset)", "\uFF08\u9884\u8BBE\u4E0D\u5B58\u5728\uFF09"],
3572
+ conflict: ["\uAC19\uC740 \uC2DC\uC810\uC5D0 \uCF1C\uC9C4 \uAC8C\uC774\uD2B8\uAC00 \uB458 \uC774\uC0C1\uC785\uB2C8\uB2E4", "More than one enabled gate at this moment", "\u540C\u4E00\u65F6\u673A\u542F\u7528\u4E86\u591A\u4E2A\u95E8\u63A7"],
3573
+ editPresets: ["\uD504\uB9AC\uC14B", "Presets", "\u9884\u8BBE"],
3574
+ scriptMissing: ["(\uD3F4\uB354\uC5D0 \uC5C6\uC74C)", "(not in folder)", "\uFF08\u6587\u4EF6\u5939\u4E2D\u4E0D\u5B58\u5728\uFF09"],
3575
+ scriptUnsupported: ["\uC774 \uD658\uACBD\uC5D0\uC11C\uB294 \uD6C5 \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.", "Hook scripts are not supported in this environment.", "\u6B64\u73AF\u5883\u4E0D\u652F\u6301\u94A9\u5B50\u811A\u672C\u3002"],
3576
+ scriptsFailed: ["\uC2A4\uD06C\uB9BD\uD2B8 \uBAA9\uB85D\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4", "Could not list scripts", "\u65E0\u6CD5\u8BFB\u53D6\u811A\u672C\u5217\u8868"],
3577
+ scriptShell: ["\uC790\uC138\uD55C \uC2A4\uD06C\uB9BD\uD2B8 \uADDC\uCE59\uC740 {link}\uC5D0\uC11C \uBCFC \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "See the {link} for the full script rules.", "\u5B8C\u6574\u7684\u811A\u672C\u89C4\u5219\u8BF7\u53C2\u9605{link}\u3002"],
3578
+ variables: ["Pixie \uD6C5 \uACB0\uACFC\uB85C \uC4F8 \uC218 \uC788\uB294 \uAC12", "Values from the Pixie hook result", "\u53EF\u7528\u4F5C Pixie \u94A9\u5B50\u7ED3\u679C\u7684\u503C"],
3579
+ "var-text": ["\uC2A4\uD06C\uB9BD\uD2B8 \uCD9C\uB825 \uD14D\uC2A4\uD2B8", "script output text", "\u811A\u672C\u8F93\u51FA\u6587\u672C"],
3580
+ "var-data": ["\uC2A4\uD06C\uB9BD\uD2B8 \uCD9C\uB825 \uB370\uC774\uD130(JSON)", "script output data (JSON)", "\u811A\u672C\u8F93\u51FA\u6570\u636E\uFF08JSON\uFF09"],
3581
+ confirmReplace: ["\uBC14\uAFB8\uAE30 \uC804\uC5D0 \uD655\uC778", "Confirm before replacing", "\u66FF\u6362\u524D\u786E\u8BA4"],
3582
+ confirmReplaceHint: ["\uBC14\uAFC0 \uB0B4\uC6A9\uC744 \uBC14\uB85C \uBCF4\uB0B4\uC9C0 \uC54A\uACE0 Pixie \uCE74\uB4DC\uC5D0\uC11C \uD655\uC778 \uD6C4 \uBCF4\uB0C5\uB2C8\uB2E4.", "Holds the replacement on a Pixie card until you confirm.", "\u66FF\u6362\u5185\u5BB9\u5148\u4FDD\u7559\u5728 Pixie \u5361\u7247\uFF0C\u786E\u8BA4\u540E\u518D\u53D1\u9001\u3002"],
3583
+ showInChat: ["\uACB0\uACFC\uB97C \uB300\uD654\uC5D0 \uD45C\uC2DC", "Show the result in the chat", "\u5728\u5BF9\u8BDD\u4E2D\u663E\u793A\u7ED3\u679C"],
3584
+ showInChatHint: ["\uAC8C\uC774\uD2B8\uAC00 \uB05D\uB098\uBA74 \uACB0\uACFC\uB97C \uAC80\uC0AC\uD55C \uB300\uC0C1(\uBA54\uC2DC\uC9C0\xB7\uB3C4\uAD6C \uD638\uCD9C\xB7\uB2F5\uBCC0) \uBC14\uB85C \uC544\uB798\uC5D0 \uBCF4\uC5EC \uC90D\uB2C8\uB2E4. \uBA54\uBAA8\uAC00 \uC788\uC73C\uBA74 \uBA54\uBAA8\uB97C, \uC5C6\uC73C\uBA74 \uD310\uC815\uACFC \uC774\uC720\uB97C \uBCF4\uC5EC \uC90D\uB2C8\uB2E4. \uC138\uC158 \uAE30\uB85D\uC5D0\uB294 \uB0A8\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.", "Shows the result right under what the gate checked (message, tool call, or answer) when it finishes: the note if there is one, otherwise the verdict and reason. Nothing is added to the session log.", "\u95E8\u63A7\u7ED3\u675F\u540E\u5728\u6240\u68C0\u67E5\u7684\u5BF9\u8C61\uFF08\u6D88\u606F\u3001\u5DE5\u5177\u8C03\u7528\u6216\u56DE\u7B54\uFF09\u4E0B\u65B9\u663E\u793A\u7ED3\u679C\uFF1A\u6709\u5907\u6CE8\u65F6\u663E\u793A\u5907\u6CE8\uFF0C\u5426\u5219\u663E\u793A\u5224\u5B9A\u548C\u539F\u56E0\u3002\u4E0D\u4F1A\u5199\u5165\u4F1A\u8BDD\u8BB0\u5F55\u3002"],
3585
+ onError: ["Pixie\uAC00 \uC2E4\uD328\uD558\uBA74", "If Pixie fails", "\u82E5 Pixie \u5931\u8D25"],
3586
+ errorPass: ["\uADF8\uB300\uB85C \uC9C4\uD589", "Continue as usual", "\u7167\u5E38\u7EE7\u7EED"],
3587
+ errorBlock: ["\uB9C9\uC74C", "Stop it", "\u62E6\u4E0B"],
3588
+ agents: ["\uB300\uC0C1 \uC5D0\uC774\uC804\uD2B8", "Target agents", "\u76EE\u6807\u4EE3\u7406"],
3589
+ root: ["\uBA54\uC778 \uC5D0\uC774\uC804\uD2B8", "Main agent", "\u4E3B\u4EE3\u7406"],
3590
+ child: ["\uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8", "Subagents", "\u5B50\u4EE3\u7406"],
3591
+ any: ["\uBAA8\uB450", "All", "\u5168\u90E8"],
3592
+ timeout: ["\uC81C\uD55C \uC2DC\uAC04 (\uCD08)", "Time limit (seconds)", "\u65F6\u9650\uFF08\u79D2\uFF09"],
3593
+ maxSteers: ["\uD134\uB2F9 \uB2E4\uC2DC \uD558\uAE30 \uCD5C\uB300 \uD69F\uC218", "Redo limit per turn", "\u6BCF\u8F6E\u91CD\u505A\u4E0A\u9650"],
3594
+ // trial
3595
+ trial: ["\uAC8C\uC774\uD2B8 \uD14C\uC2A4\uD2B8", "Gate test", "\u95E8\u63A7\u6D4B\u8BD5"],
3596
+ trialSample: ["\uC608\uC2DC {target}", "Sample {target}", "\u793A\u4F8B{target}"],
3597
+ trialRun: ["\uC2E4\uD589", "Run", "\u8FD0\u884C"],
3598
+ trialPreview: ["\uC124\uC815\uD55C Pixie \uBAA8\uB378\uC744 \uC2E4\uC81C\uB85C \uD638\uCD9C\uD569\uB2C8\uB2E4. \uAE30\uB85D\uC744 \uB0A8\uAE30\uAC70\uB098 \uC138\uC158\uC5D0 \uBCF4\uB0B4\uC9C0\uB294 \uC54A\uC2B5\uB2C8\uB2E4.", "Calls the configured Pixie model. Nothing is recorded or sent to a session.", "\u4F1A\u5B9E\u9645\u8C03\u7528\u5DF2\u914D\u7F6E\u7684 Pixie \u6A21\u578B\uFF0C\u4E0D\u4F1A\u8BB0\u5F55\u6216\u53D1\u9001\u5230\u4F1A\u8BDD\u3002"],
3599
+ trialScript: ["\uAC8C\uC774\uD2B8 \uD14C\uC2A4\uD2B8\uC5D0\uC11C\uB294 \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uC2E4\uD589\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.", "Gate tests do not run the script.", "\u95E8\u63A7\u6D4B\u8BD5\u4E0D\u4F1A\u8FD0\u884C\u811A\u672C\u3002"],
3600
+ trialTool: ["\uC608\uC2DC \uB3C4\uAD6C \uC774\uB984 (\uC120\uD0DD)", "Sample tool name (optional)", "\u793A\u4F8B\u5DE5\u5177\u540D\u79F0\uFF08\u53EF\u9009\uFF09"],
3601
+ trialRunning: ["\uC2E4\uD589 \uC911\u2026", "Running\u2026", "\u8FD0\u884C\u4E2D\u2026"],
3602
+ trialCancel: ["\uCDE8\uC18C", "Cancel", "\u53D6\u6D88"],
3603
+ trialFailed: ["\uC2DC\uD5D8 \uC2E4\uD589 \uC2E4\uD328", "Trial failed", "\u8BD5\u8FD0\u884C\u5931\u8D25"],
3604
+ trialUsage: ["\uD1A0\uD070 \uC785\uB825 {input} \xB7 \uCD9C\uB825 {output}", "Tokens in {input} \xB7 out {output}", "\u4EE4\u724C \u8F93\u5165 {input} \xB7 \u8F93\u51FA {output}"],
3605
+ trialApplied: ["\uC2E4\uC81C \uC801\uC6A9", "What happens", "\u5B9E\u9645\u6548\u679C"],
3606
+ "plan-stop": ["\uB9C9\uC74C", "Stopped", "\u5DF2\u62E6\u4E0B"],
3607
+ "plan-confirm": ["\uAD50\uCCB4 \uC804 \uD655\uC778\uC744 \uC694\uCCAD\uD568", "Asks before replacing", "\u66FF\u6362\u524D\u8BF7\u6C42\u786E\u8BA4"],
3608
+ "plan-replace": ["\uB0B4\uC6A9\uC744 \uBC14\uAFC8", "Replaces the content", "\u66FF\u6362\u5185\u5BB9"],
3609
+ "plan-append": ["\uB0B4\uC6A9\uC744 \uB367\uBD99\uC784", "Adds content", "\u8FFD\u52A0\u5185\u5BB9"],
3610
+ "plan-pass": ["\uADF8\uB300\uB85C \uD1B5\uACFC", "Passes unchanged", "\u539F\u6837\u901A\u8FC7"],
3611
+ trialPass: ["\uD1B5\uACFC", "Pass", "\u901A\u8FC7"],
3612
+ trialStop: ["\uB9C9\uC74C", "Stopped", "\u5DF2\u62E6\u4E0B"],
3613
+ trialEmpty: ["(\uBE44\uC5B4 \uC788\uC74C)", "(empty)", "\uFF08\u7A7A\uFF09"],
3614
+ // problems
3615
+ "problem-name": ["\uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694.", "Enter a name.", "\u8BF7\u8F93\u5165\u540D\u79F0\u3002"],
3616
+ "problem-instruction": ["Pixie\uAC00 \uD560 \uC77C\uC744 \uC785\uB825\uD558\uC138\uC694.", "Describe what Pixie should do.", "\u8BF7\u586B\u5199 Pixie \u7684\u4EFB\u52A1\u3002"],
3617
+ "problem-limits": ["\uC81C\uD55C \uC2DC\uAC04\uACFC \uC0C1\uD55C\uC744 \uD655\uC778\uD558\uC138\uC694.", "Check the time limit and redo limit.", "\u8BF7\u68C0\u67E5\u65F6\u9650\u548C\u4E0A\u9650\u3002"],
3618
+ // scope
3619
+ enabled: ["\uCF1C\uC9D0", "Enabled", "\u542F\u7528"],
3620
+ presets: ["\uC801\uC6A9 \uD504\uB9AC\uC14B", "Presets", "\u9002\u7528\u9884\u8BBE"],
3621
+ presetsHint: ["\uC774 \uD504\uB9AC\uC14B\uC73C\uB85C \uC2E4\uD589\uB418\uB294 \uC5D0\uC774\uC804\uD2B8\uC5D0\uB9CC \uAC8C\uC774\uD2B8\uAC00 \uAC78\uB9BD\uB2C8\uB2E4.", "The gate runs only for agents using these presets.", "\u95E8\u63A7\u53EA\u4F5C\u7528\u4E8E\u4F7F\u7528\u8FD9\u4E9B\u9884\u8BBE\u7684\u4EE3\u7406\u3002"],
3622
+ choosePresets: ["\uD504\uB9AC\uC14B \uC120\uD0DD", "Choose presets", "\u9009\u62E9\u9884\u8BBE"],
3623
+ searchPresets: ["\uD504\uB9AC\uC14B \uAC80\uC0C9", "Search presets", "\u641C\u7D22\u9884\u8BBE"],
3624
+ done: ["\uC644\uB8CC", "Done", "\u5B8C\u6210"],
3625
+ scopeEmpty: ["\uAC8C\uC774\uD2B8 \uAD6C\uC131\uC5D0\uC11C \uBA3C\uC800 \uAC8C\uC774\uD2B8\uB97C \uB9CC\uB4DC\uC138\uC694.", "Create a gate in Gate composition first.", "\u8BF7\u5148\u5728\u95E8\u63A7\u6784\u6210\u4E2D\u521B\u5EFA\u95E8\u63A7\u3002"],
3626
+ // templates
3627
+ "tpl-format-check": ["\uC791\uC5C5 \uC9C0\uC2DC \uC591\uC2DD \uAC80\uC0AC", "Instruction format check", "\u4EFB\u52A1\u6307\u4EE4\u683C\u5F0F\u68C0\u67E5"],
3628
+ "tplDesc-format-check": ["\uC9C0\uC2DC\uC5D0 \uBAA9\uD45C\xB7\uBC94\uC704\xB7\uC644\uB8CC \uC870\uAC74\uC774 \uC788\uB294\uC9C0 \uBCF4\uACE0, \uBE60\uC9C0\uBA74 \uB3CC\uB824\uBCF4\uB0C5\uB2C8\uB2E4.", "Checks that an instruction has a goal, scope, and done criteria; sends it back if not.", "\u68C0\u67E5\u6307\u4EE4\u662F\u5426\u5305\u542B\u76EE\u6807\u3001\u8303\u56F4\u548C\u5B8C\u6210\u6761\u4EF6\uFF0C\u7F3A\u5C11\u5219\u9000\u56DE\u3002"],
3629
+ "tplText-format-check": ["\uC774 \uC9C0\uC2DC\uC5D0 \uBAA9\uD45C, \uBC94\uC704, \uC644\uB8CC \uC870\uAC74\uC774 \uBAA8\uB450 \uC788\uB294\uC9C0 \uD655\uC778\uD574.\n\uBE60\uC9C4 \uD56D\uBAA9\uC774 \uC788\uC73C\uBA74 \uB9C9\uACE0, \uBB34\uC5C7\uC774 \uBE60\uC84C\uB294\uC9C0 \uC774\uC720\uC5D0 \uC4F0\uACE0, \uC591\uC2DD\uC5D0 \uB9DE\uAC8C \uB2E4\uC2DC \uC4F4 \uC9C0\uC2DC\uB97C \uBC14\uAFC0 \uB0B4\uC6A9\uC5D0 \uB123\uC5B4.", "Check that this instruction has a goal, scope, and done criteria.\nIf any is missing, stop it, list what is missing as the reason, and put a rewritten instruction in the replacement.", "\u68C0\u67E5\u8BE5\u6307\u4EE4\u662F\u5426\u5305\u542B\u76EE\u6807\u3001\u8303\u56F4\u548C\u5B8C\u6210\u6761\u4EF6\u3002\n\u82E5\u7F3A\u5C11\uFF0C\u8BF7\u62E6\u4E0B\uFF0C\u5728\u539F\u56E0\u4E2D\u5199\u660E\u7F3A\u5C11\u9879\uFF0C\u5E76\u628A\u6539\u5199\u540E\u7684\u6307\u4EE4\u653E\u5165\u66FF\u6362\u5185\u5BB9\u3002"],
3630
+ "tpl-agent-protocol": ["\uC5D0\uC774\uC804\uD2B8 \uB300\uD654 \uADDC\uACA9 \uD310\uC815", "Agent message protocol", "\u4EE3\u7406\u6D88\u606F\u89C4\u8303\u5224\u5B9A"],
3631
+ "tplDesc-agent-protocol": ["\uC5D0\uC774\uC804\uD2B8\uB07C\uB9AC \uC8FC\uACE0\uBC1B\uB294 \uBA54\uC2DC\uC9C0\uAC00 \uC815\uD574\uC9C4 \uADDC\uACA9\uC744 \uB530\uB974\uB294\uC9C0 \uD310\uC815\uD569\uB2C8\uB2E4.", "Checks that messages between agents follow the agreed format.", "\u5224\u5B9A\u4EE3\u7406\u4E4B\u95F4\u7684\u6D88\u606F\u662F\u5426\u9075\u5FAA\u7EA6\u5B9A\u683C\u5F0F\u3002"],
3632
+ "tplText-agent-protocol": ['\uC774 \uBA54\uC2DC\uC9C0\uAC00 "\uC791\uC5C5 / \uADFC\uAC70 / \uB2E4\uC74C \uD589\uB3D9" \uC138 \uBD80\uBD84\uC744 \uAC16\uCDC4\uB294\uC9C0 \uD655\uC778\uD574.\n\uAC16\uCD94\uC9C0 \uC54A\uC558\uC73C\uBA74 \uB9C9\uACE0 \uC774\uC720\uC5D0 \uBB34\uC5C7\uC774 \uBE60\uC84C\uB294\uC9C0 \uC368.', "Check that this message has three parts: task, evidence, next action.\nIf not, stop it and give what is missing as the reason.", "\u68C0\u67E5\u8BE5\u6D88\u606F\u662F\u5426\u5305\u542B\u201C\u4EFB\u52A1 / \u4F9D\u636E / \u4E0B\u4E00\u6B65\u201D\u4E09\u90E8\u5206\u3002\n\u82E5\u4E0D\u5B8C\u6574\uFF0C\u8BF7\u62E6\u4E0B\u5E76\u5728\u539F\u56E0\u4E2D\u5199\u660E\u7F3A\u5C11\u7684\u90E8\u5206\u3002"],
3633
+ "tpl-command-guard": ["\uC704\uD5D8\uD55C \uBA85\uB839 \uCC28\uB2E8", "Block risky commands", "\u62E6\u622A\u5371\u9669\u547D\u4EE4"],
3634
+ "tplDesc-command-guard": ["\uC2E4\uD589 \uC804 \uB3C4\uAD6C \uD638\uCD9C\uC744 \uD655\uC778\uD558\uACE0, \uB418\uB3CC\uB9AC\uAE30 \uC5B4\uB824\uC6B4 \uC791\uC5C5\uC774\uBA74 \uC774\uC720\uC640 \uD568\uAED8 \uB9C9\uC2B5\uB2C8\uB2E4.", "Reviews a tool call before it runs and stops it, with a reason, if it is hard to undo.", "\u5728\u5DE5\u5177\u8FD0\u884C\u524D\u68C0\u67E5\u8C03\u7528\uFF0C\u82E5\u96BE\u4EE5\u64A4\u9500\u5219\u62E6\u4E0B\u5E76\u8BF4\u660E\u539F\u56E0\u3002"],
3635
+ "tplText-command-guard": ["\uC774 \uB3C4\uAD6C \uD638\uCD9C\uC774 \uD30C\uC77C\uC744 \uB300\uB7C9\uC73C\uB85C \uC9C0\uC6B0\uAC70\uB098, \uC791\uC5C5 \uACF5\uAC04 \uBC16\uC744 \uBC14\uAFB8\uAC70\uB098, \uAC15\uC81C \uD478\uC2DC\uCC98\uB7FC \uB418\uB3CC\uB9AC\uAE30 \uC5B4\uB824\uC6B4 \uC791\uC5C5\uC778\uC9C0 \uD655\uC778\uD574.\n\uADF8\uB807\uB2E4\uBA74 \uB9C9\uACE0, \uBB34\uC5C7\uC774 \uC704\uD5D8\uD55C\uC9C0\uC640 \uB354 \uC548\uC804\uD55C \uBC29\uBC95\uC744 \uC774\uC720\uC5D0 \uC368. \uC544\uB2C8\uBA74 \uC544\uBB34\uAC83\uB3C4 \uD558\uC9C0 \uB9C8.", "Check whether this tool call does something hard to undo, such as deleting many files, changing things outside the workspace, or a force push.\nIf so, stop it and give the risk and a safer approach as the reason. Otherwise do nothing.", "\u68C0\u67E5\u8BE5\u5DE5\u5177\u8C03\u7528\u662F\u5426\u96BE\u4EE5\u64A4\u9500\uFF0C\u4F8B\u5982\u5927\u91CF\u5220\u9664\u6587\u4EF6\u3001\u4FEE\u6539\u5DE5\u4F5C\u533A\u4E4B\u5916\u7684\u5185\u5BB9\u6216\u5F3A\u5236\u63A8\u9001\u3002\n\u82E5\u662F\uFF0C\u8BF7\u62E6\u4E0B\u5E76\u5728\u539F\u56E0\u4E2D\u5199\u660E\u98CE\u9669\u548C\u66F4\u5B89\u5168\u7684\u505A\u6CD5\u3002\u5426\u5219\u4E0D\u505A\u4EFB\u4F55\u4E8B\u3002"],
3636
+ "tpl-tool-digest": ["\uAE34 \uB3C4\uAD6C \uACB0\uACFC \uC694\uC57D", "Digest long tool results", "\u6982\u62EC\u5197\u957F\u7684\u5DE5\u5177\u7ED3\u679C"],
3637
+ "tplDesc-tool-digest": ["\uB3C4\uAD6C \uACB0\uACFC\uAC00 \uAE38\uBA74 \uD604\uC7AC \uC791\uC5C5\uACFC \uAD00\uB828 \uC788\uB294 \uB0B4\uC6A9\uB9CC \uACE8\uB77C \uC5D0\uC774\uC804\uD2B8\uC5D0\uAC8C \uC90D\uB2C8\uB2E4.", "When a tool result is long, gives the agent only what matters to the current task.", "\u5DE5\u5177\u7ED3\u679C\u8FC7\u957F\u65F6\uFF0C\u53EA\u628A\u4E0E\u5F53\u524D\u4EFB\u52A1\u76F8\u5173\u7684\u5185\u5BB9\u4EA4\u7ED9\u4EE3\u7406\u3002"],
3638
+ "tplText-tool-digest": ["\uB3C4\uAD6C \uACB0\uACFC\uAC00 \uAE38\uBA74 \uD604\uC7AC \uC791\uC5C5\uACFC \uAD00\uB828 \uC788\uB294 \uD56D\uBAA9\uB9CC \uACE8\uB77C \uC694\uC57D\uD574\uC11C \uBC14\uAFC0 \uB0B4\uC6A9\uC5D0 \uB123\uC5B4. \uD30C\uC77C \uACBD\uB85C\xB7\uC904 \uBC88\uD638\xB7\uC624\uB958 \uBB38\uAD6C\uB294 \uADF8\uB300\uB85C \uB0A8\uACA8.\n\uACB0\uACFC\uAC00 \uC9E7\uC73C\uBA74 \uC544\uBB34\uAC83\uB3C4 \uD558\uC9C0 \uB9C8.", "If the tool result is long, put a summary of only the items relevant to the current task in the replacement. Keep file paths, line numbers and error text as they are.\nIf the result is short, do nothing.", "\u82E5\u5DE5\u5177\u7ED3\u679C\u8F83\u957F\uFF0C\u8BF7\u53EA\u6311\u9009\u4E0E\u5F53\u524D\u4EFB\u52A1\u76F8\u5173\u7684\u6761\u76EE\u5E76\u628A\u6458\u8981\u653E\u5165\u66FF\u6362\u5185\u5BB9\uFF0C\u6587\u4EF6\u8DEF\u5F84\u3001\u884C\u53F7\u548C\u9519\u8BEF\u6587\u672C\u4FDD\u6301\u539F\u6837\u3002\n\u82E5\u7ED3\u679C\u8F83\u77ED\uFF0C\u5219\u4E0D\u505A\u4EFB\u4F55\u4E8B\u3002"],
3639
+ "tpl-verify-answer": ["\uCD5C\uC885 \uB2F5\uBCC0 \uAC80\uC99D", "Verify the final answer", "\u9A8C\u8BC1\u6700\u7EC8\u56DE\u7B54"],
3640
+ "tplDesc-verify-answer": ["\uB2F5\uBCC0\uC774 \uC694\uCCAD\uC744 \uB2E4 \uCC44\uC6E0\uB294\uC9C0 \uD310\uC815\uD558\uACE0, \uBAA8\uC790\uB77C\uBA74 \uB2E4\uC2DC \uD558\uB77C\uACE0 \uC9C0\uC2DC\uD569\uB2C8\uB2E4.", "Judges whether the answer meets the request; asks the agent to redo it if not.", "\u5224\u5B9A\u56DE\u7B54\u662F\u5426\u6EE1\u8DB3\u8BF7\u6C42\uFF0C\u4E0D\u6EE1\u8DB3\u5219\u8BA9\u4EE3\u7406\u91CD\u505A\u3002"],
3641
+ "tplText-verify-answer": ["\uB2F5\uBCC0\uC774 \uC0AC\uC6A9\uC790\uC758 \uC694\uCCAD\uC744 \uBAA8\uB450 \uB2E4\uB918\uB294\uC9C0 \uD655\uC778\uD574.\n\uBE60\uC9C4 \uBD80\uBD84\uC774 \uC788\uC73C\uBA74 \uB9C9\uACE0, \uBB34\uC5C7\uC744 \uB354 \uD574\uC57C \uD558\uB294\uC9C0 \uC774\uC720\uC5D0 \uC368.", "Check that the answer covers everything the user asked.\nIf something is missing, stop it and say what still needs doing as the reason.", "\u68C0\u67E5\u56DE\u7B54\u662F\u5426\u6DB5\u76D6\u7528\u6237\u7684\u5168\u90E8\u8BF7\u6C42\u3002\n\u82E5\u6709\u9057\u6F0F\uFF0C\u8BF7\u62E6\u4E0B\u5E76\u5728\u539F\u56E0\u4E2D\u5199\u660E\u8FD8\u9700\u5B8C\u6210\u7684\u5185\u5BB9\u3002"]
3642
+ };
3643
+ function gateTaskText(locale, key, values = {}) {
3644
+ const text = messages2[key][locale.startsWith("ko") ? 0 : locale.startsWith("zh") ? 2 : 1];
3645
+ return text.replace(/\{(\w+)\}/g, (match2, name) => name in values ? String(values[name]) : match2);
3646
+ }
3647
+
3373
3648
  // src/pixie-gate-runs.tsx
3374
3649
  var import_jsx_runtime15 = require("react/jsx-runtime");
3650
+ function SessionGateList({ actions, locale, disabled }) {
3651
+ const t = (key) => gateText(locale, key);
3652
+ const [view, setView] = import_react13.default.useState();
3653
+ const [busy, setBusy] = import_react13.default.useState();
3654
+ const [error, setError] = import_react13.default.useState("");
3655
+ const load = actions.sessionGates;
3656
+ import_react13.default.useEffect(() => {
3657
+ if (!load) return;
3658
+ let active = true;
3659
+ void load().then((next) => {
3660
+ if (active) setView(next);
3661
+ }, (cause) => {
3662
+ if (active) setError(String(cause));
3663
+ });
3664
+ return () => {
3665
+ active = false;
3666
+ };
3667
+ }, [load]);
3668
+ import_react13.default.useEffect(() => {
3669
+ if (!disabled) return;
3670
+ const off = new Set(disabled);
3671
+ setView((current) => current && { ...current, gates: current.gates.map((gate) => ({ ...gate, sessionEnabled: !off.has(gate.id) })) });
3672
+ }, [disabled]);
3673
+ if (!load || !actions.setSessionGate || !view) return null;
3674
+ const toggle = async (id, enabled) => {
3675
+ setBusy(id);
3676
+ setError("");
3677
+ try {
3678
+ const off = new Set(await actions.setSessionGate(id, enabled));
3679
+ setView((current) => current && { ...current, gates: current.gates.map((gate) => ({ ...gate, sessionEnabled: !off.has(gate.id) })) });
3680
+ } catch (cause) {
3681
+ setError(`${t("sessionGateFailed")} (${cause instanceof Error ? cause.message : String(cause)})`);
3682
+ } finally {
3683
+ setBusy(void 0);
3684
+ }
3685
+ };
3686
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("section", { className: "studio-gate-block studio-gate-session", "aria-label": t("sessionGates"), children: [
3687
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SectionHead, { title: t("sessionGates"), description: t("sessionGatesHint") }),
3688
+ error && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Notice, { children: error }),
3689
+ !view.gates.length ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Note, { children: t("sessionGatesEmpty") }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("ul", { className: "studio-gate-session-list", children: view.gates.map((gate) => /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("li", { className: "studio-gate-session-row", "data-gate-session": gate.id, children: [
3690
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "studio-gate-session-name", children: [
3691
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: gate.name }),
3692
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "studio-card-meta", children: [
3693
+ gateTaskText(locale, `when-${gate.when}`),
3694
+ gate.script ? ` \xB7 ${gate.script}` : "",
3695
+ gate.sessionEnabled ? "" : ` \xB7 ${t("sessionGateOff")}`
3696
+ ] })
3697
+ ] }),
3698
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Toggle, { label: t("sessionGateToggle").replace("{name}", gate.name), checked: gate.sessionEnabled, disabled: busy === gate.id, onChange: (checked) => {
3699
+ void toggle(gate.id, checked);
3700
+ } })
3701
+ ] }, gate.id)) })
3702
+ ] });
3703
+ }
3375
3704
  function gateRunStatus(run) {
3376
3705
  return run.applied !== "none" ? run.applied : run.status === "done" ? "none" : run.status;
3377
3706
  }
@@ -3381,6 +3710,7 @@ function GateRunsPanel({ actions, locale }) {
3381
3710
  const [openId, setOpenId] = import_react13.default.useState();
3382
3711
  const [error, setError] = import_react13.default.useState("");
3383
3712
  const [busy, setBusy] = import_react13.default.useState(false);
3713
+ const [disabled, setDisabled] = import_react13.default.useState();
3384
3714
  import_react13.default.useEffect(() => {
3385
3715
  let active = true;
3386
3716
  let generation = 0;
@@ -3389,9 +3719,9 @@ function GateRunsPanel({ actions, locale }) {
3389
3719
  const request = ++generation;
3390
3720
  updates = /* @__PURE__ */ new Map();
3391
3721
  try {
3392
- const record2 = await actions.gateRuns();
3722
+ const record3 = await actions.gateRuns();
3393
3723
  if (!active || request !== generation) return;
3394
- const merged2 = new Map(record2.runs.map((run) => [run.id, run]));
3724
+ const merged2 = new Map(record3.runs.map((run) => [run.id, run]));
3395
3725
  for (const [id, run] of updates) merged2.set(id, run);
3396
3726
  setRuns([...merged2.values()]);
3397
3727
  setError("");
@@ -3405,6 +3735,10 @@ function GateRunsPanel({ actions, locale }) {
3405
3735
  void refresh();
3406
3736
  return;
3407
3737
  }
3738
+ if (frame.type === "session") {
3739
+ setDisabled(frame.disabledGateIds);
3740
+ return;
3741
+ }
3408
3742
  updates.set(frame.run.id, frame.run);
3409
3743
  setRuns((current) => [...current.filter((run) => run.id !== frame.run.id), frame.run]);
3410
3744
  });
@@ -3434,6 +3768,7 @@ function GateRunsPanel({ actions, locale }) {
3434
3768
  }
3435
3769
  };
3436
3770
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "studio-pixie-chat", children: [
3771
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SessionGateList, { actions, locale, disabled }),
3437
3772
  error && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Notice, { children: error }),
3438
3773
  !runs.length && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Note, { children: t("emptyRuns") }),
3439
3774
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "studio-pixie-threads", "data-open": opened ? "true" : "false", children: [
@@ -3470,6 +3805,10 @@ function GateRunsPanel({ actions, locale }) {
3470
3805
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("dl", { className: "studio-gate-facts", children: [
3471
3806
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dt", { children: t("applied") }),
3472
3807
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dd", { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Badge, { tone: shown.applied === "none" || shown.applied === "pass" ? "neutral" : "info", children: t(shown.applied) }) }),
3808
+ shown.result?.concludedBy && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
3809
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dt", { children: t("concludedBy") }),
3810
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dd", { children: t(shown.result.concludedBy === "script" ? "concludedScript" : shown.result.concludedBy === "skipped" ? "concludedSkipped" : "concludedPixie") })
3811
+ ] }),
3473
3812
  shown.output && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
3474
3813
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dt", { children: t("verdict") }),
3475
3814
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dd", { children: /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Badge, { tone: shown.output.verdict === "stop" ? "warning" : "success", children: t(shown.output.verdict === "stop" ? "stop" : "pass") }) })
@@ -3541,7 +3880,7 @@ function GateRunsPanel({ actions, locale }) {
3541
3880
  ] })
3542
3881
  ] }),
3543
3882
  shown.output && ["replace", "append", "note"].some((key) => shown.output[key] !== void 0) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("section", { className: "studio-gate-block", "aria-label": t("output"), children: [
3544
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SectionHead, { title: t("output") }),
3883
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SectionHead, { title: t(shown.result?.concludedBy === "script" ? "scriptOutput" : "output") }),
3545
3884
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dl", { className: "studio-gate-facts", children: ["replace", "append", "note"].map((key) => shown.output[key] !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_react13.default.Fragment, { children: [
3546
3885
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dt", { children: t(key === "note" ? "notes" : key) }),
3547
3886
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dd", { className: "studio-gate-text", children: shown.output[key] })
@@ -3558,6 +3897,39 @@ function GateRunsPanel({ actions, locale }) {
3558
3897
 
3559
3898
  // src/pixie-locale.ts
3560
3899
  var en4 = {
3900
+ mdCopy: "Copy",
3901
+ mdCopied: "Copied",
3902
+ mdFootnotes: "Footnotes",
3903
+ pageJudge: "Decision engine",
3904
+ pageJudgeDescription: "The engine behind 'pixie judge' in gate hook scripts. Judgments run only when a script asks for one.",
3905
+ judgeEngine: "Engine",
3906
+ judgeEngineLlm: "LLM",
3907
+ judgeEngineJev: "Jev",
3908
+ judgeEngineLlmHint: "A conversation model answers in the Jev format.",
3909
+ judgeEngineJevHint: "TypeSafe Jev answers through its API. Gate input is sent to TypeSafe.",
3910
+ judgeModel: "Judge model",
3911
+ judgeModelHint: "When not set, the value entered in the Pixie model settings is used.",
3912
+ judgeModelPixie: "Pixie model",
3913
+ judgePrompt: "Judge system prompt",
3914
+ judgePromptHint: "Leave empty for the built-in prompt.",
3915
+ jevModel: "Jev model",
3916
+ jevModelHint: "A model ID or alias such as jev-latest. Pin a version once you tune thresholds.",
3917
+ jevKey: "TypeSafe API key",
3918
+ jevKeyHint: "Stored in DSH credentials as TYPESAFE_API_KEY. It is never shown again.",
3919
+ jevKeySet: "Set",
3920
+ jevKeyFrom: "Source: {source}",
3921
+ jevKeyMissing: "Not set",
3922
+ jevKeyReadOnly: "Set by a read-only source ({source}). Change it there.",
3923
+ jevKeyUnavailable: "The DSH credentials service is not available, so the key cannot be stored here.",
3924
+ jevKeyPlaceholder: "Paste the key",
3925
+ jevKeySave: "Save key",
3926
+ jevKeyDelete: "Remove key",
3927
+ jevKeyFailed: "Could not update the key.",
3928
+ errCredentialsRefs: "The DSH credentials file (.credentials.yaml in the DSH home) has an empty refs: line. Change it to refs: {} and save again.",
3929
+ jevKeySaving: "Saving\u2026",
3930
+ jevKeyRemoving: "Removing\u2026",
3931
+ jevKeySaved: "Key saved.",
3932
+ jevKeyRemoved: "Key removed.",
3561
3933
  title: "Pixie",
3562
3934
  chat: "Threads",
3563
3935
  judge: "Judge",
@@ -3635,34 +4007,67 @@ var en4 = {
3635
4007
  errEmpty: "Type a question after /pixie."
3636
4008
  };
3637
4009
  var ko4 = {
4010
+ mdCopy: "\uBCF5\uC0AC",
4011
+ mdCopied: "\uBCF5\uC0AC\uB428",
4012
+ mdFootnotes: "\uAC01\uC8FC",
4013
+ pageJudge: "\uACB0\uC815 \uC5D4\uC9C4",
4014
+ pageJudgeDescription: "\uAC8C\uC774\uD2B8 \uD6C5 \uC2A4\uD06C\uB9BD\uD2B8\uC5D0\uC11C 'pixie judge'\uAC00 \uC0AC\uC6A9\uD558\uB294 \uC5D4\uC9C4\uC785\uB2C8\uB2E4. \uC2A4\uD06C\uB9BD\uD2B8\uAC00 \uC694\uCCAD\uD560 \uB54C\uB9CC \uD310\uC815\uD569\uB2C8\uB2E4.",
4015
+ judgeEngine: "\uC5D4\uC9C4",
4016
+ judgeEngineLlm: "LLM",
4017
+ judgeEngineJev: "Jev",
4018
+ judgeEngineLlmHint: "\uB300\uD654 \uBAA8\uB378\uC774 Jev \uD615\uC2DD\uC73C\uB85C \uB2F5\uC744 \uC0DD\uC131\uD569\uB2C8\uB2E4.",
4019
+ judgeEngineJevHint: "TypeSafe Jev API\uAC00 \uB2F5\uD569\uB2C8\uB2E4. \uAC8C\uC774\uD2B8 \uC785\uB825\uC774 TypeSafe\uB85C \uC804\uC1A1\uB429\uB2C8\uB2E4.",
4020
+ judgeModel: "\uD310\uC815 \uBAA8\uB378",
4021
+ judgeModelHint: "\uC815\uD558\uC9C0 \uC54A\uC73C\uBA74 Pixie \uBAA8\uB378 \uC124\uC815\uC5D0\uC11C \uC785\uB825\uD55C \uAC12\uC744 \uC0AC\uC6A9\uD569\uB2C8\uB2E4.",
4022
+ judgeModelPixie: "Pixie \uBAA8\uB378",
4023
+ judgePrompt: "\uD310\uC815 \uC2DC\uC2A4\uD15C \uD504\uB86C\uD504\uD2B8",
4024
+ judgePromptHint: "\uBE44\uC6B0\uBA74 \uAE30\uBCF8 \uD504\uB86C\uD504\uD2B8\uB97C \uC501\uB2C8\uB2E4.",
4025
+ jevModel: "Jev \uBAA8\uB378",
4026
+ jevModelHint: "jev-latest \uAC19\uC740 \uBAA8\uB378 ID\uB098 \uBCC4\uCE6D\uC744 \uB123\uC2B5\uB2C8\uB2E4. \uAE30\uC900\uAC12\uC744 \uC870\uC815\uD55C \uB4A4\uC5D0\uB294 \uBC84\uC804\uC744 \uACE0\uC815\uD558\uC138\uC694.",
4027
+ jevKey: "TypeSafe API \uD0A4",
4028
+ jevKeyHint: "DSH \uC790\uACA9 \uC99D\uBA85\uC5D0 TYPESAFE_API_KEY\uB85C \uC800\uC7A5\uB418\uBA70, \uC800\uC7A5\uD55C \uD0A4\uB294 \uB2E4\uC2DC \uD45C\uC2DC\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
4029
+ jevKeySet: "\uC124\uC815\uB428",
4030
+ jevKeyFrom: "\uCD9C\uCC98: {source}",
4031
+ jevKeyMissing: "\uC124\uC815 \uC548 \uB428",
4032
+ jevKeyReadOnly: "\uC77D\uAE30 \uC804\uC6A9 \uCD9C\uCC98({source})\uC5D0\uC11C \uC124\uC815\uD55C \uAC12\uC785\uB2C8\uB2E4. \uADF8\uACF3\uC5D0\uC11C \uBC14\uAFB8\uC138\uC694.",
4033
+ jevKeyUnavailable: "DSH \uC790\uACA9 \uC99D\uBA85 \uC11C\uBE44\uC2A4\uB97C \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC5B4 \uC5EC\uAE30\uC5D0 \uD0A4\uB97C \uC800\uC7A5\uD560 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
4034
+ jevKeyPlaceholder: "\uD0A4 \uBD99\uC5EC \uB123\uAE30",
4035
+ jevKeySave: "\uD0A4 \uC800\uC7A5",
4036
+ jevKeyDelete: "\uD0A4 \uC0AD\uC81C",
4037
+ jevKeyFailed: "\uD0A4\uB97C \uBC14\uAFB8\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
4038
+ errCredentialsRefs: "DSH \uC790\uACA9 \uC99D\uBA85 \uD30C\uC77C(DSH \uD648\uC758 .credentials.yaml)\uC5D0\uC11C refs: \uC904\uC774 \uBE44\uC5B4 \uC788\uC2B5\uB2C8\uB2E4. refs: {}\uB85C \uACE0\uCE5C \uB4A4 \uB2E4\uC2DC \uC800\uC7A5\uD558\uC138\uC694.",
4039
+ jevKeySaving: "\uC800\uC7A5 \uC911\u2026",
4040
+ jevKeyRemoving: "\uC0AD\uC81C \uC911\u2026",
4041
+ jevKeySaved: "\uD0A4\uB97C \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4.",
4042
+ jevKeyRemoved: "\uD0A4\uB97C \uC0AD\uC81C\uD588\uC2B5\uB2C8\uB2E4.",
3638
4043
  title: "Pixie",
3639
4044
  chat: "\uC2A4\uB808\uB4DC",
3640
4045
  judge: "\uD310\uC815",
3641
4046
  threads: "Pixie \uC2A4\uB808\uB4DC",
3642
4047
  newThread: "\uC0C8 \uC2A4\uB808\uB4DC",
3643
4048
  fresh: "\uC0C8 \uB300\uD654",
3644
- fork: "\uC774\uC5B4\uBC1B\uAE30",
4049
+ fork: "\uC774\uC5B4\uC4F0\uAE30",
3645
4050
  mode: "\uCEE8\uD14D\uC2A4\uD2B8 \uBAA8\uB4DC",
3646
4051
  model: "\uBAA8\uB378",
3647
4052
  allThreads: "\uC804\uCCB4 \uC2A4\uB808\uB4DC",
3648
4053
  turnCount: "\uAC1C \uC9C8\uBB38",
3649
- activeBadge: "/pixie\uAC00 \uC5EC\uAE30\uB85C \uBCF4\uB0C5\uB2C8\uB2E4",
3650
- makeTarget: "/pixie\uB97C \uC5EC\uAE30\uB85C \uBCF4\uB0B4\uAE30",
4054
+ activeBadge: "\uC5EC\uAE30\uB85C /pixie \uBCF4\uB0B4\uAE30",
4055
+ makeTarget: "/pixie\uB97C \uC774 \uC2A4\uB808\uB4DC\uB85C \uBCF4\uB0B4\uAE30",
3651
4056
  freshMeta: "\uBE48 \uC0C1\uD0DC\uB85C \uC2DC\uC791",
3652
- forkMeta: "\uC138\uC158 \uB300\uD654 \uBCF5\uC0AC",
4057
+ forkMeta: "\uC138\uC158 \uD14D\uC2A4\uD2B8\uB97C \uBCF5\uC0AC\uD568",
3653
4058
  noTurns: "\uC544\uC9C1 \uC9C8\uBB38\uC774 \uC5C6\uC2B5\uB2C8\uB2E4",
3654
4059
  streaming: "\uB2F5\uBCC0 \uC911",
3655
4060
  cancelled: "\uCDE8\uC18C\uB428",
3656
4061
  error: "\uC2E4\uD328",
3657
4062
  cancel: "\uCDE8\uC18C",
3658
- ask: "\uC694\uCCAD",
4063
+ ask: "\uBB3B\uAE30",
3659
4064
  retry: "\uB2E4\uC2DC \uC2DC\uB3C4",
3660
4065
  loading: "\uBD88\uB7EC\uC624\uB294 \uC911\u2026",
3661
4066
  question: "Pixie\uC5D0\uAC8C \uC9C8\uBB38",
3662
4067
  placeholder: "Pixie\uC5D0\uAC8C \uBB3B\uAE30\u2026 (\u2318/Ctrl+Enter)",
3663
4068
  isolation: "Pixie \uB2F5\uBCC0\uC740 \uC5EC\uAE30\uC5D0\uB9CC \uB0A8\uC2B5\uB2C8\uB2E4. \uB300\uD654\uC640 \uC5D0\uC774\uC804\uD2B8 \uCEE8\uD14D\uC2A4\uD2B8\uC5D0\uB294 \uC544\uBB34\uAC83\uB3C4 \uCD94\uAC00\uB418\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.",
3664
4069
  noModel: "Pixie \uBAA8\uB378\uC774 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. DSH Studio \u2192 Pixie\uC5D0\uC11C \uC120\uD0DD\uD558\uC138\uC694.",
3665
- judgeNote: "Pixie \uBAA8\uB378\uB85C \uD310\uC815\uC744 \uC2DC\uD5D8\uD569\uB2C8\uB2E4. \uC0C1\uD0DC\uC640 \uC9C8\uBB38\uC744 \uB123\uC73C\uBA74 \uC9C8\uBB38\uB9C8\uB2E4 \uC120\uD0DD\uC9C0, \uC810\uC218, \uC608 \uD655\uB960\uC744 \uB3CC\uB824\uC90D\uB2C8\uB2E4.",
4070
+ judgeNote: "Pixie \uBAA8\uB378\uB85C \uD310\uC815\uC744 \uC2DC\uD5D8\uD574 \uBCF4\uC138\uC694. \uC0C1\uD0DC\uC640 \uC9C8\uBB38\uC744 \uB123\uC73C\uBA74 \uC9C8\uBB38\uB9C8\uB2E4 \uC120\uD0DD\uC9C0, \uC810\uC218, \uC608 \uD655\uB960\uC744 \uB3CC\uB824\uC90D\uB2C8\uB2E4.",
3666
4071
  judgeState: "\uC0C1\uD0DC (\uD14D\uC2A4\uD2B8 \uB610\uB294 JSON)",
3667
4072
  judgeQuestions: "\uC9C8\uBB38 (ID\uBCC4 JSON)",
3668
4073
  runJudge: "\uD310\uC815 \uC2E4\uD589",
@@ -3706,12 +4111,45 @@ var ko4 = {
3706
4111
  create: "\uB9CC\uB4E4\uAE30",
3707
4112
  noThreads: "\uC544\uC9C1 \uC2A4\uB808\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4",
3708
4113
  rowWaiting: "Pixie\uAC00 \uB2F5\uBCC0\uD558\uB294 \uC911\u2026",
3709
- truncated: "\uD1A0\uD070 \uD55C\uB3C4\uC5D0 \uAC78\uB824 \uC798\uB9BC",
4114
+ truncated: "\uD1A0\uD070 \uD55C\uB3C4\uC5D0\uC11C \uC798\uB838\uC2B5\uB2C8\uB2E4",
3710
4115
  errNoModel: "Pixie \uBAA8\uB378\uC774 \uC124\uC815\uB418\uC9C0 \uC54A\uC558\uC2B5\uB2C8\uB2E4. DSH Studio \u2192 Pixie\uC5D0\uC11C \uC120\uD0DD\uD558\uC138\uC694.",
3711
4116
  errBusy: "\uC774 \uC138\uC158\uC5D0\uC11C Pixie\uAC00 \uC544\uC9C1 \uB2F5\uBCC0 \uC911\uC785\uB2C8\uB2E4.",
3712
4117
  errEmpty: "/pixie \uB4A4\uC5D0 \uC9C8\uBB38\uC744 \uC785\uB825\uD558\uC138\uC694."
3713
4118
  };
3714
4119
  var zh4 = {
4120
+ mdCopy: "\u590D\u5236",
4121
+ mdCopied: "\u5DF2\u590D\u5236",
4122
+ mdFootnotes: "\u811A\u6CE8",
4123
+ pageJudge: "\u51B3\u7B56\u5F15\u64CE",
4124
+ pageJudgeDescription: "\u95E8\u63A7\u94A9\u5B50\u811A\u672C\u4E2D 'pixie judge' \u4F7F\u7528\u7684\u5F15\u64CE\uFF0C\u4EC5\u5728\u811A\u672C\u8BF7\u6C42\u65F6\u5224\u5B9A\u3002",
4125
+ judgeEngine: "\u5F15\u64CE",
4126
+ judgeEngineLlm: "LLM",
4127
+ judgeEngineJev: "Jev",
4128
+ judgeEngineLlmHint: "\u7531\u5BF9\u8BDD\u6A21\u578B\u6309 Jev \u683C\u5F0F\u56DE\u7B54\u3002",
4129
+ judgeEngineJevHint: "\u7531 TypeSafe Jev API \u56DE\u7B54\uFF0C\u95E8\u63A7\u8F93\u5165\u4F1A\u53D1\u9001\u7ED9 TypeSafe\u3002",
4130
+ judgeModel: "\u5224\u5B9A\u6A21\u578B",
4131
+ judgeModelHint: "\u672A\u8BBE\u7F6E\u65F6\u4F7F\u7528 Pixie \u6A21\u578B\u8BBE\u7F6E\u4E2D\u586B\u5199\u7684\u503C\u3002",
4132
+ judgeModelPixie: "Pixie \u6A21\u578B",
4133
+ judgePrompt: "\u5224\u5B9A\u7CFB\u7EDF\u63D0\u793A\u8BCD",
4134
+ judgePromptHint: "\u7559\u7A7A\u5219\u4F7F\u7528\u5185\u7F6E\u63D0\u793A\u8BCD\u3002",
4135
+ jevModel: "Jev \u6A21\u578B",
4136
+ jevModelHint: "\u6A21\u578B ID \u6216\u522B\u540D\uFF0C\u5982 jev-latest\u3002\u8C03\u597D\u9608\u503C\u540E\u8BF7\u56FA\u5B9A\u7248\u672C\u3002",
4137
+ jevKey: "TypeSafe API \u5BC6\u94A5",
4138
+ jevKeyHint: "\u4EE5 TYPESAFE_API_KEY \u5B58\u5165 DSH \u51ED\u636E\uFF0C\u4FDD\u5B58\u540E\u4E0D\u518D\u663E\u793A\u3002",
4139
+ jevKeySet: "\u5DF2\u8BBE\u7F6E",
4140
+ jevKeyFrom: "\u6765\u6E90\uFF1A{source}",
4141
+ jevKeyMissing: "\u672A\u8BBE\u7F6E",
4142
+ jevKeyReadOnly: "\u7531\u53EA\u8BFB\u6765\u6E90\uFF08{source}\uFF09\u8BBE\u7F6E\uFF0C\u8BF7\u5728\u8BE5\u5904\u4FEE\u6539\u3002",
4143
+ jevKeyUnavailable: "DSH \u51ED\u636E\u670D\u52A1\u4E0D\u53EF\u7528\uFF0C\u65E0\u6CD5\u5728\u6B64\u4FDD\u5B58\u5BC6\u94A5\u3002",
4144
+ jevKeyPlaceholder: "\u7C98\u8D34\u5BC6\u94A5",
4145
+ jevKeySave: "\u4FDD\u5B58\u5BC6\u94A5",
4146
+ jevKeyDelete: "\u5220\u9664\u5BC6\u94A5",
4147
+ jevKeyFailed: "\u65E0\u6CD5\u66F4\u65B0\u5BC6\u94A5\u3002",
4148
+ errCredentialsRefs: "DSH \u51ED\u636E\u6587\u4EF6\uFF08DSH \u4E3B\u76EE\u5F55\u4E2D\u7684 .credentials.yaml\uFF09\u7684 refs: \u884C\u4E3A\u7A7A\u3002\u8BF7\u6539\u4E3A refs: {} \u540E\u91CD\u65B0\u4FDD\u5B58",
4149
+ jevKeySaving: "\u4FDD\u5B58\u4E2D\u2026",
4150
+ jevKeyRemoving: "\u5220\u9664\u4E2D\u2026",
4151
+ jevKeySaved: "\u5DF2\u4FDD\u5B58\u5BC6\u94A5",
4152
+ jevKeyRemoved: "\u5DF2\u5220\u9664\u5BC6\u94A5",
3715
4153
  title: "Pixie",
3716
4154
  chat: "\u7EBF\u7A0B",
3717
4155
  judge: "\u5224\u5B9A",
@@ -3794,10 +4232,13 @@ function pixieText(locale, key) {
3794
4232
  return table[key];
3795
4233
  }
3796
4234
  var PIXIE_ERROR_CODES = { "pixie/no-model": "errNoModel", "pixie/busy": "errBusy", "pixie/empty": "errEmpty" };
4235
+ var PIXIE_DETAILED_ERROR_CODES = { "pixie/credentials-refs": "errCredentialsRefs" };
3797
4236
  function pixieError(locale, message4) {
3798
- const match = /^\[(pixie\/[\w-]+)\]\s*/.exec(message4);
3799
- const key = match ? PIXIE_ERROR_CODES[match[1]] : void 0;
3800
- return key ? pixieText(locale, key) : message4;
4237
+ const match2 = /^\[(pixie\/[\w-]+)\]\s*/.exec(message4);
4238
+ const key = match2 ? PIXIE_ERROR_CODES[match2[1]] : void 0;
4239
+ if (key) return pixieText(locale, key);
4240
+ const detailed = match2 ? PIXIE_DETAILED_ERROR_CODES[match2[1]] : void 0;
4241
+ return detailed ? `${pixieText(locale, detailed)} (${message4.slice(match2[0].length)})` : message4;
3801
4242
  }
3802
4243
 
3803
4244
  // src/pixie-tab.tsx
@@ -3812,7 +4253,7 @@ function Turn({ turn, live, locale }) {
3812
4253
  const answer = live ?? turn.answer;
3813
4254
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("li", { className: "studio-pixie-turn", children: [
3814
4255
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "studio-pixie-question", children: turn.question }),
3815
- answer && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "studio-pixie-answer", children: answer }),
4256
+ answer && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ModelText, { text: answer, locale, streaming: live !== void 0 || turn.status === "streaming" }),
3816
4257
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "studio-pixie-turn-meta", children: [
3817
4258
  turn.status === "streaming" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Badge, { tone: "info", children: t("streaming") }),
3818
4259
  turn.status === "cancelled" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Badge, { tone: "neutral", children: t("cancelled") }),
@@ -3904,9 +4345,9 @@ function PixieTab({ actions, locale }) {
3904
4345
  void refresh();
3905
4346
  }, children: t("retry") }), children: loadError }) });
3906
4347
  if (!view) return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StudioSurface, { className: "studio-pixie", children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "studio-muted", children: t("loading") }) });
3907
- const record2 = view.record;
3908
- const opened = record2.threads.find((thread) => thread.id === openId);
3909
- const shown = opened ?? record2.threads.find((thread) => thread.id === record2.activeThreadId) ?? record2.threads.at(-1);
4348
+ const record3 = view.record;
4349
+ const opened = record3.threads.find((thread) => thread.id === openId);
4350
+ const shown = opened ?? record3.threads.find((thread) => thread.id === record3.activeThreadId) ?? record3.threads.at(-1);
3910
4351
  const running = live !== void 0 || view.running;
3911
4352
  const configured = Boolean(view.settings.model);
3912
4353
  const answering = (thread) => live?.threadId === thread.id || thread.turns.some((turn) => turn.status === "streaming");
@@ -3938,7 +4379,7 @@ function PixieTab({ actions, locale }) {
3938
4379
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "studio-pixie-list-head", children: [
3939
4380
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "studio-pixie-list-title", children: [
3940
4381
  t("allThreads"),
3941
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "studio-count", children: record2.threads.length })
4382
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "studio-count", children: record3.threads.length })
3942
4383
  ] }),
3943
4384
  configured && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(IconButton, { label: t("newThread"), onClick: () => setCreating((open) => !open), children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PlusIcon, {}) })
3944
4385
  ] }),
@@ -3960,14 +4401,14 @@ function PixieTab({ actions, locale }) {
3960
4401
  void createThread();
3961
4402
  }, children: t("create") })
3962
4403
  ] }),
3963
- record2.threads.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { role: "status", className: "studio-muted", children: t("noThreads") }),
3964
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("ul", { className: "studio-pixie-thread-list", "aria-label": t("threads"), children: [...record2.threads].reverse().map((thread) => {
4404
+ record3.threads.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { role: "status", className: "studio-muted", children: t("noThreads") }),
4405
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("ul", { className: "studio-pixie-thread-list", "aria-label": t("threads"), children: [...record3.threads].reverse().map((thread) => {
3965
4406
  const last = thread.id === live?.threadId && !thread.turns.some((turn) => turn.id === live.turnId) ? live.question : thread.turns.at(-1)?.question;
3966
4407
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("button", { type: "button", className: "studio-pixie-thread", "aria-current": thread.id === shown?.id ? "true" : void 0, onClick: () => setOpenId(thread.id), children: [
3967
4408
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "studio-card-head", children: [
3968
4409
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "studio-pixie-title", children: [
3969
4410
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("strong", { children: thread.title }),
3970
- thread.id === record2.activeThreadId && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "studio-pixie-pin", role: "img", "aria-label": t("activeBadge"), title: t("activeBadge"), children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PinIcon, { filled: true }) })
4411
+ thread.id === record3.activeThreadId && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "studio-pixie-pin", role: "img", "aria-label": t("activeBadge"), title: t("activeBadge"), children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PinIcon, { filled: true }) })
3971
4412
  ] }),
3972
4413
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ThreadBadges, { thread, answering: answering(thread), locale })
3973
4414
  ] }),
@@ -3982,15 +4423,15 @@ function PixieTab({ actions, locale }) {
3982
4423
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "studio-card-head", children: [
3983
4424
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { className: "studio-pixie-title", children: [
3984
4425
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("strong", { children: shown.title }),
3985
- /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "studio-pixie-pin-toggle", "data-target": shown.id === record2.activeThreadId, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
4426
+ /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "studio-pixie-pin-toggle", "data-target": shown.id === record3.activeThreadId, children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
3986
4427
  IconButton,
3987
4428
  {
3988
- label: shown.id === record2.activeThreadId ? t("activeBadge") : t("makeTarget"),
3989
- pressed: shown.id === record2.activeThreadId,
4429
+ label: shown.id === record3.activeThreadId ? t("activeBadge") : t("makeTarget"),
4430
+ pressed: shown.id === record3.activeThreadId,
3990
4431
  onClick: () => {
3991
- if (shown.id !== record2.activeThreadId) void target(shown);
4432
+ if (shown.id !== record3.activeThreadId) void target(shown);
3992
4433
  },
3993
- children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PinIcon, { filled: shown.id === record2.activeThreadId })
4434
+ children: /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(PinIcon, { filled: shown.id === record3.activeThreadId })
3994
4435
  }
3995
4436
  ) })
3996
4437
  ] }),
@@ -4098,7 +4539,7 @@ function PixieCommandRow({ question, outcome, locale, onOpen, actions }) {
4098
4539
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "studio-pixie-row-question", children: question }),
4099
4540
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Button, { small: true, onClick: onOpen, children: t("openTab") })
4100
4541
  ] }),
4101
- outcome?.kind === "error" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "studio-pixie-error", role: "alert", children: pixieError(locale, outcome.text ?? "") }) : turn?.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "studio-pixie-error", role: "alert", children: pixieError(locale, turn.error ?? "") }) : answer ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "studio-pixie-answer", children: answer }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "studio-muted", children: !outcome ? t("streaming") : status === "cancelled" ? t("cancelled") : loaded && !turn ? t("rowAsked") : t("rowWaiting") }),
4542
+ outcome?.kind === "error" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "studio-pixie-error", role: "alert", children: pixieError(locale, outcome.text ?? "") }) : turn?.status === "error" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "studio-pixie-error", role: "alert", children: pixieError(locale, turn.error ?? "") }) : answer ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ModelText, { text: answer, locale, streaming: live !== void 0 && !outcome }) : /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { className: "studio-muted", children: !outcome ? t("streaming") : status === "cancelled" ? t("cancelled") : loaded && !turn ? t("rowAsked") : t("rowWaiting") }),
4102
4543
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "studio-pixie-turn-meta", children: [
4103
4544
  status === "cancelled" && answer && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Badge, { tone: "neutral", children: t("cancelled") }),
4104
4545
  turn?.truncated && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Badge, { tone: "warning", children: t("truncated") })
@@ -4106,172 +4547,231 @@ function PixieCommandRow({ question, outcome, locale, onOpen, actions }) {
4106
4547
  ] });
4107
4548
  }
4108
4549
 
4109
- // src/pixie-settings.tsx
4110
- var import_react16 = __toESM(require("react"), 1);
4111
-
4112
- // src/pixie-gate-task-pages.tsx
4550
+ // src/pixie-gate-tail.tsx
4113
4551
  var import_react15 = __toESM(require("react"), 1);
4114
4552
 
4115
- // src/pixie-gate-task-locale.ts
4116
- var messages2 = {
4117
- composition: ["\uAC8C\uC774\uD2B8 \uAD6C\uC131", "Gate composition", "\u95E8\u63A7\u6784\u6210"],
4118
- scope: ["\uC801\uC6A9 \uBC94\uC704", "Scope", "\u9002\u7528\u8303\u56F4"],
4119
- scopeDescription: ["\uAC8C\uC774\uD2B8\uB97C \uCF1C\uACE0, \uC5B4\uB5A4 \uD504\uB9AC\uC14B\uC5D0 \uC801\uC6A9\uD560\uC9C0 \uC815\uD569\uB2C8\uB2E4.", "Turn gates on and choose the presets they apply to.", "\u542F\u7528\u95E8\u63A7\u5E76\u9009\u62E9\u9002\u7528\u7684\u9884\u8BBE\u3002"],
4120
- loading: ["\uAC8C\uC774\uD2B8\uB97C \uBD88\uB7EC\uC624\uB294 \uC911\u2026", "Loading gates\u2026", "\u6B63\u5728\u52A0\u8F7D\u95E8\u63A7\u2026"],
4121
- retry: ["\uB2E4\uC2DC \uC2DC\uB3C4", "Retry", "\u91CD\u8BD5"],
4122
- save: ["\uC800\uC7A5", "Save", "\u4FDD\u5B58"],
4123
- saving: ["\uC800\uC7A5 \uC911\u2026", "Saving\u2026", "\u6B63\u5728\u4FDD\u5B58\u2026"],
4124
- saved: ["\uC800\uC7A5\uB428", "Saved", "\u5DF2\u4FDD\u5B58"],
4125
- saveFailed: ["\uC800\uC7A5\uD558\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4", "Could not save", "\u65E0\u6CD5\u4FDD\u5B58"],
4126
- dismiss: ["\uB2EB\uAE30", "Dismiss", "\u5173\u95ED"],
4127
- unsaved: ["\uC800\uC7A5\uD558\uC9C0 \uC54A\uC740 \uBCC0\uACBD\uC774 \uC788\uC2B5\uB2C8\uB2E4. \uC800\uC7A5\uD574\uC57C \uC2E4\uD589\uC5D0 \uC801\uC6A9\uB429\uB2C8\uB2E4.", "Unsaved changes. Save to apply them to runs.", "\u6709\u672A\u4FDD\u5B58\u7684\u66F4\u6539\u3002\u4FDD\u5B58\u540E\u624D\u4F1A\u5E94\u7528\u4E8E\u8FD0\u884C\u3002"],
4128
- invalid: ["\uC77D\uC744 \uC218 \uC5C6\uB294 \uAC8C\uC774\uD2B8 {count}\uAC1C\uB294 \uD30C\uC77C\uC5D0 \uADF8\uB300\uB85C \uB450\uC5C8\uC2B5\uB2C8\uB2E4. \uC800\uC7A5\uD558\uBA74 \uC774 \uD56D\uBAA9\uC740 \uBE60\uC9D1\uB2C8\uB2E4: {reasons}", "{count} unreadable gates were left in the file. Saving drops them: {reasons}", "\u6709 {count} \u4E2A\u65E0\u6CD5\u8BFB\u53D6\u7684\u95E8\u63A7\u4FDD\u7559\u5728\u6587\u4EF6\u4E2D\u3002\u4FDD\u5B58\u540E\u5C06\u79FB\u9664\uFF1A{reasons}"],
4129
- newGate: ["\uC0C8 \uAC8C\uC774\uD2B8", "New gate", "\u65B0\u5EFA\u95E8\u63A7"],
4130
- empty: ["\uC544\uC9C1 \uAC8C\uC774\uD2B8\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uD15C\uD50C\uB9BF\uC5D0\uC11C \uC2DC\uC791\uD574 \uBCF4\uC138\uC694.", "No gates yet. Start from a template.", "\u5C1A\u65E0\u95E8\u63A7\u3002\u8BF7\u4ECE\u6A21\u677F\u5F00\u59CB\u3002"],
4131
- pickTemplate: ["\uBB34\uC5C7\uC744 \uD558\uACE0 \uC2F6\uB098\uC694?", "What should the gate do?", "\u4F60\u60F3\u8BA9\u95E8\u63A7\u505A\u4EC0\u4E48\uFF1F"],
4132
- pickHint: ["\uD15C\uD50C\uB9BF\uC744 \uACE8\uB77C \uBB38\uAD6C\uB97C \uC218\uC815\uD569\uB2C8\uB2E4.", "Pick a template, then adjust the wording.", "\u9009\u62E9\u6A21\u677F\u540E\u4FEE\u6539\u6587\u5B57\u5373\u53EF\u3002"],
4133
- blank: ["\uBE48 \uAC8C\uC774\uD2B8", "Blank gate", "\u7A7A\u767D\u95E8\u63A7"],
4134
- blankDescription: ["\uC5B8\uC81C \uC2E4\uD589\uD560\uC9C0\uC640 \uD560 \uC77C\uC744 \uC9C1\uC811 \uC815\uD569\uB2C8\uB2E4.", "Write when and what yourself.", "\u81EA\u884C\u586B\u5199\u65F6\u673A\u548C\u4EFB\u52A1\u3002"],
4135
- edit: ["\uD3B8\uC9D1", "Edit", "\u7F16\u8F91"],
4136
- duplicate: ["\uBCF5\uC81C", "Duplicate", "\u590D\u5236"],
4137
- delete: ["\uC0AD\uC81C", "Delete", "\u5220\u9664"],
4138
- close: ["\uB2EB\uAE30", "Close", "\u5173\u95ED"],
4139
- cancel: ["\uCDE8\uC18C", "Cancel", "\u53D6\u6D88"],
4140
- back: ["\uB4A4\uB85C", "Back", "\u8FD4\u56DE"],
4141
- apply: ["\uC801\uC6A9", "Apply", "\u5E94\u7528"],
4142
- applyHint: ["\uC801\uC6A9 \uD6C4 \uD398\uC774\uC9C0\uC5D0\uC11C \uC800\uC7A5\uD574\uC57C \uC2E4\uD589\uC5D0 \uBC18\uC601\uB429\uB2C8\uB2E4.", "After applying, press Save on the page to use it in runs.", "\u5E94\u7528\u540E\u9700\u5728\u9875\u9762\u4E0A\u70B9\u51FB\u4FDD\u5B58\u624D\u4F1A\u7528\u4E8E\u8FD0\u884C\u3002"],
4143
- on: ["\uCF1C\uC9D0", "On", "\u5F00\u542F"],
4144
- off: ["\uAEBC\uC9D0", "Off", "\u5173\u95ED"],
4145
- presetCount: ["\uD504\uB9AC\uC14B {count}\uAC1C", "{count} presets", "{count} \u4E2A\u9884\u8BBE"],
4146
- noPreset: ["\uD504\uB9AC\uC14B \uC5C6\uC74C", "No preset", "\u65E0\u9884\u8BBE"],
4147
- sentence: ["{when} \u2192 {what}", "{when} \u2192 {what}", "{when} \u2192 {what}"],
4148
- name: ["\uC774\uB984", "Name", "\u540D\u79F0"],
4149
- when: ["\uC5B8\uC81C", "When", "\u4F55\u65F6"],
4150
- what: ["Pixie\uC5D0\uAC8C \uBCF4\uB0BC \uB0B4\uC6A9", "What to send Pixie", "\u53D1\u9001\u7ED9 Pixie \u7684\u5185\u5BB9"],
4151
- whatHint: ["Pixie\uAC00 \uC774 \uB0B4\uC6A9\uC744 \uBCF4\uACE0 \uAC8C\uC774\uD2B8 \uACB0\uACFC\uB97C \uC815\uD569\uB2C8\uB2E4. \uACB0\uACFC \uC885\uB958\uB294 \uAC00\uC774\uB4DC\uB97C \uCC38\uACE0\uD558\uC138\uC694.", "Pixie checks the content and decides the gate result. See the guide for details on results.", "Pixie \u68C0\u67E5\u5185\u5BB9\u5E76\u51B3\u5B9A\u95E8\u63A7\u7ED3\u679C\u3002\u7ED3\u679C\u8BE6\u60C5\u8BF7\u53C2\u9605\u6307\u5357\u3002"],
4152
- "out-verdict": ["\uACB0\uB860", "Verdict", "\u7ED3\u8BBA"],
4153
- "out-reason": ["\uC774\uC720", "Reason", "\u539F\u56E0"],
4154
- "out-replace": ["\uBC14\uAFC0 \uB0B4\uC6A9", "Replacement", "\u66FF\u6362\u5185\u5BB9"],
4155
- "out-append": ["\uB367\uBD99\uC77C \uB0B4\uC6A9", "Addition", "\u8FFD\u52A0\u5185\u5BB9"],
4156
- "out-note": ["\uBA54\uBAA8", "Note", "\u5907\u6CE8"],
4157
- // when options
4158
- "when-user-message": ["\uC0AC\uC6A9\uC790\uAC00 \uC9C0\uC2DC\uB97C \uBCF4\uB0BC \uB54C", "When you send an instruction", "\u5F53\u4F60\u53D1\u9001\u6307\u4EE4\u65F6"],
4159
- "when-agent-message": ["\uC5D0\uC774\uC804\uD2B8\uB07C\uB9AC \uBA54\uC2DC\uC9C0\uB97C \uC8FC\uACE0\uBC1B\uC744 \uB54C", "When agents message each other", "\u5F53\u4EE3\u7406\u4E4B\u95F4\u4E92\u53D1\u6D88\u606F\u65F6"],
4160
- "when-tool-before": ["\uB3C4\uAD6C\uB97C \uC2E4\uD589\uD558\uAE30 \uC804", "Before a tool runs", "\u5DE5\u5177\u8FD0\u884C\u524D"],
4161
- "when-tool-after": ["\uB3C4\uAD6C \uACB0\uACFC\uAC00 \uB098\uC654\uC744 \uB54C", "When a tool result arrives", "\u5DE5\u5177\u7ED3\u679C\u8FD4\u56DE\u65F6"],
4162
- "when-turn-end": ["\uC5D0\uC774\uC804\uD2B8 \uB2F5\uBCC0\uC774 \uB05D\uB0AC\uC744 \uB54C", "When the agent finishes its answer", "\u4EE3\u7406\u5B8C\u6210\u56DE\u7B54\u65F6"],
4163
- "target-user-message": ["\uBCF4\uB0B8 \uC9C0\uC2DC", "your instruction", "\u4F60\u53D1\u9001\u7684\u6307\u4EE4"],
4164
- "target-agent-message": ["\uC8FC\uACE0\uBC1B\uB294 \uBA54\uC2DC\uC9C0", "the message between agents", "\u4EE3\u7406\u4E4B\u95F4\u7684\u6D88\u606F"],
4165
- "target-tool-before": ["\uB3C4\uAD6C \uD638\uCD9C \uB0B4\uC6A9", "the tool call", "\u5DE5\u5177\u8C03\u7528\u5185\u5BB9"],
4166
- "target-tool-after": ["\uB3C4\uAD6C \uACB0\uACFC", "the tool result", "\u5DE5\u5177\u7ED3\u679C"],
4167
- "target-turn-end": ["\uB9C8\uC9C0\uB9C9 \uB2F5\uBCC0", "the final answer", "\u6700\u540E\u7684\u56DE\u7B54"],
4168
- // advanced
4169
- advanced: ["\uACE0\uAE09", "Advanced", "\u9AD8\u7EA7"],
4170
- script: ["Pixie \uD6C5 \uC2A4\uD06C\uB9BD\uD2B8", "Pixie hook script", "Pixie \u94A9\u5B50\u811A\u672C"],
4171
- scriptHint: ["Pixie\uC5D0\uAC8C \uC9C0\uC2DC\uD558\uAE30 \uC804\uC5D0 \uC2E4\uD589\uD560 \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uACE0\uB985\uB2C8\uB2E4. \uC2A4\uD06C\uB9BD\uD2B8 \uACB0\uACFC\uB97C Pixie\uC5D0\uAC8C \uB118\uAE38 \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "The script to run before instructing Pixie. Its output can be passed to Pixie.", "\u6307\u5B9A\u5728\u5411 Pixie \u53D1\u51FA\u6307\u4EE4\u524D\u8FD0\u884C\u7684\u811A\u672C\u3002\u811A\u672C\u7ED3\u679C\u53EF\u4F20\u9012\u7ED9 Pixie\u3002"],
4172
- guideLink: ["\uC2A4\uD06C\uB9BD\uD2B8 \uC791\uC131 \uAC00\uC774\uB4DC", "script guide", "\u811A\u672C\u7F16\u5199\u6307\u5357"],
4173
- resultGuide: ["\uAC00\uC774\uB4DC", "Guide", "\u6307\u5357"],
4174
- scriptEnv: ["DSH\uC5D0\uC11C bash \uD504\uB85C\uD544\uC744 \uC9C0\uC6D0\uD560 \uB54C\uB9CC \uC0AC\uC6A9\uD560 \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Available only when DSH runs with a bash profile.", "\u4EC5\u5728 DSH \u652F\u6301 bash \u914D\u7F6E\u6587\u4EF6\u65F6\u53EF\u7528\u3002"],
4175
- noScript: ["\uC0AC\uC6A9 \uC548 \uD568", "None", "\u4E0D\u4F7F\u7528"],
4176
- scriptDir: ["\uC2A4\uD06C\uB9BD\uD2B8 \uD3F4\uB354", "Script folder", "\u811A\u672C\u6587\u4EF6\u5939"],
4177
- copyPath: ["\uACBD\uB85C \uBCF5\uC0AC", "Copy path", "\u590D\u5236\u8DEF\u5F84"],
4178
- refresh: ["\uBAA9\uB85D \uC0C8\uB85C\uACE0\uCE68", "Refresh list", "\u5237\u65B0\u5217\u8868"],
4179
- openFolder: ["\uD3F4\uB354 \uC5F4\uAE30", "Open folder", "\u6253\u5F00\u6587\u4EF6\u5939"],
4180
- openFailed: ["\uD3F4\uB354\uB97C \uC5F4\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4", "Could not open the folder", "\u65E0\u6CD5\u6253\u5F00\u6587\u4EF6\u5939"],
4181
- presetsTitle: ["Studio \uD504\uB9AC\uC14B", "Studio presets", "Studio \u9884\u8BBE"],
4182
- presetsTitleHint: ["Studio \uD504\uB9AC\uC14B\uB9C8\uB2E4 \uC801\uC6A9\uD560 \uAC8C\uC774\uD2B8\uB97C \uACE0\uB985\uB2C8\uB2E4. \uAC19\uC740 \uAC8C\uC774\uD2B8\uB97C \uC5EC\uB7EC \uD504\uB9AC\uC14B\uC5D0 \uC801\uC6A9\uD558\uACE0 \uAC01\uAC01 \uCF1C\uAC70\uB098 \uB04C \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "Choose the gates for each preset made in Studio. A gate can be added to several presets, and each preset switches it on or off on its own.", "\u4E3A Studio \u521B\u5EFA\u7684\u6BCF\u4E2A\u9884\u8BBE\u9009\u62E9\u95E8\u63A7\u3002\u540C\u4E00\u95E8\u63A7\u53EF\u52A0\u5165\u591A\u4E2A\u9884\u8BBE\uFF0C\u5404\u9884\u8BBE\u5355\u72EC\u5F00\u5173\u3002"],
4183
- noStudioPresets: ["Studio\uC5D0\uC11C \uB9CC\uB4E0 \uD504\uB9AC\uC14B\uC774 \uC5C6\uC2B5\uB2C8\uB2E4. \uD504\uB9AC\uC14B \uBA54\uB274\uC5D0\uC11C \uBA3C\uC800 \uB9CC\uB4DC\uC138\uC694.", "No presets made in Studio yet. Create one under Presets first.", "\u5C1A\u65E0 Studio \u521B\u5EFA\u7684\u9884\u8BBE\u3002\u8BF7\u5148\u5728\u9884\u8BBE\u83DC\u5355\u4E2D\u521B\u5EFA\u3002"],
4184
- addGate: ["\uAC8C\uC774\uD2B8 \uCD94\uAC00", "Add gate", "\u6DFB\u52A0\u95E8\u63A7"],
4185
- addGateTo: ["{preset}\uC5D0 \uAC8C\uC774\uD2B8 \uCD94\uAC00", "Add a gate to {preset}", "\u5411 {preset} \u6DFB\u52A0\u95E8\u63A7"],
4186
- noGateToAdd: ["\uCD94\uAC00\uD560 \uAC8C\uC774\uD2B8\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4. \uAC8C\uC774\uD2B8 \uAD6C\uC131\uC5D0\uC11C \uBA3C\uC800 \uB9CC\uB4DC\uC138\uC694.", "No gate to add. Create one in Gate composition first.", "\u6CA1\u6709\u53EF\u6DFB\u52A0\u7684\u95E8\u63A7\u3002\u8BF7\u5148\u5728\u95E8\u63A7\u6784\u6210\u4E2D\u521B\u5EFA\u3002"],
4187
- noGatesInPreset: ["\uC774 \uD504\uB9AC\uC14B\uC5D0 \uAC74 \uAC8C\uC774\uD2B8\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4.", "No gates on this preset.", "\u6B64\u9884\u8BBE\u6CA1\u6709\u95E8\u63A7\u3002"],
4188
- removeFromPreset: ["\uD504\uB9AC\uC14B\uC5D0\uC11C \uBE7C\uAE30", "Remove from preset", "\u4ECE\u9884\u8BBE\u79FB\u9664"],
4189
- gateOff: ["\uC804\uCCB4 \uAEBC\uC9D0 \xB7 \uAC8C\uC774\uD2B8 \uAD6C\uC131\uC5D0\uC11C \uCF1C\uAE30", "The gate is off everywhere (turn it on in Gate composition)", "\u8BE5\u95E8\u63A7\u5DF2\u5168\u5C40\u5173\u95ED\uFF08\u5728\u95E8\u63A7\u6784\u6210\u4E2D\u5F00\u542F\uFF09"],
4190
- gateEnabled: ["\uAC8C\uC774\uD2B8 \uCF1C\uC9D0", "Gate on", "\u95E8\u63A7\u5F00\u542F"],
4191
- gateEnabledHint: ["\uB044\uBA74 \uBAA8\uB4E0 \uD504\uB9AC\uC14B\uC5D0\uC11C \uBA48\uCDA5\uB2C8\uB2E4. \uC801\uC6A9 \uBC94\uC704\uC5D0\uC11C \uD504\uB9AC\uC14B\uBCC4\uB85C \uCF1C\uAC70\uB098 \uB055\uB2C8\uB2E4.", "Off stops it on every preset. Switch it per preset under Scope.", "\u5173\u95ED\u540E\u5728\u6240\u6709\u9884\u8BBE\u4E0A\u505C\u6B62\u3002\u6309\u9884\u8BBE\u5F00\u5173\u8BF7\u5728\u9002\u7528\u8303\u56F4\u4E2D\u8BBE\u7F6E\u3002"],
4192
- folderTitle: ["\uC2A4\uD06C\uB9BD\uD2B8 \uD3F4\uB354", "Script folder", "\u811A\u672C\u6587\u4EF6\u5939"],
4193
- folderHint: ["\uD6C5 \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uCC3E\uB294 \uD3F4\uB354\uC785\uB2C8\uB2E4. \uC808\uB300 \uACBD\uB85C\uB098 ~/ \uACBD\uB85C\uB97C \uC4F0\uACE0, \uBE44\uC6B0\uBA74 \uAE30\uBCF8 \uD3F4\uB354\uB97C \uC501\uB2C8\uB2E4.", "The folder hook scripts are found in. Use an absolute or ~/ path; leave empty for the default.", "\u67E5\u627E\u94A9\u5B50\u811A\u672C\u7684\u6587\u4EF6\u5939\u3002\u8BF7\u4F7F\u7528\u7EDD\u5BF9\u8DEF\u5F84\u6216 ~/ \u8DEF\u5F84\uFF0C\u7559\u7A7A\u5219\u4F7F\u7528\u9ED8\u8BA4\u6587\u4EF6\u5939\u3002"],
4194
- folderDefault: ["\uAE30\uBCF8 \uD3F4\uB354", "Default folder", "\u9ED8\u8BA4\u6587\u4EF6\u5939"],
4195
- folderCurrent: ["\uD604\uC7AC \uD3F4\uB354", "Current folder", "\u5F53\u524D\u6587\u4EF6\u5939"],
4196
- folderCount: ["\uC2A4\uD06C\uB9BD\uD2B8 {count}\uAC1C", "{count} scripts", "{count} \u4E2A\u811A\u672C"],
4197
- folderApply: ["\uD3F4\uB354 \uC801\uC6A9", "Use folder", "\u4F7F\u7528\u6587\u4EF6\u5939"],
4198
- folderReset: ["\uAE30\uBCF8\uAC12\uC73C\uB85C", "Use default", "\u6062\u590D\u9ED8\u8BA4"],
4199
- folderFailed: ["\uD3F4\uB354\uB97C \uBC14\uAFB8\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4", "Could not change the folder", "\u65E0\u6CD5\u66F4\u6539\u6587\u4EF6\u5939"],
4200
- gateCount: ["\uAC8C\uC774\uD2B8 {count}\uAC1C \xB7 \uCF1C\uC9D0 {on}\uAC1C", "{count} gates \xB7 {on} on", "{count} \u4E2A\u95E8\u63A7 \xB7 \u542F\u7528 {on} \u4E2A"],
4201
- unknownPreset: ["(\uC5C6\uB294 \uD504\uB9AC\uC14B)", "(missing preset)", "\uFF08\u9884\u8BBE\u4E0D\u5B58\u5728\uFF09"],
4202
- conflict: ["\uAC19\uC740 \uC2DC\uC810\uC5D0 \uCF1C\uC9C4 \uAC8C\uC774\uD2B8\uAC00 \uB458 \uC774\uC0C1\uC785\uB2C8\uB2E4", "More than one enabled gate at this moment", "\u540C\u4E00\u65F6\u673A\u542F\u7528\u4E86\u591A\u4E2A\u95E8\u63A7"],
4203
- editPresets: ["\uD504\uB9AC\uC14B", "Presets", "\u9884\u8BBE"],
4204
- scriptMissing: ["(\uD3F4\uB354\uC5D0 \uC5C6\uC74C)", "(not in folder)", "\uFF08\u6587\u4EF6\u5939\u4E2D\u4E0D\u5B58\u5728\uFF09"],
4205
- scriptUnsupported: ["\uC774 \uD658\uACBD\uC5D0\uC11C\uB294 \uD6C5 \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uC9C0\uC6D0\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.", "Hook scripts are not supported in this environment.", "\u6B64\u73AF\u5883\u4E0D\u652F\u6301\u94A9\u5B50\u811A\u672C\u3002"],
4206
- scriptsFailed: ["\uC2A4\uD06C\uB9BD\uD2B8 \uBAA9\uB85D\uC744 \uC77D\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4", "Could not list scripts", "\u65E0\u6CD5\u8BFB\u53D6\u811A\u672C\u5217\u8868"],
4207
- scriptShell: ["\uC790\uC138\uD55C \uC2A4\uD06C\uB9BD\uD2B8 \uADDC\uCE59\uC740 {link}\uC5D0\uC11C \uBCFC \uC218 \uC788\uC2B5\uB2C8\uB2E4.", "See the {link} for the full script rules.", "\u5B8C\u6574\u7684\u811A\u672C\u89C4\u5219\u8BF7\u53C2\u9605{link}\u3002"],
4208
- variables: ["Pixie \uD6C5 \uACB0\uACFC\uB85C \uC4F8 \uC218 \uC788\uB294 \uAC12", "Values from the Pixie hook result", "\u53EF\u7528\u4F5C Pixie \u94A9\u5B50\u7ED3\u679C\u7684\u503C"],
4209
- "var-text": ["\uC2A4\uD06C\uB9BD\uD2B8 \uCD9C\uB825 \uD14D\uC2A4\uD2B8", "script output text", "\u811A\u672C\u8F93\u51FA\u6587\u672C"],
4210
- "var-data": ["\uC2A4\uD06C\uB9BD\uD2B8 \uCD9C\uB825 \uB370\uC774\uD130(JSON)", "script output data (JSON)", "\u811A\u672C\u8F93\u51FA\u6570\u636E\uFF08JSON\uFF09"],
4211
- confirmReplace: ["\uBC14\uAFB8\uAE30 \uC804\uC5D0 \uD655\uC778", "Confirm before replacing", "\u66FF\u6362\u524D\u786E\u8BA4"],
4212
- confirmReplaceHint: ["\uBC14\uAFC0 \uB0B4\uC6A9\uC744 \uBC14\uB85C \uBCF4\uB0B4\uC9C0 \uC54A\uACE0 Pixie \uCE74\uB4DC\uC5D0\uC11C \uD655\uC778 \uD6C4 \uBCF4\uB0C5\uB2C8\uB2E4.", "Holds the replacement on a Pixie card until you confirm.", "\u66FF\u6362\u5185\u5BB9\u5148\u4FDD\u7559\u5728 Pixie \u5361\u7247\uFF0C\u786E\u8BA4\u540E\u518D\u53D1\u9001\u3002"],
4213
- onError: ["Pixie\uAC00 \uC2E4\uD328\uD558\uBA74", "If Pixie fails", "\u82E5 Pixie \u5931\u8D25"],
4214
- errorPass: ["\uADF8\uB300\uB85C \uC9C4\uD589", "Continue as usual", "\u7167\u5E38\u7EE7\u7EED"],
4215
- errorBlock: ["\uB9C9\uC74C", "Stop it", "\u62E6\u4E0B"],
4216
- agents: ["\uB300\uC0C1 \uC5D0\uC774\uC804\uD2B8", "Target agents", "\u76EE\u6807\u4EE3\u7406"],
4217
- root: ["\uBA54\uC778 \uC5D0\uC774\uC804\uD2B8", "Main agent", "\u4E3B\u4EE3\u7406"],
4218
- child: ["\uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8", "Subagents", "\u5B50\u4EE3\u7406"],
4219
- any: ["\uBAA8\uB450", "All", "\u5168\u90E8"],
4220
- timeout: ["\uC81C\uD55C \uC2DC\uAC04 (\uCD08)", "Time limit (seconds)", "\u65F6\u9650\uFF08\u79D2\uFF09"],
4221
- maxSteers: ["\uD134\uB2F9 \uB2E4\uC2DC \uD558\uAE30 \uCD5C\uB300 \uD69F\uC218", "Redo limit per turn", "\u6BCF\u8F6E\u91CD\u505A\u4E0A\u9650"],
4222
- // trial
4223
- trial: ["\uAC8C\uC774\uD2B8 \uD14C\uC2A4\uD2B8", "Gate test", "\u95E8\u63A7\u6D4B\u8BD5"],
4224
- trialSample: ["\uC608\uC2DC {target}", "Sample {target}", "\u793A\u4F8B{target}"],
4225
- trialRun: ["\uC2E4\uD589", "Run", "\u8FD0\u884C"],
4226
- trialPreview: ["\uC124\uC815\uD55C Pixie \uBAA8\uB378\uC744 \uC2E4\uC81C\uB85C \uD638\uCD9C\uD569\uB2C8\uB2E4. \uAE30\uB85D\uC744 \uB0A8\uAE30\uAC70\uB098 \uC138\uC158\uC5D0 \uBCF4\uB0B4\uC9C0\uB294 \uC54A\uC2B5\uB2C8\uB2E4.", "Calls the configured Pixie model. Nothing is recorded or sent to a session.", "\u4F1A\u5B9E\u9645\u8C03\u7528\u5DF2\u914D\u7F6E\u7684 Pixie \u6A21\u578B\uFF0C\u4E0D\u4F1A\u8BB0\u5F55\u6216\u53D1\u9001\u5230\u4F1A\u8BDD\u3002"],
4227
- trialScript: ["\uAC8C\uC774\uD2B8 \uD14C\uC2A4\uD2B8\uC5D0\uC11C\uB294 \uC2A4\uD06C\uB9BD\uD2B8\uB97C \uC2E4\uD589\uD558\uC9C0 \uC54A\uC2B5\uB2C8\uB2E4.", "Gate tests do not run the script.", "\u95E8\u63A7\u6D4B\u8BD5\u4E0D\u4F1A\u8FD0\u884C\u811A\u672C\u3002"],
4228
- trialTool: ["\uC608\uC2DC \uB3C4\uAD6C \uC774\uB984 (\uC120\uD0DD)", "Sample tool name (optional)", "\u793A\u4F8B\u5DE5\u5177\u540D\u79F0\uFF08\u53EF\u9009\uFF09"],
4229
- trialRunning: ["\uC2E4\uD589 \uC911\u2026", "Running\u2026", "\u8FD0\u884C\u4E2D\u2026"],
4230
- trialCancel: ["\uCDE8\uC18C", "Cancel", "\u53D6\u6D88"],
4231
- trialFailed: ["\uC2DC\uD5D8 \uC2E4\uD589 \uC2E4\uD328", "Trial failed", "\u8BD5\u8FD0\u884C\u5931\u8D25"],
4232
- trialUsage: ["\uD1A0\uD070 \uC785\uB825 {input} \xB7 \uCD9C\uB825 {output}", "Tokens in {input} \xB7 out {output}", "\u4EE4\u724C \u8F93\u5165 {input} \xB7 \u8F93\u51FA {output}"],
4233
- trialApplied: ["\uC2E4\uC81C \uC801\uC6A9", "What happens", "\u5B9E\u9645\u6548\u679C"],
4234
- "plan-stop": ["\uB9C9\uC74C", "Stopped", "\u5DF2\u62E6\u4E0B"],
4235
- "plan-confirm": ["\uAD50\uCCB4 \uC804 \uD655\uC778\uC744 \uC694\uCCAD\uD568", "Asks before replacing", "\u66FF\u6362\u524D\u8BF7\u6C42\u786E\u8BA4"],
4236
- "plan-replace": ["\uB0B4\uC6A9\uC744 \uBC14\uAFC8", "Replaces the content", "\u66FF\u6362\u5185\u5BB9"],
4237
- "plan-append": ["\uB0B4\uC6A9\uC744 \uB367\uBD99\uC784", "Adds content", "\u8FFD\u52A0\u5185\u5BB9"],
4238
- "plan-pass": ["\uADF8\uB300\uB85C \uD1B5\uACFC", "Passes unchanged", "\u539F\u6837\u901A\u8FC7"],
4239
- trialPass: ["\uD1B5\uACFC", "Pass", "\u901A\u8FC7"],
4240
- trialStop: ["\uB9C9\uC74C", "Stopped", "\u5DF2\u62E6\u4E0B"],
4241
- trialEmpty: ["(\uBE44\uC5B4 \uC788\uC74C)", "(empty)", "\uFF08\u7A7A\uFF09"],
4242
- // problems
4243
- "problem-name": ["\uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694.", "Enter a name.", "\u8BF7\u8F93\u5165\u540D\u79F0\u3002"],
4244
- "problem-instruction": ["Pixie\uAC00 \uD560 \uC77C\uC744 \uC785\uB825\uD558\uC138\uC694.", "Describe what Pixie should do.", "\u8BF7\u586B\u5199 Pixie \u7684\u4EFB\u52A1\u3002"],
4245
- "problem-limits": ["\uC81C\uD55C \uC2DC\uAC04\uACFC \uC0C1\uD55C\uC744 \uD655\uC778\uD558\uC138\uC694.", "Check the time limit and redo limit.", "\u8BF7\u68C0\u67E5\u65F6\u9650\u548C\u4E0A\u9650\u3002"],
4246
- // scope
4247
- enabled: ["\uCF1C\uC9D0", "Enabled", "\u542F\u7528"],
4248
- presets: ["\uC801\uC6A9 \uD504\uB9AC\uC14B", "Presets", "\u9002\u7528\u9884\u8BBE"],
4249
- presetsHint: ["\uC774 \uD504\uB9AC\uC14B\uC73C\uB85C \uC2E4\uD589\uB418\uB294 \uC5D0\uC774\uC804\uD2B8\uC5D0\uB9CC \uAC8C\uC774\uD2B8\uAC00 \uAC78\uB9BD\uB2C8\uB2E4.", "The gate runs only for agents using these presets.", "\u95E8\u63A7\u53EA\u4F5C\u7528\u4E8E\u4F7F\u7528\u8FD9\u4E9B\u9884\u8BBE\u7684\u4EE3\u7406\u3002"],
4250
- choosePresets: ["\uD504\uB9AC\uC14B \uC120\uD0DD", "Choose presets", "\u9009\u62E9\u9884\u8BBE"],
4251
- searchPresets: ["\uD504\uB9AC\uC14B \uAC80\uC0C9", "Search presets", "\u641C\u7D22\u9884\u8BBE"],
4252
- done: ["\uC644\uB8CC", "Done", "\u5B8C\u6210"],
4253
- scopeEmpty: ["\uAC8C\uC774\uD2B8 \uAD6C\uC131\uC5D0\uC11C \uBA3C\uC800 \uAC8C\uC774\uD2B8\uB97C \uB9CC\uB4DC\uC138\uC694.", "Create a gate in Gate composition first.", "\u8BF7\u5148\u5728\u95E8\u63A7\u6784\u6210\u4E2D\u521B\u5EFA\u95E8\u63A7\u3002"],
4254
- // templates
4255
- "tpl-format-check": ["\uC791\uC5C5 \uC9C0\uC2DC \uC591\uC2DD \uAC80\uC0AC", "Instruction format check", "\u4EFB\u52A1\u6307\u4EE4\u683C\u5F0F\u68C0\u67E5"],
4256
- "tplDesc-format-check": ["\uC9C0\uC2DC\uC5D0 \uBAA9\uD45C\xB7\uBC94\uC704\xB7\uC644\uB8CC \uC870\uAC74\uC774 \uC788\uB294\uC9C0 \uBCF4\uACE0, \uBE60\uC9C0\uBA74 \uB3CC\uB824\uBCF4\uB0C5\uB2C8\uB2E4.", "Checks that an instruction has a goal, scope, and done criteria; sends it back if not.", "\u68C0\u67E5\u6307\u4EE4\u662F\u5426\u5305\u542B\u76EE\u6807\u3001\u8303\u56F4\u548C\u5B8C\u6210\u6761\u4EF6\uFF0C\u7F3A\u5C11\u5219\u9000\u56DE\u3002"],
4257
- "tplText-format-check": ["\uC774 \uC9C0\uC2DC\uC5D0 \uBAA9\uD45C, \uBC94\uC704, \uC644\uB8CC \uC870\uAC74\uC774 \uBAA8\uB450 \uC788\uB294\uC9C0 \uD655\uC778\uD574.\n\uBE60\uC9C4 \uD56D\uBAA9\uC774 \uC788\uC73C\uBA74 \uB9C9\uACE0, \uBB34\uC5C7\uC774 \uBE60\uC84C\uB294\uC9C0 \uC774\uC720\uC5D0 \uC4F0\uACE0, \uC591\uC2DD\uC5D0 \uB9DE\uAC8C \uB2E4\uC2DC \uC4F4 \uC9C0\uC2DC\uB97C \uBC14\uAFC0 \uB0B4\uC6A9\uC5D0 \uB123\uC5B4.", "Check that this instruction has a goal, scope, and done criteria.\nIf any is missing, stop it, list what is missing as the reason, and put a rewritten instruction in the replacement.", "\u68C0\u67E5\u8BE5\u6307\u4EE4\u662F\u5426\u5305\u542B\u76EE\u6807\u3001\u8303\u56F4\u548C\u5B8C\u6210\u6761\u4EF6\u3002\n\u82E5\u7F3A\u5C11\uFF0C\u8BF7\u62E6\u4E0B\uFF0C\u5728\u539F\u56E0\u4E2D\u5199\u660E\u7F3A\u5C11\u9879\uFF0C\u5E76\u628A\u6539\u5199\u540E\u7684\u6307\u4EE4\u653E\u5165\u66FF\u6362\u5185\u5BB9\u3002"],
4258
- "tpl-agent-protocol": ["\uC5D0\uC774\uC804\uD2B8 \uB300\uD654 \uADDC\uACA9 \uD310\uC815", "Agent message protocol", "\u4EE3\u7406\u6D88\u606F\u89C4\u8303\u5224\u5B9A"],
4259
- "tplDesc-agent-protocol": ["\uC5D0\uC774\uC804\uD2B8\uB07C\uB9AC \uC8FC\uACE0\uBC1B\uB294 \uBA54\uC2DC\uC9C0\uAC00 \uC815\uD574\uC9C4 \uADDC\uACA9\uC744 \uB530\uB974\uB294\uC9C0 \uD310\uC815\uD569\uB2C8\uB2E4.", "Checks that messages between agents follow the agreed format.", "\u5224\u5B9A\u4EE3\u7406\u4E4B\u95F4\u7684\u6D88\u606F\u662F\u5426\u9075\u5FAA\u7EA6\u5B9A\u683C\u5F0F\u3002"],
4260
- "tplText-agent-protocol": ['\uC774 \uBA54\uC2DC\uC9C0\uAC00 "\uC791\uC5C5 / \uADFC\uAC70 / \uB2E4\uC74C \uD589\uB3D9" \uC138 \uBD80\uBD84\uC744 \uAC16\uCDC4\uB294\uC9C0 \uD655\uC778\uD574.\n\uAC16\uCD94\uC9C0 \uC54A\uC558\uC73C\uBA74 \uB9C9\uACE0 \uC774\uC720\uC5D0 \uBB34\uC5C7\uC774 \uBE60\uC84C\uB294\uC9C0 \uC368.', "Check that this message has three parts: task, evidence, next action.\nIf not, stop it and give what is missing as the reason.", "\u68C0\u67E5\u8BE5\u6D88\u606F\u662F\u5426\u5305\u542B\u201C\u4EFB\u52A1 / \u4F9D\u636E / \u4E0B\u4E00\u6B65\u201D\u4E09\u90E8\u5206\u3002\n\u82E5\u4E0D\u5B8C\u6574\uFF0C\u8BF7\u62E6\u4E0B\u5E76\u5728\u539F\u56E0\u4E2D\u5199\u660E\u7F3A\u5C11\u7684\u90E8\u5206\u3002"],
4261
- "tpl-command-guard": ["\uC704\uD5D8\uD55C \uBA85\uB839 \uCC28\uB2E8", "Block risky commands", "\u62E6\u622A\u5371\u9669\u547D\u4EE4"],
4262
- "tplDesc-command-guard": ["\uC2E4\uD589 \uC804 \uB3C4\uAD6C \uD638\uCD9C\uC744 \uD655\uC778\uD558\uACE0, \uB418\uB3CC\uB9AC\uAE30 \uC5B4\uB824\uC6B4 \uC791\uC5C5\uC774\uBA74 \uC774\uC720\uC640 \uD568\uAED8 \uB9C9\uC2B5\uB2C8\uB2E4.", "Reviews a tool call before it runs and stops it, with a reason, if it is hard to undo.", "\u5728\u5DE5\u5177\u8FD0\u884C\u524D\u68C0\u67E5\u8C03\u7528\uFF0C\u82E5\u96BE\u4EE5\u64A4\u9500\u5219\u62E6\u4E0B\u5E76\u8BF4\u660E\u539F\u56E0\u3002"],
4263
- "tplText-command-guard": ["\uC774 \uB3C4\uAD6C \uD638\uCD9C\uC774 \uD30C\uC77C\uC744 \uB300\uB7C9\uC73C\uB85C \uC9C0\uC6B0\uAC70\uB098, \uC791\uC5C5 \uACF5\uAC04 \uBC16\uC744 \uBC14\uAFB8\uAC70\uB098, \uAC15\uC81C \uD478\uC2DC\uCC98\uB7FC \uB418\uB3CC\uB9AC\uAE30 \uC5B4\uB824\uC6B4 \uC791\uC5C5\uC778\uC9C0 \uD655\uC778\uD574.\n\uADF8\uB807\uB2E4\uBA74 \uB9C9\uACE0, \uBB34\uC5C7\uC774 \uC704\uD5D8\uD55C\uC9C0\uC640 \uB354 \uC548\uC804\uD55C \uBC29\uBC95\uC744 \uC774\uC720\uC5D0 \uC368. \uC544\uB2C8\uBA74 \uC544\uBB34\uAC83\uB3C4 \uD558\uC9C0 \uB9C8.", "Check whether this tool call does something hard to undo, such as deleting many files, changing things outside the workspace, or a force push.\nIf so, stop it and give the risk and a safer approach as the reason. Otherwise do nothing.", "\u68C0\u67E5\u8BE5\u5DE5\u5177\u8C03\u7528\u662F\u5426\u96BE\u4EE5\u64A4\u9500\uFF0C\u4F8B\u5982\u5927\u91CF\u5220\u9664\u6587\u4EF6\u3001\u4FEE\u6539\u5DE5\u4F5C\u533A\u4E4B\u5916\u7684\u5185\u5BB9\u6216\u5F3A\u5236\u63A8\u9001\u3002\n\u82E5\u662F\uFF0C\u8BF7\u62E6\u4E0B\u5E76\u5728\u539F\u56E0\u4E2D\u5199\u660E\u98CE\u9669\u548C\u66F4\u5B89\u5168\u7684\u505A\u6CD5\u3002\u5426\u5219\u4E0D\u505A\u4EFB\u4F55\u4E8B\u3002"],
4264
- "tpl-tool-digest": ["\uAE34 \uB3C4\uAD6C \uACB0\uACFC \uC694\uC57D", "Digest long tool results", "\u6982\u62EC\u5197\u957F\u7684\u5DE5\u5177\u7ED3\u679C"],
4265
- "tplDesc-tool-digest": ["\uB3C4\uAD6C \uACB0\uACFC\uAC00 \uAE38\uBA74 \uD604\uC7AC \uC791\uC5C5\uACFC \uAD00\uB828 \uC788\uB294 \uB0B4\uC6A9\uB9CC \uACE8\uB77C \uC5D0\uC774\uC804\uD2B8\uC5D0\uAC8C \uC90D\uB2C8\uB2E4.", "When a tool result is long, gives the agent only what matters to the current task.", "\u5DE5\u5177\u7ED3\u679C\u8FC7\u957F\u65F6\uFF0C\u53EA\u628A\u4E0E\u5F53\u524D\u4EFB\u52A1\u76F8\u5173\u7684\u5185\u5BB9\u4EA4\u7ED9\u4EE3\u7406\u3002"],
4266
- "tplText-tool-digest": ["\uB3C4\uAD6C \uACB0\uACFC\uAC00 \uAE38\uBA74 \uD604\uC7AC \uC791\uC5C5\uACFC \uAD00\uB828 \uC788\uB294 \uD56D\uBAA9\uB9CC \uACE8\uB77C \uC694\uC57D\uD574\uC11C \uBC14\uAFC0 \uB0B4\uC6A9\uC5D0 \uB123\uC5B4. \uD30C\uC77C \uACBD\uB85C\xB7\uC904 \uBC88\uD638\xB7\uC624\uB958 \uBB38\uAD6C\uB294 \uADF8\uB300\uB85C \uB0A8\uACA8.\n\uACB0\uACFC\uAC00 \uC9E7\uC73C\uBA74 \uC544\uBB34\uAC83\uB3C4 \uD558\uC9C0 \uB9C8.", "If the tool result is long, put a summary of only the items relevant to the current task in the replacement. Keep file paths, line numbers and error text as they are.\nIf the result is short, do nothing.", "\u82E5\u5DE5\u5177\u7ED3\u679C\u8F83\u957F\uFF0C\u8BF7\u53EA\u6311\u9009\u4E0E\u5F53\u524D\u4EFB\u52A1\u76F8\u5173\u7684\u6761\u76EE\u5E76\u628A\u6458\u8981\u653E\u5165\u66FF\u6362\u5185\u5BB9\uFF0C\u6587\u4EF6\u8DEF\u5F84\u3001\u884C\u53F7\u548C\u9519\u8BEF\u6587\u672C\u4FDD\u6301\u539F\u6837\u3002\n\u82E5\u7ED3\u679C\u8F83\u77ED\uFF0C\u5219\u4E0D\u505A\u4EFB\u4F55\u4E8B\u3002"],
4267
- "tpl-verify-answer": ["\uCD5C\uC885 \uB2F5\uBCC0 \uAC80\uC99D", "Verify the final answer", "\u9A8C\u8BC1\u6700\u7EC8\u56DE\u7B54"],
4268
- "tplDesc-verify-answer": ["\uB2F5\uBCC0\uC774 \uC694\uCCAD\uC744 \uB2E4 \uCC44\uC6E0\uB294\uC9C0 \uD310\uC815\uD558\uACE0, \uBAA8\uC790\uB77C\uBA74 \uB2E4\uC2DC \uD558\uB77C\uACE0 \uC9C0\uC2DC\uD569\uB2C8\uB2E4.", "Judges whether the answer meets the request; asks the agent to redo it if not.", "\u5224\u5B9A\u56DE\u7B54\u662F\u5426\u6EE1\u8DB3\u8BF7\u6C42\uFF0C\u4E0D\u6EE1\u8DB3\u5219\u8BA9\u4EE3\u7406\u91CD\u505A\u3002"],
4269
- "tplText-verify-answer": ["\uB2F5\uBCC0\uC774 \uC0AC\uC6A9\uC790\uC758 \uC694\uCCAD\uC744 \uBAA8\uB450 \uB2E4\uB918\uB294\uC9C0 \uD655\uC778\uD574.\n\uBE60\uC9C4 \uBD80\uBD84\uC774 \uC788\uC73C\uBA74 \uB9C9\uACE0, \uBB34\uC5C7\uC744 \uB354 \uD574\uC57C \uD558\uB294\uC9C0 \uC774\uC720\uC5D0 \uC368.", "Check that the answer covers everything the user asked.\nIf something is missing, stop it and say what still needs doing as the reason.", "\u68C0\u67E5\u56DE\u7B54\u662F\u5426\u6DB5\u76D6\u7528\u6237\u7684\u5168\u90E8\u8BF7\u6C42\u3002\n\u82E5\u6709\u9057\u6F0F\uFF0C\u8BF7\u62E6\u4E0B\u5E76\u5728\u539F\u56E0\u4E2D\u5199\u660E\u8FD8\u9700\u5B8C\u6210\u7684\u5185\u5BB9\u3002"]
4553
+ // src/pixie-gate-chat-node.ts
4554
+ var GATE_RESULT_NODE = "studio-pixie-gate-result";
4555
+ var ANCHOR_OFFSET = 0.2;
4556
+ var SESSION_LOCATION = Object.freeze({ kind: "session" });
4557
+ var record2 = (value) => !!value && typeof value === "object";
4558
+ var appended = (event) => event.surfaceOp === void 0 || event.surfaceOp === "append";
4559
+ function eventAnchor(event) {
4560
+ if (!appended(event) || !record2(event.data)) return void 0;
4561
+ if (event.type === "tool/result") {
4562
+ const message4 = event.data.message;
4563
+ return record2(message4) && typeof message4.toolCallId === "string" ? { kind: "tool", callId: message4.toolCallId } : void 0;
4564
+ }
4565
+ const source = event.data.source;
4566
+ if (event.type === "user/message" && typeof event.data.id === "string" && record2(source) && (source.kind === "user" || source.kind === "agent-message")) return { kind: "message", messageId: event.data.id };
4567
+ return void 0;
4568
+ }
4569
+ var anchorId = (anchor) => anchor.kind === "tool" ? `tool:${anchor.callId}` : `message:${anchor.messageId}`;
4570
+ var match = (event) => {
4571
+ const anchor = eventAnchor(event);
4572
+ return anchor ? { id: anchorId(anchor), role: "start" } : null;
4270
4573
  };
4271
- function gateTaskText(locale, key, values = {}) {
4272
- const text = messages2[key][locale.startsWith("ko") ? 0 : locale.startsWith("zh") ? 2 : 1];
4273
- return text.replace(/\{(\w+)\}/g, (match, name) => name in values ? String(values[name]) : match);
4574
+ var gateResultDefinition = {
4575
+ kind: GATE_RESULT_NODE,
4576
+ target: "chat",
4577
+ // Function form: DSH 0.2.0-rc.2 does not accept the event-type table form.
4578
+ match,
4579
+ start: (_context, start) => ({ anchor: eventAnchor(start.event), seq: start.event.seq }),
4580
+ update: (context) => context.state,
4581
+ buildViewNode: (context) => {
4582
+ const state = context.state;
4583
+ if (!state) return null;
4584
+ const location = state.anchor.kind === "message" ? SESSION_LOCATION : context.start?.location ?? context.matches[0]?.location ?? { kind: "unresolved" };
4585
+ const anchorSeq = state.seq + ANCHOR_OFFSET;
4586
+ const current = context.current.get("chat");
4587
+ if (current && current.anchorSeq === anchorSeq && current.location === location) return current;
4588
+ return { key: context.key, kind: GATE_RESULT_NODE, id: context.id, target: "chat", anchorSeq, location, visibility: "visible", data: { anchor: state.anchor } };
4589
+ }
4590
+ };
4591
+ function applyGateFrame(record3, frame) {
4592
+ return frame.type === "session" ? { ...record3, disabledGateIds: frame.disabledGateIds } : { ...record3, runs: [...record3.runs.filter((run) => run.id !== frame.run.id), frame.run] };
4593
+ }
4594
+ function bufferGateFrame(frames, frame) {
4595
+ const same = frames.findIndex((old) => old.type === frame.type && (frame.type === "session" || old.type === "run" && old.run.id === frame.run.id));
4596
+ if (same >= 0) frames.splice(same, 1);
4597
+ frames.push(frame);
4274
4598
  }
4599
+ function gateRunHub(fetch, connect) {
4600
+ let state;
4601
+ let pending;
4602
+ let generation = 0;
4603
+ let stop;
4604
+ const listeners = /* @__PURE__ */ new Set();
4605
+ const load = () => {
4606
+ const id = ++generation;
4607
+ const frames = [];
4608
+ const promise = fetch().then((value) => {
4609
+ const next = frames.reduce(applyGateFrame, value);
4610
+ if (id === generation) {
4611
+ state = next;
4612
+ pending = void 0;
4613
+ }
4614
+ return next;
4615
+ }, (error) => {
4616
+ if (id === generation) pending = void 0;
4617
+ throw error;
4618
+ });
4619
+ promise.catch(() => {
4620
+ });
4621
+ pending = { generation: id, promise, frames };
4622
+ return promise;
4623
+ };
4624
+ const apply2 = (frame) => {
4625
+ if (frame.type === "sync") {
4626
+ state = void 0;
4627
+ void load();
4628
+ } else {
4629
+ if (state) state = applyGateFrame(state, frame);
4630
+ if (pending) bufferGateFrame(pending.frames, frame);
4631
+ }
4632
+ for (const listener of [...listeners]) listener(frame);
4633
+ };
4634
+ return {
4635
+ gateRuns: () => state ? Promise.resolve(state) : pending ? pending.promise : load(),
4636
+ followGates(listener) {
4637
+ listeners.add(listener);
4638
+ if (listeners.size === 1) stop = connect(apply2);
4639
+ return () => {
4640
+ if (!listeners.delete(listener) || listeners.size) return;
4641
+ stop?.();
4642
+ stop = void 0;
4643
+ state = void 0;
4644
+ pending = void 0;
4645
+ generation++;
4646
+ };
4647
+ }
4648
+ };
4649
+ }
4650
+
4651
+ // src/pixie-gate-tail.tsx
4652
+ var import_jsx_runtime17 = require("react/jsx-runtime");
4653
+ var UNVERIFIED = /미확인|not verified|unverified|未确认/i;
4654
+ var atAnchor = (run, anchor) => anchor.kind === "turn" ? run.point === "turn-end" && run.turn === anchor.turn : anchor.kind === "tool" ? (run.point === "tool-before" || run.point === "tool-after") && run.tool?.callId === anchor.callId : run.point === "input" && run.messageId === anchor.messageId;
4655
+ function anchorRuns(runs, anchor) {
4656
+ const last = /* @__PURE__ */ new Map();
4657
+ for (const run of runs.filter((run2) => atAnchor(run2, anchor) && run2.showInChat !== false && (run2.status === "done" || run2.status === "error") && run2.result?.concludedBy !== "skipped").sort((a, b) => a.startedAt - b.startedAt)) last.set(run.point, run);
4658
+ return [...last.values()].sort((a, b) => a.startedAt - b.startedAt);
4659
+ }
4660
+ function tailContent(run) {
4661
+ const output = run.output;
4662
+ if (output?.note?.trim()) return { kind: "note", ...splitNote(output.note) };
4663
+ if (run.status === "error") return { kind: "error", reason: output?.reason ?? run.result?.forwardError?.reason ?? run.reason ?? "" };
4664
+ return {
4665
+ kind: "verdict",
4666
+ verdict: output?.verdict ?? "pass",
4667
+ ...output?.reason?.trim() ? { reason: output.reason } : {},
4668
+ ...output?.replace?.trim() ? { replace: output.replace } : {},
4669
+ ...output?.append?.trim() ? { append: output.append } : {}
4670
+ };
4671
+ }
4672
+ function splitNote(note) {
4673
+ const match2 = /^\s*\[([^\]\n]{1,80})\]\s*\n?/.exec(note);
4674
+ return match2 ? { label: match2[1], body: note.slice(match2[0].length) } : { body: note };
4675
+ }
4676
+ function GateResults({ actions, anchor, locale, Surface = import_react15.default.Fragment }) {
4677
+ const [runs, setRuns] = import_react15.default.useState([]);
4678
+ const [disabled, setDisabled] = import_react15.default.useState([]);
4679
+ import_react15.default.useEffect(() => {
4680
+ let active = true;
4681
+ let refreshing;
4682
+ let latest = 0;
4683
+ const refresh = () => {
4684
+ const id = ++latest;
4685
+ const own2 = { id, frames: [] };
4686
+ refreshing = own2;
4687
+ actions.gateRuns().then((snapshot) => {
4688
+ if (!active || id !== latest) return;
4689
+ const record3 = own2.frames.reduce(applyGateFrame, snapshot);
4690
+ refreshing = void 0;
4691
+ setRuns(record3.runs);
4692
+ setDisabled(record3.disabledGateIds ?? []);
4693
+ }, () => {
4694
+ if (id === latest) refreshing = void 0;
4695
+ });
4696
+ };
4697
+ const stop = actions.followGates((frame) => {
4698
+ if (!active) return;
4699
+ if (frame.type === "sync") {
4700
+ refresh();
4701
+ return;
4702
+ }
4703
+ if (refreshing) bufferGateFrame(refreshing.frames, frame);
4704
+ if (frame.type === "session") {
4705
+ setDisabled(frame.disabledGateIds);
4706
+ return;
4707
+ }
4708
+ setRuns((current) => [...current.filter((run) => run.id !== frame.run.id), frame.run]);
4709
+ });
4710
+ refresh();
4711
+ return () => {
4712
+ active = false;
4713
+ stop();
4714
+ };
4715
+ }, [actions]);
4716
+ const shown = anchorRuns(runs, anchor);
4717
+ if (!shown.length) return null;
4718
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Surface, { children: shown.map((run) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(GateResultBlock, { run, actions, locale, off: disabled.includes(run.gateId), onDisabled: setDisabled }, run.id)) });
4719
+ }
4720
+ function GateTail({ turn, ...props }) {
4721
+ const anchor = import_react15.default.useMemo(() => ({ kind: "turn", turn }), [turn]);
4722
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(GateResults, { ...props, anchor });
4723
+ }
4724
+ function GateResultBlock({ run, actions, locale, off, onDisabled }) {
4725
+ const t = (key) => gateText(locale, key);
4726
+ const [open, setOpen] = import_react15.default.useState(true);
4727
+ const [busy, setBusy] = import_react15.default.useState(false);
4728
+ const [error, setError] = import_react15.default.useState("");
4729
+ const content = tailContent(run);
4730
+ const label = content.kind === "note" ? content.label : void 0;
4731
+ const unverified = !!label && UNVERIFIED.test(label);
4732
+ const turnOff = async () => {
4733
+ setBusy(true);
4734
+ setError("");
4735
+ try {
4736
+ onDisabled(await actions.setSessionGate(run.gateId, false));
4737
+ } catch (cause) {
4738
+ setError(`${t("sessionGateFailed")} (${cause instanceof Error ? cause.message : String(cause)})`);
4739
+ } finally {
4740
+ setBusy(false);
4741
+ }
4742
+ };
4743
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "studio-gate-tail-body", "aria-label": t("tailTitle").replace("{name}", run.gateName), "data-gate-tail": run.gateId, "data-gate-point": run.point, "data-tail-kind": content.kind, "data-unverified": unverified ? "true" : void 0, children: [
4744
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "studio-gate-tail-head", children: [
4745
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: label ?? run.gateName }),
4746
+ unverified && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Badge, { tone: "warning", children: t("tailUnverified") }),
4747
+ content.kind === "verdict" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Badge, { tone: content.verdict === "stop" ? "warning" : "success", children: t(content.verdict) }),
4748
+ content.kind === "error" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Badge, { tone: "warning", children: t("error") }),
4749
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "studio-card-meta", children: `${t("tailTitle").replace("{name}", run.gateName)} \xB7 ${gatePointText(locale, run.point)}` }),
4750
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "studio-inline-actions", children: [
4751
+ content.kind !== "error" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, onClick: () => setOpen((value) => !value), children: t(open ? "tailHide" : "tailShow") }),
4752
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, onClick: actions.openTab, children: t("tailOpen") }),
4753
+ !off && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, disabled: busy, onClick: () => {
4754
+ void turnOff();
4755
+ }, children: t("tailOff") })
4756
+ ] })
4757
+ ] }),
4758
+ error && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Notice, { children: error }),
4759
+ off && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { role: "status", className: "studio-muted", children: t("tailOffDone") }),
4760
+ content.kind === "error" && content.reason && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "studio-muted", children: content.reason }),
4761
+ open && content.kind === "note" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ModelText, { text: content.body, locale }),
4762
+ open && content.kind === "verdict" && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
4763
+ content.reason && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ModelText, { text: content.reason, locale }),
4764
+ content.replace && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Disclosure, { title: t("replace"), children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ModelText, { text: content.replace, locale }) }),
4765
+ content.append && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Disclosure, { title: t("append"), children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ModelText, { text: content.append, locale }) })
4766
+ ] })
4767
+ ] });
4768
+ }
4769
+
4770
+ // src/pixie-settings.tsx
4771
+ var import_react17 = __toESM(require("react"), 1);
4772
+
4773
+ // src/pixie-gate-task-pages.tsx
4774
+ var import_react16 = __toESM(require("react"), 1);
4275
4775
 
4276
4776
  // src/pixie-gate-task.ts
4277
4777
  var GATE_WHENS = ["user-message", "agent-message", "tool-before", "tool-after", "turn-end"];
@@ -4287,6 +4787,7 @@ var GATE_GUIDE_URL = "https://github.com/matamt-dbg/dsh-studio/blob/main/docs/ap
4287
4787
  var enabledFor = (task, preset) => task.enabled && task.presetIds.includes(preset) && !task.disabledPresetIds?.includes(preset);
4288
4788
  var isTool = (when) => when === "tool-before" || when === "tool-after";
4289
4789
  var isMessage = (when) => when === "user-message" || when === "agent-message";
4790
+ var showsInChat = (task) => task.advanced.showInChat !== false;
4290
4791
  function makeTask(name, when = "user-message", instruction = "") {
4291
4792
  return {
4292
4793
  id: globalThis.crypto.randomUUID(),
@@ -4294,7 +4795,7 @@ function makeTask(name, when = "user-message", instruction = "") {
4294
4795
  enabled: true,
4295
4796
  when,
4296
4797
  instruction,
4297
- advanced: { confirmReplace: false, onError: "pass", agents: when === "agent-message" ? "child" : "root", timeoutMs: 6e4, maxSteers: 1 },
4798
+ advanced: { confirmReplace: false, onError: "pass", agents: when === "agent-message" ? "child" : "root", timeoutMs: 6e4, maxSteers: 1, showInChat: true },
4298
4799
  presetIds: []
4299
4800
  };
4300
4801
  }
@@ -4308,16 +4809,16 @@ function taskVariables(task) {
4308
4809
  }
4309
4810
  function taskProblem(task) {
4310
4811
  if (!task.name.trim()) return "name";
4311
- if (!task.instruction.trim()) return "instruction";
4812
+ if (!task.instruction.trim() && task.advanced.script === void 0) return "instruction";
4312
4813
  if (!(task.advanced.timeoutMs > 0) || !Number.isInteger(task.advanced.maxSteers) || task.advanced.maxSteers < 0) return "limits";
4313
4814
  return void 0;
4314
4815
  }
4315
4816
 
4316
4817
  // src/pixie-gate-task-pages.tsx
4317
- var import_jsx_runtime17 = require("react/jsx-runtime");
4818
+ var import_jsx_runtime18 = require("react/jsx-runtime");
4318
4819
  var withLink = (text, link) => {
4319
4820
  const [before, after = ""] = text.split("{link}");
4320
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
4821
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4321
4822
  before,
4322
4823
  link,
4323
4824
  after
@@ -4325,13 +4826,13 @@ var withLink = (text, link) => {
4325
4826
  };
4326
4827
  var useText = (locale) => (key, values) => gateTaskText(locale, key, values);
4327
4828
  function useGateTasks(actions) {
4328
- const [tasks, setTasks] = import_react15.default.useState();
4329
- const [stored, setStored] = import_react15.default.useState("");
4330
- const [invalid, setInvalid] = import_react15.default.useState([]);
4331
- const [error, setError] = import_react15.default.useState("");
4332
- const [status, setStatus] = import_react15.default.useState("idle");
4333
- const [saveError, setSaveError] = import_react15.default.useState("");
4334
- const load = import_react15.default.useCallback(async () => {
4829
+ const [tasks, setTasks] = import_react16.default.useState();
4830
+ const [stored, setStored] = import_react16.default.useState("");
4831
+ const [invalid, setInvalid] = import_react16.default.useState([]);
4832
+ const [error, setError] = import_react16.default.useState("");
4833
+ const [status, setStatus] = import_react16.default.useState("idle");
4834
+ const [saveError, setSaveError] = import_react16.default.useState("");
4835
+ const load = import_react16.default.useCallback(async () => {
4335
4836
  setError("");
4336
4837
  try {
4337
4838
  const read = await actions.read();
@@ -4343,7 +4844,7 @@ function useGateTasks(actions) {
4343
4844
  setError(cause instanceof Error ? cause.message : String(cause));
4344
4845
  }
4345
4846
  }, [actions]);
4346
- import_react15.default.useEffect(() => {
4847
+ import_react16.default.useEffect(() => {
4347
4848
  void load();
4348
4849
  }, [load]);
4349
4850
  const edit = (change) => {
@@ -4383,17 +4884,17 @@ function useGateTasks(actions) {
4383
4884
  };
4384
4885
  }
4385
4886
  function GateHead({ gates, title, description, t }) {
4386
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
4387
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PageHead, { title, ...description ? { description } : {}, actions: gates.loaded ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { primary: true, disabled: gates.status === "saving" || !gates.dirty, onClick: () => {
4887
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4888
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PageHead, { title, ...description ? { description } : {}, actions: gates.loaded ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { primary: true, disabled: gates.status === "saving" || !gates.dirty, onClick: () => {
4388
4889
  void gates.saveAll();
4389
4890
  }, children: gates.status === "saving" ? t("saving") : gates.dirty ? t("save") : t("saved") }) : void 0 }),
4390
- gates.saveError && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Notice, { action: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, onClick: gates.clearSaveError, children: t("dismiss") }), children: `${t("saveFailed")} (${gates.saveError})` }),
4391
- gates.error && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Notice, { action: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, onClick: () => {
4891
+ gates.saveError && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { action: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: gates.clearSaveError, children: t("dismiss") }), children: `${t("saveFailed")} (${gates.saveError})` }),
4892
+ gates.error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { action: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: () => {
4392
4893
  void gates.load();
4393
4894
  }, children: t("retry") }), children: gates.error }),
4394
- !gates.error && !gates.loaded && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { role: "status", className: "studio-muted", children: t("loading") }),
4395
- gates.invalid.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Notice, { children: t("invalid", { count: gates.invalid.length, reasons: gates.invalid.map((item) => `#${item.index + 1} ${item.error.message}`).join("; ") }) }),
4396
- gates.dirty && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Notice, { tone: "info", children: t("unsaved") })
4895
+ !gates.error && !gates.loaded && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "status", className: "studio-muted", children: t("loading") }),
4896
+ gates.invalid.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { children: t("invalid", { count: gates.invalid.length, reasons: gates.invalid.map((item) => `#${item.index + 1} ${item.error.message}`).join("; ") }) }),
4897
+ gates.dirty && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { tone: "info", children: t("unsaved") })
4397
4898
  ] });
4398
4899
  }
4399
4900
  function TemplatePicker({ open, locale, onPick, onClose }) {
@@ -4402,25 +4903,25 @@ function TemplatePicker({ open, locale, onPick, onClose }) {
4402
4903
  name: t(`tpl-${template.id}`),
4403
4904
  instruction: t(`tplText-${template.id}`)
4404
4905
  }));
4405
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DetailDialog, { open, title: t("pickTemplate"), subtitle: t("pickHint"), onClose, footer: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { onClick: onClose, children: t("cancel") }), children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("ul", { className: "studio-pick-list", "aria-label": t("pickTemplate"), children: [
4406
- GATE_TEMPLATES.map((template) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PickOption, { title: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
4906
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DetailDialog, { open, title: t("pickTemplate"), subtitle: t("pickHint"), onClose, footer: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { onClick: onClose, children: t("cancel") }), children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("ul", { className: "studio-pick-list", "aria-label": t("pickTemplate"), children: [
4907
+ GATE_TEMPLATES.map((template) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PickOption, { title: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4407
4908
  t(`tpl-${template.id}`),
4408
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Badge, { tone: "outline", children: t(`when-${template.when}`) })
4909
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Badge, { tone: "outline", children: t(`when-${template.when}`) })
4409
4910
  ] }), description: t(`tplDesc-${template.id}`), onClick: () => pick(template) }) }, template.id)),
4410
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PickOption, { title: t("blank"), description: t("blankDescription"), onClick: () => onPick(makeTask(t("newGate"))) }) })
4911
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PickOption, { title: t("blank"), description: t("blankDescription"), onClick: () => onPick(makeTask(t("newGate"))) }) })
4411
4912
  ] }) });
4412
4913
  }
4413
4914
  function GateTaskEditor({ task: initial2, open, locale, actions, onApply, onClose }) {
4414
4915
  const t = useText(locale);
4415
- const [task, setTask] = import_react15.default.useState(initial2);
4416
- const [problem, setProblem] = import_react15.default.useState();
4417
- const [sample, setSample] = import_react15.default.useState("");
4418
- const [toolName, setToolName] = import_react15.default.useState("");
4419
- const [trial, setTrial] = import_react15.default.useState();
4420
- const [copied, setCopied] = import_react15.default.useState(false);
4421
- const [scripts, setScripts] = import_react15.default.useState();
4422
- const [scriptError, setScriptError] = import_react15.default.useState("");
4423
- const refreshScripts = import_react15.default.useCallback(async () => {
4916
+ const [task, setTask] = import_react16.default.useState(initial2);
4917
+ const [problem, setProblem] = import_react16.default.useState();
4918
+ const [sample, setSample] = import_react16.default.useState("");
4919
+ const [toolName, setToolName] = import_react16.default.useState("");
4920
+ const [trial, setTrial] = import_react16.default.useState();
4921
+ const [copied, setCopied] = import_react16.default.useState(false);
4922
+ const [scripts, setScripts] = import_react16.default.useState();
4923
+ const [scriptError, setScriptError] = import_react16.default.useState("");
4924
+ const refreshScripts = import_react16.default.useCallback(async () => {
4424
4925
  setScriptError("");
4425
4926
  try {
4426
4927
  setScripts(await actions.scripts());
@@ -4428,19 +4929,19 @@ function GateTaskEditor({ task: initial2, open, locale, actions, onApply, onClos
4428
4929
  setScriptError(cause instanceof Error ? cause.message : String(cause));
4429
4930
  }
4430
4931
  }, [actions]);
4431
- import_react15.default.useEffect(() => {
4932
+ import_react16.default.useEffect(() => {
4432
4933
  if (open) void refreshScripts();
4433
4934
  }, [open, refreshScripts]);
4434
- import_react15.default.useEffect(() => {
4935
+ import_react16.default.useEffect(() => {
4435
4936
  setTask(initial2);
4436
4937
  setProblem(void 0);
4437
4938
  setSample("");
4438
4939
  setTrial(void 0);
4439
4940
  }, [initial2]);
4440
- import_react15.default.useEffect(() => () => {
4941
+ import_react16.default.useEffect(() => () => {
4441
4942
  if (trial?.state === "running") trial.cancel();
4442
4943
  }, [trial]);
4443
- if (!task) return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DetailDialog, { open: false, title: "", onClose });
4944
+ if (!task) return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DetailDialog, { open: false, title: "", onClose });
4444
4945
  const set = (patch) => {
4445
4946
  setTask({ ...task, ...patch });
4446
4947
  setProblem(void 0);
@@ -4460,9 +4961,9 @@ function GateTaskEditor({ task: initial2, open, locale, actions, onApply, onClos
4460
4961
  (cause) => setTrial((current) => current?.state === "running" ? { state: "error", message: cause instanceof Error ? cause.message : String(cause) } : current)
4461
4962
  );
4462
4963
  };
4463
- const field2 = (key, value) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_react15.default.Fragment, { children: [
4464
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dt", { children: t(key) }),
4465
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dd", { className: value === void 0 ? "studio-muted" : void 0, children: value ?? t("trialEmpty") })
4964
+ const field2 = (key, value) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react16.default.Fragment, { children: [
4965
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dt", { children: t(key) }),
4966
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dd", { className: value === void 0 ? "studio-muted" : void 0, children: value ?? t("trialEmpty") })
4466
4967
  ] }, key);
4467
4968
  const planKey = (plan) => plan.stop ? plan.suggestion !== void 0 && task.advanced.confirmReplace && plan.reason === void 0 ? "plan-confirm" : "plan-stop" : plan.replacement !== void 0 ? "plan-replace" : plan.addition !== void 0 ? "plan-append" : "plan-pass";
4468
4969
  const adv = (patch) => set({ advanced: { ...task.advanced, ...patch } });
@@ -4476,44 +4977,44 @@ function GateTaskEditor({ task: initial2, open, locale, actions, onApply, onClos
4476
4977
  }
4477
4978
  onApply(task);
4478
4979
  };
4479
- const problemAt = (key) => problem === key ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Notice, { children: t(`problem-${key}`) }) : null;
4480
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DetailDialog, { open, title: task.name || t("newGate"), subtitle: t("applyHint"), onClose, footer: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
4481
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { onClick: onClose, children: t("close") }),
4482
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { primary: true, onClick: apply2, children: t("apply") })
4483
- ] }), children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "studio-gate-task", children: [
4484
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(SettingsRow, { title: t("name"), children: [
4485
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { "aria-label": t("name"), value: task.name, onChange: (event) => set({ name: event.target.value }) }),
4980
+ const problemAt = (key) => problem === key ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { children: t(`problem-${key}`) }) : null;
4981
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DetailDialog, { open, title: task.name || t("newGate"), subtitle: t("applyHint"), onClose, footer: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4982
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { onClick: onClose, children: t("close") }),
4983
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { primary: true, onClick: apply2, children: t("apply") })
4984
+ ] }), children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-gate-task", children: [
4985
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(SettingsRow, { title: t("name"), children: [
4986
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("input", { "aria-label": t("name"), value: task.name, onChange: (event) => set({ name: event.target.value }) }),
4486
4987
  problemAt("name")
4487
4988
  ] }),
4488
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SettingsRow, { title: t("when"), control: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("select", { className: "studio-compact", "aria-label": t("when"), value: task.when, onChange: (event) => {
4989
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SettingsRow, { title: t("when"), control: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("select", { className: "studio-compact", "aria-label": t("when"), value: task.when, onChange: (event) => {
4489
4990
  const when = event.target.value;
4490
4991
  set({ when, advanced: { ...task.advanced, ...!isMessage(when) ? { confirmReplace: false } : {} } });
4491
- }, children: GATE_WHENS.map((when) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: when, children: t(`when-${when}`) }, when)) }) }),
4492
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(SettingsRow, { title: t("what"), description: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
4992
+ }, children: GATE_WHENS.map((when) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: when, children: t(`when-${when}`) }, when)) }) }),
4993
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(SettingsRow, { title: t("what"), description: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4493
4994
  t("whatHint"),
4494
4995
  " ",
4495
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("a", { href: GATE_GUIDE_URL, target: "_blank", rel: "noreferrer", children: t("resultGuide") })
4996
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("a", { href: GATE_GUIDE_URL, target: "_blank", rel: "noreferrer", children: t("resultGuide") })
4496
4997
  ] }), children: [
4497
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("textarea", { className: "studio-gate-instruction", "aria-label": t("what"), value: task.instruction, onChange: (event) => set({ instruction: event.target.value }) }),
4498
- variables.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "studio-gate-vars", children: [
4499
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "studio-muted", children: t("variables") }),
4500
- variables.map((value, i) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("code", { title: t(i === 0 ? "var-text" : "var-data"), children: value }, value))
4998
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("textarea", { className: "studio-gate-instruction", "aria-label": t("what"), value: task.instruction, onChange: (event) => set({ instruction: event.target.value }) }),
4999
+ variables.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-gate-vars", children: [
5000
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "studio-muted", children: t("variables") }),
5001
+ variables.map((value, i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("code", { title: t(i === 0 ? "var-text" : "var-data"), children: value }, value))
4501
5002
  ] }),
4502
5003
  problemAt("instruction")
4503
5004
  ] }),
4504
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(Disclosure, { title: t("advanced"), children: [
4505
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(SettingsRow, { title: t("script"), description: t("scriptHint"), control: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("select", { className: "studio-compact", "aria-label": t("script"), value: task.advanced.script ?? "", onChange: (event) => {
5005
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Disclosure, { title: t("advanced"), children: [
5006
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(SettingsRow, { title: t("script"), description: t("scriptHint"), control: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("select", { className: "studio-compact", "aria-label": t("script"), value: task.advanced.script ?? "", onChange: (event) => {
4506
5007
  const { script: _, ...rest } = task.advanced;
4507
5008
  set({ advanced: event.target.value ? { ...rest, script: event.target.value } : rest });
4508
5009
  }, children: [
4509
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: "", children: t("noScript") }),
4510
- (scripts?.scripts ?? []).map((name) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: name, children: name }, name)),
4511
- task.advanced.script && !(scripts?.scripts ?? []).includes(task.advanced.script) && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("option", { value: task.advanced.script, children: `${task.advanced.script} ${t("scriptMissing")}` })
5010
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "", children: t("noScript") }),
5011
+ (scripts?.scripts ?? []).map((name) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: name, children: name }, name)),
5012
+ task.advanced.script && !(scripts?.scripts ?? []).includes(task.advanced.script) && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: task.advanced.script, children: `${task.advanced.script} ${t("scriptMissing")}` })
4512
5013
  ] }), children: [
4513
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "studio-gate-path", children: [
4514
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "studio-muted", children: t("scriptDir") }),
4515
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("code", { children: directory }),
4516
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, onClick: async () => {
5014
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-gate-path", children: [
5015
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "studio-muted", children: t("scriptDir") }),
5016
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("code", { children: directory }),
5017
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: async () => {
4517
5018
  try {
4518
5019
  await navigator.clipboard.writeText(directory);
4519
5020
  setCopied(true);
@@ -4521,101 +5022,102 @@ function GateTaskEditor({ task: initial2, open, locale, actions, onApply, onClos
4521
5022
  setCopied(false);
4522
5023
  }
4523
5024
  }, children: copied ? "\u2713" : t("copyPath") }),
4524
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, onClick: () => {
5025
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: () => {
4525
5026
  void refreshScripts();
4526
5027
  }, children: t("refresh") })
4527
5028
  ] }),
4528
- scriptError && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Notice, { children: `${t("scriptsFailed")} (${scriptError})` }),
4529
- scripts && !scripts.supported && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Notice, { children: t("scriptUnsupported") }),
4530
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "studio-muted", children: t("scriptEnv") }),
4531
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "studio-muted", children: withLink(t("scriptShell"), /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("a", { href: GATE_GUIDE_URL, target: "_blank", rel: "noreferrer", children: t("guideLink") })) })
5029
+ scriptError && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { children: `${t("scriptsFailed")} (${scriptError})` }),
5030
+ scripts && !scripts.supported && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { children: t("scriptUnsupported") }),
5031
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "studio-muted", children: t("scriptEnv") }),
5032
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "studio-muted", children: withLink(t("scriptShell"), /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("a", { href: GATE_GUIDE_URL, target: "_blank", rel: "noreferrer", children: t("guideLink") })) })
4532
5033
  ] }),
4533
- isMessage(task.when) && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SettingsRow, { title: t("confirmReplace"), description: t("confirmReplaceHint"), control: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Toggle, { label: t("confirmReplace"), checked: task.advanced.confirmReplace, onChange: (confirmReplace) => adv({ confirmReplace }) }) }),
4534
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SettingsRow, { title: t("onError"), control: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Segmented, { label: t("onError"), value: task.advanced.onError, options: [{ value: "pass", label: t("errorPass") }, { value: "block", label: t("errorBlock") }], onChange: (onError) => adv({ onError }) }) }),
4535
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SettingsRow, { title: t("agents"), control: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Segmented, { label: t("agents"), value: task.advanced.agents, options: ["root", "child", "any"].map((value) => ({ value, label: t(value) })), onChange: (agents) => adv({ agents }) }) }),
4536
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SettingsRow, { title: t("timeout"), control: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { className: "studio-compact", type: "number", min: 1, "aria-label": t("timeout"), value: task.advanced.timeoutMs / 1e3, onChange: (event) => adv({ timeoutMs: Number(event.target.value) * 1e3 }) }) }),
4537
- task.when === "turn-end" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SettingsRow, { title: t("maxSteers"), control: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { className: "studio-compact", type: "number", min: 0, "aria-label": t("maxSteers"), value: task.advanced.maxSteers, onChange: (event) => adv({ maxSteers: Number(event.target.value) }) }) }),
5034
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SettingsRow, { title: t("showInChat"), description: t("showInChatHint"), control: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Toggle, { label: t("showInChat"), checked: showsInChat(task), onChange: (showInChat) => adv({ showInChat }) }) }),
5035
+ isMessage(task.when) && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SettingsRow, { title: t("confirmReplace"), description: t("confirmReplaceHint"), control: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Toggle, { label: t("confirmReplace"), checked: task.advanced.confirmReplace, onChange: (confirmReplace) => adv({ confirmReplace }) }) }),
5036
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SettingsRow, { title: t("onError"), control: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Segmented, { label: t("onError"), value: task.advanced.onError, options: [{ value: "pass", label: t("errorPass") }, { value: "block", label: t("errorBlock") }], onChange: (onError) => adv({ onError }) }) }),
5037
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SettingsRow, { title: t("agents"), control: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Segmented, { label: t("agents"), value: task.advanced.agents, options: ["root", "child", "any"].map((value) => ({ value, label: t(value) })), onChange: (agents) => adv({ agents }) }) }),
5038
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SettingsRow, { title: t("timeout"), control: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("input", { className: "studio-compact", type: "number", min: 1, "aria-label": t("timeout"), value: task.advanced.timeoutMs / 1e3, onChange: (event) => adv({ timeoutMs: Number(event.target.value) * 1e3 }) }) }),
5039
+ task.when === "turn-end" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SettingsRow, { title: t("maxSteers"), control: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("input", { className: "studio-compact", type: "number", min: 0, "aria-label": t("maxSteers"), value: task.advanced.maxSteers, onChange: (event) => adv({ maxSteers: Number(event.target.value) }) }) }),
4538
5040
  problemAt("limits")
4539
5041
  ] }),
4540
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "studio-gate-trial", "aria-label": t("trial"), children: [
4541
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h3", { className: "studio-panel-title", children: t("trial") }),
4542
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "studio-muted", children: t("trialPreview") }),
4543
- task.advanced.script && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "studio-muted", children: t("trialScript") }),
4544
- isTool(task.when) && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { "aria-label": t("trialTool"), placeholder: t("trialTool"), value: toolName, onChange: (event) => setToolName(event.target.value) }),
4545
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("textarea", { "aria-label": t("trialSample", { target }), placeholder: t("trialSample", { target }), value: sample, onChange: (event) => {
5042
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: "studio-gate-trial", "aria-label": t("trial"), children: [
5043
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h3", { className: "studio-panel-title", children: t("trial") }),
5044
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "studio-muted", children: t("trialPreview") }),
5045
+ task.advanced.script && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "studio-muted", children: t("trialScript") }),
5046
+ isTool(task.when) && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("input", { "aria-label": t("trialTool"), placeholder: t("trialTool"), value: toolName, onChange: (event) => setToolName(event.target.value) }),
5047
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("textarea", { "aria-label": t("trialSample", { target }), placeholder: t("trialSample", { target }), value: sample, onChange: (event) => {
4546
5048
  setSample(event.target.value);
4547
5049
  setTrial(void 0);
4548
5050
  } }),
4549
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "studio-inline-actions", children: trial?.state === "running" ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
4550
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { role: "status", className: "studio-muted", children: t("trialRunning") }),
4551
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { onClick: () => {
5051
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "studio-inline-actions", children: trial?.state === "running" ? /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
5052
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { role: "status", className: "studio-muted", children: t("trialRunning") }),
5053
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { onClick: () => {
4552
5054
  trial.cancel();
4553
5055
  setTrial(void 0);
4554
5056
  }, children: t("trialCancel") })
4555
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { disabled: !sample.trim(), onClick: runTrial, children: t("trialRun") }) }),
4556
- trial?.state === "error" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Notice, { children: `${t("trialFailed")} (${trial.message})` }),
4557
- trial?.state === "done" && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("dl", { className: "studio-gate-result", "aria-label": t("trial"), children: [
4558
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dt", { children: t("out-verdict") }),
4559
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dd", { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Badge, { tone: trial.value.output.verdict === "stop" ? "warning" : "success", children: t(trial.value.output.verdict === "stop" ? "trialStop" : "trialPass") }) }),
5057
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { disabled: !sample.trim(), onClick: runTrial, children: t("trialRun") }) }),
5058
+ trial?.state === "error" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { children: `${t("trialFailed")} (${trial.message})` }),
5059
+ trial?.state === "done" && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("dl", { className: "studio-gate-result", "aria-label": t("trial"), children: [
5060
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dt", { children: t("out-verdict") }),
5061
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dd", { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Badge, { tone: trial.value.output.verdict === "stop" ? "warning" : "success", children: t(trial.value.output.verdict === "stop" ? "trialStop" : "trialPass") }) }),
4560
5062
  field2("out-reason", trial.value.output.reason),
4561
5063
  field2("out-replace", trial.value.output.replace),
4562
5064
  field2("out-append", trial.value.output.append),
4563
5065
  field2("out-note", trial.value.output.note),
4564
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dt", { children: t("trialApplied") }),
4565
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dd", { children: t(planKey(trial.value.plan)) }),
4566
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dt", {}),
4567
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("dd", { className: "studio-muted", children: t("trialUsage", { input: trial.value.usage.inputTokens, output: trial.value.usage.outputTokens }) })
5066
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dt", { children: t("trialApplied") }),
5067
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dd", { children: t(planKey(trial.value.plan)) }),
5068
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dt", {}),
5069
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dd", { className: "studio-muted", children: t("trialUsage", { input: trial.value.usage.inputTokens, output: trial.value.usage.outputTokens }) })
4568
5070
  ] })
4569
5071
  ] })
4570
5072
  ] }) });
4571
5073
  }
4572
5074
  function GateTaskCompositionPage({ gates, locale }) {
4573
5075
  const t = useText(locale);
4574
- const [picking, setPicking] = import_react15.default.useState(false);
4575
- const [editing, setEditing] = import_react15.default.useState();
5076
+ const [picking, setPicking] = import_react16.default.useState(false);
5077
+ const [editing, setEditing] = import_react16.default.useState();
4576
5078
  const firstLine = (text) => (text.split("\n").map((line) => line.trim()).find((line) => line && !/\{\{[^}]+\}\}\s*$/.test(line)) ?? text.trim()).slice(0, 80);
4577
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "studio-page-stack", children: [
4578
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(GateHead, { gates, title: t("composition"), t }),
4579
- gates.loaded && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "studio-inline-actions", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { onClick: () => setPicking(true), children: t("newGate") }) }),
4580
- gates.loaded && !gates.tasks.length && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { role: "status", className: "studio-muted", children: t("empty") }),
4581
- gates.tasks.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "studio-tool-cards studio-card-pair", children: gates.tasks.map((task) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("article", { className: "studio-preset-card studio-gate-card", "data-gate-task": task.id, children: [
4582
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "studio-card-head", children: [
4583
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h3", { children: task.name }),
4584
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Toggle, { label: `${t("gateEnabled")} ${task.name}`, checked: task.enabled, onChange: (enabled) => gates.update(task.id, (item) => ({ ...item, enabled })) })
5079
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-page-stack", children: [
5080
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(GateHead, { gates, title: t("composition"), t }),
5081
+ gates.loaded && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "studio-inline-actions", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { onClick: () => setPicking(true), children: t("newGate") }) }),
5082
+ gates.loaded && !gates.tasks.length && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "status", className: "studio-muted", children: t("empty") }),
5083
+ gates.tasks.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "studio-tool-cards studio-card-pair", children: gates.tasks.map((task) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("article", { className: "studio-preset-card studio-gate-card", "data-gate-task": task.id, children: [
5084
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-card-head", children: [
5085
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h3", { children: task.name }),
5086
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Toggle, { label: `${t("gateEnabled")} ${task.name}`, checked: task.enabled, onChange: (enabled) => gates.update(task.id, (item) => ({ ...item, enabled })) })
4585
5087
  ] }),
4586
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("p", { className: "studio-gate-sentence", children: [
4587
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: t(`when-${task.when}`) }),
4588
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { "aria-hidden": "true", children: "\u2192" }),
4589
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: firstLine(task.instruction) })
5088
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { className: "studio-gate-sentence", children: [
5089
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: t(`when-${task.when}`) }),
5090
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { "aria-hidden": "true", children: "\u2192" }),
5091
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: firstLine(task.instruction) })
4590
5092
  ] }),
4591
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("p", { className: "studio-card-meta", children: [
5093
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { className: "studio-card-meta", children: [
4592
5094
  task.presetIds.length ? t("presetCount", { count: task.presetIds.length }) : t("noPreset"),
4593
5095
  task.advanced.script ? ` \xB7 ${task.advanced.script}` : ""
4594
5096
  ] }),
4595
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "studio-card-footer", children: [
4596
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, onClick: () => setEditing(structuredClone(task)), children: t("edit") }),
4597
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, onClick: () => {
5097
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-card-footer", children: [
5098
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: () => setEditing(structuredClone(task)), children: t("edit") }),
5099
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: () => {
4598
5100
  const { disabledPresetIds: _, ...copy5 } = structuredClone(task);
4599
5101
  gates.save({ ...copy5, id: globalThis.crypto.randomUUID(), name: `${task.name} (${t("duplicate")})`, presetIds: [] });
4600
5102
  }, children: t("duplicate") }),
4601
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, onClick: () => gates.remove(task.id), children: t("delete") })
5103
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: () => gates.remove(task.id), children: t("delete") })
4602
5104
  ] })
4603
5105
  ] }, task.id)) }),
4604
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(TemplatePicker, { open: picking, locale, onClose: () => setPicking(false), onPick: (task) => {
5106
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TemplatePicker, { open: picking, locale, onClose: () => setPicking(false), onPick: (task) => {
4605
5107
  setPicking(false);
4606
5108
  setEditing(task);
4607
5109
  } }),
4608
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(GateTaskEditor, { open: !!editing, task: editing, locale, actions: gates.actions, onClose: () => setEditing(void 0), onApply: (task) => {
5110
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(GateTaskEditor, { open: !!editing, task: editing, locale, actions: gates.actions, onClose: () => setEditing(void 0), onApply: (task) => {
4609
5111
  gates.save(task);
4610
5112
  setEditing(void 0);
4611
5113
  } })
4612
5114
  ] });
4613
5115
  }
4614
5116
  function ScriptFolder({ actions, t }) {
4615
- const [list, setList] = import_react15.default.useState();
4616
- const [draft, setDraft] = import_react15.default.useState("");
4617
- const [busy, setBusy] = import_react15.default.useState(false);
4618
- const [error, setError] = import_react15.default.useState("");
5117
+ const [list, setList] = import_react16.default.useState();
5118
+ const [draft, setDraft] = import_react16.default.useState("");
5119
+ const [busy, setBusy] = import_react16.default.useState(false);
5120
+ const [error, setError] = import_react16.default.useState("");
4619
5121
  const run = async (work, failed) => {
4620
5122
  setBusy(true);
4621
5123
  setError("");
@@ -4632,7 +5134,7 @@ function ScriptFolder({ actions, t }) {
4632
5134
  setList(next);
4633
5135
  setDraft(next.custom ? next.directory : "");
4634
5136
  }, "folderFailed");
4635
- import_react15.default.useEffect(() => {
5137
+ import_react16.default.useEffect(() => {
4636
5138
  let active = true;
4637
5139
  actions.scripts().then((next) => {
4638
5140
  if (active) {
@@ -4646,31 +5148,31 @@ function ScriptFolder({ actions, t }) {
4646
5148
  active = false;
4647
5149
  };
4648
5150
  }, [actions]);
4649
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("section", { className: "studio-settings-card", "aria-label": t("folderTitle"), children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(SettingsRow, { title: t("folderTitle"), description: t("folderHint"), children: [
4650
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "studio-gate-folder", children: [
4651
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { "aria-label": t("folderTitle"), placeholder: list?.defaultDirectory ?? GATE_SCRIPT_DIR, value: draft, disabled: busy, onChange: (event) => setDraft(event.target.value) }),
4652
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, disabled: busy || !list || draft.trim() === (list.custom ? list.directory : ""), onClick: () => {
5151
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("section", { className: "studio-settings-card", "aria-label": t("folderTitle"), children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(SettingsRow, { title: t("folderTitle"), description: t("folderHint"), children: [
5152
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-gate-folder", children: [
5153
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("input", { "aria-label": t("folderTitle"), placeholder: list?.defaultDirectory ?? GATE_SCRIPT_DIR, value: draft, disabled: busy, onChange: (event) => setDraft(event.target.value) }),
5154
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, disabled: busy || !list || draft.trim() === (list.custom ? list.directory : ""), onClick: () => {
4653
5155
  void apply2(draft);
4654
5156
  }, children: t("folderApply") }),
4655
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, disabled: busy || !list?.custom, onClick: () => {
5157
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, disabled: busy || !list?.custom, onClick: () => {
4656
5158
  void apply2("");
4657
5159
  }, children: t("folderReset") }),
4658
- actions.openFolder && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, disabled: busy || !list, onClick: () => {
5160
+ actions.openFolder && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, disabled: busy || !list, onClick: () => {
4659
5161
  void run(() => actions.openFolder(list.directory), "openFailed");
4660
5162
  }, children: t("openFolder") })
4661
5163
  ] }),
4662
- list && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("p", { className: "studio-card-meta", children: [
5164
+ list && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { className: "studio-card-meta", children: [
4663
5165
  t(list.custom ? "folderCurrent" : "folderDefault"),
4664
5166
  ": ",
4665
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("code", { children: list.directory })
5167
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("code", { children: list.directory })
4666
5168
  ] }),
4667
- list && !list.supported && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Notice, { children: t("scriptUnsupported") }),
4668
- error && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Notice, { children: error })
5169
+ list && !list.supported && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { children: t("scriptUnsupported") }),
5170
+ error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { children: error })
4669
5171
  ] }) });
4670
5172
  }
4671
5173
  function GateTaskScopePage({ gates, presets, locale }) {
4672
5174
  const t = useText(locale);
4673
- const [adding, setAdding] = import_react15.default.useState();
5175
+ const [adding, setAdding] = import_react16.default.useState();
4674
5176
  const attachedTo = (preset) => gates.tasks.filter((task) => task.presetIds.includes(preset));
4675
5177
  const detach = (task, preset) => gates.update(task.id, (item) => ({ ...item, presetIds: item.presetIds.filter((id) => id !== preset), ...item.disabledPresetIds ? { disabledPresetIds: item.disabledPresetIds.filter((id) => id !== preset) } : {} }));
4676
5178
  const switchFor = (task, preset, on) => gates.update(task.id, (item) => {
@@ -4683,50 +5185,50 @@ function GateTaskScopePage({ gates, presets, locale }) {
4683
5185
  const row = (task, preset) => {
4684
5186
  const on = enabledFor(task, preset);
4685
5187
  const conflict = on && gates.tasks.some((other) => other.id !== task.id && other.when === task.when && enabledFor(other, preset));
4686
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("li", { className: "studio-gate-scope-row", "data-gate-scope": task.id, children: [
4687
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "studio-gate-scope-name", children: [
4688
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: task.name }),
4689
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "studio-card-meta", children: [
5188
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("li", { className: "studio-gate-scope-row", "data-gate-scope": task.id, children: [
5189
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "studio-gate-scope-name", children: [
5190
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("strong", { children: task.name }),
5191
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "studio-card-meta", children: [
4690
5192
  t(`when-${task.when}`),
4691
5193
  task.advanced.script ? ` \xB7 ${task.advanced.script}` : ""
4692
5194
  ] }),
4693
- !task.enabled && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Badge, { tone: "neutral", children: t("gateOff") }),
4694
- conflict && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Badge, { tone: "warning", children: t("conflict") })
5195
+ !task.enabled && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Badge, { tone: "neutral", children: t("gateOff") }),
5196
+ conflict && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Badge, { tone: "warning", children: t("conflict") })
4695
5197
  ] }),
4696
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "studio-gate-scope-actions", children: [
4697
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, onClick: () => detach(task, preset), children: t("removeFromPreset") }),
4698
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "studio-gate-scope-switch", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Toggle, { label: `${t("enabled")} ${task.name}`, checked: on, disabled: !task.enabled, onChange: (next) => switchFor(task, preset, next) }) })
5198
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "studio-gate-scope-actions", children: [
5199
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: () => detach(task, preset), children: t("removeFromPreset") }),
5200
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "studio-gate-scope-switch", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Toggle, { label: `${t("enabled")} ${task.name}`, checked: on, disabled: !task.enabled, onChange: (next) => switchFor(task, preset, next) }) })
4699
5201
  ] })
4700
5202
  ] }, task.id);
4701
5203
  };
4702
5204
  const presetCard = (preset) => {
4703
5205
  const tasks = attachedTo(preset.id);
4704
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("section", { className: "studio-settings-card", "aria-label": preset.name, "data-gate-preset": preset.id, children: [
4705
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "studio-gate-scope-head", children: [
4706
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "studio-gate-scope-title", children: [
4707
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: preset.name }),
4708
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "studio-card-meta", children: t("gateCount", { count: tasks.length, on: tasks.filter((task) => enabledFor(task, preset.id)).length }) })
5206
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: "studio-settings-card", "aria-label": preset.name, "data-gate-preset": preset.id, children: [
5207
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-gate-scope-head", children: [
5208
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "studio-gate-scope-title", children: [
5209
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("strong", { children: preset.name }),
5210
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "studio-card-meta", children: t("gateCount", { count: tasks.length, on: tasks.filter((task) => enabledFor(task, preset.id)).length }) })
4709
5211
  ] }),
4710
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "studio-gate-scope-actions", children: [
4711
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, disabled: !gates.loaded, onClick: () => setAdding(preset), children: t("addGate") }),
4712
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "studio-gate-scope-switch", "aria-hidden": "true" })
5212
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "studio-gate-scope-actions", children: [
5213
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, disabled: !gates.loaded, onClick: () => setAdding(preset), children: t("addGate") }),
5214
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "studio-gate-scope-switch", "aria-hidden": "true" })
4713
5215
  ] })
4714
5216
  ] }),
4715
- tasks.length ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("ul", { className: "studio-gate-scope-list", children: tasks.map((task) => row(task, preset.id)) }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "studio-card-meta", children: t("noGatesInPreset") })
5217
+ tasks.length ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ul", { className: "studio-gate-scope-list", children: tasks.map((task) => row(task, preset.id)) }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "studio-card-meta", children: t("noGatesInPreset") })
4716
5218
  ] }, preset.id);
4717
5219
  };
4718
5220
  const candidates = adding ? gates.tasks.filter((task) => !task.presetIds.includes(adding.id)) : [];
4719
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "studio-page-stack", children: [
4720
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(GateHead, { gates, title: t("scope"), description: t("scopeDescription"), t }),
4721
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ScriptFolder, { actions: gates.actions, t }),
4722
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(SectionHead, { title: t("presetsTitle"), description: t("presetsTitleHint") }),
4723
- !presets.length && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { role: "status", className: "studio-muted", children: t("noStudioPresets") }),
5221
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-page-stack", children: [
5222
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(GateHead, { gates, title: t("scope"), description: t("scopeDescription"), t }),
5223
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ScriptFolder, { actions: gates.actions, t }),
5224
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SectionHead, { title: t("presetsTitle"), description: t("presetsTitleHint") }),
5225
+ !presets.length && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "status", className: "studio-muted", children: t("noStudioPresets") }),
4724
5226
  presets.map(presetCard),
4725
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(DetailDialog, { compact: true, open: !!adding, title: adding ? t("addGateTo", { preset: adding.name }) : "", onClose: () => setAdding(void 0), footer: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { onClick: () => setAdding(void 0), children: t("close") }), children: [
4726
- !candidates.length && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { className: "studio-muted", children: t("noGateToAdd") }),
4727
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("ul", { className: "studio-pick-list", "aria-label": adding ? t("addGateTo", { preset: adding.name }) : "", children: candidates.map((task) => /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PickOption, { title: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
5227
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(DetailDialog, { compact: true, open: !!adding, title: adding ? t("addGateTo", { preset: adding.name }) : "", onClose: () => setAdding(void 0), footer: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { onClick: () => setAdding(void 0), children: t("close") }), children: [
5228
+ !candidates.length && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "studio-muted", children: t("noGateToAdd") }),
5229
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("ul", { className: "studio-pick-list", "aria-label": adding ? t("addGateTo", { preset: adding.name }) : "", children: candidates.map((task) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(PickOption, { title: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4728
5230
  task.name,
4729
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Badge, { tone: "outline", children: t(`when-${task.when}`) })
5231
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Badge, { tone: "outline", children: t(`when-${task.when}`) })
4730
5232
  ] }), description: task.instruction.split("\n")[0], onClick: () => {
4731
5233
  gates.update(task.id, (item) => ({ ...item, presetIds: [...item.presetIds, adding.id] }));
4732
5234
  setAdding(void 0);
@@ -4878,11 +5380,11 @@ var messages3 = {
4878
5380
  };
4879
5381
  function gateComposeText(locale, key, values = {}) {
4880
5382
  const text = messages3[key][locale.startsWith("ko") ? 0 : locale.startsWith("zh") ? 2 : 1];
4881
- return text.replace(/\{(\w+)\}/g, (match, name) => name in values ? String(values[name]) : match);
5383
+ return text.replace(/\{(\w+)\}/g, (match2, name) => name in values ? String(values[name]) : match2);
4882
5384
  }
4883
5385
 
4884
5386
  // src/pixie-settings.tsx
4885
- var import_jsx_runtime18 = require("react/jsx-runtime");
5387
+ var import_jsx_runtime19 = require("react/jsx-runtime");
4886
5388
  var SEP = "\0";
4887
5389
  var NO_GATES = {
4888
5390
  read: async () => ({ entries: [], invalid: [] }),
@@ -4895,20 +5397,20 @@ var NO_GATES = {
4895
5397
  };
4896
5398
  function PixieSettingsPage({ actions, gateActions, locale, navFooter }) {
4897
5399
  const t = (key) => pixieText(locale, key);
4898
- const [page, setPage] = import_react16.default.useState("model");
5400
+ const [page, setPage] = import_react17.default.useState("model");
4899
5401
  const gates = useGateTasks(gateActions ?? NO_GATES);
4900
- const [gatePresets, setGatePresets] = import_react16.default.useState([]);
4901
- import_react16.default.useEffect(() => {
5402
+ const [gatePresets, setGatePresets] = import_react17.default.useState([]);
5403
+ import_react17.default.useEffect(() => {
4902
5404
  if (gateActions) void gateActions.presets().then(setGatePresets, () => setGatePresets([]));
4903
5405
  }, [gateActions]);
4904
5406
  const gt = (key) => gateComposeText(locale, key);
4905
- const [draft, setDraft] = import_react16.default.useState();
4906
- const [catalog, setCatalog] = import_react16.default.useState();
4907
- const [error, setError] = import_react16.default.useState("");
4908
- const [status, setStatus] = import_react16.default.useState("idle");
4909
- const [saveError, setSaveError] = import_react16.default.useState("");
4910
- const [stored, setStored] = import_react16.default.useState("");
4911
- const load = import_react16.default.useCallback(async () => {
5407
+ const [draft, setDraft] = import_react17.default.useState();
5408
+ const [catalog, setCatalog] = import_react17.default.useState();
5409
+ const [error, setError] = import_react17.default.useState("");
5410
+ const [status, setStatus] = import_react17.default.useState("idle");
5411
+ const [saveError, setSaveError] = import_react17.default.useState("");
5412
+ const [stored, setStored] = import_react17.default.useState("");
5413
+ const load = import_react17.default.useCallback(async () => {
4912
5414
  setError("");
4913
5415
  try {
4914
5416
  const [settings, models] = await Promise.all([actions.read(), actions.models()]);
@@ -4919,7 +5421,7 @@ function PixieSettingsPage({ actions, gateActions, locale, navFooter }) {
4919
5421
  setError(reason instanceof Error ? reason.message : String(reason));
4920
5422
  }
4921
5423
  }, [actions]);
4922
- import_react16.default.useEffect(() => {
5424
+ import_react17.default.useEffect(() => {
4923
5425
  void load();
4924
5426
  }, [load]);
4925
5427
  const save = async () => {
@@ -4947,47 +5449,54 @@ function PixieSettingsPage({ actions, gateActions, locale, navFooter }) {
4947
5449
  setStatus("idle");
4948
5450
  };
4949
5451
  const dirty = draft !== void 0 && JSON.stringify(draft) !== stored;
4950
- const section = (title, description, body) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-page-stack", children: [
4951
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5452
+ const section = (title, description, body) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "studio-page-stack", children: [
5453
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4952
5454
  PageHead,
4953
5455
  {
4954
5456
  title: t(title),
4955
5457
  description: t(description),
4956
- actions: draft && catalog ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { primary: true, disabled: status === "saving" || !dirty, onClick: () => {
5458
+ actions: draft && catalog ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Button, { primary: true, disabled: status === "saving" || !dirty, onClick: () => {
4957
5459
  void save();
4958
5460
  }, children: status === "saving" ? t("saving") : dirty ? t("save") : t("savedButton") }) : void 0
4959
5461
  }
4960
5462
  ),
4961
- saveError && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { action: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: () => setSaveError(""), children: t("dismiss") }), children: `${t("saveFailed")} (${saveError})` }),
4962
- error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { action: !draft ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: () => {
5463
+ saveError && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Notice, { action: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Button, { small: true, onClick: () => setSaveError(""), children: t("dismiss") }), children: `${t("saveFailed")} (${saveError})` }),
5464
+ error && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Notice, { action: !draft ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Button, { small: true, onClick: () => {
4963
5465
  void load();
4964
5466
  }, children: t("retry") }) : void 0, children: error }),
4965
- !error && (!draft || !catalog) && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "status", className: "studio-muted", children: t("loading") }),
5467
+ !error && (!draft || !catalog) && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { role: "status", className: "studio-muted", children: t("loading") }),
4966
5468
  draft && catalog && body(draft, catalog)
4967
5469
  ] });
5470
+ const modelSelect = (label, emptyLabel, value, onChange, catalog2) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("select", { className: "studio-compact", "aria-label": label, value: value ? `${value.provider}${SEP}${value.model}` : "", onChange: (event) => {
5471
+ const [provider, model] = event.target.value.split(SEP);
5472
+ onChange(provider && model ? { provider, model } : void 0);
5473
+ }, children: [
5474
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: emptyLabel }),
5475
+ catalog2.groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("optgroup", { label: group.name, children: group.models.map((model) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: `${group.id}${SEP}${model.id}`, children: model.name }, model.id)) }, group.id))
5476
+ ] });
4968
5477
  const modelPage = section("pageModel", "pageModelDescription", (draft2, catalog2) => {
4969
5478
  const selected = draft2.model ? catalog2.groups.find((group) => group.id === draft2.model.provider)?.models.find((model) => model.id === draft2.model.model) : void 0;
4970
5479
  const efforts = selected?.reasoning?.efforts ?? [];
4971
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4972
- catalog2.failures && catalog2.failures.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { children: `${t("catalogFailed")} ${catalog2.failures.map((failure) => failure.name).join(", ")}` }),
4973
- /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: "studio-settings-card", children: [
4974
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SettingsRow, { title: t("settingsModel"), description: t("settingsModelHint"), control: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("select", { className: "studio-compact", "aria-label": t("settingsModel"), value: draft2.model ? `${draft2.model.provider}${SEP}${draft2.model.model}` : "", onChange: (event) => {
5480
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5481
+ catalog2.failures && catalog2.failures.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Notice, { children: `${t("catalogFailed")} ${catalog2.failures.map((failure) => failure.name).join(", ")}` }),
5482
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { className: "studio-settings-card", children: [
5483
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SettingsRow, { title: t("settingsModel"), description: t("settingsModelHint"), control: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("select", { className: "studio-compact", "aria-label": t("settingsModel"), value: draft2.model ? `${draft2.model.provider}${SEP}${draft2.model.model}` : "", onChange: (event) => {
4975
5484
  const [provider, model] = event.target.value.split(SEP);
4976
5485
  const { model: _previous, ...rest } = draft2;
4977
5486
  replace(provider && model ? { ...rest, model: { provider, model } } : rest);
4978
5487
  }, children: [
4979
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "", children: t("settingsNoModel") }),
4980
- catalog2.groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("optgroup", { label: group.name, children: group.models.map((model) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: `${group.id}${SEP}${model.id}`, children: model.name }, model.id)) }, group.id))
5488
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: t("settingsNoModel") }),
5489
+ catalog2.groups.map((group) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("optgroup", { label: group.name, children: group.models.map((model) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: `${group.id}${SEP}${model.id}`, children: model.name }, model.id)) }, group.id))
4981
5490
  ] }) }),
4982
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SettingsRow, { title: t("settingsEffort"), control: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("select", { className: "studio-compact", "aria-label": t("settingsEffort"), disabled: !draft2.model || efforts.length === 0, value: draft2.model?.reasoningEffort ?? "", onChange: (event) => {
5491
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SettingsRow, { title: t("settingsEffort"), control: /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("select", { className: "studio-compact", "aria-label": t("settingsEffort"), disabled: !draft2.model || efforts.length === 0, value: draft2.model?.reasoningEffort ?? "", onChange: (event) => {
4983
5492
  if (!draft2.model) return;
4984
5493
  const { reasoningEffort: _previous, ...model } = draft2.model;
4985
5494
  update2({ model: event.target.value ? { ...model, reasoningEffort: event.target.value } : model });
4986
5495
  }, children: [
4987
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "", children: t("settingsEffortDefault") }),
4988
- efforts.map((effort) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: effort.id, children: effort.name }, effort.id))
5496
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: t("settingsEffortDefault") }),
5497
+ efforts.map((effort) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: effort.id, children: effort.name }, effort.id))
4989
5498
  ] }) }),
4990
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SettingsRow, { title: t("settingsMaxTokens"), control: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("input", { className: "studio-compact", "aria-label": t("settingsMaxTokens"), type: "number", min: 1, step: 1, disabled: !draft2.model, placeholder: t("settingsEffortDefault"), value: draft2.model?.maxTokens ?? "", onChange: (event) => {
5499
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SettingsRow, { title: t("settingsMaxTokens"), control: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { className: "studio-compact", "aria-label": t("settingsMaxTokens"), type: "number", min: 1, step: 1, disabled: !draft2.model, placeholder: t("settingsEffortDefault"), value: draft2.model?.maxTokens ?? "", onChange: (event) => {
4991
5500
  if (!draft2.model) return;
4992
5501
  const { maxTokens: _previous, ...model } = draft2.model;
4993
5502
  const value = Number(event.target.value);
@@ -4996,8 +5505,8 @@ function PixieSettingsPage({ actions, gateActions, locale, navFooter }) {
4996
5505
  ] })
4997
5506
  ] });
4998
5507
  });
4999
- const threadsPage = section("pageThreads", "pageThreadsDescription", (draft2) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: "studio-settings-card", children: [
5000
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SettingsRow, { title: t("settingsMode"), description: t(draft2.contextMode === "fresh" ? "settingsModeFresh" : "settingsModeFork"), control: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(
5508
+ const threadsPage = section("pageThreads", "pageThreadsDescription", (draft2) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { className: "studio-settings-card", children: [
5509
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SettingsRow, { title: t("settingsMode"), description: t(draft2.contextMode === "fresh" ? "settingsModeFresh" : "settingsModeFork"), control: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5001
5510
  Segmented,
5002
5511
  {
5003
5512
  label: t("settingsMode"),
@@ -5006,22 +5515,103 @@ function PixieSettingsPage({ actions, gateActions, locale, navFooter }) {
5006
5515
  options: [{ value: "fresh", label: t("fresh") }, { value: "fork", label: t("fork") }]
5007
5516
  }
5008
5517
  ) }),
5009
- /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SettingsRow, { title: t("settingsAllowThreadModel"), description: t(draft2.allowThreadModel ? "settingsThreadModelOnHint" : "settingsThreadModelOffHint"), control: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Toggle, { label: t("settingsAllowThreadModel"), checked: draft2.allowThreadModel, onChange: (allowThreadModel) => update2({ allowThreadModel }) }) })
5518
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SettingsRow, { title: t("settingsAllowThreadModel"), description: t(draft2.allowThreadModel ? "settingsThreadModelOnHint" : "settingsThreadModelOffHint"), control: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Toggle, { label: t("settingsAllowThreadModel"), checked: draft2.allowThreadModel, onChange: (allowThreadModel) => update2({ allowThreadModel }) }) })
5010
5519
  ] }));
5011
- const promptPage = section("pagePrompt", "pagePromptDescription", (draft2) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("section", { className: "studio-settings-card", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SettingsRow, { title: t("settingsPrompt"), children: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("textarea", { className: "studio-pixie-prompt", "aria-label": t("settingsPrompt"), value: draft2.systemPrompt, onChange: (event) => update2({ systemPrompt: event.target.value }) }) }) }));
5012
- return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DetailLayout, { footer: navFooter, navigation: t("settingsNavigation"), selected: page, onSelect: (next) => setPage(next), pages: [
5520
+ const promptPage = section("pagePrompt", "pagePromptDescription", (draft2) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("section", { className: "studio-settings-card", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SettingsRow, { title: t("settingsPrompt"), children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("textarea", { className: "studio-pixie-prompt", "aria-label": t("settingsPrompt"), value: draft2.systemPrompt, onChange: (event) => update2({ systemPrompt: event.target.value }) }) }) }));
5521
+ const judgePage = section("pageJudge", "pageJudgeDescription", (draft2, catalog2) => {
5522
+ const engine = draft2.judgeEngine ?? "llm";
5523
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { className: "studio-settings-card", children: [
5524
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SettingsRow, { title: t("judgeEngine"), description: t(engine === "jev" ? "judgeEngineJevHint" : "judgeEngineLlmHint"), control: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5525
+ Segmented,
5526
+ {
5527
+ label: t("judgeEngine"),
5528
+ value: engine,
5529
+ onChange: (judgeEngine) => update2({ judgeEngine }),
5530
+ options: [{ value: "llm", label: t("judgeEngineLlm") }, { value: "jev", label: t("judgeEngineJev") }]
5531
+ }
5532
+ ) }),
5533
+ engine === "llm" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5534
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SettingsRow, { title: t("judgeModel"), description: t("judgeModelHint"), control: modelSelect(t("judgeModel"), t("judgeModelPixie"), draft2.judgeModel, (judgeModel) => {
5535
+ const { judgeModel: _previous, ...rest } = draft2;
5536
+ replace(judgeModel ? { ...rest, judgeModel } : rest);
5537
+ }, catalog2) }),
5538
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SettingsRow, { title: t("judgePrompt"), description: t("judgePromptHint"), children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("textarea", { className: "studio-pixie-prompt", "aria-label": t("judgePrompt"), value: draft2.judgeSystemPrompt ?? "", onChange: (event) => {
5539
+ const { judgeSystemPrompt: _previous, ...rest } = draft2;
5540
+ replace(event.target.value ? { ...rest, judgeSystemPrompt: event.target.value } : rest);
5541
+ } }) })
5542
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5543
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SettingsRow, { title: t("jevModel"), description: t("jevModelHint"), control: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { className: "studio-compact", "aria-label": t("jevModel"), placeholder: "jev-latest", value: draft2.jevModel ?? "", onChange: (event) => {
5544
+ const { jevModel: _previous, ...rest } = draft2;
5545
+ const value = event.target.value.trim();
5546
+ replace(value ? { ...rest, jevModel: value } : rest);
5547
+ } }) }),
5548
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(JevKeyRow, { actions: actions.jevKey, locale })
5549
+ ] })
5550
+ ] });
5551
+ });
5552
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DetailLayout, { footer: navFooter, navigation: t("settingsNavigation"), selected: page, onSelect: (next) => setPage(next), pages: [
5013
5553
  { id: "model", group: t("settingsGroup"), label: t("pageModel"), content: modelPage },
5014
5554
  { id: "threads", group: t("settingsGroup"), label: t("pageThreads"), content: threadsPage },
5015
5555
  { id: "prompt", group: t("settingsGroup"), label: t("pagePrompt"), content: promptPage },
5016
5556
  ...gateActions ? [
5017
- { id: "gate-composition", group: gt("group"), label: gt("composition"), content: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(GateTaskCompositionPage, { gates, locale }) },
5018
- { id: "gate-scope", group: gt("group"), label: gt("scope"), content: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(GateTaskScopePage, { gates, presets: gatePresets, locale }) }
5557
+ { id: "gate-composition", group: gt("group"), label: gt("composition"), content: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(GateTaskCompositionPage, { gates, locale }) },
5558
+ { id: "gate-scope", group: gt("group"), label: gt("scope"), content: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(GateTaskScopePage, { gates, presets: gatePresets, locale }) },
5559
+ { id: "judge", group: gt("group"), label: t("pageJudge"), content: judgePage }
5019
5560
  ] : []
5020
5561
  ] });
5021
5562
  }
5563
+ function JevKeyRow({ actions, locale }) {
5564
+ const t = (key) => pixieText(locale, key);
5565
+ const [status, setStatus] = import_react17.default.useState();
5566
+ const [value, setValue] = import_react17.default.useState("");
5567
+ const [busy, setBusy] = import_react17.default.useState();
5568
+ const [done, setDone] = import_react17.default.useState();
5569
+ const [error, setError] = import_react17.default.useState("");
5570
+ import_react17.default.useEffect(() => {
5571
+ if (!actions) {
5572
+ setStatus({ available: false, configured: false, writable: false });
5573
+ return;
5574
+ }
5575
+ void actions.status().then(setStatus, (reason) => setError(reason instanceof Error ? reason.message : String(reason)));
5576
+ }, [actions]);
5577
+ const run = async (kind, call) => {
5578
+ setBusy(kind);
5579
+ setDone(void 0);
5580
+ setError("");
5581
+ try {
5582
+ setStatus(await call());
5583
+ setValue("");
5584
+ setDone(kind);
5585
+ } catch (reason) {
5586
+ setError(reason instanceof Error ? reason.message : String(reason));
5587
+ } finally {
5588
+ setBusy(void 0);
5589
+ }
5590
+ };
5591
+ const source = status?.source ?? "";
5592
+ const state = !status ? t("loading") : !status.available ? t("jevKeyUnavailable") : status.configured ? `${t("jevKeySet")}${source ? ` \xB7 ${t("jevKeyFrom").replace("{source}", source)}` : ""}` : t("jevKeyMissing");
5593
+ const readOnly = !!status?.available && status.configured && !status.writable;
5594
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(SettingsRow, { title: t("jevKey"), description: t("jevKeyHint"), children: [
5595
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { role: "status", className: "studio-muted", children: readOnly ? t("jevKeyReadOnly").replace("{source}", source) : state }),
5596
+ error && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Notice, { action: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Button, { small: true, onClick: () => setError(""), children: t("dismiss") }), children: /^\[pixie\//.test(error) ? `${t("jevKeyFailed")} ${pixieError(locale, error)}` : `${t("jevKeyFailed")} (${error})` }),
5597
+ actions && status?.available && !readOnly && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "studio-inline-actions", children: [
5598
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { className: "studio-compact", type: "password", autoComplete: "off", "aria-label": t("jevKey"), placeholder: t("jevKeyPlaceholder"), value, onChange: (event) => {
5599
+ setValue(event.target.value);
5600
+ setDone(void 0);
5601
+ } }),
5602
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Button, { small: true, primary: true, disabled: !!busy || !value.trim(), onClick: () => {
5603
+ void run("save", () => actions.save(value));
5604
+ }, children: t(busy === "save" ? "jevKeySaving" : "jevKeySave") }),
5605
+ status.configured && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Button, { small: true, disabled: !!busy, onClick: () => {
5606
+ void run("remove", () => actions.remove());
5607
+ }, children: t(busy === "remove" ? "jevKeyRemoving" : "jevKeyDelete") }),
5608
+ done && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { role: "status", className: "studio-muted", children: t(done === "save" ? "jevKeySaved" : "jevKeyRemoved") })
5609
+ ] })
5610
+ ] });
5611
+ }
5022
5612
 
5023
5613
  // src/pixie-client.tsx
5024
- var import_jsx_runtime19 = require("react/jsx-runtime");
5614
+ var import_jsx_runtime20 = require("react/jsx-runtime");
5025
5615
  var NAMESPACE = "studioPixie";
5026
5616
  var TAB_ID = `${PACKAGE_NAME}/pixie`;
5027
5617
  var KIND = "studio-pixie";
@@ -5050,6 +5640,8 @@ function pixieDescriptors() {
5050
5640
  descriptor("gateRuns", ["sessionId"]),
5051
5641
  descriptor("followGates", ["sessionId"], { mode: "stream", cancellation: { parameter: "signal" } }),
5052
5642
  descriptor("resolveGateRejection", ["sessionId", "runId", "status"]),
5643
+ descriptor("sessionGates", ["sessionId"]),
5644
+ descriptor("setSessionGate", ["sessionId", "gateId", "enabled"]),
5053
5645
  descriptor("view", ["sessionId"]),
5054
5646
  descriptor("createThread", ["sessionId", "payload"]),
5055
5647
  descriptor("activate", ["sessionId", "threadId"]),
@@ -5065,7 +5657,10 @@ function pixieDescriptors() {
5065
5657
  descriptor("saveGateDefinitions", ["payload"]),
5066
5658
  descriptor("readSettings", []),
5067
5659
  descriptor("saveSettings", ["payload"]),
5068
- descriptor("models", [])
5660
+ descriptor("models", []),
5661
+ descriptor("jevKeyStatus", []),
5662
+ descriptor("saveJevKey", ["payload"]),
5663
+ descriptor("deleteJevKey", [])
5069
5664
  ];
5070
5665
  }
5071
5666
  function followPixieStream(connect, listener) {
@@ -5101,17 +5696,23 @@ function followPixieStream(connect, listener) {
5101
5696
  };
5102
5697
  }
5103
5698
  function mountPixie(ctx, options = {}) {
5699
+ const withMarkdown = (node) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(MarkdownProvider, { value: options.markdown, children: node });
5104
5700
  const remote = () => {
5105
5701
  const service = ctx.get(`remote.${NAMESPACE}`);
5106
5702
  if (!service) throw new Error("Pixie API unavailable");
5107
5703
  return service;
5108
5704
  };
5109
5705
  const locale = () => ctx.locale.getLocale().active;
5110
- const useLocale = () => import_react17.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), locale);
5706
+ const useLocale = () => import_react18.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), locale);
5111
5707
  const settingsActions = {
5112
5708
  read: () => unwrap(remote().readSettings()),
5113
5709
  save: (settings) => unwrap(remote().saveSettings(JSON.stringify(settings))),
5114
- models: () => unwrap(remote().models())
5710
+ models: () => unwrap(remote().models()),
5711
+ jevKey: {
5712
+ status: () => unwrap(remote().jevKeyStatus()),
5713
+ save: (value) => unwrap(remote().saveJevKey(JSON.stringify({ value }))),
5714
+ remove: () => unwrap(remote().deleteJevKey())
5715
+ }
5115
5716
  };
5116
5717
  const gateActions = {
5117
5718
  trial: (request) => {
@@ -5136,7 +5737,7 @@ function mountPixie(ctx, options = {}) {
5136
5737
  };
5137
5738
  function SettingsPage() {
5138
5739
  const active = useLocale();
5139
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PixieSettingsPage, { actions: settingsActions, gateActions, locale: active, navFooter: options.navFooter?.(active) });
5740
+ return withMarkdown(/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PixieSettingsPage, { actions: settingsActions, gateActions, locale: active, navFooter: options.navFooter?.(active) }));
5140
5741
  }
5141
5742
  ctx.slots.inject("local.dsh-studio.services", () => ctx.slots.register({
5142
5743
  name: "local.dsh-studio.services",
@@ -5150,6 +5751,8 @@ function mountPixie(ctx, options = {}) {
5150
5751
  gateRuns: () => unwrap(remote().gateRuns(sessionId)),
5151
5752
  followGates: (listener) => followPixieStream(() => remote().followGates(sessionId), listener),
5152
5753
  resolveGateRejection: (runId, status) => unwrap(remote().resolveGateRejection(sessionId, runId, status)),
5754
+ sessionGates: () => unwrap(remote().sessionGates(sessionId)),
5755
+ setSessionGate: (gateId, enabled) => unwrap(remote().setSessionGate(sessionId, gateId, enabled)),
5153
5756
  fillDraft: (text) => {
5154
5757
  const sessions = ctx.get("sessions");
5155
5758
  const actx = sessions?.scope(sessionId);
@@ -5178,8 +5781,8 @@ function mountPixie(ctx, options = {}) {
5178
5781
  }));
5179
5782
  function Body({ sessionId }) {
5180
5783
  const active = useLocale();
5181
- const actions = import_react17.default.useMemo(() => tabActions(sessionId), [sessionId]);
5182
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PixieTab, { actions, locale: active });
5784
+ const actions = import_react18.default.useMemo(() => tabActions(sessionId), [sessionId]);
5785
+ return withMarkdown(/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PixieTab, { actions, locale: active }));
5183
5786
  }
5184
5787
  scope.slots.inject("sidebar.right.pane.tab", () => scope.slots.register({ name: "sidebar.right.pane.tab", key: TAB_ID }, Body));
5185
5788
  const openTab = () => {
@@ -5187,18 +5790,67 @@ function mountPixie(ctx, options = {}) {
5187
5790
  };
5188
5791
  function CommandRow({ node, sessionId }) {
5189
5792
  const active = useLocale();
5190
- const rowActions = import_react17.default.useMemo(() => {
5793
+ const rowActions = import_react18.default.useMemo(() => {
5191
5794
  const tab = tabActions(sessionId);
5192
5795
  return { commandId: node.commandId, follow: tab.follow, commandTurn: () => unwrap(remote().commandTurn(sessionId, node.commandId)) };
5193
5796
  }, [sessionId, node.commandId]);
5194
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(StudioSurface, { className: "studio-pixie-command", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PixieCommandRow, { question: node.args?.trim() ?? "", outcome: node.outcome, locale: active, onOpen: openTab, actions: rowActions }) });
5797
+ return withMarkdown(/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StudioSurface, { className: "studio-pixie-command", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PixieCommandRow, { question: node.args?.trim() ?? "", outcome: node.outcome, locale: active, onOpen: openTab, actions: rowActions }) }));
5195
5798
  }
5196
5799
  scope.slots.inject("conversation.chat.commandview", () => scope.slots.register({ name: "conversation.chat.commandview", key: "pixie" }, CommandRow));
5800
+ function GateTailSurface({ children }) {
5801
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StudioSurface, { className: "studio-gate-tail", children });
5802
+ }
5803
+ const hubs = /* @__PURE__ */ new Map();
5804
+ const resultActions = (sessionId) => {
5805
+ let hub = hubs.get(sessionId);
5806
+ if (!hub) {
5807
+ const tab = tabActions(sessionId);
5808
+ hub = gateRunHub(tab.gateRuns, tab.followGates);
5809
+ hubs.set(sessionId, hub);
5810
+ }
5811
+ return { ...hub, setSessionGate: (gateId, enabled) => unwrap(remote().setSessionGate(sessionId, gateId, enabled)), openTab };
5812
+ };
5813
+ function TurnTail({ sessionId, turn }) {
5814
+ const active = useLocale();
5815
+ const actions = import_react18.default.useMemo(() => resultActions(sessionId), [sessionId]);
5816
+ if (turn.status !== "closed") return null;
5817
+ return withMarkdown(/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GateTail, { actions, turn: turn.turn, locale: active, Surface: GateTailSurface }));
5818
+ }
5819
+ scope.slots.inject("conversation.chat.turnTail", () => scope.slots.register({ name: "conversation.chat.turnTail", id: "studio-pixie-gate-tail" }, TurnTail));
5820
+ function GateResultRow({ sessionId, node }) {
5821
+ const active = useLocale();
5822
+ const actions = import_react18.default.useMemo(() => resultActions(sessionId), [sessionId]);
5823
+ const anchor = node.data.anchor;
5824
+ return withMarkdown(/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GateResults, { actions, anchor, locale: active, Surface: GateTailSurface }));
5825
+ }
5826
+ scope.inject(["uiConversation"], (inner) => {
5827
+ const conversation = inner.uiConversation;
5828
+ conversation.events.register(gateResultDefinition);
5829
+ inner.slots.inject("conversation.chat.node", () => inner.slots.register({ name: "conversation.chat.node", key: GATE_RESULT_NODE }, GateResultRow));
5830
+ });
5197
5831
  });
5198
5832
  }
5199
5833
 
5834
+ // src/ui-host.tsx
5835
+ var import_react19 = __toESM(require("react"), 1);
5836
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
5837
+ var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
5838
+ var import_jsx_runtime21 = require("react/jsx-runtime");
5839
+ var markdownLabels = /* @__PURE__ */ new Map();
5840
+ var labelsFor = (locale) => {
5841
+ let labels2 = markdownLabels.get(locale);
5842
+ if (!labels2) {
5843
+ labels2 = { code: { copyLabel: pixieText(locale, "mdCopy"), copiedLabel: pixieText(locale, "mdCopied") }, footnotes: pixieText(locale, "mdFootnotes") };
5844
+ markdownLabels.set(locale, labels2);
5845
+ }
5846
+ return labels2;
5847
+ };
5848
+ function DshMarkdown({ text, streaming, locale }) {
5849
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_dsh_client_ui_primitives.MarkdownText, { text, streaming, labels: labelsFor(locale), variant: "compact" });
5850
+ }
5851
+
5200
5852
  // src/shell.tsx
5201
- var import_jsx_runtime20 = require("react/jsx-runtime");
5853
+ var import_jsx_runtime22 = require("react/jsx-runtime");
5202
5854
  var inject = ["slots", "locale", "remote"];
5203
5855
  var panel = "local-dsh-studio";
5204
5856
  async function apply(ctx) {
@@ -5242,7 +5894,7 @@ async function apply(ctx) {
5242
5894
  } }) } }],
5243
5895
  result: { mode: "src-json" }
5244
5896
  })), ...pixieDescriptors()] });
5245
- mountPixie(ctx, { navFooter: (locale) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(VersionFooter, { store: updates, locale }) });
5897
+ mountPixie(ctx, { navFooter: (locale) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VersionFooter, { store: updates, locale }), markdown: DshMarkdown });
5246
5898
  ctx.effect(() => ctx.locale.addLanguage({ id: "ko", label: "\uD55C\uAD6D\uC5B4", fallback: "en" }));
5247
5899
  const serviceListeners = /* @__PURE__ */ new Set();
5248
5900
  let services = [];
@@ -5272,18 +5924,18 @@ async function apply(ctx) {
5272
5924
  const updates = createUpdateStore(updateActions, STUDIO_VERSION);
5273
5925
  void updates.refresh();
5274
5926
  function StudioServices({ renderSlot }) {
5275
- const items = import_react18.default.useSyncExternalStore((listener) => {
5927
+ const items = import_react20.default.useSyncExternalStore((listener) => {
5276
5928
  serviceListeners.add(listener);
5277
5929
  return () => {
5278
5930
  serviceListeners.delete(listener);
5279
5931
  };
5280
5932
  }, () => services);
5281
- const locale = import_react18.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), () => ctx.locale.getLocale().active);
5282
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StudioSurface, { className: "studio-shell", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("main", { className: "studio-page", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(ServiceLayout, { locale, services: items, renderSlot }) }) });
5933
+ const locale = import_react20.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), () => ctx.locale.getLocale().active);
5934
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(StudioSurface, { className: "studio-shell", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)("main", { className: "studio-page", children: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(ServiceLayout, { locale, services: items, renderSlot }) }) });
5283
5935
  }
5284
5936
  function Icon({ size = 20 }) {
5285
- const locale = import_react18.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), () => ctx.locale.getLocale().active);
5286
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(SidebarIcon, { size, store: updates, locale });
5937
+ const locale = import_react20.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), () => ctx.locale.getLocale().active);
5938
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SidebarIcon, { size, store: updates, locale });
5287
5939
  }
5288
5940
  ctx.slots.inject(
5289
5941
  "main",
@@ -5299,10 +5951,10 @@ async function apply(ctx) {
5299
5951
  )
5300
5952
  );
5301
5953
  function OptimizationPage() {
5302
- const locale = import_react18.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), () => ctx.locale.getLocale().active);
5303
- const [catalog, setCatalog] = import_react18.default.useState();
5304
- const [catalogError, setCatalogError] = import_react18.default.useState("");
5305
- import_react18.default.useEffect(() => {
5954
+ const locale = import_react20.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), () => ctx.locale.getLocale().active);
5955
+ const [catalog, setCatalog] = import_react20.default.useState();
5956
+ const [catalogError, setCatalogError] = import_react20.default.useState("");
5957
+ import_react20.default.useEffect(() => {
5306
5958
  let active = true;
5307
5959
  const remote2 = ctx.get("remote.studioCatalog");
5308
5960
  if (!remote2) {
@@ -5320,7 +5972,7 @@ async function apply(ctx) {
5320
5972
  active = false;
5321
5973
  };
5322
5974
  }, []);
5323
- const presetActions = import_react18.default.useMemo(() => {
5975
+ const presetActions = import_react20.default.useMemo(() => {
5324
5976
  const call = async (method, ...args) => {
5325
5977
  const service = ctx.get("remote.studioCatalog");
5326
5978
  const result = await service[method](...args);
@@ -5336,7 +5988,7 @@ async function apply(ctx) {
5336
5988
  delete: (id) => call("deletePreset", id)
5337
5989
  };
5338
5990
  }, []);
5339
- const extensionActions = import_react18.default.useMemo(() => {
5991
+ const extensionActions = import_react20.default.useMemo(() => {
5340
5992
  const call = async (method, ...args) => {
5341
5993
  const service = ctx.get("remote.studioCatalog");
5342
5994
  const result = await service[method](...args);
@@ -5353,7 +6005,7 @@ async function apply(ctx) {
5353
6005
  remove: (id) => update2("removeMasterPlugin", id)
5354
6006
  };
5355
6007
  }, []);
5356
- const catalogChanges = import_react18.default.useMemo(() => {
6008
+ const catalogChanges = import_react20.default.useMemo(() => {
5357
6009
  const call = async (method) => {
5358
6010
  const service = ctx.get("remote.studioCatalog");
5359
6011
  const result = await service[method]();
@@ -5362,10 +6014,10 @@ async function apply(ctx) {
5362
6014
  };
5363
6015
  return { read: () => call("catalogChange"), confirm: () => call("confirmCatalogChange") };
5364
6016
  }, []);
5365
- import_react18.default.useEffect(() => {
6017
+ import_react20.default.useEffect(() => {
5366
6018
  void updates.refresh();
5367
6019
  }, []);
5368
- return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(OptimizationPrototype, { catalogChanges, navFooter: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(VersionFooter, { store: updates, locale }), extensionActions, presetActions, locale, catalog, catalogError, onPreview: async (request) => {
6020
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(OptimizationPrototype, { catalogChanges, navFooter: /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VersionFooter, { store: updates, locale }), extensionActions, presetActions, locale, catalog, catalogError, onPreview: async (request) => {
5369
6021
  const service = ctx.get("remote.studioCatalog");
5370
6022
  const response = await service.preview(request);
5371
6023
  if (!response.ok) throw new Error(response.error?.message ?? "Preview failed");