dsh-llm-fallbacks 0.6.0 → 0.6.2

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 先行退避,预算耗尽后同样进入决策。",
@@ -1357,8 +1357,6 @@ window.__ModuleLoader__.load({
1357
1357
  "alwaysModeRetryCap.hint": "达到上限次数后切换;0 表示禁用",
1358
1358
  "alwaysModeRetryCap.tooltip": "retryPolicy 为 always 的模型在同一请求内重试达到该次数后切换;0 表示禁用。",
1359
1359
  "advanced.label": "高级选项",
1360
- "advanced.expand": "展开高级选项",
1361
- "advanced.collapse": "收起高级选项",
1362
1360
  "roleAutoMatch.label": "启用角色自动匹配",
1363
1361
  "roleAutoMatch.hint": "规则未命中时,由模型自选最贴近的已声明角色",
1364
1362
  "roleAutoMatch.tooltip": "规则未命中时,模型会自动从已声明角色(id + persona)中选择最匹配者并注入该角色的链;关闭后未命中规则时按现状回落(inherit / rootChain)。",
@@ -1519,18 +1517,9 @@ window.__ModuleLoader__.load({
1519
1517
  };
1520
1518
  /** English dictionary, checked complete against the zh key set. */
1521
1519
  const en = {
1522
- "title": "Fallbacks",
1523
- "intro": "Automatic fallback on model failures",
1524
- "collapse": "Hide settings",
1525
- "expand": "Show settings",
1526
- "unsaved": "Unsaved",
1527
1520
  "discard": "Discard",
1528
1521
  "retry": "Retry",
1529
1522
  "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
1523
  "triggerCodes.label": "Trigger failure codes",
1535
1524
  "triggerCodes.hint": "Failures with these codes enter fallback decision",
1536
1525
  "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 +1542,6 @@ window.__ModuleLoader__.load({
1553
1542
  "alwaysModeRetryCap.hint": "Switches after the cap; 0 disables",
1554
1543
  "alwaysModeRetryCap.tooltip": "Models whose retryPolicy is always switch after this many retries within one request; 0 disables.",
1555
1544
  "advanced.label": "Advanced options",
1556
- "advanced.expand": "Show advanced options",
1557
- "advanced.collapse": "Hide advanced options",
1558
1545
  "roleAutoMatch.label": "Enable role auto-match",
1559
1546
  "roleAutoMatch.hint": "On rules-miss, the model picks the closest declared role",
1560
1547
  "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 +1738,7 @@ window.__ModuleLoader__.load({
1751
1738
  }
1752
1739
  //#endregion
1753
1740
  //#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";
1741
+ 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 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 display: block;\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\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._94c91bfd_fieldset > ._9998065c_checkboxRow {\n display: flex;\n align-items: center;\n gap: 8px;\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._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._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 transition: transform .16s;\n}\n\n._44836ce8_chevronOpen {\n transform: rotate(180deg);\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._114985b2_footer {\n display: flex;\n align-items: center;\n justify-content: flex-end;\n gap: 8px;\n padding-top: 16px;\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
1742
  const tagId$3 = "dsh-llm-fallbacks/FallbacksCard.module.css";
1756
1743
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
1757
1744
  const tag = document.createElement("style");
@@ -1761,37 +1748,25 @@ window.__ModuleLoader__.load({
1761
1748
  document.head.appendChild(tag);
1762
1749
  }
1763
1750
  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",
1751
+ "root": "_20fd0e45_root",
1773
1752
  "readOnly": "_4e39cf17_readOnly",
1774
- "pending": "_99bf7f3c_pending",
1775
1753
  "notice": "_9860a5b1_notice",
1776
1754
  "legacyNotice": "_5006d43e_legacyNotice",
1777
1755
  "error": "_21918751_error",
1778
1756
  "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
1757
  "fieldset": "_94c91bfd_fieldset",
1786
- "field": "_67826267_field",
1787
- "fieldLabel": "_13e68c3f_fieldLabel",
1788
1758
  "sectionHeading": "_ba240d82_sectionHeading",
1789
1759
  "sectionHeadingText": "_ddbc1b49_sectionHeadingText",
1790
- "sectionActions": "_c41f9db7_sectionActions",
1791
- "sectionToggle": "_b116c758_sectionToggle",
1792
- "sectionToggleText": "_a5313fdf_sectionToggleText",
1760
+ "field": "_67826267_field",
1761
+ "checkboxRow": "_9998065c_checkboxRow",
1762
+ "numberFields": "_3e95886d_numberFields",
1763
+ "fieldLabel": "_13e68c3f_fieldLabel",
1793
1764
  "hint": "_4bc809b8_hint",
1794
1765
  "defaultNote": "_579f813a_defaultNote",
1766
+ "checkLabel": "_02c2f6df_checkLabel",
1767
+ "checkLabelTitle": "_f2d47237_checkLabelTitle",
1768
+ "checkLabelDesc": "_c1bed8ea_checkLabelDesc",
1769
+ "checkbox": "_06389b18_checkbox",
1795
1770
  "slotPresetName": "_b1962759_slotPresetName",
1796
1771
  "infoHint": "_a6244318_infoHint",
1797
1772
  "infoHintDisabled": "_e655c840_infoHintDisabled",
@@ -1806,12 +1781,15 @@ window.__ModuleLoader__.load({
1806
1781
  "personaFull": "_4e4a07be_personaFull",
1807
1782
  "inputInvalid": "_7b60337a_inputInvalid",
1808
1783
  "selectInput": "_16eb7153_selectInput",
1809
- "numberFields": "_3e95886d_numberFields",
1810
1784
  "list": "_0cfb5881_list",
1811
1785
  "editorCard": "_f5c620d6_editorCard",
1812
1786
  "cardFoot": "_224b1387_cardFoot",
1813
1787
  "ruleGrid": "_8e220e07_ruleGrid",
1814
1788
  "ruleCell": "_24a12a2f_ruleCell",
1789
+ "ruleCellLabel": "_1014c097_ruleCellLabel",
1790
+ "chevron": "_631094a0_chevron",
1791
+ "chevronOpen": "_44836ce8_chevronOpen",
1792
+ "chevronFlip": "_cf3961bb_chevronFlip",
1815
1793
  "collapseRow": "_86bc52d2_collapseRow",
1816
1794
  "collapseToggle": "_a73efcc6_collapseToggle",
1817
1795
  "collapseTitle": "_af017718_collapseTitle",
@@ -1822,25 +1800,23 @@ window.__ModuleLoader__.load({
1822
1800
  "slotTagMultiplier": "_23bdb6fc_slotTagMultiplier",
1823
1801
  "slotTagActive": "_f000eed9_slotTagActive",
1824
1802
  "dragHandle": "_cd905ce5_dragHandle",
1825
- "dragHandleIcon": "_49f0c4f0_dragHandleIcon",
1826
1803
  "slotCardDragging": "_fee63b7e_slotCardDragging",
1827
1804
  "slotCardOver": "_6f108491_slotCardOver",
1828
- "ruleCellLabel": "_1014c097_ruleCellLabel",
1829
1805
  "chainSelectors": "_15a12620_chainSelectors",
1830
1806
  "selectorRow": "_240cbbf8_selectorRow",
1831
1807
  "iconButton": "_70effa64_iconButton",
1832
1808
  "iconButtonDanger": "_a0968257_iconButtonDanger",
1809
+ "outlineButton": "_711248a9_outlineButton",
1833
1810
  "addButton": "_28202c90_addButton",
1834
1811
  "slotAddRow": "_6a2bd54c_slotAddRow",
1835
1812
  "rowActions": "_4e77523e_rowActions",
1836
- "primaryButton": "_747fd56d_primaryButton",
1837
- "secondaryButton": "_7e855445_secondaryButton",
1838
- "sectionAction": "_238d19be_sectionAction",
1813
+ "footer": "_114985b2_footer",
1814
+ "discard": "_f0864181_discard",
1815
+ "save": "_ccff7e48_save",
1839
1816
  "statusBlock": "_fbd045e0_statusBlock",
1840
1817
  "statusTitle": "_d4f70367_statusTitle",
1841
1818
  "statusLine": "_8ab300ed_statusLine",
1842
1819
  "statusLineLabel": "_e8cedbf5_statusLineLabel",
1843
- "offNotice": "_b48dfcba_offNotice",
1844
1820
  "policyStatus": "_700006c9_policyStatus",
1845
1821
  "policyStatusLabel": "_d4b67a81_policyStatusLabel",
1846
1822
  "policyStatusLine": "_278bb4b3_policyStatusLine",
@@ -1856,77 +1832,71 @@ window.__ModuleLoader__.load({
1856
1832
  * registration order); owner props are empty and all data flows
1857
1833
  * through {@link FallbacksSettingsController}.
1858
1834
  *
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).
1835
+ * FLAT rebuild (plan fallbacks-web-ux-alignment T3, the advisor PR #98
1836
+ * pattern): the collapsible card chrome is gone — no header button, no
1837
+ * rotating chevron, no dirty "unsaved" pill, no card-local open state, no
1838
+ * bordered `<li>` box. The page already renders the plugin title/description
1839
+ * above the card (the `locale/*.json` meta files the host resolves per UI
1840
+ * language), so the notices, the form, and the footer tile directly beneath
1841
+ * it in the official flat settings-form language (reference §3): fields at
1842
+ * 12px vertical padding with 0.5px hairline separators, 34px inputs on the
1843
+ * 0.5px l4 border, one dark solid Save footer. The card is ALWAYS open —
1844
+ * nothing is hidden, so nothing needs disclosure state; the degraded /
1845
+ * error / read-only / migration notices render flat atop the form (the
1846
+ * unavailable notice stays always-visible per KD-G5 — the documented
1847
+ * divergence from the advisor, whose unavailable card renders nothing: the
1848
+ * fallbacks skeleton stays the USABLE last-known form and saves are
1849
+ * attempted).
1850
+ *
1851
+ * The config-level `enabled` switch is REMOVED (T2, breaking): there is no
1852
+ * checkbox row and no `enabled.off` hiding — all fields render
1853
+ * unconditionally; the Plugins-page row toggle is the master switch and the
1854
+ * runtime gates read content presence (`isFallbackActive`).
1881
1855
  *
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.
1856
+ * ONE Save replaces the per-section saves (T3): the per-section split
1857
+ * existed so one section's Save could not ride along another section's
1858
+ * unsaved edits (PR #62 UX round 3) — with ONE save over ONE document that
1859
+ * concern is moot. The footer's Save writes the whole validated draft
1860
+ * (disabled = `!dirty || invalid || saving || !writable` — `invalid` is the
1861
+ * LIVE whole-form `validateDraft` verdict plus the empty-rule-row check;
1862
+ * section bucketing survives for ERROR PLACEMENT only: each violation
1863
+ * renders under its owning section heading). Save additionally carries
1864
+ * `!writable` (W-1, qc2 fix wave: the dirty-implies-writable assumption
1865
+ * does not hold for this in-place-draft store). Discard is kept — our
1866
+ * staged edits survive refresh, the advisor's documented divergence from
1867
+ * the official no-discard form — a pure client-side revert of the WHOLE
1868
+ * draft to the last accepted config (`!dirty || saving`).
1899
1869
  *
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.
1870
+ * The form body is the two-block editing surface (spec §8): the 6 top-level
1871
+ * scalar fields (trigger codes / revert policy / three numeric fields), the
1872
+ * `rootChain` block (block 1 — the root agent's single chain, no key input),
1873
+ * and the roles block (block 2 — declared role entity cards from
1874
+ * `roles.list` plus the rule rows from `roles.rules`, whose role field is a
1875
+ * dropdown bound to the declared ids + the built-in `inherit`, same-page
1876
+ * live). Row-level disclosures that are CONTENT keep their expand/collapse:
1877
+ * the time-slot row cards and the role entity cards (with the seeded
1878
+ * persona briefs) stay collapsible — a read-only view forces them open so
1879
+ * the configs stay reachable. The 主代理 / 子代理 / 高级选项 group labels
1880
+ * stay as flat, non-collapsible section headings.
1904
1881
  *
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.
1882
+ * Validation: id format/reserved word/duplicates, undeclared rule role
1883
+ * references, illegal selectors, and a role with no chain entries (no model
1884
+ * config) block the write (the Save disabled gate) with per-section banners
1885
+ * + inline red borders / hints (never touching the store error path); a
1886
+ * non-empty `state.legacyKeys` renders the migration banner at the top.
1887
+ * The reset-to-defaults affordance is GONE from the card (PR #62 UX
1888
+ * round 3) — the gateway RPC `fallbacks/reset` and the store
1889
+ * `resetToDefaults()` stay as host APIs, only the card UI was removed.
1922
1890
  *
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.
1891
+ * The AC-7 read-only status block (recent-switch summary, D-5) stays at the
1892
+ * bottom, flat.
1893
+ *
1894
+ * Presentation is ui-primitives-free (T4, advisor parity + reference §4
1895
+ * risk): Button/Tooltip and the five icon imports are replaced by
1896
+ * self-drawn styled elements — inline SVG icons (plus / trash / chevron /
1897
+ * grip) and the CSS `data-tip` tooltip bubble (the card's existing
1898
+ * icon-button pattern); every color resolves through a `--dsw-alias-*`
1899
+ * token so the card adapts to the light/dark theme.
1930
1900
  */
1931
1901
  const ALL_DAY_LABEL_KEYS = ["allDay.flash", "allDay.pro"];
1932
1902
  const SLOT_PRESET_IDS = [
@@ -1945,6 +1915,106 @@ window.__ModuleLoader__.load({
1945
1915
  "fri",
1946
1916
  "sat"
1947
1917
  ];
1918
+ /** The disclosure chevron (12px) — content-level row/panel toggles only. */
1919
+ function ChevronDownIcon({ className }) {
1920
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1921
+ className,
1922
+ width: "12",
1923
+ height: "12",
1924
+ viewBox: "0 0 12 12",
1925
+ fill: "none",
1926
+ "aria-hidden": "true",
1927
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1928
+ d: "M3 4.5L6 7.5L9 4.5",
1929
+ stroke: "currentColor",
1930
+ strokeWidth: "1.5",
1931
+ strokeLinecap: "round",
1932
+ strokeLinejoin: "round"
1933
+ })
1934
+ });
1935
+ }
1936
+ /** The plus glyph (14px default) for the inline add buttons. */
1937
+ function PlusIcon({ size = 14 }) {
1938
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("svg", {
1939
+ width: size,
1940
+ height: size,
1941
+ viewBox: "0 0 12 12",
1942
+ fill: "none",
1943
+ "aria-hidden": "true",
1944
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1945
+ d: "M6 2.25V9.75M2.25 6H9.75",
1946
+ stroke: "currentColor",
1947
+ strokeWidth: "1.5",
1948
+ strokeLinecap: "round"
1949
+ })
1950
+ });
1951
+ }
1952
+ /** The trash glyph (14px) for the row removals. */
1953
+ function TrashIcon() {
1954
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1955
+ width: "14",
1956
+ height: "14",
1957
+ viewBox: "0 0 12 12",
1958
+ fill: "none",
1959
+ "aria-hidden": "true",
1960
+ children: [
1961
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1962
+ d: "M2.5 3.5H9.5",
1963
+ stroke: "currentColor",
1964
+ strokeWidth: "1.2",
1965
+ strokeLinecap: "round"
1966
+ }),
1967
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1968
+ 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",
1969
+ stroke: "currentColor",
1970
+ strokeWidth: "1.2",
1971
+ strokeLinecap: "round"
1972
+ }),
1973
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1974
+ 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",
1975
+ stroke: "currentColor",
1976
+ strokeWidth: "1.2",
1977
+ strokeLinecap: "round"
1978
+ }),
1979
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("path", {
1980
+ d: "M5.1 5.4V8.4M6.9 5.4V8.4",
1981
+ stroke: "currentColor",
1982
+ strokeWidth: "1.2",
1983
+ strokeLinecap: "round"
1984
+ })
1985
+ ]
1986
+ });
1987
+ }
1988
+ /** The vertical grip (⋮) for the slot-row drag handle. */
1989
+ function GripIcon() {
1990
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("svg", {
1991
+ width: "12",
1992
+ height: "12",
1993
+ viewBox: "0 0 12 12",
1994
+ fill: "none",
1995
+ "aria-hidden": "true",
1996
+ children: [
1997
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
1998
+ cx: "6",
1999
+ cy: "2.4",
2000
+ r: "0.95",
2001
+ fill: "currentColor"
2002
+ }),
2003
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
2004
+ cx: "6",
2005
+ cy: "6",
2006
+ r: "0.95",
2007
+ fill: "currentColor"
2008
+ }),
2009
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("circle", {
2010
+ cx: "6",
2011
+ cy: "9.6",
2012
+ r: "0.95",
2013
+ fill: "currentColor"
2014
+ })
2015
+ ]
2016
+ });
2017
+ }
1948
2018
  /** IANA timezone of this renderer (browser / host). */
