dsh-llm-fallbacks 0.6.7 → 0.6.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -60,12 +60,16 @@ This covers an **ordinary subagent dispatch and an Agent Team teammate** (`spawn
60
60
 
61
61
  ### Install
62
62
 
63
+ **Desktop / Web plugin page** — in DeepSeek Harness (the Desktop app, or a `dsh web` session) open the **Plugins** page in the sidebar, click **Add plugin**, enter the package name `dsh-llm-fallbacks`, and click **Install**; then follow the host's restart prompt. The wizard accepts a package name (= npm package name), a GitHub repo, or a local directory — a registry install needs only the package name. The GUI writes into the `web` profile, the same profile the `--profile web` flag below targets.
64
+
65
+ **CLI** — for scripted setups, or the terminal front end:
66
+
63
67
  ```sh
64
68
  dsh plugin --profile web add dsh-llm-fallbacks # web profile (Settings → Fallbacks card)
65
69
  dsh plugin --profile dsh-tui add dsh-llm-fallbacks # dsh-tui terminal profile
66
70
  ```
67
71
 
68
- Same plugin, either front end — the only difference is the `--profile` flag. Pin a version with `@<version>`. A registry install fetches the **built package** (`dist/`), nothing builds on the target machine. Registry / git / local-directory variants, uninstall, and `--dump-config` verification → [docs/install.md](docs/install.md). The plugin ships **localized metadata** (title/description for the Plugins-page detail view, English + Simplified Chinese) and an **icon** — both declared in the package (`locale/*.json` + `icon.svg`) and picked up by the host automatically.
72
+ `dsh-tui` has no plugin page of its own, so it stays CLI-only. Pin a version with `@<version>`. A registry install fetches the **built package** (`dist/`), so nothing builds on the target machine. Registry / git / local-directory variants, uninstall, and `--dump-config` verification → [docs/install.md](docs/install.md). The plugin ships **localized metadata** (title/description for the Plugins-page detail view, English + Simplified Chinese) and an **icon** — both declared in the package (`locale/*.json` + `icon.svg`) and picked up by the host automatically.
69
73
 
70
74
  ### Configure
71
75
 
@@ -133,7 +137,7 @@ The plugin installs as a **pure mount**: bundle insert + client inject + its own
133
137
 
134
138
  | Doc | Content |
135
139
  |---|---|
136
- | [docs/install.md](docs/install.md) | profile install (web + dsh-tui) / registry / git / local variants / uninstall / `--dump-config` verification |
140
+ | [docs/install.md](docs/install.md) | desktop/web plugin page / profile install (web + dsh-tui) / registry / git / local variants / uninstall / `--dump-config` verification |
137
141
  | [docs/configuration.md](docs/configuration.md) | full `fallbacks` namespace reference, selector syntax, example YAML, plugin-config card usage, TUI readback, behavior notes, preset roles |
138
142
  | [docs/features.md](docs/features.md) | capability reference: failover, context-window fallback, time slots, role-based subagents, picker, host policy, preset roles, agent presets, dsh-tui |
139
143
  | [docs/repair.md](docs/repair.md) | session-log repair: refusal classes, `--apply` publishing, flags, exit codes, lossy `--drop-legacy-events` |
package/README.zh-CN.md CHANGED
@@ -60,12 +60,16 @@ subagent 的角色由分发提示词声明——Assignment 头部字段 `**Execu
60
60
 
61
61
  ### 安装
62
62
 
63
+ **Desktop / Web 插件页**——在 DeepSeek Harness(Desktop 应用或 `dsh web` 会话)中打开侧边栏的**插件(Plugins)**页,点击**添加插件**,输入包名 `dsh-llm-fallbacks`,点击**安装**,然后按宿主的重启提示操作。该向导接受包名(即 npm 包名)、GitHub repo 或本地目录——registry 安装只需填包名。GUI 安装写入 `web` profile,与下方 `--profile web` 指向同一个 profile。
64
+
65
+ **CLI**——适用于脚本化环境或终端前端:
66
+
63
67
  ```sh
64
68
  dsh plugin --profile web add dsh-llm-fallbacks # web profile(设置 → Fallbacks 卡片)
65
69
  dsh plugin --profile dsh-tui add dsh-llm-fallbacks # dsh-tui 终端 profile
66
70
  ```
67
71
 
68
- 同一个插件、两种前端——唯一区别是 `--profile`。可用 `@<version>` 固定版本。registry 安装拉取**已构建包**(`dist/`),目标机器不执行构建。registry / git / 本地目录三种安装方式、卸载与 `--dump-config` 校验 → [docs/install.md](docs/install.md)。插件同时提供**本地化元数据**(Plugins 详情页的标题/描述,英文 + 简体中文)与**图标**——两者都在包内声明(`locale/*.json` + `icon.svg`),由宿主自动识别。
72
+ `dsh-tui` 没有自己的插件页,只能走 CLI。可用 `@<version>` 固定版本。registry 安装拉取**已构建包**(`dist/`),目标机器不执行构建。registry / git / 本地目录三种安装方式、卸载与 `--dump-config` 校验 → [docs/install.md](docs/install.md)。插件同时提供**本地化元数据**(Plugins 详情页的标题/描述,英文 + 简体中文)与**图标**——两者都在包内声明(`locale/*.json` + `icon.svg`),由宿主自动识别。
69
73
 
70
74
  ### 配置
71
75
 
@@ -133,7 +137,7 @@ fallbacks:
133
137
 
134
138
  | 文档 | 内容 |
135
139
  |---|---|
136
- | [docs/install.md](docs/install.md) | profile 安装(web + dsh-tui)/ registry / git / 本地目录 / 卸载 / `--dump-config` 校验 |
140
+ | [docs/install.md](docs/install.md) | 桌面/Web 插件页 / profile 安装(web + dsh-tui)/ registry / git / 本地目录 / 卸载 / `--dump-config` 校验 |
137
141
  | [docs/configuration.md](docs/configuration.md) | `fallbacks` 命名空间完整参考、选择器语法、示例 YAML、插件配置卡片用法、TUI 回读、行为说明、预设角色 |
138
142
  | [docs/features.md](docs/features.md) | 能力参考:降级、上下文窗口降级、分时槽、角色化 subagent、选择器、宿主策略、预设角色、agent 预设、dsh-tui |
139
143
  | [docs/repair.md](docs/repair.md) | 会话日志修复:拒载类别、`--apply` 发布、参数、退出码、有损 `--drop-legacy-events` |
@@ -1365,7 +1365,10 @@ window.__ModuleLoader__.load({
1365
1365
  "rootChain.label": "默认降级链",
1366
1366
  "rootChain.tooltip": "未命中任何分时槽时先走这条降级链;全部失败后落到下面的默认模型。",
1367
1367
  "defaultModel.label": "默认模型",
1368
- "chains.selector.remove": "删除该选择器",
1368
+ "chains.selector.remove": "删除第 {index} 个选择器",
1369
+ "chains.selector.providerAria": "第 {index} 个选择器的 provider",
1370
+ "chains.selector.modelAria": "第 {index} 个选择器的 model",
1371
+ "chains.selector.reorder": "拖拽排序第 {index} 个选择器,或聚焦后按 ↑/↓ 调整",
1369
1372
  "chains.selector.providerPlaceholder": "选择 provider",
1370
1373
  "chains.selector.modelPlaceholder": "选择 model",
1371
1374
  "chains.selector.wildcardLegacy": "该条目为通配(provider/*):选择具体模型后将转为精确条目",
@@ -1552,7 +1555,10 @@ window.__ModuleLoader__.load({
1552
1555
  "rootChain.label": "Default fallback chain",
1553
1556
  "rootChain.tooltip": "Walked first whenever no time slot matches; if every entry fails, the default model below is the last fallback.",
1554
1557
  "defaultModel.label": "Default model",
1555
- "chains.selector.remove": "Remove this selector",
1558
+ "chains.selector.remove": "Remove selector {index}",
1559
+ "chains.selector.providerAria": "Selector {index} provider",
1560
+ "chains.selector.modelAria": "Selector {index} model",
1561
+ "chains.selector.reorder": "Drag to reorder selector {index}, or focus and press ↑/↓",
1556
1562
  "chains.selector.providerPlaceholder": "Select provider",
1557
1563
  "chains.selector.modelPlaceholder": "Select model",
1558
1564
  "chains.selector.wildcardLegacy": "This entry is a wildcard (provider/*): picking a model converts it to an exact entry",
@@ -1742,7 +1748,7 @@ window.__ModuleLoader__.load({
1742
1748
  }
1743
1749
  //#endregion
1744
1750
  //#region \0dsh-css:/home/runner/work/dsh-llm-fallbacks/dsh-llm-fallbacks/src/client/FallbacksCard.module.css.mjs
1745
- const css$3 = "\n\n\n._20fd0e45_root {\n min-width: 0;\n}\n\n\n._4e39cf17_readOnly {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._9860a5b1_notice {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-business-primary);\n}\n\n\n._5006d43e_legacyNotice {\n margin: 12px 0 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--dsw-alias-bg-module-platform);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-business-primary);\n}\n\n._21918751_error {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-error-primary);\n}\n\n\n._7cea4b2f_noticeRow {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 12px 0 0;\n}\n\n._7cea4b2f_noticeRow ._21918751_error {\n flex: 1;\n min-width: 0;\n margin: 0;\n}\n\n\n._94c91bfd_fieldset {\n margin: 0;\n padding: 0;\n border: none;\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n\n._ba240d82_sectionHeading {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0;\n padding: 4px 0;\n font-size: 16px;\n line-height: 24px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._ddbc1b49_sectionHeadingText {\n display: block;\n min-width: 0;\n}\n\n\n._c41f9db7_sectionActions {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-left: auto;\n}\n\n._c41f9db7_sectionActions ._f0864181_discard,\n._c41f9db7_sectionActions ._ccff7e48_save {\n padding: 3px 12px;\n font-size: 12px;\n line-height: 18px;\n}\n\n\n._b116c758_sectionToggle {\n appearance: none;\n border: 0;\n background: none;\n display: flex;\n align-items: center;\n gap: 4px;\n margin: 0;\n padding: 0;\n font: inherit;\n color: inherit;\n cursor: pointer;\n}\n\n._b116c758_sectionToggle:disabled {\n cursor: default;\n}\n\n._b116c758_sectionToggle:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n\n._80101203_advancedBody {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n._94c91bfd_fieldset > ._80101203_advancedBody > ._67826267_field,\n._94c91bfd_fieldset > ._80101203_advancedBody > ._9998065c_checkboxRow,\n._94c91bfd_fieldset > ._80101203_advancedBody > ._3e95886d_numberFields {\n padding: 12px 0;\n}\n\n._94c91bfd_fieldset > ._80101203_advancedBody > ._67826267_field + ._67826267_field,\n._94c91bfd_fieldset > ._80101203_advancedBody > ._9998065c_checkboxRow + ._67826267_field,\n._94c91bfd_fieldset > ._80101203_advancedBody > ._67826267_field + ._3e95886d_numberFields {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n\n\n._67826267_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin: 0;\n padding: 0;\n border: none;\n min-width: 0;\n}\n\n\n._94c91bfd_fieldset > ._67826267_field,\n._94c91bfd_fieldset > ._9998065c_checkboxRow,\n._94c91bfd_fieldset > ._3e95886d_numberFields {\n padding: 12px 0;\n}\n\n._94c91bfd_fieldset > ._67826267_field + ._67826267_field,\n._94c91bfd_fieldset > ._67826267_field + ._3e95886d_numberFields,\n._94c91bfd_fieldset > ._9998065c_checkboxRow + ._67826267_field {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n\n\n._9998065c_checkboxRow {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n\n\n._9998065c_checkboxRow ._06389b18_checkbox {\n margin-top: 3px;\n}\n\n._13e68c3f_fieldLabel {\n \n display: inline-flex;\n align-items: center;\n gap: 10px;\n padding: 0;\n font-size: 13px;\n line-height: 1.5;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n._4bc809b8_hint {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._02c2f6df_checkLabel {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n font-size: 14px;\n line-height: 22px;\n font-weight: 400;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n\n._f2d47237_checkLabelTitle {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 400;\n}\n\n._c1bed8ea_checkLabelDesc {\n font-size: 12px;\n line-height: 18px;\n font-weight: 400;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._06389b18_checkbox {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._06389b18_checkbox:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n\n._b1962759_slotPresetName {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n\n._a6244318_infoHint {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n font-size: 14px;\n line-height: 1;\n color: var(--dsw-alias-label-tertiary);\n background: var(--dsw-alias-interactive-bg-hover);\n cursor: help;\n user-select: none;\n}\n\n._a6244318_infoHint:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._a6244318_infoHint::after {\n content: attr(data-tip);\n position: absolute;\n top: 50%;\n left: calc(100% + 8px);\n transform: translateY(-50%);\n z-index: 10;\n box-sizing: border-box;\n width: max-content;\n max-width: 280px;\n padding: 5px 10px;\n border-radius: 8px;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n font-size: 11px;\n line-height: 17px;\n font-weight: 400;\n white-space: normal;\n text-align: left;\n pointer-events: none;\n opacity: 0;\n transition: opacity .12s;\n}\n\n._a6244318_infoHint:hover::after,\n._a6244318_infoHint:focus-visible::after {\n opacity: 1;\n}\n\n\n._e655c840_infoHintDisabled {\n opacity: 0.4;\n cursor: default;\n}\n\n\n._a2521bb0_optionRow {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n\n._a2521bb0_optionRow:hover:has(input:not(:disabled)) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n\n._06389b18_checkbox,\n._a2521bb0_optionRow input {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._06389b18_checkbox:focus-visible,\n._a2521bb0_optionRow input:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._a2521bb0_optionRow input:disabled {\n cursor: default;\n}\n\n\n._c4ecbdf3_dayRow {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n\n._0330c1ed_dayCell {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 6px;\n border-radius: 6px;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n._0330c1ed_dayCell:hover:has(input:not(:disabled)) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._0330c1ed_dayCell input {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._0330c1ed_dayCell input:disabled {\n cursor: default;\n}\n\n._0330c1ed_dayCell input:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n\n._f9d86f7b_input {\n box-sizing: border-box;\n width: 100%;\n height: 34px;\n padding: 0 12px;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n background: var(--dsw-alias-bg-layer-3);\n color: var(--dsw-alias-label-primary);\n}\n\n._f9d86f7b_input:focus-visible {\n outline: none;\n border-color: var(--dsw-alias-state-business-primary);\n}\n\n._f9d86f7b_input::placeholder {\n color: var(--dsw-alias-label-dimmed);\n}\n\n._f9d86f7b_input:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n\n\n._3a9b42fd_inputTextarea {\n height: auto;\n min-height: 72px;\n padding: 8px 12px;\n resize: vertical;\n}\n\n\n._1285c19b_personaBriefRow {\n display: flex;\n align-items: center;\n gap: 4px;\n min-width: 0;\n}\n\n._4b8f7345_personaBrief {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n}\n\n\n._2686400e_personaBriefEmpty {\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._4e4a07be_personaFull {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-secondary);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n\n._7b60337a_inputInvalid,\n._7b60337a_inputInvalid:focus-visible {\n border-color: var(--dsw-alias-state-error-primary);\n}\n\n\nselect._f9d86f7b_input {\n max-width: 240px;\n cursor: pointer;\n}\n\n\n._16eb7153_selectInput {\n appearance: none;\n padding-right: 32px;\n \n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 12px center;\n background-size: 12px 12px;\n}\n\n\n._3e95886d_numberFields {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n gap: 12px;\n}\n\n._3e95886d_numberFields ._67826267_field {\n padding: 0;\n}\n\n._0cfb5881_list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 4px;\n}\n\n\n._f5c620d6_editorCard {\n display: flex;\n flex-direction: column;\n gap: 14px;\n padding: 14px 16px;\n border-radius: 12px;\n background: var(--dsw-alias-bg-module-platform);\n}\n\n._224b1387_cardFoot {\n display: flex;\n justify-content: flex-end;\n}\n\n._8e220e07_ruleGrid {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n._24a12a2f_ruleCell {\n display: flex;\n flex-direction: column;\n gap: 4px;\n min-width: 120px;\n flex: 1;\n}\n\n._1014c097_ruleCellLabel {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._631094a0_chevron {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n transform: rotate(-90deg);\n transition: transform .16s;\n}\n\n._44836ce8_chevronOpen {\n transform: none;\n}\n\n\n._cf3961bb_chevronFlip {\n transform: rotate(180deg);\n}\n\n\n._86bc52d2_collapseRow {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n._a73efcc6_collapseToggle {\n appearance: none;\n border: 0;\n background: none;\n padding: 0;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n font: inherit;\n text-align: left;\n}\n\n._a73efcc6_collapseToggle:disabled {\n cursor: default;\n}\n\n._af017718_collapseTitle {\n \n flex: none;\n max-width: 55%;\n min-width: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._2cabe603_collapseMeta {\n \n flex: none;\n margin-left: auto;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n\n._52d6df87_seedBadge {\n flex: none;\n max-width: 40%;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n border-radius: 999px;\n padding: 1px 8px;\n font-size: 11px;\n line-height: 17px;\n font-weight: 500;\n white-space: nowrap;\n background: var(--dsw-alias-bg-layer-1);\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._7b04f727_slotTag {\n flex: none;\n display: inline-flex;\n align-items: center;\n border-radius: 999px;\n padding: 0 6px;\n font-size: 11px;\n line-height: 17px;\n font-weight: 500;\n white-space: nowrap;\n border: 1px solid;\n}\n\n._c381e792_slotTagHighCost {\n color: var(--dsw-alias-state-error-primary);\n border-color: var(--dsw-alias-state-error-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-error-primary) 10%, transparent);\n}\n\n._23bdb6fc_slotTagMultiplier {\n color: var(--dsw-alias-state-warn-primary);\n border-color: var(--dsw-alias-state-warn-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-warn-primary) 10%, transparent);\n}\n\n._f000eed9_slotTagActive {\n color: var(--dsw-alias-state-success-primary);\n border-color: var(--dsw-alias-state-success-primary);\n background: color-mix(in srgb, var(--dsw-alias-state-success-primary) 10%, transparent);\n}\n\n\n._cd905ce5_dragHandle {\n appearance: none;\n border: 0;\n background: none;\n padding: 0;\n cursor: grab;\n color: var(--dsw-alias-label-tertiary);\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n border-radius: 6px;\n flex: none;\n}\n\n._cd905ce5_dragHandle:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._cd905ce5_dragHandle:active {\n cursor: grabbing;\n}\n\n._cd905ce5_dragHandle:disabled {\n cursor: default;\n opacity: 0.4;\n}\n\n._cd905ce5_dragHandle:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n\n._fee63b7e_slotCardDragging {\n opacity: 0.45;\n}\n\n._6f108491_slotCardOver {\n outline: 1px dashed var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n}\n\n\n._15a12620_chainSelectors {\n display: flex;\n flex-direction: column;\n gap: 10px;\n}\n\n._240cbbf8_selectorRow {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n\n._70effa64_iconButton {\n position: relative;\n box-sizing: border-box;\n appearance: none;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 28px;\n height: 28px;\n padding: 0;\n border: 0;\n border-radius: 6px;\n background: none;\n color: var(--dsw-alias-label-tertiary);\n cursor: pointer;\n}\n\n._70effa64_iconButton:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n._70effa64_iconButton:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n._70effa64_iconButton:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._70effa64_iconButton::after {\n content: attr(data-tip);\n position: absolute;\n bottom: calc(100% + 6px);\n left: 50%;\n transform: translateX(-50%);\n padding: 3px 8px;\n border-radius: 6px;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n font-size: 11px;\n line-height: 17px;\n white-space: nowrap;\n opacity: 0;\n pointer-events: none;\n transition: opacity .12s;\n}\n\n._70effa64_iconButton:hover::after,\n._70effa64_iconButton:focus-visible::after {\n opacity: 1;\n}\n\n\n._a0968257_iconButtonDanger:hover:not(:disabled) {\n background: var(--dsw-alias-interactive-bg-hover-danger);\n color: var(--dsw-alias-state-error-primary);\n}\n\n\n._711248a9_outlineButton {\n appearance: none;\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 4px 10px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: var(--dsw-radius-md);\n background: none;\n font: inherit;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n._711248a9_outlineButton:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n border-color: var(--dsw-alias-label-dimmed);\n}\n\n._711248a9_outlineButton:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n._711248a9_outlineButton:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n\n._28202c90_addButton {\n align-self: flex-start;\n}\n\n\n._6a2bd54c_slotAddRow {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 4px;\n flex-wrap: wrap;\n}\n\n\n._4e77523e_rowActions {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n\n._f0864181_discard,\n._ccff7e48_save {\n appearance: none;\n border: 1px solid transparent;\n border-radius: var(--dsw-radius-md);\n padding: 5px 14px;\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n cursor: pointer;\n}\n\n._f0864181_discard {\n border-color: var(--dsw-alias-border-l2);\n background: none;\n color: var(--dsw-alias-label-secondary);\n}\n\n._f0864181_discard:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n border-color: var(--dsw-alias-label-dimmed);\n}\n\n._ccff7e48_save {\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n}\n\n._f0864181_discard:disabled,\n._ccff7e48_save:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n._f0864181_discard:focus-visible,\n._ccff7e48_save:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n\n._fbd045e0_statusBlock {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px 14px;\n margin-top: 12px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n}\n\n._d4f70367_statusTitle {\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._8ab300ed_statusLine {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n._e8cedbf5_statusLineLabel {\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._700006c9_policyStatus {\n margin: 12px 0 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--dsw-alias-bg-module-platform);\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n._d4b67a81_policyStatusLabel {\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n}\n\n._278bb4b3_policyStatusLine {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-primary);\n}\n\n._da6387e5_policyStatusWarn {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._70effa64_iconButton::after,\n ._a6244318_infoHint::after {\n transition: none;\n }\n\n ._631094a0_chevron {\n transition: none;\n }\n}\n";
1751
+ const css$3 = "\n\n\n._20fd0e45_root {\n min-width: 0;\n}\n\n\n._4e39cf17_readOnly {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 1.5;\n color: var(--dsw-alias-label-tertiary);\n}\n\n._9860a5b1_notice {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-business-primary);\n}\n\n\n._5006d43e_legacyNotice {\n margin: 12px 0 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--dsw-alias-bg-module-platform);\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-business-primary);\n}\n\n._21918751_error {\n margin: 12px 0 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-error-primary);\n}\n\n\n._7cea4b2f_noticeRow {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 12px 0 0;\n}\n\n._7cea4b2f_noticeRow ._21918751_error {\n flex: 1;\n min-width: 0;\n margin: 0;\n}\n\n\n._94c91bfd_fieldset {\n margin: 0;\n padding: 0;\n border: none;\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n\n._ba240d82_sectionHeading {\n display: flex;\n align-items: center;\n gap: 8px;\n margin: 0;\n padding: 4px 0;\n font-size: 16px;\n line-height: 24px;\n font-weight: 600;\n color: var(--dsw-alias-label-primary);\n}\n\n._ddbc1b49_sectionHeadingText {\n display: block;\n min-width: 0;\n}\n\n\n._c41f9db7_sectionActions {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-left: auto;\n}\n\n._c41f9db7_sectionActions ._f0864181_discard,\n._c41f9db7_sectionActions ._ccff7e48_save {\n padding: 3px 12px;\n font-size: 12px;\n line-height: 18px;\n}\n\n\n._b116c758_sectionToggle {\n appearance: none;\n border: 0;\n background: none;\n display: flex;\n align-items: center;\n gap: 4px;\n margin: 0;\n padding: 0;\n font: inherit;\n color: inherit;\n cursor: pointer;\n}\n\n._b116c758_sectionToggle:disabled {\n cursor: default;\n}\n\n._b116c758_sectionToggle:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n\n._80101203_advancedBody {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n._94c91bfd_fieldset > ._80101203_advancedBody > ._67826267_field,\n._94c91bfd_fieldset > ._80101203_advancedBody > ._9998065c_checkboxRow,\n._94c91bfd_fieldset > ._80101203_advancedBody > ._3e95886d_numberFields {\n padding: 12px 0;\n}\n\n._94c91bfd_fieldset > ._80101203_advancedBody > ._67826267_field + ._67826267_field,\n._94c91bfd_fieldset > ._80101203_advancedBody > ._9998065c_checkboxRow + ._67826267_field,\n._94c91bfd_fieldset > ._80101203_advancedBody > ._67826267_field + ._3e95886d_numberFields {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n\n\n._67826267_field {\n display: flex;\n flex-direction: column;\n gap: 6px;\n margin: 0;\n padding: 0;\n border: none;\n min-width: 0;\n}\n\n\n._94c91bfd_fieldset > ._67826267_field,\n._94c91bfd_fieldset > ._9998065c_checkboxRow,\n._94c91bfd_fieldset > ._3e95886d_numberFields {\n padding: 12px 0;\n}\n\n._94c91bfd_fieldset > ._67826267_field + ._67826267_field,\n._94c91bfd_fieldset > ._67826267_field + ._3e95886d_numberFields,\n._94c91bfd_fieldset > ._9998065c_checkboxRow + ._67826267_field {\n border-top: 0.5px solid var(--dsw-alias-border-l2);\n}\n\n\n._9998065c_checkboxRow {\n display: flex;\n align-items: flex-start;\n gap: 8px;\n}\n\n\n._9998065c_checkboxRow ._06389b18_checkbox {\n margin-top: 3px;\n}\n\n._13e68c3f_fieldLabel {\n \n display: inline-flex;\n align-items: center;\n gap: 10px;\n padding: 0;\n font-size: 13px;\n line-height: 1.5;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n._4bc809b8_hint {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n flex-wrap: wrap;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._02c2f6df_checkLabel {\n flex: 1;\n min-width: 0;\n display: flex;\n flex-direction: column;\n gap: 4px;\n font-size: 14px;\n line-height: 22px;\n font-weight: 400;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n\n._f2d47237_checkLabelTitle {\n display: inline-flex;\n align-items: center;\n gap: 6px;\n font-weight: 400;\n}\n\n._c1bed8ea_checkLabelDesc {\n font-size: 12px;\n line-height: 18px;\n font-weight: 400;\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._06389b18_checkbox {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._06389b18_checkbox:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n\n._b1962759_slotPresetName {\n font-size: 14px;\n line-height: 22px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n}\n\n\n._a6244318_infoHint {\n position: relative;\n display: inline-flex;\n align-items: center;\n justify-content: center;\n flex: none;\n width: 16px;\n height: 16px;\n border-radius: 50%;\n font-size: 14px;\n line-height: 1;\n color: var(--dsw-alias-label-tertiary);\n background: var(--dsw-alias-interactive-bg-hover);\n cursor: help;\n user-select: none;\n}\n\n._a6244318_infoHint:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._a6244318_infoHint::after {\n content: attr(data-tip);\n position: absolute;\n top: 50%;\n left: calc(100% + 8px);\n transform: translateY(-50%);\n z-index: 10;\n box-sizing: border-box;\n width: max-content;\n max-width: 280px;\n padding: 5px 10px;\n border-radius: 8px;\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n font-size: 11px;\n line-height: 17px;\n font-weight: 400;\n white-space: normal;\n text-align: left;\n pointer-events: none;\n opacity: 0;\n transition: opacity .12s;\n}\n\n._a6244318_infoHint:hover::after,\n._a6244318_infoHint:focus-visible::after {\n opacity: 1;\n}\n\n\n._e655c840_infoHintDisabled {\n opacity: 0.4;\n cursor: default;\n}\n\n\n._a2521bb0_optionRow {\n display: flex;\n align-items: center;\n gap: 8px;\n padding: 6px 8px;\n border-radius: 6px;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n cursor: pointer;\n}\n\n._a2521bb0_optionRow:hover:has(input:not(:disabled)) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n\n._06389b18_checkbox,\n._a2521bb0_optionRow input {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._06389b18_checkbox:focus-visible,\n._a2521bb0_optionRow input:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n._a2521bb0_optionRow input:disabled {\n cursor: default;\n}\n\n\n._c4ecbdf3_dayRow {\n display: flex;\n flex-wrap: wrap;\n gap: 4px;\n}\n\n._0330c1ed_dayCell {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n padding: 2px 6px;\n border-radius: 6px;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n cursor: pointer;\n}\n\n._0330c1ed_dayCell:hover:has(input:not(:disabled)) {\n background: var(--dsw-alias-interactive-bg-hover);\n}\n\n._0330c1ed_dayCell input {\n flex: none;\n width: 16px;\n height: 16px;\n margin: 0;\n accent-color: var(--dsw-alias-brand-primary);\n cursor: pointer;\n}\n\n._0330c1ed_dayCell input:disabled {\n cursor: default;\n}\n\n._0330c1ed_dayCell input:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n\n._f9d86f7b_input {\n box-sizing: border-box;\n width: 100%;\n height: 34px;\n padding: 0 12px;\n border: 0.5px solid var(--dsw-alias-border-l4);\n border-radius: var(--dsw-radius-md);\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n background: var(--dsw-alias-bg-layer-3);\n color: var(--dsw-alias-label-primary);\n}\n\n._f9d86f7b_input:focus-visible {\n outline: none;\n border-color: var(--dsw-alias-state-business-primary);\n}\n\n._f9d86f7b_input::placeholder {\n color: var(--dsw-alias-label-dimmed);\n}\n\n._f9d86f7b_input:disabled {\n color: var(--dsw-alias-label-tertiary);\n cursor: default;\n}\n\n\n._3a9b42fd_inputTextarea {\n height: auto;\n min-height: 72px;\n padding: 8px 12px;\n resize: vertical;\n}\n\n\n._1285c19b_personaBriefRow {\n display: flex;\n align-items: center;\n gap: 4px;\n min-width: 0;\n}\n\n._4b8f7345_personaBrief {\n flex: 1;\n min-width: 0;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-primary);\n}\n\n\n._2686400e_personaBriefEmpty {\n color: var(--dsw-alias-label-tertiary);\n}\n\n\n._4e4a07be_personaFull {\n margin: 0;\n font-size: 14px;\n line-height: 22px;\n color: var(--dsw-alias-label-secondary);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n}\n\n\n._7b60337a_inputInvalid,\n._7b60337a_inputInvalid:focus-visible {\n border-color: var(--dsw-alias-state-error-primary);\n}\n\n\nselect._f9d86f7b_input {\n max-width: 240px;\n cursor: pointer;\n}\n\n\n._16eb7153_selectInput {\n appearance: none;\n padding-right: 32px;\n \n background-image: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12' fill='none'%3E%3Cpath d='M3 4.5L6 7.5L9 4.5' stroke='%2381858C' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E\");\n background-repeat: no-repeat;\n background-position: right 12px center;\n background-size: 12px 12px;\n}\n\n\n._3e95886d_numberFields {\n display: grid;\n grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));\n gap: 12px;\n}\n\n._3e95886d_numberFields ._67826267_field {\n padding: 0;\n}\n\n._0cfb5881_list {\n display: flex;\n flex-direction: column;\n gap: 8px;\n margin-top: 4px;\n}\n\n\n._f5c620d6_editorCard {\n display: flex;\n flex-direction: column;\n gap: 14px;\n padding: 14px 16px;\n border-radius: 12px;\n background: var(--dsw-alias-bg-module-platform);\n}\n\n._224b1387_cardFoot {\n display: flex;\n justify-content: flex-end;\n}\n\n._8e220e07_ruleGrid {\n display: flex;\n flex-wrap: wrap;\n gap: 8px;\n}\n\n._24a12a2f_ruleCell {\n display: flex;\n flex-direction: column;\n gap: 4px;\n min-width: 120px;\n flex: 1;\n}\n\n._1014c097_ruleCellLabel {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._631094a0_chevron {\n flex: none;\n color: var(--dsw-alias-label-tertiary);\n transform: rotate(-90deg);\n transition: transform .16s;\n}\n\n._44836ce8_chevronOpen {\n transform: none;\n}\n\n\n._cf3961bb_chevronFlip {\n transform: rotate(180deg);\n}\n\n\n._86bc52d2_collapseRow {\n display: flex;\n align-items: center;\n gap: 8px;\n min-width: 0;\n}\n\n._a73efcc6_collapseToggle {\n appearance: none;\n border: 0;\n background: none;\n padding: 0;\n cursor: pointer;\n color: var(--dsw-alias-label-secondary);\n display: flex;\n align-items: center;\n gap: 8px;\n flex: 1;\n min-width: 0;\n font: inherit;\n text-align: left;\n}\n\n._a73efcc6_collapseToggle:disabled {\n cursor: default;\n}\n\n._af017718_collapseTitle {\n \n flex: none;\n max-width: 55%;\n min-width: 0;\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-primary);\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n}\n\n._2cabe603_collapseMeta {\n \n flex: 0 1 auto;\n min-width: 0;\n max-width: 40%;\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._1a0fa2e1_selectorRowDragging {\n opacity: 0.45;\n}\n\n._688095f2_selectorRowOver {\n outline: 1px dashed var(--dsw-alias-brand-primary);\n outline-offset: 2px;\n border-radius: 6px;\n}\n\n\n._7489fed0_selectorGrip {\n flex: none;\n}\n\n._7489fed0_selectorGrip:disabled {\n display: none;\n}\n\n\n._28237b53_chainBlock {\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n\n._15a12620_chainSelectors {\n display: flex;\n flex-direction: column;\n gap: 4px;\n}\n\n\n._5694c1de_selectorLine {\n display: flex;\n align-items: center;\n gap: 8px;\n flex-wrap: nowrap;\n \n min-height: 32px;\n}\n\n\n._2f156f38_selectorIndex {\n flex: none;\n width: 1.5em;\n text-align: right;\n font-size: 11px;\n line-height: 16px;\n color: var(--dsw-alias-label-tertiary);\n font-variant-numeric: tabular-nums;\n}\n\n\n._4843ae21_selectorProviderCell {\n flex: 0 1 clamp(140px, 20%, 220px);\n min-width: 0;\n}\n\n._df828181_selectorModelCell {\n flex: 1 1 auto;\n min-width: 0;\n}\n\n\n._df828181_selectorModelCell > select._f9d86f7b_input {\n max-width: 100%;\n}\n\n\n._fe6d05a5_selectorHint {\n display: flex;\n align-items: center;\n flex: 0 1 auto;\n min-width: 0;\n}\n\n\n._d04ee9fe_selectorHintText {\n flex: 0 1 auto;\n min-width: 0;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n font-size: 11px;\n line-height: 16px;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._fe6d05a5_selectorHint > ._a6244318_infoHint {\n flex: none;\n margin-left: 4px;\n}\n\n\n._ec7c2fac_selectorRemove {\n flex: none;\n opacity: 0;\n transition: opacity .12s;\n}\n\n\n._ec7c2fac_selectorRemove:disabled {\n display: none;\n}\n\n\n._240cbbf8_selectorRow:hover ._ec7c2fac_selectorRemove:not(:disabled),\n._240cbbf8_selectorRow:focus-within ._ec7c2fac_selectorRemove:not(:disabled) {\n opacity: 1;\n}\n\n@media (hover: none) {\n ._ec7c2fac_selectorRemove:not(:disabled) {\n opacity: 0.7;\n }\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._28237b53_chainBlock > ._28202c90_addButton {\n box-sizing: border-box;\n align-self: flex-start;\n height: 26px;\n padding: 0 8px;\n border: 1px solid transparent;\n gap: 4px;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n}\n\n._28237b53_chainBlock > ._28202c90_addButton:hover:not(:disabled) {\n border-color: transparent;\n background: var(--dsw-alias-interactive-bg-hover);\n color: var(--dsw-alias-label-primary);\n}\n\n\n._28237b53_chainBlock > ._28202c90_addButton:focus-visible {\n outline: none;\n box-shadow: 0 0 0 2px var(--dsw-alias-border-l3);\n}\n\n\n._6a2bd54c_slotAddRow {\n display: flex;\n align-items: center;\n gap: 8px;\n margin-top: 4px;\n flex-wrap: wrap;\n}\n\n\n._4e77523e_rowActions {\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n\n._f0864181_discard,\n._ccff7e48_save {\n appearance: none;\n border: 1px solid transparent;\n border-radius: var(--dsw-radius-md);\n padding: 5px 14px;\n font: inherit;\n font-size: 13px;\n line-height: 1.5;\n cursor: pointer;\n}\n\n._f0864181_discard {\n border-color: var(--dsw-alias-border-l2);\n background: none;\n color: var(--dsw-alias-label-secondary);\n}\n\n._f0864181_discard:hover:not(:disabled) {\n color: var(--dsw-alias-label-primary);\n border-color: var(--dsw-alias-label-dimmed);\n}\n\n._ccff7e48_save {\n background: var(--dsw-alias-label-primary);\n color: var(--dsw-alias-bg-layer-3);\n}\n\n._f0864181_discard:disabled,\n._ccff7e48_save:disabled {\n opacity: 0.4;\n cursor: default;\n}\n\n._f0864181_discard:focus-visible,\n._ccff7e48_save:focus-visible {\n outline: 2px solid var(--dsw-alias-brand-primary);\n outline-offset: 1px;\n}\n\n\n._fbd045e0_statusBlock {\n display: flex;\n flex-direction: column;\n gap: 12px;\n padding: 12px 14px;\n margin-top: 12px;\n border: 1px solid var(--dsw-alias-border-l2);\n border-radius: 12px;\n}\n\n._d4f70367_statusTitle {\n font-size: 12px;\n line-height: 18px;\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._8ab300ed_statusLine {\n margin: 0;\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n._e8cedbf5_statusLineLabel {\n font-weight: 500;\n color: var(--dsw-alias-label-secondary);\n}\n\n\n._700006c9_policyStatus {\n margin: 12px 0 0;\n padding: 10px 12px;\n border-radius: 8px;\n background: var(--dsw-alias-bg-module-platform);\n display: flex;\n flex-direction: column;\n gap: 6px;\n}\n\n._d4b67a81_policyStatusLabel {\n font-size: 12px;\n font-weight: 600;\n line-height: 18px;\n color: var(--dsw-alias-label-secondary);\n}\n\n._278bb4b3_policyStatusLine {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-label-primary);\n}\n\n._da6387e5_policyStatusWarn {\n font-size: 12px;\n line-height: 18px;\n color: var(--dsw-alias-state-warn-primary);\n}\n\n@media (prefers-reduced-motion: reduce) {\n ._70effa64_iconButton::after,\n ._a6244318_infoHint::after {\n transition: none;\n }\n\n ._631094a0_chevron {\n transition: none;\n }\n}\n";
1746
1752
  const tagId$3 = "dsh-llm-fallbacks/FallbacksCard.module.css";
1747
1753
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$3) + "]") === null) {
1748
1754
  const tag = document.createElement("style");
@@ -1810,7 +1816,18 @@ window.__ModuleLoader__.load({
1810
1816
  "dragHandle": "_cd905ce5_dragHandle",
1811
1817
  "slotCardDragging": "_fee63b7e_slotCardDragging",
1812
1818
  "slotCardOver": "_6f108491_slotCardOver",
1819
+ "selectorRowDragging": "_1a0fa2e1_selectorRowDragging",
1820
+ "selectorRowOver": "_688095f2_selectorRowOver",
1821
+ "selectorGrip": "_7489fed0_selectorGrip",
1822
+ "chainBlock": "_28237b53_chainBlock",
1813
1823
  "chainSelectors": "_15a12620_chainSelectors",
1824
+ "selectorLine": "_5694c1de_selectorLine",
1825
+ "selectorIndex": "_2f156f38_selectorIndex",
1826
+ "selectorProviderCell": "_4843ae21_selectorProviderCell",
1827
+ "selectorModelCell": "_df828181_selectorModelCell",
1828
+ "selectorHint": "_fe6d05a5_selectorHint",
1829
+ "selectorHintText": "_d04ee9fe_selectorHintText",
1830
+ "selectorRemove": "_ec7c2fac_selectorRemove",
1814
1831
  "selectorRow": "_240cbbf8_selectorRow",
1815
1832
  "iconButton": "_70effa64_iconButton",
1816
1833
  "iconButtonDanger": "_a0968257_iconButtonDanger",
@@ -2310,7 +2327,36 @@ window.__ModuleLoader__.load({
2310
2327
  });
2311
2328
  }
2312
2329
  /**
2330
+ * The whole chain as one line (plan fallbacks-chain-reorder T2, user request):
2331
+ * every non-blank entry in walk order joined with `>`, or `undefined` for an
2332
+ * empty/blank chain so the caller keeps its own summary (a role's raw strategy
2333
+ * token). The card ellipsizes long summaries; the full string rides `title`.
2334
+ */
2335
+ function chainSummary(selectors) {
2336
+ const entries = selectors.map(selectorRowToRaw).filter((entry) => entry !== "");
2337
+ return entries.length === 0 ? void 0 : entries.join(" > ");
2338
+ }
2339
+ /**
2340
+ * Pure chain reorder (plan fallbacks-chain-reorder T1): a copy of `list` with
2341
+ * the entry at `from` re-inserted at `to`; an out-of-range or same-position
2342
+ * move returns `list` untouched (the end-clamping the keyboard and the drop
2343
+ * handler both rely on).
2344
+ */
2345
+ function moveItem(list, from, to) {
2346
+ if (from === to || from < 0 || to < 0 || from >= list.length || to >= list.length) return list;
2347
+ const next = [...list];
2348
+ const [moved] = next.splice(from, 1);
2349
+ next.splice(to, 0, moved);
2350
+ return next;
2351
+ }
2352
+ /**
2313
2353
  * One chain entry selector row: provider select + model select (cascade).
2354
+ * The row is ONE compact line (plan fallbacks-chain-row-compact T1): the
2355
+ * 1-based order index, the provider select, the model select, any row-level
2356
+ * hint (inline, so it never re-opens the row height) and the trailing remove
2357
+ * icon. The visible provider/model field labels are gone — the two selects
2358
+ * carry their accessible name on `aria-label` (the visible labels repeated on
2359
+ * every row and cost a whole line).
2314
2360
  * The GUI never offers a `provider/*` wildcard (root agent and role chains
2315
2361
  * alike; provider-any matching lives in the role rules) — but `provider/*`
2316
2362
  * stays a legal YAML entry, so a wildcard row read back from the server
@@ -2327,7 +2373,7 @@ window.__ModuleLoader__.load({
2327
2373
  * existing value is never hidden or dropped. New rows only offer configured
2328
2374
  * options.
2329
2375
  */
2330
- function ChainSelectorEditor({ selector, catalog, configuredProviders, disabled, t, onChange, onRemove }) {
2376
+ function ChainSelectorEditor({ selector, index, catalog, configuredProviders, disabled, t, onChange, onRemove, reorder }) {
2331
2377
  const providerRaw = selectionToRaw(selector.provider);
2332
2378
  const providerOutside = selector.provider?.kind === "outside";
2333
2379
  const providerUnconfigured = !providerOutside && providerRaw !== "" && (catalog?.providers.some((entry) => entry.provider === providerRaw) ?? false) && !configuredProviders.some((entry) => entry.provider === providerRaw);
@@ -2336,19 +2382,36 @@ window.__ModuleLoader__.load({
2336
2382
  const group = catalog?.groups.find((entry) => entry.id === providerRaw);
2337
2383
  const groupMissing = providerRaw !== "" && !providerOutside && group === void 0;
2338
2384
  const modelDisabled = disabled || providerRaw === "" || groupMissing || providerOutside && modelRaw === "";
2339
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2340
- className: FallbacksCard_module_css_default.selectorRow,
2341
- children: [
2342
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2343
- className: FallbacksCard_module_css_default.ruleGrid,
2344
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2345
- className: FallbacksCard_module_css_default.ruleCell,
2346
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2347
- className: FallbacksCard_module_css_default.ruleCellLabel,
2348
- children: t("roles.rule.provider")
2349
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
2385
+ const hintInstanceId = (0, react.useId)().replace(/:/g, "");
2386
+ const strictHintId = groupMissing ? `fallbacks-selector-hint-${index}-${hintInstanceId}` : void 0;
2387
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2388
+ className: `${FallbacksCard_module_css_default.selectorRow}${reorder.dragging ? ` ${FallbacksCard_module_css_default.selectorRowDragging}` : ""}${reorder.dropTarget ? ` ${FallbacksCard_module_css_default.selectorRowOver}` : ""}`,
2389
+ "data-selector-row": "",
2390
+ onDragOver: (event) => {
2391
+ if (disabled || !reorder.active) return;
2392
+ event.preventDefault();
2393
+ reorder.onDragOver();
2394
+ },
2395
+ onDrop: (event) => {
2396
+ if (disabled || !reorder.active) return;
2397
+ event.preventDefault();
2398
+ reorder.onDrop();
2399
+ },
2400
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
2401
+ className: FallbacksCard_module_css_default.selectorLine,
2402
+ children: [
2403
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2404
+ className: FallbacksCard_module_css_default.selectorIndex,
2405
+ "aria-hidden": "true",
2406
+ "data-selector-index": index,
2407
+ children: index
2408
+ }),
2409
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2410
+ className: FallbacksCard_module_css_default.selectorProviderCell,
2411
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
2350
2412
  className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
2351
2413
  value: providerRaw,
2414
+ "aria-label": t("chains.selector.providerAria", { index: String(index) }),
2352
2415
  disabled,
2353
2416
  onChange: (event) => {
2354
2417
  if (event.target.value === providerRaw) return;
@@ -2375,69 +2438,166 @@ window.__ModuleLoader__.load({
2375
2438
  children: `${providerRaw}${t("catalog.outside.short")}`
2376
2439
  })
2377
2440
  ]
2441
+ })
2442
+ }),
2443
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2444
+ className: FallbacksCard_module_css_default.selectorModelCell,
2445
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
2446
+ className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
2447
+ value: modelRaw,
2448
+ "aria-label": t("chains.selector.modelAria", { index: String(index) }),
2449
+ "aria-describedby": strictHintId,
2450
+ disabled: modelDisabled,
2451
+ onChange: (event) => {
2452
+ onChange({
2453
+ model: classifyModel(providerRaw, event.target.value, catalog),
2454
+ ...selector.wildcard ? { wildcard: false } : {}
2455
+ });
2456
+ },
2457
+ children: [
2458
+ modelRaw === "" && !providerOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2459
+ value: "",
2460
+ children: t("chains.selector.modelPlaceholder")
2461
+ }),
2462
+ (group?.models ?? []).map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2463
+ value: model.id,
2464
+ children: model.name
2465
+ }, model.id)),
2466
+ modelOutside && !selector.wildcard && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2467
+ value: modelRaw,
2468
+ children: `${modelRaw}${t("catalog.outside.short")}`
2469
+ })
2470
+ ]
2471
+ })
2472
+ }),
2473
+ groupMissing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2474
+ className: FallbacksCard_module_css_default.selectorHint,
2475
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2476
+ id: strictHintId,
2477
+ className: FallbacksCard_module_css_default.selectorHintText,
2478
+ title: t("chains.selector.noModelsStrict"),
2479
+ children: t("chains.selector.noModelsStrict")
2480
+ })
2481
+ }),
2482
+ (providerOutside || modelOutside) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2483
+ className: FallbacksCard_module_css_default.selectorHint,
2484
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2485
+ className: FallbacksCard_module_css_default.selectorHintText,
2486
+ title: t("catalog.outside.hint"),
2487
+ children: t("catalog.outside.hint")
2488
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
2489
+ label: t("catalog.outside.tooltip"),
2490
+ disabled
2378
2491
  })]
