feat: dsh 进 PLUGIN_AGENTS——native 插件部署 + 拦截层(native 模式 D) - #525
feat: dsh 进 PLUGIN_AGENTS——native 插件部署 + 拦截层(native 模式 D)#525ranxianglei wants to merge 1 commit into
Conversation
- bili plugin install/remove/status dsh: cordis entry in every profile's cordis.patch.yml (idempotent, stale-entry drop, .bili-bak backups) - launcher: skip legacy --patch overlay when a live native entry exists - bili daemon --fresh --json --parent-pid N: per-session ephemeral-port proxy (BILI_INSTANCE_FILE handshake, no global instance/registry writes, auto-update off, parent-gone reap); config accepts port 0 - agent/intercept.ts: shared globalThis.fetch interceptor (origin-scoped /bili/ rewrite, async target gate, degrade-once direct retry) - dsh-acp: sync install + async bootstrap (env attach or daemon spawn), upstream origin per settings baseURL ?? llm-deepseek ?? DEEPSEEK_BASE_URL ?? official default; /acp reports routing head; wire mode unchanged - e2e: real dsh headless through intercepted proxy; compression pipeline engaged on real traffic (preflight fail-fast adjudication verified)
📦 Built Package ArtifactBranch: Option A — Install from npm PR tag (recommended)npm install -g billion-context@pr-525Each push to this PR publishes a new version under the Option B — Download artifact
tar xzf billion-context-pr525.tgz
npm install -g packageThis comment is automatically updated on each push. |
[bot] 🏷 Reviewing now. Plan: check out the PR head ( |
[bot] 🏷 Review 结论:LGTM,可以合并(合并操作留给人工)。三个 minor 备注见下,均不阻塞。 验证了什么Pre-flight(本地复跑,与描述完全一致)
逐条核对 PR 声称的组件,全部属实:
测试覆盖质量:interceptor 8 个测试(含 race gate、degrade、abort 不重试、gate reject 不挂死)、settings 7 个(含 malformed fall-through)、plugin-install roundtrip 覆盖了幂等/共享 insert group 保留他人条目+组头/stale→broken/no-profiles 报错(tests/plugin-agent.test.ts:954-1014)。WORKLOG 对 e2e 局限(headless one-shot 无法出多轮压缩循环、argv 上限)的披露诚实且合理。 Minor 备注(不阻塞)
判断小结方案层面:Triage 阶段的审核结论我独立复核后全部成立——resolution chain 打到核心(settings 显式配置优先、env 兜底、不可解析即不拦截),race window 用"同步安装 + per-call 异步解析"关闭是正确的层次(不是治标),per-session port 0 + session instance file 干净地绕开了 #394 而不污染全局注册表。实现与声明一致,e2e 证据充分,可合并。 |
|
Review vs master 3cd85b6: Good properties (verified):
Issues:
Recommendation: hold for family decision; consolidate with #524 on one interception core; rework launcher integration against post-#544 dsh flow. |
|
Verified against master 5836f78 (165 commits drifted, zero conflicts — GitHub reports mergeable=True, just "behind"). Test-merged locally: Pre-flight: typecheck ✓ · 1258/1260 tests (2 known env fails in plugin-agent.test.ts, unrelated; +20 dsh-native tests pass) · build ✓. No rebase needed — merge as-is. |
[bot] 🏷 收到。我这边也独立做了轻量复核,与你的结论一致:
你本地 test-merge 的 pre-flight(typecheck ✓ · 1258/1260,2 个已知环境依赖失败与改动无关 · build ✓)+ GitHub mergeable=True + 我的零冲突确认,三重一致——无需 rebase,直接合即可。 不过按系统规则 Agent 不能执行 PR 合并(human-only),请你自己点合: 合并后 CI 会跑完整 pre-flight;如需我跟进合并后的验证(如发布流程或 e2e),在 issue 里说一声即可。 |
Closes #521
What
dsh native plugin deployment + fetch interception layer — the task-D slice of #513's confirmed design (per-session dynamic port, thin
bili daemonsubcommand, in-process fetch interception). Shared primitives are structured for B/C reuse.bili plugin install dsh(src/plugin-install.ts)"dsh"joinsPLUGIN_AGENTS; install/remove/status operate on every profile under$DSH_HOME/profiles/*, merging- insert: - name: <file://…/dist/agent/dsh-acp.js>into each profile'scordis.patch.yml(replaces bare[], appends otherwise).- insert:group only when empty);.bili-bakbackup per file once; clear error when no profiles exist yet.dshNativeInstalled()for the launcher.Launcher compat (src/launcher.ts)
--patchoverlay is skipped when a live native entry exists (any-profile rule → no double-registration of the same module via both layers). Fresh machines keep the legacy path untouched.LaunchOptions += forceFresh / parentPid / instanceFile / autoUpdateOff.Per-session proxy:
bili daemon --fresh --json --parent-pid N(cli/server/config)BILI_INSTANCE_FILE) — global instance file andinstances.jsonregistry skipped for session proxies (无单实例守卫:多个 bili 代理进程并存共写 sessions 目录,伴随孤儿 ref、有注册表无 transcript、计数自相矛盾的污染簇 #394 dual-writer noise); JSON{origin, port, pid, logPath}on stdout; auto-update off; parent-gone reap ≤2s after agent exit.Fetch interception (src/agent/intercept.ts, new — shared primitive)
globalThis.fetch; rewrites ONLY requests whose origin == active upstream origin →<proxy>/bili/<url>; everything else passthrough; network failure on a rewritten call retries once direct (degrade, never break traffic); stats{rewritten, passthrough, degraded}; uninstall restores.apply(); regression test included.dsh-acp (rewritten) + src/agent/dsh-settings.ts (new line-based reader)
BILLION_CONTEXT_PROXYwins (launcher attach mode), else spawnbili daemon. Upstream origin per issue spec: settings providerbaseURL??llm-deepseek.baseURL?? envDEEPSEEK_BASE_URL?? official DeepSeek default (official route only)./acpstillfetchStatusLatest(now reports the routing head). Underbili dshthe wrapped settings URL equals the proxy origin → interceptor passthrough → zero double-proxying by construction.Triage notes
- insert:entry shape from the existing launcher overlay, pi-ai's barefetch()calls (no captured references → wrap works), parent-gone watcher semantics, instance-file APIs.config.baseURL ?? $DEEPSEEK_BASE_URL); the implementation extends it with the llm-deepseek section as a middle fallback so both route styles are covered.Pre-flight
npm test: 1052 tests, 1051 pass, 1 fail = pre-existing env-dependentresolveClientCommand: codex/claude resolve to themselves(sandbox has a local codex binary; passes on runners without one; unrelated) · build OK (dist/agent/dsh-acp.js12.56 KB, tsup entries unchanged)E2E (real dsh, bare
dsh --profile headless, no--patch)/v1/chat/completions; a non-SSE mock body made dsh render the proxy's own error string — proxy definitively in path)./acplive rendering needs interactive TUI (unit-covered); sandbox argv limit caps headless prompt size.