@matamt-dbg/dsh-studio 0.3.0 → 0.4.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
@@ -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.4.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,7 +3433,7 @@ 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") }),
@@ -3353,7 +3465,7 @@ 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") }),
@@ -3370,8 +3482,223 @@ 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
+ onError: ["Pixie\uAC00 \uC2E4\uD328\uD558\uBA74", "If Pixie fails", "\u82E5 Pixie \u5931\u8D25"],
3584
+ errorPass: ["\uADF8\uB300\uB85C \uC9C4\uD589", "Continue as usual", "\u7167\u5E38\u7EE7\u7EED"],
3585
+ errorBlock: ["\uB9C9\uC74C", "Stop it", "\u62E6\u4E0B"],
3586
+ agents: ["\uB300\uC0C1 \uC5D0\uC774\uC804\uD2B8", "Target agents", "\u76EE\u6807\u4EE3\u7406"],
3587
+ root: ["\uBA54\uC778 \uC5D0\uC774\uC804\uD2B8", "Main agent", "\u4E3B\u4EE3\u7406"],
3588
+ child: ["\uC11C\uBE0C\uC5D0\uC774\uC804\uD2B8", "Subagents", "\u5B50\u4EE3\u7406"],
3589
+ any: ["\uBAA8\uB450", "All", "\u5168\u90E8"],
3590
+ timeout: ["\uC81C\uD55C \uC2DC\uAC04 (\uCD08)", "Time limit (seconds)", "\u65F6\u9650\uFF08\u79D2\uFF09"],
3591
+ maxSteers: ["\uD134\uB2F9 \uB2E4\uC2DC \uD558\uAE30 \uCD5C\uB300 \uD69F\uC218", "Redo limit per turn", "\u6BCF\u8F6E\u91CD\u505A\u4E0A\u9650"],
3592
+ // trial
3593
+ trial: ["\uAC8C\uC774\uD2B8 \uD14C\uC2A4\uD2B8", "Gate test", "\u95E8\u63A7\u6D4B\u8BD5"],
3594
+ trialSample: ["\uC608\uC2DC {target}", "Sample {target}", "\u793A\u4F8B{target}"],
3595
+ trialRun: ["\uC2E4\uD589", "Run", "\u8FD0\u884C"],
3596
+ 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"],
3597
+ 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"],
3598
+ trialTool: ["\uC608\uC2DC \uB3C4\uAD6C \uC774\uB984 (\uC120\uD0DD)", "Sample tool name (optional)", "\u793A\u4F8B\u5DE5\u5177\u540D\u79F0\uFF08\u53EF\u9009\uFF09"],
3599
+ trialRunning: ["\uC2E4\uD589 \uC911\u2026", "Running\u2026", "\u8FD0\u884C\u4E2D\u2026"],
3600
+ trialCancel: ["\uCDE8\uC18C", "Cancel", "\u53D6\u6D88"],
3601
+ trialFailed: ["\uC2DC\uD5D8 \uC2E4\uD589 \uC2E4\uD328", "Trial failed", "\u8BD5\u8FD0\u884C\u5931\u8D25"],
3602
+ 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}"],
3603
+ trialApplied: ["\uC2E4\uC81C \uC801\uC6A9", "What happens", "\u5B9E\u9645\u6548\u679C"],
3604
+ "plan-stop": ["\uB9C9\uC74C", "Stopped", "\u5DF2\u62E6\u4E0B"],
3605
+ "plan-confirm": ["\uAD50\uCCB4 \uC804 \uD655\uC778\uC744 \uC694\uCCAD\uD568", "Asks before replacing", "\u66FF\u6362\u524D\u8BF7\u6C42\u786E\u8BA4"],
3606
+ "plan-replace": ["\uB0B4\uC6A9\uC744 \uBC14\uAFC8", "Replaces the content", "\u66FF\u6362\u5185\u5BB9"],
3607
+ "plan-append": ["\uB0B4\uC6A9\uC744 \uB367\uBD99\uC784", "Adds content", "\u8FFD\u52A0\u5185\u5BB9"],
3608
+ "plan-pass": ["\uADF8\uB300\uB85C \uD1B5\uACFC", "Passes unchanged", "\u539F\u6837\u901A\u8FC7"],
3609
+ trialPass: ["\uD1B5\uACFC", "Pass", "\u901A\u8FC7"],
3610
+ trialStop: ["\uB9C9\uC74C", "Stopped", "\u5DF2\u62E6\u4E0B"],
3611
+ trialEmpty: ["(\uBE44\uC5B4 \uC788\uC74C)", "(empty)", "\uFF08\u7A7A\uFF09"],
3612
+ // problems
3613
+ "problem-name": ["\uC774\uB984\uC744 \uC785\uB825\uD558\uC138\uC694.", "Enter a name.", "\u8BF7\u8F93\u5165\u540D\u79F0\u3002"],
3614
+ "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"],
3615
+ "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"],
3616
+ // scope
3617
+ enabled: ["\uCF1C\uC9D0", "Enabled", "\u542F\u7528"],
3618
+ presets: ["\uC801\uC6A9 \uD504\uB9AC\uC14B", "Presets", "\u9002\u7528\u9884\u8BBE"],
3619
+ 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"],
3620
+ choosePresets: ["\uD504\uB9AC\uC14B \uC120\uD0DD", "Choose presets", "\u9009\u62E9\u9884\u8BBE"],
3621
+ searchPresets: ["\uD504\uB9AC\uC14B \uAC80\uC0C9", "Search presets", "\u641C\u7D22\u9884\u8BBE"],
3622
+ done: ["\uC644\uB8CC", "Done", "\u5B8C\u6210"],
3623
+ 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"],
3624
+ // templates
3625
+ "tpl-format-check": ["\uC791\uC5C5 \uC9C0\uC2DC \uC591\uC2DD \uAC80\uC0AC", "Instruction format check", "\u4EFB\u52A1\u6307\u4EE4\u683C\u5F0F\u68C0\u67E5"],
3626
+ "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"],
3627
+ "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"],
3628
+ "tpl-agent-protocol": ["\uC5D0\uC774\uC804\uD2B8 \uB300\uD654 \uADDC\uACA9 \uD310\uC815", "Agent message protocol", "\u4EE3\u7406\u6D88\u606F\u89C4\u8303\u5224\u5B9A"],
3629
+ "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"],
3630
+ "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"],
3631
+ "tpl-command-guard": ["\uC704\uD5D8\uD55C \uBA85\uB839 \uCC28\uB2E8", "Block risky commands", "\u62E6\u622A\u5371\u9669\u547D\u4EE4"],
3632
+ "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"],
3633
+ "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"],
3634
+ "tpl-tool-digest": ["\uAE34 \uB3C4\uAD6C \uACB0\uACFC \uC694\uC57D", "Digest long tool results", "\u6982\u62EC\u5197\u957F\u7684\u5DE5\u5177\u7ED3\u679C"],
3635
+ "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"],
3636
+ "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"],
3637
+ "tpl-verify-answer": ["\uCD5C\uC885 \uB2F5\uBCC0 \uAC80\uC99D", "Verify the final answer", "\u9A8C\u8BC1\u6700\u7EC8\u56DE\u7B54"],
3638
+ "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"],
3639
+ "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"]
3640
+ };
3641
+ function gateTaskText(locale, key, values = {}) {
3642
+ const text = messages2[key][locale.startsWith("ko") ? 0 : locale.startsWith("zh") ? 2 : 1];
3643
+ return text.replace(/\{(\w+)\}/g, (match, name) => name in values ? String(values[name]) : match);
3644
+ }
3645
+
3373
3646
  // src/pixie-gate-runs.tsx
3374
3647
  var import_jsx_runtime15 = require("react/jsx-runtime");
3648
+ function SessionGateList({ actions, locale, disabled }) {
3649
+ const t = (key) => gateText(locale, key);
3650
+ const [view, setView] = import_react13.default.useState();
3651
+ const [busy, setBusy] = import_react13.default.useState();
3652
+ const [error, setError] = import_react13.default.useState("");
3653
+ const load = actions.sessionGates;
3654
+ import_react13.default.useEffect(() => {
3655
+ if (!load) return;
3656
+ let active = true;
3657
+ void load().then((next) => {
3658
+ if (active) setView(next);
3659
+ }, (cause) => {
3660
+ if (active) setError(String(cause));
3661
+ });
3662
+ return () => {
3663
+ active = false;
3664
+ };
3665
+ }, [load]);
3666
+ import_react13.default.useEffect(() => {
3667
+ if (!disabled) return;
3668
+ const off = new Set(disabled);
3669
+ setView((current) => current && { ...current, gates: current.gates.map((gate) => ({ ...gate, sessionEnabled: !off.has(gate.id) })) });
3670
+ }, [disabled]);
3671
+ if (!load || !actions.setSessionGate || !view) return null;
3672
+ const toggle = async (id, enabled) => {
3673
+ setBusy(id);
3674
+ setError("");
3675
+ try {
3676
+ const off = new Set(await actions.setSessionGate(id, enabled));
3677
+ setView((current) => current && { ...current, gates: current.gates.map((gate) => ({ ...gate, sessionEnabled: !off.has(gate.id) })) });
3678
+ } catch (cause) {
3679
+ setError(`${t("sessionGateFailed")} (${cause instanceof Error ? cause.message : String(cause)})`);
3680
+ } finally {
3681
+ setBusy(void 0);
3682
+ }
3683
+ };
3684
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("section", { className: "studio-gate-block studio-gate-session", "aria-label": t("sessionGates"), children: [
3685
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SectionHead, { title: t("sessionGates"), description: t("sessionGatesHint") }),
3686
+ error && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Notice, { children: error }),
3687
+ !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: [
3688
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "studio-gate-session-name", children: [
3689
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("strong", { children: gate.name }),
3690
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { className: "studio-card-meta", children: [
3691
+ gateTaskText(locale, `when-${gate.when}`),
3692
+ gate.script ? ` \xB7 ${gate.script}` : "",
3693
+ gate.sessionEnabled ? "" : ` \xB7 ${t("sessionGateOff")}`
3694
+ ] })
3695
+ ] }),
3696
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Toggle, { label: t("sessionGateToggle").replace("{name}", gate.name), checked: gate.sessionEnabled, disabled: busy === gate.id, onChange: (checked) => {
3697
+ void toggle(gate.id, checked);
3698
+ } })
3699
+ ] }, gate.id)) })
3700
+ ] });
3701
+ }
3375
3702
  function gateRunStatus(run) {
3376
3703
  return run.applied !== "none" ? run.applied : run.status === "done" ? "none" : run.status;
3377
3704
  }