2379
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", {
2380
- className: FallbacksCard_module_css_default.ruleCell,
2381
- children: [
2382
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2383
- className: FallbacksCard_module_css_default.ruleCellLabel,
2384
- children: t("roles.rule.model")
2385
- }),
2386
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("select", {
2387
- className: `${FallbacksCard_module_css_default.input} ${FallbacksCard_module_css_default.selectInput}`,
2388
- value: modelRaw,
2389
- disabled: modelDisabled,
2390
- onChange: (event) => {
2391
- onChange({
2392
- model: classifyModel(providerRaw, event.target.value, catalog),
2393
- ...selector.wildcard ? { wildcard: false } : {}
2394
- });
2395
- },
2396
- children: [
2397
- modelRaw === "" && !providerOutside && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2398
- value: "",
2399
- children: t("chains.selector.modelPlaceholder")
2400
- }),
2401
- (group?.models ?? []).map((model) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2402
- value: model.id,
2403
- children: model.name
2404
- }, model.id)),
2405
- modelOutside && !selector.wildcard && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("option", {
2406
- value: modelRaw,
2407
- children: `${modelRaw}${t("catalog.outside.short")}`
2408
- })
2409
- ]
2410
- }),
2411
- groupMissing && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2412
- className: FallbacksCard_module_css_default.hint,
2413
- children: t("chains.selector.noModelsStrict")
2414
- })
2415
- ]
2416
- })]
2417
- }),
2418
- (providerOutside || modelOutside) && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
2419
- className: FallbacksCard_module_css_default.hint,
2420
- children: [t("catalog.outside.hint"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(InfoHint, {
2421
- label: t("catalog.outside.tooltip"),
2422
- disabled
2423
- })]
2424
- }),
2425
- selector.wildcard && !modelDisabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2426
- className: FallbacksCard_module_css_default.hint,
2427
- children: t("chains.selector.wildcardLegacy")
2428
- }),
2429
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2430
- className: FallbacksCard_module_css_default.cardFoot,
2431
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2492
+ }),
2493
+ selector.wildcard && !modelDisabled && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2494
+ className: FallbacksCard_module_css_default.selectorHint,
2495
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
2496
+ className: FallbacksCard_module_css_default.selectorHintText,
2497
+ title: t("chains.selector.wildcardLegacy"),
2498
+ children: t("chains.selector.wildcardLegacy")
2499
+ })
2500
+ }),
2501
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2432
2502
  type: "button",
