dsh-llm-fallbacks 0.6.1 → 0.6.3

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.
@@ -8,7 +8,6 @@ window.__ModuleLoader__.load({
8
8
  var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
9
9
  //#endregion
10
10
  let react = require("react");
11
- let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
12
11
  let _deepseek_ai_dsh_client_store = require("@deepseek-ai/dsh-client-store");
13
12
  let react_jsx_runtime = require("react/jsx-runtime");
14
13
  //#region node_modules/use-sync-external-store/cjs/use-sync-external-store-shim.production.js
@@ -471,13 +470,12 @@ window.__ModuleLoader__.load({
471
470
  //#region src/config.ts
472
471
  /**
473
472
  * Spec §4 defaults — `Config({})` must equal this (no-op install).
474
- * `enabled` defaults to `false` (readme-settings spec §1.2): the feature
475
- * switch is off until the user turns it on in the settings page; an
476
- * unconfigured install (`enabled: false`, empty rootChain, empty roles)
477
- * behaves exactly like an uninstalled plugin (AC-3 / no-op invariant).
473
+ * There is no `enabled` default (the key is removed — the Plugins-page row
474
+ * toggle is the master switch): an unconfigured install (empty rootChain,
475
+ * no time slots, empty roles) behaves exactly like an uninstalled plugin
476
+ * (AC-3 / no-op invariant, {@link isFallbackActive}).
478
477
  */
479
478
  const defaultFallbacksConfig = {
480
- enabled: false,
481
479
  triggerCodes: [
482
480
  "AUTH",
483
481
  "QUOTA",
@@ -503,6 +501,20 @@ window.__ModuleLoader__.load({
503
501
  * the no-rule-match fallback, but FORBIDDEN in `roles.list[].id`.
504
502
  */
505
503
  const INHERIT_ROLE_ID = "inherit";
504
+ /**
505
+ * The no-op gate (AC-8), re-keyed from the removed `enabled` switch to
506
+ * CONTENT PRESENCE (plan fallbacks-web-ux-alignment T2): the plugin
507
+ * intervenes exactly when something is configured — a non-empty `rootChain`
508
+ * (the all-day chain), at least one time-slot row, or at least one declared
509
+ * role. An inactive config is a pass-through exactly like an uninstalled
510
+ * plugin; the Plugins-page row toggle remains the master switch (row
511
+ * disable = fiber destroy). ONE helper for every runtime gate — the former
512
+ * `config.enabled` sites (request waterfalls, picker-row registration, TUI
513
+ * summary, General-row badge) all read through this.
514
+ */
515
+ function isFallbackActive(config) {
516
+ return config.rootChain.length > 0 || (config.timeSlots?.length ?? 0) > 0 || config.roles.list.length > 0;
517
+ }
506
518
  /** Role id format (aligned with yet-another-subagent `isValidProfileId`). */
507
519
  const ROLE_ID_PATTERN = /^[a-z0-9-]{1,32}$/;
508
520
  //#endregion
@@ -687,8 +699,6 @@ window.__ModuleLoader__.load({
687
699
  if (revertPolicy !== void 0 && revertPolicy !== "cooldown-expiry" && revertPolicy !== "never") throw new TypeError("fallbacks descriptor revertPolicy must be cooldown-expiry|never");
688
700
  const presets = value.presets;
689
701
  if (presets !== void 0 && presets !== "bundled" && presets !== "none") throw new TypeError("fallbacks descriptor presets must be bundled|none");
690
- const enabled = value.enabled;
691
- if (enabled !== void 0 && typeof enabled !== "boolean") throw new TypeError("fallbacks descriptor enabled must be a boolean");
692
702
  const roleAutoMatch = value.roleAutoMatch;
693
703
  if (roleAutoMatch !== void 0 && typeof roleAutoMatch !== "boolean") throw new TypeError("fallbacks descriptor roleAutoMatch must be a boolean");
694
704
  const timeSlots = value.timeSlots;
@@ -711,7 +721,6 @@ window.__ModuleLoader__.load({
711
721
  const recovery = value.recovery;
712
722
  if (recovery !== void 0 && recovery !== "timer" && recovery !== "half-open") throw new TypeError("fallbacks descriptor recovery must be timer|half-open");
713
723
  return {
714
- enabled: enabled ?? defaultFallbacksConfig.enabled,
715
724
  triggerCodes: triggerCodes ?? [...defaultFallbacksConfig.triggerCodes],
716
725
  rootChain: rootChain ?? [...defaultFallbacksConfig.rootChain],
717
726
  roles: {
@@ -1323,18 +1332,9 @@ window.__ModuleLoader__.load({
1323
1332
  */
1324
1333
  /** Simplified Chinese dictionary (the key-set source of truth). */
1325
1334
  const zh = {
1326
- "title": "Fallbacks",
1327
- "intro": "模型故障自动降级",
1328
- "collapse": "收起设置",
1329
- "expand": "展开设置",
1330
- "unsaved": "未保存",
1331
1335
  "discard": "放弃修改",
1332
1336
  "retry": "重试",
1333
1337
  "readOnly": "当前环境中的设置为只读。",
1334
- "enabled.label": "启用故障降级",
1335
- "enabled.hint": "关闭后插件完全不介入",
1336
- "enabled.tooltip": "关闭后插件完全不介入;开启但未配置 rootChain 时行为与未安装插件一致。",
1337
- "enabled.off": "功能未开启:打开 enabled 开关以显示配置界面。",
1338
1338
  "triggerCodes.label": "触发失败码",
1339
1339
  "triggerCodes.hint": "命中这些失败码时进入降级决策",
1340
1340
  "triggerCodes.tooltip": "命中这些失败码时进入降级链决策;可重试型故障(如 5xx)由 llm-retry 先行退避,预算耗尽后同样进入决策。",
@@ -1519,18 +1519,9 @@ window.__ModuleLoader__.load({
1519
1519
  };
1520
1520
  /** English dictionary, checked complete against the zh key set. */
1521
1521
  const en = {
1522
- "title": "Fallbacks",
1523
- "intro": "Automatic fallback on model failures",
1524
- "collapse": "Hide settings",
1525
- "expand": "Show settings",
1526
- "unsaved": "Unsaved",
1527
1522
  "discard": "Discard",
1528
1523
  "retry": "Retry",
1529
1524
  "readOnly": "Settings are read-only in this environment.",
1530
- "enabled.label": "Enable failure fallback",
1531
- "enabled.hint": "Plugin never intervenes when off",
1532
- "enabled.tooltip": "When off the plugin never intervenes; when on with no rootChain configured behavior is identical to an uninstalled plugin.",
1533
- "enabled.off": "Feature disabled: turn on the enabled switch to show the configuration interface.",
1534
1525
  "triggerCodes.label": "Trigger failure codes",
1535
1526
  "triggerCodes.hint": "Failures with these codes enter fallback decision",
1536
1527
  "triggerCodes.tooltip": "Failures with these codes enter chain decision; retryable failures (e.g. 5xx) back off via llm-retry first and reach the decision only when its budget is exhausted.",
@@ -1553,8 +1544,8 @@ window.__ModuleLoader__.load({
1553
1544
  "alwaysModeRetryCap.hint": "Switches after the cap; 0 disables",
1554
1545
  "alwaysModeRetryCap.tooltip": "Models whose retryPolicy is always switch after this many retries within one request; 0 disables.",
1555
1546
  "advanced.label": "Advanced options",
1556
- "advanced.expand": "Show advanced options",
1557
- "advanced.collapse": "Hide advanced options",
1547
+ "advanced.expand": "Expand advanced options",
1548
+ "advanced.collapse": "Collapse advanced options",
1558
1549
  "roleAutoMatch.label": "Enable role auto-match",
1559
1550
  "roleAutoMatch.hint": "On rules-miss, the model picks the closest declared role",
1560
1551
  "roleAutoMatch.tooltip": "When no rule matches, the model auto-selects the best-fit declared role (id + persona) and uses its chain; turn off to keep today's fallback (inherit / rootChain) on a rules-miss.",
@@ -1751,7 +1742,7 @@ window.__ModuleLoader__.load({
1751
1742
  }
1752
1743
  //#endregion
1753
1744
  //#region \0dsh-css:/home/runner/work/dsh-llm-fallbacks/dsh-llm-fallbacks/src/client/FallbacksCard.module.css.mjs
1754
- const css$3 = "\n\n\n._8827595f_card {\n list-style: none;\n min-width: 0;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n background: var(--dsw-alias-bg-layer-3);\n transition: border-color .16s, background .16s;\n}\n\n._8827595f_card:hover {\n border-color: var(--dsw-alias-label-dimmed);\n}\n\n\n._06704203_cardOpen {\n background: var(--dsw-alias-bg-layer-2);\n border-color: var(--dsw-alias-label-dimmed);\n}\n\n\n._e488d460_header {\n width: 100%;\n appearance: none;\n border: 0;\n background: none;\n font: inherit;\n color: inherit;\n text-align: left;\n cursor: pointer;\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 14px 16px;\n border-radius: 12px;\n}\n\n._e488d460_header:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: -2px;\n}\n\n\n._f5dfe084_headText {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n._8d39bde6_name {\n font-size: 15px;\n font-weight: 600;\n line-height: 1.4;\n color: var(--dsw-alias-label-primary);\n}\n\n._346f3b69_description {\n font-size: 13px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._631094a0_chevron {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n transition: transform .16s;\n}\n\n._44836ce8_chevronOpen {\n transform: rotate(180deg);\n}\n\n\n._dbaa7975_body {\n border-top: 1px solid var(--dsw-alias-border-l2);\n margin: 0 16px;\n padding-bottom: 8px;\n}\n\n._4e39cf17_readOnly {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._99bf7f3c_pending {\n flex: none;\n border-radius: 999px;\n padding: 1px 8px;\n font-size: 11px;\n line-height: 17px;\n font-weight: 500;\n white-space: nowrap;\n background: var(--dsw-alias-bg-module-platform);\n color: var(--dsw-alias-label-secondary);\n}\n\n\n\n\n._9860a5b1_notice {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-business-primary);\n}\n\n\n._5006d43e_legacyNotice {\n margin: 12px 0 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--dsw-alias-bg-module-platform);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-business-primary);\n}\n\n._21918751_error {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-error-primary);\n}\n\n\n._7cea4b2f_noticeRow {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 12px 0 0;\n}\n\n._7cea4b2f_noticeRow ._21918751_error {\n flex: 1;\n min-width: 0;\n margin: 0;\n}\n\n\n._4058c747_form {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px 0 0;\n}\n\n\n._9998065c_checkboxRow {\n display: flex;\n align-items: center;\n gap: 8px;\n}\n\n._02c2f6df_checkLabel {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n font-size: 14px;\n line-height: 22px;\n font-weight: 400;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n\n._f2d47237_checkLabelTitle {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 400;\n}\n\n._c1bed8ea_checkLabelDesc {\n font-size: 12px;\n line-height: 18px;\n font-weight: 400;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._06389b18_checkbox {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._06389b18_checkbox:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n\n._94c91bfd_fieldset {\n margin: 0;\n padding: 0;\n border: none;\n display: flex;\n flex-direction: column;\n gap: 12px;\n min-width: 0;\n}\n\n\n._67826267_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin: 0;\n padding: 0;\n border: none;\n min-width: 0;\n}\n\n._13e68c3f_fieldLabel {\n \n display: inline-flex;\n align-items: center;\n gap: 10px;\n padding: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._ba240d82_sectionHeading {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._ddbc1b49_sectionHeadingText {\n flex: 1;\n min-width: 0;\n}\n\n\n._c41f9db7_sectionActions {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-left: auto;\n}\n\n\n._b116c758_sectionToggle {\n width: 100%;\n appearance: none;\n border: 0;\n background: none;\n font: inherit;\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 4px 0;\n cursor: pointer;\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n._b116c758_sectionToggle:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n}\n\n._b116c758_sectionToggle:disabled {\n cursor: default;\n}\n\n._b116c758_sectionToggle:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: 6px;\n}\n\n._a5313fdf_sectionToggleText {\n flex: 1;\n min-width: 0;\n text-align: left;\n}\n\n._4bc809b8_hint {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._579f813a_defaultNote {\n font-size: 12px;\n line-height: 18px;\n font-weight: 400;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._b1962759_slotPresetName {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n\n._a6244318_infoHint {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n font-size: 14px;\n line-height: 1;\n color: var(--dsw-alias-label-tertiary);\n background: var(--dsw-alias-interactive-bg-hover);\n cursor: help;\n user-select: none;\n}\n\n._a6244318_infoHint:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n\n._e655c840_infoHintDisabled {\n opacity: 0.4;\n cursor: default;\n}\n\n\n._a2521bb0_optionRow {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n\n._a2521bb0_optionRow:hover:has(input:not(:disabled)) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n\n._06389b18_checkbox,\n._a2521bb0_optionRow input {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._06389b18_checkbox:focus-visible,\n._a2521bb0_optionRow input:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._a2521bb0_optionRow input:disabled {\n cursor: default;\n}\n\n\n._c4ecbdf3_dayRow {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n\n._0330c1ed_dayCell {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 6px;\n border-radius: 6px;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n._0330c1ed_dayCell:hover:has(input:not(:disabled)) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._0330c1ed_dayCell input {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._0330c1ed_dayCell input:disabled {\n cursor: default;\n}\n\n._0330c1ed_dayCell input:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n\n._f9d86f7b_input {\n box-sizing: border-box;\n width: 100%;\n height: 32px;\n padding: 0 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 8px;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-primary);\n}\n\n._f9d86f7b_input:focus {\n outline: none;\n border-color: var(--dsw-alias-brand-primary);\n}\n\n._f9d86f7b_input::placeholder {\n color: var(--dsw-alias-label-dimmed);\n}\n\n._f9d86f7b_input:disabled {\n opacity: 0.6;\n cursor: default;\n}\n\n\n._3a9b42fd_inputTextarea {\n height: auto;\n min-height: 72px;\n padding: 6px 10px;\n resize: vertical;\n line-height: 20px;\n}\n\n\n._1285c19b_personaBriefRow {\n display: flex;\n align-items: center;\n gap: 4px;\n min-width: 0;\n}\n\n._4b8f7345_personaBrief {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n}\n\n\n._2686400e_personaBriefEmpty {\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._4e4a07be_personaFull {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-secondary);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n\n._7b60337a_inputInvalid,\n._7b60337a_inputInvalid:focus {\n border-color: var(--dsw-alias-state-error-primary);\n}\n\n\nselect._f9d86f7b_input {\n max-width: 240px;\n cursor: pointer;\n}\n\n\n._16eb7153_selectInput {\n appearance: none;\n padding-right: 32px;\n \n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 12px center;\n background-size: 12px 12px;\n}\n\n\n._3e95886d_numberFields {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n gap: 8px;\n}\n\n._0cfb5881_list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 4px;\n}\n\n\n._f5c620d6_editorCard {\n display: flex;\n flex-direction: column;\n gap: 14px;\n padding: 14px 16px;\n border-radius: 12px;\n background: var(--dsw-alias-bg-module-platform);\n}\n\n._224b1387_cardFoot {\n display: flex;\n justify-content: flex-end;\n}\n\n._8e220e07_ruleGrid {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n._24a12a2f_ruleCell {\n display: flex;\n flex-direction: column;\n gap: 4px;\n min-width: 120px;\n flex: 1;\n}\n\n\n._86bc52d2_collapseRow {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n._a73efcc6_collapseToggle {\n appearance: none;\n border: 0;\n background: none;\n padding: 0;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n font: inherit;\n text-align: left;\n}\n\n._a73efcc6_collapseToggle:disabled {\n cursor: default;\n}\n\n._af017718_collapseTitle {\n \n flex: none;\n max-width: 55%;\n min-width: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._2cabe603_collapseMeta {\n \n flex: none;\n margin-left: auto;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n._52d6df87_seedBadge {\n flex: none;\n max-width: 40%;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n border-radius: 999px;\n padding: 1px 8px;\n font-size: 11px;\n line-height: 17px;\n font-weight: 500;\n white-space: nowrap;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._7b04f727_slotTag {\n flex: none;\n display: inline-flex;\n align-items: center;\n border-radius: 999px;\n padding: 0 6px;\n font-size: 11px;\n line-height: 17px;\n font-weight: 500;\n white-space: nowrap;\n border: 1px solid;\n}\n\n._c381e792_slotTagHighCost {\n color: var(--dsw-alias-state-error-primary);\n border-color: var(--dsw-alias-state-error-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n._23bdb6fc_slotTagMultiplier {\n color: var(--dsw-alias-state-warn-primary);\n border-color: var(--dsw-alias-state-warn-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 10%, transparent);\n}\n\n._f000eed9_slotTagActive {\n color: var(--dsw-alias-state-success-primary);\n border-color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent);\n}\n\n\n._cd905ce5_dragHandle {\n appearance: none;\n border: 0;\n background: none;\n padding: 0;\n cursor: grab;\n color: var(--dsw-alias-label-tertiary);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n border-radius: 6px;\n flex: none;\n}\n\n._cd905ce5_dragHandle:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._cd905ce5_dragHandle:active {\n cursor: grabbing;\n}\n\n._cd905ce5_dragHandle:disabled {\n cursor: default;\n opacity: 0.4;\n}\n\n._cd905ce5_dragHandle:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._49f0c4f0_dragHandleIcon {\n transform: rotate(90deg);\n}\n\n\n._fee63b7e_slotCardDragging {\n opacity: 0.45;\n}\n\n._6f108491_slotCardOver {\n outline: 1px dashed var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n}\n\n._1014c097_ruleCellLabel {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._15a12620_chainSelectors {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n._240cbbf8_selectorRow {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n\n._70effa64_iconButton {\n position: relative;\n box-sizing: border-box;\n appearance: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: 0;\n border-radius: 6px;\n background: none;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n\n._70effa64_iconButton:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n._70effa64_iconButton:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._70effa64_iconButton:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._70effa64_iconButton::after {\n content: attr(data-tip);\n position: absolute;\n bottom: calc(100% + 6px);\n left: 50%;\n transform: translateX(-50%);\n padding: 3px 8px;\n border-radius: 6px;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n font-size: 11px;\n line-height: 17px;\n white-space: nowrap;\n opacity: 0;\n pointer-events: none;\n transition: opacity .12s;\n}\n\n._70effa64_iconButton:hover::after,\n._70effa64_iconButton:focus-visible::after {\n opacity: 1;\n}\n\n\n._a0968257_iconButtonDanger:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-danger);\n color: var(--dsw-alias-state-error-primary);\n}\n\n\n._28202c90_addButton {\n align-self: flex-start;\n}\n\n\n._6a2bd54c_slotAddRow {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 4px;\n flex-wrap: wrap;\n}\n\n\n._4e77523e_rowActions {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n\n._747fd56d_primaryButton,\n._7e855445_secondaryButton {\n box-sizing: border-box;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n gap: 4px;\n height: 36px;\n padding: 0 14px;\n border: none;\n border-radius: 18px;\n font: inherit;\n font-size: 14px;\n line-height: 22px;\n cursor: pointer;\n}\n\n._747fd56d_primaryButton {\n background: var(--dsw-alias-button-primary-fill);\n color: var(--dsw-alias-label-primary-foreground);\n}\n\n._747fd56d_primaryButton:hover:not(:disabled) {\n background: var(--dsw-alias-button-primary-hover);\n}\n\n._7e855445_secondaryButton {\n border: 1px solid var(--dsw-alias-border-l2);\n background: transparent;\n color: var(--dsw-alias-label-primary);\n}\n\n._7e855445_secondaryButton:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-solid);\n}\n\n._747fd56d_primaryButton:disabled,\n._7e855445_secondaryButton:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n._747fd56d_primaryButton:focus-visible,\n._7e855445_secondaryButton:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n\n._238d19be_sectionAction {\n height: 28px;\n padding: 0 12px;\n border-radius: 14px;\n font-size: 12px;\n line-height: 18px;\n}\n\n\n._fbd045e0_statusBlock {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px 14px;\n margin-top: 12px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n}\n\n._d4f70367_statusTitle {\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._8ab300ed_statusLine {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n._e8cedbf5_statusLineLabel {\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._b48dfcba_offNotice {\n margin: 0;\n padding: 12px;\n border: 1px dashed var(--dsw-alias-border-l3);\n border-radius: 8px;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n text-align: center;\n}\n\n\n._700006c9_policyStatus {\n margin: 12px 0 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--dsw-alias-bg-module-platform);\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n._d4b67a81_policyStatusLabel {\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n}\n\n._278bb4b3_policyStatusLine {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-primary);\n}\n\n._da6387e5_policyStatusWarn {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._70effa64_iconButton::after {\n transition: none;\n }\n}\n";
1745
+ const css$3 = "\n\n\n._20fd0e45_root {\n min-width: 0;\n}\n\n\n._4e39cf17_readOnly {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._9860a5b1_notice {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-business-primary);\n}\n\n\n._5006d43e_legacyNotice {\n margin: 12px 0 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--dsw-alias-bg-module-platform);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-business-primary);\n}\n\n._21918751_error {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-error-primary);\n}\n\n\n._7cea4b2f_noticeRow {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 12px 0 0;\n}\n\n._7cea4b2f_noticeRow ._21918751_error {\n flex: 1;\n min-width: 0;\n margin: 0;\n}\n\n\n._94c91bfd_fieldset {\n margin: 0;\n padding: 0;\n border: none;\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n\n._ba240d82_sectionHeading {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0;\n padding: 4px 0;\n font-size: 16px;\n line-height: 24px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._ddbc1b49_sectionHeadingText {\n display: block;\n min-width: 0;\n}\n\n\n._c41f9db7_sectionActions {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-left: auto;\n}\n\n._c41f9db7_sectionActions ._f0864181_discard,\n._c41f9db7_sectionActions ._ccff7e48_save {\n padding: 3px 12px;\n font-size: 12px;\n line-height: 18px;\n}\n\n\n._b116c758_sectionToggle {\n appearance: none;\n border: 0;\n background: none;\n display: flex;\n align-items: center;\n gap: 4px;\n margin: 0;\n padding: 0;\n font: inherit;\n color: inherit;\n cursor: pointer;\n}\n\n._b116c758_sectionToggle:disabled {\n cursor: default;\n}\n\n._b116c758_sectionToggle:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n\n._80101203_advancedBody {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n._94c91bfd_fieldset > ._80101203_advancedBody > ._67826267_field,\n._94c91bfd_fieldset > ._80101203_advancedBody > ._9998065c_checkboxRow,\n._94c91bfd_fieldset > ._80101203_advancedBody > ._3e95886d_numberFields {\n padding: 12px 0;\n}\n\n._94c91bfd_fieldset > ._80101203_advancedBody > ._67826267_field + ._67826267_field,\n._94c91bfd_fieldset > ._80101203_advancedBody > ._9998065c_checkboxRow + ._67826267_field,\n._94c91bfd_fieldset > ._80101203_advancedBody > ._67826267_field + ._3e95886d_numberFields {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n\n\n._67826267_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin: 0;\n padding: 0;\n border: none;\n min-width: 0;\n}\n\n\n._94c91bfd_fieldset > ._67826267_field,\n._94c91bfd_fieldset > ._9998065c_checkboxRow,\n._94c91bfd_fieldset > ._3e95886d_numberFields {\n padding: 12px 0;\n}\n\n._94c91bfd_fieldset > ._67826267_field + ._67826267_field,\n._94c91bfd_fieldset > ._67826267_field + ._3e95886d_numberFields,\n._94c91bfd_fieldset > ._9998065c_checkboxRow + ._67826267_field {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n\n\n._9998065c_checkboxRow {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n\n\n._9998065c_checkboxRow ._06389b18_checkbox {\n margin-top: 3px;\n}\n\n._13e68c3f_fieldLabel {\n \n display: inline-flex;\n align-items: center;\n gap: 10px;\n padding: 0;\n font-size: 13px;\n line-height: 1.5;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n._4bc809b8_hint {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._02c2f6df_checkLabel {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n font-size: 14px;\n line-height: 22px;\n font-weight: 400;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n\n._f2d47237_checkLabelTitle {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 400;\n}\n\n._c1bed8ea_checkLabelDesc {\n font-size: 12px;\n line-height: 18px;\n font-weight: 400;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._06389b18_checkbox {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._06389b18_checkbox:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n\n._b1962759_slotPresetName {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n\n._a6244318_infoHint {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n font-size: 14px;\n line-height: 1;\n color: var(--dsw-alias-label-tertiary);\n background: var(--dsw-alias-interactive-bg-hover);\n cursor: help;\n user-select: none;\n}\n\n._a6244318_infoHint:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._a6244318_infoHint::after {\n content: attr(data-tip);\n position: absolute;\n top: 50%;\n left: calc(100% + 8px);\n transform: translateY(-50%);\n z-index: 10;\n box-sizing: border-box;\n width: max-content;\n max-width: 280px;\n padding: 5px 10px;\n border-radius: 8px;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n font-size: 11px;\n line-height: 17px;\n font-weight: 400;\n white-space: normal;\n text-align: left;\n pointer-events: none;\n opacity: 0;\n transition: opacity .12s;\n}\n\n._a6244318_infoHint:hover::after,\n._a6244318_infoHint:focus-visible::after {\n opacity: 1;\n}\n\n\n._e655c840_infoHintDisabled {\n opacity: 0.4;\n cursor: default;\n}\n\n\n._a2521bb0_optionRow {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n\n._a2521bb0_optionRow:hover:has(input:not(:disabled)) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n\n._06389b18_checkbox,\n._a2521bb0_optionRow input {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._06389b18_checkbox:focus-visible,\n._a2521bb0_optionRow input:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._a2521bb0_optionRow input:disabled {\n cursor: default;\n}\n\n\n._c4ecbdf3_dayRow {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n\n._0330c1ed_dayCell {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 6px;\n border-radius: 6px;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n._0330c1ed_dayCell:hover:has(input:not(:disabled)) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._0330c1ed_dayCell input {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._0330c1ed_dayCell input:disabled {\n cursor: default;\n}\n\n._0330c1ed_dayCell input:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n\n._f9d86f7b_input {\n box-sizing: border-box;\n width: 100%;\n height: 34px;\n padding: 0 12px;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n background: var(--dsw-alias-bg-layer-3);\n color: var(--dsw-alias-label-primary);\n}\n\n._f9d86f7b_input:focus-visible {\n outline: none;\n border-color: var(--dsw-alias-state-business-primary);\n}\n\n._f9d86f7b_input::placeholder {\n color: var(--dsw-alias-label-dimmed);\n}\n\n._f9d86f7b_input:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n\n\n._3a9b42fd_inputTextarea {\n height: auto;\n min-height: 72px;\n padding: 8px 12px;\n resize: vertical;\n}\n\n\n._1285c19b_personaBriefRow {\n display: flex;\n align-items: center;\n gap: 4px;\n min-width: 0;\n}\n\n._4b8f7345_personaBrief {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n}\n\n\n._2686400e_personaBriefEmpty {\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._4e4a07be_personaFull {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-secondary);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n\n._7b60337a_inputInvalid,\n._7b60337a_inputInvalid:focus-visible {\n border-color: var(--dsw-alias-state-error-primary);\n}\n\n\nselect._f9d86f7b_input {\n max-width: 240px;\n cursor: pointer;\n}\n\n\n._16eb7153_selectInput {\n appearance: none;\n padding-right: 32px;\n \n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 12px center;\n background-size: 12px 12px;\n}\n\n\n._3e95886d_numberFields {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n gap: 12px;\n}\n\n._3e95886d_numberFields ._67826267_field {\n padding: 0;\n}\n\n._0cfb5881_list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 4px;\n}\n\n\n._f5c620d6_editorCard {\n display: flex;\n flex-direction: column;\n gap: 14px;\n padding: 14px 16px;\n border-radius: 12px;\n background: var(--dsw-alias-bg-module-platform);\n}\n\n._224b1387_cardFoot {\n display: flex;\n justify-content: flex-end;\n}\n\n._8e220e07_ruleGrid {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n._24a12a2f_ruleCell {\n display: flex;\n flex-direction: column;\n gap: 4px;\n min-width: 120px;\n flex: 1;\n}\n\n._1014c097_ruleCellLabel {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._631094a0_chevron {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n transform: rotate(-90deg);\n transition: transform .16s;\n}\n\n._44836ce8_chevronOpen {\n transform: none;\n}\n\n\n._cf3961bb_chevronFlip {\n transform: rotate(180deg);\n}\n\n\n._86bc52d2_collapseRow {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n._a73efcc6_collapseToggle {\n appearance: none;\n border: 0;\n background: none;\n padding: 0;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n font: inherit;\n text-align: left;\n}\n\n._a73efcc6_collapseToggle:disabled {\n cursor: default;\n}\n\n._af017718_collapseTitle {\n \n flex: none;\n max-width: 55%;\n min-width: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._2cabe603_collapseMeta {\n \n flex: none;\n margin-left: auto;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n._52d6df87_seedBadge {\n flex: none;\n max-width: 40%;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n border-radius: 999px;\n padding: 1px 8px;\n font-size: 11px;\n line-height: 17px;\n font-weight: 500;\n white-space: nowrap;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._7b04f727_slotTag {\n flex: none;\n display: inline-flex;\n align-items: center;\n border-radius: 999px;\n padding: 0 6px;\n font-size: 11px;\n line-height: 17px;\n font-weight: 500;\n white-space: nowrap;\n border: 1px solid;\n}\n\n._c381e792_slotTagHighCost {\n color: var(--dsw-alias-state-error-primary);\n border-color: var(--dsw-alias-state-error-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n._23bdb6fc_slotTagMultiplier {\n color: var(--dsw-alias-state-warn-primary);\n border-color: var(--dsw-alias-state-warn-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 10%, transparent);\n}\n\n._f000eed9_slotTagActive {\n color: var(--dsw-alias-state-success-primary);\n border-color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent);\n}\n\n\n._cd905ce5_dragHandle {\n appearance: none;\n border: 0;\n background: none;\n padding: 0;\n cursor: grab;\n color: var(--dsw-alias-label-tertiary);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n border-radius: 6px;\n flex: none;\n}\n\n._cd905ce5_dragHandle:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._cd905ce5_dragHandle:active {\n cursor: grabbing;\n}\n\n._cd905ce5_dragHandle:disabled {\n cursor: default;\n opacity: 0.4;\n}\n\n._cd905ce5_dragHandle:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n\n._fee63b7e_slotCardDragging {\n opacity: 0.45;\n}\n\n._6f108491_slotCardOver {\n outline: 1px dashed var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n}\n\n\n._15a12620_chainSelectors {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n._240cbbf8_selectorRow {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n\n._70effa64_iconButton {\n position: relative;\n box-sizing: border-box;\n appearance: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: 0;\n border-radius: 6px;\n background: none;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n\n._70effa64_iconButton:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n._70effa64_iconButton:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._70effa64_iconButton:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._70effa64_iconButton::after {\n content: attr(data-tip);\n position: absolute;\n bottom: calc(100% + 6px);\n left: 50%;\n transform: translateX(-50%);\n padding: 3px 8px;\n border-radius: 6px;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n font-size: 11px;\n line-height: 17px;\n white-space: nowrap;\n opacity: 0;\n pointer-events: none;\n transition: opacity .12s;\n}\n\n._70effa64_iconButton:hover::after,\n._70effa64_iconButton:focus-visible::after {\n opacity: 1;\n}\n\n\n._a0968257_iconButtonDanger:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-danger);\n color: var(--dsw-alias-state-error-primary);\n}\n\n\n._711248a9_outlineButton {\n appearance: none;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: none;\n font: inherit;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n._711248a9_outlineButton:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n border-color: var(--dsw-alias-label-dimmed);\n}\n\n._711248a9_outlineButton:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n._711248a9_outlineButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n\n._28202c90_addButton {\n align-self: flex-start;\n}\n\n\n._6a2bd54c_slotAddRow {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 4px;\n flex-wrap: wrap;\n}\n\n\n._4e77523e_rowActions {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n\n._f0864181_discard,\n._ccff7e48_save {\n appearance: none;\n border: 1px solid transparent;\n border-radius: var(--dsw-radius-md);\n padding: 5px 14px;\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n cursor: pointer;\n}\n\n._f0864181_discard {\n border-color: var(--dsw-alias-border-l2);\n background: none;\n color: var(--dsw-alias-label-secondary);\n}\n\n._f0864181_discard:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n border-color: var(--dsw-alias-label-dimmed);\n}\n\n._ccff7e48_save {\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n}\n\n._f0864181_discard:disabled,\n._ccff7e48_save:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n._f0864181_discard:focus-visible,\n._ccff7e48_save:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n\n._fbd045e0_statusBlock {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px 14px;\n margin-top: 12px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n}\n\n._d4f70367_statusTitle {\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._8ab300ed_statusLine {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n._e8cedbf5_statusLineLabel {\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._700006c9_policyStatus {\n margin: 12px 0 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--dsw-alias-bg-module-platform);\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n._d4b67a81_policyStatusLabel {\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n}\n\n._278bb4b3_policyStatusLine {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-primary);\n}\n\n._da6387e5_policyStatusWarn {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._70effa64_iconButton::after,\n ._a6244318_infoHint::after {\n transition: none;\n }\n\n ._631094a0_chevron {\n transition: none;\n }\n}\n";
1755
1746
  const tagId$3 = "dsh-llm-fallbacks/FallbacksCard.module.css";
1756
1747
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
1757
1748
  const tag = document.createElement("style");
@@ -1761,37 +1752,29 @@ window.__ModuleLoader__.load({
1761
1752
  document.head.appendChild(tag);
1762
1753
  }
1763
1754
  var FallbacksCard_module_css_default = {
1764
- "card": "_8827595f_card",
1765
- "cardOpen": "_06704203_cardOpen",
1766
- "header": "_e488d460_header",
1767
- "headText": "_f5dfe084_headText",
1768
- "name": "_8d39bde6_name",
1769
- "description": "_346f3b69_description",
1770
- "chevron": "_631094a0_chevron",
1771
- "chevronOpen": "_44836ce8_chevronOpen",
1772
- "body": "_dbaa7975_body",
1755
+ "root": "_20fd0e45_root",
1773
1756
  "readOnly": "_4e39cf17_readOnly",
1774
- "pending": "_99bf7f3c_pending",
1775
1757
  "notice": "_9860a5b1_notice",
1776
1758
  "legacyNotice": "_5006d43e_legacyNotice",
1777
1759
  "error": "_21918751_error",
1778
1760
  "noticeRow": "_7cea4b2f_noticeRow",
1779
- "form": "_4058c747_form",
1780
- "checkboxRow": "_9998065c_checkboxRow",
1781
- "checkLabel": "_02c2f6df_checkLabel",
1782
- "checkLabelTitle": "_f2d47237_checkLabelTitle",
1783
- "checkLabelDesc": "_c1bed8ea_checkLabelDesc",
1784
- "checkbox": "_06389b18_checkbox",
1785
1761
  "fieldset": "_94c91bfd_fieldset",
1786
- "field": "_67826267_field",
1787
- "fieldLabel": "_13e68c3f_fieldLabel",
1788
1762
  "sectionHeading": "_ba240d82_sectionHeading",
1789
1763
  "sectionHeadingText": "_ddbc1b49_sectionHeadingText",
1790
1764
  "sectionActions": "_c41f9db7_sectionActions",
1765
+ "discard": "_f0864181_discard",
1766
+ "save": "_ccff7e48_save",
1791
1767
  "sectionToggle": "_b116c758_sectionToggle",
1792
- "sectionToggleText": "_a5313fdf_sectionToggleText",
1768
+ "advancedBody": "_80101203_advancedBody",
1769
+ "field": "_67826267_field",
1770
+ "checkboxRow": "_9998065c_checkboxRow",
1771
+ "numberFields": "_3e95886d_numberFields",
1772
+ "checkbox": "_06389b18_checkbox",
1773
+ "fieldLabel": "_13e68c3f_fieldLabel",
1793
1774
  "hint": "_4bc809b8_hint",
1794
- "defaultNote": "_579f813a_defaultNote",
1775
+ "checkLabel": "_02c2f6df_checkLabel",
1776
+ "checkLabelTitle": "_f2d47237_checkLabelTitle",
1777
+ "checkLabelDesc": "_c1bed8ea_checkLabelDesc",
1795
1778
  "slotPresetName": "_b1962759_slotPresetName",
1796
1779
  "infoHint": "_a6244318_infoHint",
1797
1780
  "infoHintDisabled": "_e655c840_infoHintDisabled",
@@ -1806,12 +1789,15 @@ window.__ModuleLoader__.load({
1806
1789
  "personaFull": "_4e4a07be_personaFull",
1807
1790
  "inputInvalid": "_7b60337a_inputInvalid",
1808
1791
  "selectInput": "_16eb7153_selectInput",
1809
- "numberFields": "_3e95886d_numberFields",
1810
1792
  "list": "_0cfb5881_list",
1811
1793
  "editorCard": "_f5c620d6_editorCard",
1812
1794
  "cardFoot": "_224b1387_cardFoot",
1813
1795
  "ruleGrid": "_8e220e07_ruleGrid",
1814
1796
  "ruleCell": "_24a12a2f_ruleCell",
1797
+ "ruleCellLabel": "_1014c097_ruleCellLabel",
1798
+ "chevron": "_631094a0_chevron",
1799
+ "chevronOpen": "_44836ce8_chevronOpen",
1800
+ "chevronFlip": "_cf3961bb_chevronFlip",
1815
1801
  "collapseRow": "_86bc52d2_collapseRow",
1816
1802
  "collapseToggle": "_a73efcc6_collapseToggle",
1817
1803
  "collapseTitle": "_af017718_collapseTitle",
@@ -1822,25 +1808,20 @@ window.__ModuleLoader__.load({
1822
1808
  "slotTagMultiplier": "_23bdb6fc_slotTagMultiplier",
1823
1809
  "slotTagActive": "_f000eed9_slotTagActive",
1824
1810
  "dragHandle": "_cd905ce5_dragHandle",
1825
- "dragHandleIcon": "_49f0c4f0_dragHandleIcon",
1826
1811
  "slotCardDragging": "_fee63b7e_slotCardDragging",
1827
1812
  "slotCardOver": "_6f108491_slotCardOver",
1828
- "ruleCellLabel": "_1014c097_ruleCellLabel",
1829
1813
  "chainSelectors": "_15a12620_chainSelectors",
1830
1814
  "selectorRow": "_240cbbf8_selectorRow",
1831
1815
  "iconButton": "_70effa64_iconButton",
1832
1816
  "iconButtonDanger": "_a0968257_iconButtonDanger",
1817
+ "outlineButton": "_711248a9_outlineButton",
1833
1818
  "addButton": "_28202c90_addButton",
1834
1819
  "slotAddRow": "_6a2bd54c_slotAddRow",
1835
1820
  "rowActions": "_4e77523e_rowActions",
1836
- "primaryButton": "_747fd56d_primaryButton",
1837
- "secondaryButton": "_7e855445_secondaryButton",
1838
- "sectionAction": "_238d19be_sectionAction",
1839
1821
  "statusBlock": "_fbd045e0_statusBlock",
1840
1822
  "statusTitle": "_d4f70367_statusTitle",
1841
1823
  "statusLine": "_8ab300ed_statusLine",
1842
1824
  "statusLineLabel": "_e8cedbf5_statusLineLabel",
1843
- "offNotice": "_b48dfcba_offNotice",
1844
1825
  "policyStatus": "_700006c9_policyStatus",
1845
1826
  "policyStatusLabel": "_d4b67a81_policyStatusLabel",
1846
1827
  "policyStatusLine": "_278bb4b3_policyStatusLine",
@@ -1856,77 +1837,78 @@ window.__ModuleLoader__.load({
1856
1837
  * registration order); owner props are empty and all data flows
1857
1838
  * through {@link FallbacksSettingsController}.
1858
1839
  *
1859
- * The card chrome replicates the upstream `PluginCard` contract (self-drawn:
1860
- * the upstream client value face exports no reusable card): a collapsible
1861
- * `<li>` whose header is a button stacking the plugin name over its
1862
- * description, with a dirty "unsaved" pill and a rotating chevron
1863
- * (`IconChevronDownOutlineMedium` from ui-primitives — a CLIENT_EXTERNALS value
1864
- * import), `aria-expanded`/`aria-label` like the upstream header; a divider
1865
- * under the header; then the form content. PR #62 UX round 2: the card
1866
- * footer is gone — each big section (主代理 / 子代理 / 高级选项) carries its
1867
- * own Save/Discard actions beside its heading (高级选项: inside the expanded
1868
- * body) and its own validation / save-error surface. PR #62 UX round 3:
1869
- * each section's Save writes ONLY that section's fields — 主代理 owns
1870
- * rootChain / timeSlots / tz (+ the card-level `enabled`), 子代理 owns
1871
- * roles, 高级选项 owns the advanced scalars; the patch spreads the last
1872
- * ACCEPTED config for every other section, so a 主代理 Save can never
1873
- * ride along an unsaved 子代理 edit (and vice versa) — and validation /
1874
- * the dirty gate apply per section too (a bad role id never blocks 主代理,
1875
- * and only the saved section's Discard reverts that section's edits).
1876
- * Save/discard disabled terms: save = `!sectionDirty || saving ||
1877
- * !writable`, discard = `!sectionDirty || saving` (KD-U1). Disclosure is
1878
- * card-local state:
1879
- * which card a user has open is a reading gesture, and staged edits outlive
1880
- * collapsing — the pill rides the header (upstream rationale).
1840
+ * FLAT rebuild (plan fallbacks-web-ux-alignment T3, the advisor PR #98
1841
+ * pattern): the collapsible card chrome is gone — no header button, no
1842
+ * rotating chevron, no dirty "unsaved" pill, no card-local open state, no
1843
+ * bordered `<li>` box. The page already renders the plugin title/description
1844
+ * above the card (the `locale/*.json` meta files the host resolves per UI
1845
+ * language), so the notices, the form, and the section actions directly
1846
+ * beneath it in the official flat settings-form language (reference §3):
1847
+ * fields at
1848
+ * 12px vertical padding with 0.5px hairline separators, 34px inputs on the
1849
+ * 0.5px l4 border, per-section Discard + Save pairs on the section
1850
+ * headings. The card is ALWAYS open —
1851
+ * nothing needs card-level disclosure state; the degraded /
1852
+ * error / read-only / migration notices render flat atop the form (the
1853
+ * unavailable notice stays always-visible per KD-G5 — the documented
1854
+ * divergence from the advisor, whose unavailable card renders nothing: the
1855
+ * fallbacks skeleton stays the USABLE last-known form and saves are
1856
+ * attempted).
1857
+ *
1858
+ * The config-level `enabled` switch is REMOVED (T2, breaking): there is no
1859
+ * checkbox row and no `enabled.off` hiding — all fields render
1860
+ * unconditionally; the Plugins-page row toggle is the master switch and the
1861
+ * runtime gates read content presence (`isFallbackActive`).
1881
1862
  *
1882
- * The form body is the two-block editing surface (spec §8): the `enabled`
1883
- * checkbox row, the 6 top-level scalar fields (trigger codes / revert
1884
- * policy / three numeric fields), the `rootChain` block (block 1 — the
1885
- * root agent's single chain, no key input), and the roles block (block 2 —
1886
- * declared role entity cards from `roles.list` plus the rule rows from
1887
- * `roles.rules`, whose role field is a dropdown bound to the declared ids
1888
- * + the built-in `inherit`, same-page live). Saving runs `validateDraft`
1889
- * first — id format/reserved word/duplicates, undeclared rule role
1890
- * references, illegal selectors, and a role with no chain entries (no
1891
- * model config) block the write with a validation banner + inline red
1892
- * borders / hints (never touching the store error path); a
1893
- * non-empty `state.legacyKeys` renders the migration banner at the top of
1894
- * the card body. The row editors keep their filled editorCard surface
1895
- * inside the card, with `--dsw-alias-*` tokens throughout. The reset-
1896
- * to-defaults affordance is GONE from the card (PR #62 UX round 3) — the
1897
- * gateway RPC `fallbacks/reset` and the store `resetToDefaults()` stay as
1898
- * host APIs (store/gateway tests unchanged), only the card UI was removed.
1863
+ * PER-SECTION Save/Discard return beside each section heading (plan
1864
+ * fallbacks-card-section-ux, the maintainer's live-host feedback reversing
1865
+ * the flat plan's one-document model): the scroll-to-save cost of ONE
1866
+ * bottom Save outweighed it. Each section's Save writes ONLY that section's
1867
+ * fields (patch = the last ACCEPTED config with the section's fields
1868
+ * replaced — the ride-along protection, PR #62 UX round 3), gated by that
1869
+ * section's dirty term and validation bucket only (KD-U1: save =
1870
+ * `!sectionDirty || saving || !writable`, discard = `!sectionDirty ||
1871
+ * saving`; Save additionally carries `!writable` — W-1, qc2 fix wave: the
1872
+ * dirty-implies-writable assumption does not hold for this in-place-draft
1873
+ * store). Violations render live under their OWNING section heading, and a
1874
+ * store write failure renders under the section whose Save was last
1875
+ * clicked (`lastSaveSection`). Discard is kept — our staged edits survive
1876
+ * refresh, the advisor's documented divergence from the official
1877
+ * no-discard form — a pure client-side revert of THAT section's editors to
1878
+ * the last accepted config.
1899
1879
  *
1900
- * The page-only chrome is gone (720px column wrapper, title/intro banners,
1901
- * page-bottom status block): the AC-7 read-only status (derived effective
1902
- * model + recent-switch summary) is folded into the card body, and the
1903
- * plugin-config section owns the column width.
1880
+ * The form body is the two-block editing surface (spec §8): the 6 top-level
1881
+ * scalar fields (trigger codes / revert policy / three numeric fields), the
1882
+ * `rootChain` block (block 1 — the root agent's single chain, no key input),
1883
+ * and the roles block (block 2 — declared role entity cards from
1884
+ * `roles.list` plus the rule rows from `roles.rules`, whose role field is a
1885
+ * dropdown bound to the declared ids + the built-in `inherit`, same-page
1886
+ * live). Row-level disclosures that are CONTENT keep their expand/collapse:
1887
+ * the time-slot row cards and the role entity cards (with the seeded
1888
+ * persona briefs) stay collapsible — a read-only view forces them open so
1889
+ * the configs stay reachable. The 主代理 / 子代理 / 高级选项 group labels
1890
+ * are semantic `<h2>` headings (T1); 高级选项 is a content-level disclosure
1891
+ * collapsed by default (T3 — same expand/collapse contract as the rows, a
1892
+ * read-only view forces it open).
1904
1893
  *
1905
- * Degraded/error/loading states keep the same card chrome (KD-U3): the
1906
- * header always renders title+description+chevron, and the body carries the
1907
- * config-channel notice or the load error. A card that cannot reach the
1908
- * `fallbacks/get` gateway channel (`ready && !present`) keeps the USABLE
1909
- * skeleton — the form stays writable and saves are attempted (KD-G5) — with
1910
- * the `unavailable` notice ALWAYS visible (derived open — the header cannot
1911
- * collapse it away), while a healthy card is collapsed until the user
1912
- * expands it (AC-1, the documented divergence from upstream whose
1913
- * unavailable card renders nothing). A hard load failure (`status ===
1914
- * 'error'`) also forces the body open with an error notice and — when the
1915
- * form is inert (`!writable`, i.e. the load never landed) — a Retry button;
1916
- * a save failure keeps the editable form so the Save action itself is the
1917
- * retry. PR #62 UX round 2: the single `state.error` surface is split by
1918
- * origin — a LOAD failure keeps the card-top notice (with Retry when
1919
- * inert), while a WRITE failure renders under the section whose Save was
1920
- * last clicked (`lastSaveSection`), unlike the advisor's separate
1921
- * apply-failure hints.
1894
+ * Validation: id format/reserved word/duplicates, undeclared rule role
1895
+ * references, illegal selectors, and a role with no chain entries (no model
1896
+ * config) block the write (the Save disabled gate) with per-section banners
1897
+ * + inline red borders / hints (never touching the store error path); a
1898
+ * non-empty `state.legacyKeys` renders the migration banner at the top.
1899
+ * The reset-to-defaults affordance is GONE from the card (PR #62 UX
1900
+ * round 3) — the gateway RPC `fallbacks/reset` and the store
1901
+ * `resetToDefaults()` stay as host APIs, only the card UI was removed.
1922
1902
  *
1923
- * The degraded derivation is latched in the card (the store stays untouched):
1924
- * `present` only ever changes inside the store's `accept()`, so the settled
1925
- * `ready` read is authoritative, and a card-local latch carries that value
1926
- * through refresh/save windows (`loading`/`saving`) so the notice body can
1927
- * never collapse mid-refresh (the advisor's latched `degraded` field,
1928
- * implemented without a store change); on a first mount the latch is false,
1929
- * so the healthy card starts (and stays) collapsed through its first load.
1903
+ * The AC-7 read-only status block (recent-switch summary, D-5) stays at the
1904
+ * bottom, flat.
1905
+ *
1906
+ * Presentation is ui-primitives-free (T4, advisor parity + reference §4
1907
+ * risk): Button/Tooltip and the five icon imports are replaced by
1908
+ * self-drawn styled elements — inline SVG icons (plus / trash / chevron /
1909
+ * grip) and the CSS `data-tip` tooltip bubble (the card's existing
1910
+ * icon-button pattern); every color resolves through a `--dsw-alias-*`
1911
+ * token so the card adapts to the light/dark theme.
1930
1912
  */
1931
1913
  const ALL_DAY_LABEL_KEYS = ["allDay.flash", "allDay.pro"];
1932
1914
  const SLOT_PRESET_IDS = [
@@ -1945,6 +1927,106 @@ window.__ModuleLoader__.load({
1945
1927
  "fri",
1946
1928
  "sat"
1947
1929
  ];
1930
+ /** The disclosure chevron (12px) — content-level row/panel toggles only. */
1931
+ function ChevronDownIcon({ className }) {
1932
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1933
+ className,
1934
+ width: "12",
1935
+ height: "12",
1936
+ viewBox: "0 0 12 12",
1937
+ fill: "none",
1938
+ "aria-hidden": "true",
1939
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1940
+ d: "M3 4.5L6 7.5L9 4.5",
1941
+ stroke: "currentColor",
1942
+ strokeWidth: "1.5",
1943
+ strokeLinecap: "round",
1944
+ strokeLinejoin: "round"
1945
+ })
1946
+ });
1947
+ }
1948
+ /** The plus glyph (14px default) for the inline add buttons. */
1949
+ function PlusIcon({ size = 14 }) {
1950
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1951
+ width: size,
1952
+ height: size,
1953
+ viewBox: "0 0 12 12",
1954
+ fill: "none",
1955
+ "aria-hidden": "true",
1956
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1957
+ d: "M6 2.25V9.75M2.25 6H9.75",
1958
+ stroke: "currentColor",
1959
+ strokeWidth: "1.5",
1960
+ strokeLinecap: "round"
1961
+ })
1962
+ });
1963
+ }
1964
+ /** The trash glyph (14px) for the row removals. */
1965
+ function TrashIcon() {
1966
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1967
+ width: "14",
1968
+ height: "14",
1969
+ viewBox: "0 0 12 12",
1970
+ fill: "none",
1971
+ "aria-hidden": "true",
1972
+ children: [
1973
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1974
+ d: "M2.5 3.5H9.5",
1975
+ stroke: "currentColor",
1976
+ strokeWidth: "1.2",
1977
+ strokeLinecap: "round"
1978
+ }),
1979
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1980
+ d: "M4.75 3.25V2.5C4.75 2.22386 4.97386 2 5.25 2H6.75C7.02614 2 7.25 2.22386 7.25 2.5V3.25",
1981
+ stroke: "currentColor",
1982
+ strokeWidth: "1.2",
1983
+ strokeLinecap: "round"
1984
+ }),
1985
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1986
+ d: "M3.5 3.5L3.87464 9.24692C3.91109 9.80186 4.36905 10.2333 4.92513 10.2333H7.07487C7.63095 10.2333 8.08891 9.80186 8.12536 9.24692L8.5 3.5",
1987
+ stroke: "currentColor",
1988
+ strokeWidth: "1.2",
1989
+ strokeLinecap: "round"
1990
+ }),
1991
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1992
+ d: "M5.1 5.4V8.4M6.9 5.4V8.4",
1993
+ stroke: "currentColor",
1994
+ strokeWidth: "1.2",
1995
+ strokeLinecap: "round"
1996
+ })
1997
+ ]
1998
+ });
1999
+ }
2000
+ /** The vertical grip (⋮) for the slot-row drag handle. */
2001
+ function GripIcon() {
2002
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
2003
+ width: "12",
2004
+ height: "12",
2005
+ viewBox: "0 0 12 12",
2006
+ fill: "none",
2007
+ "aria-hidden": "true",
2008
+ children: [
2009
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
2010
+ cx: "6",
2011
+ cy: "2.4",
2012
+ r: "0.95",
2013
+ fill: "currentColor"
2014
+ }),
2015
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
2016
+ cx: "6",
2017
+ cy: "6",
2018
+ r: "0.95",
2019
+ fill: "currentColor"
2020
+ }),
2021
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
2022
+ cx: "6",
2023
+ cy: "9.6",
2024
+ r: "0.95",
2025
+ fill: "currentColor"
2026
+ })
2027
+ ]
2028
+ });
2029
+ }
1948
2030
  /** IANA timezone of this renderer (browser / host). */
1949
2031
  function hostTimeZone() {
1950
2032
  try {
@@ -2001,7 +2083,6 @@ window.__ModuleLoader__.load({
2001
2083
  /** Split scalars from the row editors (rootChain / role entities / role rules). */
2002
2084
  function scalarsOf(config) {
2003
2085
  return {
2004
- enabled: config.enabled,
2005
2086
  triggerCodes: [...config.triggerCodes],
2006
2087
  cooldownMs: config.cooldownMs,
2007
2088
  revertPolicy: config.revertPolicy,
@@ -2039,7 +2120,6 @@ window.__ModuleLoader__.load({
2039
2120
  const trailingChain = rowsToRootChain([allDayChainRow]);
2040
2121
  const tz = resolvedSlotTz(timeSlotRows, scalars.tz);
2041
2122
  return {
2042
- enabled: scalars.enabled,
2043
2123
  triggerCodes: [...scalars.triggerCodes],
2044
2124
  rootChain: allDayModel === "" ? [...acceptedRootChain] : [...trailingChain, allDayModel],
2045
2125
  roles: {
@@ -2056,14 +2136,6 @@ window.__ModuleLoader__.load({
2056
2136
  tz
2057
2137
  };
2058
2138
  }
2059
- /** An empty per-section validation-error record (the clean-draft shape). */
2060
- function emptyValidationErrors() {
2061
- return {
2062
- main: [],
2063
- sub: [],
2064
- advanced: []
2065
- };
2066
- }
2067
2139
  /**
2068
2140
  * Badge label for one row's provenance (plan role-card-seeded-ux): every
2069
2141
  * row states where its seed state comes from. The three reserved labels
@@ -2088,22 +2160,27 @@ window.__ModuleLoader__.load({
2088
2160
  * (only reachable through the synthetic outside option — the dropdown
2089
2161
  * itself constrains normal edits), and illegal selector entries in
2090
2162
  * rootChain and role chains. Returns one localized message per violation,
2091
- * bucketed by the section that owns the offending field (PR #62 UX round
2092
- * 2 — 主代理: allDay / timeSlots / slot* / tz / default model / default
2093
- * chain; 子代理: role* / rule*; 高级选项: trigger / cooldown / revert /
2094
- * always / roleAutoMatch — the scalars are never validated, so the
2095
- * advanced bucket stays empty today). A non-empty result blocks
2096
- * {@link save} — the draft is never written. `persona` is free text and
2097
- * never validated.
2163
+ * bucketed by the section that owns the offending field (主代理: allDay /
2164
+ * timeSlots / slot* / tz / default model / default chain; 子代理: role* /
2165
+ * rule*; 高级选项: trigger / cooldown / revert / always / roleAutoMatch —
2166
+ * the scalars are never validated, so the advanced bucket stays empty
2167
+ * today). A non-empty bucket blocks THAT section's Save write only
2168
+ * (per-section saves, plan fallbacks-card-section-ux) — a sibling section
2169
+ * with a clean bucket still saves. `persona` is free text and never
2170
+ * validated.
2098
2171
  *
2099
2172
  * `seedInfo` is the live trimmed-id → seed-entry map derived from
2100
2173
  * `state.seeds` (spec §9.4): the empty-chain block relaxes for seeded ids
2101
2174
  * only (spec §9.6 / AC-3 — a seeded role's chain is legitimately empty by
2102
- * design, R4, and the row must stay persistable through a section save);
2103
- * non-seeded behavior is byte-identical.
2175
+ * design, R4, and the row must stay persistable); non-seeded behavior is
2176
+ * byte-identical.
2104
2177
  */
2105
2178
  function validateDraft(draft, t, seedInfo) {
2106
- const errors = emptyValidationErrors();
2179
+ const errors = {
2180
+ main: [],
2181
+ sub: [],
2182
+ advanced: []
2183
+ };
2107
2184
  const declaredIds = /* @__PURE__ */ new Set();
2108
2185
  for (const role of draft.roles.list) {
2109
2186
  if (!ROLE_ID_PATTERN.test(role.id)) errors.sub.push(t("validation.roleIdFormat", { id: role.id }));
@@ -2158,11 +2235,12 @@ window.__ModuleLoader__.load({
2158
2235
  }
2159
2236
  /**
2160
2237
  * The trimmed role ids that are validation failures (format / reserved word
2161
- * / duplicate) — drives the inline red border after a blocked save attempt.
2162
- * Derived once per render into a Set (qc3 F-3): a duplicate scan inside the
2163
- * render loop would be O(N²) per row; here the whole derivation is O(N) and
2164
- * each row's check is a single Set lookup. Selector errors stay on the
2165
- * banner only (plan Task 3 inline-scope rule).
2238
+ * / duplicate) — drives the inline red border on the offending id input
2239
+ * (live: the border tracks the draft, matching the live Save disabled
2240
+ * gate). Derived once per render into a Set (qc3 F-3): a duplicate scan
2241
+ * inside the render loop would be O(N²) per row; here the whole derivation
2242
+ * is O(N) and each row's check is a single Set lookup. Selector errors stay
2243
+ * on the banner only (plan Task 3 inline-scope rule).
2166
2244
  */
2167
2245
  function collectInvalidRoleIds(rows) {
2168
2246
  const counts = /* @__PURE__ */ new Map();
@@ -2184,9 +2262,8 @@ window.__ModuleLoader__.load({
2184
2262
  }
2185
2263
  /**
2186
2264
  * Custom time-slot rows whose window is not valid `HH:mm` — drives the
2187
- * inline red border after a blocked save attempt (same derivation pattern
2188
- * as {@link collectInvalidRoleIds}: one pass per render, index lookup per
2189
- * row).
2265
+ * inline red border on the start/end inputs (same derivation pattern as
2266
+ * {@link collectInvalidRoleIds}: one pass per render, index lookup per row).
2190
2267
  */
2191
2268
  function collectInvalidSlotRows(rows) {
2192
2269
  const invalid = /* @__PURE__ */ new Set();
@@ -2204,12 +2281,13 @@ window.__ModuleLoader__.load({
2204
2281
  } : void 0;
2205
2282
  }
2206
2283
  /**
2207
- * Inline "!" info badge (T3): the detailed explanation rides a primitives
2208
- * Tooltip bubble (side "right", ~300ms hover delay, immediate on keyboard
2209
- * focus) while the short inline hint stays on the row. The badge is an
2210
- * exposed, focusable image — the Models page credential-status pattern
2211
- * (role="img" + aria-label) — so the accessible name is always available;
2212
- * the tooltip is a progressive enhancement on top.
2284
+ * Inline "!" info badge (T3): the detailed explanation rides a CSS
2285
+ * `data-tip` bubble (the card's self-drawn tooltip pattern — T4 replaces
2286
+ * the primitives Tooltip; anchored to the RIGHT of the badge, the original
2287
+ * primitives side="right" contract) while the short inline hint stays on
2288
+ * the row. The badge is an exposed, focusable image — the Models page
2289
+ * credential-status pattern (role="img" + aria-label) — so the accessible
2290
+ * name is always available; the bubble is a progressive enhancement on top.
2213
2291
  *
2214
2292
  * `disabled` mirrors the read-only/loading suppression of the surrounding
2215
2293
  * controls: the bubble is suppressed, the badge drops out of the tab order
@@ -2222,18 +2300,13 @@ window.__ModuleLoader__.load({
2222
2300
  * label-activation default action to cancel.
2223
2301
  */
2224
2302
  function InfoHint({ label, disabled = false }) {
2225
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Tooltip, {
2226
- label,
2227
- side: "right",
2228
- delayMs: 300,
2229
- disabled,
2230
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2231
- className: disabled ? `${FallbacksCard_module_css_default.infoHint} ${FallbacksCard_module_css_default.infoHintDisabled}` : FallbacksCard_module_css_default.infoHint,
2232
- role: "img",
2233
- "aria-label": label,
2234
- tabIndex: disabled ? -1 : 0,
2235
- children: "!"
2236
- })
2303
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2304
+ className: disabled ? `${FallbacksCard_module_css_default.infoHint} ${FallbacksCard_module_css_default.infoHintDisabled}` : FallbacksCard_module_css_default.infoHint,
2305
+ role: "img",
2306
+ "aria-label": label,
2307
+ "data-tip": label,
2308
+ tabIndex: disabled ? -1 : 0,
2309
+ children: "!"
2237
2310
  });
2238
2311
  }
2239
2312
  /**
@@ -2361,17 +2434,16 @@ window.__ModuleLoader__.load({
2361
2434
  "data-tip": t("chains.selector.remove"),
2362
2435
  "aria-label": t("chains.selector.remove"),
2363
2436
  onClick: onRemove,
2364
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineMedium, {})
2437
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrashIcon, {})
2365
2438
  })
2366
2439
  })
2367
2440
  ]
2368
2441
  });
2369
2442
  }
2370
2443
  /**
2371
- * Render the Fallbacks settings card inside the plugin-config section,
2372
- * replicating the upstream PluginCard chrome (KD-U1). The body carries the
2373
- * existing form content unchanged plus the folded-in status block and the
2374
- * footer actions (Discard / Reset / Save).
2444
+ * Render the Fallbacks settings card inside the plugin-config section —
2445
+ * flat: the notices, the form, and the section action pairs directly under
2446
+ * the page's plugin title/description, with no chrome of our own.
2375
2447
  * @param props - slot-delivered injected dependencies and the synthesized t seat.
2376
2448
  * @returns the card.
2377
2449
  */
@@ -2390,14 +2462,12 @@ window.__ModuleLoader__.load({
2390
2462
  const [roleRows, setRoleRows] = (0, react.useState)(() => rolesToRows(defaultFallbacksConfig.roles.list));
2391
2463
  const [ruleRows, setRuleRows] = (0, react.useState)(() => rulesToRows(defaultFallbacksConfig.roles.rules));
2392
2464
  const [presetToAdd, setPresetToAdd] = (0, react.useState)("");
2393
- const [validationErrors, setValidationErrors] = (0, react.useState)(emptyValidationErrors);
2394
- const [validationAttempted, setValidationAttempted] = (0, react.useState)(false);
2395
2465
  const [lastSaveSection, setLastSaveSection] = (0, react.useState)(null);
2466
+ const [advancedOpen, setAdvancedOpen] = (0, react.useState)(false);
2396
2467
  const seededConfigKey = (0, react.useRef)(null);
2397
2468
  const draft = assembleConfig(scalars, allDayModel, state.config.rootChain, allDayChainRow, roleRows, ruleRows, state.config.roles.list, state.config.presets, scalars.roleAutoMatch, timeSlotRows);
2398
2469
  const hasEmptyRuleRows = ruleRows.some((row) => row.role === "");
2399
- const enabledDirty = scalars.enabled !== state.config.enabled;
2400
- const mainDirty = enabledDirty || JSON.stringify([...draft.rootChain, draft.timeSlots]) !== JSON.stringify([...state.config.rootChain, state.config.timeSlots ?? []]);
2470
+ const mainDirty = JSON.stringify([...draft.rootChain, draft.timeSlots]) !== JSON.stringify([...state.config.rootChain, state.config.timeSlots ?? []]);
2401
2471
  const subDirty = hasEmptyRuleRows || JSON.stringify(draft.roles) !== JSON.stringify(state.config.roles);
2402
2472
  const advancedDirty = JSON.stringify([
2403
2473
  draft.triggerCodes,
@@ -2414,7 +2484,6 @@ window.__ModuleLoader__.load({
2414
2484
  state.config.alwaysModeRetryCap,
2415
2485
  state.config.roleAutoMatch
2416
2486
  ]);
2417
- const dirty = mainDirty || subDirty || advancedDirty;
2418
2487
  const firstSeedDone = (0, react.useRef)(false);
2419
2488
  (0, react.useEffect)(() => {
2420
2489
  if (state.status !== "ready") return;
@@ -2430,7 +2499,6 @@ window.__ModuleLoader__.load({
2430
2499
  setTimeSlotRows(timeSlotsToRows(state.config.timeSlots ?? [], catalog));
2431
2500
  setScalars((prev) => ({
2432
2501
  ...prev,
2433
- enabled: state.config.enabled,
2434
2502
  tz: state.config.tz ?? "Asia/Shanghai"
2435
2503
  }));
2436
2504
  }
@@ -2643,26 +2711,26 @@ window.__ModuleLoader__.load({
2643
2711
  return next;
2644
2712
  });
2645
2713
  };
2646
- const allValidationErrors = [
2647
- ...validationErrors.main,
2648
- ...validationErrors.sub,
2649
- ...validationErrors.advanced
2650
- ];
2651
2714
  const saving = state.status === "saving";
2652
2715
  const writable = state.writable;
2716
+ const advancedVisible = advancedOpen || !writable;
2717
+ const cooldownMsTip = `${t("cooldownMs.tooltip")} ${t("defaults.prefix")}: ${defaultFallbacksConfig.cooldownMs}`;
2718
+ const maxSwitchesPerStepTip = `${t("maxSwitchesPerStep.tooltip")} ${t("defaults.prefix")}: ${defaultFallbacksConfig.maxSwitchesPerStep}`;
2719
+ const alwaysModeRetryCapTip = `${t("alwaysModeRetryCap.tooltip")} ${t("defaults.prefix")}: ${defaultFallbacksConfig.alwaysModeRetryCap}`;
2653
2720
  const unknownCodes = scalars.triggerCodes.filter((code) => !KNOWN_TRIGGER_CODES.includes(code));
2654
2721
  const presetsPresent = timeSlotRows.some((row) => row.kind === "preset");
2655
2722
  const glmConfigured = state.configuredProviders.some((entry) => entry.provider === "zai-coding-cn");
2656
2723
  const slotState = resolveSlotState(state.config, /* @__PURE__ */ new Date(), scalars.tz);
2657
2724
  const activeSlotIndex = slotState.winner === "all-day" ? -1 : state.config.timeSlots?.indexOf(slotState.winner) ?? -1;
2658
2725
  const roleOptions = ruleRoleOptions({ list: roleRows });
2659
- const invalidRoleIds = validationAttempted ? collectInvalidRoleIds(roleRows) : null;
2660
- const invalidSlotRows = validationAttempted ? collectInvalidSlotRows(timeSlotRows) : null;
2726
+ const invalidRoleIds = collectInvalidRoleIds(roleRows);
2727
+ const invalidSlotRows = collectInvalidSlotRows(timeSlotRows);
2661
2728
  const seedInfo = /* @__PURE__ */ new Map();
2662
2729
  for (const seed of state.seeds) seedInfo.set(seed.id.trim(), {
2663
2730
  overridden: seed.overridden,
2664
2731
  source: seed.source
2665
2732
  });
2733
+ const liveErrors = validateDraft(draft, t, seedInfo);
2666
2734
  const latestSwitch = state.switches[0];
2667
2735
  let switchesLine;
2668
2736
  if (state.switchesStatus === "error") switchesLine = t("status.switches.error", { message: state.switchesError });
@@ -2712,10 +2780,7 @@ window.__ModuleLoader__.load({
2712
2780
  subDirty
2713
2781
  ]);
2714
2782
  const sectionPatch = (section) => {
2715
- const base = {
2716
- ...state.config,
2717
- enabled: scalars.enabled
2718
- };
2783
+ const base = { ...state.config };
2719
2784
  switch (section) {
2720
2785
  case "main": return {
2721
2786
  ...base,
@@ -2738,43 +2803,26 @@ window.__ModuleLoader__.load({
2738
2803
  };
2739
2804
  }
2740
2805
  };
2741
- const save = (section) => {
2806
+ const saveSection = (section) => {
2807
+ if (liveErrors[section].length > 0 || section === "sub" && hasEmptyRuleRows) return;
2742
2808
  setLastSaveSection(section);
2743
- const errors = validateDraft(draft, t, seedInfo);
2744
- if (section === "sub" && hasEmptyRuleRows) errors.sub.push(t("validation.ruleRoleRequired"));
2745
- if (errors[section].length > 0) {
2746
- setValidationErrors(errors);
2747
- setValidationAttempted(true);
2748
- return;
2749
- }
2750
- setValidationErrors(emptyValidationErrors());
2751
- setValidationAttempted(false);
2752
2809
  controller.save(sectionPatch(section));
2753
2810
  };
2754
- const saveEnabled = () => {
2755
- setLastSaveSection("main");
2756
- setValidationErrors(emptyValidationErrors());
2757
- setValidationAttempted(false);
2758
- controller.save({
2759
- ...state.config,
2760
- enabled: scalars.enabled
2761
- });
2762
- };
2763
2811
  const discardSection = (section) => {
2812
+ const catalog = catalogOf(state);
2764
2813
  switch (section) {
2765
2814
  case "main":
2766
2815
  setAllDayModel(allDayModelOf(state.config.rootChain));
2767
- setAllDayChainRow(allDayChainRowOf(state.config.rootChain, catalogOf(state)));
2768
- setTimeSlotRows(timeSlotsToRows(state.config.timeSlots ?? [], catalogOf(state)));
2816
+ setAllDayChainRow(allDayChainRowOf(state.config.rootChain, catalog));
2817
+ setTimeSlotRows(timeSlotsToRows(state.config.timeSlots ?? [], catalog));
2769
2818
  setScalars((prev) => ({
2770
2819
  ...prev,
2771
- enabled: state.config.enabled,
2772
2820
  tz: state.config.tz ?? "Asia/Shanghai"
2773
2821
  }));
2774
2822
  break;
2775
2823
  case "sub":
2776
- setRoleRows(rolesToRows(state.config.roles.list, catalogOf(state)));
2777
- setRuleRows(rulesToRows(state.config.roles.rules, catalogOf(state)));
2824
+ setRoleRows(rolesToRows(state.config.roles.list, catalog));
2825
+ setRuleRows(rulesToRows(state.config.roles.rules, catalog));
2778
2826
  break;
2779
2827
  case "advanced": setScalars((prev) => ({
2780
2828
  ...prev,
@@ -2786,1418 +2834,1254 @@ window.__ModuleLoader__.load({
2786
2834
  roleAutoMatch: state.config.roleAutoMatch
2787
2835
  }));
2788
2836
  }
2789
- setValidationErrors(emptyValidationErrors());
2790
- setValidationAttempted(false);
2791
- };
2792
- const discardEnabled = () => {
2793
- setScalars((prev) => ({
2794
- ...prev,
2795
- enabled: state.config.enabled
2796
- }));
2797
- setValidationErrors(emptyValidationErrors());
2798
- setValidationAttempted(false);
2799
2837
  };
2800
- (0, react.useEffect)(() => {
2801
- if (!validationAttempted) return;
2802
- const errors = validateDraft(draft, t, seedInfo);
2803
- if (errors.main.length === 0 && errors.sub.length === 0 && errors.advanced.length === 0 && !ruleRows.some((row) => row.role === "")) {
2804
- setValidationErrors(emptyValidationErrors());
2805
- setValidationAttempted(false);
2806
- }
2807
- }, [
2808
- validationAttempted,
2809
- draft,
2810
- ruleRows,
2811
- t
2812
- ]);
2813
2838
  (0, react.useEffect)(() => {
2814
2839
  if (state.status === "ready") setLastSaveSection(null);
2815
2840
  }, [state.status]);
2816
- const [userOpen, setUserOpen] = (0, react.useState)(false);
2817
- const [advancedOpen, setAdvancedOpen] = (0, react.useState)(false);
2818
2841
  const degradedLatch = (0, react.useRef)(false);
2819
- const errorLatch = (0, react.useRef)(false);
2820
- if (state.status === "ready") {
2821
- degradedLatch.current = !state.present;
2822
- errorLatch.current = false;
2823
- } else if (state.status === "error") errorLatch.current = true;
2842
+ if (state.status === "ready") degradedLatch.current = !state.present;
2824
2843
  const degraded = state.status === "ready" ? !state.present : degradedLatch.current;
2825
- const open = userOpen || errorLatch.current || degraded;
2826
- const advancedVisible = advancedOpen || !writable;
2827
- const title = t("title");
2828
- const header = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2829
- type: "button",
2830
- className: FallbacksCard_module_css_default.header,
2831
- "aria-expanded": open,
2832
- "aria-label": `${t(open ? "collapse" : "expand")}: ${title}`,
2833
- onClick: () => {
2834
- if (!degraded && state.status !== "error") setUserOpen(!userOpen);
2835
- },
2844
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2845
+ className: FallbacksCard_module_css_default.root,
2836
2846
  children: [
2837
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2838
- className: FallbacksCard_module_css_default.headText,
2839
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2840
- className: FallbacksCard_module_css_default.name,
2841
- children: title
2842
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2843
- className: FallbacksCard_module_css_default.description,
2844
- children: t("intro")
2847
+ state.legacyKeys.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2848
+ className: FallbacksCard_module_css_default.legacyNotice,
2849
+ role: "status",
2850
+ children: t("legacy.banner", { keys: state.legacyKeys.join(", ") })
2851
+ }),
2852
+ state.status === "error" && state.error !== null && lastSaveSection === null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2853
+ className: FallbacksCard_module_css_default.noticeRow,
2854
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2855
+ className: FallbacksCard_module_css_default.error,
2856
+ role: "alert",
2857
+ children: t("error.generic", { message: state.error })
2858
+ }), !state.writable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2859
+ type: "button",
2860
+ className: FallbacksCard_module_css_default.outlineButton,
2861
+ onClick: () => {
2862
+ controller.load();
2863
+ },
2864
+ children: t("retry")
2845
2865
  })]
2846
2866
  }),
2847
- dirty ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2848
- className: FallbacksCard_module_css_default.pending,
2849
- children: t("unsaved")
2850
- }) : null,
2851
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineMedium, { className: open ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron })
2852
- ]
2853
- });
2854
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
2855
- className: open ? `${FallbacksCard_module_css_default.card} ${FallbacksCard_module_css_default.cardOpen}` : FallbacksCard_module_css_default.card,
2856
- children: [header, open && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2857
- className: FallbacksCard_module_css_default.body,
2858
- children: [
2859
- state.legacyKeys.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2860
- className: FallbacksCard_module_css_default.legacyNotice,
2861
- role: "status",
2862
- children: t("legacy.banner", { keys: state.legacyKeys.join(", ") })
2863
- }),
2864
- state.status === "error" && state.error !== null && lastSaveSection === null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2865
- className: FallbacksCard_module_css_default.noticeRow,
2866
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2867
+ degraded && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2868
+ className: FallbacksCard_module_css_default.notice,
2869
+ role: "status",
2870
+ children: t("unavailable")
2871
+ }),
2872
+ state.status === "ready" && !state.writable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2873
+ className: FallbacksCard_module_css_default.readOnly,
2874
+ role: "status",
2875
+ children: t("readOnly")
2876
+ }),
2877
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
2878
+ className: FallbacksCard_module_css_default.fieldset,
2879
+ disabled: !writable,
2880
+ children: [
2881
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h2", {
2882
+ className: FallbacksCard_module_css_default.sectionHeading,
2883
+ id: "fallbacks-main-agent",
2884
+ "aria-label": t("mainAgent.label"),
2885
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2886
+ className: FallbacksCard_module_css_default.sectionHeadingText,
2887
+ children: t("mainAgent.label")
2888
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2889
+ className: FallbacksCard_module_css_default.sectionActions,
2890
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2891
+ type: "button",
2892
+ className: FallbacksCard_module_css_default.discard,
2893
+ disabled: !mainDirty || saving,
2894
+ onClick: () => {
2895
+ discardSection("main");
2896
+ },
2897
+ children: t("discard")
2898
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2899
+ type: "button",
2900
+ className: FallbacksCard_module_css_default.save,
2901
+ disabled: !writable || saving || !mainDirty,
2902
+ onClick: () => {
2903
+ saveSection("main");
2904
+ },
2905
+ children: saving ? t("save.saving") : t("save")
2906
+ })]
2907
+ })]
2908
+ }),
2909
+ liveErrors.main.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2910
+ className: FallbacksCard_module_css_default.error,
2911
+ role: "alert",
2912
+ children: `${t("validation.blocked")}${liveErrors.main.join("; ")}`
2913
+ }),
2914
+ lastSaveSection === "main" && state.status === "error" && state.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2867
2915
  className: FallbacksCard_module_css_default.error,
2868
2916
  role: "alert",
2869
2917
  children: t("error.generic", { message: state.error })
2870
- }), !state.writable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
2871
- variant: "outline",
2872
- size: "sm",
2873
- onClick: () => {
2874
- controller.load();
2875
- },
2876
- children: t("retry")
2877
- })]
2878
- }),
2879
- degraded && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2880
- className: FallbacksCard_module_css_default.notice,
2881
- role: "status",
2882
- children: t("unavailable")
2883
- }),
2884
- state.status === "ready" && !state.writable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2885
- className: FallbacksCard_module_css_default.readOnly,
2886
- role: "status",
2887
- children: t("readOnly")
2888
- }),
2889
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2890
- className: FallbacksCard_module_css_default.form,
2891
- children: [
2892
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2893
- className: FallbacksCard_module_css_default.checkboxRow,
2894
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2895
- className: FallbacksCard_module_css_default.checkLabel,
2896
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2897
- className: FallbacksCard_module_css_default.checkLabelTitle,
2898
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
2899
- htmlFor: "fallbacks-enabled",
2900
- children: t("enabled.label")
2901
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
2902
- label: t("enabled.tooltip"),
2903
- disabled: !writable
2904
- })]
2905
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2906
- className: FallbacksCard_module_css_default.checkLabelDesc,
2907
- children: t("enabled.hint")
2918
+ }),
2919
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2920
+ className: FallbacksCard_module_css_default.field,
2921
+ role: "group",
2922
+ "aria-labelledby": "fallbacks-time-slots",
2923
+ children: [
2924
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2925
+ className: FallbacksCard_module_css_default.fieldLabel,
2926
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2927
+ id: "fallbacks-time-slots",
2928
+ children: t("timeSlots.label")
2929
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
2930
+ label: t("timeSlots.tooltip"),
2931
+ disabled: !writable
2908
2932
  })]
