Repository navigation
fix: 打包 zod 进 dist——薄安装(dsh/pi 插件裸拷)启动即崩的 P0(#3511) - #3519
Merged
Merged
Conversation
… P0) #3425 inlined jimp (devDependency, noExternal), and jimp imports zod at module scope: 16 STATIC from"zod" imports landed in dist/index.js and dist/agent/pi-native.js. Static imports have no degrade path, so installs shipping the package without its node_modules (dsh profile bare copies, thin pi plugin copies) died with ERR_MODULE_NOT_FOUND and traffic silently went direct, uncompressed. Bundle zod like every other transitive of an inlined dep (~1.4 MB on the two affected entries). The one sanctioned external consumer — opencode V1 host interop, which wants the HOST zod instance and already degrades when unresolvable — keeps its runtime resolution via an opaque specifier, unchanged behavior. New build gate scripts/check-dist-external-zod.mjs fails the build if a static zod import ever reappears; verified a bare dist copy with zero node_modules now runs --version clean.
Contributor
📦 Built Package ArtifactBranch: Option A — Install this exact build (recommended)npm install -g billion-context@0.0.4165-pr.3519.3340a52This exact version is immutable and reproducible. The rolling Option B — Download artifact
tar xzf billion-context-pr3519.tgz
npm install -g packageInstall instructions are refreshed on each push. |
Gives the two guard helpers real consumers (unused-exports gate) and locks the regex: the four #3425 leak forms are violations, the sanctioned opaque lazy import and zod vendor strings are not.
Same shape as tests/dist-import-annotations.test.ts: a variable-specifier dynamic import keeps tsc away from the untyped .mjs while still giving the gate helpers a consumer.
Contributor
📦 Merged Build PublishedThis merge to master was published as npm install -g billion-context@0.0.529-master.766720f # this exact build
npm install -g billion-context@master # always the newest merged build
|
ranxianglei
added a commit
that referenced
this pull request
Oct 17, 2026
…ernal-zod build gate Conflict resolution (#3519 vs #3524, same P0, two designs): - tsup.config.ts: keep jimp EXTERNAL + lazy-load degrade (this branch's design). Master's noExternal:["zod"] is dropped as moot — with jimp out of the bundle nothing statically imports zod, so bundling it had no effect anymore. dist/index.js shrinks 7.1MB -> 4.8MB. - package.json build line: keep master's check-dist-external-zod.mjs gate (stricter: flags literal import("zod") too, catches any future static zod leak). This branch's check-dist-no-zod.mjs + tests/dist-no-zod.test.ts removed as the weaker duplicate. - ework's optionalDependencies jimp + guardrail knob wiring unchanged. Verified: npm run build + dist-external-zod gate OK; thin install (bare dist, no node_modules) `node dist/index.js --version` exit 0; issue3400-image-rescale 18 + check-dist-external-zod 3 + opencode-native-v1 28 = 49 pass; typecheck clean.
This was referenced Oct 17, 2026
Closed
tgazer933-boop
pushed a commit
to tgazer933-boop/billion-context
that referenced
this pull request
Oct 18, 2026
…all (ranxianglei#3617-C) New scripts/check-dist-thin-install.mjs, wired into the static-gates job after > billion-context@0.1.199 build > npm --prefix kernel run build && npm --prefix pi-subagents run build && tsup && node scripts/write-build-info.mjs && node scripts/check-dist-import-annotations.mjs && node scripts/check-dist-external-zod.mjs > acp-kernel@0.0.130 build > npm run clean && tsup && tsc --emitDeclarationOnly > acp-kernel@0.0.130 clean > node -e "require('fs').rmSync('dist',{recursive:true,force:true})" �[34mCLI�[39m Building entry: src/index.ts, src/panel/index.ts, src/persist/index.ts, src/wire/index.ts �[34mCLI�[39m Using tsconfig: tsconfig.json �[34mCLI�[39m tsup v8.5.1 �[34mCLI�[39m Using tsup config: /var/lib/ework-daemon/share/opencode-workdir/ranxianglei--billion-context/3617/ework-daemon/kernel/tsup.config.ts �[34mCLI�[39m Target: es2022 �[34mESM�[39m Build start �[32mESM�[39m �[1mdist/persist/index.js �[22m�[32m19.83 KB�[39m �[32mESM�[39m �[1mdist/wire/index.js �[22m�[32m58.33 KB�[39m �[32mESM�[39m �[1mdist/index.js �[22m�[32m314.09 KB�[39m �[32mESM�[39m �[1mdist/chunk-KJXO6XX7.js �[22m�[32m29.34 KB�[39m �[32mESM�[39m �[1mdist/chunk-6ECDTFU5.js �[22m�[32m2.02 KB�[39m �[32mESM�[39m �[1mdist/panel/index.js �[22m�[32m6.96 KB�[39m �[32mESM�[39m �[1mdist/persist/index.js.map �[22m�[32m46.16 KB�[39m �[32mESM�[39m �[1mdist/wire/index.js.map �[22m�[32m154.06 KB�[39m �[32mESM�[39m �[1mdist/chunk-KJXO6XX7.js.map �[22m�[32m53.58 KB�[39m �[32mESM�[39m �[1mdist/chunk-6ECDTFU5.js.map �[22m�[32m4.38 KB�[39m �[32mESM�[39m �[1mdist/panel/index.js.map �[22m�[32m17.58 KB�[39m �[32mESM�[39m �[1mdist/index.js.map �[22m�[32m752.42 KB�[39m �[32mESM�[39m ⚡️ Build success in 92ms > billion-context-pi-subagents@0.2.0 build > tsup && tsc --emitDeclarationOnly �[34mCLI�[39m Building entry: src/index.ts �[34mCLI�[39m Using tsconfig: tsconfig.json �[34mCLI�[39m tsup v8.5.1 �[34mCLI�[39m Using tsup config: /var/lib/ework-daemon/share/opencode-workdir/ranxianglei--billion-context/3617/ework-daemon/pi-subagents/tsup.config.ts �[34mCLI�[39m Target: es2022 �[34mCLI�[39m Cleaning output folder �[34mESM�[39m Build start �[32mESM�[39m �[1mdist/index.js �[22m�[32m464.23 KB�[39m �[32mESM�[39m �[1mdist/index.js.map �[22m�[32m1.31 MB�[39m �[32mESM�[39m ⚡️ Build success in 266ms �[34mCLI�[39m Building entry: {"agent/dsh-native-client":"src/agent/dsh-native-client.ts"} �[34mCLI�[39m Using tsconfig: tsconfig.json �[34mCLI�[39m tsup v8.5.1 �[34mCLI�[39m Using tsup config: /var/lib/ework-daemon/share/opencode-workdir/ranxianglei--billion-context/3617/ework-daemon/tsup.config.ts �[34mCLI�[39m Building entry: src/claude-native-bootstrap.ts, src/index.ts, src/mcp.ts, src/agent/dsh-acp.ts, src/agent/dsh-native.ts, src/agent/omp-native.ts, src/agent/omp.ts, src/agent/opencode-native.ts, src/agent/opencode.ts, src/agent/pi-native.ts, src/agent/pi.ts, src/kimi/bootstrap-hook.ts, src/kimi/native-mcp.ts, src/zcode/bootstrap-hook.ts, src/zcode/mcp-entry.ts �[34mCLI�[39m Using tsconfig: tsconfig.json �[34mCLI�[39m tsup v8.5.1 �[34mCLI�[39m Using tsup config: /var/lib/ework-daemon/share/opencode-workdir/ranxianglei--billion-context/3617/ework-daemon/tsup.config.ts �[34mCLI�[39m Target: es2020 �[34mCJS�[39m Build start �[34mCLI�[39m Target: node20 �[34mCLI�[39m Cleaning output folder �[34mESM�[39m Build start �[32mCJS�[39m �[1mdist/agent/dsh-native-client.js �[22m�[32m14.08 KB�[39m �[32mCJS�[39m ⚡️ Build success in 36ms �[32mESM�[39m �[1mdist/agent/dsh-acp.js �[22m�[32m5.77 KB�[39m �[32mESM�[39m �[1mdist/mcp.js �[22m�[32m731.30 KB�[39m �[32mESM�[39m �[1mdist/agent/omp.js �[22m�[32m1.27 MB�[39m �[32mESM�[39m �[1mdist/agent/pi.js �[22m�[32m1.27 MB�[39m �[32mESM�[39m �[1mdist/claude-native-bootstrap.js �[22m�[32m2.13 MB�[39m �[32mESM�[39m �[1mdist/agent/opencode-native.js �[22m�[32m2.30 MB�[39m �[32mESM�[39m �[1mdist/agent/opencode.js �[22m�[32m2.27 MB�[39m �[32mESM�[39m �[1mdist/kimi/bootstrap-hook.js �[22m�[32m2.10 MB�[39m �[32mESM�[39m �[1mdist/kimi/native-mcp.js �[22m�[32m2.14 MB�[39m �[32mESM�[39m �[1mdist/zcode/bootstrap-hook.js �[22m�[32m2.11 MB�[39m �[32mESM�[39m �[1mdist/zcode/mcp-entry.js �[22m�[32m2.16 MB�[39m �[32mESM�[39m �[1mdist/agent/dsh-native.js �[22m�[32m2.22 MB�[39m �[32mESM�[39m �[1mdist/agent/dsh-acp.js.map �[22m�[32m49.41 KB�[39m �[32mESM�[39m �[1mdist/agent/omp-native.js �[22m�[32m2.60 MB�[39m �[32mESM�[39m �[1mdist/index.js �[22m�[32m4.64 MB�[39m �[32mESM�[39m �[1mdist/agent/pi-native.js �[22m�[32m4.69 MB�[39m �[32mESM�[39m �[1mdist/mcp.js.map �[22m�[32m2.05 MB�[39m �[32mESM�[39m �[1mdist/agent/omp.js.map �[22m�[32m5.32 MB�[39m �[32mESM�[39m �[1mdist/agent/pi.js.map �[22m�[32m5.32 MB�[39m �[32mESM�[39m �[1mdist/claude-native-bootstrap.js.map �[22m�[32m6.92 MB�[39m �[32mESM�[39m �[1mdist/kimi/native-mcp.js.map �[22m�[32m6.94 MB�[39m �[32mESM�[39m �[1mdist/zcode/mcp-entry.js.map �[22m�[32m6.95 MB�[39m �[32mESM�[39m �[1mdist/agent/opencode.js.map �[22m�[32m8.07 MB�[39m �[32mESM�[39m �[1mdist/agent/opencode-native.js.map �[22m�[32m8.16 MB�[39m �[32mESM�[39m �[1mdist/zcode/bootstrap-hook.js.map �[22m�[32m6.91 MB�[39m �[32mESM�[39m �[1mdist/agent/dsh-native.js.map �[22m�[32m7.50 MB�[39m �[32mESM�[39m �[1mdist/kimi/bootstrap-hook.js.map �[22m�[32m6.91 MB�[39m �[32mESM�[39m �[1mdist/agent/omp-native.js.map �[22m�[32m8.85 MB�[39m �[32mESM�[39m �[1mdist/index.js.map �[22m�[32m13.03 MB�[39m �[32mESM�[39m �[1mdist/agent/pi-native.js.map �[22m�[32m14.22 MB�[39m �[32mESM�[39m ⚡️ Build success in 3342ms build-info: commit=fd3232fae-dirty dist-import-annotations: OK dist-external-zod: OK (additive step; no matrix/leg-name changes, branch protection untouched). It packs the current tree, installs ONLY the tarball into a scratch dir with no repo node_modules, then proves the artifact runs: 0.1.199 (fd3232f-dirty) exits 0, and every Node-consumed dist/agent/*.js entry imports in its own process. dsh-native-client.js is a browser bundle by design (tsup platform:browser, window.__ModuleLoader__ format) — parse-checked instead of imported.\n\nWhy: ranxianglei#3511 (zod statically in dist while undeclared) shipped because PR CI never installed the tarball into a bare dir — ranxianglei#3519's check-dist-external-zod gate is static analysis for ONE known offender and CI ran it only inside the build chain. This smoke catches ANY undeclared runtime dependency at import time, in the same shape a real consumer hits it. Verified negative: injecting a fake undeclared import into a built bundle fails the script with ERR_MODULE_NOT_FOUND.\n\nDeliberately NOT added to the local build chain or the prepare gate: it needs registry access for declared deps and must not slow consumer installs. Also exposed as > billion-context@0.1.199 check:dist-thin > node scripts/check-dist-thin-install.mjs dist-thin-install: OK — cli 0.1.199; imported 8 agent bundle(s) [dsh-acp.js, dsh-native.js, omp-native.js, omp.js, opencode-native.js, opencode.js, pi-native.js, pi.js]; parse-checked browser bundle(s) [dsh-native-client.js] for manual use. No behavior change to the product.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ai: zhipuai-lb/glm-5.3
修 #3511 的 P0(jimp 把 zod 带进 dist,薄安装启动即崩),顺带加构建门禁防复发。
病根
#3425 做图片降采样引入 jimp(devDependency、tsup noExternal 内联)。jimp 自己的代码在模块顶层
import { z } from "zod",而 zod 是运行时依赖(opencode V1 宿主互作用,086e80a2 有意为之)所以保持 external——两边一叠加,内联的 jimp 把 16 处静态from"zod"导入泄漏进了dist/index.js和dist/agent/pi-native.js。静态导入在模块加载时解析、没有降级路径:凡是「包旁边没有 node_modules」的安装形态(dsh profile 裸拷、pi 插件薄拷——真实插件安装路径)直接
ERR_MODULE_NOT_FOUND,代理起不来,流量静默直连不压缩。带依赖树的正常安装(npm/pnpm)不受影响,所以 CI 没炸。修法(三层)
dist/index.js/dist/agent/pi-native.js恢复自包含(各 +1.4MB),静态导入消失。实测:裸拷dist/+ 零 node_modules,node dist/index.js --version干净退出(exit 0)。const s="zod"; await import(s)),esbuild 无法静态改写到内联副本——运行时行为与之前逐字节等价(薄安装照样走文档化的降级),28/28 测试过。scripts/check-dist-external-zod.mjs挂进npm run build,dist 里再出现任何静态 zod 导入(import-from/require/字面量动态 import)直接构建失败;合法的懒加载路径(变量说明符)和普通 "zod" 字符串(zod 自己的 vendor 标记)不误报。验证
tests/issue3400-image-rescale.test.ts18/18、tests/opencode-native-v1.test.ts28/28、typecheck 干净Ref #3511