1949
2019
  function hostTimeZone() {
1950
2020
  try {
@@ -2001,7 +2071,6 @@ window.__ModuleLoader__.load({
2001
2071
  /** Split scalars from the row editors (rootChain / role entities / role rules). */
2002
2072
  function scalarsOf(config) {
2003
2073
  return {
2004
- enabled: config.enabled,
2005
2074
  triggerCodes: [...config.triggerCodes],
2006
2075
  cooldownMs: config.cooldownMs,
2007
2076
  revertPolicy: config.revertPolicy,
@@ -2039,7 +2108,6 @@ window.__ModuleLoader__.load({
2039
2108
  const trailingChain = rowsToRootChain([allDayChainRow]);
2040
2109
  const tz = resolvedSlotTz(timeSlotRows, scalars.tz);
2041
2110
  return {
2042
- enabled: scalars.enabled,
2043
2111
  triggerCodes: [...scalars.triggerCodes],
2044
2112
  rootChain: allDayModel === "" ? [...acceptedRootChain] : [...trailingChain, allDayModel],
2045
2113
  roles: {
@@ -2056,14 +2124,6 @@ window.__ModuleLoader__.load({
2056
2124
  tz
2057
2125
  };
2058
2126
  }
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
2127
  /**
2068
2128
  * Badge label for one row's provenance (plan role-card-seeded-ux): every
2069
2129
  * row states where its seed state comes from. The three reserved labels
@@ -2088,22 +2148,26 @@ window.__ModuleLoader__.load({
2088
2148
  * (only reachable through the synthetic outside option — the dropdown
2089
2149
  * itself constrains normal edits), and illegal selector entries in
2090
2150
  * 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.
2151
+ * bucketed by the section that owns the offending field (主代理: allDay /
2152
+ * timeSlots / slot* / tz / default model / default chain; 子代理: role* /
2153
+ * rule*; 高级选项: trigger / cooldown / revert / always / roleAutoMatch —
2154
+ * the scalars are never validated, so the advanced bucket stays empty
2155
+ * today). A non-empty result is the Save disabled gate's `invalid` term —
2156
+ * the draft is never written while any bucket is non-empty. `persona` is
2157
+ * free text and never validated.
2098
2158
  *
2099
2159
  * `seedInfo` is the live trimmed-id → seed-entry map derived from
2100
2160
  * `state.seeds` (spec §9.4): the empty-chain block relaxes for seeded ids
2101
2161
  * 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.
2162
+ * design, R4, and the row must stay persistable); non-seeded behavior is
2163
+ * byte-identical.
2104
2164
  */
2105
2165
  function validateDraft(draft, t, seedInfo) {
2106
- const errors = emptyValidationErrors();
2166
+ const errors = {
2167
+ main: [],
2168
+ sub: [],
2169
+ advanced: []
2170
+ };
2107
2171
  const declaredIds = /* @__PURE__ */ new Set();
2108
2172
  for (const role of draft.roles.list) {
2109
2173
  if (!ROLE_ID_PATTERN.test(role.id)) errors.sub.push(t("validation.roleIdFormat", { id: role.id }));
@@ -2158,11 +2222,12 @@ window.__ModuleLoader__.load({
2158
2222
  }
2159
2223
  /**
2160
2224
  * 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).
2225
+ * / duplicate) — drives the inline red border on the offending id input
2226
+ * (live: the border tracks the draft, matching the live Save disabled
2227
+ * gate). Derived once per render into a Set (qc3 F-3): a duplicate scan
2228
+ * inside the render loop would be O(N²) per row; here the whole derivation
2229
+ * is O(N) and each row's check is a single Set lookup. Selector errors stay
2230
+ * on the banner only (plan Task 3 inline-scope rule).
2166
2231
  */
2167
2232
  function collectInvalidRoleIds(rows) {
2168
2233
  const counts = /* @__PURE__ */ new Map();
@@ -2184,9 +2249,8 @@ window.__ModuleLoader__.load({
2184
2249
  }
2185
2250
  /**
2186
2251
  * 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).
2252
+ * inline red border on the start/end inputs (same derivation pattern as
2253
+ * {@link collectInvalidRoleIds}: one pass per render, index lookup per row).
2190
2254
  */
2191
2255
  function collectInvalidSlotRows(rows) {
2192
2256
  const invalid = /* @__PURE__ */ new Set();
@@ -2204,12 +2268,13 @@ window.__ModuleLoader__.load({
2204
2268
  } : void 0;
2205
2269
  }
2206
2270
  /**
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.
2271
+ * Inline "!" info badge (T3): the detailed explanation rides a CSS
2272
+ * `data-tip` bubble (the card's self-drawn tooltip pattern — T4 replaces
2273
+ * the primitives Tooltip; anchored to the RIGHT of the badge, the original
2274
+ * primitives side="right" contract) while the short inline hint stays on
2275
+ * the row. The badge is an exposed, focusable image — the Models page
2276
+ * credential-status pattern (role="img" + aria-label) — so the accessible
2277
+ * name is always available; the bubble is a progressive enhancement on top.
2213
2278
  *
2214
2279
  * `disabled` mirrors the read-only/loading suppression of the surrounding
2215
2280
  * controls: the bubble is suppressed, the badge drops out of the tab order
@@ -2222,18 +2287,13 @@ window.__ModuleLoader__.load({
2222
2287
  * label-activation default action to cancel.
2223
2288
  */
2224
2289
  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
- })
2290
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2291
+ className: disabled ? `${FallbacksCard_module_css_default.infoHint} ${FallbacksCard_module_css_default.infoHintDisabled}` : FallbacksCard_module_css_default.infoHint,
2292
+ role: "img",
2293
+ "aria-label": label,
2294
+ "data-tip": label,
2295
+ tabIndex: disabled ? -1 : 0,
2296
+ children: "!"
2237
2297
  });
2238
2298
  }
2239
2299
  /**
@@ -2361,17 +2421,16 @@ window.__ModuleLoader__.load({
2361
2421
  "data-tip": t("chains.selector.remove"),
2362
2422
  "aria-label": t("chains.selector.remove"),
2363
2423
  onClick: onRemove,
2364
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconTrashOutlineMedium, {})
2424
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrashIcon, {})
2365
2425
  })
2366
2426
  })
2367
2427
  ]
2368
2428
  });
2369
2429
  }
2370
2430
  /**
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).
2431
+ * Render the Fallbacks settings card inside the plugin-config section —
2432
+ * flat: the notices, the form, and the footer tile directly under the
2433
+ * page's plugin title/description, with no chrome of our own.
2375
2434
  * @param props - slot-delivered injected dependencies and the synthesized t seat.
2376
2435
  * @returns the card.
2377
2436
  */
@@ -2390,14 +2449,10 @@ window.__ModuleLoader__.load({
2390
2449
  const [roleRows, setRoleRows] = (0, react.useState)(() => rolesToRows(defaultFallbacksConfig.roles.list));
2391
2450
  const [ruleRows, setRuleRows] = (0, react.useState)(() => rulesToRows(defaultFallbacksConfig.roles.rules));
2392
2451
  const [presetToAdd, setPresetToAdd] = (0, react.useState)("");
2393
- const [validationErrors, setValidationErrors] = (0, react.useState)(emptyValidationErrors);
2394
- const [validationAttempted, setValidationAttempted] = (0, react.useState)(false);
2395
- const [lastSaveSection, setLastSaveSection] = (0, react.useState)(null);
2396
2452
  const seededConfigKey = (0, react.useRef)(null);
2397
2453
  const draft = assembleConfig(scalars, allDayModel, state.config.rootChain, allDayChainRow, roleRows, ruleRows, state.config.roles.list, state.config.presets, scalars.roleAutoMatch, timeSlotRows);
2398
2454
  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 ?? []]);
2455
+ const mainDirty = JSON.stringify([...draft.rootChain, draft.timeSlots]) !== JSON.stringify([...state.config.rootChain, state.config.timeSlots ?? []]);
2401
2456
  const subDirty = hasEmptyRuleRows || JSON.stringify(draft.roles) !== JSON.stringify(state.config.roles);
2402
2457
  const advancedDirty = JSON.stringify([
2403
2458
  draft.triggerCodes,
@@ -2430,7 +2485,6 @@ window.__ModuleLoader__.load({
2430
2485
  setTimeSlotRows(timeSlotsToRows(state.config.timeSlots ?? [], catalog));
2431
2486
  setScalars((prev) => ({
2432
2487
  ...prev,
2433
- enabled: state.config.enabled,
2434
2488
  tz: state.config.tz ?? "Asia/Shanghai"
2435
2489
  }));
2436
2490
  }
@@ -2643,11 +2697,6 @@ window.__ModuleLoader__.load({
2643
2697
  return next;
2644
2698
  });
2645
2699
  };
2646
- const allValidationErrors = [
2647
- ...validationErrors.main,
2648
- ...validationErrors.sub,
2649
- ...validationErrors.advanced
2650
- ];
2651
2700
  const saving = state.status === "saving";
2652
2701
  const writable = state.writable;
2653
2702
  const unknownCodes = scalars.triggerCodes.filter((code) => !KNOWN_TRIGGER_CODES.includes(code));
@@ -2656,13 +2705,15 @@ window.__ModuleLoader__.load({
2656
2705
  const slotState = resolveSlotState(state.config, /* @__PURE__ */ new Date(), scalars.tz);
2657
2706
  const activeSlotIndex = slotState.winner === "all-day" ? -1 : state.config.timeSlots?.indexOf(slotState.winner) ?? -1;
2658
2707
  const roleOptions = ruleRoleOptions({ list: roleRows });
2659
- const invalidRoleIds = validationAttempted ? collectInvalidRoleIds(roleRows) : null;
2660
- const invalidSlotRows = validationAttempted ? collectInvalidSlotRows(timeSlotRows) : null;
2708
+ const invalidRoleIds = collectInvalidRoleIds(roleRows);
2709
+ const invalidSlotRows = collectInvalidSlotRows(timeSlotRows);
2661
2710
  const seedInfo = /* @__PURE__ */ new Map();
2662
2711
  for (const seed of state.seeds) seedInfo.set(seed.id.trim(), {
2663
2712
  overridden: seed.overridden,
2664
2713
  source: seed.source
2665
2714
  });
2715
+ const liveErrors = validateDraft(draft, t, seedInfo);
2716
+ const invalid = hasEmptyRuleRows || liveErrors.main.length > 0 || liveErrors.sub.length > 0 || liveErrors.advanced.length > 0;
2666
2717
  const latestSwitch = state.switches[0];
2667
2718
  let switchesLine;
2668
2719
  if (state.switchesStatus === "error") switchesLine = t("status.switches.error", { message: state.switchesError });
@@ -2711,1493 +2762,1217 @@ window.__ModuleLoader__.load({
2711
2762
  mainDirty,
2712
2763
  subDirty
2713
2764
  ]);
2714
- const sectionPatch = (section) => {
2715
- const base = {
2716
- ...state.config,
2717
- enabled: scalars.enabled
2718
- };
2719
- switch (section) {
2720
- case "main": return {
2721
- ...base,
2722
- rootChain: draft.rootChain,
2723
- timeSlots: draft.timeSlots,
2724
- tz: draft.tz
2725
- };
2726
- case "sub": return {
2727
- ...base,
2728
- roles: draft.roles
2729
- };
2730
- case "advanced": return {
2731
- ...base,
2732
- triggerCodes: draft.triggerCodes,
2733
- cooldownMs: draft.cooldownMs,
2734
- revertPolicy: draft.revertPolicy,
2735
- maxSwitchesPerStep: draft.maxSwitchesPerStep,
2736
- alwaysModeRetryCap: draft.alwaysModeRetryCap,
2737
- roleAutoMatch: draft.roleAutoMatch
2738
- };
2739
- }
2740
- };
2741
- const save = (section) => {
2742
- 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
- controller.save(sectionPatch(section));
2753
- };
2754
- const saveEnabled = () => {
2755
- setLastSaveSection("main");
2756
- setValidationErrors(emptyValidationErrors());
2757
- setValidationAttempted(false);
2758
- controller.save({
2759
- ...state.config,
2760
- enabled: scalars.enabled
2761
- });
2765
+ const save = () => {
2766
+ controller.save(draft);
2762
2767
  };
2763
- const discardSection = (section) => {
2764
- switch (section) {
2765
- case "main":
2766
- setAllDayModel(allDayModelOf(state.config.rootChain));
2767
- setAllDayChainRow(allDayChainRowOf(state.config.rootChain, catalogOf(state)));
2768
- setTimeSlotRows(timeSlotsToRows(state.config.timeSlots ?? [], catalogOf(state)));
2769
- setScalars((prev) => ({
2770
- ...prev,
2771
- enabled: state.config.enabled,
2772
- tz: state.config.tz ?? "Asia/Shanghai"
2773
- }));
2774
- break;
2775
- case "sub":
2776
- setRoleRows(rolesToRows(state.config.roles.list, catalogOf(state)));
2777
- setRuleRows(rulesToRows(state.config.roles.rules, catalogOf(state)));
2778
- break;
2779
- case "advanced": setScalars((prev) => ({
2780
- ...prev,
2781
- triggerCodes: [...state.config.triggerCodes],
2782
- cooldownMs: state.config.cooldownMs,
2783
- revertPolicy: state.config.revertPolicy,
2784
- maxSwitchesPerStep: state.config.maxSwitchesPerStep,
2785
- alwaysModeRetryCap: state.config.alwaysModeRetryCap,
2786
- roleAutoMatch: state.config.roleAutoMatch
2787
- }));
2788
- }
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);
2768
+ const discard = () => {
2769
+ const catalog = catalogOf(state);
2770
+ setAllDayModel(allDayModelOf(state.config.rootChain));
2771
+ setAllDayChainRow(allDayChainRowOf(state.config.rootChain, catalog));
2772
+ setTimeSlotRows(timeSlotsToRows(state.config.timeSlots ?? [], catalog));
2773
+ setRoleRows(rolesToRows(state.config.roles.list, catalog));
2774
+ setRuleRows(rulesToRows(state.config.roles.rules, catalog));
2775
+ setScalars(scalarsOf(state.config));
2799
2776
  };
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
- (0, react.useEffect)(() => {
2814
- if (state.status === "ready") setLastSaveSection(null);
2815
- }, [state.status]);
2816
- const [userOpen, setUserOpen] = (0, react.useState)(false);
2817
- const [advancedOpen, setAdvancedOpen] = (0, react.useState)(false);
2818
2777
  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;
2778
+ if (state.status === "ready") degradedLatch.current = !state.present;
2824
2779
  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
- },
2780
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2781
+ className: FallbacksCard_module_css_default.root,
2836
2782
  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")
2783
+ state.legacyKeys.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2784
+ className: FallbacksCard_module_css_default.legacyNotice,
2785
+ role: "status",
2786
+ children: t("legacy.banner", { keys: state.legacyKeys.join(", ") })
2787
+ }),
2788
+ state.status === "error" && state.error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2789
+ className: FallbacksCard_module_css_default.noticeRow,
2790
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2791
+ className: FallbacksCard_module_css_default.error,
2792
+ role: "alert",
2793
+ children: t("error.generic", { message: state.error })
2794
+ }), !state.writable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2795
+ type: "button",
2796
+ className: FallbacksCard_module_css_default.outlineButton,
2797
+ onClick: () => {
2798
+ controller.load();
2799
+ },
2800
+ children: t("retry")
2845
2801
  })]
2846
2802
  }),
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", {
2803
+ degraded && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2804
+ className: FallbacksCard_module_css_default.notice,
2805
+ role: "status",
2806
+ children: t("unavailable")
2807
+ }),
2808
+ state.status === "ready" && !state.writable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2809
+ className: FallbacksCard_module_css_default.readOnly,
2810
+ role: "status",
2811
+ children: t("readOnly")
2812
+ }),
2813
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("fieldset", {
2814
+ className: FallbacksCard_module_css_default.fieldset,
2815
+ disabled: !writable,
2816
+ children: [
2817
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2818
+ className: FallbacksCard_module_css_default.sectionHeading,
2819
+ id: "fallbacks-main-agent",
2820
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2821
+ className: FallbacksCard_module_css_default.sectionHeadingText,
2822
+ children: t("mainAgent.label")
2823
+ })
2824
+ }),
2825
+ liveErrors.main.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
2867
2826
  className: FallbacksCard_module_css_default.error,
2868
2827
  role: "alert",
2869
- 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")
2828
+ children: `${t("validation.blocked")}${liveErrors.main.join("; ")}`
2829
+ }),
2830
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2831
+ className: FallbacksCard_module_css_default.field,
2832
+ role: "group",
2833
+ "aria-labelledby": "fallbacks-time-slots",
2834
+ children: [
2835
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2836
+ className: FallbacksCard_module_css_default.fieldLabel,
2837
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2838
+ id: "fallbacks-time-slots",
2839
+ children: t("timeSlots.label")
2840
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
2841
+ label: t("timeSlots.tooltip"),
2842
+ disabled: !writable
2908
2843
  })]
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
2844
  }),
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 })
2845
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2846
+ className: FallbacksCard_module_css_default.hint,
2847
+ children: t("timeSlots.hint")
2936
2848
  }),
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
2849
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2850
+ className: FallbacksCard_module_css_default.list,
2851
+ children: timeSlotRows.map((row, index) => {
2852
+ const invalidWindow = invalidSlotRows.has(index);
2853
+ const chainEmpty = row.selectors.every((selector) => selectorRowToRaw(selector) === "");
2854
+ const firstModel = row.selectors.map(selectorRowToRaw).find((entry) => entry !== "");
2855
+ const slotExpanded = !row.collapsed || !writable;
2856
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2857
+ className: `${FallbacksCard_module_css_default.editorCard} ${draggedSlotIndex === index ? FallbacksCard_module_css_default.slotCardDragging : ""} ${overSlotIndex === index && draggedSlotIndex !== null && draggedSlotIndex !== index ? FallbacksCard_module_css_default.slotCardOver : ""}`,
2858
+ onDragOver: (event) => {
2859
+ if (draggedSlotIndex === null) return;
2860
+ event.preventDefault();
2861
+ if (overSlotIndex !== index) setOverSlotIndex(index);
2862
+ },
2863
+ onDrop: (event) => {
2864
+ event.preventDefault();
2865
+ const from = draggedSlotIndex;
2866
+ setDraggedSlotIndex(null);
2867
+ setOverSlotIndex(null);
2868
+ if (from !== null && from !== index) reorderTimeSlotRow(from, index);
2869
+ },
2870
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2871
+ className: FallbacksCard_module_css_default.collapseRow,
2872
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
2873
+ type: "button",
2874
+ className: FallbacksCard_module_css_default.collapseToggle,
2875
+ "aria-expanded": slotExpanded,
2876
+ "aria-label": t(slotExpanded ? "timeSlots.collapse" : "timeSlots.expand"),
2877
+ disabled: !writable,
2878
+ onClick: () => {
2879
+ updateTimeSlotRow(index, { collapsed: !row.collapsed });
2880
+ },
2881
+ children: [
2882
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDownIcon, { className: slotExpanded ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron }),
2883
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2884
+ className: FallbacksCard_module_css_default.collapseTitle,
2885
+ children: row.kind === "preset" ? t(`timeSlots.preset.${row.preset}.label`) : row.name !== "" ? row.name : `custom ${row.start}-${row.end}`
2886
+ }),
2887
+ 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", {
2888
+ className: `${FallbacksCard_module_css_default.slotTag} ${FallbacksCard_module_css_default.slotTagHighCost}`,
2889
+ children: t("timeSlots.preset.highCost")
2890
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2891
+ className: `${FallbacksCard_module_css_default.slotTag} ${FallbacksCard_module_css_default.slotTagMultiplier}`,
2892
+ children: t("timeSlots.preset.multiplier", { n: row.preset === "liang-peak" ? "2" : "3" })
2893
+ })] }),
2894
+ activeSlotIndex === index && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2895
+ className: `${FallbacksCard_module_css_default.slotTag} ${FallbacksCard_module_css_default.slotTagActive}`,
2896
+ children: t("timeSlots.active")
2897
+ }),
2898
+ firstModel !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2899
+ className: FallbacksCard_module_css_default.collapseMeta,
2900
+ children: firstModel
2901
+ })
2902
+ ]
2903
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2904
+ type: "button",
2905
+ className: FallbacksCard_module_css_default.dragHandle,
2906
+ draggable: writable,
2907
+ "data-tip": t("timeSlots.drag"),
2908
+ "aria-label": t("timeSlots.drag"),
2909
+ disabled: !writable,
2910
+ onDragStart: () => {
2911
+ if (!writable) return;
2912
+ setDraggedSlotIndex(index);
2913
+ setOverSlotIndex(index);
2914
+ },
2915
+ onDragEnd: () => {
2916
+ setDraggedSlotIndex(null);
2917
+ setOverSlotIndex(null);
2918
+ },
2919
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GripIcon, {})
3008
2920
  })]
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
- },
2921
+ }), slotExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2922
+ row.kind === "preset" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2923
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2924
+ className: FallbacksCard_module_css_default.ruleGrid,
3035
2925
  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 })