2909
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2910
- id: "fallbacks-enabled",
2911
- type: "checkbox",
2912
- className: FallbacksCard_module_css_default.checkbox,
2913
- checked: scalars.enabled,
2914
- disabled: !writable,
2915
- onChange: (event) => {
2916
- updateScalars((draft) => {
2917
- draft.enabled = event.target.checked;
2918
- });
2919
- }
2920
- })]
2921
- }),
2922
- !scalars.enabled && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2923
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2924
- className: FallbacksCard_module_css_default.offNotice,
2925
- children: t("enabled.off")
2926
- }),
2927
- allValidationErrors.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2928
- className: FallbacksCard_module_css_default.error,
2929
- role: "alert",
2930
- children: `${t("validation.blocked")}${allValidationErrors.join("; ")}`
2931
2933
  }),
2932
- lastSaveSection === "main" && state.status === "error" && state.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2933
- className: FallbacksCard_module_css_default.error,
2934
- role: "alert",
2935
- children: t("error.generic", { message: state.error })
2934
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2935
+ className: FallbacksCard_module_css_default.hint,
2936
+ children: t("timeSlots.hint")
2936
2937
  }),
2937
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2938
- className: FallbacksCard_module_css_default.sectionActions,
2939
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2940
- type: "button",
2941
- className: `${FallbacksCard_module_css_default.secondaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
2942
- disabled: !enabledDirty || saving,
2943
- onClick: discardEnabled,
2944
- children: t("discard")
2945
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2946
- type: "button",
2947
- className: `${FallbacksCard_module_css_default.primaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
2948
- disabled: !writable || saving || !enabledDirty,
2949
- onClick: saveEnabled,
2950
- children: saving ? t("save.saving") : t("save")
2951
- })]
2952
- })
2953
- ] }),
2954
- scalars.enabled && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
2955
- className: FallbacksCard_module_css_default.fieldset,
2956
- disabled: !writable,
2957
- children: [
2958
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2959
- className: FallbacksCard_module_css_default.sectionHeading,
2960
- id: "fallbacks-main-agent",
2961
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2962
- className: FallbacksCard_module_css_default.sectionHeadingText,
2963
- children: t("mainAgent.label")
2964
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2965
- className: FallbacksCard_module_css_default.sectionActions,
2966
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2967
- type: "button",
2968
- className: `${FallbacksCard_module_css_default.secondaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
2969
- disabled: !mainDirty || saving,
2970
- onClick: () => {
2971
- discardSection("main");
2972
- },
2973
- children: t("discard")
2974
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2975
- type: "button",
2976
- className: `${FallbacksCard_module_css_default.primaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
2977
- disabled: !writable || saving || !mainDirty,
2978
- onClick: () => {
2979
- save("main");
2980
- },
2981
- children: saving ? t("save.saving") : t("save")
2982
- })]
2983
- })]
2984
- }),
2985
- validationErrors.main.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2986
- className: FallbacksCard_module_css_default.error,
2987
- role: "alert",
2988
- children: `${t("validation.blocked")}${validationErrors.main.join("; ")}`
2989
- }),
2990
- lastSaveSection === "main" && state.status === "error" && state.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2991
- className: FallbacksCard_module_css_default.error,
2992
- role: "alert",
2993
- children: t("error.generic", { message: state.error })
2994
- }),
2995
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2996
- className: FallbacksCard_module_css_default.field,
2997
- role: "group",
2998
- "aria-labelledby": "fallbacks-time-slots",
2999
- children: [
3000
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3001
- className: FallbacksCard_module_css_default.fieldLabel,
3002
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3003
- id: "fallbacks-time-slots",
3004
- children: t("timeSlots.label")
3005
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3006
- label: t("timeSlots.tooltip"),
3007
- disabled: !writable
2938
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2939
+ className: FallbacksCard_module_css_default.list,
2940
+ children: timeSlotRows.map((row, index) => {
2941
+ const invalidWindow = invalidSlotRows.has(index);
2942
+ const chainEmpty = row.selectors.every((selector) => selectorRowToRaw(selector) === "");
2943
+ const firstModel = row.selectors.map(selectorRowToRaw).find((entry) => entry !== "");
2944
+ const slotExpanded = !row.collapsed || !writable;
2945
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2946
+ className: `${FallbacksCard_module_css_default.editorCard} ${draggedSlotIndex === index ? FallbacksCard_module_css_default.slotCardDragging : ""} ${overSlotIndex === index && draggedSlotIndex !== null && draggedSlotIndex !== index ? FallbacksCard_module_css_default.slotCardOver : ""}`,
2947
+ onDragOver: (event) => {
2948
+ if (draggedSlotIndex === null) return;
2949
+ event.preventDefault();
2950
+ if (overSlotIndex !== index) setOverSlotIndex(index);
2951
+ },
2952
+ onDrop: (event) => {
2953
+ event.preventDefault();
2954
+ const from = draggedSlotIndex;
2955
+ setDraggedSlotIndex(null);
2956
+ setOverSlotIndex(null);
2957
+ if (from !== null && from !== index) reorderTimeSlotRow(from, index);
2958
+ },
2959
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2960
+ className: FallbacksCard_module_css_default.collapseRow,
2961
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2962
+ type: "button",
2963
+ className: FallbacksCard_module_css_default.collapseToggle,
2964
+ "aria-expanded": slotExpanded,
2965
+ "aria-label": t(slotExpanded ? "timeSlots.collapse" : "timeSlots.expand"),
2966
+ disabled: !writable,
2967
+ onClick: () => {
2968
+ updateTimeSlotRow(index, { collapsed: !row.collapsed });
2969
+ },
2970
+ children: [
2971
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDownIcon, { className: slotExpanded ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron }),
2972
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2973
+ className: FallbacksCard_module_css_default.collapseTitle,
2974
+ children: row.kind === "preset" ? t(`timeSlots.preset.${row.preset}.label`) : row.name !== "" ? row.name : `custom ${row.start}-${row.end}`
2975
+ }),
2976
+ row.kind === "preset" && (row.preset === "liang-peak" || row.preset === "glm-peak") && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2977
+ className: `${FallbacksCard_module_css_default.slotTag} ${FallbacksCard_module_css_default.slotTagHighCost}`,
2978
+ children: t("timeSlots.preset.highCost")
2979
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2980
+ className: `${FallbacksCard_module_css_default.slotTag} ${FallbacksCard_module_css_default.slotTagMultiplier}`,
2981
+ children: t("timeSlots.preset.multiplier", { n: row.preset === "liang-peak" ? "2" : "3" })
2982
+ })] }),
2983
+ activeSlotIndex === index && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2984
+ className: `${FallbacksCard_module_css_default.slotTag} ${FallbacksCard_module_css_default.slotTagActive}`,
2985
+ children: t("timeSlots.active")
2986
+ }),
2987
+ firstModel !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2988
+ className: FallbacksCard_module_css_default.collapseMeta,
2989
+ children: firstModel
2990
+ })
2991
+ ]
2992
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2993
+ type: "button",
2994
+ className: FallbacksCard_module_css_default.dragHandle,
2995
+ draggable: writable,
2996
+ "data-tip": t("timeSlots.drag"),
2997
+ "aria-label": t("timeSlots.drag"),
2998
+ disabled: !writable,
2999
+ onDragStart: () => {
3000
+ if (!writable) return;
3001
+ setDraggedSlotIndex(index);
3002
+ setOverSlotIndex(index);
3003
+ },
3004
+ onDragEnd: () => {
3005
+ setDraggedSlotIndex(null);
3006
+ setOverSlotIndex(null);
3007
+ },
3008
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GripIcon, {})
3008
3009
  })]