@@ -3381,6 +3708,7 @@ function GateRunsPanel({ actions, locale }) {
3381
3708
  const [openId, setOpenId] = import_react13.default.useState();
3382
3709
  const [error, setError] = import_react13.default.useState("");
3383
3710
  const [busy, setBusy] = import_react13.default.useState(false);
3711
+ const [disabled, setDisabled] = import_react13.default.useState();
3384
3712
  import_react13.default.useEffect(() => {
3385
3713
  let active = true;
3386
3714
  let generation = 0;
@@ -3405,6 +3733,10 @@ function GateRunsPanel({ actions, locale }) {
3405
3733
  void refresh();
3406
3734
  return;
3407
3735
  }
3736
+ if (frame.type === "session") {
3737
+ setDisabled(frame.disabledGateIds);
3738
+ return;
3739
+ }
3408
3740
  updates.set(frame.run.id, frame.run);
3409
3741
  setRuns((current) => [...current.filter((run) => run.id !== frame.run.id), frame.run]);
3410
3742
  });
@@ -3434,6 +3766,7 @@ function GateRunsPanel({ actions, locale }) {
3434
3766
  }
3435
3767
  };
3436
3768
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "studio-pixie-chat", children: [
3769
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SessionGateList, { actions, locale, disabled }),
3437
3770
  error && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Notice, { children: error }),
3438
3771
  !runs.length && /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Note, { children: t("emptyRuns") }),