2926
+ className: FallbacksCard_module_css_default.ruleCell,
2927
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2928
+ className: FallbacksCard_module_css_default.ruleCellLabel,
2929
+ children: t("timeSlots.preset.name")
2930
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2931
+ className: FallbacksCard_module_css_default.slotPresetName,
2932
+ children: t(`timeSlots.preset.${row.preset}.label`)
3085
2933
  })]
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", {
2934
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2935
+ className: FallbacksCard_module_css_default.ruleCell,
2936
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2937
+ className: FallbacksCard_module_css_default.ruleCellLabel,
2938
+ children: t("timeSlots.preset.windowLabel")
2939
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3213
2940
  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);
2941
+ children: t(`timeSlots.preset.${row.preset}.window`)
2942
+ })]
3307
2943
  })]
3308
2944
  }),
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")
2945
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2946
+ className: FallbacksCard_module_css_default.hint,
2947
+ children: t("timeSlots.preset.chainsOnly")
3316
2948
  }),
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")
2949
+ (row.preset === "glm-peak" || row.preset === "glm-valley") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2950
+ className: FallbacksCard_module_css_default.hint,
2951
+ children: t("timeSlots.preset.glm.note")
3324
2952
  })
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,
2953
+ ] }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
2954
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2955
+ className: FallbacksCard_module_css_default.field,
2956
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2957
+ className: FallbacksCard_module_css_default.ruleCellLabel,
2958
+ children: t("timeSlots.name")
2959
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2960
+ className: FallbacksCard_module_css_default.input,
2961
+ value: row.name,
2962
+ placeholder: t("timeSlots.name"),
2963
+ "aria-label": t("timeSlots.name"),
3366
2964
  disabled: !writable,