3009
- }),
3010
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3011
- className: FallbacksCard_module_css_default.hint,
3012
- children: t("timeSlots.hint")
3013
- }),
3014
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3015
- className: FallbacksCard_module_css_default.list,
3016
- children: timeSlotRows.map((row, index) => {
3017
- const invalidWindow = invalidSlotRows?.has(index) ?? false;
3018
- const chainEmpty = row.selectors.every((selector) => selectorRowToRaw(selector) === "");
3019
- const firstModel = row.selectors.map(selectorRowToRaw).find((entry) => entry !== "");
3020
- const slotExpanded = !row.collapsed || !writable;
3021
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3022
- className: `${FallbacksCard_module_css_default.editorCard} ${draggedSlotIndex === index ? FallbacksCard_module_css_default.slotCardDragging : ""} ${overSlotIndex === index && draggedSlotIndex !== null && draggedSlotIndex !== index ? FallbacksCard_module_css_default.slotCardOver : ""}`,
3023
- onDragOver: (event) => {
3024
- if (draggedSlotIndex === null) return;
3025
- event.preventDefault();
3026
- if (overSlotIndex !== index) setOverSlotIndex(index);
3027
- },
3028
- onDrop: (event) => {
3029
- event.preventDefault();
3030
- const from = draggedSlotIndex;
3031
- setDraggedSlotIndex(null);
3032
- setOverSlotIndex(null);
3033
- if (from !== null && from !== index) reorderTimeSlotRow(from, index);
3034
- },
3010
+ }), slotExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
3011
+ row.kind === "preset" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
3012
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3013
+ className: FallbacksCard_module_css_default.ruleGrid,
3035
3014
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3036
- className: FallbacksCard_module_css_default.collapseRow,
3037
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3038
- type: "button",
3039
- className: FallbacksCard_module_css_default.collapseToggle,
3040
- "aria-expanded": slotExpanded,
3041
- "aria-label": t(slotExpanded ? "timeSlots.collapse" : "timeSlots.expand"),
3042
- disabled: !writable,
3043
- onClick: () => {
3044
- updateTimeSlotRow(index, { collapsed: !row.collapsed });
3045
- },
3046
- children: [
3047
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineMedium, { className: slotExpanded ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron }),
3048
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3049
- className: FallbacksCard_module_css_default.collapseTitle,
3050
- children: row.kind === "preset" ? t(`timeSlots.preset.${row.preset}.label`) : row.name !== "" ? row.name : `custom ${row.start}-${row.end}`
3051
- }),
3052
- row.kind === "preset" && (row.preset === "liang-peak" || row.preset === "glm-peak") && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3053
- className: `${FallbacksCard_module_css_default.slotTag} ${FallbacksCard_module_css_default.slotTagHighCost}`,
3054
- children: t("timeSlots.preset.highCost")
3055
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3056
- className: `${FallbacksCard_module_css_default.slotTag} ${FallbacksCard_module_css_default.slotTagMultiplier}`,
3057
- children: t("timeSlots.preset.multiplier", { n: row.preset === "liang-peak" ? "2" : "3" })
3058
- })] }),
3059
- activeSlotIndex === index && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3060
- className: `${FallbacksCard_module_css_default.slotTag} ${FallbacksCard_module_css_default.slotTagActive}`,
3061
- children: t("timeSlots.active")
3062
- }),
3063
- firstModel !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3064
- className: FallbacksCard_module_css_default.collapseMeta,
3065
- children: firstModel
3066
- })
3067
- ]
3068
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3069
- type: "button",
3070
- className: FallbacksCard_module_css_default.dragHandle,
3071
- draggable: writable,
3072
- "data-tip": t("timeSlots.drag"),
3073
- "aria-label": t("timeSlots.drag"),
3074
- disabled: !writable,
3075
- onDragStart: () => {
3076
- if (!writable) return;
3077
- setDraggedSlotIndex(index);
3078
- setOverSlotIndex(index);
3079
- },
3080
- onDragEnd: () => {
3081
- setDraggedSlotIndex(null);
3082
- setOverSlotIndex(null);
3083
- },
3084
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconEllipsisOutlineMedium, { className: FallbacksCard_module_css_default.dragHandleIcon })
3015
+ className: FallbacksCard_module_css_default.ruleCell,
3016
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3017
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3018
+ children: t("timeSlots.preset.name")
3019
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3020
+ className: FallbacksCard_module_css_default.slotPresetName,
3021
+ children: t(`timeSlots.preset.${row.preset}.label`)
3085
3022
  })]