3439
3772
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { className: "studio-pixie-threads", "data-open": opened ? "true" : "false", children: [
@@ -3470,6 +3803,10 @@ function GateRunsPanel({ actions, locale }) {
3470
3803
  /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("dl", { className: "studio-gate-facts", children: [
3471
3804
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dt", { children: t("applied") }),
3472
3805
  /* @__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) }) }),
3806
+ shown.result?.concludedBy && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
3807
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dt", { children: t("concludedBy") }),
3808
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dd", { children: t(shown.result.concludedBy === "script" ? "concludedScript" : shown.result.concludedBy === "skipped" ? "concludedSkipped" : "concludedPixie") })
3809
+ ] }),
3473
3810
  shown.output && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(import_jsx_runtime15.Fragment, { children: [
3474
3811
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dt", { children: t("verdict") }),
3475
3812
  /* @__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 +3878,7 @@ function GateRunsPanel({ actions, locale }) {
3541
3878
  ] })
3542
3879
  ] }),
3543
3880
  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") }),
3881
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(SectionHead, { title: t(shown.result?.concludedBy === "script" ? "scriptOutput" : "output") }),
3545
3882
  /* @__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
3883
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dt", { children: t(key === "note" ? "notes" : key) }),
3547
3884
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("dd", { className: "studio-gate-text", children: shown.output[key] })
@@ -3558,6 +3895,39 @@ function GateRunsPanel({ actions, locale }) {
3558
3895
 
3559
3896
  // src/pixie-locale.ts
3560
3897
  var en4 = {
3898
+ mdCopy: "Copy",
3899
+ mdCopied: "Copied",
3900
+ mdFootnotes: "Footnotes",
3901
+ pageJudge: "Decision engine",
3902
+ pageJudgeDescription: "The engine behind 'pixie judge' in gate hook scripts. Judgments run only when a script asks for one.",
3903
+ judgeEngine: "Engine",
3904
+ judgeEngineLlm: "LLM",
3905
+ judgeEngineJev: "Jev",
3906
+ judgeEngineLlmHint: "A conversation model answers in the Jev format.",
3907
+ judgeEngineJevHint: "TypeSafe Jev answers through its API. Gate input is sent to TypeSafe.",
3908
+ judgeModel: "Judge model",
3909
+ judgeModelHint: "When not set, the value entered in the Pixie model settings is used.",
3910
+ judgeModelPixie: "Pixie model",
3911
+ judgePrompt: "Judge system prompt",
3912
+ judgePromptHint: "Leave empty for the built-in prompt.",
3913
+ jevModel: "Jev model",
3914
+ jevModelHint: "A model ID or alias such as jev-latest. Pin a version once you tune thresholds.",
3915
+ jevKey: "TypeSafe API key",
3916
+ jevKeyHint: "Stored in DSH credentials as TYPESAFE_API_KEY. It is never shown again.",
3917
+ jevKeySet: "Set",
3918
+ jevKeyFrom: "Source: {source}",
3919
+ jevKeyMissing: "Not set",
3920
+ jevKeyReadOnly: "Set by a read-only source ({source}). Change it there.",
3921
+ jevKeyUnavailable: "The DSH credentials service is not available, so the key cannot be stored here.",
3922
+ jevKeyPlaceholder: "Paste the key",
3923
+ jevKeySave: "Save key",
3924
+ jevKeyDelete: "Remove key",
3925
+ jevKeyFailed: "Could not update the key.",
3926
+ errCredentialsRefs: "The DSH credentials file (.credentials.yaml in the DSH home) has an empty refs: line. Change it to refs: {} and save again.",
3927
+ jevKeySaving: "Saving\u2026",
3928
+ jevKeyRemoving: "Removing\u2026",
3929
+ jevKeySaved: "Key saved.",
3930
+ jevKeyRemoved: "Key removed.",
3561
3931
  title: "Pixie",
3562
3932
  chat: "Threads",
3563
3933
  judge: "Judge",
@@ -3635,34 +4005,67 @@ var en4 = {
3635
4005
  errEmpty: "Type a question after /pixie."
3636
4006
  };
3637
4007
  var ko4 = {
4008
+ mdCopy: "\uBCF5\uC0AC",
4009
+ mdCopied: "\uBCF5\uC0AC\uB428",
4010
+ mdFootnotes: "\uAC01\uC8FC",
4011
+ pageJudge: "\uACB0\uC815 \uC5D4\uC9C4",
4012
+ 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.",
4013
+ judgeEngine: "\uC5D4\uC9C4",
4014
+ judgeEngineLlm: "LLM",
4015
+ judgeEngineJev: "Jev",
4016
+ judgeEngineLlmHint: "\uB300\uD654 \uBAA8\uB378\uC774 Jev \uD615\uC2DD\uC73C\uB85C \uB2F5\uC744 \uC0DD\uC131\uD569\uB2C8\uB2E4.",
4017
+ judgeEngineJevHint: "TypeSafe Jev API\uAC00 \uB2F5\uD569\uB2C8\uB2E4. \uAC8C\uC774\uD2B8 \uC785\uB825\uC774 TypeSafe\uB85C \uC804\uC1A1\uB429\uB2C8\uB2E4.",
4018
+ judgeModel: "\uD310\uC815 \uBAA8\uB378",
4019
+ judgeModelHint: "\uC815\uD558\uC9C0 \uC54A\uC73C\uBA74 Pixie \uBAA8\uB378 \uC124\uC815\uC5D0\uC11C \uC785\uB825\uD55C \uAC12\uC744 \uC0AC\uC6A9\uD569\uB2C8\uB2E4.",
4020
+ judgeModelPixie: "Pixie \uBAA8\uB378",
4021
+ judgePrompt: "\uD310\uC815 \uC2DC\uC2A4\uD15C \uD504\uB86C\uD504\uD2B8",
4022
+ judgePromptHint: "\uBE44\uC6B0\uBA74 \uAE30\uBCF8 \uD504\uB86C\uD504\uD2B8\uB97C \uC501\uB2C8\uB2E4.",
4023
+ jevModel: "Jev \uBAA8\uB378",
4024
+ 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.",
4025
+ jevKey: "TypeSafe API \uD0A4",
4026
+ 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.",
4027
+ jevKeySet: "\uC124\uC815\uB428",
4028
+ jevKeyFrom: "\uCD9C\uCC98: {source}",
4029
+ jevKeyMissing: "\uC124\uC815 \uC548 \uB428",
4030
+ 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.",
4031
+ 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.",
4032
+ jevKeyPlaceholder: "\uD0A4 \uBD99\uC5EC \uB123\uAE30",
4033
+ jevKeySave: "\uD0A4 \uC800\uC7A5",
4034
+ jevKeyDelete: "\uD0A4 \uC0AD\uC81C",
4035
+ jevKeyFailed: "\uD0A4\uB97C \uBC14\uAFB8\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.",
4036
+ 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.",
4037
+ jevKeySaving: "\uC800\uC7A5 \uC911\u2026",
4038
+ jevKeyRemoving: "\uC0AD\uC81C \uC911\u2026",
4039
+ jevKeySaved: "\uD0A4\uB97C \uC800\uC7A5\uD588\uC2B5\uB2C8\uB2E4.",
4040
+ jevKeyRemoved: "\uD0A4\uB97C \uC0AD\uC81C\uD588\uC2B5\uB2C8\uB2E4.",
3638
4041
  title: "Pixie",
3639
4042
  chat: "\uC2A4\uB808\uB4DC",
3640
4043
  judge: "\uD310\uC815",
3641
4044
  threads: "Pixie \uC2A4\uB808\uB4DC",
3642
4045
  newThread: "\uC0C8 \uC2A4\uB808\uB4DC",
3643
4046
  fresh: "\uC0C8 \uB300\uD654",
3644
- fork: "\uC774\uC5B4\uBC1B\uAE30",
4047
+ fork: "\uC774\uC5B4\uC4F0\uAE30",
3645
4048
  mode: "\uCEE8\uD14D\uC2A4\uD2B8 \uBAA8\uB4DC",
3646
4049
  model: "\uBAA8\uB378",
3647
4050
  allThreads: "\uC804\uCCB4 \uC2A4\uB808\uB4DC",
3648
4051
  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",
4052
+ activeBadge: "\uC5EC\uAE30\uB85C /pixie \uBCF4\uB0B4\uAE30",
4053
+ makeTarget: "/pixie\uB97C \uC774 \uC2A4\uB808\uB4DC\uB85C \uBCF4\uB0B4\uAE30",
3651
4054
  freshMeta: "\uBE48 \uC0C1\uD0DC\uB85C \uC2DC\uC791",
3652
- forkMeta: "\uC138\uC158 \uB300\uD654 \uBCF5\uC0AC",
4055
+ forkMeta: "\uC138\uC158 \uD14D\uC2A4\uD2B8\uB97C \uBCF5\uC0AC\uD568",
3653
4056
  noTurns: "\uC544\uC9C1 \uC9C8\uBB38\uC774 \uC5C6\uC2B5\uB2C8\uB2E4",
3654
4057
  streaming: "\uB2F5\uBCC0 \uC911",
3655
4058
  cancelled: "\uCDE8\uC18C\uB428",
3656
4059
  error: "\uC2E4\uD328",
3657
4060
  cancel: "\uCDE8\uC18C",
3658
- ask: "\uC694\uCCAD",
4061
+ ask: "\uBB3B\uAE30",
3659
4062
  retry: "\uB2E4\uC2DC \uC2DC\uB3C4",
3660
4063
  loading: "\uBD88\uB7EC\uC624\uB294 \uC911\u2026",
3661
4064
  question: "Pixie\uC5D0\uAC8C \uC9C8\uBB38",
3662
4065
  placeholder: "Pixie\uC5D0\uAC8C \uBB3B\uAE30\u2026 (\u2318/Ctrl+Enter)",
3663
4066
  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
4067
  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.",
4068
+ 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
4069
  judgeState: "\uC0C1\uD0DC (\uD14D\uC2A4\uD2B8 \uB610\uB294 JSON)",
3667
4070
  judgeQuestions: "\uC9C8\uBB38 (ID\uBCC4 JSON)",
3668
4071
  runJudge: "\uD310\uC815 \uC2E4\uD589",
@@ -3706,12 +4109,45 @@ var ko4 = {
3706
4109
  create: "\uB9CC\uB4E4\uAE30",
3707
4110
  noThreads: "\uC544\uC9C1 \uC2A4\uB808\uB4DC\uAC00 \uC5C6\uC2B5\uB2C8\uB2E4",
3708
4111
  rowWaiting: "Pixie\uAC00 \uB2F5\uBCC0\uD558\uB294 \uC911\u2026",
3709
- truncated: "\uD1A0\uD070 \uD55C\uB3C4\uC5D0 \uAC78\uB824 \uC798\uB9BC",
4112
+ truncated: "\uD1A0\uD070 \uD55C\uB3C4\uC5D0\uC11C \uC798\uB838\uC2B5\uB2C8\uB2E4",
3710
4113
  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
4114
  errBusy: "\uC774 \uC138\uC158\uC5D0\uC11C Pixie\uAC00 \uC544\uC9C1 \uB2F5\uBCC0 \uC911\uC785\uB2C8\uB2E4.",
3712
4115
  errEmpty: "/pixie \uB4A4\uC5D0 \uC9C8\uBB38\uC744 \uC785\uB825\uD558\uC138\uC694."
3713
4116
  };
3714
4117
  var zh4 = {
4118
+ mdCopy: "\u590D\u5236",
4119
+ mdCopied: "\u5DF2\u590D\u5236",
4120
+ mdFootnotes: "\u811A\u6CE8",
4121
+ pageJudge: "\u51B3\u7B56\u5F15\u64CE",
4122
+ 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",
4123
+ judgeEngine: "\u5F15\u64CE",
4124
+ judgeEngineLlm: "LLM",
4125
+ judgeEngineJev: "Jev",
4126
+ judgeEngineLlmHint: "\u7531\u5BF9\u8BDD\u6A21\u578B\u6309 Jev \u683C\u5F0F\u56DE\u7B54\u3002",
4127
+ judgeEngineJevHint: "\u7531 TypeSafe Jev API \u56DE\u7B54\uFF0C\u95E8\u63A7\u8F93\u5165\u4F1A\u53D1\u9001\u7ED9 TypeSafe\u3002",
4128
+ judgeModel: "\u5224\u5B9A\u6A21\u578B",
4129
+ judgeModelHint: "\u672A\u8BBE\u7F6E\u65F6\u4F7F\u7528 Pixie \u6A21\u578B\u8BBE\u7F6E\u4E2D\u586B\u5199\u7684\u503C\u3002",
4130
+ judgeModelPixie: "Pixie \u6A21\u578B",
4131
+ judgePrompt: "\u5224\u5B9A\u7CFB\u7EDF\u63D0\u793A\u8BCD",
4132
+ judgePromptHint: "\u7559\u7A7A\u5219\u4F7F\u7528\u5185\u7F6E\u63D0\u793A\u8BCD\u3002",
4133
+ jevModel: "Jev \u6A21\u578B",
4134
+ jevModelHint: "\u6A21\u578B ID \u6216\u522B\u540D\uFF0C\u5982 jev-latest\u3002\u8C03\u597D\u9608\u503C\u540E\u8BF7\u56FA\u5B9A\u7248\u672C\u3002",
4135
+ jevKey: "TypeSafe API \u5BC6\u94A5",
4136
+ jevKeyHint: "\u4EE5 TYPESAFE_API_KEY \u5B58\u5165 DSH \u51ED\u636E\uFF0C\u4FDD\u5B58\u540E\u4E0D\u518D\u663E\u793A\u3002",
4137
+ jevKeySet: "\u5DF2\u8BBE\u7F6E",
4138
+ jevKeyFrom: "\u6765\u6E90\uFF1A{source}",
4139
+ jevKeyMissing: "\u672A\u8BBE\u7F6E",
4140
+ jevKeyReadOnly: "\u7531\u53EA\u8BFB\u6765\u6E90\uFF08{source}\uFF09\u8BBE\u7F6E\uFF0C\u8BF7\u5728\u8BE5\u5904\u4FEE\u6539\u3002",
4141
+ jevKeyUnavailable: "DSH \u51ED\u636E\u670D\u52A1\u4E0D\u53EF\u7528\uFF0C\u65E0\u6CD5\u5728\u6B64\u4FDD\u5B58\u5BC6\u94A5\u3002",
4142
+ jevKeyPlaceholder: "\u7C98\u8D34\u5BC6\u94A5",
4143
+ jevKeySave: "\u4FDD\u5B58\u5BC6\u94A5",
4144
+ jevKeyDelete: "\u5220\u9664\u5BC6\u94A5",
4145
+ jevKeyFailed: "\u65E0\u6CD5\u66F4\u65B0\u5BC6\u94A5\u3002",
4146
+ 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",
4147
+ jevKeySaving: "\u4FDD\u5B58\u4E2D\u2026",
4148
+ jevKeyRemoving: "\u5220\u9664\u4E2D\u2026",
4149
+ jevKeySaved: "\u5DF2\u4FDD\u5B58\u5BC6\u94A5",
4150
+ jevKeyRemoved: "\u5DF2\u5220\u9664\u5BC6\u94A5",
3715
4151
  title: "Pixie",
3716
4152
  chat: "\u7EBF\u7A0B",
3717
4153
  judge: "\u5224\u5B9A",
@@ -3794,10 +4230,13 @@ function pixieText(locale, key) {
3794
4230
  return table[key];
3795
4231
  }
3796
4232
  var PIXIE_ERROR_CODES = { "pixie/no-model": "errNoModel", "pixie/busy": "errBusy", "pixie/empty": "errEmpty" };
4233
+ var PIXIE_DETAILED_ERROR_CODES = { "pixie/credentials-refs": "errCredentialsRefs" };
3797
4234
  function pixieError(locale, message4) {
3798
4235
  const match = /^\[(pixie\/[\w-]+)\]\s*/.exec(message4);
3799
4236
  const key = match ? PIXIE_ERROR_CODES[match[1]] : void 0;
3800
- return key ? pixieText(locale, key) : message4;
4237
+ if (key) return pixieText(locale, key);
4238
+ const detailed = match ? PIXIE_DETAILED_ERROR_CODES[match[1]] : void 0;
4239
+ return detailed ? `${pixieText(locale, detailed)} (${message4.slice(match[0].length)})` : message4;
3801
4240
  }
3802
4241
 
3803
4242
  // src/pixie-tab.tsx
@@ -3812,7 +4251,7 @@ function Turn({ turn, live, locale }) {
3812
4251
  const answer = live ?? turn.answer;
3813
4252
  return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("li", { className: "studio-pixie-turn", children: [
3814
4253
  /* @__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 }),
4254
+ answer && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(ModelText, { text: answer, locale, streaming: live !== void 0 || turn.status === "streaming" }),
3816
4255
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "studio-pixie-turn-meta", children: [
3817
4256
  turn.status === "streaming" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Badge, { tone: "info", children: t("streaming") }),
3818
4257
  turn.status === "cancelled" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Badge, { tone: "neutral", children: t("cancelled") }),
@@ -4098,7 +4537,7 @@ function PixieCommandRow({ question, outcome, locale, onOpen, actions }) {
4098
4537
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "studio-pixie-row-question", children: question }),
4099
4538
  /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Button, { small: true, onClick: onOpen, children: t("openTab") })
4100
4539
  ] }),
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") }),
4540
+ 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
4541
  /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "studio-pixie-turn-meta", children: [
4103
4542
  status === "cancelled" && answer && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Badge, { tone: "neutral", children: t("cancelled") }),
4104
4543
  turn?.truncated && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(Badge, { tone: "warning", children: t("truncated") })
@@ -4106,172 +4545,91 @@ function PixieCommandRow({ question, outcome, locale, onOpen, actions }) {
4106
4545
  ] });
4107
4546
  }
4108
4547
 
4548
+ // src/pixie-gate-tail.tsx
4549
+ var import_react15 = __toESM(require("react"), 1);
4550
+ var import_jsx_runtime17 = require("react/jsx-runtime");
4551
+ var UNVERIFIED = /미확인|not verified|unverified|未确认/i;
4552
+ function tailRun(runs, turn) {
4553
+ return runs.filter((run) => run.point === "turn-end" && run.turn === turn && run.status === "done" && run.result?.concludedBy === "script" && typeof run.output?.note === "string" && run.output.note.trim() !== "").sort((a, b) => a.startedAt - b.startedAt).at(-1);
4554
+ }
4555
+ function splitNote(note) {
4556
+ const match = /^\s*\[([^\]\n]{1,80})\]\s*\n?/.exec(note);
4557
+ return match ? { label: match[1], body: note.slice(match[0].length) } : { body: note };
4558
+ }
4559
+ function GateTail({ actions, turn, locale, Surface = import_react15.default.Fragment }) {
4560
+ const t = (key) => gateText(locale, key);
4561
+ const [runs, setRuns] = import_react15.default.useState([]);
4562
+ const [disabled, setDisabled] = import_react15.default.useState([]);
4563
+ const [open, setOpen] = import_react15.default.useState(true);
4564
+ const [busy, setBusy] = import_react15.default.useState(false);
4565
+ const [error, setError] = import_react15.default.useState("");
4566
+ import_react15.default.useEffect(() => {
4567
+ let active = true;
4568
+ const refresh = () => actions.gateRuns().then((record2) => {
4569
+ if (active) {
4570
+ setRuns(record2.runs);
4571
+ setDisabled(record2.disabledGateIds ?? []);
4572
+ }
4573
+ }, () => {
4574
+ });
4575
+ const stop = actions.followGates((frame) => {
4576
+ if (!active) return;
4577
+ if (frame.type === "sync") {
4578
+ void refresh();
4579
+ return;
4580
+ }
4581
+ if (frame.type === "session") {
4582
+ setDisabled(frame.disabledGateIds);
4583
+ return;
4584
+ }
4585
+ setRuns((current) => [...current.filter((run2) => run2.id !== frame.run.id), frame.run]);
4586
+ });
4587
+ void refresh();
4588
+ return () => {
4589
+ active = false;
4590
+ stop();
4591
+ };
4592
+ }, [actions]);
4593
+ const run = tailRun(runs, turn);
4594
+ if (!run) return null;
4595
+ const { label, body } = splitNote(run.output.note);
4596
+ const off = disabled.includes(run.gateId);
4597
+ const unverified = !!label && UNVERIFIED.test(label);
4598
+ const turnOff = async () => {
4599
+ setBusy(true);
4600
+ setError("");
4601
+ try {
4602
+ setDisabled(await actions.setSessionGate(run.gateId, false));
4603
+ } catch (cause) {
4604
+ setError(`${t("sessionGateFailed")} (${cause instanceof Error ? cause.message : String(cause)})`);
4605
+ } finally {
4606
+ setBusy(false);
4607
+ }
4608
+ };
4609
+ return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Surface, { children: /* @__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-unverified": unverified ? "true" : void 0, children: [
4610
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "studio-gate-tail-head", children: [
4611
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("strong", { children: label ?? run.gateName }),
4612
+ unverified && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Badge, { tone: "warning", children: t("tailUnverified") }),
4613
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "studio-card-meta", children: t("tailTitle").replace("{name}", run.gateName) }),
4614
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "studio-inline-actions", children: [
4615
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, onClick: () => setOpen((value) => !value), children: t(open ? "tailHide" : "tailShow") }),
4616
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, onClick: actions.openTab, children: t("tailOpen") }),
4617
+ !off && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, disabled: busy, onClick: () => {
4618
+ void turnOff();
4619
+ }, children: t("tailOff") })
4620
+ ] })
4621
+ ] }),
4622
+ error && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Notice, { children: error }),
4623
+ off && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { role: "status", className: "studio-muted", children: t("tailOffDone") }),
4624
+ open && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ModelText, { text: body, locale })
4625
+ ] }) });
4626
+ }
4627
+
4109
4628
  // src/pixie-settings.tsx
4110
- var import_react16 = __toESM(require("react"), 1);
4629
+ var import_react17 = __toESM(require("react"), 1);
4111
4630
 
4112
4631
  // src/pixie-gate-task-pages.tsx
4113
- var import_react15 = __toESM(require("react"), 1);
4114
-
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"]
4270
- };
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);
4274
- }
4632
+ var import_react16 = __toESM(require("react"), 1);
4275
4633
 
4276
4634
  // src/pixie-gate-task.ts
4277
4635
  var GATE_WHENS = ["user-message", "agent-message", "tool-before", "tool-after", "turn-end"];
@@ -4308,16 +4666,16 @@ function taskVariables(task) {
4308
4666
  }
4309
4667
  function taskProblem(task) {
4310
4668
  if (!task.name.trim()) return "name";
4311
- if (!task.instruction.trim()) return "instruction";
4669
+ if (!task.instruction.trim() && task.advanced.script === void 0) return "instruction";
4312
4670
  if (!(task.advanced.timeoutMs > 0) || !Number.isInteger(task.advanced.maxSteers) || task.advanced.maxSteers < 0) return "limits";
4313
4671
  return void 0;
4314
4672
  }
4315
4673
 
4316
4674
  // src/pixie-gate-task-pages.tsx
4317
- var import_jsx_runtime17 = require("react/jsx-runtime");
4675
+ var import_jsx_runtime18 = require("react/jsx-runtime");
4318
4676
  var withLink = (text, link) => {
4319
4677
  const [before, after = ""] = text.split("{link}");
4320
- return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
4678
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4321
4679
  before,
4322
4680
  link,
4323
4681
  after
@@ -4325,13 +4683,13 @@ var withLink = (text, link) => {
4325
4683
  };
4326
4684
  var useText = (locale) => (key, values) => gateTaskText(locale, key, values);
4327
4685
  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 () => {
4686
+ const [tasks, setTasks] = import_react16.default.useState();
4687
+ const [stored, setStored] = import_react16.default.useState("");
4688
+ const [invalid, setInvalid] = import_react16.default.useState([]);
4689
+ const [error, setError] = import_react16.default.useState("");
4690
+ const [status, setStatus] = import_react16.default.useState("idle");
4691
+ const [saveError, setSaveError] = import_react16.default.useState("");
4692
+ const load = import_react16.default.useCallback(async () => {
4335
4693
  setError("");
4336
4694
  try {
4337
4695
  const read = await actions.read();
@@ -4343,7 +4701,7 @@ function useGateTasks(actions) {
4343
4701
  setError(cause instanceof Error ? cause.message : String(cause));
4344
4702
  }
4345
4703
  }, [actions]);
4346
- import_react15.default.useEffect(() => {
4704
+ import_react16.default.useEffect(() => {
4347
4705
  void load();
4348
4706
  }, [load]);
4349
4707
  const edit = (change) => {
@@ -4383,17 +4741,17 @@ function useGateTasks(actions) {
4383
4741
  };
4384
4742
  }
4385
4743
  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: () => {
4744
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4745
+ /* @__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
4746
  void gates.saveAll();
4389
4747
  }, 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: () => {
4748
+ 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})` }),
4749
+ gates.error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { action: /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: () => {
4392
4750
  void gates.load();
4393
4751
  }, 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") })
4752
+ !gates.error && !gates.loaded && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "status", className: "studio-muted", children: t("loading") }),
4753
+ 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("; ") }) }),
4754
+ gates.dirty && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { tone: "info", children: t("unsaved") })
4397
4755
  ] });
4398
4756
  }
4399
4757
  function TemplatePicker({ open, locale, onPick, onClose }) {
@@ -4402,25 +4760,25 @@ function TemplatePicker({ open, locale, onPick, onClose }) {
4402
4760
  name: t(`tpl-${template.id}`),
4403
4761
  instruction: t(`tplText-${template.id}`)
4404
4762
  }));
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: [
4763
+ 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: [
4764
+ 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
4765
  t(`tpl-${template.id}`),
4408
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Badge, { tone: "outline", children: t(`when-${template.when}`) })
4766
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Badge, { tone: "outline", children: t(`when-${template.when}`) })
4409
4767
  ] }), 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"))) }) })
4768
+ /* @__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
4769
  ] }) });
4412
4770
  }
4413
4771
  function GateTaskEditor({ task: initial2, open, locale, actions, onApply, onClose }) {
4414
4772
  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 () => {
4773
+ const [task, setTask] = import_react16.default.useState(initial2);
4774
+ const [problem, setProblem] = import_react16.default.useState();
4775
+ const [sample, setSample] = import_react16.default.useState("");
4776
+ const [toolName, setToolName] = import_react16.default.useState("");
4777
+ const [trial, setTrial] = import_react16.default.useState();
4778
+ const [copied, setCopied] = import_react16.default.useState(false);
4779
+ const [scripts, setScripts] = import_react16.default.useState();
4780
+ const [scriptError, setScriptError] = import_react16.default.useState("");
4781
+ const refreshScripts = import_react16.default.useCallback(async () => {
4424
4782
  setScriptError("");
4425
4783
  try {
4426
4784
  setScripts(await actions.scripts());
@@ -4428,19 +4786,19 @@ function GateTaskEditor({ task: initial2, open, locale, actions, onApply, onClos
4428
4786
  setScriptError(cause instanceof Error ? cause.message : String(cause));
4429
4787
  }
4430
4788
  }, [actions]);
4431
- import_react15.default.useEffect(() => {
4789
+ import_react16.default.useEffect(() => {
4432
4790
  if (open) void refreshScripts();
4433
4791
  }, [open, refreshScripts]);
4434
- import_react15.default.useEffect(() => {
4792
+ import_react16.default.useEffect(() => {
4435
4793
  setTask(initial2);
4436
4794
  setProblem(void 0);
4437
4795
  setSample("");
4438
4796
  setTrial(void 0);
4439
4797
  }, [initial2]);
4440
- import_react15.default.useEffect(() => () => {
4798
+ import_react16.default.useEffect(() => () => {
4441
4799
  if (trial?.state === "running") trial.cancel();
4442
4800
  }, [trial]);
4443
- if (!task) return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(DetailDialog, { open: false, title: "", onClose });
4801
+ if (!task) return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(DetailDialog, { open: false, title: "", onClose });
4444
4802
  const set = (patch) => {
4445
4803
  setTask({ ...task, ...patch });
4446
4804
  setProblem(void 0);
@@ -4460,9 +4818,9 @@ function GateTaskEditor({ task: initial2, open, locale, actions, onApply, onClos
4460
4818
  (cause) => setTrial((current) => current?.state === "running" ? { state: "error", message: cause instanceof Error ? cause.message : String(cause) } : current)
4461
4819
  );
4462
4820
  };
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") })
4821
+ const field2 = (key, value) => /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_react16.default.Fragment, { children: [
4822
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dt", { children: t(key) }),
4823
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dd", { className: value === void 0 ? "studio-muted" : void 0, children: value ?? t("trialEmpty") })
4466
4824
  ] }, key);
4467
4825
  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
4826
  const adv = (patch) => set({ advanced: { ...task.advanced, ...patch } });
@@ -4476,44 +4834,44 @@ function GateTaskEditor({ task: initial2, open, locale, actions, onApply, onClos
4476
4834
  }
4477
4835
  onApply(task);
4478
4836
  };
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 }) }),
4837
+ const problemAt = (key) => problem === key ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { children: t(`problem-${key}`) }) : null;
4838
+ 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: [
4839
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { onClick: onClose, children: t("close") }),
4840
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { primary: true, onClick: apply2, children: t("apply") })
4841
+ ] }), children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-gate-task", children: [
4842
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(SettingsRow, { title: t("name"), children: [
4843
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("input", { "aria-label": t("name"), value: task.name, onChange: (event) => set({ name: event.target.value }) }),
4486
4844
  problemAt("name")
4487
4845
  ] }),
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) => {
4846
+ /* @__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
4847
  const when = event.target.value;
4490
4848
  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: [
4849
+ }, children: GATE_WHENS.map((when) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: when, children: t(`when-${when}`) }, when)) }) }),
4850
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(SettingsRow, { title: t("what"), description: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(import_jsx_runtime18.Fragment, { children: [
4493
4851
  t("whatHint"),
4494
4852
  " ",
4495
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("a", { href: GATE_GUIDE_URL, target: "_blank", rel: "noreferrer", children: t("resultGuide") })
4853
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("a", { href: GATE_GUIDE_URL, target: "_blank", rel: "noreferrer", children: t("resultGuide") })
4496
4854
  ] }), 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))
4855
+ /* @__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 }) }),
4856
+ variables.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-gate-vars", children: [
4857
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "studio-muted", children: t("variables") }),
4858
+ variables.map((value, i) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("code", { title: t(i === 0 ? "var-text" : "var-data"), children: value }, value))
4501
4859
  ] }),
4502
4860
  problemAt("instruction")
4503
4861
  ] }),
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) => {
4862
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)(Disclosure, { title: t("advanced"), children: [
4863
+ /* @__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
4864
  const { script: _, ...rest } = task.advanced;
4507
4865
  set({ advanced: event.target.value ? { ...rest, script: event.target.value } : rest });
4508
4866
  }, 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")}` })
4867
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: "", children: t("noScript") }),
4868
+ (scripts?.scripts ?? []).map((name) => /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("option", { value: name, children: name }, name)),
4869
+ 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
4870
  ] }), 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 () => {
4871
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-gate-path", children: [
4872
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "studio-muted", children: t("scriptDir") }),
4873
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("code", { children: directory }),
4874
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: async () => {
4517
4875
  try {
4518
4876
  await navigator.clipboard.writeText(directory);
4519
4877
  setCopied(true);
@@ -4521,101 +4879,101 @@ function GateTaskEditor({ task: initial2, open, locale, actions, onApply, onClos
4521
4879
  setCopied(false);
4522
4880
  }
4523
4881
  }, children: copied ? "\u2713" : t("copyPath") }),
4524
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, onClick: () => {
4882
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: () => {
4525
4883
  void refreshScripts();
4526
4884
  }, children: t("refresh") })
4527
4885
  ] }),
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") })) })
4886
+ scriptError && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { children: `${t("scriptsFailed")} (${scriptError})` }),
4887
+ scripts && !scripts.supported && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { children: t("scriptUnsupported") }),
4888
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "studio-muted", children: t("scriptEnv") }),
4889
+ /* @__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
4890
  ] }),
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) }) }) }),
4891
+ 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 }) }) }),
4892
+ /* @__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 }) }) }),
4893
+ /* @__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 }) }) }),
4894
+ /* @__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 }) }) }),
4895
+ 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
4896
  problemAt("limits")
4539
4897
  ] }),
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) => {
4898
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: "studio-gate-trial", "aria-label": t("trial"), children: [
4899
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h3", { className: "studio-panel-title", children: t("trial") }),
4900
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "studio-muted", children: t("trialPreview") }),
4901
+ task.advanced.script && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "studio-muted", children: t("trialScript") }),
4902
+ 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) }),
4903
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("textarea", { "aria-label": t("trialSample", { target }), placeholder: t("trialSample", { target }), value: sample, onChange: (event) => {
4546
4904
  setSample(event.target.value);
4547
4905
  setTrial(void 0);
4548
4906
  } }),
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: () => {
4907
+ /* @__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: [
4908
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { role: "status", className: "studio-muted", children: t("trialRunning") }),
4909
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { onClick: () => {
4552
4910
  trial.cancel();
4553
4911
  setTrial(void 0);
4554
4912
  }, 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") }) }),
4913
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { disabled: !sample.trim(), onClick: runTrial, children: t("trialRun") }) }),
4914
+ trial?.state === "error" && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { children: `${t("trialFailed")} (${trial.message})` }),
4915
+ trial?.state === "done" && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("dl", { className: "studio-gate-result", "aria-label": t("trial"), children: [
4916
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dt", { children: t("out-verdict") }),
4917
+ /* @__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
4918
  field2("out-reason", trial.value.output.reason),
4561
4919
  field2("out-replace", trial.value.output.replace),
4562
4920
  field2("out-append", trial.value.output.append),
4563
4921
  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 }) })
4922
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dt", { children: t("trialApplied") }),
4923
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dd", { children: t(planKey(trial.value.plan)) }),
4924
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dt", {}),
4925
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("dd", { className: "studio-muted", children: t("trialUsage", { input: trial.value.usage.inputTokens, output: trial.value.usage.outputTokens }) })
4568
4926
  ] })
4569
4927
  ] })
4570
4928
  ] }) });
4571
4929
  }
4572
4930
  function GateTaskCompositionPage({ gates, locale }) {
4573
4931
  const t = useText(locale);
4574
- const [picking, setPicking] = import_react15.default.useState(false);
4575
- const [editing, setEditing] = import_react15.default.useState();
4932
+ const [picking, setPicking] = import_react16.default.useState(false);
4933
+ const [editing, setEditing] = import_react16.default.useState();
4576
4934
  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 })) })
4935
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-page-stack", children: [
4936
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(GateHead, { gates, title: t("composition"), t }),
4937
+ 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") }) }),
4938
+ gates.loaded && !gates.tasks.length && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "status", className: "studio-muted", children: t("empty") }),
4939
+ 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: [
4940
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-card-head", children: [
4941
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("h3", { children: task.name }),
4942
+ /* @__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
4943
  ] }),
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) })
4944
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { className: "studio-gate-sentence", children: [
4945
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: t(`when-${task.when}`) }),
4946
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { "aria-hidden": "true", children: "\u2192" }),
4947
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { children: firstLine(task.instruction) })
4590
4948
  ] }),
4591
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("p", { className: "studio-card-meta", children: [
4949
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { className: "studio-card-meta", children: [
4592
4950
  task.presetIds.length ? t("presetCount", { count: task.presetIds.length }) : t("noPreset"),
4593
4951
  task.advanced.script ? ` \xB7 ${task.advanced.script}` : ""
4594
4952
  ] }),
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: () => {
4953
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-card-footer", children: [
4954
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: () => setEditing(structuredClone(task)), children: t("edit") }),
4955
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: () => {
4598
4956
  const { disabledPresetIds: _, ...copy5 } = structuredClone(task);
4599
4957
  gates.save({ ...copy5, id: globalThis.crypto.randomUUID(), name: `${task.name} (${t("duplicate")})`, presetIds: [] });
4600
4958
  }, children: t("duplicate") }),
4601
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, onClick: () => gates.remove(task.id), children: t("delete") })
4959
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: () => gates.remove(task.id), children: t("delete") })
4602
4960
  ] })
4603
4961
  ] }, task.id)) }),
4604
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(TemplatePicker, { open: picking, locale, onClose: () => setPicking(false), onPick: (task) => {
4962
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(TemplatePicker, { open: picking, locale, onClose: () => setPicking(false), onPick: (task) => {
4605
4963
  setPicking(false);
4606
4964
  setEditing(task);
4607
4965
  } }),
4608
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(GateTaskEditor, { open: !!editing, task: editing, locale, actions: gates.actions, onClose: () => setEditing(void 0), onApply: (task) => {
4966
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(GateTaskEditor, { open: !!editing, task: editing, locale, actions: gates.actions, onClose: () => setEditing(void 0), onApply: (task) => {
4609
4967
  gates.save(task);
4610
4968
  setEditing(void 0);
4611
4969
  } })
4612
4970
  ] });
4613
4971
  }
4614
4972
  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("");
4973
+ const [list, setList] = import_react16.default.useState();
4974
+ const [draft, setDraft] = import_react16.default.useState("");
4975
+ const [busy, setBusy] = import_react16.default.useState(false);
4976
+ const [error, setError] = import_react16.default.useState("");
4619
4977
  const run = async (work, failed) => {
4620
4978
  setBusy(true);
4621
4979
  setError("");
@@ -4632,7 +4990,7 @@ function ScriptFolder({ actions, t }) {
4632
4990
  setList(next);
4633
4991
  setDraft(next.custom ? next.directory : "");
4634
4992
  }, "folderFailed");
4635
- import_react15.default.useEffect(() => {
4993
+ import_react16.default.useEffect(() => {
4636
4994
  let active = true;
4637
4995
  actions.scripts().then((next) => {
4638
4996
  if (active) {
@@ -4646,31 +5004,31 @@ function ScriptFolder({ actions, t }) {
4646
5004
  active = false;
4647
5005
  };
4648
5006
  }, [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: () => {
5007
+ 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: [
5008
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-gate-folder", children: [
5009
+ /* @__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) }),
5010
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, disabled: busy || !list || draft.trim() === (list.custom ? list.directory : ""), onClick: () => {
4653
5011
  void apply2(draft);
4654
5012
  }, children: t("folderApply") }),
4655
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, disabled: busy || !list?.custom, onClick: () => {
5013
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, disabled: busy || !list?.custom, onClick: () => {
4656
5014
  void apply2("");
4657
5015
  }, children: t("folderReset") }),
4658
- actions.openFolder && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Button, { small: true, disabled: busy || !list, onClick: () => {
5016
+ actions.openFolder && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, disabled: busy || !list, onClick: () => {
4659
5017
  void run(() => actions.openFolder(list.directory), "openFailed");
4660
5018
  }, children: t("openFolder") })
4661
5019
  ] }),
4662
- list && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("p", { className: "studio-card-meta", children: [
5020
+ list && /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("p", { className: "studio-card-meta", children: [
4663
5021
  t(list.custom ? "folderCurrent" : "folderDefault"),
4664
5022
  ": ",
4665
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("code", { children: list.directory })
5023
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("code", { children: list.directory })
4666
5024
  ] }),
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 })
5025
+ list && !list.supported && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { children: t("scriptUnsupported") }),
5026
+ error && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Notice, { children: error })
4669
5027
  ] }) });
4670
5028
  }
4671
5029
  function GateTaskScopePage({ gates, presets, locale }) {
4672
5030
  const t = useText(locale);
4673
- const [adding, setAdding] = import_react15.default.useState();
5031
+ const [adding, setAdding] = import_react16.default.useState();
4674
5032
  const attachedTo = (preset) => gates.tasks.filter((task) => task.presetIds.includes(preset));
4675
5033
  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
5034
  const switchFor = (task, preset, on) => gates.update(task.id, (item) => {
@@ -4683,50 +5041,50 @@ function GateTaskScopePage({ gates, presets, locale }) {
4683
5041
  const row = (task, preset) => {
4684
5042
  const on = enabledFor(task, preset);
4685
5043
  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: [
5044
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("li", { className: "studio-gate-scope-row", "data-gate-scope": task.id, children: [
5045
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "studio-gate-scope-name", children: [
5046
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("strong", { children: task.name }),
5047
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "studio-card-meta", children: [
4690
5048
  t(`when-${task.when}`),
4691
5049
  task.advanced.script ? ` \xB7 ${task.advanced.script}` : ""
4692
5050
  ] }),
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") })
5051
+ !task.enabled && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Badge, { tone: "neutral", children: t("gateOff") }),
5052
+ conflict && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Badge, { tone: "warning", children: t("conflict") })
4695
5053
  ] }),
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) }) })
5054
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "studio-gate-scope-actions", children: [
5055
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, onClick: () => detach(task, preset), children: t("removeFromPreset") }),
5056
+ /* @__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
5057
  ] })
4700
5058
  ] }, task.id);
4701
5059
  };
4702
5060
  const presetCard = (preset) => {
4703
5061
  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 }) })
5062
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("section", { className: "studio-settings-card", "aria-label": preset.name, "data-gate-preset": preset.id, children: [
5063
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-gate-scope-head", children: [
5064
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "studio-gate-scope-title", children: [
5065
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("strong", { children: preset.name }),
5066
+ /* @__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
5067
  ] }),
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" })
5068
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("span", { className: "studio-gate-scope-actions", children: [
5069
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { small: true, disabled: !gates.loaded, onClick: () => setAdding(preset), children: t("addGate") }),
5070
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("span", { className: "studio-gate-scope-switch", "aria-hidden": "true" })
4713
5071
  ] })
4714
5072
  ] }),
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") })
5073
+ 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
5074
  ] }, preset.id);
4717
5075
  };
4718
5076
  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") }),
5077
+ return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "studio-page-stack", children: [
5078
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(GateHead, { gates, title: t("scope"), description: t("scopeDescription"), t }),
5079
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(ScriptFolder, { actions: gates.actions, t }),
5080
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(SectionHead, { title: t("presetsTitle"), description: t("presetsTitleHint") }),
5081
+ !presets.length && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { role: "status", className: "studio-muted", children: t("noStudioPresets") }),
4724
5082
  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: [
5083
+ /* @__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: [
5084
+ !candidates.length && /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("p", { className: "studio-muted", children: t("noGateToAdd") }),
5085
+ /* @__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
5086
  task.name,
4729
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Badge, { tone: "outline", children: t(`when-${task.when}`) })
5087
+ /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Badge, { tone: "outline", children: t(`when-${task.when}`) })
4730
5088
  ] }), description: task.instruction.split("\n")[0], onClick: () => {
4731
5089
  gates.update(task.id, (item) => ({ ...item, presetIds: [...item.presetIds, adding.id] }));
4732
5090
  setAdding(void 0);
@@ -4882,7 +5240,7 @@ function gateComposeText(locale, key, values = {}) {
4882
5240
  }
4883
5241
 
4884
5242
  // src/pixie-settings.tsx
4885
- var import_jsx_runtime18 = require("react/jsx-runtime");
5243
+ var import_jsx_runtime19 = require("react/jsx-runtime");
4886
5244
  var SEP = "\0";
4887
5245
  var NO_GATES = {
4888
5246
  read: async () => ({ entries: [], invalid: [] }),
@@ -4895,20 +5253,20 @@ var NO_GATES = {
4895
5253
  };
4896
5254
  function PixieSettingsPage({ actions, gateActions, locale, navFooter }) {
4897
5255
  const t = (key) => pixieText(locale, key);
4898
- const [page, setPage] = import_react16.default.useState("model");
5256
+ const [page, setPage] = import_react17.default.useState("model");
4899
5257
  const gates = useGateTasks(gateActions ?? NO_GATES);
4900
- const [gatePresets, setGatePresets] = import_react16.default.useState([]);
4901
- import_react16.default.useEffect(() => {
5258
+ const [gatePresets, setGatePresets] = import_react17.default.useState([]);
5259
+ import_react17.default.useEffect(() => {
4902
5260
  if (gateActions) void gateActions.presets().then(setGatePresets, () => setGatePresets([]));
4903
5261
  }, [gateActions]);
4904
5262
  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 () => {
5263
+ const [draft, setDraft] = import_react17.default.useState();
5264
+ const [catalog, setCatalog] = import_react17.default.useState();
5265
+ const [error, setError] = import_react17.default.useState("");
5266
+ const [status, setStatus] = import_react17.default.useState("idle");
5267
+ const [saveError, setSaveError] = import_react17.default.useState("");
5268
+ const [stored, setStored] = import_react17.default.useState("");
5269
+ const load = import_react17.default.useCallback(async () => {
4912
5270
  setError("");
4913
5271
  try {
4914
5272
  const [settings, models] = await Promise.all([actions.read(), actions.models()]);
@@ -4919,7 +5277,7 @@ function PixieSettingsPage({ actions, gateActions, locale, navFooter }) {
4919
5277
  setError(reason instanceof Error ? reason.message : String(reason));
4920
5278
  }
4921
5279
  }, [actions]);
4922
- import_react16.default.useEffect(() => {
5280
+ import_react17.default.useEffect(() => {
4923
5281
  void load();
4924
5282
  }, [load]);
4925
5283
  const save = async () => {
@@ -4947,47 +5305,54 @@ function PixieSettingsPage({ actions, gateActions, locale, navFooter }) {
4947
5305
  setStatus("idle");
4948
5306
  };
4949
5307
  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)(
5308
+ const section = (title, description, body) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "studio-page-stack", children: [
5309
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
4952
5310
  PageHead,
4953
5311
  {
4954
5312
  title: t(title),
4955
5313
  description: t(description),
4956
- actions: draft && catalog ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)(Button, { primary: true, disabled: status === "saving" || !dirty, onClick: () => {
5314
+ actions: draft && catalog ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Button, { primary: true, disabled: status === "saving" || !dirty, onClick: () => {
4957
5315
  void save();
4958
5316
  }, children: status === "saving" ? t("saving") : dirty ? t("save") : t("savedButton") }) : void 0
4959
5317
  }
4960
5318
  ),
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: () => {
5319
+ 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})` }),
5320
+ error && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Notice, { action: !draft ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Button, { small: true, onClick: () => {
4963
5321
  void load();
4964
5322
  }, 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") }),
5323
+ !error && (!draft || !catalog) && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { role: "status", className: "studio-muted", children: t("loading") }),
4966
5324
  draft && catalog && body(draft, catalog)
4967
5325
  ] });
5326
+ 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) => {
5327
+ const [provider, model] = event.target.value.split(SEP);
5328
+ onChange(provider && model ? { provider, model } : void 0);
5329
+ }, children: [
5330
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: emptyLabel }),
5331
+ 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))
5332
+ ] });
4968
5333
  const modelPage = section("pageModel", "pageModelDescription", (draft2, catalog2) => {
4969
5334
  const selected = draft2.model ? catalog2.groups.find((group) => group.id === draft2.model.provider)?.models.find((model) => model.id === draft2.model.model) : void 0;
4970
5335
  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) => {
5336
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5337
+ catalog2.failures && catalog2.failures.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Notice, { children: `${t("catalogFailed")} ${catalog2.failures.map((failure) => failure.name).join(", ")}` }),
5338
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { className: "studio-settings-card", children: [
5339
+ /* @__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
5340
  const [provider, model] = event.target.value.split(SEP);
4976
5341
  const { model: _previous, ...rest } = draft2;
4977
5342
  replace(provider && model ? { ...rest, model: { provider, model } } : rest);
4978
5343
  }, 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))
5344
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: t("settingsNoModel") }),
5345
+ 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
5346
  ] }) }),
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) => {
5347
+ /* @__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
5348
  if (!draft2.model) return;
4984
5349
  const { reasoningEffort: _previous, ...model } = draft2.model;
4985
5350
  update2({ model: event.target.value ? { ...model, reasoningEffort: event.target.value } : model });
4986
5351
  }, 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))
5352
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: "", children: t("settingsEffortDefault") }),
5353
+ efforts.map((effort) => /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("option", { value: effort.id, children: effort.name }, effort.id))
4989
5354
  ] }) }),
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) => {
5355
+ /* @__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
5356
  if (!draft2.model) return;
4992
5357
  const { maxTokens: _previous, ...model } = draft2.model;
4993
5358
  const value = Number(event.target.value);
@@ -4996,8 +5361,8 @@ function PixieSettingsPage({ actions, gateActions, locale, navFooter }) {
4996
5361
  ] })
4997
5362
  ] });
4998
5363
  });
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)(
5364
+ const threadsPage = section("pageThreads", "pageThreadsDescription", (draft2) => /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { className: "studio-settings-card", children: [
5365
+ /* @__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
5366
  Segmented,
5002
5367
  {
5003
5368
  label: t("settingsMode"),
@@ -5006,22 +5371,103 @@ function PixieSettingsPage({ actions, gateActions, locale, navFooter }) {
5006
5371
  options: [{ value: "fresh", label: t("fresh") }, { value: "fork", label: t("fork") }]
5007
5372
  }
5008
5373
  ) }),
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 }) }) })
5374
+ /* @__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
5375
  ] }));
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: [
5376
+ 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 }) }) }) }));
5377
+ const judgePage = section("pageJudge", "pageJudgeDescription", (draft2, catalog2) => {
5378
+ const engine = draft2.judgeEngine ?? "llm";
5379
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("section", { className: "studio-settings-card", children: [
5380
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SettingsRow, { title: t("judgeEngine"), description: t(engine === "jev" ? "judgeEngineJevHint" : "judgeEngineLlmHint"), control: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
5381
+ Segmented,
5382
+ {
5383
+ label: t("judgeEngine"),
5384
+ value: engine,
5385
+ onChange: (judgeEngine) => update2({ judgeEngine }),
5386
+ options: [{ value: "llm", label: t("judgeEngineLlm") }, { value: "jev", label: t("judgeEngineJev") }]
5387
+ }
5388
+ ) }),
5389
+ engine === "llm" ? /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5390
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SettingsRow, { title: t("judgeModel"), description: t("judgeModelHint"), control: modelSelect(t("judgeModel"), t("judgeModelPixie"), draft2.judgeModel, (judgeModel) => {
5391
+ const { judgeModel: _previous, ...rest } = draft2;
5392
+ replace(judgeModel ? { ...rest, judgeModel } : rest);
5393
+ }, catalog2) }),
5394
+ /* @__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) => {
5395
+ const { judgeSystemPrompt: _previous, ...rest } = draft2;
5396
+ replace(event.target.value ? { ...rest, judgeSystemPrompt: event.target.value } : rest);
5397
+ } }) })
5398
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(import_jsx_runtime19.Fragment, { children: [
5399
+ /* @__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) => {
5400
+ const { jevModel: _previous, ...rest } = draft2;
5401
+ const value = event.target.value.trim();
5402
+ replace(value ? { ...rest, jevModel: value } : rest);
5403
+ } }) }),
5404
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(JevKeyRow, { actions: actions.jevKey, locale })
5405
+ ] })
5406
+ ] });
5407
+ });
5408
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(DetailLayout, { footer: navFooter, navigation: t("settingsNavigation"), selected: page, onSelect: (next) => setPage(next), pages: [
5013
5409
  { id: "model", group: t("settingsGroup"), label: t("pageModel"), content: modelPage },
5014
5410
  { id: "threads", group: t("settingsGroup"), label: t("pageThreads"), content: threadsPage },
5015
5411
  { id: "prompt", group: t("settingsGroup"), label: t("pagePrompt"), content: promptPage },
5016
5412
  ...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 }) }
5413
+ { id: "gate-composition", group: gt("group"), label: gt("composition"), content: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(GateTaskCompositionPage, { gates, locale }) },
5414
+ { id: "gate-scope", group: gt("group"), label: gt("scope"), content: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(GateTaskScopePage, { gates, presets: gatePresets, locale }) },
5415
+ { id: "judge", group: gt("group"), label: t("pageJudge"), content: judgePage }
5019
5416
  ] : []
5020
5417
  ] });
5021
5418
  }
5419
+ function JevKeyRow({ actions, locale }) {
5420
+ const t = (key) => pixieText(locale, key);
5421
+ const [status, setStatus] = import_react17.default.useState();
5422
+ const [value, setValue] = import_react17.default.useState("");
5423
+ const [busy, setBusy] = import_react17.default.useState();
5424
+ const [done, setDone] = import_react17.default.useState();
5425
+ const [error, setError] = import_react17.default.useState("");
5426
+ import_react17.default.useEffect(() => {
5427
+ if (!actions) {
5428
+ setStatus({ available: false, configured: false, writable: false });
5429
+ return;
5430
+ }
5431
+ void actions.status().then(setStatus, (reason) => setError(reason instanceof Error ? reason.message : String(reason)));
5432
+ }, [actions]);
5433
+ const run = async (kind, call) => {
5434
+ setBusy(kind);
5435
+ setDone(void 0);
5436
+ setError("");
5437
+ try {
5438
+ setStatus(await call());
5439
+ setValue("");
5440
+ setDone(kind);
5441
+ } catch (reason) {
5442
+ setError(reason instanceof Error ? reason.message : String(reason));
5443
+ } finally {
5444
+ setBusy(void 0);
5445
+ }
5446
+ };
5447
+ const source = status?.source ?? "";
5448
+ const state = !status ? t("loading") : !status.available ? t("jevKeyUnavailable") : status.configured ? `${t("jevKeySet")}${source ? ` \xB7 ${t("jevKeyFrom").replace("{source}", source)}` : ""}` : t("jevKeyMissing");
5449
+ const readOnly = !!status?.available && status.configured && !status.writable;
5450
+ return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(SettingsRow, { title: t("jevKey"), description: t("jevKeyHint"), children: [
5451
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("p", { role: "status", className: "studio-muted", children: readOnly ? t("jevKeyReadOnly").replace("{source}", source) : state }),
5452
+ 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})` }),
5453
+ actions && status?.available && !readOnly && /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { className: "studio-inline-actions", children: [
5454
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("input", { className: "studio-compact", type: "password", autoComplete: "off", "aria-label": t("jevKey"), placeholder: t("jevKeyPlaceholder"), value, onChange: (event) => {
5455
+ setValue(event.target.value);
5456
+ setDone(void 0);
5457
+ } }),
5458
+ /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Button, { small: true, primary: true, disabled: !!busy || !value.trim(), onClick: () => {
5459
+ void run("save", () => actions.save(value));
5460
+ }, children: t(busy === "save" ? "jevKeySaving" : "jevKeySave") }),
5461
+ status.configured && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Button, { small: true, disabled: !!busy, onClick: () => {
5462
+ void run("remove", () => actions.remove());
5463
+ }, children: t(busy === "remove" ? "jevKeyRemoving" : "jevKeyDelete") }),
5464
+ done && /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { role: "status", className: "studio-muted", children: t(done === "save" ? "jevKeySaved" : "jevKeyRemoved") })
5465
+ ] })
5466
+ ] });
5467
+ }
5022
5468
 
5023
5469
  // src/pixie-client.tsx
5024
- var import_jsx_runtime19 = require("react/jsx-runtime");
5470
+ var import_jsx_runtime20 = require("react/jsx-runtime");
5025
5471
  var NAMESPACE = "studioPixie";
5026
5472
  var TAB_ID = `${PACKAGE_NAME}/pixie`;
5027
5473
  var KIND = "studio-pixie";
@@ -5050,6 +5496,8 @@ function pixieDescriptors() {
5050
5496
  descriptor("gateRuns", ["sessionId"]),
5051
5497
  descriptor("followGates", ["sessionId"], { mode: "stream", cancellation: { parameter: "signal" } }),
5052
5498
  descriptor("resolveGateRejection", ["sessionId", "runId", "status"]),
5499
+ descriptor("sessionGates", ["sessionId"]),
5500
+ descriptor("setSessionGate", ["sessionId", "gateId", "enabled"]),
5053
5501
  descriptor("view", ["sessionId"]),
5054
5502
  descriptor("createThread", ["sessionId", "payload"]),
5055
5503
  descriptor("activate", ["sessionId", "threadId"]),
@@ -5065,7 +5513,10 @@ function pixieDescriptors() {
5065
5513
  descriptor("saveGateDefinitions", ["payload"]),
5066
5514
  descriptor("readSettings", []),
5067
5515
  descriptor("saveSettings", ["payload"]),
5068
- descriptor("models", [])
5516
+ descriptor("models", []),
5517
+ descriptor("jevKeyStatus", []),
5518
+ descriptor("saveJevKey", ["payload"]),
5519
+ descriptor("deleteJevKey", [])
5069
5520
  ];
5070
5521
  }
5071
5522
  function followPixieStream(connect, listener) {
@@ -5101,17 +5552,23 @@ function followPixieStream(connect, listener) {
5101
5552
  };
5102
5553
  }
5103
5554
  function mountPixie(ctx, options = {}) {
5555
+ const withMarkdown = (node) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(MarkdownProvider, { value: options.markdown, children: node });
5104
5556
  const remote = () => {
5105
5557
  const service = ctx.get(`remote.${NAMESPACE}`);
5106
5558
  if (!service) throw new Error("Pixie API unavailable");
5107
5559
  return service;
5108
5560
  };
5109
5561
  const locale = () => ctx.locale.getLocale().active;
5110
- const useLocale = () => import_react17.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), locale);
5562
+ const useLocale = () => import_react18.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), locale);
5111
5563
  const settingsActions = {
5112
5564
  read: () => unwrap(remote().readSettings()),
5113
5565
  save: (settings) => unwrap(remote().saveSettings(JSON.stringify(settings))),
5114
- models: () => unwrap(remote().models())
5566
+ models: () => unwrap(remote().models()),
5567
+ jevKey: {
5568
+ status: () => unwrap(remote().jevKeyStatus()),
5569
+ save: (value) => unwrap(remote().saveJevKey(JSON.stringify({ value }))),
5570
+ remove: () => unwrap(remote().deleteJevKey())
5571
+ }
5115
5572
  };
5116
5573
  const gateActions = {
5117
5574
  trial: (request) => {
@@ -5136,7 +5593,7 @@ function mountPixie(ctx, options = {}) {
5136
5593
  };
5137
5594
  function SettingsPage() {
5138
5595
  const active = useLocale();
5139
- return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(PixieSettingsPage, { actions: settingsActions, gateActions, locale: active, navFooter: options.navFooter?.(active) });
5596
+ return withMarkdown(/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PixieSettingsPage, { actions: settingsActions, gateActions, locale: active, navFooter: options.navFooter?.(active) }));
5140
5597
  }
5141
5598
  ctx.slots.inject("local.dsh-studio.services", () => ctx.slots.register({
5142
5599
  name: "local.dsh-studio.services",
@@ -5150,6 +5607,8 @@ function mountPixie(ctx, options = {}) {
5150
5607
  gateRuns: () => unwrap(remote().gateRuns(sessionId)),
5151
5608
  followGates: (listener) => followPixieStream(() => remote().followGates(sessionId), listener),
5152
5609
  resolveGateRejection: (runId, status) => unwrap(remote().resolveGateRejection(sessionId, runId, status)),
5610
+ sessionGates: () => unwrap(remote().sessionGates(sessionId)),
5611
+ setSessionGate: (gateId, enabled) => unwrap(remote().setSessionGate(sessionId, gateId, enabled)),
5153
5612
  fillDraft: (text) => {
5154
5613
  const sessions = ctx.get("sessions");
5155
5614
  const actx = sessions?.scope(sessionId);
@@ -5178,8 +5637,8 @@ function mountPixie(ctx, options = {}) {
5178
5637
  }));
5179
5638
  function Body({ sessionId }) {
5180
5639
  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 });
5640
+ const actions = import_react18.default.useMemo(() => tabActions(sessionId), [sessionId]);
5641
+ return withMarkdown(/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(PixieTab, { actions, locale: active }));
5183
5642
  }
5184
5643
  scope.slots.inject("sidebar.right.pane.tab", () => scope.slots.register({ name: "sidebar.right.pane.tab", key: TAB_ID }, Body));
5185
5644
  const openTab = () => {
@@ -5187,18 +5646,49 @@ function mountPixie(ctx, options = {}) {
5187
5646
  };
5188
5647
  function CommandRow({ node, sessionId }) {
5189
5648
  const active = useLocale();
5190
- const rowActions = import_react17.default.useMemo(() => {
5649
+ const rowActions = import_react18.default.useMemo(() => {
5191
5650
  const tab = tabActions(sessionId);
5192
5651
  return { commandId: node.commandId, follow: tab.follow, commandTurn: () => unwrap(remote().commandTurn(sessionId, node.commandId)) };
5193
5652
  }, [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 }) });
5653
+ 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
5654
  }
5196
5655
  scope.slots.inject("conversation.chat.commandview", () => scope.slots.register({ name: "conversation.chat.commandview", key: "pixie" }, CommandRow));
5656
+ function GateTailSurface({ children }) {
5657
+ return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(StudioSurface, { className: "studio-gate-tail", children });
5658
+ }
5659
+ function TurnTail({ sessionId, turn }) {
5660
+ const active = useLocale();
5661
+ const actions = import_react18.default.useMemo(() => {
5662
+ const tab = tabActions(sessionId);
5663
+ return { gateRuns: tab.gateRuns, followGates: tab.followGates, setSessionGate: (gateId, enabled) => unwrap(remote().setSessionGate(sessionId, gateId, enabled)), openTab };
5664
+ }, [sessionId]);
5665
+ if (turn.status !== "closed") return null;
5666
+ return withMarkdown(/* @__PURE__ */ (0, import_jsx_runtime20.jsx)(GateTail, { actions, turn: turn.turn, locale: active, Surface: GateTailSurface }));
5667
+ }
5668
+ scope.slots.inject("conversation.chat.turnTail", () => scope.slots.register({ name: "conversation.chat.turnTail", id: "studio-pixie-gate-tail" }, TurnTail));
5197
5669
  });
5198
5670
  }
5199
5671
 
5672
+ // src/ui-host.tsx
5673
+ var import_react19 = __toESM(require("react"), 1);
5674
+ var import_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
5675
+ var import_dsh_client_ui_primitives2 = require("@deepseek-ai/dsh-client-ui-primitives");
5676
+ var import_jsx_runtime21 = require("react/jsx-runtime");
5677
+ var markdownLabels = /* @__PURE__ */ new Map();
5678
+ var labelsFor = (locale) => {
5679
+ let labels2 = markdownLabels.get(locale);
5680
+ if (!labels2) {
5681
+ labels2 = { code: { copyLabel: pixieText(locale, "mdCopy"), copiedLabel: pixieText(locale, "mdCopied") }, footnotes: pixieText(locale, "mdFootnotes") };
5682
+ markdownLabels.set(locale, labels2);
5683
+ }
5684
+ return labels2;
5685
+ };
5686
+ function DshMarkdown({ text, streaming, locale }) {
5687
+ return /* @__PURE__ */ (0, import_jsx_runtime21.jsx)(import_dsh_client_ui_primitives.MarkdownText, { text, streaming, labels: labelsFor(locale), variant: "compact" });
5688
+ }
5689
+
5200
5690
  // src/shell.tsx
5201
- var import_jsx_runtime20 = require("react/jsx-runtime");
5691
+ var import_jsx_runtime22 = require("react/jsx-runtime");
5202
5692
  var inject = ["slots", "locale", "remote"];
5203
5693
  var panel = "local-dsh-studio";
5204
5694
  async function apply(ctx) {
@@ -5242,7 +5732,7 @@ async function apply(ctx) {
5242
5732
  } }) } }],