3367
- t,
3368
- onChange: (patch) => {
3369
- updateAllDayChainSelector(selectorIndex, patch);
3370
- },
3371
- onRemove: () => {
3372
- removeAllDayChainSelector(selectorIndex);
2965
+ onChange: (event) => {
2966
+ updateTimeSlotRow(index, { name: event.target.value });
3373
2967
  }
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"),
2968
+ })]
2969
+ }),
2970
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2971
+ className: FallbacksCard_module_css_default.field,
2972
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2973
+ className: FallbacksCard_module_css_default.ruleCellLabel,
2974
+ children: t("timeSlots.tz.label")
2975
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2976
+ className: FallbacksCard_module_css_default.hint,
2977
+ "aria-label": t("timeSlots.tz.label"),
2978
+ children: tzDisplayLabel(presetsPresent ? "Asia/Shanghai" : hostTimeZone())
2979
+ })]
2980
+ }),
2981
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2982
+ className: FallbacksCard_module_css_default.ruleGrid,
2983
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2984
+ className: FallbacksCard_module_css_default.ruleCell,
2985
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2986
+ className: FallbacksCard_module_css_default.ruleCellLabel,
2987
+ children: t("timeSlots.start")
2988
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
2989
+ className: `${FallbacksCard_module_css_default.input} ${invalidWindow ? FallbacksCard_module_css_default.inputInvalid : ""}`,
2990
+ value: row.start,
2991
+ placeholder: "09:00",
2992
+ "aria-label": t("timeSlots.start"),
3532
2993
  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