3086
- }), slotExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
3087
- row.kind === "preset" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
3088
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3089
- className: FallbacksCard_module_css_default.ruleGrid,
3090
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3091
- className: FallbacksCard_module_css_default.ruleCell,
3092
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3093
- className: FallbacksCard_module_css_default.ruleCellLabel,
3094
- children: t("timeSlots.preset.name")
3095
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3096
- className: FallbacksCard_module_css_default.slotPresetName,
3097
- children: t(`timeSlots.preset.${row.preset}.label`)
3098
- })]
3099
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3100
- className: FallbacksCard_module_css_default.ruleCell,
3101
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3102
- className: FallbacksCard_module_css_default.ruleCellLabel,
3103
- children: t("timeSlots.preset.windowLabel")
3104
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3105
- className: FallbacksCard_module_css_default.hint,
3106
- children: t(`timeSlots.preset.${row.preset}.window`)
3107
- })]
3108
- })]
3109
- }),
3110
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3111
- className: FallbacksCard_module_css_default.hint,
3112
- children: t("timeSlots.preset.chainsOnly")
3113
- }),
3114
- (row.preset === "glm-peak" || row.preset === "glm-valley") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3115
- className: FallbacksCard_module_css_default.hint,
3116
- children: t("timeSlots.preset.glm.note")
3117
- })
3118
- ] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
3119
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3120
- className: FallbacksCard_module_css_default.field,
3121
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3122
- className: FallbacksCard_module_css_default.ruleCellLabel,
3123
- children: t("timeSlots.name")
3124
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3125
- className: FallbacksCard_module_css_default.input,
3126
- value: row.name,
3127
- placeholder: t("timeSlots.name"),
3128
- "aria-label": t("timeSlots.name"),
3129
- disabled: !writable,
3130
- onChange: (event) => {
3131
- updateTimeSlotRow(index, { name: event.target.value });
3132
- }
3133
- })]
3134
- }),
3135
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3136
- className: FallbacksCard_module_css_default.field,
3137
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3138
- className: FallbacksCard_module_css_default.ruleCellLabel,
3139
- children: t("timeSlots.tz.label")
3140
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3141
- className: FallbacksCard_module_css_default.hint,
3142
- "aria-label": t("timeSlots.tz.label"),
3143
- children: tzDisplayLabel(presetsPresent ? "Asia/Shanghai" : hostTimeZone())
3144
- })]
3145
- }),
3146
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3147
- className: FallbacksCard_module_css_default.ruleGrid,
3148
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3149
- className: FallbacksCard_module_css_default.ruleCell,
3150
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3151
- className: FallbacksCard_module_css_default.ruleCellLabel,
3152
- children: t("timeSlots.start")
3153
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3154
- className: `${FallbacksCard_module_css_default.input} ${invalidWindow ? FallbacksCard_module_css_default.inputInvalid : ""}`,
3155
- value: row.start,
3156
- placeholder: "09:00",
3157
- "aria-label": t("timeSlots.start"),
3158
- disabled: !writable,
3159
- onChange: (event) => {
3160
- updateTimeSlotRow(index, { start: event.target.value });
3161
- }
3162
- })]
3163
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3164
- className: FallbacksCard_module_css_default.ruleCell,
3165
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3166
- className: FallbacksCard_module_css_default.ruleCellLabel,
3167
- children: t("timeSlots.end")
3168
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3169
- className: `${FallbacksCard_module_css_default.input} ${invalidWindow ? FallbacksCard_module_css_default.inputInvalid : ""}`,
3170
- value: row.end,
3171
- placeholder: "18:00",
3172
- "aria-label": t("timeSlots.end"),
3173
- disabled: !writable,
3174
- onChange: (event) => {
3175
- updateTimeSlotRow(index, { end: event.target.value });
3176
- }
3177
- })]
3178
- })]
3179
- }),
3180
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3181
- className: FallbacksCard_module_css_default.field,
3182
- children: [
3183
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3184
- className: FallbacksCard_module_css_default.ruleCellLabel,
3185
- children: t("timeSlots.days")
3186
- }),
3187
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3188
- className: FallbacksCard_module_css_default.dayRow,
3189
- children: SLOT_WEEKDAYS.map((day, dayIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3190
- className: FallbacksCard_module_css_default.dayCell,
3191
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3192
- type: "checkbox",
3193
- checked: row.days.includes(dayIndex),
3194
- disabled: !writable,
3195
- onChange: () => {
3196
- updateTimeSlotRow(index, { days: row.days.includes(dayIndex) ? row.days.filter((existing) => existing !== dayIndex) : [...row.days, dayIndex] });
3197
- }
3198
- }), t(`timeSlots.day.${day}`)]
3199
- }, day))
3200
- }),
3201
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3202
- className: FallbacksCard_module_css_default.hint,
3203
- children: t("timeSlots.days.hint")
3204
- })
3205
- ]
3206
- }),
3207
- (row.start !== "" || row.end !== "") && !(HHMM_RE.test(row.start) && HHMM_RE.test(row.end)) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3208
- className: FallbacksCard_module_css_default.hint,
3209
- children: t("validation.slotWindow")
3210
- })
3211
- ] }),
3212
- chainEmpty && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3023
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3024
+ className: FallbacksCard_module_css_default.ruleCell,
3025
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3026
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3027
+ children: t("timeSlots.preset.windowLabel")
3028
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3213
3029
  className: FallbacksCard_module_css_default.hint,
