@michengai/dsh-agency-agents 0.1.33 → 0.1.35

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/CHANGELOG.md CHANGED
@@ -6,6 +6,15 @@ The five most recent published versions are listed below.
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## 0.1.35 - 2026-09-09
10
+
11
+ - Unified settings headings, descriptions, and action layouts; maintenance controls no longer squeeze titles or versions. The layout adapts to native DSH settings without Codex UI.
12
+
13
+ ## 0.1.34 - 2026-09-08
14
+
15
+ - Fixed the composer Expert picker so its scrollable menu opens within the available viewport space instead of being clipped when many experts are enabled.
16
+ - Kept the initial enabled-first ordering in Expert Settings stable while toggling individual experts, preventing cards from jumping during bulk setup.
17
+
9
18
  ## 0.1.33 - 2026-09-07
10
19
 
11
20
  - Added independent in-product update checks with automatic updates when a verified DSH update service is available and a profile-specific manual fallback otherwise.
@@ -6,6 +6,15 @@
6
6
 
7
7
  ## 未发布
8
8
 
9
+ ## 0.1.35 - 2026-09-09
10
+
11
+ - 统一设置页标题、说明与操作布局,标题及版本不再被维护按钮挤压;适配原生 DSH 设置内容区,无需安装 Codex UI。
12
+
13
+ ## 0.1.34 - 2026-09-08
14
+
15
+ - 修复输入框「专家」选择器在启用较多专家时超出视口而被截断的问题,菜单现在会在可用空间内展开并滚动。
16
+ - 设置页首次进入后保持已启用优先的卡片顺序,连续启停专家不再让卡片跳动。
17
+
9
18
  ## 0.1.33 - 2026-09-07
10
19
 
11
20
  - 新增独立的插件内检查更新能力:仅在已验证的 DSH 更新服务可用时自动更新,其余环境提供与 Profile 对应的手工更新命令。
package/README.md CHANGED
@@ -22,13 +22,12 @@
22
22
 
23
23
  ## Features
24
24
 
25
- - Filter by category or search, then enable or disable bundled experts in **Settings → Experts**.
26
- - Summon enabled experts by their localized name from the composer's **Experts** picker.
27
- - Use `list_experts` to discover experts and `summon_expert` to start a one-shot specialist subagent.
28
- - Use 321 bundled personas immediately, or connect a separately synchronized expert directory.
29
- - Paste one sentence into DSH, Codex, or WorkBuddy and let that agent install the plugin locally.
25
+ Choose a specialist in DSH for code review, design, operations, or research. All 321 experts are bundled and ready to use after installation.
30
26
 
31
- The parent session keeps task context, judgment, and the final answer. Expert children provide a specialist perspective only and cannot summon further experts.
27
+ - **Find the right expert**: filter by category or search in **Settings → Experts**.
28
+ - **Enable the roles you need**: keep the picker focused by enabling or disabling experts.
29
+ - **Describe the task directly**: use `@` or the **Experts** picker, then write your complete request.
30
+ - **Get one final delivery**: experts provide specialist analysis and the parent conversation brings the results together. Experts cannot summon further experts.
32
31
 
33
32
  ## Screenshots
34
33
 
@@ -46,13 +45,18 @@ The localized expert name is inserted as a short tag; write the complete task ne
46
45
 
47
46
  ## DSH product ecosystem
48
47
 
