IM 渠道卡工作目录设定区: 未绑定态渲染 / 默认模型顺序 / 默认权限模式待整理
- Dominant language
- TypeScript
- Stars
- 2.7k
- Forks
- 395
- Avg merge
- 21h 48m
- Merged PRs (30d)
- 776
Description
IM 渠道卡(Slack / Telegram / X)展开区里的「工作目录映射 + 会话偏好」这块有三个问题,都在同一片 UI 上,一起整理。
---
# 1. 账号未关联时不应渲染工作目录设定区
## 现象
**已连接但账号未关联**时,「工作目录映射」区块照常渲染出来,里面的 Agent / 模型 / 权限三个控件全部置灰。用户看到的是「控件坏了、选不了模型」,而不是「有前置条件没满足」。
实测中同一个人在同一处卡了两次,两次都判断成故障而不是待办。
## 为什么会读错
禁用态的因果关系在视线外:
- 解释文案「先完成 X 账号关联后可编辑」是灰色小字,挂在「工作目录映射」标题下方;
- 被禁用的模型选择器在更下面的独立卡片里,中间隔着说明段落。
视线落到灰掉的下拉上时,那行解释已经滚出注意力范围。同时这些禁用控件本身占了整块视觉面积,把真正该点的「打开 X 完成授权」挤成了次要元素——**该抢焦点的没抢到,不该抢的抢了**。
## 当前实现
判据在 `apps/desktop/src/renderer/components/settings/HookWorkspacePrefsEditor.tsx`:
```ts
// :434
const hint = !connected
? requireConnected // 连接未就绪
: loadError === 'unavailable'
? serverUnsupported // 服务器版本过旧(带重试入口)
: !providerBindingConfirmed || (activePrefsView !== null && !bound)
? requireBinding // 已连接但未绑定 ← 本节
: null;
// :446
editable: connected && bound && loadError === null,
```
渲染宿主两处:`HookConnectionsSection.tsx:976`(通用 provider,含 Telegram / X)与 `:1299`(Slack)。
## 期望行为
**未绑定成功时不渲染工作目录设定区**,而不是渲染出来再整体置灰。让「完成账号授权」成为该状态下唯一的行动焦点。
**三个 IM bot(Slack / Telegram / X)行为一致**,不要只改 X。
## 需要一并裁决的点
1. **与设计规范规则 7「无视觉跳变」的张力**。现有注释写明了这是刻意取舍:
> 状态模型(禁用整体置灰而非增删行, 规则 7)
本节方案会在绑定成功那一刻引入一次布局变化。倾向认为此处可以例外:绑定是**用户主动触发的一次性状态迁移**,那一刻的区块出现是预期内的正反馈,与规则 7 想防的「频繁抖动 / 莫名其妙的跳变」不是一回事。但这属于设计规范的例外裁决,不应由实现者单方面决定,需要在改之前定下来并把结论写回代码注释,否则下一个人会按规则 7 改回去。
2. **另外两个 hint 态怎么处理**:
- `requireConnected`(连接未就绪):按同一逻辑更应该隐藏;
- `serverUnsupported`(服务器版本过旧):**不能简单隐藏** —— 它带着重试入口,隐藏了用户就没有恢复路径。这一态可能仍需保留可见区块或另给出口。
3. 隐藏后,未绑定态的卡片高度会明显变矮,展开/收起动画与相邻卡片的间距需要一并核对。
---
# 2. 默认模型取的是「清单第一个」,没有确定的优先级
## 现象
未设置显式偏好时,界面展示的默认模型不是当前最合适的那个(实测展示了上一代模型,而非同系列最新款)。
## 根因
取值链的最后两级兜底到「可用清单的第一项」,两侧实现一致:
```ts
// main 侧 apps/desktop/src/main/hook-control/defaults.ts:93-111
// 2. model:显式且在可用清单 > 草稿默认(在清单) > 清单第一个 > 草稿默认裸值。
model = models[0]?.id ?? draft ?? '';
// renderer 侧 apps/desktop/src/renderer/components/settings/hookWorkspacePrefsLogic.ts:153
: (caps?.models[0]?.id ?? draftModel);
```
而 `models` 的顺序来自 `visibleModelUnion` → `deriveModelList`(`packages/model-providers/src/sections.ts:105`),是**供应商目录的返回顺序 + first-wins 去重**,并没有按代次 / 能力 / 推荐度排序。也就是说「清单第一个」是目录顺序的副产品,不代表任何人做过「这个该当默认」的判断;换一个供应商、目录顺序一变,默认模型就跟着变,且没有任何提示。
## 期望
给「未设置时该用哪个模型」一个**确定且可解释的优先级**,而不是依赖目录顺序。至少要明确:
- 排序键是什么(代次?推荐标记?与桌面端新建对话的默认保持一致?);
- 桌面端新建对话已经有一套默认选取逻辑,IM 侧是否应当直接复用同一套(注释里声称的语义就是「Slack 里开的会话与桌面端新开会话行为一致」,值得核对当前是否真的一致);
- main 与 renderer 两侧必须同判据,否则「界面显示的默认」与「实际派发用的默认」会不一致——这两处现在是各写一遍的,本身就是漂移风险点。
---
# 3. 默认权限模式是「完全访问」
## 现状
```ts
// apps/desktop/src/renderer/components/settings/hookWorkspacePrefsLogic.ts:99
export const HOOK_DEFAULT_PERMISSION_MODE = 'bypassPermissions';
// :121
if (explicit === null) return HOOK_DEFAULT_PERMISSION_MODE;
```
main 侧 `defaults.ts` 同口径:从未填显式档 → `bypassPermissions`。界面上这一档自带 ⚠️ 标记。
## 为什么值得重新裁决
现有取值链里有一条明确的安全约束,而且理由写得很充分——**显式档不被当前 agent 支持时回落该 agent 最严档,绝不放宽**:
> 用户填过显式档 = 明确表达过「不要默认的完全访问」……而这是无人值守的 IM 派发链路,没有人在旁边确认。
这条约束保护的是「用户表达过意愿」的情况。但**从未设置过的新目录**走的是另一条分支,直接落在 `bypassPermissions`。同一份注释把它记作「无人值守历史默认保持不变」——也就是说它是历史沿袭,不是重新论证过的选择。
X 渠道让这件事更值得看一眼:它是**公开渠道**,任何人都能 @ 到 bot(虽然只有已绑定用户才能真正派发任务),暴露面与私有 Slack workspace / Telegram 群不是一个量级。
## 期望
重新裁决「从未设置过时的默认权限档」,并把结论(无论是否改动)写成有理由的注释,而不是继续以「历史默认」的形式留着。若决定收紧,需要一并考虑:
- 存量已在使用、依赖当前默认行为的目录如何迁移(不能静默变严导致任务卡在等确认上,那同样是无人值守链路);
- 收紧后,需要确认的操作在 IM 侧如何呈现与响应。
---
# 交付要求(三节共同)
- 双模式(Light / Dark)都要实现,颜色走语义 token。
- 三个 provider 的状态迁移都要有测试覆盖:未连接 → 已连接未绑定 → 已绑定,区块的出现/消失符合裁决结论。
- 第 2、3 节的默认值逻辑在 main 与 renderer 两侧都要有测试锁住同判据。
Contributor guide
Research direction
Start with HookWorkspacePrefsEditor.tsx, HookConnectionsSection.tsx, hookWorkspacePrefsLogic.ts, main/hook-control/defaults.ts, and packages/model-providers/src/sections.ts. First resolve the binding, model-priority, and permission-default decisions, then inspect the existing desktop default-selection logic. Done means the agreed behavior is shared by main and renderer, Light/Dark states use semantic tokens, and tests cover all three providers and both default-value paths.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- electron, typescript
- Domain
- desktop, frontend, security
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100