3214
- children: t("validation.slotChainRequired")
3215
- }),
3216
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3217
- className: FallbacksCard_module_css_default.chainSelectors,
3218
- children: row.selectors.map((selector, selectorIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
3219
- selector,
3220
- catalog: catalogOf(state),
3221
- configuredProviders: state.configuredProviders,
3222
- disabled: !writable,
3223
- t,
3224
- onChange: (patch) => {
3225
- updateTimeSlotSelector(index, selectorIndex, patch);
3226
- },
3227
- onRemove: () => {
3228
- removeTimeSlotSelector(index, selectorIndex);
3229
- }
3230
- }, selectorIndex))
3231
- }),
3232
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
3233
- variant: "outline",
3234
- size: "sm",
3235
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineMedium, { size: 14 }),
3236
- className: FallbacksCard_module_css_default.addButton,
3237
- onClick: () => {
3238
- addTimeSlotSelector(index);
3239
- },
3240
- children: t("timeSlots.selector.add")
3241
- }),
3242
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3243
- className: FallbacksCard_module_css_default.cardFoot,
3244
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3245
- className: FallbacksCard_module_css_default.rowActions,
3246
- children: [
3247
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3248
- type: "button",
3249
- className: FallbacksCard_module_css_default.iconButton,
3250
- "data-tip": t("timeSlots.moveUp"),
3251
- "aria-label": t("timeSlots.moveUp"),
3252
- disabled: !writable || index === 0,
3253
- onClick: () => {
3254
- moveTimeSlotRow(index, -1);
3255
- },
3256
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronUpOutlineMedium, {})
3257
- }),
3258
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3259
- type: "button",
3260
- className: FallbacksCard_module_css_default.iconButton,
3261
- "data-tip": t("timeSlots.moveDown"),
3262
- "aria-label": t("timeSlots.moveDown"),
3263
- disabled: !writable || index === timeSlotRows.length - 1,
3264
- onClick: () => {
3265
- moveTimeSlotRow(index, 1);
3266
- },
3267
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineMedium, {})
3268
- }),
3269
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3270
- type: "button",
3271
- className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger}`,
3272
- "data-tip": t("timeSlots.remove"),
3273
- "aria-label": t("timeSlots.remove"),
3274
- onClick: () => {
3275
- removeTimeSlotRow(index);
3276
- },
3277
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineMedium, {})
3278
- })
3279
- ]
3280
- })
3281
- })
3282
- ] })]
3283
- }, index);
3284
- })
3285
- }),
3286
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3287
- className: FallbacksCard_module_css_default.slotAddRow,
3288
- children: [
3289
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3290
- className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
3291
- value: presetToAdd,
3292
- "aria-label": t("timeSlots.presetPlaceholder"),
3293
- disabled: !writable,
3294
- onChange: (event) => {
3295
- setPresetToAdd(event.target.value);
3296
- },
3297
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3298
- value: "",
3299
- children: t("timeSlots.presetPlaceholder")
3300
- }), SLOT_PRESET_IDS.filter((id) => !timeSlotRows.some((row) => row.kind === "preset" && row.preset === id)).map((id) => {
3301
- const glmUnconfigured = !glmConfigured && (id === "glm-peak" || id === "glm-valley");
3302
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
3303
- value: id,
3304
- disabled: glmUnconfigured,
3305
- children: [t(`timeSlots.preset.${id}.label`), glmUnconfigured ? t("timeSlots.preset.glm.unconfigured") : null]
3306
- }, id);
3030
+ children: t(`timeSlots.preset.${row.preset}.window`)
3031
+ })]
3307
3032
  })]
3308
3033
  }),
3309
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
3310
- variant: "outline",
3311
- size: "sm",
3312
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineMedium, { size: 14 }),
3313
- disabled: !writable || presetToAdd === "",
3314
- onClick: addPresetSlotRow,
3315
- children: t("timeSlots.addPreset")
3034
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3035
+ className: FallbacksCard_module_css_default.hint,
3036
+ children: t("timeSlots.preset.chainsOnly")
3316
3037
  }),
3317
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
3318
- variant: "outline",
3319
- size: "sm",
3320
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineMedium, { size: 14 }),
3321
- disabled: !writable,
3322
- onClick: addCustomSlotRow,
3323
- children: t("timeSlots.addCustom")
3038
+ (row.preset === "glm-peak" || row.preset === "glm-valley") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3039
+ className: FallbacksCard_module_css_default.hint,
3040
+ children: t("timeSlots.preset.glm.note")
3324
3041
  })
3325
- ]
3326
- })
3327
- ]
3328
- }),
3329
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3330
- className: FallbacksCard_module_css_default.field,
3331
- role: "group",
3332
- "aria-labelledby": "fallbacks-root-chain",
3333
- children: [
3334
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3335
- className: FallbacksCard_module_css_default.fieldLabel,
3336
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3337
- id: "fallbacks-root-chain",
3338
- children: t("rootChain.label")
3339
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3340
- label: t("rootChain.tooltip"),
3341
- disabled: !writable
3342
- })]
3343
- }),
3344
- state.catalogStatus === "error" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3345
- className: FallbacksCard_module_css_default.hint,
3346
- children: t("catalog.error", { message: state.catalogError })
3347
- }),
3348
- state.catalogStatus === "ready" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3349
- className: FallbacksCard_module_css_default.hint,
3350
- children: t("catalog.partial", { message: state.catalogError })
3351
- }),
3352
- state.catalogStatus === "ready" && (state.groups.length === 0 || state.configuredProviders.length === 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3353
- className: FallbacksCard_module_css_default.hint,
3354
- children: t("catalog.empty")
3355
- }),
3356
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3357
- className: FallbacksCard_module_css_default.list,
3358
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3359
- className: FallbacksCard_module_css_default.editorCard,
3360
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3361
- className: FallbacksCard_module_css_default.chainSelectors,
3362
- children: allDayChainRow.selectors.map((selector, selectorIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
3363
- selector,
3364
- catalog: catalogOf(state),
3365
- configuredProviders: state.configuredProviders,
3042
+ ] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
3043
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3044
+ className: FallbacksCard_module_css_default.field,
3045
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3046
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3047
+ children: t("timeSlots.name")
3048
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3049
+ className: FallbacksCard_module_css_default.input,
3050
+ value: row.name,
3051
+ placeholder: t("timeSlots.name"),
3052
+ "aria-label": t("timeSlots.name"),
3366
3053
  disabled: !writable,
3367
- t,
3368
- onChange: (patch) => {
3369
- updateAllDayChainSelector(selectorIndex, patch);
3370
- },
3371
- onRemove: () => {
3372
- removeAllDayChainSelector(selectorIndex);
3054
+ onChange: (event) => {
3055
+ updateTimeSlotRow(index, { name: event.target.value });
3373
3056
  }
3374
- }, selectorIndex))
3375
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
3376
- variant: "outline",
3377
- size: "sm",
3378
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineMedium, { size: 14 }),
3379
- className: FallbacksCard_module_css_default.addButton,
3380
- onClick: addAllDayChainSelector,
3381
- children: t("timeSlots.selector.add")
3382
- })]
3383
- })
3384
- })
3385
- ]
3386
- }),
3387
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3388
- className: FallbacksCard_module_css_default.field,
3389
- role: "group",
3390
- "aria-labelledby": "fallbacks-default-model",
3391
- children: [
3392
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3393
- className: FallbacksCard_module_css_default.fieldLabel,
3394
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3395
- id: "fallbacks-default-model",
3396
- children: t("defaultModel.label")
3397
- })
3398
- }),
3399
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3400
- className: FallbacksCard_module_css_default.hint,
3401
- children: t("allDay.hint")
3402
- }),
3403
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3404
- className: FallbacksCard_module_css_default.list,
3405
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3406
- className: FallbacksCard_module_css_default.editorCard,
3407
- children: [OFFICIAL_ALL_DAY_IDS.map((id, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3408
- className: FallbacksCard_module_css_default.optionRow,
3409
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3410
- type: "radio",
3411
- name: "fallbacks-all-day",
3412
- checked: allDayModel === id,
3413
- disabled: !writable,
3414
- onChange: () => {
3415
- setAllDayModel(id);
3416
- }
3417
- }), t(ALL_DAY_LABEL_KEYS[index])]
3418
- }, id)), allDayModel === "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3419
- className: FallbacksCard_module_css_default.hint,
3420
- children: t("allDay.nonconforming")
3421
- })]
3422
- })
3423
- })
3424
- ]
3425
- }),
3426
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3427
- className: FallbacksCard_module_css_default.sectionHeading,
3428
- id: "fallbacks-subagents",
3429
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3430
- className: FallbacksCard_module_css_default.sectionHeadingText,
3431
- children: t("subagents.label")
3432
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3433
- className: FallbacksCard_module_css_default.sectionActions,
3434
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3435
- type: "button",
3436
- className: `${FallbacksCard_module_css_default.secondaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
3437
- disabled: !subDirty || saving,
3438
- onClick: () => {
3439
- discardSection("sub");
3440
- },
3441
- children: t("discard")
3442
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3443
- type: "button",
3444
- className: `${FallbacksCard_module_css_default.primaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
3445
- disabled: !writable || saving || !subDirty,
3446
- onClick: () => {
3447
- save("sub");
3448
- },
3449
- children: saving ? t("save.saving") : t("save")
3450
- })]
3451
- })]
3452
- }),
3453
- validationErrors.sub.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3454
- className: FallbacksCard_module_css_default.error,
3455
- role: "alert",
3456
- children: `${t("validation.blocked")}${validationErrors.sub.join("; ")}`
3457
- }),
3458
- lastSaveSection === "sub" && state.status === "error" && state.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3459
- className: FallbacksCard_module_css_default.error,
3460
- role: "alert",
3461
- children: t("error.generic", { message: state.error })
3462
- }),
3463
- state.subagentPolicy?.state === "enabled" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3464
- className: FallbacksCard_module_css_default.policyStatus,
3465
- role: "status",
3466
- children: [
3467
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3468
- className: FallbacksCard_module_css_default.policyStatusLabel,
3469
- children: t("subagents.policy.label")
3470
- }),
3471
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3472
- className: FallbacksCard_module_css_default.policyStatusLine,
3473
- children: `${t("subagents.policy.allowlist")}: ${state.subagentPolicy.allowedModels.map((route) => `${route.provider}/${route.model}`).join(", ")}`
3474
- }),
3475
- state.subagentPolicy.head !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3476
- className: FallbacksCard_module_css_default.policyStatusLine,
3477
- children: `${t("subagents.policy.head")}: ${state.subagentPolicy.head.route.provider}/${state.subagentPolicy.head.route.model} (${t(state.subagentPolicy.head.source === "authorized" ? "subagents.policy.source.authorized" : "subagents.policy.source.injected")})`
3478
- }),
3479
- state.subagentPolicy.blockedAttempt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3480
- className: FallbacksCard_module_css_default.policyStatusWarn,
3481
- role: "alert",
3482
- children: t("subagents.policy.blocked")
3483
- })
3484
- ]
3485
- }),
3486
- state.subagentPolicy?.state === "unprovable" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3487
- className: FallbacksCard_module_css_default.policyStatus,
3488
- role: "status",
3489
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3490
- className: FallbacksCard_module_css_default.policyStatusWarn,
3491
- role: "alert",
3492
- children: t("subagents.policy.unprovable")
3493
- })
3494
- }),
3495
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3496
- className: FallbacksCard_module_css_default.field,
3497
- role: "group",
3498
- "aria-labelledby": "fallbacks-roles-list",
3499
- children: [
3500
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3501
- className: FallbacksCard_module_css_default.fieldLabel,
3502
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3503
- id: "fallbacks-roles-list",
3504
- children: t("roles.list.label")
3505
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3506
- label: t("roles.list.tooltip"),
3507
- disabled: !writable
3508
- })]
3509
- }),
3510
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3511
- className: FallbacksCard_module_css_default.hint,
3512
- children: t("roles.list.hint")
3513
- }),
3514
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3515
- className: FallbacksCard_module_css_default.list,
3516
- children: roleRows.map((row, index) => {
3517
- const invalid = invalidRoleIds?.has(row.id.trim()) ?? false;
3518
- const seed = seedInfo.get(row.id.trim());
3519
- const seedBadge = seedBadgeLabel(seed, t);
3520
- const personaBlank = row.persona.trim() === "";
3521
- const roleSummary = row.selectors.map(selectorRowToRaw).find((entry) => entry !== "") ?? row.fallback;
3522
- const roleExpanded = !row.collapsed || !writable;
3523
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3524
- className: FallbacksCard_module_css_default.editorCard,
3525
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3526
- className: FallbacksCard_module_css_default.collapseRow,
3527
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3528
- type: "button",
3529
- className: FallbacksCard_module_css_default.collapseToggle,
3530
- "aria-expanded": roleExpanded,
3531
- "aria-label": t(roleExpanded ? "roles.collapse" : "roles.expand"),
3057
+ })]
3058
+ }),
3059
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3060
+ className: FallbacksCard_module_css_default.field,
3061
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3062
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3063
+ children: t("timeSlots.tz.label")
3064
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3065
+ className: FallbacksCard_module_css_default.hint,
3066
+ "aria-label": t("timeSlots.tz.label"),
3067
+ children: tzDisplayLabel(presetsPresent ? "Asia/Shanghai" : hostTimeZone())
3068
+ })]
3069
+ }),
3070
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3071
+ className: FallbacksCard_module_css_default.ruleGrid,
3072
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3073
+ className: FallbacksCard_module_css_default.ruleCell,
3074
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3075
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3076
+ children: t("timeSlots.start")
3077
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3078
+ className: `${FallbacksCard_module_css_default.input} ${invalidWindow ? FallbacksCard_module_css_default.inputInvalid : ""}`,
3079
+ value: row.start,
3080
+ placeholder: "09:00",
3081
+ "aria-label": t("timeSlots.start"),
3532
3082
  disabled: !writable,
3533
- onClick: () => {
3534
- updateRoleRow(index, { collapsed: !row.collapsed });
3535
- },
3536
- children: [
3537
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineMedium, { className: roleExpanded ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron }),
3538
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3539
- className: FallbacksCard_module_css_default.collapseTitle,
3540
- children: row.id
3541
- }),
3542
- seedBadge !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3543
- className: FallbacksCard_module_css_default.seedBadge,
3544
- title: seedBadge,
3545
- children: seedBadge
3546
- }),
3547
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3548
- className: FallbacksCard_module_css_default.collapseMeta,
3549
- children: roleSummary
3550
- })
3551
- ]
3552
- })
3553
- }), roleExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
3554
- seed === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3555
- className: FallbacksCard_module_css_default.ruleGrid,
3556
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3557
- className: FallbacksCard_module_css_default.ruleCell,
3558
- children: [
3559
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3560
- className: FallbacksCard_module_css_default.ruleCellLabel,
3561
- children: t("roles.id")
3562
- }),
3563
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3564
- className: `${FallbacksCard_module_css_default.input} ${invalid ? FallbacksCard_module_css_default.inputInvalid : ""}`,
3565
- value: row.id,
3566
- placeholder: t("roles.idPlaceholder"),
3567
- "aria-label": t("roles.id"),
3568
- "aria-invalid": invalid ? true : void 0,
3569
- disabled: !writable,
3570
- onChange: (event) => {
3571
- updateRoleRow(index, { id: event.target.value });
3572
- }
3573
- }),
3574
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3575
- className: FallbacksCard_module_css_default.hint,
3576
- children: t("roles.id.hint")
3577
- })
3578
- ]
3579
- })
3083
+ onChange: (event) => {
3084
+ updateTimeSlotRow(index, { start: event.target.value });
3085
+ }
3086
+ })]
3087
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3088
+ className: FallbacksCard_module_css_default.ruleCell,
3089
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3090
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3091
+ children: t("timeSlots.end")
3092
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3093
+ className: `${FallbacksCard_module_css_default.input} ${invalidWindow ? FallbacksCard_module_css_default.inputInvalid : ""}`,
3094
+ value: row.end,
3095
+ placeholder: "18:00",
3096
+ "aria-label": t("timeSlots.end"),
3097
+ disabled: !writable,
3098
+ onChange: (event) => {
3099
+ updateTimeSlotRow(index, { end: event.target.value });
3100
+ }
3101
+ })]
3102
+ })]
3103
+ }),
3104
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3105
+ className: FallbacksCard_module_css_default.field,
3106
+ children: [
3107
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3108
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3109
+ children: t("timeSlots.days")
3580
3110
  }),
3581
3111
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3582
- className: FallbacksCard_module_css_default.ruleGrid,
3583
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3584
- className: FallbacksCard_module_css_default.ruleCell,
3585
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3586
- className: FallbacksCard_module_css_default.ruleCellLabel,
3587
- children: t("roles.persona")
3588
- }), seed === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
3589
- rows: 3,
3590
- className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.inputTextarea}`,
3591
- value: row.persona,
3592
- placeholder: t("roles.personaPlaceholder"),
3593
- "aria-label": t("roles.persona"),
3112
+ className: FallbacksCard_module_css_default.dayRow,
3113
+ children: SLOT_WEEKDAYS.map((day, dayIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3114
+ className: FallbacksCard_module_css_default.dayCell,
3115
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3116
+ type: "checkbox",
3117
+ checked: row.days.includes(dayIndex),
3594
3118
  disabled: !writable,
3595
- onChange: (event) => {
3596
- updateRoleRow(index, { persona: event.target.value });
3119
+ onChange: () => {
3120
+ updateTimeSlotRow(index, { days: row.days.includes(dayIndex) ? row.days.filter((existing) => existing !== dayIndex) : [...row.days, dayIndex] });
3597
3121
  }
3598
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3599
- className: FallbacksCard_module_css_default.personaBriefRow,
3600
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3601
- className: personaBlank ? `${FallbacksCard_module_css_default.personaBrief} ${FallbacksCard_module_css_default.personaBriefEmpty}` : FallbacksCard_module_css_default.personaBrief,
3602
- children: personaBlank ? t("roles.persona.empty") : row.persona
3603
- }), !personaBlank && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3604
- role: "button",
3605
- tabIndex: 0,
3606
- className: FallbacksCard_module_css_default.iconButton,
3607
- "aria-expanded": row.personaOpen,
3608
- "aria-label": t(row.personaOpen ? "roles.persona.collapse" : "roles.persona.expand"),
3609
- "data-tip": t(row.personaOpen ? "roles.persona.collapse" : "roles.persona.expand"),
3610
- onClick: () => {
3611
- updateRoleRow(index, { personaOpen: !row.personaOpen });
3612
- },
3613
- onKeyDown: (event) => {
3614
- if (event.key === "Enter" || event.key === " ") {
3615
- event.preventDefault();
3616
- updateRoleRow(index, { personaOpen: !row.personaOpen });
3617
- }
3618
- },
3619
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineMedium, { className: row.personaOpen ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron })
3620
- })]
3621
- }), row.personaOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3622
- className: FallbacksCard_module_css_default.personaFull,
3623
- children: row.persona
3624
- })] })]
3625
- })
3626
- }),
3627
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3628
- className: FallbacksCard_module_css_default.chainSelectors,
3629
- children: [row.selectors.map((selector, selectorIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
3630
- selector,
3631
- catalog: catalogOf(state),
3632
- configuredProviders: state.configuredProviders,
3633
- disabled: !writable,
3634
- t,
3635
- onChange: (patch) => {
3636
- updateRoleSelector(index, selectorIndex, patch);
3637
- },
3638
- onRemove: () => {
3639
- removeRoleSelector(index, selectorIndex);
3640
- }
3641
- }, selectorIndex)), row.selectors.every((selector) => selectorRowToRaw(selector) === "") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3642
- className: FallbacksCard_module_css_default.hint,
3643
- children: seed !== void 0 ? t("roles.seedChainOptional", { id: row.id }) : t("validation.roleChainRequired", { id: row.id })
3644
- })]
3122
+ }), t(`timeSlots.day.${day}`)]
3123
+ }, day))
3645
3124
  }),
