billion-context 0.1.210 → 0.1.211

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -132,7 +132,7 @@ ${partialOutcomeNote(blocksCreated)}`;const out={text,failed:outcome==="failure"
132
132
  `}function legacyPlanEntries(root,createWhenEmpty){let provider=asRecord(root.provider);if(!provider){if(!createWhenEmpty)return[];provider={};root.provider=provider}const found=[];for(const id of ZCODE_LEGACY_PLAN_IDS){const entry=asRecord(provider[id]);if(!entry)continue;let options=asRecord(entry.options);if(!options){options={};entry.options=options}found.push({id,options})}if(found.length>0)return found;if(!createWhenEmpty)return[];for(const id of ZCODE_LEGACY_CREATE_IDS){const entry={options:{}};provider[id]=entry;found.push({id,options:entry.options})}return found}function legacyPlanEntriesForAll(root,policy){const routed=[];const skipped=[];const provider=asRecord(root.provider);if(!provider)return{routed,skipped};for(const id of Object.keys(provider)){const options=asRecord(asRecord(provider[id])?.options);const upstream=options===void 0?void 0:unwrapBaseUrl(options.baseURL);const reason=zcodeEntrySkipReason(id,upstream,upstream!==void 0,"legacy",policy);if(reason!==void 0||options===void 0||upstream===void 0){skipped.push({id,reason:reason??"no usable http(s) baseURL \u2014 left untouched"});continue}routed.push({id,options})}return{routed,skipped}}function applyLegacy(text,origin,policy){const root=parseRoot(text,"zcode v2/config.json");const wrapped=[];const skipped=[];if(policy.route==="all"){const selection=legacyPlanEntriesForAll(root,policy);for(const{id,options}of selection.routed){const upstream=unwrapBaseUrl(options.baseURL);if(upstream===void 0)continue;options.baseURL=`${origin}/bili/${upstream}`;wrapped.push({id,upstream})}skipped.push(...selection.skipped);return{text:serialize(root),wrapped,skipped}}for(const{id,options}of legacyPlanEntries(root,true)){const upstream=unwrapBaseUrl(options.baseURL)??ZCODE_BIGMODEL_ANTHROPIC_UPSTREAM;options.baseURL=`${origin}/bili/${upstream}`;wrapped.push({id,upstream})}return{text:serialize(root),wrapped,skipped}}function assertNewStoreShape(doc){const root=asRecord(doc);if(!root)throw new Error("zcode provider_config.json must be a JSON object");if(root.schemaVersion!==1)throw new Error(`unsupported provider_config.json schemaVersion: ${String(root.schemaVersion)}`);const config=asRecord(root.config);if(!config)throw new Error("provider_config.json is missing its config object");const rulesField=asRecord(config.providerConfigRules);if(rulesField!==void 0&&!Array.isArray(rulesField.providerRules)){throw new Error("provider_config.json config.providerConfigRules.providerRules must be an array")}}function newRuleArray(root){const rulesField=asRecord(asRecord(root.config)?.providerConfigRules);return rulesField&&Array.isArray(rulesField.providerRules)?rulesField.providerRules:[]}function newPlanRules(root,createWhenEmpty){const config=asRecord(root.config);if(!config)throw new Error("provider_config.json is missing its config object");let rulesField=asRecord(config.providerConfigRules);if(!rulesField){if(!createWhenEmpty)return[];rulesField={providerRules:[]};config.providerConfigRules=rulesField}const rules=Array.isArray(rulesField.providerRules)?rulesField.providerRules:[];const found=[];for(const raw of rules){const rule=asRecord(raw);if(!rule||typeof rule.providerId!=="string"||!ZCODE_NEW_PLAN_IDS.includes(rule.providerId))continue;const configObj=asRecord(rule.config);if(!configObj)continue;let api=asRecord(configObj.api);if(!api){api={};configObj.api=api}found.push({id:rule.providerId,api})}if(found.length>0)return found;if(!createWhenEmpty)return[];for(const id of ZCODE_NEW_CREATE_IDS){const rule={providerId:id,config:{api:{}}};rules.push(rule);const api=asRecord(asRecord(rule.config)?.api)??{};found.push({id,api})}return found}function newStoreRulesForAll(root,policy){const routed=[];const skipped=[];for(const raw of newRuleArray(root)){const rule=asRecord(raw);if(!rule||typeof rule.providerId!=="string"||rule.providerId.length===0)continue;const api=asRecord(asRecord(rule.config)?.api);const upstream=api===void 0?void 0:unwrapBaseUrl(api.baseUrl);const reason=zcodeEntrySkipReason(rule.providerId,upstream,upstream!==void 0,"new",policy);if(reason!==void 0||api===void 0||upstream===void 0){skipped.push({id:rule.providerId,reason:reason??"no usable http(s) baseUrl \u2014 left untouched"});continue}routed.push({id:rule.providerId,api})}return{routed,skipped}}function applyNew(text,origin,policy){const root=parseRoot(text,"zcode v2/provider_config.json");assertNewStoreShape(root);const wrapped=[];const skipped=[];if(policy.route==="all"){for(const{id,api}of newStoreRulesForAll(root,policy).routed){const upstream=unwrapBaseUrl(api.baseUrl);if(upstream===void 0)continue;api.baseUrl=`${origin}/bili/${upstream}`;wrapped.push({id,upstream})}skipped.push(...newStoreRulesForAll(root,policy).skipped);return{text:serialize(root),wrapped,skipped}}for(const{id,api}of newPlanRules(root,true)){const upstream=unwrapBaseUrl(api.baseUrl)??ZCODE_BIGMODEL_ANTHROPIC_UPSTREAM;api.baseUrl=`${origin}/bili/${upstream}`;wrapped.push({id,upstream})}return{text:serialize(root),wrapped,skipped}}function applyZcodeRouting(text,kind,origin,policy=defaultZcodeRoutePolicy()){return kind==="new"?applyNew(text,origin,policy):applyLegacy(text,origin,policy)}function stampHeaders(headers){const existing=asRecord(headers);const next=existing?{...existing}:{};next[ZCODE_PLUGIN_HEADER]=ZCODE_AGENT_VALUE;return next}function stampLegacy(text){const root=parseRoot(text,"zcode v2/config.json");let changed=false;const provider=asRecord(root.provider);if(provider){for(const id of Object.keys(provider)){const options=asRecord(asRecord(provider[id])?.options);if(!options||!WRAPPED_URL_RE.test(String(options.baseURL)))continue;const stamped=stampHeaders(options.headers);if(stamped){options.headers=stamped;changed=true}}}return changed?serialize(root):text}function stampNew(text){const root=parseRoot(text,"zcode v2/provider_config.json");assertNewStoreShape(root);let changed=false;const rulesField=asRecord(asRecord(root.config)?.providerConfigRules);const rules=rulesField&&Array.isArray(rulesField.providerRules)?rulesField.providerRules:[];for(const raw of rules){const api=asRecord(asRecord(asRecord(raw)?.config)?.api);if(!api||!WRAPPED_URL_RE.test(String(api.baseUrl)))continue;const stamped=stampHeaders(api.headers);if(stamped){api.headers=stamped;changed=true}}return changed?serialize(root):text}function stampZcodePluginHeader(text,kind){return kind==="new"?stampNew(text):stampLegacy(text)}function unrouteHeaders(headers){const existing=asRecord(headers);if(existing&&Object.prototype.hasOwnProperty.call(existing,ZCODE_PLUGIN_HEADER))delete existing[ZCODE_PLUGIN_HEADER]}function unrouteLegacy(text){const root=parseRoot(text,"zcode v2/config.json");let changed=false;const provider=asRecord(root.provider);if(provider){for(const id of Object.keys(provider)){const options=asRecord(asRecord(provider[id])?.options);if(!options||typeof options.baseURL!=="string")continue;const match=WRAPPED_URL_RE.exec(options.baseURL);if(!match)continue;options.baseURL=match[1];unrouteHeaders(options.headers);changed=true}}return{text:changed?serialize(root):text,changed}}function unrouteNew(text){const root=parseRoot(text,"zcode v2/provider_config.json");assertNewStoreShape(root);let changed=false;const rulesField=asRecord(asRecord(root.config)?.providerConfigRules);const rules=rulesField&&Array.isArray(rulesField.providerRules)?rulesField.providerRules:[];for(const raw of rules){const api=asRecord(asRecord(asRecord(raw)?.config)?.api);if(!api||typeof api.baseUrl!=="string")continue;const match=WRAPPED_URL_RE.exec(api.baseUrl);if(!match)continue;api.baseUrl=match[1];unrouteHeaders(api.headers);changed=true}return{text:changed?serialize(root):text,changed}}function unrouteZcodeText(text,kind){return kind==="new"?unrouteNew(text):unrouteLegacy(text)}function detectCurrentZcodeOrigin(dataDir,env=process.env){const{kind,file}=detectZcodeStore(dataDir,env);let text;try{text=fs11.readFileSync(file,"utf8")}catch{return void 0}let doc;try{doc=JSON.parse(text)}catch{return void 0}const urls=[];if(kind==="new"){const rulesField=asRecord(asRecord(asRecord(doc)?.config)?.providerConfigRules);const rules=rulesField&&Array.isArray(rulesField.providerRules)?rulesField.providerRules:[];for(const raw of rules){const api=asRecord(asRecord(asRecord(raw)?.config)?.api);if(api&&typeof api.baseUrl==="string")urls.push(api.baseUrl)}}else{const provider=asRecord(asRecord(doc)?.provider);if(!provider)return void 0;for(const value of Object.values(provider)){const options=asRecord(asRecord(value)?.options);if(options&&typeof options.baseURL==="string")urls.push(options.baseURL)}}for(const url of urls){if(WRAPPED_URL_RE.test(url))return url.slice(0,url.indexOf("/bili/"))}return void 0}import crypto3 from"crypto";import fs12 from"fs";import path19 from"path";init_instance();init_config();var SIGNING_BLOCK_MESSAGE='zcode v3.14+ client signing (#1621) rejects the http://127.0.0.1 /bili/ origin at model creation ("Client signing handshake requires HTTPS.") \u2014 skipping native routing; provider store left untouched. For compression on this build use the GUI cert-MITM setup (Settings \u2192 Network: HTTP proxy + root CA path).';function planNativeZcode(env=process.env){if(env.BILLION_CONTEXT_PLUGIN==="0"||env.BILI_NATIVE_ZCODE==="0")return{mode:"off"};if(env.BILI_PROVIDER_REWRITES!==void 0)return{mode:"off"};const attach=nativeAttachOrigin(env)??proxyEnvOrigin(env);if(attach!==void 0)return{mode:"attach",attachOrigin:attach};return{mode:"spawn"}}async function probeProxyHealth(origin,timeoutMs=2e3){try{const res=await fetch(`${origin}/__bili/plugin/status?conversationId=zcode&fallback=latest`,{signal:AbortSignal.timeout(timeoutMs)});if(res.status>=500)return false;const text=await res.text();return text.startsWith("{")&&text.includes('"ok"')}catch{return false}}async function waitForProxyHealthy(origin,deadlineMs=15e3,intervalMs=250){const deadline=Date.now()+deadlineMs;for(;;){if(await probeProxyHealth(origin))return true;if(Date.now()+intervalMs>deadline)return false;await new Promise(r=>setTimeout(r,intervalMs))}}var CONFIG_LOCK_DIR=".bili-config.lock";var CONFIG_LOCK_TIMEOUT_MS=5e3;var CONFIG_LOCK_STALE_MS=3e4;function lockStale(lockDir){try{const pidRaw=fs12.readFileSync(path19.join(lockDir,"pid"),"utf8").trim();const age=Date.now()-fs12.statSync(lockDir).mtimeMs;if(age>CONFIG_LOCK_STALE_MS)return true;const pid=Number.parseInt(pidRaw,10);return Number.isInteger(pid)&&pid>0&&!isPidAlive(pid)}catch{return true}}async function withConfigLock(dataDir,fn){const lockDir=path19.join(dataDir,"v2",CONFIG_LOCK_DIR);fs12.mkdirSync(path19.join(dataDir,"v2"),{recursive:true});const deadline=Date.now()+CONFIG_LOCK_TIMEOUT_MS;for(;;){try{fs12.mkdirSync(lockDir);fs12.writeFileSync(path19.join(lockDir,"pid"),String(process.pid));break}catch(err){if(err.code!=="EEXIST")throw err;if(lockStale(lockDir)){fs12.rmSync(lockDir,{recursive:true,force:true});continue}if(Date.now()>deadline)throw new Error("timed out waiting for the zcode config lock");await new Promise(r=>setTimeout(r,100))}}try{return fn()}finally{fs12.rmSync(lockDir,{recursive:true,force:true})}}function hashText(text){return crypto3.createHash("sha256").update(text).digest("hex")}function snapshotAndWrite(file,text){const bak=`${file}.bili-bak`;const last=`${file}.bili-last`;if(fs12.existsSync(file)){let cur;try{cur=hashText(fs12.readFileSync(file,"utf8"))}catch{return}let prev;try{prev=fs12.readFileSync(last,"utf8").trim()}catch{}if(!(prev===cur&&fs12.existsSync(bak)))fs12.copyFileSync(file,bak)}fs12.writeFileSync(file,text);try{fs12.writeFileSync(last,`${hashText(text)}
133
133
  `)}catch{}}function removeSnapshots(file){try{fs12.rmSync(`${file}.bili-bak`,{force:true})}catch{}try{fs12.rmSync(`${file}.bili-last`,{force:true})}catch{}}function zcodePolicyFromEnv(env){const raw=(env.BILI_ZCODE_ROUTE??"").trim().toLowerCase();const route=raw==="plans"||raw==="none"?raw:"all";const signRaw=(env.BILI_ZCODE_SIGNING_FIXED??"").trim().toLowerCase();return{route,directPrefixes:zcodeDirectPrefixes(env),assumeSigningFixed:signRaw==="1"||signRaw==="true"}}function logNoRouteNextSteps(opts){const{kind,dataDir,env,origin,policy,skipped,log:log2}=opts;if(skipped.length>0&&skipped.every(s3=>s3.reason.includes("#1621"))){log2("every provider rule you defined is a v3.14+ client-signing coding-plan account (#1621); native URL-rewriting cannot compress them \u2014 use the cert-MITM path (Settings \u2192 Network: HTTP proxy + root CA path), the documented #1621 workaround (confirm it on your build/account).");return}if(skipped.length===0){let msg="no explicit provider rule in the personal store to wrap. This ZCode build resolves its active providers from the built-in/account layer, not from a config file \u2014 so an empty personal store does not mean 'nothing to route', only that there is nothing for native routing to intercept here.";if(kind==="new"){const legacyFile=zcodeStoreCandidates(dataDir,"legacy",env)[0];let legacyRecords=0;try{const applied=applyZcodeRouting(fs12.readFileSync(legacyFile,"utf8"),"legacy",origin,policy);legacyRecords=applied.wrapped.length+applied.skipped.length}catch{legacyRecords=0}if(legacyRecords>0){msg+=` (The legacy file ${legacyFile} still holds ${legacyRecords} provider record(s) from before the migration; this build does not read it as a provider source, so they are not routing candidates.)`}}msg+=" Coding-plan accounts are signing-protected (#1621) and need the cert-MITM path (Settings \u2192 Network); a custom non-signing provider can be added to the personal store to route natively.";log2(msg);return}}async function routeZcodeConfig(opts){const env=opts.env??process.env;const log2=opts.log??defaultLog;const dataDir=opts.dataDir??resolveZcodeDataDir(env);const v2Dir=path19.join(dataDir,"v2");const hasStore=fs12.existsSync(v2Dir)||zcodeStoreCandidates(dataDir,"new",env).some(f2=>fs12.existsSync(f2));if(!hasStore){log2(`no ${v2Dir} \u2014 nothing to route`);return void 0}const{kind,file}=detectZcodeStore(dataDir,env);const policy=opts.policy??defaultZcodeRoutePolicy();if(zcodeSigningBlocksRouting(kind,policy)){log2(SIGNING_BLOCK_MESSAGE);return void 0}let text;try{text=fs12.readFileSync(file,"utf8")}catch{log2(`no ${file} \u2014 nothing to route`);return void 0}const port=Number.parseInt(new URL(opts.origin).port,10);if(!Number.isInteger(port)||port<=0)throw new Error(`cannot derive a port from proxy origin ${opts.origin}`);const applied=applyZcodeRouting(text,kind,opts.origin,policy);if(applied.wrapped.length===0){log2("no routable provider entry found \u2014 leaving the config untouched");if(applied.skipped.length>0){log2(`skipped ${applied.skipped.length} entr${applied.skipped.length===1?"y":"ies"}: ${applied.skipped.map(s3=>`${s3.id} (${s3.reason})`).join("; ")}`)}logNoRouteNextSteps({kind,dataDir,env,origin:opts.origin,policy,skipped:applied.skipped,log:log2});return void 0}await withConfigLock(dataDir,()=>{snapshotAndWrite(file,applied.text)});const check=applyZcodeRouting(fs12.readFileSync(file,"utf8"),kind,opts.origin,policy);if(check.wrapped.length!==applied.wrapped.length||check.text!==applied.text){throw new Error(`zcode config rewrite verification failed for ${file}`)}if(applied.skipped.length>0){log2(`skipped ${applied.skipped.length} entr${applied.skipped.length===1?"y":"ies"}: ${applied.skipped.map(s3=>`${s3.id} (${s3.reason})`).join("; ")}`)}return{origin:opts.origin,port,kind,file,upstream:applied.wrapped[0].upstream,wrapped:applied.wrapped}}async function activateZcodePluginMode(applied,opts={}){const env=opts.env??process.env;const log2=opts.log??defaultLog;const dataDir=opts.dataDir??resolveZcodeDataDir(env);await withConfigLock(dataDir,()=>{fs12.writeFileSync(applied.file,stampZcodePluginHeader(fs12.readFileSync(applied.file,"utf8"),applied.kind))});const info={agent:"zcode",model:"zcode",baseURL:applied.upstream,source:"native-bootstrap"};try{await reportRuntimeInfo(applied.origin,info)}catch(err){log2(`runtime-info report failed (non-fatal): ${err instanceof Error?err.message:String(err)}`)}}function unrouteZcode(opts){const env=opts.env??process.env;const log2=opts.log??defaultLog;const dataDir=opts.dataDir??resolveZcodeDataDir(env);try{for(const kind of["legacy","new"]){for(const file of zcodeStoreCandidates(dataDir,kind,env)){try{const text=fs12.readFileSync(file,"utf8");if(text.includes("/bili/")){fs12.writeFileSync(file,unrouteZcodeText(text,kind).text);log2(`reverted ${path19.basename(file)} to pre-native routing`)}}catch{}removeSnapshots(file)}}}catch(err){log2(`unroute failed: ${err instanceof Error?err.message:String(err)}`)}}function defaultLog(msg){process.stderr.write(`[bili-zcode] ${msg}
134
134
  `)}function planZcodeRouting(opts={}){const env=opts.env??process.env;const log2=opts.log??(()=>{});const dataDir=opts.dataDir??resolveZcodeDataDir(env);const v2Dir=path19.join(dataDir,"v2");const hasStore=fs12.existsSync(v2Dir)||zcodeStoreCandidates(dataDir,"new",env).some(f2=>fs12.existsSync(f2));if(!hasStore){log2(`no ${v2Dir} \u2014 nothing to route`);return{routable:false,reason:"no-store"}}const{kind,file}=detectZcodeStore(dataDir,env);const policy=opts.policy??zcodePolicyFromEnv(env);if(zcodeSigningBlocksRouting(kind,policy)){log2(SIGNING_BLOCK_MESSAGE);return{routable:false,reason:"signing"}}let text;try{text=fs12.readFileSync(file,"utf8")}catch{log2(`no ${file} \u2014 nothing to route`);return{routable:false,reason:"no-file"}}const applied=applyZcodeRouting(text,kind,"http://127.0.0.1:1",policy);if(applied.wrapped.length===0){log2("no routable provider entry found \u2014 leaving the config untouched");if(applied.skipped.length>0){log2(`skipped ${applied.skipped.length} entr${applied.skipped.length===1?"y":"ies"}: ${applied.skipped.map(s3=>`${s3.id} (${s3.reason})`).join("; ")}`)}logNoRouteNextSteps({kind,dataDir,env,origin:"http://127.0.0.1:1",policy,skipped:applied.skipped,log:log2});return{routable:false,reason:"empty-rules"}}return{routable:true}}async function bootstrapZcodeNative(opts={}){const env=opts.env??process.env;const log2=opts.log??defaultLog;const plan=planNativeZcode(env);if(plan.mode==="off")return{mode:"off"};const policy=zcodePolicyFromEnv(env);if(policy.route==="none"){log2('zcode route is "none" (BILI_ZCODE_ROUTE) \u2014 leaving the provider store direct');return{mode:"off"}}const dataDir=opts.dataDir??resolveZcodeDataDir(env);const routePlan=planZcodeRouting({env,dataDir,log:log2,policy});if(!routePlan.routable){return{mode:"degraded",reason:routePlan.reason}}let origin;let attached;if(plan.mode==="attach"){origin=plan.attachOrigin;attached=true;if(!await waitForProxyHealthy(origin,opts.healthDeadlineMs)){throw new Error(`attach target ${origin} is not healthy \u2014 start your bili proxy first`)}}else{const ensure=opts.ensureProxy??defaultEnsureProxy;const handle=await ensure();origin=handle.origin;attached=!!handle.attached}const routed=await routeZcodeConfig({origin,env,dataDir,log:log2,policy});if(routed)log2(`routed ${routed.wrapped.map(w2=>w2.id).join(", ")} via ${origin} \u2192 ${routed.upstream}`);return{mode:"active",attached,externallyOwned:plan.mode==="attach",routed}}async function defaultEnsureProxy(){const explicit=resolveZcodeNativePort();const handle=await ensureProxyRunning({host:LAUNCHER_DEFAULT_HOST,port:explicit??0,passthrough:false,debug:false,strictPort:explicit!==void 0,lane:"zcode"},{scriptPath:nativeProxyScriptPath()});return{origin:handle.origin,attached:!!handle.attached}}async function defaultFindReplacement(){const inst=await findLiveAttachableInstance({host:LAUNCHER_DEFAULT_HOST,port:0,passthrough:false,debug:false,lane:"zcode"},{scriptPath:nativeProxyScriptPath()});return inst?{origin:inst.origin}:void 0}async function repairSharedStoreDrift(opts){const env=opts.env??process.env;const log2=opts.log??defaultLog;const probe=opts.probe??probeProxyHealth;const dataDir=opts.dataDir??resolveZcodeDataDir(env);const current=detectCurrentZcodeOrigin(dataDir,env);if(!current)return"unmanaged";if(current===opts.selfOrigin)return"self";if(await probe(current))return"foreign-live";log2(`shared store points at dead instance ${current} \u2014 repairing`);const policy=zcodePolicyFromEnv(env);if(await probe(opts.selfOrigin)){const routed=await routeZcodeConfig({origin:opts.selfOrigin,env,dataDir:opts.dataDir,log:log2,policy});if(routed){await activateZcodePluginMode(routed,{env,dataDir:opts.dataDir,log:log2});log2(`store repaired \u2192 ${opts.selfOrigin}`);return"repointed-self"}}else{const replacement=await(opts.findReplacement??defaultFindReplacement)();if(replacement){const routed=await routeZcodeConfig({origin:replacement.origin,env,dataDir:opts.dataDir,log:log2,policy});if(routed){await activateZcodePluginMode(routed,{env,dataDir:opts.dataDir,log:log2});log2(`store repaired \u2192 ${replacement.origin}`);return"repointed-replacement"}}}unrouteZcode({env,dataDir:opts.dataDir,log:log2});log2(`store reverted to direct upstream (${current} is dead)`);return"reverted-direct"}async function handoffZcodeRoutingOnExit(opts){const env=opts.env??process.env;const log2=opts.log??defaultLog;const dataDir=opts.dataDir??resolveZcodeDataDir(env);const current=detectCurrentZcodeOrigin(dataDir,env);if(!current||current!==opts.ownOrigin)return"not-ours";const replacement=await(opts.findReplacement??defaultFindReplacement)();if(replacement){const routed=await routeZcodeConfig({origin:replacement.origin,env,dataDir:opts.dataDir,log:log2,policy:zcodePolicyFromEnv(env)});if(routed){await activateZcodePluginMode(routed,{env,dataDir:opts.dataDir,log:log2});log2(`exit handoff: store \u2192 ${replacement.origin}`);return"handed-off"}}unrouteZcode({env,dataDir:opts.dataDir,log:log2});log2("exit handoff: store reverted to direct upstream");return"reverted-direct"}init_log_mask();init_logger();init_paths();init_version();import{appendFileSync,mkdirSync as mkdirSync3}from"fs";import path21 from"path";function logHostEvent(level,origin,msg){try{const file=defaultLogFile();mkdirSync3(path21.dirname(file),{recursive:true});const safe=maskUrlsForDiagnostics(maskIpsInText(redactSecretsInText(msg)));appendFileSync(file,`${logTimestamp()} [${level}] [v=${VERSION}] ${origin?`${origin} `:""}${safe}
135
- `)}catch{}}init_logger();init_version();import http from"http";var PERMISSION_DENIED_SIGNATURE=/\b(?:EPERM|EACCES|EROFS|EBUSY)\b|operation not permitted|permission denied|read-only file system|readonly database/i;var BILI_DATA_PATH_SIGNATURE=/billion-context|combined-ca\.pem|index\.db|\.local[\\/](?:share|state)[\\/]/i;function classifyStartupFailure(sample){if(!PERMISSION_DENIED_SIGNATURE.test(sample)||!BILI_DATA_PATH_SIGNATURE.test(sample))return"";return"possible cause: the proxy could not write its own data files (EPERM/EACCES/read-only on the bili data dir) \u2014 most often antivirus (e.g. Windows Defender Controlled Folder Access) blocking the node runtime, a read-only flag or ACL on the directory, or another process holding the files; add the bili data dir and the node runtime to AV exclusions (see #367) or fix the directory permissions, then retry"}var MAX_HOLD_MS=10*6e4;init_update();init_win_cmd();init_client_config();init_config();init_registry();init_config();init_logger();function parseLauncherModelWindows(raw){if(!raw)return{};try{const parsed=JSON.parse(raw);if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))return{};const out={};for(const[id,v2]of Object.entries(parsed)){if(typeof v2==="number"&&Number.isFinite(v2)&&v2>0)out[id]=Math.floor(v2)}return out}catch{return{}}}var LAUNCHER_MODEL_WINDOWS=parseLauncherModelWindows(process.env.BILI_LAUNCHER_MODEL_WINDOWS);function parseLauncherModelMaxOutputs(raw){if(!raw)return{};try{const parsed=JSON.parse(raw);if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))return{};const out={};for(const[id,v2]of Object.entries(parsed)){if(typeof v2==="number"&&Number.isFinite(v2)&&v2>0)out[id]=Math.floor(v2)}return out}catch{return{}}}var LAUNCHER_MODEL_MAX_OUTPUTS=parseLauncherModelMaxOutputs(process.env.BILI_LAUNCHER_MODEL_MAX_OUTPUTS);init_vertex();init_client_config();init_logger();import{createHash as createHash13}from"crypto";import{createHash as createHash12,randomUUID as randomUUID4}from"crypto";import{closeSync,existsSync as existsSync6,fsyncSync,mkdirSync as mkdirSync6,openSync,readdirSync,readFileSync as readFileSync7,renameSync as renameSync2,rmSync,statSync as statSync6,writeFileSync as writeFileSync5}from"fs";import{readdir as readdir2,readFile as readFile4,rm as rm2}from"fs/promises";import*as path24 from"path";init_paths();init_knobs();init_logger();init_runtime_status();init_version();import{createCipheriv,createDecipheriv,randomBytes as randomBytes2}from"crypto";import*as zlib from"zlib";var ENCRYPT_MAGIC=Buffer.from("BILIENC1","utf8");var ZSTD_MAGIC=Buffer.from("BILIZSTD1","utf8");var NONCE_LEN=12;var TAG_LEN=16;var ENCRYPT_HEADER_LEN=ENCRYPT_MAGIC.length+2+NONCE_LEN;var MIN_ENCRYPTED_LEN=ENCRYPT_HEADER_LEN+TAG_LEN;var PLAIN_HEADER_LEN=ZSTD_MAGIC.length+2;init_logger();init_billing();init_state_hydration();init_shadow();init_backend();init_ingest();init_store();init_logger();init_paths();import{randomUUID as randomUUID2}from"crypto";import{mkdirSync as mkdirSync5,writeFileSync as writeFileSync4}from"fs";import{dirname as dirname3,join as join2}from"path";init_knobs();import{createHash as createHash11,randomUUID as randomUUID3}from"crypto";import{AsyncLocalStorage as AsyncLocalStorage3}from"async_hooks";init_logger();import{createHash as createHash10}from"crypto";import{createHash as createHash9}from"crypto";init_logger();init_logger();init_billing();init_util();var BOOT_ID=randomUUID3();var SEAM_BODY_CAP=512*1024;var BODY_FULL_CAP=8*1024*1024;var captures=new AsyncLocalStorage3;var LEARNED_IMAGE_COST_TTL_MS=24*60*60*1e3;var{join:join4}=path24;init_version();init_knobs();init_config();init_config();init_paths();init_logger();init_external_summary_settings();import*as path25 from"path";init_turn_separator();init_turn_separator();var ABORT_REANCHOR_MAX_AGE_MS=30*60*1e3;var MAX_SESSIONS=maxSessions();var MAX_RESIDENT_BYTES=sessionResidentMaxBytes();var SPLIT_CANARY_FRESH_MS=10*60*1e3;import{randomUUID as randomUUID5}from"crypto";init_knobs();init_client_config();import fs14 from"fs";import path26 from"path";init_dsh_channel();var SCAN_CACHE_TTL_MS=5*60*1e3;var CONFLICT_ACTIVE_WINDOW_MS=7*24*60*60*1e3;var LAUNCHER_DEFAULT_HOST="127.0.0.1";var HEALTH_PATH="/__bili/health";var HEALTH_POLL_INTERVAL_MS=200;var SPAWN_WAIT_MS=envMillis(process.env,"BILI_SPAWN_WAIT_MS",2e4);var SLOW_START_GRACE_MS=envMillis(process.env,"BILI_SLOW_START_GRACE_MS",4e4);var SPAWN_BUDGET_MS=SPAWN_WAIT_MS+SLOW_START_GRACE_MS;var PROBE_TIMEOUT_MS=1500;var STARTING_MARKER_TTL_MS=SPAWN_BUDGET_MS+3e4;var POST_EXIT_REDISCOVERY_MS=3e3;var DEFAULT_MITM_DOMAIN_SET=new Set(DEFAULT_MITM_DOMAINS.map(d=>d.toLowerCase()));function proxyOrigin(host,port){return`http://${host}:${port}`}function healthUrl(origin){return origin+HEALTH_PATH}async function defaultFetch(url){const ctrl=new AbortController;const t=setTimeout(()=>ctrl.abort(),PROBE_TIMEOUT_MS);try{const res=await fetch(url,{signal:ctrl.signal});return{ok:res.ok}}catch{return{ok:false}}finally{clearTimeout(t)}}async function probeHealth(origin,fetchImpl){try{const{ok}=await fetchImpl(healthUrl(origin));return ok}catch{return false}}function describeProbeFailure(err){const e=err;const code=e?.cause?.code??e?.code;if(typeof code==="string"&&code.length>0)return code;if(e?.name==="TimeoutError"||e?.name==="AbortError")return`timeout after ${PROBE_TIMEOUT_MS}ms`;if(typeof e?.message==="string"&&e.message.length>0)return e.message.slice(0,160);return String(err)}async function defaultFetchDetail(url){const ctrl=new AbortController;const t=setTimeout(()=>ctrl.abort(),PROBE_TIMEOUT_MS);try{const res=await fetch(url,{signal:ctrl.signal});return res.ok?{ok:true}:{ok:false,detail:`HTTP ${res.status}`}}catch(err){return{ok:false,detail:describeProbeFailure(err)}}finally{clearTimeout(t)}}async function fetchHealthInfoDefault(origin,opts){try{const res=await fetch(healthUrl(origin),{signal:AbortSignal.timeout(PROBE_TIMEOUT_MS),...opts?.noKeepAlive?{headers:{connection:"close"}}:{}});if(!res.ok)return void 0;const data=await res.json();const info={ok:Boolean(data.ok),instanceId:typeof data.instanceId==="string"?data.instanceId:void 0};if(typeof data.version==="string")info.version=data.version;if(typeof data.pid==="number")info.pid=data.pid;if(typeof data.auxProxy==="string"&&data.auxProxy.length>0)info.auxProxy=data.auxProxy;if(typeof data.auxProxySource==="string"&&data.auxProxySource.length>0)info.auxProxySource=data.auxProxySource;if(data.watchdog&&typeof data.watchdog==="object"&&typeof data.watchdog.armed==="boolean"){const wd=data.watchdog;const watchers=Array.isArray(wd.watchers)?wd.watchers.filter(w2=>typeof w2==="number"):void 0;info.watchdog={armed:wd.armed,watchers}}return info}catch{return void 0}}async function registerWatcherDefault(origin,pid){try{const res=await fetch(`${origin}/__bili/watcher`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({pid}),signal:AbortSignal.timeout(2e3)});if(!res.ok){if(res.status===409)return"refused";console.error(`bili: watcher registration returned HTTP ${res.status} \u2014 the shared proxy may exit when its first owner does`);return"failed"}return"ok"}catch(err){console.error(`bili: watcher registration failed \u2014 the shared proxy may exit when its first owner does (${err instanceof Error?err.message:String(err)})`);return"failed"}}function isStartingMarkerActive(marker,nowMs){return isPidAlive(marker.pid)&&nowMs-marker.startedAt<STARTING_MARKER_TTL_MS}function recordedModelMap(passed,ambientRaw,parse3){return parse3(passed&&Object.keys(passed).length>0?JSON.stringify(passed):ambientRaw)}function instanceShapeMismatch(inst,opts,foreignLanes=[]){if(opts.lane!==void 0&&inst.lane!==void 0&&inst.lane!==opts.lane&&!foreignLanes.includes(inst.lane))return"lane-mismatch";if(inst.host!==opts.host||inst.passthrough!==resolveRecordedPassthrough(opts.passthrough))return"host-or-passthrough-mismatch";const wantDomains=resolveRecordedMitmDomains(opts.mitmDomains);if(inst.mitmDomains.length!==wantDomains.length||inst.mitmDomains.some((d,i)=>d!==wantDomains[i]))return"mitm-domains-mismatch";const wantWindows=recordedModelMap(opts.modelWindows,process.env.BILI_LAUNCHER_MODEL_WINDOWS,parseLauncherModelWindows);if(Object.keys(inst.modelWindows).length!==Object.keys(wantWindows).length)return"model-windows-mismatch";if(!Object.keys(wantWindows).every(k2=>inst.modelWindows[k2]===wantWindows[k2]))return"model-windows-mismatch";const wantMax=recordedModelMap(opts.modelMaxOutputs,process.env.BILI_LAUNCHER_MODEL_MAX_OUTPUTS,parseLauncherModelMaxOutputs);if(Object.keys(inst.modelMaxOutputs??{}).length!==Object.keys(wantMax).length)return"model-max-outputs-mismatch";return Object.keys(wantMax).every(k2=>(inst.modelMaxOutputs??{})[k2]===wantMax[k2])?void 0:"model-max-outputs-mismatch"}function isNewerSameLaneHolder(inst,optsLane,healthVersion,ownVersion,userZone){if(userZone||optsLane===void 0||healthVersion===void 0)return false;return inst.lane===optsLane&&isVersionNewer(healthVersion,ownVersion)}function instanceCompatible(inst,opts,codeFingerprint,foreignLanes=[]){if(inst.codeFingerprint===void 0||inst.codeFingerprint!==codeFingerprint)return"code-fingerprint-mismatch";return instanceShapeMismatch(inst,opts,foreignLanes)}async function probeLiveInstances(readInstance,fetchHealthInfo,diag,isConnectable=tcpConnectable){const seen=new Map;const inst=readInstance();if(isProxyInstanceFile(inst))seen.set(inst.instanceId||inst.origin,inst);for(const live of discoverLiveInstances())seen.set(live.instanceId||live.origin,live);const checked=await Promise.all([...seen.values()].map(async c=>{if(!isPidAlive(c.pid)){diag?.(`native-attach: drop ${c.origin} (pid ${c.pid}): owner process gone`);return void 0}const health=await fetchHealthInfo(c.origin);if(!health||!health.ok){if(health===void 0&&await isConnectable(c.origin)){diag?.(`native-attach: keep ${c.origin} (pid ${c.pid}): health probe failed but TCP connect succeeded \u2014 instance is BUSY (event loop saturated), not dead (#3654/#4811)`);return{inst:c,health:void 0}}diag?.(health===void 0?`native-attach: drop ${c.origin} (pid ${c.pid}): health probe failed`:`native-attach: drop ${c.origin} (pid ${c.pid}): health probe answered but reports not-ok`);return void 0}if(health.instanceId!==void 0&&health.instanceId!==c.instanceId){diag?.(`native-attach: drop ${c.origin} (pid ${c.pid}): instance id mismatch (${c.instanceId} vs ${health.instanceId})`);return void 0}return{inst:c,health}}));return checked.filter(c=>c!==void 0)}function attachGateAllows(health,attachExternal){if(attachExternal)return true;return health?.watchdog?.armed===true}function isUserZoneInstance(inst){return inst.lane===void 0&&inst.launchToken===void 0}function gateRefusalMessage(inst,health){const reason=health.watchdog&&health.watchdog.armed===false?"it reports NO session-lifecycle watchdog (started without BILI_PARENT_PID, e.g. manual `bili start`)":"it does not report watchdog state (older bili build) \u2014 its lifecycle is unverifiable";return`bili: refusing to attach to ${inst.origin} (pid ${inst.pid}) \u2014 ${reason}. It would outlive this session and ignore config edits until killed (#1322/#1335). Starting a session-owned proxy instead; set native.attachExternal=true or BILI_NATIVE_ATTACH_EXTERNAL=1 to attach anyway.`}function attachClass(inst,lane,foreignLanes){if(lane===void 0)return 1;if(inst.lane===lane)return 0;if(inst.lane!==void 0)return 1+foreignLanes.indexOf(inst.lane);return foreignLanes.length+1}function normalizeOrigin(o){return o.trim().replace(/\/+$/,"").toLowerCase()}function pickAttachable(candidates,opts,codeFingerprint,attachExternal,attachPolicy,attachUrl,refusedLog,diag,foreignLanes=[]){let best;let bestClass=Number.MAX_SAFE_INTEGER;let bestStartedAt=Number.NEGATIVE_INFINITY;for(const c of candidates){if(attachUrl&&normalizeOrigin(c.inst.origin)!==normalizeOrigin(attachUrl)){diag?.(`native-attach: skip ${c.inst.origin} (pid ${c.inst.pid}): not the explicit attachUrl target`);continue}let incompatible=instanceCompatible(c.inst,opts,codeFingerprint,foreignLanes);if(incompatible==="code-fingerprint-mismatch"&&c.health?.version!==void 0&&isNewerSameLaneHolder(c.inst,opts.lane,c.health.version,VERSION,isUserZoneInstance(c.inst))){const adoptedShape=instanceShapeMismatch(c.inst,opts,foreignLanes);if(adoptedShape===void 0){diag?.(`native-attach: adopt ${c.inst.origin} (pid ${c.inst.pid}): foreign bytes but self-reported v${c.health.version} is strictly NEWER than this lane's v${VERSION} \u2014 riding the newer build instead of deadlocking behind it (#4125)`);incompatible=void 0}else{diag?.(`native-attach: skip ${c.inst.origin} (pid ${c.inst.pid}): reports v${c.health.version} (newer) but its config shape differs (${adoptedShape}) \u2014 shape guards survive upward adoption (#4125)`);incompatible=adoptedShape}}if(incompatible!==void 0){diag?.(`native-attach: skip ${c.inst.origin} (pid ${c.inst.pid}): incompatible (${incompatible})`);continue}if(opts.strictPort&&c.inst.port!==opts.port){diag?.(`native-attach: skip ${c.inst.origin} (pid ${c.inst.pid}): port mismatch`);continue}const sameLane=opts.lane!==void 0&&c.inst.lane===opts.lane;if(!attachUrl&&!attachExternal&&attachPolicy==="own-lane"&&opts.lane!==void 0&&!sameLane&&c.health?.watchdog?.armed!==true){diag?.(`native-attach: skip ${c.inst.origin} (pid ${c.inst.pid}): not own lane and not an armed shared daemon (attachPolicy=own-lane)`);continue}if(c.health===void 0){if(!sameLane&&!attachExternal&&!isUserZoneInstance(c.inst)){if(!refusedLog.has(c.inst.origin)){refusedLog.add(c.inst.origin);const msg=`bili: refusing to attach to ${c.inst.origin} (pid ${c.inst.pid}) \u2014 health probe silent but TCP alive (BUSY, event loop saturated #3654) and its lifecycle is unverifiable from this lane. Starting a session-owned proxy instead; set native.attachExternal=true or BILI_NATIVE_ATTACH_EXTERNAL=1 to attach anyway.`;console.error(msg);diag?.(msg)}continue}}else if(!attachGateAllows(c.health,attachExternal)&&!isUserZoneInstance(c.inst)){if(!refusedLog.has(c.inst.origin)){refusedLog.add(c.inst.origin);console.error(gateRefusalMessage(c.inst,c.health));diag?.(gateRefusalMessage(c.inst,c.health))}continue}const cls=attachClass(c.inst,opts.lane,foreignLanes);if(cls<bestClass||cls===bestClass&&c.inst.startedAt>bestStartedAt){best=c.inst;bestClass=cls;bestStartedAt=c.inst.startedAt}}return best}async function waitForStarterInstance(readInstance,fetchHealthInfo,now,sleepImpl,opts,codeFingerprint,attachExternal,attachPolicy,attachUrl,refusedLog,diag,foreignLanes=[],isConnectable=tcpConnectable){const deadline=now()+SPAWN_BUDGET_MS;const probe=async()=>pickAttachable(await probeLiveInstances(readInstance,fetchHealthInfo,diag,isConnectable),opts,codeFingerprint,attachExternal,attachPolicy,attachUrl,refusedLog,diag,foreignLanes);let inst;while(now()<deadline){await sleepImpl(HEALTH_POLL_INTERVAL_MS);inst=await probe();if(inst)break;const still=readStartingMarker();if(!still||!isStartingMarkerActive(still,now()))break}return inst??await probe()}function defaultAttachDiag(debug){return msg=>{logHostEvent("info","",msg);if(debug)process.stderr.write(`${logTimestamp()} [info] [v=${VERSION}] ${msg}
135
+ `)}catch{}}init_logger();init_version();import http from"http";var PERMISSION_DENIED_SIGNATURE=/\b(?:EPERM|EACCES|EROFS|EBUSY)\b|operation not permitted|permission denied|read-only file system|readonly database/i;var BILI_DATA_PATH_SIGNATURE=/billion-context|combined-ca\.pem|index\.db|\.local[\\/](?:share|state)[\\/]/i;function classifyStartupFailure(sample){if(!PERMISSION_DENIED_SIGNATURE.test(sample)||!BILI_DATA_PATH_SIGNATURE.test(sample))return"";return"possible cause: the proxy could not write its own data files (EPERM/EACCES/read-only on the bili data dir) \u2014 most often antivirus (e.g. Windows Defender Controlled Folder Access) blocking the node runtime, a read-only flag or ACL on the directory, or another process holding the files; add the bili data dir and the node runtime to AV exclusions (see #367) or fix the directory permissions, then retry"}var MAX_HOLD_MS=10*6e4;init_update();init_win_cmd();init_client_config();init_config();init_registry();init_config();init_logger();function parseLauncherModelWindows(raw){if(!raw)return{};try{const parsed=JSON.parse(raw);if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))return{};const out={};for(const[id,v2]of Object.entries(parsed)){if(typeof v2==="number"&&Number.isFinite(v2)&&v2>0)out[id]=Math.floor(v2)}return out}catch{return{}}}var LAUNCHER_MODEL_WINDOWS=parseLauncherModelWindows(process.env.BILI_LAUNCHER_MODEL_WINDOWS);function parseLauncherModelMaxOutputs(raw){if(!raw)return{};try{const parsed=JSON.parse(raw);if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))return{};const out={};for(const[id,v2]of Object.entries(parsed)){if(typeof v2==="number"&&Number.isFinite(v2)&&v2>0)out[id]=Math.floor(v2)}return out}catch{return{}}}var LAUNCHER_MODEL_MAX_OUTPUTS=parseLauncherModelMaxOutputs(process.env.BILI_LAUNCHER_MODEL_MAX_OUTPUTS);init_vertex();init_client_config();init_logger();import{createHash as createHash13}from"crypto";import{createHash as createHash12,randomUUID as randomUUID4}from"crypto";import{closeSync,existsSync as existsSync6,fsyncSync,mkdirSync as mkdirSync6,openSync,readdirSync,readFileSync as readFileSync7,renameSync as renameSync2,rmSync,statSync as statSync6,writeFileSync as writeFileSync5}from"fs";import{readdir as readdir2,readFile as readFile4,rm as rm2}from"fs/promises";import*as path24 from"path";init_paths();init_knobs();init_logger();init_runtime_status();init_version();import{createCipheriv,createDecipheriv,randomBytes as randomBytes2}from"crypto";import*as zlib from"zlib";var ENCRYPT_MAGIC=Buffer.from("BILIENC1","utf8");var ZSTD_MAGIC=Buffer.from("BILIZSTD1","utf8");var NONCE_LEN=12;var TAG_LEN=16;var ENCRYPT_HEADER_LEN=ENCRYPT_MAGIC.length+2+NONCE_LEN;var MIN_ENCRYPTED_LEN=ENCRYPT_HEADER_LEN+TAG_LEN;var PLAIN_HEADER_LEN=ZSTD_MAGIC.length+2;init_logger();init_billing();init_state_hydration();init_shadow();init_logger();var HOT_ATTACH_WINDOW_MS=10*6e4;var ATTACH_SILENCE_MS=5*6e4;init_backend();init_ingest();init_store();init_logger();init_paths();import{randomUUID as randomUUID2}from"crypto";import{mkdirSync as mkdirSync5,writeFileSync as writeFileSync4}from"fs";import{dirname as dirname3,join as join2}from"path";init_knobs();import{createHash as createHash11,randomUUID as randomUUID3}from"crypto";import{AsyncLocalStorage as AsyncLocalStorage3}from"async_hooks";init_logger();import{createHash as createHash10}from"crypto";import{createHash as createHash9}from"crypto";init_logger();init_logger();init_billing();init_util();var BOOT_ID=randomUUID3();var SEAM_BODY_CAP=512*1024;var BODY_FULL_CAP=8*1024*1024;var captures=new AsyncLocalStorage3;var LEARNED_IMAGE_COST_TTL_MS=24*60*60*1e3;var{join:join4}=path24;var FROZEN_SKIP_NOTICE_COOLDOWN_MS=10*6e4;init_version();init_knobs();init_config();init_config();init_paths();init_logger();init_external_summary_settings();import*as path25 from"path";init_turn_separator();init_turn_separator();var ABORT_REANCHOR_MAX_AGE_MS=30*60*1e3;var MAX_SESSIONS=maxSessions();var MAX_RESIDENT_BYTES=sessionResidentMaxBytes();var SPLIT_CANARY_FRESH_MS=10*60*1e3;import{randomUUID as randomUUID5}from"crypto";init_knobs();init_client_config();import fs14 from"fs";import path26 from"path";init_dsh_channel();var SCAN_CACHE_TTL_MS=5*60*1e3;var CONFLICT_ACTIVE_WINDOW_MS=7*24*60*60*1e3;var LAUNCHER_DEFAULT_HOST="127.0.0.1";var HEALTH_PATH="/__bili/health";var HEALTH_POLL_INTERVAL_MS=200;var SPAWN_WAIT_MS=envMillis(process.env,"BILI_SPAWN_WAIT_MS",2e4);var SLOW_START_GRACE_MS=envMillis(process.env,"BILI_SLOW_START_GRACE_MS",4e4);var SPAWN_BUDGET_MS=SPAWN_WAIT_MS+SLOW_START_GRACE_MS;var PROBE_TIMEOUT_MS=1500;var STARTING_MARKER_TTL_MS=SPAWN_BUDGET_MS+3e4;var POST_EXIT_REDISCOVERY_MS=3e3;var DEFAULT_MITM_DOMAIN_SET=new Set(DEFAULT_MITM_DOMAINS.map(d=>d.toLowerCase()));function proxyOrigin(host,port){return`http://${host}:${port}`}function healthUrl(origin){return origin+HEALTH_PATH}async function defaultFetch(url){const ctrl=new AbortController;const t=setTimeout(()=>ctrl.abort(),PROBE_TIMEOUT_MS);try{const res=await fetch(url,{signal:ctrl.signal});return{ok:res.ok}}catch{return{ok:false}}finally{clearTimeout(t)}}async function probeHealth(origin,fetchImpl){try{const{ok}=await fetchImpl(healthUrl(origin));return ok}catch{return false}}function describeProbeFailure(err){const e=err;const code=e?.cause?.code??e?.code;if(typeof code==="string"&&code.length>0)return code;if(e?.name==="TimeoutError"||e?.name==="AbortError")return`timeout after ${PROBE_TIMEOUT_MS}ms`;if(typeof e?.message==="string"&&e.message.length>0)return e.message.slice(0,160);return String(err)}async function defaultFetchDetail(url){const ctrl=new AbortController;const t=setTimeout(()=>ctrl.abort(),PROBE_TIMEOUT_MS);try{const res=await fetch(url,{signal:ctrl.signal});return res.ok?{ok:true}:{ok:false,detail:`HTTP ${res.status}`}}catch(err){return{ok:false,detail:describeProbeFailure(err)}}finally{clearTimeout(t)}}async function fetchHealthInfoDefault(origin,opts){try{const res=await fetch(healthUrl(origin),{signal:AbortSignal.timeout(PROBE_TIMEOUT_MS),...opts?.noKeepAlive?{headers:{connection:"close"}}:{}});if(!res.ok)return void 0;const data=await res.json();const info={ok:Boolean(data.ok),instanceId:typeof data.instanceId==="string"?data.instanceId:void 0};if(typeof data.version==="string")info.version=data.version;if(typeof data.pid==="number")info.pid=data.pid;if(typeof data.auxProxy==="string"&&data.auxProxy.length>0)info.auxProxy=data.auxProxy;if(typeof data.auxProxySource==="string"&&data.auxProxySource.length>0)info.auxProxySource=data.auxProxySource;if(data.watchdog&&typeof data.watchdog==="object"&&typeof data.watchdog.armed==="boolean"){const wd=data.watchdog;const watchers=Array.isArray(wd.watchers)?wd.watchers.filter(w2=>typeof w2==="number"):void 0;info.watchdog={armed:wd.armed,watchers}}return info}catch{return void 0}}async function registerWatcherDefault(origin,pid){try{const res=await fetch(`${origin}/__bili/watcher`,{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({pid}),signal:AbortSignal.timeout(2e3)});if(!res.ok){if(res.status===409)return"refused";console.error(`bili: watcher registration returned HTTP ${res.status} \u2014 the shared proxy may exit when its first owner does`);return"failed"}return"ok"}catch(err){console.error(`bili: watcher registration failed \u2014 the shared proxy may exit when its first owner does (${err instanceof Error?err.message:String(err)})`);return"failed"}}function isStartingMarkerActive(marker,nowMs){return isPidAlive(marker.pid)&&nowMs-marker.startedAt<STARTING_MARKER_TTL_MS}function recordedModelMap(passed,ambientRaw,parse3){return parse3(passed&&Object.keys(passed).length>0?JSON.stringify(passed):ambientRaw)}function instanceShapeMismatch(inst,opts,foreignLanes=[]){if(opts.lane!==void 0&&inst.lane!==void 0&&inst.lane!==opts.lane&&!foreignLanes.includes(inst.lane))return"lane-mismatch";if(inst.host!==opts.host||inst.passthrough!==resolveRecordedPassthrough(opts.passthrough))return"host-or-passthrough-mismatch";const wantDomains=resolveRecordedMitmDomains(opts.mitmDomains);if(inst.mitmDomains.length!==wantDomains.length||inst.mitmDomains.some((d,i)=>d!==wantDomains[i]))return"mitm-domains-mismatch";const wantWindows=recordedModelMap(opts.modelWindows,process.env.BILI_LAUNCHER_MODEL_WINDOWS,parseLauncherModelWindows);if(Object.keys(inst.modelWindows).length!==Object.keys(wantWindows).length)return"model-windows-mismatch";if(!Object.keys(wantWindows).every(k2=>inst.modelWindows[k2]===wantWindows[k2]))return"model-windows-mismatch";const wantMax=recordedModelMap(opts.modelMaxOutputs,process.env.BILI_LAUNCHER_MODEL_MAX_OUTPUTS,parseLauncherModelMaxOutputs);if(Object.keys(inst.modelMaxOutputs??{}).length!==Object.keys(wantMax).length)return"model-max-outputs-mismatch";return Object.keys(wantMax).every(k2=>(inst.modelMaxOutputs??{})[k2]===wantMax[k2])?void 0:"model-max-outputs-mismatch"}function isNewerSameLaneHolder(inst,optsLane,healthVersion,ownVersion,userZone){if(userZone||optsLane===void 0||healthVersion===void 0)return false;return inst.lane===optsLane&&isVersionNewer(healthVersion,ownVersion)}function instanceCompatible(inst,opts,codeFingerprint,foreignLanes=[]){if(inst.codeFingerprint===void 0||inst.codeFingerprint!==codeFingerprint)return"code-fingerprint-mismatch";return instanceShapeMismatch(inst,opts,foreignLanes)}async function probeLiveInstances(readInstance,fetchHealthInfo,diag,isConnectable=tcpConnectable){const seen=new Map;const inst=readInstance();if(isProxyInstanceFile(inst))seen.set(inst.instanceId||inst.origin,inst);for(const live of discoverLiveInstances())seen.set(live.instanceId||live.origin,live);const checked=await Promise.all([...seen.values()].map(async c=>{if(!isPidAlive(c.pid)){diag?.(`native-attach: drop ${c.origin} (pid ${c.pid}): owner process gone`);return void 0}const health=await fetchHealthInfo(c.origin);if(!health||!health.ok){if(health===void 0&&await isConnectable(c.origin)){diag?.(`native-attach: keep ${c.origin} (pid ${c.pid}): health probe failed but TCP connect succeeded \u2014 instance is BUSY (event loop saturated), not dead (#3654/#4811)`);return{inst:c,health:void 0}}diag?.(health===void 0?`native-attach: drop ${c.origin} (pid ${c.pid}): health probe failed`:`native-attach: drop ${c.origin} (pid ${c.pid}): health probe answered but reports not-ok`);return void 0}if(health.instanceId!==void 0&&health.instanceId!==c.instanceId){diag?.(`native-attach: drop ${c.origin} (pid ${c.pid}): instance id mismatch (${c.instanceId} vs ${health.instanceId})`);return void 0}return{inst:c,health}}));return checked.filter(c=>c!==void 0)}function attachGateAllows(health,attachExternal){if(attachExternal)return true;return health?.watchdog?.armed===true}function isUserZoneInstance(inst){return inst.lane===void 0&&inst.launchToken===void 0}function gateRefusalMessage(inst,health){const reason=health.watchdog&&health.watchdog.armed===false?"it reports NO session-lifecycle watchdog (started without BILI_PARENT_PID, e.g. manual `bili start`)":"it does not report watchdog state (older bili build) \u2014 its lifecycle is unverifiable";return`bili: refusing to attach to ${inst.origin} (pid ${inst.pid}) \u2014 ${reason}. It would outlive this session and ignore config edits until killed (#1322/#1335). Starting a session-owned proxy instead; set native.attachExternal=true or BILI_NATIVE_ATTACH_EXTERNAL=1 to attach anyway.`}function attachClass(inst,lane,foreignLanes){if(lane===void 0)return 1;if(inst.lane===lane)return 0;if(inst.lane!==void 0)return 1+foreignLanes.indexOf(inst.lane);return foreignLanes.length+1}function normalizeOrigin(o){return o.trim().replace(/\/+$/,"").toLowerCase()}function pickAttachable(candidates,opts,codeFingerprint,attachExternal,attachPolicy,attachUrl,refusedLog,diag,foreignLanes=[]){let best;let bestClass=Number.MAX_SAFE_INTEGER;let bestStartedAt=Number.NEGATIVE_INFINITY;for(const c of candidates){if(attachUrl&&normalizeOrigin(c.inst.origin)!==normalizeOrigin(attachUrl)){diag?.(`native-attach: skip ${c.inst.origin} (pid ${c.inst.pid}): not the explicit attachUrl target`);continue}let incompatible=instanceCompatible(c.inst,opts,codeFingerprint,foreignLanes);if(incompatible==="code-fingerprint-mismatch"&&c.health?.version!==void 0&&isNewerSameLaneHolder(c.inst,opts.lane,c.health.version,VERSION,isUserZoneInstance(c.inst))){const adoptedShape=instanceShapeMismatch(c.inst,opts,foreignLanes);if(adoptedShape===void 0){diag?.(`native-attach: adopt ${c.inst.origin} (pid ${c.inst.pid}): foreign bytes but self-reported v${c.health.version} is strictly NEWER than this lane's v${VERSION} \u2014 riding the newer build instead of deadlocking behind it (#4125)`);incompatible=void 0}else{diag?.(`native-attach: skip ${c.inst.origin} (pid ${c.inst.pid}): reports v${c.health.version} (newer) but its config shape differs (${adoptedShape}) \u2014 shape guards survive upward adoption (#4125)`);incompatible=adoptedShape}}if(incompatible!==void 0){diag?.(`native-attach: skip ${c.inst.origin} (pid ${c.inst.pid}): incompatible (${incompatible})`);continue}if(opts.strictPort&&c.inst.port!==opts.port){diag?.(`native-attach: skip ${c.inst.origin} (pid ${c.inst.pid}): port mismatch`);continue}const sameLane=opts.lane!==void 0&&c.inst.lane===opts.lane;if(!attachUrl&&!attachExternal&&attachPolicy==="own-lane"&&opts.lane!==void 0&&!sameLane&&c.health?.watchdog?.armed!==true){diag?.(`native-attach: skip ${c.inst.origin} (pid ${c.inst.pid}): not own lane and not an armed shared daemon (attachPolicy=own-lane)`);continue}if(c.health===void 0){if(!sameLane&&!attachExternal&&!isUserZoneInstance(c.inst)){if(!refusedLog.has(c.inst.origin)){refusedLog.add(c.inst.origin);const msg=`bili: refusing to attach to ${c.inst.origin} (pid ${c.inst.pid}) \u2014 health probe silent but TCP alive (BUSY, event loop saturated #3654) and its lifecycle is unverifiable from this lane. Starting a session-owned proxy instead; set native.attachExternal=true or BILI_NATIVE_ATTACH_EXTERNAL=1 to attach anyway.`;console.error(msg);diag?.(msg)}continue}}else if(!attachGateAllows(c.health,attachExternal)&&!isUserZoneInstance(c.inst)){if(!refusedLog.has(c.inst.origin)){refusedLog.add(c.inst.origin);console.error(gateRefusalMessage(c.inst,c.health));diag?.(gateRefusalMessage(c.inst,c.health))}continue}const cls=attachClass(c.inst,opts.lane,foreignLanes);if(cls<bestClass||cls===bestClass&&c.inst.startedAt>bestStartedAt){best=c.inst;bestClass=cls;bestStartedAt=c.inst.startedAt}}return best}async function waitForStarterInstance(readInstance,fetchHealthInfo,now,sleepImpl,opts,codeFingerprint,attachExternal,attachPolicy,attachUrl,refusedLog,diag,foreignLanes=[],isConnectable=tcpConnectable){const deadline=now()+SPAWN_BUDGET_MS;const probe=async()=>pickAttachable(await probeLiveInstances(readInstance,fetchHealthInfo,diag,isConnectable),opts,codeFingerprint,attachExternal,attachPolicy,attachUrl,refusedLog,diag,foreignLanes);let inst;while(now()<deadline){await sleepImpl(HEALTH_POLL_INTERVAL_MS);inst=await probe();if(inst)break;const still=readStartingMarker();if(!still||!isStartingMarkerActive(still,now()))break}return inst??await probe()}function defaultAttachDiag(debug){return msg=>{logHostEvent("info","",msg);if(debug)process.stderr.write(`${logTimestamp()} [info] [v=${VERSION}] ${msg}
136
136
  `)}}async function findLiveAttachableInstance(opts,deps={}){const fetchHealthInfo=deps.fetchHealthInfo??fetchHealthInfoDefault;const readInstance=deps.readInstanceFile??readProxyInstanceFile;const attachExternal=(deps.resolveAttachExternal??resolveNativeAttachExternal)();const attachPolicy=(deps.resolveAttachPolicy??resolveNativeAttachPolicy)();const attachUrl=(deps.resolveAttachUrl??resolveNativeAttachUrl)();const foreignLanes=(deps.attachLanePriority??resolveNativeAttachLanePriority)();const attachDiag=deps.attachDiag??defaultAttachDiag(opts.debug);const probed=await probeLiveInstances(readInstance,fetchHealthInfo,attachDiag,deps.isConnectable??tcpConnectable);return pickAttachable(probed,opts,entryScriptFingerprint(deps.scriptPath??process.argv[1]),attachExternal,attachPolicy,attachUrl,new Set,attachDiag,foreignLanes)}function pickEphemeralPort(host=LAUNCHER_DEFAULT_HOST){return new Promise((resolve,reject)=>{const srv=net3.createServer();srv.once("error",reject);srv.listen(0,host,()=>{const addr=srv.address();srv.close(()=>{if(addr&&typeof addr==="object")resolve(addr.port);else reject(new Error("could not allocate a free port"))})})})}var INHERITED_PROXY_VARS=["http_proxy","https_proxy","all_proxy","HTTP_PROXY","HTTPS_PROXY","ALL_PROXY","no_proxy","NO_PROXY"];var INTERNAL_LAUNCHER_CHANNEL_VARS=["BILI_LAUNCHER_LANE","BILI_LAUNCHER_MODEL_WINDOWS","BILI_LAUNCHER_MODEL_MAX_OUTPUTS","BILI_STRICT_PORT"];function stripInternalLauncherChannels(env){const cleaned={...env};for(const key of INTERNAL_LAUNCHER_CHANNEL_VARS)delete cleaned[key];return cleaned}function stripInheritedProxy(env){const cleaned={...env};for(const key of INHERITED_PROXY_VARS)delete cleaned[key];return stripInternalLauncherChannels(cleaned)}var INHERITED_LAUNCHER_CHANNELS=["BILI_LAUNCHER_LANE","BILI_LAUNCHER_MODEL_WINDOWS","BILI_LAUNCHER_MODEL_MAX_OUTPUTS","BILI_STRICT_PORT",SPAWN_FINGERPRINT_ENV];function stripInheritedLauncherChannels(env){const cleaned={...env};for(const key of INHERITED_LAUNCHER_CHANNELS)delete cleaned[key];return cleaned}function captureInheritedProxyEnv(env){const captured={};const pairs=[["BILI_INHERITED_HTTP_PROXY",env.HTTP_PROXY,env.http_proxy],["BILI_INHERITED_HTTPS_PROXY",env.HTTPS_PROXY,env.https_proxy],["BILI_INHERITED_ALL_PROXY",env.ALL_PROXY,env.all_proxy],["BILI_INHERITED_NO_PROXY",env.NO_PROXY,env.no_proxy]];for(const[name,upper,lower]of pairs){const value=(upper??lower??"").trim();if(value)captured[name]=value}return captured}function proxyStartArgs(opts){const args=["start","--host",opts.host,"--port",String(opts.port)];if(opts.passthrough)args.push("--passthrough");if(opts.debug)args.push("--debug");return args}function probeNodeWrapperTarget(candidate,env){try{const out=execFileSync5(candidate,["-p","process.execPath"],{windowsHide:true,timeout:5e3,encoding:"utf8",stdio:["ignore","pipe","pipe"],env});const p2=out.trim();return p2.length>0?p2:void 0}catch{return void 0}}function probeNodeMajor(candidate,env){try{const out=execFileSync5(candidate,["--version"],{windowsHide:true,timeout:5e3,encoding:"utf8",stdio:["ignore","pipe","pipe"],env});const m2=/^v(\d+)\.\d+\.\d+/.exec(out.trim());return m2?Number(m2[1]):void 0}catch{return void 0}}var MIN_PROXY_NODE_MAJOR=20;function looksLikeNodeExecutable(p2,platform){if(platform==="win32"){if(!/^[a-zA-Z]:[\\/]/.test(p2))return false}else if(!p2.startsWith("/")){return false}const base=p2.split(/[\\/]/).pop()?.toLowerCase()??"";return base==="node"||base==="node.exe"}function resolveNodeRuntime(execPath=process.execPath,env=process.env,platform=process.platform,existsImpl=fs15.existsSync,electronVersion=typeof process.versions.electron==="string"?process.versions.electron:void 0,probeWrapper=probeNodeWrapperTarget,probeNode=probeNodeMajor){const base=path27.basename(execPath).toLowerCase();if(base==="node"||base==="node.exe")return execPath;const override=typeof env.BILLION_CONTEXT_NODE==="string"?env.BILLION_CONTEXT_NODE.trim():"";if(override.length>0&&existsImpl(override))return override;const resolveDiscovered=candidate=>{let subject=candidate;if(platform==="win32"){const probed=probeWrapper(candidate,env);const target=probed?.trim();if(target&&target.length>0&&looksLikeNodeExecutable(target,platform)&&existsImpl(target)){if(target.toLowerCase()!==candidate.toLowerCase()){log("info",`bili: ${candidate} is a Windows node wrapper resolving to ${target} \u2014 spawning the real Node directly (#1887)`);subject=target}}}const major=probeNode(subject,env);if(major===void 0||major<MIN_PROXY_NODE_MAJOR)return void 0;return subject};const sep=platform==="win32"?";":":";const names=platform==="win32"?["node.exe"]:["node"];const home=platform==="win32"?env.USERPROFILE??"":env.HOME??"";const voltaHome=platform==="win32"?env.VOLTA_HOME??(home?home+"/Tools/volta":""):home?home+"/.volta":"";const extraDirs=platform==="win32"?["C:/Program Files/nodejs",env.LOCALAPPDATA?env.LOCALAPPDATA+"/Programs/nodejs":"",voltaHome?voltaHome+"/bin":""]:["/usr/local/bin","/opt/homebrew/bin","/opt/local/bin",voltaHome?voltaHome+"/bin":"",home?home+"/.local/bin":""];for(const dir of[...(env.PATH??"").split(sep),...extraDirs]){if(!dir)continue;for(const name of names){const candidate=dir.endsWith("/")||dir.endsWith("\\")?dir+name:dir+"/"+name;if(!existsImpl(candidate))continue;const resolved=resolveDiscovered(candidate);if(resolved!==void 0)return resolved;log("warn",`bili: skipping ${candidate} \u2014 not a usable Node runtime (--version did not report v${MIN_PROXY_NODE_MAJOR}+; set BILLION_CONTEXT_NODE if this is wrong, #3383)`)}}if(electronVersion&&electronVersion.length>0){log("warn",`bili: no usable Node runtime found on PATH or install dirs \u2014 falling back to the Electron host binary ${execPath} run as Node via ELECTRON_RUN_AS_NODE=1 (#1429/#3383)`);return execPath}throw new Error("bili: cannot find a Node runtime to spawn the proxy (this process is not Node) \u2014 set BILLION_CONTEXT_NODE")}var PORT_LOG_MAX_BYTES=5*1024*1024;function rotatePortLogIfNeeded(logPath2){try{if(fs15.statSync(logPath2).size<PORT_LOG_MAX_BYTES)return;try{fs15.unlinkSync(`${logPath2}.old`)}catch{}fs15.renameSync(logPath2,`${logPath2}.old`)}catch{}}var STALE_ROTATION_WAIT_MS=12e3;var SHUTDOWN_REQUEST_TIMEOUT_MS=3e3;var OWNER_HEARTBEAT_INTERVAL_MS=5e3;var OWNER_HEARTBEAT_POST_TIMEOUT_MS=2e3;async function requestInstanceShutdown(origin){try{const res=await fetch(`${origin}/__bili/shutdown`,{method:"POST",headers:{"content-type":"application/json",connection:"close"},body:"{}",signal:AbortSignal.timeout(SHUTDOWN_REQUEST_TIMEOUT_MS)});return res.ok}catch{return false}}async function rotateStalePredecessor(probed,resolveTargetPort,opts,attachUrl,foreignLanes,fetchHealthInfoNoReuse,now,sleep,requestShutdown){if(attachUrl!==void 0)return;const stale=probed.filter(c=>c.health!==void 0&&!isUserZoneInstance(c.inst)&&c.health.watchdog?.armed===true&&instanceShapeMismatch(c.inst,opts,foreignLanes)===void 0&&c.health.version!==void 0&&isVersionNewer(VERSION,c.health.version));if(stale.length===0)return;const targetPort=resolveTargetPort();if(targetPort===void 0)return;const candidate=stale.find(c=>c.inst.port===targetPort);if(!candidate)return;const running=candidate.health.version;if(running===void 0||!isVersionNewer(VERSION,running))return;console.error(`bili: rotating stale proxy ${candidate.inst.origin} (pid ${candidate.inst.pid}, running v${running}) \u2014 ours is v${VERSION}; requesting graceful shutdown before taking over port ${targetPort}`);const asked=await requestShutdown(candidate.inst.origin);if(!asked){console.error(`bili: stale rotation skipped \u2014 ${candidate.inst.origin} refused /__bili/shutdown (older build); falling back to the normal spawn ladder`);return}const deadline=now()+STALE_ROTATION_WAIT_MS;for(;;){const h=await fetchHealthInfoNoReuse(candidate.inst.origin);if(!h?.ok)break;if(now()>=deadline){console.error(`bili: stale rotation timed out after ${STALE_ROTATION_WAIT_MS}ms \u2014 ${candidate.inst.origin} still accepts fresh connections (listener open); falling back to the normal spawn ladder`);return}await sleep(HEALTH_POLL_INTERVAL_MS)}}function startOwnerHeartbeat(origin,pid,intervalMs=OWNER_HEARTBEAT_INTERVAL_MS,post){if(pid!==process.pid)return void 0;if(post!==void 0)return runOwnerHeartbeatLoop(post,pid,intervalMs);return runOwnerHeartbeatWorker(origin,pid,intervalMs)}var ownerHeartbeatWorkers=new Map;function runOwnerHeartbeatLoop(post,pid,intervalMs){let stopped=false;const beat=async()=>{while(!stopped){await new Promise(r=>{const t=setTimeout(r,intervalMs);t.unref?.()});if(stopped)return;try{await post(JSON.stringify({pid,hb:true}))}catch{}}};void beat();return()=>{stopped=true}}var OWNER_HEARTBEAT_WORKER_SOURCE=`
137
137
  const { parentPort, workerData } = require("node:worker_threads");
138
138
  const { origin, pid, intervalMs, timeoutMs } = workerData;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "billion-context",
3
- "version": "0.1.210",
3
+ "version": "0.1.211",
4
4
  "description": "A context-compression plugin \u2014 small context windows (a 100K context is enough), 5x fewer tokens, month-long single sessions (billions of tokens), and compression quality \u2014 for all agents: pi, OpenCode, Codex, Claude Code, and more. billion-context is all you need.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -0,0 +1,13 @@
1
+ ---
2
+ title: "What to do when billion-context compresses frequently?"
3
+ title_zh: "billion-context频繁压缩该怎么办?"
4
+ date: 2026-11-01
5
+ excerpt: "Is it broken?"
6
+ excerpt_zh: "是不是坏了"
7
+ ---
8
+
9
+ A few cases to tell apart:
10
+
11
+ 1. Unlike traditional compression software, billion-context only does incremental compression, never whole-context (global) compression. So seeing it compress more often than a classic tool is normal.
12
+ 2. In some cases it will still compress frequently: if a compression happens every three or five calls, the model is most likely reading huge amounts of logs, code, etc., which trips the incremental threshold. If you have many such scenarios, raising `nudge` (default 50k) to 80k–100k improves things noticeably.
13
+ 3. If none of the above applies, it's probably a bug — report it at [github.com/ranxianglei/billion-context/issues](https://github.com/ranxianglei/billion-context/issues), with your log attached if possible. Usually resolved within the week.
@@ -0,0 +1,12 @@
1
+ ---
2
+ title: "billion-context频繁压缩该怎么办?"
3
+ date: 2026-11-01
4
+ excerpt: "是不是坏了"
5
+ excerpt_zh: "是不是坏了"
6
+ ---
7
+
8
+ 区分几种情况:
9
+
10
+ 1. 区别于传统压缩软件,billion-context 只做增量压缩不做全局压缩。所以看到的压缩比传统更频繁很正常。
11
+ 2. 有一些情况下,还是会频繁压缩:如果三五个调用就压缩一次,大概率模型在疯狂读入日志、代码等,触发了增量阈值。如果有大量类似场景,建议调大 `nudge`(默认 5w),调大到 8w 到 10w 可以明显改善。
12
+ 3. 如果以上都不是,那么可能是遇到了 bug,请到 [github.com/ranxianglei/billion-context/issues](https://github.com/ranxianglei/billion-context/issues) 报告,最好带上日志,一般会周内解决。