- })
2994
+ onChange: (event) => {
2995
+ updateTimeSlotRow(index, { start: event.target.value });
2996
+ }
2997
+ })]
2998
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2999
+ className: FallbacksCard_module_css_default.ruleCell,
3000
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3001
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3002
+ children: t("timeSlots.end")
3003
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3004
+ className: `${FallbacksCard_module_css_default.input} ${invalidWindow ? FallbacksCard_module_css_default.inputInvalid : ""}`,
3005
+ value: row.end,
3006
+ placeholder: "18:00",
3007
+ "aria-label": t("timeSlots.end"),
3008
+ disabled: !writable,
3009
+ onChange: (event) => {
3010
+ updateTimeSlotRow(index, { end: event.target.value });
3011
+ }
3012
+ })]
3013
+ })]
3014
+ }),
3015
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3016
+ className: FallbacksCard_module_css_default.field,
3017
+ children: [
3018
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3019
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3020
+ children: t("timeSlots.days")
3580
3021
  }),
3581
3022
  /* @__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"),
3023
+ className: FallbacksCard_module_css_default.dayRow,
3024
+ children: SLOT_WEEKDAYS.map((day, dayIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3025
+ className: FallbacksCard_module_css_default.dayCell,
3026
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3027
+ type: "checkbox",
3028
+ checked: row.days.includes(dayIndex),
3594
3029
  disabled: !writable,
3595
- onChange: (event) => {
3596
- updateRoleRow(index, { persona: event.target.value });
3030
+ onChange: () => {
3031
+ updateTimeSlotRow(index, { days: row.days.includes(dayIndex) ? row.days.filter((existing) => existing !== dayIndex) : [...row.days, dayIndex] });
3597
3032
  }
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
- })]
3033
+ }), t(`timeSlots.day.${day}`)]
3034
+ }, day))
3645
3035
  }),
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
- })
3036
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3037
+ className: FallbacksCard_module_css_default.hint,
3038
+ children: t("timeSlots.days.hint")
3039
+ })
3040
+ ]
3041
+ }),
3042
+ (row.start !== "" || row.end !== "") && !(HHMM_RE.test(row.start) && HHMM_RE.test(row.end)) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3043
+ className: FallbacksCard_module_css_default.hint,
3044
+ children: t("validation.slotWindow")
3045
+ })
3046
+ ] }),
3047
+ chainEmpty && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3048
+ className: FallbacksCard_module_css_default.hint,
3049
+ children: t("validation.slotChainRequired")
3050
+ }),
3051
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3052
+ className: FallbacksCard_module_css_default.chainSelectors,
3053
+ children: row.selectors.map((selector, selectorIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
3054
+ selector,
3055
+ catalog: catalogOf(state),
3056
+ configuredProviders: state.configuredProviders,
3057
+ disabled: !writable,
3058
+ t,
3059
+ onChange: (patch) => {
3060
+ updateTimeSlotSelector(index, selectorIndex, patch);
3061
+ },
3062
+ onRemove: () => {
3063
+ removeTimeSlotSelector(index, selectorIndex);
3064
+ }
3065
+ }, selectorIndex))
3066
+ }),
3067
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3068
+ type: "button",
3069
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3070
+ disabled: !writable,
3071
+ onClick: () => {
3072
+ addTimeSlotSelector(index);
3073
+ },
3074
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("timeSlots.selector.add")]
3075
+ }),
3076
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3077
+ className: FallbacksCard_module_css_default.cardFoot,
3078
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3079
+ className: FallbacksCard_module_css_default.rowActions,
3080
+ children: [
3081
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3082
+ type: "button",
3083
+ className: FallbacksCard_module_css_default.iconButton,
3084
+ "data-tip": t("timeSlots.moveUp"),
3085
+ "aria-label": t("timeSlots.moveUp"),
3086
+ disabled: !writable || index === 0,
3087
+ onClick: () => {
3088
+ moveTimeSlotRow(index, -1);
3089
+ },
3090
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDownIcon, { className: FallbacksCard_module_css_default.chevronFlip })
3670
3091
  }),
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,
3092
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3093
+ type: "button",
3094
+ className: FallbacksCard_module_css_default.iconButton,
3095
+ "data-tip": t("timeSlots.moveDown"),
3096
+ "aria-label": t("timeSlots.moveDown"),
3097
+ disabled: !writable || index === timeSlotRows.length - 1,
3676
3098
  onClick: () => {
3677
- addRoleSelector(index);
3099
+ moveTimeSlotRow(index, 1);
3678
3100
  },
3679
- children: t("roles.selector.add")
3101
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDownIcon, {})
3680
3102
  }),
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
- })
3103
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3104
+ type: "button",
3105
+ className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger}`,
3106
+ "data-tip": t("timeSlots.remove"),
3107
+ "aria-label": t("timeSlots.remove"),
3108
+ onClick: () => {
3109
+ removeTimeSlotRow(index);
3110
+ },
3111
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrashIcon, {})
3693
3112
  })
3694
- ] })]
3695
- }, index);
3113
+ ]
3114
+ })
3696
3115
  })
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,
3116
+ ] })]
3117
+ }, index);
3118
+ })
3119
+ }),
3120
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3121
+ className: FallbacksCard_module_css_default.slotAddRow,
3122
+ children: [
3123
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3124
+ className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
3125
+ value: presetToAdd,
3126
+ "aria-label": t("timeSlots.presetPlaceholder"),
3127
+ disabled: !writable,
3128
+ onChange: (event) => {
3129
+ setPresetToAdd(event.target.value);
3130
+ },
3131
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3132
+ value: "",
3133
+ children: t("timeSlots.presetPlaceholder")
3134
+ }), SLOT_PRESET_IDS.filter((id) => !timeSlotRows.some((row) => row.kind === "preset" && row.preset === id)).map((id) => {
3135
+ const glmUnconfigured = !glmConfigured && (id === "glm-peak" || id === "glm-valley");
3136
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("option", {
3137
+ value: id,
3138
+ disabled: glmUnconfigured,
3139
+ children: [t(`timeSlots.preset.${id}.label`), glmUnconfigured ? t("timeSlots.preset.glm.unconfigured") : null]
3140
+ }, id);
3141
+ })]
3142
+ }),
3143
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3144
+ type: "button",
3145
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3146
+ disabled: !writable || presetToAdd === "",
3147
+ onClick: addPresetSlotRow,
3148
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("timeSlots.addPreset")]
3149
+ }),
3150
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3151
+ type: "button",
3152
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3153
+ disabled: !writable,
3154
+ onClick: addCustomSlotRow,
3155
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("timeSlots.addCustom")]
3156
+ })
3157
+ ]
3158
+ })
3159
+ ]
3160
+ }),
3161
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3162
+ className: FallbacksCard_module_css_default.field,
3163
+ role: "group",
3164
+ "aria-labelledby": "fallbacks-root-chain",
3165
+ children: [
3166
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3167
+ className: FallbacksCard_module_css_default.fieldLabel,
3168
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3169
+ id: "fallbacks-root-chain",
3170
+ children: t("rootChain.label")
3171
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3172
+ label: t("rootChain.tooltip"),
3173
+ disabled: !writable
3174
+ })]
3175
+ }),
3176
+ state.catalogStatus === "error" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3177
+ className: FallbacksCard_module_css_default.hint,
3178
+ children: t("catalog.error", { message: state.catalogError })
3179
+ }),
3180
+ state.catalogStatus === "ready" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3181
+ className: FallbacksCard_module_css_default.hint,
3182
+ children: t("catalog.partial", { message: state.catalogError })
3183
+ }),
3184
+ state.catalogStatus === "ready" && (state.groups.length === 0 || state.configuredProviders.length === 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3185
+ className: FallbacksCard_module_css_default.hint,
3186
+ children: t("catalog.empty")
3187
+ }),
3188
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3189
+ className: FallbacksCard_module_css_default.list,
3190
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3191
+ className: FallbacksCard_module_css_default.editorCard,
3192
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3193
+ className: FallbacksCard_module_css_default.chainSelectors,
3194
+ children: allDayChainRow.selectors.map((selector, selectorIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
3195
+ selector,
3196
+ catalog: catalogOf(state),
3197
+ configuredProviders: state.configuredProviders,
3198
+ disabled: !writable,
3199
+ t,
3200
+ onChange: (patch) => {
3201
+ updateAllDayChainSelector(selectorIndex, patch);
3202
+ },
3203
+ onRemove: () => {
3204
+ removeAllDayChainSelector(selectorIndex);
3205
+ }
3206
+ }, selectorIndex))
3207
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3208
+ type: "button",
3209
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3210
+ disabled: !writable,
3211
+ onClick: addAllDayChainSelector,
3212
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("timeSlots.selector.add")]
3213
+ })]
3214
+ })
3215
+ })
3216
+ ]
3217
+ }),
3218
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3219
+ className: FallbacksCard_module_css_default.field,
3220
+ role: "group",
3221
+ "aria-labelledby": "fallbacks-default-model",
3222
+ children: [
3223
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3224
+ className: FallbacksCard_module_css_default.fieldLabel,
3225
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3226
+ id: "fallbacks-default-model",
3227
+ children: t("defaultModel.label")
3228
+ })
3229
+ }),
3230
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3231
+ className: FallbacksCard_module_css_default.hint,
3232
+ children: t("allDay.hint")
3233
+ }),
3234
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3235
+ className: FallbacksCard_module_css_default.list,
3236
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3237
+ className: FallbacksCard_module_css_default.editorCard,
3238
+ children: [OFFICIAL_ALL_DAY_IDS.map((id, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3239
+ className: FallbacksCard_module_css_default.optionRow,
3240
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3241
+ type: "radio",
3242
+ name: "fallbacks-all-day",
3243
+ checked: allDayModel === id,
3244
+ disabled: !writable,
3245
+ onChange: () => {
3246
+ setAllDayModel(id);
3247
+ }
3248
+ }), t(ALL_DAY_LABEL_KEYS[index])]
3249
+ }, id)), allDayModel === "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3250
+ className: FallbacksCard_module_css_default.hint,
3251
+ children: t("allDay.nonconforming")
3252
+ })]
3253
+ })
3254
+ })
3255
+ ]
3256
+ }),
3257
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3258
+ className: FallbacksCard_module_css_default.sectionHeading,
3259
+ id: "fallbacks-subagents",
3260
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3261
+ className: FallbacksCard_module_css_default.sectionHeadingText,
3262
+ children: t("subagents.label")
3263
+ })
3264
+ }),
3265
+ liveErrors.sub.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3266
+ className: FallbacksCard_module_css_default.error,
3267
+ role: "alert",
3268
+ children: `${t("validation.blocked")}${liveErrors.sub.join("; ")}`
3269
+ }),
3270
+ state.subagentPolicy?.state === "enabled" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3271
+ className: FallbacksCard_module_css_default.policyStatus,
3272
+ role: "status",
3273
+ children: [
3274
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3275
+ className: FallbacksCard_module_css_default.policyStatusLabel,
3276
+ children: t("subagents.policy.label")
3277
+ }),
3278
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3279
+ className: FallbacksCard_module_css_default.policyStatusLine,
3280
+ children: `${t("subagents.policy.allowlist")}: ${state.subagentPolicy.allowedModels.map((route) => `${route.provider}/${route.model}`).join(", ")}`
3281
+ }),
3282
+ state.subagentPolicy.head !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3283
+ className: FallbacksCard_module_css_default.policyStatusLine,
3284
+ 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")})`
3285
+ }),
3286
+ state.subagentPolicy.blockedAttempt !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3287
+ className: FallbacksCard_module_css_default.policyStatusWarn,
3288
+ role: "alert",
3289
+ children: t("subagents.policy.blocked")
3290
+ })
3291
+ ]
3292
+ }),
3293
+ state.subagentPolicy?.state === "unprovable" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3294
+ className: FallbacksCard_module_css_default.policyStatus,
3295
+ role: "status",
3296
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3297
+ className: FallbacksCard_module_css_default.policyStatusWarn,
3298
+ role: "alert",
3299
+ children: t("subagents.policy.unprovable")
3300
+ })
3301
+ }),
3302
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3303
+ className: FallbacksCard_module_css_default.field,
3304
+ role: "group",
3305
+ "aria-labelledby": "fallbacks-roles-list",
3306
+ children: [
3307
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3308
+ className: FallbacksCard_module_css_default.fieldLabel,
3309
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3310
+ id: "fallbacks-roles-list",
3311
+ children: t("roles.list.label")
3312
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3313
+ label: t("roles.list.tooltip"),
3314
+ disabled: !writable
3315
+ })]
3316
+ }),
3317
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3318
+ className: FallbacksCard_module_css_default.hint,
3319
+ children: t("roles.list.hint")
3320
+ }),
3321
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3322
+ className: FallbacksCard_module_css_default.list,
3323
+ children: roleRows.map((row, index) => {
3324
+ const invalid = invalidRoleIds.has(row.id.trim());
3325
+ const seed = seedInfo.get(row.id.trim());
3326
+ const seedBadge = seedBadgeLabel(seed, t);
3327
+ const personaBlank = row.persona.trim() === "";
3328
+ const roleSummary = row.selectors.map(selectorRowToRaw).find((entry) => entry !== "") ?? row.fallback;
3329
+ const roleExpanded = !row.collapsed || !writable;
3330
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3331
+ className: FallbacksCard_module_css_default.editorCard,
3332
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3333
+ className: FallbacksCard_module_css_default.collapseRow,
3334
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3335
+ type: "button",
3336
+ className: FallbacksCard_module_css_default.collapseToggle,
3337
+ "aria-expanded": roleExpanded,
3338
+ "aria-label": t(roleExpanded ? "roles.collapse" : "roles.expand"),
3339
+ disabled: !writable,
3340
+ onClick: () => {
3341
+ updateRoleRow(index, { collapsed: !row.collapsed });
3342
+ },
3343
+ children: [
3344
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChevronDownIcon, { className: roleExpanded ? `${FallbacksCard_module_css_default.chevron} ${FallbacksCard_module_css_default.chevronOpen}` : FallbacksCard_module_css_default.chevron }),
3345
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3346
+ className: FallbacksCard_module_css_default.collapseTitle,
3347
+ children: row.id
3348
+ }),
3349
+ seedBadge !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3350
+ className: FallbacksCard_module_css_default.seedBadge,
3351
+ title: seedBadge,
3352
+ children: seedBadge
3353
+ }),
3354
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3355
+ className: FallbacksCard_module_css_default.collapseMeta,
3356
+ children: roleSummary
3357
+ })
3358
+ ]
3359
+ })
3360
+ }), roleExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
3361
+ seed === void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3362
+ className: FallbacksCard_module_css_default.ruleGrid,
3363
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3364
+ className: FallbacksCard_module_css_default.ruleCell,
3751
3365
  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
- ]
3366
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3367
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3368
+ children: t("roles.id")
3846
3369
  }),
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
- })]
3370
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3371
+ className: `${FallbacksCard_module_css_default.input} ${invalid ? FallbacksCard_module_css_default.inputInvalid : ""}`,
3372
+ value: row.id,
3373
+ placeholder: t("roles.idPlaceholder"),
3374
+ "aria-label": t("roles.id"),
3375
+ "aria-invalid": invalid ? true : void 0,
3376
+ disabled: !writable,
3377
+ onChange: (event) => {
3378
+ updateRoleRow(index, { id: event.target.value });
3379
+ }
3853
3380
  }),
3854
- row.role === "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3381
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3855
3382
  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
- })
3383
+ children: t("roles.id.hint")
3870
3384
  })
3871
3385
  ]
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
3386
+ })
3387
+ }),
3388
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3389
+ className: FallbacksCard_module_css_default.ruleGrid,
3390
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3391
+ className: FallbacksCard_module_css_default.ruleCell,
3392
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3393
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3394
+ children: t("roles.persona")
3395
+ }), seed === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("textarea", {
3396
+ rows: 3,
3397
+ className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.inputTextarea}`,
3398
+ value: row.persona,
3399
+ placeholder: t("roles.personaPlaceholder"),
3400
+ "aria-label": t("roles.persona"),
3401
+ disabled: !writable,
3402
+ onChange: (event) => {
3403
+ updateRoleRow(index, { persona: event.target.value });
3404
+ }
3405
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3406
+ className: FallbacksCard_module_css_default.personaBriefRow,
3407
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3408
+ className: personaBlank ? `${FallbacksCard_module_css_default.personaBrief} ${FallbacksCard_module_css_default.personaBriefEmpty}` : FallbacksCard_module_css_default.personaBrief,
3409
+ children: personaBlank ? t("roles.persona.empty") : row.persona
3410
+ }), !personaBlank && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3411
+ role: "button",
3412
+ tabIndex: 0,
3413
+ className: FallbacksCard_module_css_default.iconButton,
3414
+ "aria-expanded": row.personaOpen,
3415
+ "aria-label": t(row.personaOpen ? "roles.persona.collapse" : "roles.persona.expand"),
3416
+ "data-tip": t(row.personaOpen ? "roles.persona.collapse" : "roles.persona.expand"),
3417
+ onClick: () => {
3418
+ updateRoleRow(index, { personaOpen: !row.personaOpen });
3419
+ },
3420
+ onKeyDown: (event) => {
3421
+ if (event.key === "Enter" || event.key === " ") {
3422
+ event.preventDefault();
3423
+ updateRoleRow(index, { personaOpen: !row.personaOpen });
3424
+ }
3425
+ },
3426
+ 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
3427
  })]
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,
3428
+ }), row.personaOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3429
+ className: FallbacksCard_module_css_default.personaFull,
3430
+ children: row.persona
3431
+ })] })]
3432
+ })
3433
+ }),
3434
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3435
+ className: FallbacksCard_module_css_default.chainSelectors,
3436
+ children: [row.selectors.map((selector, selectorIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
3437
+ selector,
3438
+ catalog: catalogOf(state),
3439
+ configuredProviders: state.configuredProviders,
3935
3440
  disabled: !writable,
3936
- onChange: (event) => {
3937
- updateScalars((draft) => {
3938
- draft.roleAutoMatch = event.target.checked;
3939
- });
3441
+ t,
3442
+ onChange: (patch) => {
3443
+ updateRoleSelector(index, selectorIndex, patch);
3444
+ },
3445
+ onRemove: () => {
3446
+ removeRoleSelector(index, selectorIndex);
3940
3447
  }
3448
+ }, selectorIndex)), row.selectors.every((selector) => selectorRowToRaw(selector) === "") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3449
+ className: FallbacksCard_module_css_default.hint,
3450
+ children: seed !== void 0 ? t("roles.seedChainOptional", { id: row.id }) : t("validation.roleChainRequired", { id: row.id })
3941
3451
  })]
3942
3452
  }),
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
3453
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3454
+ className: FallbacksCard_module_css_default.ruleGrid,
3455
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3456
+ className: FallbacksCard_module_css_default.ruleCell,
3457
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3458
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3459
+ children: t("roles.fallback")
3460
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3461
+ className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
3462
+ value: row.fallback,
3463
+ "aria-label": t("roles.fallback"),
3464
+ disabled: !writable,
3465
+ onChange: (event) => {
3466
+ updateRoleRow(index, { fallback: event.target.value });
3467
+ },
3468
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3469
+ value: "inherit-root",
3470
+ children: t("roles.fallback.inherit-root")
3471
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3472
+ value: "none",
3473
+ children: t("roles.fallback.none")
3956
3474
  })]
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
- ]
3475
+ })]
3476
+ })
3979
3477
  }),
3478
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3479
+ type: "button",
3480
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3481
+ disabled: !writable,
3482
+ onClick: () => {
3483
+ addRoleSelector(index);
3484
+ },
3485
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("roles.selector.add")]
3486
+ }),
3487
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3488
+ className: FallbacksCard_module_css_default.cardFoot,
3489
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3490
+ type: "button",
3491
+ className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger}`,
3492
+ "data-tip": t("roles.remove"),
3493
+ "aria-label": t("roles.remove"),
3494
+ onClick: () => {
3495
+ removeRole(index);
3496
+ },
3497
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrashIcon, {})
3498
+ })
3499
+ })
3500
+ ] })]
3501
+ }, index);
3502
+ })
3503
+ }),
3504
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3505
+ type: "button",
3506
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3507
+ disabled: !writable,
3508
+ onClick: addRole,
3509
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("roles.add")]
3510
+ })
3511
+ ]
3512
+ }),
3513
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3514
+ className: FallbacksCard_module_css_default.field,
3515
+ role: "group",
3516
+ "aria-labelledby": "fallbacks-roles-rules",
3517
+ children: [
3518
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3519
+ className: FallbacksCard_module_css_default.fieldLabel,
3520
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3521
+ id: "fallbacks-roles-rules",
3522
+ children: t("roles.rules")
3523
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3524
+ label: t("roles.rules.tooltip"),
3525
+ disabled: !writable
3526
+ })]
3527
+ }),
3528
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3529
+ className: FallbacksCard_module_css_default.hint,
3530
+ children: t("roles.rules.hint")
3531
+ }),
3532
+ state.catalogStatus === "error" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3533
+ className: FallbacksCard_module_css_default.hint,
3534
+ children: t("catalog.error", { message: state.catalogError })
3535
+ }),
3536
+ state.catalogStatus === "ready" && state.catalogError !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3537
+ className: FallbacksCard_module_css_default.hint,
3538
+ children: t("catalog.partial", { message: state.catalogError })
3539
+ }),
3540
+ state.catalogStatus === "ready" && (state.groups.length === 0 || state.configuredProviders.length === 0) && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3541
+ className: FallbacksCard_module_css_default.hint,
3542
+ children: t("catalog.empty")
3543
+ }),
3544
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3545
+ className: FallbacksCard_module_css_default.list,
3546
+ children: ruleRows.map((row, index) => {
3547
+ const catalog = catalogOf(state);
3548
+ const providerRaw = selectionToRaw(row.provider);
3549
+ const group = catalog?.groups.find((entry) => entry.id === providerRaw);
3550
+ const providerOutside = row.provider?.kind === "outside";
3551
+ const providerUnconfigured = !providerOutside && providerRaw !== "" && (catalog?.providers.some((entry) => entry.provider === providerRaw) ?? false) && !state.configuredProviders.some((entry) => entry.provider === providerRaw);
3552
+ const modelOutside = row.model?.kind === "outside";
3553
+ const roleOutside = row.role !== "" && !roleOptions.includes(row.role);
3554
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3555
+ className: FallbacksCard_module_css_default.editorCard,
3556
+ children: [
3980
3557
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3981
- className: FallbacksCard_module_css_default.field,
3982
- role: "group",
3983
- "aria-labelledby": "fallbacks-revert-policy",
3558
+ className: FallbacksCard_module_css_default.ruleGrid,
3984
3559
  children: [
3985
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3986
- className: FallbacksCard_module_css_default.fieldLabel,
3560
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3561
+ className: FallbacksCard_module_css_default.ruleCell,
3987
3562
  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;
3563
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3564
+ children: t("roles.rule.provider")
3565
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3566
+ className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
3567
+ value: providerRaw,
3568
+ onChange: (event) => {
3569
+ if (event.target.value === providerRaw) return;
3570
+ updateRuleRow(index, {
3571
+ provider: classifyProvider(event.target.value, catalog),
3572
+ model: null
4008
3573
  });
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
- ]
3574
+ },
3575
+ children: [
3576
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3577
+ value: "",
3578
+ children: t("roles.rule.provider.any")
3579
+ }),
3580
+ state.configuredProviders.map((entry) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3581
+ value: entry.provider,
3582
+ children: entry.displayName
3583
+ }, entry.provider)),
3584
+ providerUnconfigured && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3585
+ value: providerRaw,
3586
+ children: `${providerRaw}${t("catalog.unconfigured.short")}`
3587
+ }),
3588
+ providerOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3589
+ value: providerRaw,
3590
+ children: `${providerRaw}${t("catalog.outside.short")}`
3591
+ })
3592
+ ]
3593
+ })]
4059
3594
  }),
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
- ]
3595
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3596
+ className: FallbacksCard_module_css_default.ruleCell,
3597
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3598
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3599
+ children: t("roles.rule.model")
3600
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3601
+ className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
3602
+ value: selectionToRaw(row.model),
3603
+ onChange: (event) => {
3604
+ updateRuleRow(index, { model: classifyModel(providerRaw, event.target.value, catalog) });
3605
+ },
3606
+ children: [
3607
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3608
+ value: "",
3609
+ children: t("roles.rule.model.any")
3610
+ }),
3611
+ (group?.models ?? []).map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3612
+ value: model.id,
3613
+ children: model.name
3614
+ }, model.id)),
3615
+ modelOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3616
+ value: selectionToRaw(row.model),
3617
+ children: `${selectionToRaw(row.model)}${t("catalog.outside.short")}`
3618
+ })
3619
+ ]
3620
+ })]
4102
3621
  }),
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
- ]
3622
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3623
+ className: FallbacksCard_module_css_default.ruleCell,
3624
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3625
+ className: FallbacksCard_module_css_default.ruleCellLabel,
3626
+ children: t("roles.rule.role")
3627
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
3628
+ className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
3629
+ value: row.role,
3630
+ disabled: !writable,
3631
+ onChange: (event) => {
3632
+ updateRuleRow(index, { role: event.target.value });
3633
+ },
3634
+ children: [
3635
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3636
+ value: "",
3637
+ children: t("roles.rule.roleSelectPlaceholder")
3638
+ }),
3639
+ roleOptions.map((id) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3640
+ value: id,
3641
+ children: id === "inherit" ? t("roles.rule.role.inherit") : id
3642
+ }, id)),
3643
+ roleOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
3644
+ value: row.role,
3645
+ children: `${row.role}${t("roles.rule.roleUndeclared.short")}`
3646
+ })
3647
+ ]
3648
+ })]
4145
3649
  })
4146
3650
  ]
4147
3651
  }),
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("; ")}`
3652
+ (providerOutside || modelOutside) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3653
+ className: FallbacksCard_module_css_default.hint,
3654
+ children: [t("catalog.outside.hint"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3655
+ label: t("catalog.outside.tooltip"),
3656
+ disabled: !writable
3657
+ })]
4152
3658
  }),
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 })
3659
+ row.role === "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3660
+ className: FallbacksCard_module_css_default.hint,
3661
+ children: t("validation.ruleRoleRequired")
4157
3662
  }),
4158
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4159
- className: FallbacksCard_module_css_default.sectionActions,
4160
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3663
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3664
+ className: FallbacksCard_module_css_default.cardFoot,
3665
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
4161
3666
  type: "button",
4162
- className: `${FallbacksCard_module_css_default.secondaryButton} ${FallbacksCard_module_css_default.sectionAction}`,
4163
- disabled: !advancedDirty || saving,
3667
+ className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger}`,
3668
+ "data-tip": t("roles.removeRule"),
3669
+ "aria-label": t("roles.removeRule"),
4164
3670
  onClick: () => {
4165
- discardSection("advanced");
3671
+ setRuleRows((rows) => rows.filter((_, rowIndex) => rowIndex !== index));
4166
3672
  },
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
- })]
3673
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrashIcon, {})
3674
+ })
4177
3675
  })
4178
3676
  ]
4179
- })]
3677
+ }, index);
4180
3678
  })
4181
- ]
3679
+ }),
3680
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3681
+ type: "button",
3682
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3683
+ disabled: !writable,
3684
+ onClick: () => {
3685
+ setRuleRows((rows) => [...rows, {
3686
+ provider: null,
3687
+ model: null,
3688
+ role: ""
3689
+ }]);
3690
+ },
3691
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("roles.addRule")]
3692
+ })
3693
+ ]
3694
+ }),
3695
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3696
+ className: FallbacksCard_module_css_default.sectionHeading,
3697
+ id: "fallbacks-advanced",
3698
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3699
+ className: FallbacksCard_module_css_default.sectionHeadingText,
3700
+ children: t("advanced.label")
4182
3701
  })
4183
- ]
4184
- }),
4185
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
4186
- className: FallbacksCard_module_css_default.statusBlock,
3702
+ }),
3703
+ liveErrors.advanced.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
3704
+ className: FallbacksCard_module_css_default.error,
3705
+ role: "alert",
3706
+ children: `${t("validation.blocked")}${liveErrors.advanced.join("; ")}`
3707
+ }),
3708
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3709
+ className: FallbacksCard_module_css_default.checkboxRow,
3710
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3711
+ className: FallbacksCard_module_css_default.checkLabel,
3712
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3713
+ className: FallbacksCard_module_css_default.checkLabelTitle,
3714
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
3715
+ htmlFor: "fallbacks-role-automatch",
3716
+ children: t("roleAutoMatch.label")
3717
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3718
+ label: t("roleAutoMatch.tooltip"),
3719
+ disabled: !writable
3720
+ })]
3721
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3722
+ className: FallbacksCard_module_css_default.checkLabelDesc,
3723
+ children: t("roleAutoMatch.hint")
3724
+ })]
3725
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3726
+ id: "fallbacks-role-automatch",
3727
+ type: "checkbox",
3728
+ className: FallbacksCard_module_css_default.checkbox,
3729
+ checked: scalars.roleAutoMatch,
3730
+ disabled: !writable,
3731
+ onChange: (event) => {
3732
+ updateScalars((draft) => {
3733
+ draft.roleAutoMatch = event.target.checked;
3734
+ });
3735
+ }
3736
+ })]
3737
+ }),
3738
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3739
+ className: FallbacksCard_module_css_default.field,
3740
+ role: "group",
3741
+ "aria-labelledby": "fallbacks-trigger-codes",
3742
+ children: [
3743
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3744
+ className: FallbacksCard_module_css_default.fieldLabel,
3745
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3746
+ id: "fallbacks-trigger-codes",
3747
+ children: t("triggerCodes.label")
3748
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3749
+ label: t("triggerCodes.tooltip"),
3750
+ disabled: !writable
3751
+ })]
3752
+ }),
3753
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3754
+ className: FallbacksCard_module_css_default.hint,
3755
+ children: t("triggerCodes.hint")
3756
+ }),
3757
+ KNOWN_TRIGGER_CODES.map((code) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3758
+ className: FallbacksCard_module_css_default.optionRow,
3759
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3760
+ type: "checkbox",
3761
+ checked: scalars.triggerCodes.includes(code),
3762
+ onChange: (event) => {
3763
+ updateScalars((draft) => {
3764
+ draft.triggerCodes = withTriggerCode(draft.triggerCodes, code, event.target.checked);
3765
+ });
3766
+ }
3767
+ }), t(TRIGGER_CODE_LABELS[code])]
3768
+ }, code)),
3769
+ unknownCodes.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3770
+ className: FallbacksCard_module_css_default.hint,
3771
+ children: t("triggerCodes.extra", { codes: unknownCodes.join(", ") })
3772
+ })
3773
+ ]
3774
+ }),
3775
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3776
+ className: FallbacksCard_module_css_default.field,
3777
+ role: "group",
3778
+ "aria-labelledby": "fallbacks-revert-policy",
3779
+ children: [
3780
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3781
+ className: FallbacksCard_module_css_default.fieldLabel,
3782
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3783
+ id: "fallbacks-revert-policy",
3784
+ children: t("revertPolicy.label")
3785
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3786
+ label: t("revertPolicy.tooltip"),
3787
+ disabled: !writable
3788
+ })]
3789
+ }),
3790
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3791
+ className: FallbacksCard_module_css_default.hint,
3792
+ children: t("revertPolicy.hint")
3793
+ }),
3794
+ ["cooldown-expiry", "never"].map((policy) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
3795
+ className: FallbacksCard_module_css_default.optionRow,
3796
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3797
+ type: "radio",
3798
+ name: "fallbacks-revert-policy",
3799
+ checked: scalars.revertPolicy === policy,
3800
+ onChange: () => {
3801
+ updateScalars((draft) => {
3802
+ draft.revertPolicy = policy;
3803
+ });
3804
+ }
3805
+ }), t(`revertPolicy.${policy}`)]
3806
+ }, policy))
3807
+ ]
3808
+ }),
3809
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3810
+ className: FallbacksCard_module_css_default.numberFields,
3811
+ children: [
3812
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3813
+ className: FallbacksCard_module_css_default.field,
3814
+ children: [
3815
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3816
+ className: FallbacksCard_module_css_default.fieldLabel,
3817
+ children: [
3818
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
3819
+ htmlFor: "fallbacks-cooldown-ms",
3820
+ children: t("cooldownMs.label")
3821
+ }),
3822
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3823
+ label: t("cooldownMs.tooltip"),
3824
+ disabled: !writable
3825
+ }),
3826
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3827
+ className: FallbacksCard_module_css_default.defaultNote,
3828
+ children: [
3829
+ t("defaults.prefix"),
3830
+ ": ",
3831
+ state.config.cooldownMs
3832
+ ]
3833
+ })
3834
+ ]
3835
+ }),
3836
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3837
+ id: "fallbacks-cooldown-ms",
3838
+ className: FallbacksCard_module_css_default.input,
3839
+ type: "number",
3840
+ min: 0,
3841
+ value: String(scalars.cooldownMs),
3842
+ disabled: !writable,
3843
+ onChange: (event) => {
3844
+ updateScalars((draft) => {
3845
+ draft.cooldownMs = parseCount(event.target.value);
3846
+ });
3847
+ }
3848
+ }),
3849
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3850
+ className: FallbacksCard_module_css_default.hint,
3851
+ children: t("cooldownMs.hint")
3852
+ })
3853
+ ]
3854
+ }),
3855
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3856
+ className: FallbacksCard_module_css_default.field,
3857
+ children: [
3858
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3859
+ className: FallbacksCard_module_css_default.fieldLabel,
3860
+ children: [
3861
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
3862
+ htmlFor: "fallbacks-max-switches",
3863
+ children: t("maxSwitchesPerStep.label")
3864
+ }),
3865
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3866
+ label: t("maxSwitchesPerStep.tooltip"),
3867
+ disabled: !writable
3868
+ }),
3869
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3870
+ className: FallbacksCard_module_css_default.defaultNote,
3871
+ children: [
3872
+ t("defaults.prefix"),
3873
+ ": ",
3874
+ state.config.maxSwitchesPerStep
3875
+ ]
3876
+ })
3877
+ ]
3878
+ }),
3879
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3880
+ id: "fallbacks-max-switches",
3881
+ className: FallbacksCard_module_css_default.input,
3882
+ type: "number",
3883
+ min: 0,
3884
+ value: String(scalars.maxSwitchesPerStep),
3885
+ disabled: !writable,
3886
+ onChange: (event) => {
3887
+ updateScalars((draft) => {
3888
+ draft.maxSwitchesPerStep = parseCount(event.target.value);
3889
+ });
3890
+ }
3891
+ }),
3892
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3893
+ className: FallbacksCard_module_css_default.hint,
3894
+ children: t("maxSwitchesPerStep.hint")
3895
+ })
3896
+ ]
3897
+ }),
3898
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3899
+ className: FallbacksCard_module_css_default.field,
3900
+ children: [
3901
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3902
+ className: FallbacksCard_module_css_default.fieldLabel,
3903
+ children: [
3904
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
3905
+ htmlFor: "fallbacks-always-cap",
3906
+ children: t("alwaysModeRetryCap.label")
3907
+ }),
3908
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
3909
+ label: t("alwaysModeRetryCap.tooltip"),
3910
+ disabled: !writable
3911
+ }),
3912
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
3913
+ className: FallbacksCard_module_css_default.defaultNote,
3914
+ children: [
3915
+ t("defaults.prefix"),
3916
+ ": ",
3917
+ state.config.alwaysModeRetryCap
3918
+ ]
3919
+ })
3920
+ ]
3921
+ }),
3922
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
3923
+ id: "fallbacks-always-cap",
3924
+ className: FallbacksCard_module_css_default.input,
3925
+ type: "number",
3926
+ min: 0,
3927
+ value: String(scalars.alwaysModeRetryCap),
3928
+ disabled: !writable,
3929
+ onChange: (event) => {
3930
+ updateScalars((draft) => {
3931
+ draft.alwaysModeRetryCap = parseCount(event.target.value);
3932
+ });
3933
+ }
3934
+ }),
3935
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3936
+ className: FallbacksCard_module_css_default.hint,
3937
+ children: t("alwaysModeRetryCap.hint")
3938
+ })
3939
+ ]
3940
+ })
3941
+ ]
3942
+ })
3943
+ ]
3944
+ }),
3945
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3946
+ className: FallbacksCard_module_css_default.footer,
3947
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3948
+ type: "button",
3949
+ className: FallbacksCard_module_css_default.discard,
3950
+ disabled: !dirty || saving,
3951
+ onClick: discard,
3952
+ children: t("discard")
3953
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
3954
+ type: "button",
3955
+ className: FallbacksCard_module_css_default.save,
3956
+ disabled: !dirty || invalid || saving || !writable,
3957
+ onClick: save,
3958
+ children: saving ? t("save.saving") : t("save")
3959
+ })]
3960
+ }),
3961
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3962
+ className: FallbacksCard_module_css_default.statusBlock,
3963
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3964
+ className: FallbacksCard_module_css_default.statusTitle,
3965
+ children: t("status.title")
3966
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
3967
+ className: FallbacksCard_module_css_default.statusLine,
3968
+ role: state.switchesStatus === "error" ? "alert" : void 0,
4187
3969
  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
- })]
3970
+ className: FallbacksCard_module_css_default.statusLineLabel,
3971
+ children: t("status.switches.label")
3972
+ }), switchesLine]
3973
+ })]
3974
+ })
3975
+ ]
4201
3976
  });
4202
3977
  }
4203
3978
  //#endregion
@@ -4237,7 +4012,9 @@ window.__ModuleLoader__.load({
4237
4012
  * afterwards — no new data path, no store API change.
4238
4013
  *
4239
4014
  * 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.
4015
+ * a control surface): an active/inactive badge (content presence — the
4016
+ * removed config-level `enabled` switch is re-keyed to `isFallbackActive`,
4017
+ * plan fallbacks-web-ux-alignment T2) + a compact last-switch summary.
4241
4018
  * Honest degraded states: a hard load error or an unreachable gateway
4242
4019
  * channel (`ready && !present`) render the neutral 'unknown' badge — a
4243
4020
  * channel-down read must never masquerade as 'disabled' (KD-G5); the
@@ -4261,7 +4038,7 @@ window.__ModuleLoader__.load({
4261
4038
  if (snapshot.switchesStatus === "idle") controller.loadSwitches();
4262
4039
  }, [controller]);
4263
4040
  const settled = state.status === "ready";
4264
- const badgeKey = settled && state.present ? state.config.enabled ? "general.enabled" : "general.disabled" : "general.unknown";
4041
+ const badgeKey = settled && state.present ? isFallbackActive(state.config) ? "general.enabled" : "general.disabled" : "general.unknown";
4265
4042
  const latestSwitch = state.switches[0];
4266
4043
  let summary;
4267
4044
  if (state.status === "error") summary = t("general.error", { message: state.error ?? "" });