3646
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3647
- className: FallbacksCard_module_css_default.ruleGrid,
3648
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3649
- className: FallbacksCard_module_css_default.ruleCell,
3650
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3651
- className: FallbacksCard_module_css_default.ruleCellLabel,
3652
- children: t("roles.fallback")
3653
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3654
- className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
3655
- value: row.fallback,
3656
- "aria-label": t("roles.fallback"),
3657
- disabled: !writable,
3658
- onChange: (event) => {
3659
- updateRoleRow(index, { fallback: event.target.value });
3660
- },
3661
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3662
- value: "inherit-root",
3663
- children: t("roles.fallback.inherit-root")
3664
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3665
- value: "none",
3666
- children: t("roles.fallback.none")
3667
- })]
3668
- })]
3669
- })
3125
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3126
+ className: FallbacksCard_module_css_default.hint,
3127
+ children: t("timeSlots.days.hint")
3128
+ })
3129
+ ]
3130
+ }),
3131
+ (row.start !== "" || row.end !== "") && !(HHMM_RE.test(row.start) && HHMM_RE.test(row.end)) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3132
+ className: FallbacksCard_module_css_default.hint,
3133
+ children: t("validation.slotWindow")
3134
+ })
3135
+ ] }),
3136
+ chainEmpty && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3137
+ className: FallbacksCard_module_css_default.hint,
3138
+ children: t("validation.slotChainRequired")
3139
+ }),
3140
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3141
+ className: FallbacksCard_module_css_default.chainSelectors,
3142
+ children: row.selectors.map((selector, selectorIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
3143
+ selector,
3144
+ catalog: catalogOf(state),
3145
+ configuredProviders: state.configuredProviders,
3146
+ disabled: !writable,
3147
+ t,
3148
+ onChange: (patch) => {
3149
+ updateTimeSlotSelector(index, selectorIndex, patch);
3150
+ },
3151
+ onRemove: () => {
3152
+ removeTimeSlotSelector(index, selectorIndex);
3153
+ }
3154
+ }, selectorIndex))
3155
+ }),
3156
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3157
+ type: "button",
3158
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3159
+ disabled: !writable,
3160
+ onClick: () => {
3161
+ addTimeSlotSelector(index);
3162
+ },
3163
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("timeSlots.selector.add")]
3164
+ }),
3165
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3166
+ className: FallbacksCard_module_css_default.cardFoot,
3167
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3168
+ className: FallbacksCard_module_css_default.rowActions,
3169
+ children: [
3170
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3171
+ type: "button",
3172
+ className: FallbacksCard_module_css_default.iconButton,
3173
+ "data-tip": t("timeSlots.moveUp"),
3174
+ "aria-label": t("timeSlots.moveUp"),
3175
+ disabled: !writable || index === 0,
3176
+ onClick: () => {
3177
+ moveTimeSlotRow(index, -1);
3178
+ },
3179
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDownIcon, { className: FallbacksCard_module_css_default.chevronFlip })
3670
3180
  }),
3671
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
3672
- variant: "outline",
3673
- size: "sm",
3674
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineMedium, { size: 14 }),
3675
- className: FallbacksCard_module_css_default.addButton,
3181
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3182
+ type: "button",
3183
+ className: FallbacksCard_module_css_default.iconButton,
3184
+ "data-tip": t("timeSlots.moveDown"),
3185
+ "aria-label": t("timeSlots.moveDown"),
3186
+ disabled: !writable || index === timeSlotRows.length - 1,
3676
3187
  onClick: () => {
3677
- addRoleSelector(index);
3188
+ moveTimeSlotRow(index, 1);
3678
3189
  },
3679
- children: t("roles.selector.add")
3190
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDownIcon, {})
3680
3191
  }),
3681
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3682
- className: FallbacksCard_module_css_default.cardFoot,
3683
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3684
- type: "button",
3685
- className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger}`,
3686
- "data-tip": t("roles.remove"),
3687
- "aria-label": t("roles.remove"),
3688
- onClick: () => {
3689
- removeRole(index);
3690
- },
3691
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineMedium, {})
3692
- })
3192
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3193
+ type: "button",
3194
+ className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger}`,
3195
+ "data-tip": t("timeSlots.remove"),
3196
+ "aria-label": t("timeSlots.remove"),
3197
+ onClick: () => {
3198
+ removeTimeSlotRow(index);
3199
+ },
3200
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrashIcon, {})
3693
3201
  })
3694
- ] })]
3695
- }, index);
3202
+ ]
3203
+ })
3696
3204
  })
