dsh-web-search-ddg
aooyoo
Zero-token DuckDuckGo search provider for the DeepSeek Harness (DSH) web seam — local headless browser, no API key, no m…
PROJECT TOPICS
PROJECT README
中文 | English
把 DSH(DeepSeek Harness)Web GUI 的新会话屏,改造成四步卡片向导的独立插件——防止"用默认配置却忘了配置任务模式、模型"。
对 DSH 本体零修改:独立 bundle 分发,dsh plugin add 一条命令装上,remove 一条命令卸掉。
DSH 整个产品都是 Cordis 插件树——没有需要"手术"的核心,所有东西都可以从外面替换:
--dsw-alias-* 语义色板,插件写样式零字面色值,明暗主题自动适配dsh.bundle + dsh.client 两个 manifest,本地目录 / tarball / GitHub 直装都行你不需要 fork DSH 就能深度改造它的界面。本插件就是一条完整的例子:接管 → 配置 → 让位。
新会话屏原本的配置入口(工作区芯片、agent preset 芯片、输入卡角落的小模型选择器)都默认落在部署默认值上,用户极易跳过配置直接发送。本插件把新会话屏替换为:
确认本身不发送任何消息。任何配置都不会在用户不知情时使用默认值。
也可以随时回到原版 hero:向导底部「使用标准输入框」,或 设置 → 通用设置 → 新会话配置向导 开关(偏好存于浏览器 localStorage)。
# 前置:DSH CLI 已安装并初始化过 profile(如 web)
dsh plugin --profile web add github:supergameboy/dsh-new-session-cards
GitHub 安装拉取的是源码,pnpm ≥10 需要显式允许构建脚本(只允许你信任的源码):
# <profile 目录>/pnpm-workspace.yaml
allowBuilds:
dsh-new-session-cards: true
然后重新执行 add(prepare 脚本自动构建 lib/)。本地目录或 tarball 安装不需要允许构建:
dsh plugin --profile web add ./dsh-new-session-cards # 本地目录(需先 pnpm build)
dsh plugin --profile web add ./dsh-new-session-cards-0.1.0.tgz
验证与启用:
dsh --profile web --dump-config # 应看到 "# == dsh-new-session-cards" 层
dsh --profile web # 打开新会话屏,即见向导
如果插件已装过且改了代码:profile 是 link 安装,浏览器刷新即生效,无需重启服务(服务端每次请求都读最新 bundle 文件)。
卸载:
dsh plugin --profile web remove dsh-new-session-cards
pnpm install
pnpm build # tsdown:lib/index.js(node half)+ lib/client.js(浏览器 bundle)
pnpm typecheck # 需要 DSH 源码树在 ../deepseek-harness(见踩坑 #1)
以下是开发本插件时真实踩过的坑,按"坑 → 现象 → 解法"记录。想快速上手 DSH 客户端插件,先读这份。
@deepseek-ai/* 依赖链不完整@deepseek-ai/* 包(rc 版)的传递依赖有缺失(如 dsh-user-interaction 未发布),pnpm install 直接 404。package.json 不声明任何 @deepseek-ai 依赖。运行时不需要——client bundle 的 externals(react、dsh-client-runtime/client 等平台模块)由 shell 的模块表提供,其余依赖全部内联;构建也不需要——import type 会被擦除。类型检查用 tsconfig paths 指向 DSH 源码树的构建产物(../deepseek-harness/packages/*/*/lib/types)。--dsw-alias-brand-primary 是墨色,不是品牌蓝brand-primary 解析为 neutral-bluish-1000(接近黑的墨色)。用它做按钮底 + label-primary(同墨色)做文字 → 深字深底,按钮文字完全看不见。--dsw-alias-state-business-primary(DeepSeek 品牌蓝,input-bar 内部注释原话:"Business blue, not brand-primary: that token resolves to ink");主按钮用 --dsw-alias-button-primary-fill 底 + --dsw-alias-label-primary-foreground(白)字——优先直接复用 ui-primitives 的 Button 组件。load 回调只在组件里定义了,没有任何人调用 → 卡片永远渲染骨架屏(无文字)、下一步按钮永远 disabled(依赖 status === 'ready')→ 用户卡死在向导里。useEffect(() => { load() }, [load])(照抄 shipped ModelSelect 的模式)。conversation.composer.bar 被接管时 DOM 保留、CSS 隐藏(textarea 一直"在"DOM 里)。依赖它的东西会跟着隐藏:conversation.input.overlay 槽(命令菜单 MenuView、popupSelect shell)的锚点在隐藏的 InputBar 内,非 portal。sessions.scope(sessionId) 拿到 session 作用域,inputTriggers.sessionOf(actx) 拿到会话控制器(menu store / track / arbitrate / pick),菜单 UI 读 menu store 自己渲染。conversation.blocks.set(sessionId, undefined)(root 订阅 block 变化);(b) 发送首条消息后 composerPhase 从 blank 变 active(本插件最终采用:Step4 发送即自然让位,无需手动翻转)。ctx.locale.register(NS, ...) 的类型签名是 N extends keyof LocaleNamespaceMap,自定义 NS 直接编译报错。declare module '@deepseek-ai/dsh-client-ui-slots' { interface LocaleNamespaceMap { myNs: MyKeyUnion } }。组件里 PropsLocale<typeof NS>(NS 是值,要用 typeof)。response.result.ok 收窄在 store.update((draft) => { ... response.result.error.message }) 回调里失效(TS 不把窄化传播进 mutator 回调)→ "Property 'error' does not exist"。const message = response.result.error.message,回调里用 message。settingsScope.bind(),但 namespace 是 host 侧注册的(需要 host 插件代码);client-only 插件的 namespace 永远是 unavailable。dsh-new-session-cards:useWizard),用 createSnapshotStore 包一层做响应式镜像;设置行(settings.general.item)读写它——UI 与内置设置行完全一致。resolve(dirname(importer), source)),否则 ENOENT。fixedExtension: false,否则输出 index.mjs 而 package.json exports 指向 .js。paths 通配每 pattern 只能有一个 *(packages/*/*/lib/types 不行,要按组展开)。allowImportingTsExtensions、lib: ["ES2023"](源码用 findLast)、types: ["node"]、CSS Modules 声明文件(src/css-modules.d.ts)。@deepseek-ai/cordis(npm 有 4.x)不是必需的:cordis 类型同样由 paths 从 vendor/cordis 解析。prepare 脚本(pnpm ≥10 跑在 allowBuilds 之后)自包含构建,不能假设有 monorepo 上下文。dsh.client manifest 的 exports["./client"] 必须指向真实 bundle 文件(clientModules 启动扫描会校验,缺失直接 FAILED)。flowchart LR
A[新会话屏 hero] -->|conversation.composer 接管链| B[四步向导]
B -->|确认配置| C[Step4 输入内容]
C -->|发送首条消息| D[对话界面]
D -->|新建另一会话| A
conversation.composer 链 entry,selector 只在"空白会话 + 偏好开启 + 未确认"时命中;发送后 blank → active,链自动让位agentPresets.list/select RPC;模型走 modelDirectories 服务;工作区/会话走标准 store;命令菜单复用 inputTriggers 管道--dsw-alias-* token,CSS Modules,WCAG 2.1 AA,prefers-reduced-motion 降级,zh/en 双语文案useWizard 开关),设置页 General 区一行切换docs/design/ 下有完整的分形 UI 设计文档(L0 决策链 → 页面 → 组件库 → 样式规范,两轮独立验证通过)。
MIT
CLASSIFICATION EVIDENCE
系统优先读取 GitHub Topics,再与站内分类词典和词根规则比对。