2433
- className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger}`,
2434
- "data-tip": t("chains.selector.remove"),
2435
- "aria-label": t("chains.selector.remove"),
2503
+ className: `${FallbacksCard_module_css_default.iconButton} ${FallbacksCard_module_css_default.iconButtonDanger} ${FallbacksCard_module_css_default.selectorRemove}`,
2504
+ "data-tip": t("chains.selector.remove", { index: String(index) }),
2505
+ "aria-label": t("chains.selector.remove", { index: String(index) }),
2506
+ disabled,
2436
2507
  onClick: onRemove,
2437
2508
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TrashIcon, {})
2509
+ }),
2510
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
2511
+ type: "button",
2512
+ ref: reorder.gripRef,
2513
+ className: `${FallbacksCard_module_css_default.dragHandle} ${FallbacksCard_module_css_default.selectorGrip}`,
2514
+ draggable: !disabled,
2515
+ "data-tip": t("chains.selector.reorder", { index: String(index) }),
2516
+ "aria-label": t("chains.selector.reorder", { index: String(index) }),
2517
+ disabled,
2518
+ onDragStart: () => {
2519
+ if (disabled) return;
2520
+ reorder.onDragStart();
2521
+ },
2522
+ onDragEnd: reorder.onDragEnd,
2523
+ onKeyDown: (event) => {
2524
+ if (disabled) return;
2525
+ const step = event.key === "ArrowUp" ? -1 : event.key === "ArrowDown" ? 1 : 0;
2526
+ if (step === 0) return;
2527
+ event.preventDefault();
2528
+ reorder.onKeyMove(index - 1, index - 1 + step);
2529
+ },
2530
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(GripIcon, {})
2438
2531
  })
2439
- })
2440
- ]
2532
+ ]
2533
+ })
2534
+ });
2535
+ }
2536
+ /**
2537
+ * One chain's selector rows plus their drag state (plan
2538
+ * fallbacks-chain-reorder T1). The list owns the dragged/over index pair —
2539
+ * card-local state, no DataTransfer payload (the jsdom-testable slot-card
2540
+ * pattern), one instance per rendered chain, so hooks are never called inside
2541
+ * a loop and no two lists share a drag. All three chain editors (default
2542
+ * chain, time-slot chains, role chains) render through this component.
2543
+ */
2544
+ function ChainSelectorList({ selectors, catalog, configuredProviders, disabled, t, onChange, onRemove, onMove }) {
2545
+ const [draggedIndex, setDraggedIndex] = (0, react.useState)(null);
2546
+ const [overIndex, setOverIndex] = (0, react.useState)(null);
2547
+ const settle = () => {
2548
+ setDraggedIndex(null);
2549
+ setOverIndex(null);
2550
+ };
2551
+ const gripRefs = (0, react.useRef)([]);
2552
+ const [pendingFocus, setPendingFocus] = (0, react.useState)(null);
2553
+ (0, react.useEffect)(() => {
2554
+ if (pendingFocus === null) return;
2555
+ gripRefs.current[pendingFocus]?.focus();
2556
+ setPendingFocus(null);
2557
+ }, [pendingFocus]);
2558
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
2559
+ className: FallbacksCard_module_css_default.chainSelectors,
2560
+ children: selectors.map((selector, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
2561
+ index: index + 1,
2562
+ selector,
2563
+ catalog,
2564
+ configuredProviders,
2565
+ disabled,
2566
+ t,
2567
+ onChange: (patch) => {
2568
+ onChange(index, patch);
2569
+ },
2570
+ onRemove: () => {
2571
+ onRemove(index);
2572
+ },
2573
+ reorder: {
2574
+ dragging: draggedIndex === index,
2575
+ dropTarget: draggedIndex !== null && draggedIndex !== index && overIndex === index,
2576
+ active: draggedIndex !== null,
2577
+ gripRef: (node) => {
2578
+ gripRefs.current[index] = node;
2579
+ },
2580
+ onDragStart: () => {
2581
+ setDraggedIndex(index);
2582
+ setOverIndex(index);
2583
+ },
2584
+ onDragOver: () => {
2585
+ if (draggedIndex === null || overIndex === index) return;
2586
+ setOverIndex(index);
2587
+ },
2588
+ onDrop: () => {
2589
+ const from = draggedIndex;
2590
+ settle();
2591
+ if (from !== null && from !== index) onMove(from, index);
2592
+ },
2593
+ onDragEnd: settle,
2594
+ onKeyMove: (from, to) => {
2595
+ if (from === to || from < 0 || to < 0 || from >= selectors.length || to >= selectors.length) return;
2596
+ setPendingFocus(to);
2597
+ onMove(from, to);
2598
+ }
2599
+ }
2600
+ }, index))
2441
2601
  });
2442
2602
  }
2443
2603
  /**
@@ -2648,6 +2808,24 @@ window.__ModuleLoader__.load({
2648
2808
  selectors: row.selectors.filter((_, index) => index !== selectorIndex)
2649
2809
  }));
2650
2810
  };
2811
+ const reorderAllDayChainSelector = (from, to) => {
2812
+ setAllDayChainRow((row) => ({
2813
+ ...row,
2814
+ selectors: moveItem(row.selectors, from, to)
2815
+ }));
2816
+ };
2817
+ const reorderTimeSlotSelector = (slotIndex, from, to) => {
2818
+ setTimeSlotRows((rows) => rows.map((row, index) => index === slotIndex ? {
2819
+ ...row,
2820
+ selectors: moveItem(row.selectors, from, to)
2821
+ } : row));
2822
+ };
2823
+ const reorderRoleSelector = (roleIndex, from, to) => {
2824
+ setRoleRows((rows) => rows.map((row, index) => index === roleIndex ? {
2825
+ ...row,
2826
+ selectors: moveItem(row.selectors, from, to)
2827
+ } : row));
2828
+ };
2651
2829
  const updateRoleRow = (index, patch) => {
2652
2830
  setRoleRows((rows) => {
2653
2831
  const next = rows.map((row) => ({ ...row }));
@@ -3137,30 +3315,33 @@ window.__ModuleLoader__.load({
3137
3315
  className: FallbacksCard_module_css_default.hint,
3138
3316
  children: t("validation.slotChainRequired")
3139
3317
  }),
3140
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3141
- className: FallbacksCard_module_css_default.chainSelectors,
3142
- children: row.selectors.map((selector, selectorIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
3143
- selector,
3318
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3319
+ className: FallbacksCard_module_css_default.chainBlock,
3320
+ "data-chain-block": "",
3321
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorList, {
3322
+ selectors: row.selectors,
3144
3323
  catalog: catalogOf(state),
3145
3324
  configuredProviders: state.configuredProviders,
3146
3325
  disabled: !writable,
3147
3326
  t,
3148
- onChange: (patch) => {
3327
+ onChange: (selectorIndex, patch) => {
3149
3328
  updateTimeSlotSelector(index, selectorIndex, patch);
3150
3329
  },
3151
- onRemove: () => {
3330
+ onRemove: (selectorIndex) => {
3152
3331
  removeTimeSlotSelector(index, selectorIndex);
3332
+ },
3333
+ onMove: (from, to) => {
3334
+ reorderTimeSlotSelector(index, from, to);
3153
3335
  }
3154
- }, selectorIndex))
3155
- }),
3156
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3157
- type: "button",
3158
- className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3159
- disabled: !writable,
3160
- onClick: () => {
3161
- addTimeSlotSelector(index);
3162
- },
3163
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("timeSlots.selector.add")]
3336
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3337
+ type: "button",
3338
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3339
+ disabled: !writable,
3340
+ onClick: () => {
3341
+ addTimeSlotSelector(index);
3342
+ },
3343
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("timeSlots.selector.add")]
3344
+ })]
3164
3345
  }),
3165
3346
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3166
3347
  className: FallbacksCard_module_css_default.cardFoot,
@@ -3276,30 +3457,32 @@ window.__ModuleLoader__.load({
3276
3457
  }),
3277
3458
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3278
3459
  className: FallbacksCard_module_css_default.list,
3279
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3460
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3280
3461
  className: FallbacksCard_module_css_default.editorCard,
3281
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3282
- className: FallbacksCard_module_css_default.chainSelectors,
3283
- children: allDayChainRow.selectors.map((selector, selectorIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
3284
- selector,
3462
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3463
+ className: FallbacksCard_module_css_default.chainBlock,
3464
+ "data-chain-block": "",
3465
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorList, {
3466
+ selectors: allDayChainRow.selectors,
3285
3467
  catalog: catalogOf(state),
3286
3468
  configuredProviders: state.configuredProviders,
3287
3469
  disabled: !writable,
3288
3470
  t,
3289
- onChange: (patch) => {
3471
+ onChange: (selectorIndex, patch) => {
3290
3472
  updateAllDayChainSelector(selectorIndex, patch);
3291
3473
  },
3292
- onRemove: () => {
3474
+ onRemove: (selectorIndex) => {
3293
3475
  removeAllDayChainSelector(selectorIndex);
3294
- }
3295
- }, selectorIndex))
3296
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3297
- type: "button",
3298
- className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3299
- disabled: !writable,
3300
- onClick: addAllDayChainSelector,
3301
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("timeSlots.selector.add")]
3302
- })]
3476
+ },
3477
+ onMove: reorderAllDayChainSelector
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: addAllDayChainSelector,
3483
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("timeSlots.selector.add")]
3484
+ })]
3485
+ })
3303
3486
  })
3304
3487
  })
3305
3488
  ]
@@ -3439,7 +3622,8 @@ window.__ModuleLoader__.load({
3439
3622
  const seed = seedInfo.get(row.id.trim());
3440
3623
  const seedBadge = seedBadgeLabel(seed, t);
3441
3624
  const personaBlank = row.persona.trim() === "";
3442
- const roleSummary = row.selectors.map(selectorRowToRaw).find((entry) => entry !== "") ?? row.fallback;
3625
+ const roleChainSummary = chainSummary(row.selectors);
3626
+ const roleSummary = roleChainSummary ?? row.fallback;
3443
3627
  const roleExpanded = !row.collapsed || !writable;
3444
3628
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3445
3629
  className: FallbacksCard_module_css_default.editorCard,
@@ -3467,6 +3651,7 @@ window.__ModuleLoader__.load({
3467
3651
  }),
3468
3652
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3469
3653
  className: FallbacksCard_module_css_default.collapseMeta,
3654
+ title: roleChainSummary,
3470
3655
  children: roleSummary
3471
3656
  })
3472
3657
  ]
@@ -3546,23 +3731,39 @@ window.__ModuleLoader__.load({
3546
3731
  })
3547
3732
  }),
3548
3733
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
3549
- className: FallbacksCard_module_css_default.chainSelectors,
3550
- children: [row.selectors.map((selector, selectorIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorEditor, {
3551
- selector,
3552
- catalog: catalogOf(state),
3553
- configuredProviders: state.configuredProviders,
3554
- disabled: !writable,
3555
- t,
3556
- onChange: (patch) => {
3557
- updateRoleSelector(index, selectorIndex, patch);
3558
- },
3559
- onRemove: () => {
3560
- removeRoleSelector(index, selectorIndex);
3561
- }
3562
- }, selectorIndex)), row.selectors.every((selector) => selectorRowToRaw(selector) === "") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3563
- className: FallbacksCard_module_css_default.hint,
3564
- children: seed !== void 0 ? t("roles.seedChainOptional", { id: row.id }) : t("validation.roleChainRequired", { id: row.id })
3565
- })]
3734
+ className: FallbacksCard_module_css_default.chainBlock,
3735
+ "data-chain-block": "",
3736
+ children: [
3737
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ChainSelectorList, {
3738
+ selectors: row.selectors,
3739
+ catalog: catalogOf(state),
3740
+ configuredProviders: state.configuredProviders,
3741
+ disabled: !writable,
3742
+ t,
3743
+ onChange: (selectorIndex, patch) => {
3744
+ updateRoleSelector(index, selectorIndex, patch);
3745
+ },
3746
+ onRemove: (selectorIndex) => {
3747
+ removeRoleSelector(index, selectorIndex);
3748
+ },
3749
+ onMove: (from, to) => {
3750
+ reorderRoleSelector(index, from, to);
3751
+ }
3752
+ }),
3753
+ row.selectors.every((selector) => selectorRowToRaw(selector) === "") && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
3754
+ className: FallbacksCard_module_css_default.hint,
3755
+ children: seed !== void 0 ? t("roles.seedChainOptional", { id: row.id }) : t("validation.roleChainRequired", { id: row.id })
3756
+ }),
3757
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3758
+ type: "button",
3759
+ className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3760
+ disabled: !writable,
3761
+ onClick: () => {
3762
+ addRoleSelector(index);
3763
+ },
3764
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("roles.selector.add")]
3765
+ })
3766
+ ]
3566
3767
  }),
3567
3768
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3568
3769
  className: FallbacksCard_module_css_default.ruleGrid,
@@ -3589,15 +3790,6 @@ window.__ModuleLoader__.load({
3589
3790
  })]
3590
3791
  })
3591
3792
  }),
3592
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
3593
- type: "button",
3594
- className: `${FallbacksCard_module_css_default.outlineButton} ${FallbacksCard_module_css_default.addButton}`,
3595
- disabled: !writable,
3596
- onClick: () => {
3597
- addRoleSelector(index);
3598
- },
3599
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(PlusIcon, {}), t("roles.selector.add")]
3600
- }),
3601
3793
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
3602
3794
  className: FallbacksCard_module_css_default.cardFoot,
3603
3795
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
@@ -35,6 +35,9 @@ export declare const zh: {
35
35
  'rootChain.tooltip': string;
36
36
  'defaultModel.label': string;
37
37
  'chains.selector.remove': string;
38
+ 'chains.selector.providerAria': string;
39
+ 'chains.selector.modelAria': string;
40
+ 'chains.selector.reorder': string;
38
41
  'chains.selector.providerPlaceholder': string;
39
42
  'chains.selector.modelPlaceholder': string;
40
43
  'chains.selector.wildcardLegacy': string;
@@ -224,6 +227,9 @@ export declare const en: {
224
227
  'rootChain.tooltip': string;
225
228
  'defaultModel.label': string;
226
229
  'chains.selector.remove': string;
230
+ 'chains.selector.providerAria': string;
231
+ 'chains.selector.modelAria': string;
232
+ 'chains.selector.reorder': string;
227
233
  'chains.selector.providerPlaceholder': string;
228
234
  'chains.selector.modelPlaceholder': string;
229
235
  'chains.selector.wildcardLegacy': string;
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "dsh",
6
6
  "dsh-plugin"
7
7
  ],
8
- "version": "0.6.7",
8
+ "version": "0.6.9",
9
9
  "type": "module",
10
10
  "main": "./dist/index.js",
11
11
  "types": "./dist/index.d.ts",