3697
- }),
3698
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
3699
- variant: "outline",
3700
- size: "sm",
3701
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineMedium, { size: 14 }),
3702
- className: FallbacksCard_module_css_default.addButton,
3703
- onClick: addRole,
3704
- children: t("roles.add")
3705
- })
3706
- ]
3707
- }),
3708
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3709
- className: FallbacksCard_module_css_default.field,
3710
- role: "group",
3711
- "aria-labelledby": "fallbacks-roles-rules",
3712
- children: [
3713
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3714
- className: FallbacksCard_module_css_default.fieldLabel,
3715
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3716
- id: "fallbacks-roles-rules",
3717
- children: t("roles.rules")
3718
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3719
- label: t("roles.rules.tooltip"),
3720
- disabled: !writable
3721
- })]
3722
- }),
3723
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3724
- className: FallbacksCard_module_css_default.hint,
3725
- children: t("roles.rules.hint")
3726
- }),
3727
- state.catalogStatus === "error" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3728
- className: FallbacksCard_module_css_default.hint,
3729
- children: t("catalog.error", { message: state.catalogError })
3730
- }),
3731
- state.catalogStatus === "ready" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3732
- className: FallbacksCard_module_css_default.hint,
3733
- children: t("catalog.partial", { message: state.catalogError })
3734
- }),
3735
- state.catalogStatus === "ready" && (state.groups.length === 0 || state.configuredProviders.length === 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3736
- className: FallbacksCard_module_css_default.hint,
3737
- children: t("catalog.empty")
3738
- }),
3739
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3740
- className: FallbacksCard_module_css_default.list,
3741
- children: ruleRows.map((row, index) => {
3742
- const catalog = catalogOf(state);
3743
- const providerRaw = selectionToRaw(row.provider);
3744
- const group = catalog?.groups.find((entry) => entry.id === providerRaw);
3745
- const providerOutside = row.provider?.kind === "outside";
3746
- const providerUnconfigured = !providerOutside && providerRaw !== "" && (catalog?.providers.some((entry) => entry.provider === providerRaw) ?? false) && !state.configuredProviders.some((entry) => entry.provider === providerRaw);
3747
- const modelOutside = row.model?.kind === "outside";
3748
- const roleOutside = row.role !== "" && !roleOptions.includes(row.role);
3749
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3750
- className: FallbacksCard_module_css_default.editorCard,
3205
+ ] })]
3206
+ }, index);
3207
+ })
3208
+ }),
3209
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3210
+ className: FallbacksCard_module_css_default.slotAddRow,
3211
+ children: [
3212
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3213
+ className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
3214
+ value: presetToAdd,
3215
+ "aria-label": t("timeSlots.presetPlaceholder"),
3216
+ disabled: !writable,
3217
+ onChange: (event) => {
3218
+ setPresetToAdd(event.target.value);
3219
+ },
3220
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3221
+ value: "",
3222
+ children: t("timeSlots.presetPlaceholder")
3223
+ }), SLOT_PRESET_IDS.filter((id) => !timeSlotRows.some((row) => row.kind === "preset" && row.preset === id)).map((id) => {
3224
+ const glmUnconfigured = !glmConfigured && (id === "glm-peak" || id === "glm-valley");
3225
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
3226
+ value: id,
3227
+ disabled: glmUnconfigured,
3228
+ children: [t(`timeSlots.preset.${id}.label`), glmUnconfigured ? t("timeSlots.preset.glm.unconfigured") : null]
3229
+ }, id);
3230
+ })]
3231
+ }),
3232
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3233
+ type: "button",
3234
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3235
+ disabled: !writable || presetToAdd === "",
3236
+ onClick: addPresetSlotRow,
3237
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("timeSlots.addPreset")]
3238
+ }),
3239
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3240
+ type: "button",
3241
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3242
+ disabled: !writable,
3243
+ onClick: addCustomSlotRow,
3244
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("timeSlots.addCustom")]
3245
+ })
3246
+ ]
3247
+ })
3248
+ ]
3249
+ }),
3250
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3251
+ className: FallbacksCard_module_css_default.field,
3252
+ role: "group",
3253
+ "aria-labelledby": "fallbacks-root-chain",
3254
+ children: [
3255
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3256
+ className: FallbacksCard_module_css_default.fieldLabel,
3257
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3258
+ id: "fallbacks-root-chain",
3259
+ children: t("rootChain.label")
3260
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3261
+ label: t("rootChain.tooltip"),
3262
+ disabled: !writable
3263
+ })]
3264
+ }),
3265
+ state.catalogStatus === "error" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3266
+ className: FallbacksCard_module_css_default.hint,
3267
+ children: t("catalog.error", { message: state.catalogError })
3268
+ }),
3269
+ state.catalogStatus === "ready" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3270
+ className: FallbacksCard_module_css_default.hint,
3271
+ children: t("catalog.partial", { message: state.catalogError })
3272
+ }),
3273
+ state.catalogStatus === "ready" && (state.groups.length === 0 || state.configuredProviders.length === 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3274
+ className: FallbacksCard_module_css_default.hint,
3275
+ children: t("catalog.empty")
3276
+ }),
3277
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3278
+ className: FallbacksCard_module_css_default.list,
3279
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3280
+ className: FallbacksCard_module_css_default.editorCard,
3281
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3282
+ className: FallbacksCard_module_css_default.chainSelectors,
3283
+ children: allDayChainRow.selectors.map((selector, selectorIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
3284
+ selector,
3285
+ catalog: catalogOf(state),
3286
+ configuredProviders: state.configuredProviders,
3287
+ disabled: !writable,
3288
+ t,
3289
+ onChange: (patch) => {
3290
+ updateAllDayChainSelector(selectorIndex, patch);
3291
+ },
3292
+ onRemove: () => {
3293
+ removeAllDayChainSelector(selectorIndex);
3294
+ }
3295
+ }, selectorIndex))
3296
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3297
+ type: "button",
3298
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3299
+ disabled: !writable,
3300
+ onClick: addAllDayChainSelector,
3301
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("timeSlots.selector.add")]
3302
+ })]
3303
+ })
3304
+ })
3305
+ ]
3306
+ }),
3307
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3308
+ className: FallbacksCard_module_css_default.field,
3309
+ role: "group",
3310
+ "aria-labelledby": "fallbacks-default-model",
3311
+ children: [
3312
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3313
+ className: FallbacksCard_module_css_default.fieldLabel,
3314
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3315
+ id: "fallbacks-default-model",
3316
+ children: t("defaultModel.label")
3317
+ })
3318
+ }),
3319
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3320
+ className: FallbacksCard_module_css_default.hint,
3321
+ children: t("allDay.hint")
3322
+ }),
3323
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3324
+ className: FallbacksCard_module_css_default.list,
3325
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3326
+ className: FallbacksCard_module_css_default.editorCard,
3327
+ children: [OFFICIAL_ALL_DAY_IDS.map((id, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3328
+ className: FallbacksCard_module_css_default.optionRow,
3329
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3330
+ type: "radio",
3331
+ name: "fallbacks-all-day",
3332
+ checked: allDayModel === id,
3333
+ disabled: !writable,
3334
+ onChange: () => {
3335
+ setAllDayModel(id);
3336
+ }
3337
+ }), t(ALL_DAY_LABEL_KEYS[index])]
3338
+ }, id)), allDayModel === "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3339
+ className: FallbacksCard_module_css_default.hint,
3340
+ children: t("allDay.nonconforming")
3341
+ })]
3342
+ })
3343
+ })
3344
+ ]
3345
+ }),
3346
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("h2", {
3347
+ className: FallbacksCard_module_css_default.sectionHeading,
3348
+ id: "fallbacks-subagents",
3349
+ "aria-label": t("subagents.label"),
3350
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3351
+ className: FallbacksCard_module_css_default.sectionHeadingText,
3352
+ children: t("subagents.label")
3353
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3354
+ className: FallbacksCard_module_css_default.sectionActions,
3355
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3356
+ type: "button",
3357
+ className: FallbacksCard_module_css_default.discard,
3358
+ disabled: !subDirty || saving,
3359
+ onClick: () => {
3360
+ discardSection("sub");
3361
+ },
3362
+ children: t("discard")
3363
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3364
+ type: "button",
3365
+ className: FallbacksCard_module_css_default.save,
3366
+ disabled: !writable || saving || !subDirty,
3367
+ onClick: () => {
3368
+ saveSection("sub");
3369
+ },
3370
+ children: saving ? t("save.saving") : t("save")
3371
+ })]
3372
+ })]
3373
+ }),
3374
+ liveErrors.sub.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3375
+ className: FallbacksCard_module_css_default.error,
3376
+ role: "alert",
3377
+ children: `${t("validation.blocked")}${liveErrors.sub.join("; ")}`
3378
+ }),
3379
+ lastSaveSection === "sub" && state.status === "error" && state.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3380
+ className: FallbacksCard_module_css_default.error,
3381
+ role: "alert",
3382
+ children: t("error.generic", { message: state.error })
3383
+ }),
3384
+ state.subagentPolicy?.state === "enabled" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3385
+ className: FallbacksCard_module_css_default.policyStatus,
3386
+ role: "status",
3387
+ children: [
3388
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3389
+ className: FallbacksCard_module_css_default.policyStatusLabel,
3390
+ children: t("subagents.policy.label")
3391
+ }),
3392
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3393
+ className: FallbacksCard_module_css_default.policyStatusLine,
3394
+ children: `${t("subagents.policy.allowlist")}: ${state.subagentPolicy.allowedModels.map((route) => `${route.provider}/${route.model}`).join(", ")}`
3395
+ }),
3396
+ state.subagentPolicy.head !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3397
+ className: FallbacksCard_module_css_default.policyStatusLine,
3398
+ children: `${t("subagents.policy.head")}: ${state.subagentPolicy.head.route.provider}/${state.subagentPolicy.head.route.model} (${t(state.subagentPolicy.head.source === "authorized" ? "subagents.policy.source.authorized" : "subagents.policy.source.injected")})`
3399
+ }),
3400
+ state.subagentPolicy.blockedAttempt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3401
+ className: FallbacksCard_module_css_default.policyStatusWarn,
3402
+ role: "alert",
3403
+ children: t("subagents.policy.blocked")
3404
+ })
3405
+ ]
3406
+ }),
3407
+ state.subagentPolicy?.state === "unprovable" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3408
+ className: FallbacksCard_module_css_default.policyStatus,
3409
+ role: "status",
3410
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3411
+ className: FallbacksCard_module_css_default.policyStatusWarn,
3412
+ role: "alert",
3413
+ children: t("subagents.policy.unprovable")
3414
+ })
3415
+ }),
3416
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3417
+ className: FallbacksCard_module_css_default.field,
3418
+ role: "group",
3419
+ "aria-labelledby": "fallbacks-roles-list",
3420
+ children: [
3421
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3422
+ className: FallbacksCard_module_css_default.fieldLabel,
3423
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3424
+ id: "fallbacks-roles-list",
3425
+ children: t("roles.list.label")
3426
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3427
+ label: t("roles.list.tooltip"),
3428
+ disabled: !writable
3429
+ })]
3430
+ }),
3431
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3432
+ className: FallbacksCard_module_css_default.hint,
3433
+ children: t("roles.list.hint")
3434
+ }),
3435
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3436
+ className: FallbacksCard_module_css_default.list,
3437
+ children: roleRows.map((row, index) => {
3438
+ const invalid = invalidRoleIds.has(row.id.trim());
3439
+ const seed = seedInfo.get(row.id.trim());
3440
+ const seedBadge = seedBadgeLabel(seed, t);
3441
+ const personaBlank = row.persona.trim() === "";
3442
+ const roleSummary = row.selectors.map(selectorRowToRaw).find((entry) => entry !== "") ?? row.fallback;
3443
+ const roleExpanded = !row.collapsed || !writable;
3444
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3445
+ className: FallbacksCard_module_css_default.editorCard,
3446
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3447
+ className: FallbacksCard_module_css_default.collapseRow,
3448
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3449
+ type: "button",
3450
+ className: FallbacksCard_module_css_default.collapseToggle,
3451
+ "aria-expanded": roleExpanded,
3452
+ "aria-label": t(roleExpanded ? "roles.collapse" : "roles.expand"),
3453
+ disabled: !writable,
3454
+ onClick: () => {
3455
+ updateRoleRow(index, { collapsed: !row.collapsed });
3456
+ },
3457
+ children: [
3458
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDownIcon, { className: roleExpanded ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron }),
3459
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3460
+ className: FallbacksCard_module_css_default.collapseTitle,
3461
+ children: row.id
3462
+ }),
3463
+ seedBadge !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3464
+ className: FallbacksCard_module_css_default.seedBadge,
3465
+ title: seedBadge,
3466
+ children: seedBadge
3467
+ }),
3468
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3469
+ className: FallbacksCard_module_css_default.collapseMeta,
3470
+ children: roleSummary
3471
+ })
3472
+ ]
3473
+ })
3474
+ }), roleExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
3475
+ seed === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3476
+ className: FallbacksCard_module_css_default.ruleGrid,
3477
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3478
+ className: FallbacksCard_module_css_default.ruleCell,
3751
3479
  children: [
3752
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3753
- className: FallbacksCard_module_css_default.ruleGrid,
3754
- children: [
3755
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3756
- className: FallbacksCard_module_css_default.ruleCell,
3757
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3758
- className: FallbacksCard_module_css_default.ruleCellLabel,
3759
- children: t("roles.rule.provider")
3760
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3761
- className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
3762
- value: providerRaw,
3763
- onChange: (event) => {
3764
- if (event.target.value === providerRaw) return;
3765
- updateRuleRow(index, {
3766
- provider: classifyProvider(event.target.value, catalog),
3767
- model: null
3768
- });
3769
- },
3770
- children: [
3771
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3772
- value: "",
3773
- children: t("roles.rule.provider.any")
3774
- }),
3775
- state.configuredProviders.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3776
- value: entry.provider,
3777
- children: entry.displayName
3778
- }, entry.provider)),
3779
- providerUnconfigured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3780
- value: providerRaw,
3781
- children: `${providerRaw}${t("catalog.unconfigured.short")}`
3782
- }),
3783
- providerOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3784
- value: providerRaw,
3785
- children: `${providerRaw}${t("catalog.outside.short")}`
3786
- })
3787
- ]
3788
- })]
3789
- }),
3790
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3791
- className: FallbacksCard_module_css_default.ruleCell,
3792
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3793
- className: FallbacksCard_module_css_default.ruleCellLabel,
3794
- children: t("roles.rule.model")
3795
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3796
- className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
3797
- value: selectionToRaw(row.model),
3798
- onChange: (event) => {
3799
- updateRuleRow(index, { model: classifyModel(providerRaw, event.target.value, catalog) });
3800
- },
3801
- children: [
3802
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3803
- value: "",
3804
- children: t("roles.rule.model.any")
3805
- }),
3806
- (group?.models ?? []).map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3807
- value: model.id,
3808
- children: model.name
3809
- }, model.id)),
3810
- modelOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3811
- value: selectionToRaw(row.model),
3812
- children: `${selectionToRaw(row.model)}${t("catalog.outside.short")}`
3813
- })
3814
- ]
3815
- })]
3816
- }),
3817
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3818
- className: FallbacksCard_module_css_default.ruleCell,
3819
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3820
- className: FallbacksCard_module_css_default.ruleCellLabel,
3821
- children: t("roles.rule.role")
3822
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3823
- className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
3824
- value: row.role,
3825
- disabled: !writable,
3826
- onChange: (event) => {
3827
- updateRuleRow(index, { role: event.target.value });
3828
- },
3829
- children: [
3830
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3831
- value: "",
3832
- children: t("roles.rule.roleSelectPlaceholder")
3833
- }),
3834
- roleOptions.map((id) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3835
- value: id,
3836
- children: id === "inherit" ? t("roles.rule.role.inherit") : id
3837
- }, id)),
3838
- roleOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3839
- value: row.role,
3840
- children: `${row.role}${t("roles.rule.roleUndeclared.short")}`
3841
- })
3842
- ]
3843
- })]
3844
- })
3845
- ]
3480
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3481
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3482
+ children: t("roles.id")
3846
3483
  }),
3847
- (providerOutside || modelOutside) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3848
- className: FallbacksCard_module_css_default.hint,
3849
- children: [t("catalog.outside.hint"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3850
- label: t("catalog.outside.tooltip"),
3851
- disabled: !writable
3852
- })]
3484
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3485
+ className: `${FallbacksCard_module_css_default.input} ${invalid ? FallbacksCard_module_css_default.inputInvalid : ""}`,
3486
+ value: row.id,
3487
+ placeholder: t("roles.idPlaceholder"),
3488
+ "aria-label": t("roles.id"),
3489
+ "aria-invalid": invalid ? true : void 0,
3490
+ disabled: !writable,
3491
+ onChange: (event) => {
3492
+ updateRoleRow(index, { id: event.target.value });
3493
+ }
3853
3494
  }),
3854
- row.role === "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3495
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3855
3496
  className: FallbacksCard_module_css_default.hint,
3856
- children: t("validation.ruleRoleRequired")
3857
- }),
3858
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3859
- className: FallbacksCard_module_css_default.cardFoot,
3860
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3861
- type: "button",
3862
- className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger}`,
3863
- "data-tip": t("roles.removeRule"),
3864
- "aria-label": t("roles.removeRule"),
3865
- onClick: () => {
3866
- setRuleRows((rows) => rows.filter((_, rowIndex) => rowIndex !== index));
3867
- },
3868
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineMedium, {})
3869
- })
3497
+ children: t("roles.id.hint")
3870
3498
  })
3871
3499
  ]
3872
- }, index);
3873
- })
3874
- }),
3875
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Button, {
3876
- variant: "outline",
3877
- size: "sm",
3878
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconPlusOutlineMedium, { size: 14 }),
3879
- className: FallbacksCard_module_css_default.addButton,
3880
- onClick: () => {
3881
- setRuleRows((rows) => [...rows, {
3882
- provider: null,
3883
- model: null,
3884
- role: ""
3885
- }]);
3886
- },
3887
- children: t("roles.addRule")
3888
- })
3889
- ]
3890
- }),
3891
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3892
- className: FallbacksCard_module_css_default.field,
3893
- role: "group",
3894
- "aria-labelledby": "fallbacks-advanced",
3895
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3896
- type: "button",
3897
- className: FallbacksCard_module_css_default.sectionToggle,
3898
- disabled: !writable,
3899
- "aria-expanded": advancedVisible,
3900
- "aria-controls": advancedVisible ? "fallbacks-advanced-body" : void 0,
3901
- "aria-label": t(advancedVisible ? "advanced.collapse" : "advanced.expand"),
3902
- onClick: () => {
3903
- if (writable) setAdvancedOpen(!advancedOpen);
3904
- },
3905
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3906
- id: "fallbacks-advanced",
3907
- className: FallbacksCard_module_css_default.sectionToggleText,
3908
- children: t("advanced.label")
3909
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconChevronDownOutlineMedium, { className: advancedVisible ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron })]
3910
- }), advancedVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3911
- id: "fallbacks-advanced-body",
3912
- children: [
3913
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3914
- className: FallbacksCard_module_css_default.checkboxRow,
3915
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3916
- className: FallbacksCard_module_css_default.checkLabel,
3917
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3918
- className: FallbacksCard_module_css_default.checkLabelTitle,
3919
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
3920
- htmlFor: "fallbacks-role-automatch",
3921
- children: t("roleAutoMatch.label")
3922
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3923
- label: t("roleAutoMatch.tooltip"),
3924
- disabled: !writable
3500
+ })
3501
+ }),
3502
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3503
+ className: FallbacksCard_module_css_default.ruleGrid,
3504
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3505
+ className: FallbacksCard_module_css_default.ruleCell,
3506
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3507
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3508
+ children: t("roles.persona")
3509
+ }), seed === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
3510
+ rows: 3,
3511
+ className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.inputTextarea}`,
3512
+ value: row.persona,
3513
+ placeholder: t("roles.personaPlaceholder"),
3514
+ "aria-label": t("roles.persona"),
3515
+ disabled: !writable,
3516
+ onChange: (event) => {
3517
+ updateRoleRow(index, { persona: event.target.value });
3518
+ }
3519
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3520
+ className: FallbacksCard_module_css_default.personaBriefRow,
3521
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3522
+ className: personaBlank ? `${FallbacksCard_module_css_default.personaBrief} ${FallbacksCard_module_css_default.personaBriefEmpty}` : FallbacksCard_module_css_default.personaBrief,
3523
+ children: personaBlank ? t("roles.persona.empty") : row.persona
3524
+ }), !personaBlank && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3525
+ role: "button",
3526
+ tabIndex: 0,
3527
+ className: FallbacksCard_module_css_default.iconButton,
3528
+ "aria-expanded": row.personaOpen,
3529
+ "aria-label": t(row.personaOpen ? "roles.persona.collapse" : "roles.persona.expand"),
3530
+ "data-tip": t(row.personaOpen ? "roles.persona.collapse" : "roles.persona.expand"),
3531
+ onClick: () => {
3532
+ updateRoleRow(index, { personaOpen: !row.personaOpen });
3533
+ },
3534
+ onKeyDown: (event) => {
3535
+ if (event.key === "Enter" || event.key === " ") {
3536
+ event.preventDefault();
3537
+ updateRoleRow(index, { personaOpen: !row.personaOpen });
3538
+ }
3539
+ },
3540
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDownIcon, { className: row.personaOpen ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron })
3925
3541
  })]
3926
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3927
- className: FallbacksCard_module_css_default.checkLabelDesc,
3928
- children: t("roleAutoMatch.hint")
3929
- })]
3930
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3931
- id: "fallbacks-role-automatch",
3932
- type: "checkbox",
3933
- className: FallbacksCard_module_css_default.checkbox,
3934
- checked: scalars.roleAutoMatch,
3542
+ }), row.personaOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3543
+ className: FallbacksCard_module_css_default.personaFull,
3544
+ children: row.persona
3545
+ })] })]
3546
+ })
3547
+ }),
3548
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3549
+ className: FallbacksCard_module_css_default.chainSelectors,
3550
+ children: [row.selectors.map((selector, selectorIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
3551
+ selector,
3552
+ catalog: catalogOf(state),
3553
+ configuredProviders: state.configuredProviders,
3935
3554
  disabled: !writable,
3936
- onChange: (event) => {
3937
- updateScalars((draft) => {
3938
- draft.roleAutoMatch = event.target.checked;
3939
- });
3555
+ t,
3556
+ onChange: (patch) => {
3557
+ updateRoleSelector(index, selectorIndex, patch);
3558
+ },
3559
+ onRemove: () => {
3560
+ removeRoleSelector(index, selectorIndex);
3940
3561
  }
3562
+ }, selectorIndex)), row.selectors.every((selector) => selectorRowToRaw(selector) === "") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3563
+ className: FallbacksCard_module_css_default.hint,
3564
+ children: seed !== void 0 ? t("roles.seedChainOptional", { id: row.id }) : t("validation.roleChainRequired", { id: row.id })
3941
3565
  })]
3942
3566
  }),
3943
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3944
- className: FallbacksCard_module_css_default.field,
3945
- role: "group",
3946
- "aria-labelledby": "fallbacks-trigger-codes",
3947
- children: [
3948
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3949
- className: FallbacksCard_module_css_default.fieldLabel,
3950
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3951
- id: "fallbacks-trigger-codes",
3952
- children: t("triggerCodes.label")
3953
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3954
- label: t("triggerCodes.tooltip"),
3955
- disabled: !writable
3567
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3568
+ className: FallbacksCard_module_css_default.ruleGrid,
3569
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3570
+ className: FallbacksCard_module_css_default.ruleCell,
3571
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3572
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3573
+ children: t("roles.fallback")
3574
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3575
+ className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
3576
+ value: row.fallback,
3577
+ "aria-label": t("roles.fallback"),
3578
+ disabled: !writable,
3579
+ onChange: (event) => {
3580
+ updateRoleRow(index, { fallback: event.target.value });
3581
+ },
3582
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3583
+ value: "inherit-root",
3584
+ children: t("roles.fallback.inherit-root")
3585
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3586
+ value: "none",
3587
+ children: t("roles.fallback.none")
3956
3588
  })]
3957
- }),
3958
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3959
- className: FallbacksCard_module_css_default.hint,
3960
- children: t("triggerCodes.hint")
3961
- }),
3962
- KNOWN_TRIGGER_CODES.map((code) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3963
- className: FallbacksCard_module_css_default.optionRow,
3964
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3965
- type: "checkbox",
3966
- checked: scalars.triggerCodes.includes(code),
3967
- onChange: (event) => {
3968
- updateScalars((draft) => {
3969
- draft.triggerCodes = withTriggerCode(draft.triggerCodes, code, event.target.checked);
3970
- });
3971
- }
3972
- }), t(TRIGGER_CODE_LABELS[code])]
3973
- }, code)),
3974
- unknownCodes.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3975
- className: FallbacksCard_module_css_default.hint,
3976
- children: t("triggerCodes.extra", { codes: unknownCodes.join(", ") })
3977
- })
3978
- ]
3589
+ })]
3590
+ })
3979
3591
  }),