49
- This product can be installed independently or used through the desktop app or Web suite. They share the same DSH core but serve different ways of working:
48
+ For a ready-to-use workbench, download [DSH Codex Desktop](https://github.com/MichengAI/dsh-codex-desktop/releases). If you already use [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness), install any of these eight plugins individually. The desktop app includes all eight.
50
49
 
51
- | Product | Relationship to this product |
50
+ | Plugin | What you can do |
52
51
  | --- | --- |
53
- | [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) | The host runtime that provides models, sessions, tools, and the plugin system |
54
- | [DSH Codex Desktop](https://github.com/MichengAI/dsh-codex-desktop) | A ready-to-install desktop product with this product and the other five feature products built in |
55
- | Six feature products | [Codex UI](https://github.com/MichengAI/dsh-codex-ui) · [IM Connect](https://github.com/MichengAI/dsh-im-connect) · [Automation](https://github.com/MichengAI/dsh-automation) · [Skills Manager](https://github.com/MichengAI/dsh-skills-manager) · [Archive Manager](https://github.com/MichengAI/dsh-archive-manager) · [Agency Agents](https://github.com/MichengAI/dsh-agency-agents) |
52
+ | [Codex UI](https://github.com/MichengAI/dsh-codex-ui) | Organize projects and conversations, search tasks, and navigate chat turns |
53
+ | [IM Connect](https://github.com/MichengAI/dsh-im-connect) | Send tasks and receive replies through your usual messenger |
54
+ | [Automation](https://github.com/MichengAI/dsh-automation) | Schedule tasks and review each run |
55
+ | [Skills Manager](https://github.com/MichengAI/dsh-skills-manager) | Find, enable, create, and import local skills |
56
+ | [Archive Manager](https://github.com/MichengAI/dsh-archive-manager) | Search, restore, or clean up archived conversations |
57
+ | [Agency Agents](https://github.com/MichengAI/dsh-agency-agents) | Choose and summon specialists for your task |
58
+ | [BTW](https://github.com/MichengAI/dsh-btw) | Ask side questions without interrupting the main task |
59
+ | [Simplify](https://github.com/MichengAI/dsh-simplify) | Use /simplify to improve code within your Git changes |
56
60
 
57
61
  ## Prerequisites
58
62
 
@@ -62,40 +66,16 @@ This product can be installed independently or used through the desktop app or W
62
66
 
63
67
  ## Installation
64
68
 
65
- `dsh plugin add` forwards to `pnpm add` in the profile directory. Without a version and official registry, a local mirror or minimum-release-age policy can leave you on an older build.
69
+ The installation commands below use the official npm registry.
66
70
 
67
- ### Ask another agent to install it
71
+ ### Ask an agent to install it (recommended)
68
72
 
69
- This plugin runs inside DeepSeek Harness Web. Copy one of the sentences below into DSH, Codex, or WorkBuddy and let that agent install it into your local `web` profile.
70
-
71
- From npm:
73
+ Send the prompt below to any agent that can run terminal commands on your computer. Replace `web` with your actual profile. Once installed, use the plugin in DSH.
72
74
 
73
75
  ```text
74
- Install the latest DSH plugin @michengai/dsh-agency-agents into my local web profile using the official npm registry: dsh plugin --profile web add @michengai/dsh-agency-agents@latest --registry=https://registry.npmjs.org/. Then run dsh --profile web --dump-config, confirm agency-agents is mounted, and remind me to restart DSH Web and hard-refresh the browser.
75
- ```
76
-
77
- From source:
78
-
79
- ```text
80
- Install the DSH plugin from source at https://github.com/MichengAI/dsh-agency-agents: clone it, run pnpm install --frozen-lockfile and pnpm build, then run dsh plugin --profile web add . from that directory. Do not copy lib by itself. Then run dsh --profile web --dump-config, confirm agency-agents is mounted, and remind me to restart DSH Web and hard-refresh the browser.
81
- ```
82
-
83
- | Product | How to use it |
84
- | --- | --- |
85
- | DSH | Send one of the sentences above to the current session. |
86
- | Codex | Send one of the sentences above to Codex and let it install locally. |
87
- | WorkBuddy | Send one of the sentences above to WorkBuddy; for a source install you can also paste `https://github.com/MichengAI/dsh-agency-agents`. |
88
-
89
- Codex and WorkBuddy only install the plugin. After that, open DSH Web and use **Settings → Experts**.
90
-
91
- You can also run the same npm command yourself:
92
-
93
- ```powershell
94
- dsh plugin --profile web add @michengai/dsh-agency-agents@latest --registry=https://registry.npmjs.org/
76
+ Install the DSH plugin @michengai/dsh-agency-agents into my local web profile by running: dsh plugin --profile web add @michengai/dsh-agency-agents@latest --registry=https://registry.npmjs.org/. Then run dsh --profile web --dump-config, confirm the configuration includes agency-agents, agency-agents-remote, and explain how to reload DSH and start using the plugin.
95
77
  ```
96
78
 
97
- If `dsh` is not on PATH, replace the leading `dsh` with `npx --yes @deepseek-ai/dsh`.
98
-
99
79
  ### Install the latest package from the official npm registry
100
80
 
101
81
  Run this from any PowerShell directory:
@@ -111,24 +91,6 @@ To pin a release, replace `@latest` with a version such as `@0.1.17`.
111
91
 
112
92
  The configuration output should contain `agency-agents` and `agency-agents-remote`. Restart DSH Web and hard-refresh the browser. Do not copy client files manually: the Settings page needs the mounted Remote service.
113
93
 
114
- ### Install from source
115
-
116
- Use this for debugging or unpublished changes. The cloned directory becomes the plugin source path:
117
-
118
- ```powershell
119
- [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
120
- $OutputEncoding = [System.Text.Encoding]::UTF8
121
- Set-Location D:\Repository\deepseek-harness-plugin
122
- git clone https://github.com/MichengAI/dsh-agency-agents.git
123
- Set-Location .\dsh-agency-agents
124
- pnpm install --frozen-lockfile
125
- pnpm build
126
- dsh plugin --profile web add .
127
- dsh --profile web --dump-config
128
- ```
129
-
130
- Restart DSH Web and hard-refresh the browser. `dsh plugin ... add .` reads the package metadata and `cordis.patch.yml`; do not install by copying `lib` directly.
131
-
132
94
  ## Updates
133
95
 
134
96
  The settings title shows the installed version and a **Check for updates** button. When a newer release is available, **Update automatically** runs only when the DSH CLI or Desktop update service is available; otherwise, the dialog provides a profile-specific manual command to copy and run.
@@ -730,6 +692,24 @@ Set `AGENCY_AGENTS_ROOT` to use an external expert directory. Persona bodies fro
730
692
 
731
693
  ## Secondary development
732
694
 
695
+ ### Install from source
696
+
697
+ Use this for debugging or unpublished changes. The cloned directory becomes the plugin source path:
698
+
699
+ ```powershell
700
+ [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
701
+ $OutputEncoding = [System.Text.Encoding]::UTF8
702
+ Set-Location D:\Repository\deepseek-harness-plugin
703
+ git clone https://github.com/MichengAI/dsh-agency-agents.git
704
+ Set-Location .\dsh-agency-agents
705
+ pnpm install --frozen-lockfile
706
+ pnpm build
707
+ dsh plugin --profile web add .
708
+ dsh --profile web --dump-config
709
+ ```
710
+
711
+ Restart DSH Web and hard-refresh the browser. `dsh plugin ... add .` reads the package metadata and `cordis.patch.yml`; do not install by copying `lib` directly.
712
+
733
713
  - [src\index.ts](src/index.ts): host entry point for catalog loading, tools, and settings.
734
714
  - [src\remote-contract.ts](src/remote-contract.ts) and [src\remote.ts](src/remote.ts): Remote contract and implementation.
735
715
  - [src\client\index.ts](src/client/index.ts): Settings page, composer button, and `@` trigger.
@@ -746,8 +726,6 @@ pnpm verify
746
726
  dsh plugin --profile web add .
747
727
  ```
748
728
 
749
- Handoff and iteration notes stay in the local `docs` directory and are not tracked in Git; a fresh clone will not include that handover entry.
750
-
751
729
  The published package includes `lib`, `assets`, the patch, and the root README/license files. Do not publish `node_modules` or local development files.
752
730
 
753
731
  ## Validation
@@ -765,7 +743,3 @@ pnpm verify
765
743
  ## License and attribution
766
744
 
767
745
  This project’s TypeScript source, build scripts, and documentation use [Apache License 2.0](LICENSE). Bundled personas originate from [The Agency](https://github.com/msitarzewski/agency-agents) and remain MIT-licensed; see [assets\agency-agents\LICENSE](assets/agency-agents/LICENSE).
768
-
769
- ## Changelog
770
-
771
- See [CHANGELOG.md](CHANGELOG.md) for the five most recent releases.
package/README.zh-CN.md CHANGED
@@ -22,13 +22,12 @@
22
22
 
23
23
  ## 功能概览
24
24
 
25
- - 在「设置 → 专家」中按分类筛选或搜索,再启用或停用内置专家。
26
- - 在输入框的「专家」中按当前语言的名称召唤已启用的专家处理完整任务。
27
- - 提供 `list_experts` 与 `summon_expert` 工具,分别用于发现专家和启动一次性子代理。
28
- - 内置 321 份 persona,无需额外下载;也可接入自行同步的专家目录。
29
- - 可把一句话复制到 DSH、Codex 或 WorkBuddy,让对方代装到本机 DSH。
25
+ 遇到代码审查、设计、运营或研究任务时,在 DSH 中选一位合适的专家,让它从专业角度协助你完成工作。内置 321 名专家,安装后即可选择使用。
30
26
 
31
- 主会话保留任务上下文、判断和最终交付;专家子代理只提供专业视角,不能继续召唤专家,避免递归委派。
27
+ - **找到合适的专家**:在「设置 → 专家」按分类筛选或搜索。
28
+ - **只启用需要的角色**:随时启用或停用专家,让选择列表更简洁。
29
+ - **直接交代任务**:在输入框用 `@` 或「专家」选择角色,再写下完整需求。
30
+ - **由主会话统一交付**:专家提供专业分析,主会话汇总结果;专家不会继续召唤其他专家。
32
31
 
33
32
  ## 界面预览
34
33
 
@@ -46,13 +45,18 @@
46
45
 
47
46
  ## DSH 产品生态
48
47
 
49
- 本产品既可以独立安装,也可以随桌面端或 Web 套件一起使用。它们共享同一个 DSH 核心,但面向不同的使用方式:
48
+ 想直接使用完整工作台,可下载 [DSH Codex Desktop](https://github.com/MichengAI/dsh-codex-desktop/releases);已有 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) 环境,可按需独立安装以下 8 个自研插件。桌面端已随附这些插件。
50
49
 
51
- | 产品 | 与本产品的关系 |
50
+ | 插件 | 你可以用它做什么 |
52
51
  | --- | --- |
53
- | [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness) | 本产品的运行宿主,提供模型、会话、工具和插件系统 |
54
- | [DSH Codex Desktop](https://github.com/MichengAI/dsh-codex-desktop) | 下载安装即用的桌面产品,已内置本产品和其他 5 个功能产品 |
55
- | 6 个功能产品 | [Codex UI](https://github.com/MichengAI/dsh-codex-ui) · [IM Connect](https://github.com/MichengAI/dsh-im-connect) · [Automation](https://github.com/MichengAI/dsh-automation) · [Skills Manager](https://github.com/MichengAI/dsh-skills-manager) · [Archive Manager](https://github.com/MichengAI/dsh-archive-manager) · [Agency Agents](https://github.com/MichengAI/dsh-agency-agents) |
52
+ | [Codex UI](https://github.com/MichengAI/dsh-codex-ui) | 整理项目与会话、搜索任务、跳转对话轮次 |
53
+ | [IM Connect](https://github.com/MichengAI/dsh-im-connect) | 从微信、飞书、钉钉等消息平台下任务、收回复 |
54
+ | [Automation](https://github.com/MichengAI/dsh-automation) | 按计划执行任务,查看每次运行的结果 |
55
+ | [Skills Manager](https://github.com/MichengAI/dsh-skills-manager) | 统一查找、启停、创建和导入本机技能 |
56
+ | [Archive Manager](https://github.com/MichengAI/dsh-archive-manager) | 搜索、恢复或清理已归档会话 |
57
+ | [Agency Agents](https://github.com/MichengAI/dsh-agency-agents) | 按任务选择并召唤专业角色 |
58
+ | [BTW](https://github.com/MichengAI/dsh-btw) | 在当前上下文中临时旁问,不打断主任务 |
59
+ | [Simplify](https://github.com/MichengAI/dsh-simplify) | 用 /simplify 整理 Git 改动范围内的代码 |
56
60
 
57
61
  ## 前置条件
58
62
 
@@ -62,40 +66,16 @@
62
66
 
63
67
  ## 安装
64
68
 
65
- `dsh plugin add` 会转发到 profile 目录里的 `pnpm add`。不写版本、不指定官方源时,本机镜像和最短发布间隔可能让你停在旧版。
69
+ 以下安装命令使用官方 npm 源。
66
70
 
67
- ### 交给其他 Agent 一句话安装
71
+ ### 让 Agent 帮你安装(推荐)
68
72
 
69
- 本插件运行在 DeepSeek Harness Web 里。把下面其中一句复制到 DSH、Codex 或 WorkBuddy,让它代你安装到本机 `web` profile。
70
-
71
- 从 npm 安装:
73
+ 把下面这段话发给任意能够执行本机终端命令的 Agent。将 `web` 替换为实际使用的 profile;安装完成后,在 DSH 中使用本插件。
72
74
 
73
75
  ```text
74
- 请把 DSH 插件 @michengai/dsh-agency-agents 最新版装进本机 web profile,使用官方 npm 源执行:dsh plugin --profile web add @michengai/dsh-agency-agents@latest --registry=https://registry.npmjs.org/。装完执行 dsh --profile web --dump-config,确认已挂载 agency-agents,并提醒我重启 DSH Web 后硬刷新浏览器。
75
- ```
76
-
77
- 从源码安装:
78
-
79
- ```text
80
- 请从源码安装 DSH 插件 https://github.com/MichengAI/dsh-agency-agents:克隆到本机后执行 pnpm install --frozen-lockfile 和 pnpm build,再用 dsh plugin --profile web add . 把当前目录装进 web profile。不要只复制 lib。装完执行 dsh --profile web --dump-config,确认已挂载 agency-agents,并提醒我重启 DSH Web 后硬刷新浏览器。
81
- ```
82
-
83
- | 产品 | 怎么用 |
84
- | --- | --- |
85
- | DSH | 把上面其中一句发给当前会话。 |
86
- | Codex | 把上面其中一句发给 Codex,让它在本机执行安装。 |
87
- | WorkBuddy | 把上面其中一句发给 WorkBuddy;源码安装也可同时粘贴仓库地址 `https://github.com/MichengAI/dsh-agency-agents`。 |
88
-
89
- Codex 和 WorkBuddy 只负责代装;装好后仍要打开 DSH Web 使用「设置 → 专家」。
90
-
91
- 也可以自己执行同一条 npm 命令:
92
-
93
- ```powershell
94
- dsh plugin --profile web add @michengai/dsh-agency-agents@latest --registry=https://registry.npmjs.org/
76
+ 请将 DSH 插件 @michengai/dsh-agency-agents 安装到本机 web profile,执行:dsh plugin --profile web add @michengai/dsh-agency-agents@latest --registry=https://registry.npmjs.org/。安装后执行 dsh --profile web --dump-config,确认配置包含 agency-agents, agency-agents-remote,并告诉我如何重新加载 DSH 和开始使用。
95
77
  ```
96
78
 
97
- 未把 `dsh` 装进 PATH 时,把开头的 `dsh` 换成 `npx --yes @deepseek-ai/dsh`。
98
-
99
79
  ### 从官方 npm 安装最新版
100
80
 
101
81
  在任意 PowerShell 目录执行:
@@ -111,24 +91,6 @@ dsh --profile web --dump-config
111
91
 
112
92
  配置输出中应包含 `agency-agents` 与 `agency-agents-remote`。安装后重启 DSH Web 并在浏览器硬刷新;请勿手工复制客户端文件,否则设置页所需的 Remote 服务不会被挂载。
113
93
 
114
- ### 从源码安装
115
-
116
- 适用于调试或使用未发布改动。克隆后的本地路径就是插件安装路径:
117
-
118
- ```powershell
119
- [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
120
- $OutputEncoding = [System.Text.Encoding]::UTF8
121
- Set-Location D:\Repository\deepseek-harness-plugin
122
- git clone https://github.com/MichengAI/dsh-agency-agents.git
123
- Set-Location .\dsh-agency-agents
124
- pnpm install --frozen-lockfile
125
- pnpm build
126
- dsh plugin --profile web add .
127
- dsh --profile web --dump-config
128
- ```
129
-
130
- 完成后重启 DSH Web 并硬刷新浏览器。`dsh plugin ... add .` 会读取当前目录的包信息和 `cordis.patch.yml`;不要改为直接复制 `lib` 目录。
131
-
132
94
  ## 在线更新
133
95
 
134
96
  设置标题会显示当前版本和“检查更新”按钮。发现新版后,只有检测到 DSH CLI 或 Desktop 更新服务时才可使用“自动更新”;其他环境会在弹窗中提供可复制、与当前 Profile 对应的手工更新命令。
@@ -730,6 +692,24 @@ dsh --profile web --dump-config
730
692
 
731
693
  ## 二次开发
732
694
 
695
+ ### 从源码安装
696
+
697
+ 适用于调试或使用未发布改动。克隆后的本地路径就是插件安装路径:
698
+
699
+ ```powershell
700
+ [Console]::OutputEncoding = [System.Text.Encoding]::UTF8
701
+ $OutputEncoding = [System.Text.Encoding]::UTF8
702
+ Set-Location D:\Repository\deepseek-harness-plugin
703
+ git clone https://github.com/MichengAI/dsh-agency-agents.git
704
+ Set-Location .\dsh-agency-agents
705
+ pnpm install --frozen-lockfile
706
+ pnpm build
707
+ dsh plugin --profile web add .
708
+ dsh --profile web --dump-config
709
+ ```
710
+
711
+ 完成后重启 DSH Web 并硬刷新浏览器。`dsh plugin ... add .` 会读取当前目录的包信息和 `cordis.patch.yml`;不要改为直接复制 `lib` 目录。
712
+
733
713
  - Host 端入口:[src\index.ts](src/index.ts),负责加载专家目录、注册工具和设置项。
734
714
  - Remote 契约与实现:[src\remote-contract.ts](src/remote-contract.ts)、[src\remote.ts](src/remote.ts)。
735
715
  - 客户端入口:[src\client\index.ts](src/client/index.ts),负责设置页、输入框按钮与 `@` 触发器。
@@ -746,8 +726,6 @@ pnpm verify
746
726
  dsh plugin --profile web add .
747
727
  ```
748
728
 
749
- 交接与迭代文档只保留在本机 `docs` 目录,不纳入 Git;克隆仓库后不会得到交接入口。
750
-
751
729
  发布包只包含 `lib`、`assets`、补丁和根目录说明/许可证;不要将 `node_modules` 或本地开发文件加入发布内容。
752
730
 
753
731
  ## 验证
@@ -765,7 +743,3 @@ pnpm verify
765
743
  ## 许可证与归属
766
744
 
767
745
  本项目 TypeScript 源码、构建脚本和文档采用 [Apache License 2.0](LICENSE)。内置专家 persona 源自 [The Agency](https://github.com/msitarzewski/agency-agents),仍采用 MIT,许可证位于 [assets\agency-agents\LICENSE](assets/agency-agents/LICENSE)。
768
-
769
- ## 更新日志
770
-
771
- 最近五个发布版本见 [CHANGELOG.zh-CN.md](CHANGELOG.zh-CN.md)。
package/lib/client.js CHANGED
@@ -7690,6 +7690,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7690
7690
  else inactive.push(expert);
7691
7691
  return [...active, ...inactive];
7692
7692
  }
7693
+ /** 按首次进入设置页时保存的顺序排列;不在单项启停后重新排序。 */
7694
+ function sortExpertsByOrder(list, order) {
7695
+ const positions = new Map(order.map((slug, index) => [slug, index]));
7696
+ return list.slice().sort((left, right) => {
7697
+ return (positions.get(left.slug) ?? Number.MAX_SAFE_INTEGER) - (positions.get(right.slug) ?? Number.MAX_SAFE_INTEGER);
7698
+ });
7699
+ }
7693
7700
  const DIVISION_COUNTS = Object.fromEntries(DIVISION_ORDER.map((division) => [division, EXPERTS.filter((expert) => expert.division === division).length]));
7694
7701
  /** 根据 slug 稳定分配复用头像;空头像池安全回退为第 0 项。 */
7695
7702
  function expertAvatarIndex(slug, avatarCount) {
@@ -7828,13 +7835,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7828
7835
  const MENU_NAME_OVERRIDE = DIVISION_ORDER.map((division) => inputTriggerSourceId(division)).map((name) => `[role="listbox"] div[data-source=${JSON.stringify(name)}] ~ button`).map((selector) => `${selector} span:last-child`).join(",");
7829
7836
  /** Windows 优先使用彩色 emoji 字体,名称中的普通文字由后续字体安全回退。 */
7830
7837
  const EXPERT_MENU_NAME_STYLE = "flex:1 1 auto;max-width:none;min-width:0;font-family:\"Segoe UI Emoji\",\"Apple Color Emoji\",\"Noto Color Emoji\",sans-serif!important;font-variant-emoji:emoji!important";
7831
- const COMPOSER_CSS = ".aag-btn-wrap{position:relative;order:1;margin-right:-8px}.aag-btn{display:inline-flex;align-items:center;gap:4px;height:28px;padding:0 4px 0 8px;border:none;border-radius:24px;background:transparent;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px;font-weight:500;cursor:pointer}.aag-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.aag-menu{position:absolute;bottom:calc(100% + 4px);left:0;box-sizing:border-box;padding:4px;display:flex;flex-direction:column;gap:0;width:300px;max-width:360px;max-height:calc(100vh - 24px);overflow-y:auto;border:1px solid var(--dsw-alias-border-inverted);border-radius:12px;background:var(--dsw-specific-menu);box-shadow:var(--dsw-shadow-lv3);z-index:10000}.aag-menu-title{padding:8px 10px;font-size:12px;line-height:16px;color:var(--dsw-alias-label-tertiary)}.aag-menu-item{display:flex;align-items:center;gap:8px;width:100%;min-height:40px;padding:8px 10px;border:none;border-radius:10px;background:transparent;cursor:pointer;text-align:left;font-size:14px;line-height:22px;color:var(--dsw-alias-label-primary);box-sizing:border-box}.aag-menu-item:hover{background:var(--dsw-alias-interactive-bg-hover)}.aag-emoji{flex:0 0 auto;font-size:16px}.aag-menu-empty{padding:8px 10px;color:var(--dsw-alias-label-secondary);font-size:13px}[data-composer-card] :has(> button[aria-haspopup=\"listbox\"]) > :nth-child(2){order:2}";
7838
+ const COMPOSER_CSS = ".aag-btn-wrap{position:relative;order:1;margin-right:-8px}.aag-btn{display:inline-flex;align-items:center;gap:4px;height:28px;padding:0 4px 0 8px;border:none;border-radius:24px;background:transparent;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px;font-weight:500;cursor:pointer}.aag-btn:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.aag-menu{position:absolute;bottom:calc(100% + 4px);left:0;box-sizing:border-box;padding:4px;display:flex;flex-direction:column;gap:0;width:300px;max-width:360px;max-height:calc(100dvh - 24px);overflow-y:auto;border:1px solid var(--dsw-alias-border-inverted);border-radius:12px;background:var(--dsw-specific-menu);box-shadow:var(--dsw-shadow-lv3);z-index:10000}.aag-menu[data-placement=\"below\"]{top:calc(100% + 4px);bottom:auto}.aag-menu-title{padding:8px 10px;font-size:12px;line-height:16px;color:var(--dsw-alias-label-tertiary)}.aag-menu-item{display:flex;align-items:center;gap:8px;width:100%;min-height:40px;padding:8px 10px;border:none;border-radius:10px;background:transparent;cursor:pointer;text-align:left;font-size:14px;line-height:22px;color:var(--dsw-alias-label-primary);box-sizing:border-box}.aag-menu-item:hover{background:var(--dsw-alias-interactive-bg-hover)}.aag-emoji{flex:0 0 auto;font-size:16px}.aag-menu-empty{padding:8px 10px;color:var(--dsw-alias-label-secondary);font-size:13px}[data-composer-card] :has(> button[aria-haspopup=\"listbox\"]) > :nth-child(2){order:2}";
7832
7839
  const SETTINGS_CSS = `
7833
7840
  .aag-section{box-sizing:border-box;display:flex;min-width:0;max-width:760px;width:100%;margin:0 auto;flex-direction:column;gap:16px;padding:0 0 32px;color:var(--dsw-alias-label-primary)}
7834
7841
  .aag-toolbar{display:flex;align-items:flex-start;gap:16px;padding-bottom:12px}
7835
- .aag-title-row{display:flex;align-items:center;gap:8px;min-width:0}.aag-settings-links{display:flex;align-items:center;gap:4px}.aag-settings-link{display:inline-flex;align-items:center;gap:5px;min-height:28px;padding:0 8px;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;background:transparent;color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px;text-decoration:none;white-space:nowrap}.aag-settings-link:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.aag-settings-link:focus-visible{outline:2px solid var(--dsw-alias-state-success-primary);outline-offset:2px}.aag-settings-link svg{flex:none}
7842
+ .aag-title-row{display:flex;align-items:center;gap:8px;min-width:0}.aag-settings-links{display:flex;align-items:center;gap:4px;flex-wrap:wrap}.aag-settings-link{display:inline-flex;align-items:center;gap:5px;min-height:28px;padding:0 8px;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;background:transparent;color:var(--dsw-alias-label-secondary);font-size:12px;font-weight:500;line-height:18px;text-decoration:none;white-space:nowrap}.aag-settings-link:hover{background:var(--dsw-alias-interactive-bg-hover);color:var(--dsw-alias-label-primary)}.aag-settings-link:focus-visible{outline:2px solid var(--dsw-alias-state-success-primary);outline-offset:2px}.aag-settings-link svg{flex:none}
7836
7843
  .aag-title{margin:0;font-size:20px;line-height:28px;font-weight:650;letter-spacing:-.2px}
7837
- .aag-desc{margin:4px 0 0;max-width:42em;color:var(--dsw-alias-label-tertiary);font-size:13px;line-height:1.5}
7844
+ .aag-desc{margin:12px 0 0;max-width:42em;color:var(--dsw-alias-label-tertiary);font-size:14px;line-height:22px}
7838
7845
  .aag-actions{display:flex;align-items:center;gap:8px;margin-left:auto}
7839
7846
  .aag-action{box-sizing:border-box;display:inline-flex;align-items:center;justify-content:center;min-height:32px;padding:0 12px;border:1px solid transparent;border-radius:8px;background:var(--dsw-alias-button-primary-fill);color:var(--dsw-alias-label-primary-foreground);font:inherit;font-size:13px;font-weight:550;cursor:pointer;transition:opacity 180ms ease,background 180ms ease,border-color 180ms ease}
7840
7847
  .aag-action:hover:not(:disabled){opacity:.9}.aag-action:disabled{opacity:.5;cursor:default}
@@ -7871,13 +7878,13 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7871
7878
  `;
7872
7879
  const CARD_SETTINGS_CSS = `
7873
7880
  .aag-section{container-type:inline-size}
7874
- .aag-toolbar{display:flex;align-items:center;gap:16px;min-height:44px;padding:0}
7875
- .aag-title-row{display:flex;align-items:baseline;gap:16px;min-width:0;flex-wrap:wrap}
7876
- .aag-title{font-size:22px;line-height:30px;font-weight:700;letter-spacing:0}
7881
+ .aag-toolbar{display:flex;align-items:flex-start;gap:12px;min-height:36px;padding:0}
7882
+ .aag-title-row{display:flex;flex:1;align-items:center;gap:8px 12px;min-width:0;flex-wrap:wrap}
7883
+ .aag-title{font-size:24px;line-height:32px;font-weight:600;letter-spacing:-.4px;white-space:nowrap}
7877
7884
  .aag-header-stat{display:inline-flex;align-items:baseline;gap:5px;color:var(--dsw-alias-label-secondary);font-size:13px;line-height:20px;white-space:nowrap}
7878
7885
  .aag-header-stat strong{color:var(--dsw-alias-label-primary);font-weight:500}
7879
7886
  .aag-actions{margin-left:auto}
7880
- .aag-refresh-button{display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;padding:0;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;background:transparent;color:var(--dsw-alias-label-primary);cursor:pointer}
7887
+ .aag-refresh-button{display:inline-flex;align-items:center;justify-content:center;width:32px;height:32px;padding:0;border:1px solid var(--dsw-alias-border-l2);border-radius:7px;background:transparent;color:var(--dsw-alias-label-primary);cursor:pointer}
7881
7888
  .aag-refresh-button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
7882
7889
  .aag-refresh-button:disabled{opacity:.5;cursor:default}
7883
7890
  .aag-refresh-button:focus-visible,.aag-card-action:focus-visible,.aag-switch-input:focus-visible+.aag-switch-track,.aag-modal-close:focus-visible,.aag-search:focus-visible{outline:2px solid var(--dsw-alias-state-success-primary);outline-offset:2px}
@@ -7918,7 +7925,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
7918
7925
  .aag-modal-title{margin:0;font-size:15px;line-height:22px}
7919
7926
  .aag-modal-close{min-height:32px;padding:0 10px;border:1px solid var(--dsw-alias-border-l2);border-radius:6px;background:transparent;color:var(--dsw-alias-label-primary);font:inherit;font-size:12px;cursor:pointer}
7920
7927
  .aag-prompt-content{margin:0;overflow:auto;padding:16px;white-space:pre-wrap;color:var(--dsw-alias-label-primary);font-family:ui-monospace,SFMono-Regular,Consolas,monospace;font-size:12px;line-height:1.65}
7921
- @container (max-width:519px){.aag-expert-grid{grid-template-columns:1fr}.aag-title-row{gap:8px 12px}.aag-title{width:100%}}
7928
+ @container (max-width:519px){.aag-expert-grid{grid-template-columns:1fr}.aag-title-row{gap:8px 12px}.aag-settings-links{flex-basis:100%}}
7922
7929
  @container (max-width:430px){.aag-card-body{grid-template-columns:40px minmax(0,1fr);column-gap:10px}.aag-expert-avatar{width:40px;height:40px}.aag-card-name{font-size:16px;line-height:22px}}
7923
7930
  @media (prefers-reduced-motion:reduce){.aag-switch-track,.aag-switch-track::after{transition:none}}
7924
7931
  `;
@@ -8047,6 +8054,23 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8047
8054
  function resolveExpertToolbarClick(enabledCount) {
8048
8055
  return enabledCount === 0 ? "settings" : "menu";
8049
8056
  }
8057
+ /**
8058
+ * 让浮层始终留在可视区域内。输入框通常贴近底部,因此默认向上展开;
8059
+ * 当上方空间更小时,改为向下展开并将列表限制在实际可滚动的高度内。
8060
+ */
8061
+ function resolveExpertMenuPosition(trigger, viewportHeight) {
8062
+ const gap = 4;
8063
+ const viewportInset = 12;
8064
+ const above = Math.max(0, Math.floor(trigger.top - gap - viewportInset));
8065
+ const below = Math.max(0, Math.floor(viewportHeight - trigger.bottom - gap - viewportInset));
8066
+ return above >= below ? {
8067
+ placement: "above",
8068
+ maxHeight: above
8069
+ } : {
8070
+ placement: "below",
8071
+ maxHeight: below
8072
+ };
8073
+ }
8050
8074
  const SETTINGS_TRIGGER_LABELS = /* @__PURE__ */ new Set(["设置", "Settings"]);
8051
8075
  const COMPOSER_TRIGGER_SCOPE = "[data-composer-card], .aag-btn-wrap";
8052
8076
  function isSettingsTriggerLabel(label) {
@@ -8146,6 +8170,33 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8146
8170
  const [open, setOpen] = react.default.useState(false);
8147
8171
  const [enabled, setEnabled] = react.default.useState(/* @__PURE__ */ new Set());
8148
8172
  const [insertError, setInsertError] = react.default.useState(null);
8173
+ const [menuPosition, setMenuPosition] = react.default.useState();
8174
+ const rootRef = react.default.useRef(null);
8175
+ react.default.useLayoutEffect(() => {
8176
+ if (!open) return;
8177
+ const updatePosition = () => {
8178
+ const root = rootRef.current;
8179
+ if (root === null) return;
8180
+ const viewportHeight = window.visualViewport?.height ?? window.innerHeight;
8181
+ const next = resolveExpertMenuPosition(root.getBoundingClientRect(), viewportHeight);
8182
+ setMenuPosition((current) => current?.placement === next.placement && current.maxHeight === next.maxHeight ? current : next);
8183
+ };
8184
+ updatePosition();
8185
+ window.addEventListener("resize", updatePosition);
8186
+ window.addEventListener("scroll", updatePosition, true);
8187
+ const visualViewport = window.visualViewport;
8188
+ visualViewport?.addEventListener("resize", updatePosition);
8189
+ visualViewport?.addEventListener("scroll", updatePosition);
8190
+ const observer = typeof ResizeObserver === "undefined" ? void 0 : new ResizeObserver(updatePosition);
8191
+ if (rootRef.current !== null) observer?.observe(rootRef.current);
8192
+ return () => {
8193
+ window.removeEventListener("resize", updatePosition);
8194
+ window.removeEventListener("scroll", updatePosition, true);
8195
+ visualViewport?.removeEventListener("resize", updatePosition);
8196
+ visualViewport?.removeEventListener("scroll", updatePosition);
8197
+ observer?.disconnect();
8198
+ };
8199
+ }, [open]);
8149
8200
  react.default.useEffect(() => {
8150
8201
  if (!open) return;
8151
8202
  const onPointerDown = (ev) => {
@@ -8181,14 +8232,22 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8181
8232
  setOpen(false);
8182
8233
  };
8183
8234
  const groups = groupByDivision(EXPERTS.filter((e) => enabled.has(e.slug)), props.getActive());
8184
- const menu = open ? react.default.createElement("div", { className: "aag-menu" }, insertError === null ? null : react.default.createElement("div", {
8235
+ const menu = open ? react.default.createElement("div", {
8236
+ className: "aag-menu",
8237
+ "data-placement": menuPosition?.placement,
8238
+ style: menuPosition === void 0 ? void 0 : { maxHeight: `${menuPosition.maxHeight}px` }
8239
+ }, insertError === null ? null : react.default.createElement("div", {
8185
8240
  className: "aag-error",
8186
8241
  role: "alert"
8187
8242
  }, insertError), groups.length === 0 ? react.default.createElement("div", { className: "aag-menu-empty" }, props.t("menu.empty")) : groups.map((g) => menuGroup(g, pick, props.t, props.getActive))) : null;
8188
- return react.default.createElement("div", { className: "aag-btn-wrap" }, react.default.createElement("button", {
8243
+ return react.default.createElement("div", {
8244
+ className: "aag-btn-wrap",
8245
+ ref: rootRef
8246
+ }, react.default.createElement("button", {
8189
8247
  type: "button",
8190
8248
  className: "aag-btn",
8191
8249
  title: props.t("button.title"),
8250
+ "aria-expanded": open,
8192
8251
  onMouseDown: keepComposerFocus,
8193
8252
  onClick
8194
8253
  }, expertIcon(), react.default.createElement("span", null, props.t("settings.nav"))), menu);
@@ -8349,6 +8408,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8349
8408
  }
8350
8409
  function ExpertCardsSettings(props) {
8351
8410
  const [state, setState] = react.default.useState(null);
8411
+ const [initialOrder, setInitialOrder] = react.default.useState(null);
8352
8412
  const [error, setError] = react.default.useState(null);
8353
8413
  const [query, setQuery] = react.default.useState("");
8354
8414
  const [division, setDivision] = react.default.useState("");
@@ -8361,6 +8421,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8361
8421
  const load = react.default.useCallback(() => {
8362
8422
  readEnabled(props.remote).then((current) => {
8363
8423
  setState(current);
8424
+ setInitialOrder((order) => order ?? sortExpertsByEnabled(EXPERTS, current.enabled).map((expert) => expert.slug));
8364
8425
  setError(null);
8365
8426
  props.onEnabledChange?.(current.enabled);
8366
8427
  }).catch((err) => {
@@ -8372,6 +8433,7 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8372
8433
  readEnabled(props.remote).then((current) => {
8373
8434
  if (!alive) return;
8374
8435
  setState(current);
8436
+ setInitialOrder((order) => order ?? sortExpertsByEnabled(EXPERTS, current.enabled).map((expert) => expert.slug));
8375
8437
  props.onEnabledChange?.(current.enabled);
8376
8438
  }).catch((err) => {
8377
8439
  if (alive) setError(err instanceof Error ? err.message : String(err));
@@ -8459,10 +8521,10 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8459
8521
  className: "aag-note"
8460
8522
  }, props.t("settings.loading")));
8461
8523
  else {
8462
- const filtered = sortExpertsByEnabled(filterExperts(EXPERTS, {
8524
+ const filtered = filterExperts(initialOrder === null ? sortExpertsByEnabled(EXPERTS, state.enabled) : sortExpertsByOrder(EXPERTS, initialOrder), {
8463
8525
  query,
8464
8526
  division
8465
- }), state.enabled);
8527
+ });
8466
8528
  const enabledCount = [...state.enabled].filter((slug) => EXPERTS.some((expert) => expert.slug === slug)).length;
8467
8529
  const total = EXPERTS.length;
8468
8530
  const hasFilter = normalizeExpertQuery(query) !== "" || division !== "";
@@ -8784,9 +8846,11 @@ Set the \`cycles\` parameter to \`"ref"\` to resolve cyclical schemas with defs.
8784
8846
  exports.normalizeExpertQuery = normalizeExpertQuery;
8785
8847
  exports.openAgentSettings = openAgentSettings;
8786
8848
  exports.pickHostSettingsTrigger = pickHostSettingsTrigger;
8849
+ exports.resolveExpertMenuPosition = resolveExpertMenuPosition;
8787
8850
  exports.resolveExpertToolbarClick = resolveExpertToolbarClick;
8788
8851
  exports.resolveReferenceInsertionTarget = resolveReferenceInsertionTarget;
8789
8852
  exports.sortExpertsByEnabled = sortExpertsByEnabled;
8853
+ exports.sortExpertsByOrder = sortExpertsByOrder;
8790
8854
  exports.writeErrorKey = writeErrorKey;
8791
8855
  exports.writeErrorMessage = writeErrorMessage;
8792
8856
  return module.exports;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@michengai/dsh-agency-agents",
3
3
  "description": "Agency Experts — a summonable domain-expert roster for DSH (expert mode)",
4
- "version": "0.1.33",
4
+ "version": "0.1.35",
5
5
  "type": "module",
6
6
  "packageManager": "pnpm@11.22.0",
7
7
  "engines": {