dsh-plugin-devin
v0.1.9
Published
Independent DSH Devin OAuth and shared web/code search bundle
Readme
dsh-plugin-devin
独立的 DSH npm ESM bundle:浏览器登录 Devin 一次,由 DSH Host 持久化 session;原生 web_search 与新增 code_search 共用登录。保留原生 web_fetch(HTTP)和你的主模型,不修改 DSH/piwin,不依赖 piwin 私有包,不读取其他应用的 token。
仅离线验证,尚未进行真实 OAuth 或线上 Devin/Windsurf 调用。 这是使用 alpha DSH API 与非公开云端协议的候选实现;服务可能改变协议或拒绝账户/权限。代码搜索会上传查询及所选代码到 Devin/Windsurf,请先确认你有权限。
兼容与安装
- Node >=22.19.0,ESM。
- DSH 服务 peers/devDependencies 均锁定 0.2.1-alpha.1。npm 实际 metadata 要求 Cordis 4.0.5-alpha.1,不是 4.0.4;本项目锁定前者,避免强制绕过 peer 冲突。共享 Cordis/DSH 运行时使用 peers,不使用
workspace:*。 - 需要已有 base-backed DSH profile 提供
credentials(通常 credentials-local)、authorization、commands、web、tools、fs。缺少服务会保持待注入状态,不提供自制文件授权 fallback。
在本项目构建 tarball:
npm ci
npm run check
npm pack
# 产生 dsh-plugin-devin-0.1.0.tgz推荐: 已有 DSH Web 的 Plugins 页面安装 tarball 的绝对路径(或已构建项目目录的绝对路径),启用 dsh-plugin-devin bundle。未发布到 npm,不要假设 npm install dsh-plugin-devin 已可用。
手动 local profile: 在已有 $DSH_HOME/profiles/<你的profile>/ 中使用该 profile 的包管理器,例如 pnpm add /绝对路径/dsh-plugin-devin-0.1.0.tgz;在 profile package.json 的 已有 dsh.profile.bundles 数组末尾追加 "dsh-plugin-devin",保留原 base/mode bundles。随后重启 dsh --profile <你的profile>(Web HMR 可应用 bundle 增删;替换 npm 包仍应重启)。开发目录先运行 build 再安装;不要用另一 checkout 的 node_modules 符号链接。
bundle 的 dsh.bundle.patch 指向 cordis.patch.yml,先将已有 web 行设为 { searchProvider: devin, fetchProvider: http },再插入插件。此显式配置不受 DSH_WEB_SEARCH_PROVIDER 覆盖;更高优先级的 profile/home patch 可主动更改它。它不重复注册 web_search,也不注册主模型 adapter。仅依赖普通 Node host filesystem,不引入 SSH 判定包。
登录与清理
- 在 DSH 交互界面运行
/devin-login。 - 命令立即返回浏览器 URL;点击并完成登录,不能将 URL/token 粘贴进模型对话。插件不自动启动外部浏览器。
/devin-status查看 pending、已保存、过期或 provider 拒绝状态。也支持 DSH 原生授权 UI 的 Devin search / Browser login;两入口使用同一 authorization flow 与取消/原子 commit machinery。/devin-cancel取消 pending;/devin-logout同时取消本插件实例的登录/搜索、等待已进入 commit 的写入,然后只删除devin-search/session。
PKCE S256 + 随机 state,监听 127.0.0.1:59653/callback;端口占用则使用随机端口。错误 state 请求返回 400 但不终止合法尝试。登录含 exchange 的总期限 5 分钟;取消/超时/unload 会关闭回调服务器。
session 是 DSH GrantRecord,由 credentials-local 在 $DSH_HOME/.credentials.yaml 中保存(POSIX 0600、原子写与文件锁由 DSH 负责),不是普通 profile 配置 YAML。重启从该 store 恢复;任何 token 都不应进入日志、模型结果或普通配置。/devin-logout 不影响其他插件 credentials;卸载 bundle 不会自动删 session,应先 logout。不要删除整个共享 credential 文件以清理本插件。
没有 refresh grant / 不自动 refresh: JWT 形式的 session 使用 exp(提前 60 秒视为过期);opaque token 只保守记录 24 小时,不保证永久有效。401/403 将匹配的 session 标为 revoked,请重新登录;普通网络错误不清除登录。短期 GetUserJwt 是搜索专用缓存,按 session token/account 隔离,最多 5 分钟;本实例收到 credential rotation/logout 时清缓存、取消搜索。多进程只能共享 durable store,并不能取消另一进程的 pending 登录;避免同时跨进程登录/登出。
code_search 与数据边界
模型参数仅:
{"search_term":"定位 OAuth callback 的实现","search_folder_absolute_uri":"/绝对路径/当前工作区"}exec.agent.session.header.cwd是权威 root;缺少 cwd 拒绝。先 canonicalize,再由ctx.fs.processPathFromHostPath确认映射等于 host canonical path;remote world 不因 Host 存在同名文件而读取它。- 搜索 folder 必须为 root 内真实目录。cloud 只获得虚拟
/codebase路径;最终结果重新 fence/read,返回真实文件、行号与 snippet。 - 最多 3 tool turns + 1 final,每轮
restricted_exec最多 4 structured commands:rg/readfile/tree/ls/glob。这是 JSON 对象 allowlist,不是任意 shell,无 exec 子进程。 rg为 literalincludes,不运行用户 regex;glob仅*/?,使用有界 DP,不执行任意正则。- 每文件 512 KiB;最多 512 files visited / 4096 entries / depth24;每命令保留 24 KiB、全程最多 192 KiB command output;最终最多 8 files / 16 ranges / 每 range400行 / 48 KiB snippets;总期限 90 秒。超界明确失败,不默默扩大搜索。全模块串行 code search,DSH concurrency classifier 为 exclusive;web 可并发只读。
- 跳过
.git、node_modules、常见生成目录、.env*、credentials/secret/token/private-key 命名与 key/certificate 文件;不 follow symlinks;NUL/非 UTF-8 二进制与 oversized file 拒绝。命令执行与最终 snippets 二次校验路径/身份;文件打开使用 O_NOFOLLOW。 - 尊重 搜索 folder 及子目录的
.gitignore(通过ignore库),命令/最终结果都不能读已排除文件。限制:不读 folder 祖先的.gitignore、.git/info/exclude或全局 Git ignore;子目录否定规则不能重新纳入被祖先排除的目录。 请以项目 root 搜索,或在搜索 folder 内补充排除规则。 - 名称排除不是 secret/DLP 扫描:普通源码中的内嵌密钥可能随 snippet 上传。不要对有敏感内容的代码启用此云端搜索。此同进程只读 fence 也不是抵御本机恶意进程并发修改 filesystem 的 OS sandbox;请使用可信工作区。
云端协议与错误处理
web 请求两个主机,先 server.codeium.com,再 server.self-serve.windsurf.com;仅普通失败 fallback,abort 不继续。结果仅接受 http/https URL(禁止内嵌用户名密码),最多10条、bounded response/snippet;不 echo provider 错误正文/cause。
code search 私有 client 使用 GetUserJwt raw application/proto,以及 GetDevstralStream Connect-gzip。Metadata API key field3、user JWT21;message roles5/1/2/4,工具通过 [TOOL_CALLS]...[ARGS] JSON。按参考的当前 endpoint 默认 swe-1-6-fast 使用;未猜测额外 protobuf model 字段或注册主模型。严格校验 gzip、partial frame/protobuf、末帧 trailer/error,限制压缩/解压 bytes,取消时关闭 reader。云端若改变 tool marker/XML 语法会 fail closed,而不会执行新的命令。
离线检查
npm test
npm run typecheck
npm run build
npm pack --dry-runfixture 使用 localhost、合成 token 与独立临时目录,不读取真实 .env/token,也不调用付费 API:
- OAuth code/state/S256、wrong-state 抗干扰、port fallback、timeout/preabort、exchange 取消与 server cleanup。
- 真正 Cordis authorization/commands/web/tools/fs services,native flow 与 slash login、注册/unload、原子 commit/logout 竞态、credentials-local 0600 和 restart/shared login。
- Web 双主机、aliases/schema/URL/result cap、abort/reader、失效与 error redaction。
- Protobuf/Connect/gzip、tool markers、trailer/partial/bytes cap、JWT 缓存跨账户/rotation/revocation。
- 真实临时代码多轮 loop、命令/最终 path fence、symlink/secret/binary/ignore、turn/output/file/range 配额及取消/并发。
未验证: 真实浏览器/Devin 登录、服务默认模型/协议持续兼容、真实账户额度/计费、完整 DSH GUI 的实际点击流程、Windows 平台 ACL/路径行为。Cordis fixture 与 tarball import 测试不等同于线上服务 smoke test。参考与许可见 NOTICE / LICENSE。