5243
5733
  result: { mode: "src-json" }
5244
5734
  })), ...pixieDescriptors()] });
5245
- mountPixie(ctx, { navFooter: (locale) => /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(VersionFooter, { store: updates, locale }) });
5735
+ mountPixie(ctx, { navFooter: (locale) => /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(VersionFooter, { store: updates, locale }), markdown: DshMarkdown });
5246
5736
  ctx.effect(() => ctx.locale.addLanguage({ id: "ko", label: "\uD55C\uAD6D\uC5B4", fallback: "en" }));
5247
5737
  const serviceListeners = /* @__PURE__ */ new Set();
5248
5738
  let services = [];
@@ -5272,18 +5762,18 @@ async function apply(ctx) {
5272
5762
  const updates = createUpdateStore(updateActions, STUDIO_VERSION);
5273
5763
  void updates.refresh();
5274
5764
  function StudioServices({ renderSlot }) {
5275
- const items = import_react18.default.useSyncExternalStore((listener) => {
5765
+ const items = import_react20.default.useSyncExternalStore((listener) => {
5276
5766
  serviceListeners.add(listener);
5277
5767
  return () => {
5278
5768
  serviceListeners.delete(listener);
5279
5769
  };
5280
5770
  }, () => 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 }) }) });
5771
+ const locale = import_react20.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), () => ctx.locale.getLocale().active);
5772
+ 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
5773
  }