3592
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3593
+ type: "button",
3594
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3595
+ disabled: !writable,
3596
+ onClick: () => {
3597
+ addRoleSelector(index);
3598
+ },
3599
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("roles.selector.add")]
3600
+ }),
3601
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3602
+ className: FallbacksCard_module_css_default.cardFoot,
3603
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3604
+ type: "button",
3605
+ className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger}`,
3606
+ "data-tip": t("roles.remove"),
3607
+ "aria-label": t("roles.remove"),
3608
+ onClick: () => {
3609
+ removeRole(index);
3610
+ },
3611
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrashIcon, {})
3612
+ })
3613
+ })
3614
+ ] })]
3615
+ }, index);
3616
+ })
3617
+ }),
3618
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3619
+ type: "button",
3620
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3621
+ disabled: !writable,
3622
+ onClick: addRole,
3623
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("roles.add")]
3624
+ })
3625
+ ]
3626
+ }),
3627
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3628
+ className: FallbacksCard_module_css_default.field,
3629
+ role: "group",
3630
+ "aria-labelledby": "fallbacks-roles-rules",
3631
+ children: [
3632
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3633
+ className: FallbacksCard_module_css_default.fieldLabel,
3634
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3635
+ id: "fallbacks-roles-rules",
3636
+ children: t("roles.rules")
3637
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3638
+ label: t("roles.rules.tooltip"),
3639
+ disabled: !writable
3640
+ })]
3641
+ }),
3642
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3643
+ className: FallbacksCard_module_css_default.hint,
3644
+ children: t("roles.rules.hint")
3645
+ }),
3646
+ state.catalogStatus === "error" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3647
+ className: FallbacksCard_module_css_default.hint,
3648
+ children: t("catalog.error", { message: state.catalogError })
3649
+ }),
3650
+ state.catalogStatus === "ready" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3651
+ className: FallbacksCard_module_css_default.hint,
3652
+ children: t("catalog.partial", { message: state.catalogError })
3653
+ }),
3654
+ state.catalogStatus === "ready" && (state.groups.length === 0 || state.configuredProviders.length === 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3655
+ className: FallbacksCard_module_css_default.hint,
3656
+ children: t("catalog.empty")
3657
+ }),
3658
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3659
+ className: FallbacksCard_module_css_default.list,
3660
+ children: ruleRows.map((row, index) => {
3661
+ const catalog = catalogOf(state);
3662
+ const providerRaw = selectionToRaw(row.provider);
3663
+ const group = catalog?.groups.find((entry) => entry.id === providerRaw);
3664
+ const providerOutside = row.provider?.kind === "outside";
3665
+ const providerUnconfigured = !providerOutside && providerRaw !== "" && (catalog?.providers.some((entry) => entry.provider === providerRaw) ?? false) && !state.configuredProviders.some((entry) => entry.provider === providerRaw);
3666
+ const modelOutside = row.model?.kind === "outside";
3667
+ const roleOutside = row.role !== "" && !roleOptions.includes(row.role);
3668
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3669
+ className: FallbacksCard_module_css_default.editorCard,
3670
+ children: [
3980
3671
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3981
- className: FallbacksCard_module_css_default.field,
3982
- role: "group",
3983
- "aria-labelledby": "fallbacks-revert-policy",
3672
+ className: FallbacksCard_module_css_default.ruleGrid,
3984
3673
  children: [
3985
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3986
- className: FallbacksCard_module_css_default.fieldLabel,
3674
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3675
+ className: FallbacksCard_module_css_default.ruleCell,
3987
3676
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3988
- id: "fallbacks-revert-policy",
3989
- children: t("revertPolicy.label")
3990
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3991
- label: t("revertPolicy.tooltip"),
3992
- disabled: !writable
3993
- })]
3994
- }),
3995
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3996
- className: FallbacksCard_module_css_default.hint,
3997
- children: t("revertPolicy.hint")
3998
- }),
3999
- ["cooldown-expiry", "never"].map((policy) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
4000
- className: FallbacksCard_module_css_default.optionRow,
4001
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4002
- type: "radio",
4003
- name: "fallbacks-revert-policy",
4004
- checked: scalars.revertPolicy === policy,
4005
- onChange: () => {
4006
- updateScalars((draft) => {
4007
- draft.revertPolicy = policy;
3677
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3678
+ children: t("roles.rule.provider")
3679
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3680
+ className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
3681
+ value: providerRaw,
3682
+ onChange: (event) => {
3683
+ if (event.target.value === providerRaw) return;
3684
+ updateRuleRow(index, {
3685
+ provider: classifyProvider(event.target.value, catalog),
3686
+ model: null
4008
3687
  });
4009
- }
4010
- }), t(`revertPolicy.${policy}`)]
4011
- }, policy))
4012
- ]
4013
- }),
4014
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4015
- className: FallbacksCard_module_css_default.numberFields,
4016
- children: [
4017
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4018
- className: FallbacksCard_module_css_default.field,
4019
- children: [
4020
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4021
- className: FallbacksCard_module_css_default.fieldLabel,
4022
- children: [
4023
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
4024
- htmlFor: "fallbacks-cooldown-ms",
4025
- children: t("cooldownMs.label")
4026
- }),
4027
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
4028
- label: t("cooldownMs.tooltip"),
4029
- disabled: !writable
4030
- }),
4031
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4032
- className: FallbacksCard_module_css_default.defaultNote,
4033
- children: [
4034
- t("defaults.prefix"),
4035
- ": ",
4036
- state.config.cooldownMs
4037
- ]
4038
- })
4039
- ]
4040
- }),
4041
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4042
- id: "fallbacks-cooldown-ms",
4043
- className: FallbacksCard_module_css_default.input,
4044
- type: "number",
4045
- min: 0,
4046
- value: String(scalars.cooldownMs),
4047
- disabled: !writable,
4048
- onChange: (event) => {
4049
- updateScalars((draft) => {
4050
- draft.cooldownMs = parseCount(event.target.value);
4051
- });
4052
- }
4053
- }),
4054
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4055
- className: FallbacksCard_module_css_default.hint,
4056
- children: t("cooldownMs.hint")
4057
- })
4058
- ]
3688
+ },
3689
+ children: [
3690
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3691
+ value: "",
3692
+ children: t("roles.rule.provider.any")
3693
+ }),
3694
+ state.configuredProviders.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3695
+ value: entry.provider,
3696
+ children: entry.displayName
3697
+ }, entry.provider)),
3698
+ providerUnconfigured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3699
+ value: providerRaw,
3700
+ children: `${providerRaw}${t("catalog.unconfigured.short")}`
3701
+ }),
3702
+ providerOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3703
+ value: providerRaw,
3704
+ children: `${providerRaw}${t("catalog.outside.short")}`
3705
+ })
3706
+ ]
3707
+ })]
4059
3708
  }),
4060
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4061
- className: FallbacksCard_module_css_default.field,
4062
- children: [
4063
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4064
- className: FallbacksCard_module_css_default.fieldLabel,
4065
- children: [
4066
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
4067
- htmlFor: "fallbacks-max-switches",
4068
- children: t("maxSwitchesPerStep.label")
4069
- }),
4070
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
4071
- label: t("maxSwitchesPerStep.tooltip"),
4072
- disabled: !writable
4073
- }),
4074
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4075
- className: FallbacksCard_module_css_default.defaultNote,
4076
- children: [
4077
- t("defaults.prefix"),
4078
- ": ",
4079
- state.config.maxSwitchesPerStep
4080
- ]
4081
- })
4082
- ]
4083
- }),
4084
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4085
- id: "fallbacks-max-switches",
4086
- className: FallbacksCard_module_css_default.input,
4087
- type: "number",
4088
- min: 0,
4089
- value: String(scalars.maxSwitchesPerStep),
4090
- disabled: !writable,
4091
- onChange: (event) => {
4092
- updateScalars((draft) => {
4093
- draft.maxSwitchesPerStep = parseCount(event.target.value);
4094
- });
4095
- }
4096
- }),
4097
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4098
- className: FallbacksCard_module_css_default.hint,
4099
- children: t("maxSwitchesPerStep.hint")
4100
- })
4101
- ]
3709
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3710
+ className: FallbacksCard_module_css_default.ruleCell,
3711
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3712
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3713
+ children: t("roles.rule.model")
3714
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3715
+ className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
3716
+ value: selectionToRaw(row.model),
3717
+ onChange: (event) => {
3718
+ updateRuleRow(index, { model: classifyModel(providerRaw, event.target.value, catalog) });
3719
+ },
3720
+ children: [
3721
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3722
+ value: "",
3723
+ children: t("roles.rule.model.any")
3724
+ }),
3725
+ (group?.models ?? []).map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3726
+ value: model.id,
3727
+ children: model.name
3728
+ }, model.id)),
3729
+ modelOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3730
+ value: selectionToRaw(row.model),
3731
+ children: `${selectionToRaw(row.model)}${t("catalog.outside.short")}`
3732
+ })
3733
+ ]
3734
+ })]
4102
3735
  }),
4103
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4104
- className: FallbacksCard_module_css_default.field,
4105
- children: [
4106
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4107
- className: FallbacksCard_module_css_default.fieldLabel,
4108
- children: [
4109
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
4110
- htmlFor: "fallbacks-always-cap",
4111
- children: t("alwaysModeRetryCap.label")
4112
- }),
4113
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
4114
- label: t("alwaysModeRetryCap.tooltip"),
4115
- disabled: !writable
4116
- }),
4117
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4118
- className: FallbacksCard_module_css_default.defaultNote,
4119
- children: [
4120
- t("defaults.prefix"),
4121
- ": ",
4122
- state.config.alwaysModeRetryCap
4123
- ]
4124
- })
4125
- ]
4126
- }),
4127
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4128
- id: "fallbacks-always-cap",
4129
- className: FallbacksCard_module_css_default.input,
4130
- type: "number",
4131
- min: 0,
4132
- value: String(scalars.alwaysModeRetryCap),
4133
- disabled: !writable,
4134
- onChange: (event) => {
4135
- updateScalars((draft) => {
4136
- draft.alwaysModeRetryCap = parseCount(event.target.value);
4137
- });
4138
- }
4139
- }),
4140
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4141
- className: FallbacksCard_module_css_default.hint,
4142
- children: t("alwaysModeRetryCap.hint")
4143
- })
4144
- ]
3736
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3737
+ className: FallbacksCard_module_css_default.ruleCell,
3738
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3739
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3740
+ children: t("roles.rule.role")
3741
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3742
+ className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
3743
+ value: row.role,
3744
+ disabled: !writable,
3745
+ onChange: (event) => {
3746
+ updateRuleRow(index, { role: event.target.value });
3747
+ },
3748
+ children: [
3749
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3750
+ value: "",
3751
+ children: t("roles.rule.roleSelectPlaceholder")
3752
+ }),
3753
+ roleOptions.map((id) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3754
+ value: id,
3755
+ children: id === "inherit" ? t("roles.rule.role.inherit") : id
3756
+ }, id)),
3757
+ roleOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3758
+ value: row.role,
3759
+ children: `${row.role}${t("roles.rule.roleUndeclared.short")}`
3760
+ })
3761
+ ]
3762
+ })]
4145
3763
  })
4146
3764
  ]
4147
3765
  }),
4148
- validationErrors.advanced.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4149
- className: FallbacksCard_module_css_default.error,
4150
- role: "alert",
4151
- children: `${t("validation.blocked")}${validationErrors.advanced.join("; ")}`
3766
+ (providerOutside || modelOutside) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3767
+ className: FallbacksCard_module_css_default.hint,
3768
+ children: [t("catalog.outside.hint"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3769
+ label: t("catalog.outside.tooltip"),
3770
+ disabled: !writable
3771
+ })]
4152
3772
  }),
4153
- lastSaveSection === "advanced" && state.status === "error" && state.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
4154
- className: FallbacksCard_module_css_default.error,
4155
- role: "alert",
4156
- children: t("error.generic", { message: state.error })
3773
+ row.role === "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3774
+ className: FallbacksCard_module_css_default.hint,
3775
+ children: t("validation.ruleRoleRequired")
4157
3776
  }),
4158
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4159
- className: FallbacksCard_module_css_default.sectionActions,
4160
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3777
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3778
+ className: FallbacksCard_module_css_default.cardFoot,
3779
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4161
3780
  type: "button",
4162
- className: `${FallbacksCard_module_css_default.secondaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
4163
- disabled: !advancedDirty || saving,
3781
+ className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger}`,
3782
+ "data-tip": t("roles.removeRule"),
3783
+ "aria-label": t("roles.removeRule"),
4164
3784
  onClick: () => {
4165
- discardSection("advanced");
3785
+ setRuleRows((rows) => rows.filter((_, rowIndex) => rowIndex !== index));
4166
3786
  },
4167
- children: t("discard")
4168
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4169
- type: "button",
4170
- className: `${FallbacksCard_module_css_default.primaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
4171
- disabled: !writable || saving || !advancedDirty,
4172
- onClick: () => {
4173
- save("advanced");
4174
- },
4175
- children: saving ? t("save.saving") : t("save")
4176
- })]
3787
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrashIcon, {})
3788
+ })
4177
3789
  })
4178
3790
  ]
4179
- })]
3791
+ }, index);
4180
3792
  })
4181
- ]
3793
+ }),
3794
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3795
+ type: "button",
3796
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3797
+ disabled: !writable,
3798
+ onClick: () => {
3799
+ setRuleRows((rows) => [...rows, {
3800
+ provider: null,
3801
+ model: null,
3802
+ role: ""
3803
+ }]);
3804
+ },
3805
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("roles.addRule")]
3806
+ })
3807
+ ]
3808
+ }),
3809
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", {
3810
+ className: FallbacksCard_module_css_default.sectionHeading,
3811
+ id: "fallbacks-advanced",
3812
+ "aria-label": t("advanced.label"),
3813
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3814
+ type: "button",
3815
+ className: FallbacksCard_module_css_default.sectionToggle,
3816
+ disabled: !writable,
3817
+ "aria-expanded": advancedVisible,
3818
+ "aria-controls": advancedVisible ? "fallbacks-advanced-body" : void 0,
3819
+ "aria-label": t(advancedVisible ? "advanced.collapse" : "advanced.expand"),
3820
+ onClick: () => {
3821
+ if (writable) setAdvancedOpen(!advancedOpen);
3822
+ },
3823
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDownIcon, { className: advancedVisible ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3824
+ className: FallbacksCard_module_css_default.sectionHeadingText,
3825
+ children: t("advanced.label")
3826
+ })]
4182
3827
  })
4183
- ]
4184
- }),
4185
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4186
- className: FallbacksCard_module_css_default.statusBlock,
3828
+ }),
3829
+ advancedVisible && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3830
+ id: "fallbacks-advanced-body",
3831
+ className: FallbacksCard_module_css_default.advancedBody,
3832
+ children: [
3833
+ liveErrors.advanced.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3834
+ className: FallbacksCard_module_css_default.error,
3835
+ role: "alert",
3836
+ children: `${t("validation.blocked")}${liveErrors.advanced.join("; ")}`
3837
+ }),
3838
+ lastSaveSection === "advanced" && state.status === "error" && state.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3839
+ className: FallbacksCard_module_css_default.error,
3840
+ role: "alert",
3841
+ children: t("error.generic", { message: state.error })
3842
+ }),
3843
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3844
+ className: FallbacksCard_module_css_default.checkboxRow,
3845
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3846
+ id: "fallbacks-role-automatch",
3847
+ type: "checkbox",
3848
+ className: FallbacksCard_module_css_default.checkbox,
3849
+ checked: scalars.roleAutoMatch,
3850
+ disabled: !writable,
3851
+ onChange: (event) => {
3852
+ updateScalars((draft) => {
3853
+ draft.roleAutoMatch = event.target.checked;
3854
+ });
3855
+ }
3856
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3857
+ className: FallbacksCard_module_css_default.checkLabel,
3858
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3859
+ className: FallbacksCard_module_css_default.checkLabelTitle,
3860
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
3861
+ htmlFor: "fallbacks-role-automatch",
3862
+ children: t("roleAutoMatch.label")
3863
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3864
+ label: t("roleAutoMatch.tooltip"),
3865
+ disabled: !writable
3866
+ })]
3867
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
3868
+ className: FallbacksCard_module_css_default.checkLabelDesc,
3869
+ htmlFor: "fallbacks-role-automatch",
3870
+ children: t("roleAutoMatch.hint")
3871
+ })]
3872
+ })]
3873
+ }),
3874
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3875
+ className: FallbacksCard_module_css_default.field,
3876
+ role: "group",
3877
+ "aria-labelledby": "fallbacks-trigger-codes",
3878
+ children: [
3879
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3880
+ className: FallbacksCard_module_css_default.fieldLabel,
3881
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3882
+ id: "fallbacks-trigger-codes",
3883
+ children: t("triggerCodes.label")
3884
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3885
+ label: t("triggerCodes.tooltip"),
3886
+ disabled: !writable
3887
+ })]
3888
+ }),
3889
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3890
+ className: FallbacksCard_module_css_default.hint,
3891
+ children: t("triggerCodes.hint")
3892
+ }),
3893
+ KNOWN_TRIGGER_CODES.map((code) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3894
+ className: FallbacksCard_module_css_default.optionRow,
3895
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3896
+ type: "checkbox",
3897
+ checked: scalars.triggerCodes.includes(code),
3898
+ onChange: (event) => {
3899
+ updateScalars((draft) => {
3900
+ draft.triggerCodes = withTriggerCode(draft.triggerCodes, code, event.target.checked);
3901
+ });
3902
+ }
3903
+ }), t(TRIGGER_CODE_LABELS[code])]
3904
+ }, code)),
3905
+ unknownCodes.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3906
+ className: FallbacksCard_module_css_default.hint,
3907
+ children: t("triggerCodes.extra", { codes: unknownCodes.join(", ") })
3908
+ })
3909
+ ]
3910
+ }),
3911
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3912
+ className: FallbacksCard_module_css_default.field,
3913
+ role: "group",
3914
+ "aria-labelledby": "fallbacks-revert-policy",
3915
+ children: [
3916
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3917
+ className: FallbacksCard_module_css_default.fieldLabel,
3918
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3919
+ id: "fallbacks-revert-policy",
3920
+ children: t("revertPolicy.label")
3921
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3922
+ label: t("revertPolicy.tooltip"),
3923
+ disabled: !writable
3924
+ })]
3925
+ }),
3926
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3927
+ className: FallbacksCard_module_css_default.hint,
3928
+ children: t("revertPolicy.hint")
3929
+ }),
3930
+ ["cooldown-expiry", "never"].map((policy) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3931
+ className: FallbacksCard_module_css_default.optionRow,
3932
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3933
+ type: "radio",
3934
+ name: "fallbacks-revert-policy",
3935
+ checked: scalars.revertPolicy === policy,
3936
+ onChange: () => {
3937
+ updateScalars((draft) => {
3938
+ draft.revertPolicy = policy;
3939
+ });
3940
+ }
3941
+ }), t(`revertPolicy.${policy}`)]
3942
+ }, policy))
3943
+ ]
3944
+ }),
3945
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3946
+ className: FallbacksCard_module_css_default.numberFields,
3947
+ children: [
3948
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3949
+ className: FallbacksCard_module_css_default.field,
3950
+ children: [
3951
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3952
+ className: FallbacksCard_module_css_default.fieldLabel,
3953
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
3954
+ htmlFor: "fallbacks-cooldown-ms",
3955
+ children: t("cooldownMs.label")
3956
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3957
+ label: cooldownMsTip,
3958
+ disabled: !writable
3959
+ })]
3960
+ }),
3961
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3962
+ id: "fallbacks-cooldown-ms",
3963
+ className: FallbacksCard_module_css_default.input,
3964
+ type: "number",
3965
+ min: 0,
3966
+ value: String(scalars.cooldownMs),
3967
+ disabled: !writable,
3968
+ onChange: (event) => {
3969
+ updateScalars((draft) => {
3970
+ draft.cooldownMs = parseCount(event.target.value);
3971
+ });
3972
+ }
3973
+ }),
3974
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3975
+ className: FallbacksCard_module_css_default.hint,
3976
+ children: t("cooldownMs.hint")
3977
+ })
3978
+ ]
3979
+ }),
3980
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3981
+ className: FallbacksCard_module_css_default.field,
3982
+ children: [
3983
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3984
+ className: FallbacksCard_module_css_default.fieldLabel,
3985
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
3986
+ htmlFor: "fallbacks-max-switches",
3987
+ children: t("maxSwitchesPerStep.label")
3988
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3989
+ label: maxSwitchesPerStepTip,
3990
+ disabled: !writable
3991
+ })]
3992
+ }),
3993
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3994
+ id: "fallbacks-max-switches",
3995
+ className: FallbacksCard_module_css_default.input,
3996
+ type: "number",
3997
+ min: 0,
3998
+ value: String(scalars.maxSwitchesPerStep),
3999
+ disabled: !writable,
4000
+ onChange: (event) => {
4001
+ updateScalars((draft) => {
4002
+ draft.maxSwitchesPerStep = parseCount(event.target.value);
4003
+ });
4004
+ }
4005
+ }),
4006
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4007
+ className: FallbacksCard_module_css_default.hint,
4008
+ children: t("maxSwitchesPerStep.hint")
4009
+ })
4010
+ ]
4011
+ }),
4012
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4013
+ className: FallbacksCard_module_css_default.field,
4014
+ children: [
4015
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
4016
+ className: FallbacksCard_module_css_default.fieldLabel,
4017
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
4018
+ htmlFor: "fallbacks-always-cap",
4019
+ children: t("alwaysModeRetryCap.label")
4020
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
4021
+ label: alwaysModeRetryCapTip,
4022
+ disabled: !writable
4023
+ })]
4024
+ }),
4025
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
4026
+ id: "fallbacks-always-cap",
4027
+ className: FallbacksCard_module_css_default.input,
4028
+ type: "number",
4029
+ min: 0,
4030
+ value: String(scalars.alwaysModeRetryCap),
4031
+ disabled: !writable,
4032
+ onChange: (event) => {
4033
+ updateScalars((draft) => {
4034
+ draft.alwaysModeRetryCap = parseCount(event.target.value);
4035
+ });
4036
+ }
4037
+ }),
4038
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4039
+ className: FallbacksCard_module_css_default.hint,
4040
+ children: t("alwaysModeRetryCap.hint")
4041
+ })
4042
+ ]
4043
+ })
4044
+ ]
4045
+ }),
4046
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4047
+ className: FallbacksCard_module_css_default.sectionActions,
4048
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4049
+ type: "button",
4050
+ className: FallbacksCard_module_css_default.discard,
4051
+ disabled: !advancedDirty || saving,
4052
+ onClick: () => {
4053
+ discardSection("advanced");
4054
+ },
4055
+ children: t("discard")
4056
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4057
+ type: "button",
4058
+ className: FallbacksCard_module_css_default.save,
4059
+ disabled: !writable || saving || !advancedDirty,
4060
+ onClick: () => {
4061
+ saveSection("advanced");
4062
+ },
4063
+ children: saving ? t("save.saving") : t("save")
4064
+ })]
4065
+ })
4066
+ ]
4067
+ })
4068
+ ]
4069
+ }),
4070
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4071
+ className: FallbacksCard_module_css_default.statusBlock,
4072
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4073
+ className: FallbacksCard_module_css_default.statusTitle,
4074
+ children: t("status.title")
4075
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
4076
+ className: FallbacksCard_module_css_default.statusLine,
4077
+ role: state.switchesStatus === "error" ? "alert" : void 0,
4187
4078
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4188
- className: FallbacksCard_module_css_default.statusTitle,
4189
- children: t("status.title")
4190
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
4191
- className: FallbacksCard_module_css_default.statusLine,
4192
- role: state.switchesStatus === "error" ? "alert" : void 0,
4193
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
4194
- className: FallbacksCard_module_css_default.statusLineLabel,
4195
- children: t("status.switches.label")
4196
- }), switchesLine]
4197
- })]
4198
- })
4199
- ]
4200
- })]
4079
+ className: FallbacksCard_module_css_default.statusLineLabel,
4080
+ children: t("status.switches.label")
4081
+ }), switchesLine]
4082
+ })]
4083
+ })
4084
+ ]
4201
4085
  });
4202
4086
  }
4203
4087
  //#endregion
@@ -4237,7 +4121,9 @@ window.__ModuleLoader__.load({
4237
4121
  * afterwards — no new data path, no store API change.
4238
4122
  *
4239
4123
  * The row is read-only by design (偏好位语义: a General preference row is not
4240
- * a control surface): an enabled badge + a compact last-switch summary.
4124
+ * a control surface): an active/inactive badge (content presence — the
4125
+ * removed config-level `enabled` switch is re-keyed to `isFallbackActive`,
4126
+ * plan fallbacks-web-ux-alignment T2) + a compact last-switch summary.
4241
4127
  * Honest degraded states: a hard load error or an unreachable gateway
4242
4128
  * channel (`ready && !present`) render the neutral 'unknown' badge — a
4243
4129
  * channel-down read must never masquerade as 'disabled' (KD-G5); the
@@ -4261,7 +4147,7 @@ window.__ModuleLoader__.load({
4261
4147
  if (snapshot.switchesStatus === "idle") controller.loadSwitches();
4262
4148
  }, [controller]);
4263
4149
  const settled = state.status === "ready";
4264
- const badgeKey = settled && state.present ? state.config.enabled ? "general.enabled" : "general.disabled" : "general.unknown";
4150
+ const badgeKey = settled && state.present ? isFallbackActive(state.config) ? "general.enabled" : "general.disabled" : "general.unknown";
4265
4151
  const latestSwitch = state.switches[0];
4266
4152
  let summary;
4267
4153
  if (state.status === "error") summary = t("general.error", { message: state.error ?? "" });