5284
5774
  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 });
5775
+ const locale = import_react20.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), () => ctx.locale.getLocale().active);
5776
+ return /* @__PURE__ */ (0, import_jsx_runtime22.jsx)(SidebarIcon, { size, store: updates, locale });
5287
5777
  }
5288
5778
  ctx.slots.inject(
5289
5779
  "main",
@@ -5299,10 +5789,10 @@ async function apply(ctx) {
5299
5789
  )
5300
5790
  );
5301
5791
  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(() => {
5792
+ const locale = import_react20.default.useSyncExternalStore((listener) => ctx.locale.subscribe(listener), () => ctx.locale.getLocale().active);
5793
+ const [catalog, setCatalog] = import_react20.default.useState();
5794
+ const [catalogError, setCatalogError] = import_react20.default.useState("");
5795
+ import_react20.default.useEffect(() => {
5306
5796
  let active = true;
5307
5797
  const remote2 = ctx.get("remote.studioCatalog");
5308
5798
  if (!remote2) {
@@ -5320,7 +5810,7 @@ async function apply(ctx) {
5320
5810
  active = false;
5321
5811
  };
5322
5812
  }, []);
5323
- const presetActions = import_react18.default.useMemo(() => {
5813
+ const presetActions = import_react20.default.useMemo(() => {
5324
5814
  const call = async (method, ...args) => {
5325
5815
  const service = ctx.get("remote.studioCatalog");
5326
5816
  const result = await service[method](...args);
@@ -5336,7 +5826,7 @@ async function apply(ctx) {
5336
5826
  delete: (id) => call("deletePreset", id)
5337
5827
  };
5338
5828
  }, []);
5339
- const extensionActions = import_react18.default.useMemo(() => {
5829
+ const extensionActions = import_react20.default.useMemo(() => {
5340
5830
  const call = async (method, ...args) => {
5341
5831
  const service = ctx.get("remote.studioCatalog");
5342
5832
  const result = await service[method](...args);
@@ -5353,7 +5843,7 @@ async function apply(ctx) {
5353
5843
  remove: (id) => update2("removeMasterPlugin", id)
5354
5844
  };
5355
5845
  }, []);
5356
- const catalogChanges = import_react18.default.useMemo(() => {
5846
+ const catalogChanges = import_react20.default.useMemo(() => {
5357
5847
  const call = async (method) => {
5358
5848
  const service = ctx.get("remote.studioCatalog");
5359
5849
  const result = await service[method]();
@@ -5362,10 +5852,10 @@ async function apply(ctx) {
5362
5852
  };
5363
5853
  return { read: () => call("catalogChange"), confirm: () => call("confirmCatalogChange") };
5364
5854
  }, []);
5365
- import_react18.default.useEffect(() => {
5855
+ import_react20.default.useEffect(() => {
5366
5856
  void updates.refresh();
5367
5857
  }, []);
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) => {
5858
+ 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
5859
  const service = ctx.get("remote.studioCatalog");
5370
5860
  const response = await service.preview(request);
5371
5861
  if (!response.ok) throw new Error(response.error?.message ?? "Preview failed");