billion-context 0.1.181 → 0.1.182
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.
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2567,9 +2567,9 @@ pre.tool-args, pre.tool-out { margin: 6px 0 0; padding: 8px; background: var(--b
|
|
|
2567
2567
|
</main>
|
|
2568
2568
|
<div id="toast-host" class="toast-host"></div>
|
|
2569
2569
|
<script>${WEB_CLIENT}</script>
|
|
2570
|
-
</body></html>`}import{closeSync,existsSync as existsSync5,fsyncSync,mkdirSync as mkdirSync6,openSync,readFileSync as readFileSync5,renameSync as renameSync3,unlinkSync as unlinkSync3,writeFileSync as writeFileSync5}from"fs";import{dirname as dirname5}from"path";import{randomUUID as randomUUID4}from"crypto";function readConfig(){const parsed=safeReadJson(configFile());return parsed&&typeof parsed==="object"&&!Array.isArray(parsed)?parsed:{}}function configParseError(){if(!existsSync5(configFile()))return null;const parsed=safeReadJson(configFile());if(parsed&&typeof parsed==="object"&&!Array.isArray(parsed))return null;return`config file is not valid JSON: ${configFile()}`}function readProviders(){const providers=readConfig().providers;return providers&&typeof providers==="object"&&!Array.isArray(providers)?providers:{}}function readUpstreamSettings(){const config=readConfig();const proxy=typeof config.upstreamProxy==="string"&&config.upstreamProxy.trim()?config.upstreamProxy.trim():void 0;return{mode:parseUpstreamProxyMode(config.upstreamProxyMode??(proxy?"manual":void 0)),...proxy?{proxy}:{}}}function atomicWriteConfig(config){const filePath=configFile();mkdirSync6(dirname5(filePath),{recursive:true});const tempPath=`${filePath}.${process.pid}.${randomUUID4()}.tmp`;let descriptor;try{descriptor=openSync(tempPath,"wx",384);writeFileSync5(descriptor,JSON.stringify(config,null,2)+"\n","utf8");fsyncSync(descriptor);closeSync(descriptor);descriptor=void 0;renameSync3(tempPath,filePath)}catch(error){if(descriptor!==void 0)closeSync(descriptor);try{unlinkSync3(tempPath)}catch{}throw error}}async function handleConfigGet(res){const upstream=readUpstreamSettings();const config=readConfig();const parseError=configParseError();if(parseError)log("warn",`[acp-web] ${parseError} \u2014 showing empty view; PUT is blocked until fixed`);res.writeHead(200,{"content-type":"application/json"});res.end(JSON.stringify({path:configFile(),providers:readProviders(),upstreamProxy:upstream.proxy??null,upstreamProxyMode:upstream.mode,compress:config.compress??null,passthrough:passthroughState(process.env),...existsSync5(configFile())?{raw:readFileSync5(configFile(),"utf8")}:{},...parseError?{parseError}:{}},null,2))}async function handleConfigPut(req,res,onChanged,biliPort=8787){const raw=await readJsonBody(req);if(!raw||typeof raw!=="object"||Array.isArray(raw))return sendError(res,400,"expected JSON object");const parseError=configParseError();if(parseError)return sendError(res,409,`${parseError} \u2014 fix the syntax error by hand, then retry; refusing to overwrite`);const body=raw;const hasProviders=Object.prototype.hasOwnProperty.call(body,"providers");const hasProxy=Object.prototype.hasOwnProperty.call(body,"upstreamProxy");const hasMode=Object.prototype.hasOwnProperty.call(body,"upstreamProxyMode");const hasCompress=Object.prototype.hasOwnProperty.call(body,"compress");const hasPassthrough=Object.prototype.hasOwnProperty.call(body,"passthrough");const hasFile=Object.prototype.hasOwnProperty.call(body,"file");if(!hasProviders&&!hasProxy&&!hasMode&&!hasCompress&&!hasPassthrough&&!hasFile)return sendError(res,400,"expected providers, upstream proxy, compress, passthrough settings, or the full config file");if(hasFile){if(typeof body.file!=="string")return sendError(res,400,"file must be a string (raw config JSON text)");let next;try{const p2=JSON.parse(body.file);if(!p2||typeof p2!=="object"||Array.isArray(p2))throw new Error("top level must be a JSON object");next=p2}catch(error){return sendError(res,400,`file is not valid JSON: ${String(error)}`)}if(next.providers!==void 0){if(typeof next.providers!=="object"||Array.isArray(next.providers))return sendError(res,400,"providers must be an object");for(const[url,value]of Object.entries(next.providers)){const route=parseRouteEntry(value);if(!url||!route)return sendError(res,400,`invalid provider entry: ${url||"(empty)"}`);try{validateHttpProxy(route.proxy,biliPort)}catch(error){return sendError(res,400,`invalid provider proxy for ${url}: ${String(error)}`)}}}if(next.upstreamProxy!==void 0){if(next.upstreamProxy!==null&&typeof next.upstreamProxy!=="string")return sendError(res,400,"upstreamProxy must be a string or null");try{validateHttpProxy(typeof next.upstreamProxy==="string"?next.upstreamProxy.trim()||void 0:void 0,biliPort)}catch(error){return sendError(res,400,String(error))}}if(next.upstreamProxyMode!==void 0&&(typeof next.upstreamProxyMode!=="string"||!["auto","manual","direct"].includes(next.upstreamProxyMode)))return sendError(res,400,"upstreamProxyMode must be auto, manual, or direct");if(next.compress!==void 0&&next.compress!==null&&parseCompressSettings(next.compress)===void 0)return sendError(res,400,"invalid compress settings");if(next.passthrough!==void 0&&next.passthrough!==null&&typeof next.passthrough!=="boolean")return sendError(res,400,"passthrough must be a boolean or null");if(next.passthrough===true&&passthroughState(process.env).source==="env")return sendError(res,409,"passthrough is forced by the ACP_PASSTHROUGH environment variable (or --passthrough flag); unset it and restart to change here");try{atomicWriteConfig(next);onChanged?.()}catch(error){return sendError(res,500,`failed to apply config: ${String(error)}`)}res.writeHead(200,{"content-type":"application/json"});res.end(JSON.stringify({ok:true,applied:["config file"]},null,2));return}let rawProviders;if(hasProviders){if(!body.providers||typeof body.providers!=="object"||Array.isArray(body.providers)){return sendError(res,400,"providers must be an object")}rawProviders={};for(const[url,value]of Object.entries(body.providers)){try{rejectLegacyRoute(url,value)}catch(error){return sendError(res,400,String(error))}const route=parseRouteEntry(value);if(!url||!route)return sendError(res,400,`invalid provider entry: ${url||"(empty)"}`);try{validateHttpProxy(route.proxy,biliPort)}catch(error){return sendError(res,400,`invalid provider proxy for ${url}: ${String(error)}`)}rawProviders[url]=value}}let proxy;if(hasProxy){if(body.upstreamProxy!==null&&typeof body.upstreamProxy!=="string"){return sendError(res,400,"upstreamProxy must be a string or null")}proxy=typeof body.upstreamProxy==="string"?body.upstreamProxy.trim()||void 0:void 0;try{validateHttpProxy(proxy,biliPort)}catch(error){return sendError(res,400,String(error))}}let mode;if(hasMode){if(typeof body.upstreamProxyMode!=="string"||!["auto","manual","direct"].includes(body.upstreamProxyMode)){return sendError(res,400,"upstreamProxyMode must be auto, manual, or direct")}mode=parseUpstreamProxyMode(body.upstreamProxyMode)}if(mode==="manual"&&!proxy&&!readUpstreamSettings().proxy){return sendError(res,400,"manual mode requires an upstream proxy URL")}let compress;if(hasCompress){compress=body.compress===null?{}:parseCompressSettings(body.compress);if(compress===void 0)return sendError(res,400,"invalid compress settings")}if(hasPassthrough){if(body.passthrough!==null&&typeof body.passthrough!=="boolean"){return sendError(res,400,"passthrough must be a boolean or null")}if(passthroughState(process.env).source==="env"){return sendError(res,409,"passthrough is forced by the ACP_PASSTHROUGH environment variable (or --passthrough flag); unset it and restart to change here")}}const config=readConfig();if(hasProviders)config.providers=rawProviders;if(hasProxy){if(proxy)config.upstreamProxy=proxy;else delete config.upstreamProxy}if(hasMode&&mode)config.upstreamProxyMode=mode;if(hasCompress){if(compress&&Object.keys(compress).length>0)config.compress=compress;else delete config.compress}if(hasPassthrough){if(body.passthrough===true)config.passthrough=true;else delete config.passthrough}try{atomicWriteConfig(config);onChanged?.()}catch(error){return sendError(res,500,`failed to apply config: ${String(error)}`)}const changed=[];if(hasProviders)changed.push(`${Object.keys(rawProviders??{}).length} routes`);if(hasProxy||hasMode)changed.push("network");if(hasCompress)changed.push("compress");if(hasPassthrough)changed.push("passthrough");log("info",`[acp-web] configuration updated (${changed.join(", ")||"none"})`);res.writeHead(200,{"content-type":"application/json"});res.end(JSON.stringify({ok:true,providers:hasProviders&&rawProviders?Object.keys(rawProviders).length:void 0}))}function sendError(res,status,message){res.writeHead(status,{"content-type":"application/json"});res.end(JSON.stringify({error:message}))}function readJsonBody(req){return new Promise(resolve=>{const chunks=[];let size=0;req.on("data",chunk=>{size+=chunk.length;if(size>256*1024){req.destroy();resolve(void 0);return}chunks.push(chunk)});req.on("end",()=>{try{resolve(JSON.parse(Buffer.concat(chunks).toString("utf8")))}catch{resolve(void 0)}});req.on("error",()=>resolve(void 0))})}import{mkdirSync as mkdirSync7,writeFileSync as writeFileSync6}from"fs";import path18 from"path";function fmtDate(ms2){return ms2?new Date(ms2).toISOString().replace("T"," ").slice(0,19)+" UTC":"\u2014"}async function listSessions2(opts={}){const store=new SessionStore({dir:opts.dir,enabled:true});const sessions2=[...(await store.loadAll()).values()];sessions2.sort((a,b2)=>latestBlockTime(b2)-latestBlockTime(a));return sessions2.map(s3=>({id:s3.id,title:s3.meta.title,label:s3.meta.label,protocol:s3.meta.protocol,upstreamOrigin:s3.meta.upstreamOrigin,savedAt:latestBlockTime(s3)||void 0,contextTokens:s3.stats.contextTokens,blocks:s3.state.blocks.length}))}function latestBlockTime(s3){let latest=0;for(const b2 of s3.state.blocks)if(b2.createdAt>latest)latest=b2.createdAt;return latest}function renderHandoff2(s3,full){const messages=s3.lastMessages;if(messages&&messages.length>0){const folded=s3.lastMessagesFolded===true;const base=renderHandoff({coreMessages:messages,state:s3.state,full,folded,meta:{title:s3.meta.title,label:s3.meta.label,sessionId:s3.id,contextTokens:s3.stats.contextTokens,extraBullets:[...s3.meta.protocol?[`- protocol: ${s3.meta.protocol}`]:[],...s3.meta.upstreamOrigin?[`- upstream: ${s3.meta.upstreamOrigin}`]:[],`- requests: ${s3.stats.requests}`]}});return base+blockSummariesSection(s3,full&&folded,base)}const lines=[];lines.push(`# billion-context session handoff`);lines.push("");lines.push(`- title: ${s3.meta.title??"(untitled)"}`);if(s3.meta.label)lines.push(`- label: ${s3.meta.label}`);lines.push(`- session id: ${s3.id}`);if(s3.meta.protocol)lines.push(`- protocol: ${s3.meta.protocol}`);if(s3.meta.upstreamOrigin)lines.push(`- upstream: ${s3.meta.upstreamOrigin}`);lines.push(`- requests: ${s3.stats.requests}`);if(s3.stats.contextTokens)lines.push(`- last context tokens: ~${s3.stats.contextTokens}`);lines.push(`- compression blocks: ${s3.state.blocks.length} (active ${s3.state.blocks.filter(b2=>b2.active).length})`);lines.push("");const active=s3.state.blocks.filter(b2=>b2.active);if(active.length===0){lines.push("No active compression blocks and no persisted conversation snapshot (v2 session file). Original messages are only persisted when they are compressed into a block, so this session's conversation content is not available for export.");lines.push("")}for(const b2 of active){lines.push(`## Block ${b2.blockId}${b2.topic?` \u2014 ${b2.topic}`:""}`);lines.push("");lines.push(`tier ${b2.tier} \xB7 ~${b2.compressedTokens} tokens compressed \xB7 ${fmtDate(b2.createdAt)}`);lines.push("");lines.push(b2.summary.trim());lines.push("");const content=s3.blockContents.get(b2.blockId);if(full&&content){lines.push(`### Original messages (${content.full.count})`);lines.push("");lines.push(content.full.text.trim());lines.push("")}}if(active.length>0){lines.push("---");lines.push("");lines.push("Paste the block summaries above into a new session to continue without the proxy.");lines.push("")}return lines.join("\n")}function blockSummariesSection(s3,includeOriginals,priorDoc){const active=s3.state.blocks.filter(b2=>b2.active);if(active.length===0)return"";const lines=[];lines.push(`## Compressed block summaries`);lines.push("");for(const b2 of active){lines.push(`### Block ${b2.blockId}${b2.topic?` \u2014 ${b2.topic}`:""}`);lines.push("");lines.push(`tier ${b2.tier} \xB7 ~${b2.compressedTokens} tokens compressed \xB7 ${fmtDate(b2.createdAt)}`);lines.push("");const summary=b2.summary.trim();if(summary===""){lines.push("_no summary recorded_")}else if(priorDoc.includes(summary)){lines.push("_summary already shown in the conversation view above_")}else{lines.push(summary)}lines.push("");const content=includeOriginals?s3.blockContents.get(b2.blockId):void 0;if(content){lines.push(`#### Original messages (${content.full.count})`);lines.push("");lines.push(content.full.text.trim());lines.push("")}}return lines.join("\n")}function matchSession2(sessions2,selector){return matchSession(sessions2,selector,s3=>s3.meta.label)}async function exportSession(selector,opts={}){const store=new SessionStore({dir:opts.dir,enabled:true});const all=[...(await store.loadAll()).values()];if(all.length===0){return"No persisted sessions found. Sessions are written under the sessions directory once the proxy has served a request (compression state, compressed originals, and a bounded folded-view snapshot of the recent conversation)."}if(!selector){const list=await listSessions2(opts);const rows=list.map(s3=>`${s3.id}${s3.label?` label=${s3.label}`:""}${s3.protocol?` [${s3.protocol}]`:""} blocks=${s3.blocks}${s3.contextTokens?` ctx~${s3.contextTokens}`:""} ${s3.title??""}`);return["Persisted sessions:","",...rows.map(r=>` ${r}`),"","Usage: bili export <session-id|label> [--output handoff.md] [--full]"].join("\n")}const matches=matchSession2(all,selector);if(matches.length===0){throw new Error(`no session matches "${selector}" (run "bili export" to list sessions)`)}if(matches.length>1){const ids=matches.map(s3=>s3.id).join(", ");throw new Error(`selector "${selector}" matches ${matches.length} sessions (${ids}); use the full session id`)}const markdown=renderHandoff2(matches[0],opts.full??false);if(opts.output){mkdirSync7(path18.dirname(path18.resolve(opts.output)),{recursive:true});writeFileSync6(opts.output,markdown,"utf8");return`written to ${opts.output}`}return markdown}function escapeHtml2(s3){return s3.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function inlineMd(s3){let out=escapeHtml2(s3);out=out.replace(/`([^`]+)`/g,(_m,code)=>`<code>${code}</code>`);out=out.replace(/\*\*([^*]+)\*\*/g,"<strong>$1</strong>");out=out.replace(/(^|[^*])\*([^*\n]+)\*/g,"$1<em>$2</em>");out=out.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g,(_m,text,url)=>{if(/^(https?:\/\/|\/)/i.test(url))return`<a href="${url}" target="_blank" rel="noopener noreferrer">${text}</a>`;return text});return out}function markdownToHtml(md){const lines=md.split("\n");const html=[];let i=0;while(i<lines.length){const line=lines[i];if(line.startsWith("```")){const buf=[];i+=1;while(i<lines.length&&!lines[i].startsWith("```")){buf.push(lines[i]);i+=1}i+=1;html.push(`<pre><code>${escapeHtml2(buf.join("\n"))}</code></pre>`);continue}const h=line.match(/^(#{1,6})\s+(.*)$/);if(h){const level=h[1].length;const inner=h[2].trim();const role=level===3&&/^(user|assistant|tool)$/i.test(inner)?inner.toLowerCase():null;html.push(role?`<h3 class="msg-role ${role}">${inlineMd(inner)}</h3>`:`<h${level}>${inlineMd(h[2])}</h${level}>`);i+=1;continue}if(/^\s*(---+|\*\*\*+)\s*$/.test(line)){html.push("<hr/>");i+=1;continue}if(/^\s{2,}\S/.test(line)){const buf=[];let indent=Infinity;while(i<lines.length&&/^\s{2,}\S/.test(lines[i])){buf.push(lines[i]);const m2=lines[i].match(/^\s*/);if(m2&&m2[0].length<indent)indent=m2[0].length;i+=1}const cut=Math.min(indent,4);html.push(`<pre><code>${escapeHtml2(buf.map(l=>l.slice(cut)).join("\n"))}</code></pre>`);continue}if(/^\s*>\s?/.test(line)||/^\s*>\s?/.test(line)){const buf=[];while(i<lines.length&&/^\s*>\s?/.test(lines[i])){buf.push(lines[i].replace(/^\s*>\s?/,""));i+=1}html.push(`<blockquote><p>${inlineMd(buf.join(" "))}</p></blockquote>`);continue}if(/^\s*[-*]\s+/.test(line)){const items=[];while(i<lines.length&&/^\s*[-*]\s+/.test(lines[i])){items.push(`<li>${inlineMd(lines[i].replace(/^\s*[-*]\s+/,""))}</li>`);i+=1}html.push(`<ul>${items.join("")}</ul>`);continue}if(/^\s*\d+[.)]\s+/.test(line)){const items=[];while(i<lines.length&&/^\s*\d+[.)]\s+/.test(lines[i])){items.push(`<li>${inlineMd(lines[i].replace(/^\s*\d+[.)]\s+/,""))}</li>`);i+=1}html.push(`<ol>${items.join("")}</ol>`);continue}if(line.trim()===""){i+=1;continue}const para=[line];i+=1;while(i<lines.length&&lines[i].trim()!==""&&!/^(#{1,6}\s|```|\s*[-*]\s|\s*\d+[.)]\s|\s*>)/.test(lines[i])){para.push(lines[i]);i+=1}html.push(`<p>${para.map(inlineMd).join("<br/>")}</p>`)}return html.join("\n")}var DISK_TTL_MS=5e3;var diskStore=null;function getDiskStore(){if(!diskStore)diskStore=new SessionStore({enabled:true});return diskStore}var diskMemo=null;var diskScan=null;function loadDiskSessions(){if(diskMemo&&Date.now()-diskMemo.at<DISK_TTL_MS)return Promise.resolve(diskMemo.map);if(!diskScan){const run=(async()=>{try{const map=await getDiskStore().loadAll();diskMemo={at:Date.now(),map};return map}catch(error){log("warn",`[acp-web] session disk scan failed: ${String(error)}`);return diskMemo?.map??new Map}})();diskScan=run.finally(()=>{diskScan=null})}return diskScan}function hitPct(input,cached){return input>0?Math.round(cached/input*100):null}function summaryOf(s3,live){const led=s3.metadata["cacheLedger"];const agg=led;const requests=Math.max(s3.stats.requests??0,agg?.agg?.requests??0);const inputTokens=Math.max(s3.stats.inputTokens??0,agg?.agg?.input??0);const cachedTokens=Math.max(s3.stats.cachedTokens??0,agg?.agg?.cached??0);const outputTokens=Math.max(s3.stats.outputTokens??0,agg?.agg?.output??0);const hasLedger=Boolean(agg?.agg&&(agg.agg.requests??0)>0);let hasFolds=false,grossSaved=0,netSaved=0,repayCost=0,summaryCost=0,foldCount=0;for(const f2 of led?.folds??[]){hasFolds=true;foldCount+=1;const S2=f2.S??0,sig=f2.sigma??0,rep=f2.T??0,ra=f2.requestsAfter??0;const avoided=(S2-sig)*ra;grossSaved+=avoided;netSaved+=avoided-rep-sig;repayCost+=rep;summaryCost+=sig}let firstBlockHint="";const fb=s3.state.blocks.find(b2=>b2.topic||b2.summary);if(fb&&(fb.topic||fb.summary)){firstBlockHint=String(fb.topic||fb.summary).replace(/\s+/g," ").trim();if(firstBlockHint.length>48)firstBlockHint=firstBlockHint.slice(0,48)+"\u2026"}const metaRec=s3.metadata;const clientHint=typeof metaRec["pluginAgent"]==="string"&&metaRec["pluginAgent"]?metaRec["pluginAgent"]:typeof metaRec["clientHint"]==="string"&&metaRec["clientHint"]?metaRec["clientHint"]:"";return{id:s3.id,...s3.meta.title?{title:s3.meta.title}:{},...s3.meta.label&&s3.meta.label!==s3.id?{label:s3.meta.label}:{},...s3.meta.protocol?{protocol:s3.meta.protocol}:{},...s3.meta.upstreamOrigin?{upstreamOrigin:s3.meta.upstreamOrigin}:{},live,requests,contextTokens:s3.stats.contextTokens,...s3.stats.contextTokensSource?{contextTokensSource:s3.stats.contextTokensSource}:{},tokensSaved:s3.stats.tokensSaved,inputTokens,cachedTokens,outputTokens,cacheHitPct:hitPct(inputTokens,cachedTokens),blocks:s3.state.blocks.length,...typeof s3.metadata.effectiveContextLimit==="number"?{contextWindow:s3.metadata.effectiveContextLimit}:{},lastSeen:new Date(s3.lastSeen).toISOString(),...s3.restored?{restored:true}:{},...hasLedger?{hasLedger:true}:{},...firstBlockHint?{firstBlockHint}:{},...hasFolds?{grossSaved,netSaved,repayCost,summaryCost,foldCount}:{},...hasLedger?{newContent:agg?.agg?.nc??0,compRepay:agg?.agg?.cr??0,ttlRepay:agg?.agg?.tr??0}:{},...typeof agg?.agg?.input==="number"&&agg.agg.input>0?{missDropNew:Math.round((agg.agg.nc??0)/agg.agg.input*1e3)/10,missDropComp:Math.round((agg.agg.cr??0)/agg.agg.input*1e3)/10,missDropTtl:Math.round((agg.agg.tr??0)/agg.agg.input*1e3)/10}:{},...typeof agg?.agg?.switches==="number"&&agg.agg.switches>0?{modelSwitches:agg.agg.switches,switchMissedTokens:agg?.agg?.switchMissed??0}:{},...clientHint?{clientHint}:{}}}function isEmptyStub(s3){return(s3.requests??0)<=1&&(s3.contextTokens??0)===0&&(s3.blocks??0)===0&&!s3.hasLedger}var lastHiddenEmpty=0;function hiddenEmptyCount(){return lastHiddenEmpty}async function allSummaries(){const disk=await loadDiskSessions();const out=new Map;for(const[id,s3]of disk)out.set(id,summaryOf(s3,false));for(const s3 of listSessions())out.set(s3.id,summaryOf(s3,true));return[...out.values()].sort((a,b2)=>b2.lastSeen.localeCompare(a.lastSeen))}async function buildSessionList(){const all=await allSummaries();const vis=all.filter(s3=>!isEmptyStub(s3));lastHiddenEmpty=all.length-vis.length;return vis}async function buildOverview(){const allAll=await allSummaries();const all=allAll.filter(s3=>!isEmptyStub(s3));let requests=0,input=0,cached=0,output=0,saved=0,savedEstimated=0,blocks=0,live=0;let grossSavedTotal=0,netSavedTotal=0,repayTotal=0,summaryCostTotal=0,hasFoldData=false;let missNewTotal=0,missCompTotal=0,missTtlTotal=0,missInputTotal=0;const protoMap=new Map;for(const s3 of all){requests+=s3.requests;input+=s3.inputTokens;cached+=s3.cachedTokens;output+=s3.outputTokens;saved+=s3.tokensSaved;blocks+=s3.blocks;if(s3.live&&!s3.restored)live+=1;const key2=s3.protocol??"unknown";const row=protoMap.get(key2)??{protocol:key2,sessions:0,requests:0,inputTokens:0,cachedTokens:0,savedNet:0,folds:0,missNew:0,missComp:0,missTtl:0,missInput:0};row.sessions+=1;row.requests+=s3.requests;row.inputTokens+=s3.inputTokens;row.cachedTokens+=s3.cachedTokens;row.savedNet+=s3.hasLedger?s3.netSaved??0:s3.tokensSaved;row.folds+=s3.foldCount??0;protoMap.set(key2,row);if(s3.tokensSaved>0&&!s3.hasLedger)savedEstimated+=s3.tokensSaved;if(s3.hasLedger){missNewTotal+=s3.newContent??0;missCompTotal+=s3.compRepay??0;missTtlTotal+=s3.ttlRepay??0;missInputTotal+=s3.inputTokens;row.missNew+=s3.newContent??0;row.missComp+=s3.compRepay??0;row.missTtl+=s3.ttlRepay??0;row.missInput+=s3.inputTokens}if(s3.hasLedger&&s3.grossSaved!=null){hasFoldData=true;grossSavedTotal+=s3.grossSaved;netSavedTotal+=s3.netSaved??0;repayTotal+=s3.repayCost??0;summaryCostTotal+=s3.summaryCost??0}else if(s3.tokensSaved>0){grossSavedTotal+=s3.tokensSaved}}return{sessions:all.length,live,requests,inputTokens:input,cachedTokens:cached,outputTokens:output,tokensSaved:saved,savedEstimated,grossSavedTotal,netSavedTotal,hasFoldData,repayTotal,summaryCostTotal,missNewTotal,missCompTotal,missTtlTotal,missInputTotal,hitPct:hitPct(input,cached),blocks,byProtocol:[...protoMap.values()].map(r=>{const base=r.missInput||0;const drop=v2=>Math.round(v2/base*1e3)/10;return{protocol:r.protocol,sessions:r.sessions,requests:r.requests,inputTokens:r.inputTokens,cachedTokens:r.cachedTokens,savedNet:r.savedNet,folds:r.folds,hitPct:hitPct(r.inputTokens,r.cachedTokens),...base>0?{missDropNew:drop(r.missNew),missDropComp:drop(r.missComp),missDropTtl:drop(r.missTtl)}:{}}}),recent:all.slice(0,8),hiddenEmpty:allAll.length-all.length}}async function buildSessionDetail(id){const live=listSessions().find(s3=>s3.id===id);let session=live;if(!session){const disk=await loadDiskSessions();session=disk.get(id)}if(!session)return null;let handoffMd="";try{handoffMd=renderHandoff2(session,false)}catch(error){log("warn",`[acp-web] handoff render failed for ${id}: ${String(error)}`)}let handoffTruncated=false;if(handoffMd.length>15e5){handoffMd=handoffMd.slice(0,15e5)+"\n\n\u2026\uFF08\u5185\u5BB9\u8FC7\u957F\u5DF2\u622A\u65AD\uFF0C\u4F7F\u7528 `bili export` \u67E5\u770B\u5B8C\u6574\u4F1A\u8BDD\uFF09\n";handoffTruncated=true}const pluginAgent=typeof session.metadata["pluginAgent"]==="string"?session.metadata["pluginAgent"]:void 0;const clientHint=pluginAgent??(typeof session.metadata["clientHint"]==="string"?session.metadata["clientHint"]:void 0);const sysPrompt=typeof session.metadata["systemPromptTokens"]==="number"?session.metadata["systemPromptTokens"]:0;return{...summaryOf(session,!!live),lastInputTokens:session.stats.lastInputTokens,compressCreditTokens:session.stats.compressCreditTokens,retrieveCalls:session.stats.retrieveCalls,retrieveHits:session.stats.retrieveHits,retrieveMisses:session.stats.retrieveMisses,storedBytes:session.stats.storedBytes,storeBytesSaved:session.stats.storeBytesSaved,...session.meta.activePack?{activePack:session.meta.activePack}:{},...clientHint?{clientHint}:{},...typeof session.metadata["biliVersion"]==="string"?{biliVersion:session.metadata["biliVersion"]}:{},...sysPrompt>0?{systemPromptTokens:sysPrompt}:{},ledger:buildSessionCacheReport(session),handoffMd,handoffHtml:markdownToHtml(handoffMd),handoffTruncated,blockDetails:session.state.blocks.map(b2=>({blockId:b2.blockId,tier:b2.tier,...b2.topic!==void 0?{topic:b2.topic}:{},summary:b2.summary,compressedTokens:b2.compressedTokens,createdAt:b2.createdAt,...b2.startRef!==void 0?{startRef:b2.startRef}:{},...b2.endRef!==void 0?{endRef:b2.endRef}:{},active:b2.active}))}}function renderUI(origin){return renderPage(origin,VERSION)}var ORPHAN_THRESHOLD=3;var orphanStreaks=new WeakMap;function reapOrphanBlocks(session,visible,deactivate){if(session.state.blocks.length===0)return{reaped:[]};const presentIds=new Set(visible.map(m2=>m2.id));const reaped=[];for(const block of session.state.blocks){if(!block.active)continue;const hasHit=block.effectiveMessageIds.some(id=>presentIds.has(id));if(hasHit){orphanStreaks.delete(block);continue}const streak=(orphanStreaks.get(block)??0)+1;orphanStreaks.set(block,streak);if(streak>=ORPHAN_THRESHOLD){reaped.push(block.blockId)}}if(reaped.length===0)return{reaped:[]};session.state=deactivate(session.state,reaped);for(const id of reaped)session.blockContents.delete(id);return{reaped}}import fs8 from"fs";import path20 from"path";import path19 from"path";import{fileURLToPath as fileURLToPath3}from"url";var OMP_FIRST_EVENT_TIMEOUT_ENV="PI_OPENAI_STREAM_FIRST_EVENT_TIMEOUT_MS";var OMP_FIRST_EVENT_TIMEOUT_DEFAULT_MS=18e5;function ompFirstEventTimeoutValue(env){const raw=env[OMP_FIRST_EVENT_TIMEOUT_ENV];if(raw!==void 0&&raw.trim().length>0)return void 0;return String(OMP_FIRST_EVENT_TIMEOUT_DEFAULT_MS)}function applyOmpFirstEventTimeout(env){const value=ompFirstEventTimeoutValue(env);if(value!==void 0)env[OMP_FIRST_EVENT_TIMEOUT_ENV]=value}function isLegacyBcpEntry(entry){const e=entry.trim();const bare=e.replace(/^npm:/,"");return bare==="billion-context-pi"||/^billion-context-pi@/.test(bare)||/(^|[/\\])billion-context-pi([/\\]|$)/.test(e)}function isDesignAbsorbed(finding,pluginAgent){return finding.client==="opencode"&&finding.knownId==="opencode-acp"&&pluginAgent==="opencode"}var SCAN_CACHE_TTL_MS=5*60*1e3;var KEYWORD_RE=/\b(compress\w*|compact\w*|acp|summar\w*)\b/i;var cache4=new Map;function conflictScanEnabled(env=process.env){const v2=env.BILI_CONFLICT_SCAN?.trim().toLowerCase();return!(v2==="0"||v2==="false")}function sniffScanClient(headers){const h=name=>{const v2=headers[name];return Array.isArray(v2)?v2[0]:typeof v2==="string"?v2:void 0};if(h("x-claude-code-session-id"))return"claude";const ua=h("user-agent");if(ua&&isCodexClient({"user-agent":ua}))return void 0;if(h("x-opencode-session"))return"opencode";const affinity=h("x-session-affinity");if(affinity?.startsWith("ses_"))return"opencode";return void 0}function empty(client){return{client,findings:[],sourcesScanned:0}}function add(c,f2){const key2=`${f2.entry}\0${f2.source}`;if(c.seen.has(key2))return;c.seen.add(key2);c.findings.push(f2)}function entryName(entry){let s3=entry.trim();s3=s3.replace(/^npm:/,"");if(s3.startsWith("@")){const at2=s3.indexOf("@",1);if(at2!==-1)s3=s3.slice(0,at2)}else{const at2=s3.indexOf("@");if(at2!==-1)s3=s3.slice(0,at2)}const base=s3.split(/[\\/]/).pop()??s3;return base.replace(/\.(js|ts|mjs|cjs|json)$/i,"")}function isBiliSelf(entry){const name=entryName(entry);if(name==="billion-context")return true;return/[/\\]billion-context([/\\]|$)/.test(entry.trim())}function classifyOpencodeEntry(c,entry,source){if(isBiliSelf(entry))return;const trimmed=entry.trim();if(/^opencode-acp(@|$)/.test(trimmed)||/[/\\]opencode-acp([/\\]|$)/.test(trimmed)){add(c,{client:"opencode",entry,source,match:"known",knownId:"opencode-acp"});return}if(KEYWORD_RE.test(entryName(entry))){add(c,{client:"opencode",entry,source,match:"keyword"})}}function opencodePluginEntries(root,source,c){const arr=root?.plugin;if(!Array.isArray(arr))return;for(const item of arr){if(typeof item==="string"&&item!=="")classifyOpencodeEntry(c,item,source);else if(item&&typeof item==="object"){const name=item.name;if(typeof name==="string"&&name!=="")classifyOpencodeEntry(c,name,source)}}}function scanOpencode(env,cwd){const c={findings:[],sources:0,seen:new Set};try{const root=readOpencodeConfigRoot(env);if(root){opencodePluginEntries(root,"global config",c);c.sources+=1}}catch{}try{const start=path20.resolve(cwd);let gitRoot;let cur=start;for(;;){if(fs8.existsSync(path20.join(cur,".git"))){gitRoot=cur;break}const parent=path20.dirname(cur);if(parent===cur)break;cur=parent}const dirs=[];cur=start;for(;;){dirs.push(cur);if(gitRoot===void 0||cur===gitRoot)break;const parent=path20.dirname(cur);if(parent===cur)break;cur=parent}for(const dir of dirs){for(const file of[...OPENCODE_CONFIG_FILES,...OPENCODE_CONFIG_FILES.map(f2=>`.opencode/${f2}`)]){const full=path20.join(dir,file);let text;try{text=fs8.readFileSync(full,"utf8")}catch{continue}const parsed=parseConfigText(text);if(!parsed)continue;opencodePluginEntries(parsed,full,c);c.sources+=1}}}catch{}return{client:"opencode",findings:c.findings,sourcesScanned:c.sources}}function scanPi(env,cwd){const c={findings:[],sources:0,seen:new Set};const files=[path20.join(resolvePiHome(env),"settings.json"),path20.join(path20.resolve(cwd),".pi","settings.json")];for(const file of files){let obj;try{obj=JSON.parse(fs8.readFileSync(file,"utf8"))}catch{continue}if(!obj||typeof obj!=="object")continue;const packages=obj.packages;if(!Array.isArray(packages))continue;c.sources+=1;for(const p2 of packages){if(typeof p2!=="string"||p2==="")continue;if(isBiliSelf(p2))continue;if(isLegacyBcpEntry(p2)){add(c,{client:"pi",entry:p2,source:file,match:"known",knownId:"billion-context-pi"});continue}if(KEYWORD_RE.test(entryName(p2)))add(c,{client:"pi",entry:p2,source:file,match:"keyword"})}}return{client:"pi",findings:c.findings,sourcesScanned:c.sources}}function scanOmp(env){const c={findings:[],sources:0,seen:new Set};const file=path20.join(resolveOmpHome(env),"config.yml");let text;try{text=fs8.readFileSync(file,"utf8")}catch{return{client:"omp",findings:[],sourcesScanned:0}}c.sources+=1;const lines=text.split(/\r?\n/);let inBlock=false;for(const line of lines){if(/^extensions:(\s+(#.*)?)?$/.test(line)){inBlock=true;continue}if(inBlock){const item=/^\s+-\s+(.*)$/.exec(line);if(item){const entry=item[1].trim().replace(/^["']|["']$/g,"");if(!entry||isBiliSelf(entry))continue;if(KEYWORD_RE.test(entryName(entry)))add(c,{client:"omp",entry,source:file,match:"keyword"});continue}if(/^\S/.test(line))inBlock=false}}return{client:"omp",findings:c.findings,sourcesScanned:c.sources}}function scanKimi(env){const c={findings:[],sources:0,seen:new Set};const pluginsDir=path20.join(resolveKimiHome(env),"plugins");const registry3=path20.join(pluginsDir,"installed.json");let ids=[];try{const parsed=JSON.parse(fs8.readFileSync(registry3,"utf8"));if(Array.isArray(parsed.plugins)){ids=parsed.plugins.map(p2=>typeof p2.id==="string"?p2.id:"").filter(s3=>s3!=="");c.sources+=1}}catch{}if(ids.length===0){try{ids=fs8.readdirSync(pluginsDir,{withFileTypes:true}).filter(e=>e.isDirectory()&&e.name!=="managed"&&e.name!=="node_modules").map(e=>e.name);c.sources+=1}catch{}}for(const id of ids){if(id==="billion-context")continue;if(KEYWORD_RE.test(id))add(c,{client:"kimi",entry:id,source:registry3,match:"keyword"})}return{client:"kimi",findings:c.findings,sourcesScanned:c.sources}}function scanHermes(env){const c={findings:[],sources:0,seen:new Set};const pluginsDir=path20.join(resolveHermesHome(env),"plugins");let entries;try{entries=fs8.readdirSync(pluginsDir,{withFileTypes:true})}catch{return{client:"hermes",findings:[],sourcesScanned:0}}c.sources+=1;for(const e of entries){if(!e.isDirectory()||e.name==="billion-context")continue;if(KEYWORD_RE.test(e.name))add(c,{client:"hermes",entry:e.name,source:path20.join(pluginsDir,e.name),match:"keyword"})}return{client:"hermes",findings:c.findings,sourcesScanned:c.sources}}function scanDsh(env){const c={findings:[],sources:0,seen:new Set};let dirs;try{dirs=dshProfileDirs(env)}catch{return{client:"dsh",findings:[],sourcesScanned:0}}for(const dir of dirs){const file=path20.join(dir,"package.json");let obj;try{obj=JSON.parse(fs8.readFileSync(file,"utf8"))}catch{continue}c.sources+=1;for(const key2 of["dependencies","devDependencies"]){const deps=obj[key2];if(!deps||typeof deps!=="object"||Array.isArray(deps))continue;for(const dep of Object.keys(deps)){if(dep==="billion-context")continue;if(KEYWORD_RE.test(dep))add(c,{client:"dsh",entry:dep,source:file,match:"keyword"})}}}return{client:"dsh",findings:c.findings,sourcesScanned:c.sources}}function claudeSettingsFiles(env,cwd){const home=env.CLAUDE_CONFIG_DIR??path20.join(env.HOME??env.USERPROFILE??".",".claude");return[path20.join(home,"settings.json"),path20.join(path20.resolve(cwd),".claude","settings.json")]}function scanClaude(env,cwd){const c={findings:[],sources:0,seen:new Set};for(const file of claudeSettingsFiles(env,cwd)){let obj;try{obj=JSON.parse(fs8.readFileSync(file,"utf8"))}catch{continue}if(!obj||typeof obj!=="object")continue;c.sources+=1;const enabled=obj.enabledPlugins;if(enabled&&typeof enabled==="object"&&!Array.isArray(enabled)){for(const name of Object.keys(enabled)){if(KEYWORD_RE.test(name))add(c,{client:"claude",entry:name,source:file,match:"keyword"})}}const plugins=obj.plugins;if(Array.isArray(plugins)){for(const p2 of plugins){if(typeof p2==="string"&&p2!==""&&KEYWORD_RE.test(p2))add(c,{client:"claude",entry:p2,source:file,match:"keyword"})}}}try{const dir=path20.join(env.CLAUDE_CONFIG_DIR??path20.join(env.HOME??env.USERPROFILE??".",".claude"),"plugins");for(const e of fs8.readdirSync(dir,{withFileTypes:true})){if(!e.isDirectory())continue;if(KEYWORD_RE.test(e.name))add(c,{client:"claude",entry:e.name,source:path20.join(dir,e.name),match:"keyword"})}}catch{}return{client:"claude",findings:c.findings,sourcesScanned:c.sources}}function scanClientPlugins(client,opts={}){const env=opts.env??process.env;const cwd=opts.cwd??process.cwd();const key2=`${client}\0${cwd}`;const hit=cache4.get(key2);if(hit&&Date.now()-hit.at<SCAN_CACHE_TTL_MS)return hit.result;let result;switch(client){case"opencode":result=scanOpencode(env,cwd);break;case"pi":result=scanPi(env,cwd);break;case"omp":result=scanOmp(env);break;case"kimi":result=scanKimi(env);break;case"hermes":result=scanHermes(env);break;case"dsh":result=scanDsh(env);break;case"claude":result=scanClaude(env,cwd);break;default:result=empty(client);break}cache4.set(key2,{at:Date.now(),result});return result}var TS_RE=/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z)/;function parseTs(line){const m2=TS_RE.exec(line);if(!m2)return NaN;const v2=Date.parse(m2[1]);return Number.isFinite(v2)?v2:NaN}function timestampsOf(all){const out=new Array(all.length);let last=NaN;for(let i=0;i<all.length;i++){const p2=parseTs(all[i]);if(Number.isFinite(p2))last=p2;out[i]=last}return out}function queryLogLines(all,q2,opts){const n=Math.max(1,Math.floor(opts.n));const qLower=q2.toLowerCase();const lower=qLower?all.map(l=>l.toLowerCase()):null;const matches=[];if(qLower){for(let i=0;i<all.length;i++)if(lower[i].includes(qLower))matches.push(i)}const total=qLower?matches.length:all.length;if(total===0||all.length===0){return{total,shown:0,omitted:0,lines:[],...qLower?{isMatch:[]}:{}}}let included;if(!qLower){included=[];for(let i=0;i<all.length;i++)included.push(i)}else if(opts.winSec>0){const ts2=timestampsOf(all);const tF=ts2[matches[0]];const tL=ts2[matches[matches.length-1]];if(Number.isFinite(tF)&&Number.isFinite(tL)){const loT=tF-opts.winSec*1e3;const hiT=tL+opts.winSec*1e3;let loIdx=matches[0];while(loIdx>0&&Number.isFinite(ts2[loIdx-1])&&ts2[loIdx-1]>=loT)loIdx--;let hiIdx=matches[matches.length-1];while(hiIdx<all.length-1&&Number.isFinite(ts2[hiIdx+1])&&ts2[hiIdx+1]<=hiT)hiIdx++;included=[];for(let i=loIdx;i<=hiIdx;i++)included.push(i)}else{included=matches.slice()}}else if(opts.ctx>0){const ranges=[];for(const m2 of matches){const lo2=Math.max(0,m2-opts.ctx);const hi2=Math.min(all.length-1,m2+opts.ctx);const lastR=ranges[ranges.length-1];if(lastR&&lo2<=lastR[1]+1)lastR[1]=Math.max(lastR[1],hi2);else ranges.push([lo2,hi2])}included=[];for(const[lo2,hi2]of ranges)for(let i=lo2;i<=hi2;i++)included.push(i)}else{included=matches.slice()}let omitted=0;if(included.length>n){omitted=included.length-n;included=included.slice(-n)}return{total,shown:included.length,omitted,lines:included.map(i=>all[i]),...qLower?{isMatch:included.map(i=>lower[i].includes(qLower))}:{}}}import{createHash as createHash12,randomUUID as randomUUID5}from"crypto";import fs9 from"fs";import path21 from"path";function isProxyInstanceFile(v2){return v2!==void 0&&"instanceId"in v2}function readProxyInstanceFile(file){let raw;try{raw=fs9.readFileSync(file??instanceFilePath(),"utf8").trim()}catch{return void 0}if(raw.startsWith("{")){try{const parsed=JSON.parse(raw);if(typeof parsed.origin==="string"&&/^https?:\/\/\S+$/.test(parsed.origin)){const windows={};if(parsed.modelWindows&&typeof parsed.modelWindows==="object"){for(const[k2,v2]of Object.entries(parsed.modelWindows)){const n=Number(v2);if(Number.isFinite(n)&&n>0)windows[k2]=n}}const maxOutputs={};if(parsed.modelMaxOutputs&&typeof parsed.modelMaxOutputs==="object"){for(const[k2,v2]of Object.entries(parsed.modelMaxOutputs)){const n=Number(v2);if(Number.isFinite(n)&&n>0)maxOutputs[k2]=n}}return{origin:parsed.origin,instanceId:typeof parsed.instanceId==="string"?parsed.instanceId:"",pid:typeof parsed.pid==="number"?parsed.pid:0,startedAt:typeof parsed.startedAt==="number"?parsed.startedAt:0,host:typeof parsed.host==="string"?parsed.host:"",port:typeof parsed.port==="number"?parsed.port:0,passthrough:Boolean(parsed.passthrough),mitmDomains:Array.isArray(parsed.mitmDomains)?parsed.mitmDomains.map(String):[],modelWindows:windows,modelMaxOutputs:Object.keys(maxOutputs).length>0?maxOutputs:void 0,launchToken:typeof parsed.launchToken==="string"?parsed.launchToken:void 0,lane:typeof parsed.lane==="string"&&parsed.lane!==""?parsed.lane:void 0,codeFingerprint:typeof parsed.codeFingerprint==="string"&&parsed.codeFingerprint!==""?parsed.codeFingerprint:void 0}}}catch{}}if(/^https?:\/\/\S+$/.test(raw))return{origin:raw};return void 0}function instanceFilePath(){return path21.join(stateDir(),"proxy-origin")}function portZoneFilePath(){return path21.join(stateDir(),"port-zone.json")}function readZonePort(lane,file=portZoneFilePath()){let raw;try{raw=fs9.readFileSync(file,"utf8")}catch{return void 0}try{const parsed=JSON.parse(raw);const v2=parsed?.lanes?.[lane];if(typeof v2==="number"&&Number.isInteger(v2)&&v2>0&&v2<65536)return v2;return void 0}catch{return void 0}}function writeZonePort(lane,port,file=portZoneFilePath()){if(!Number.isInteger(port)||port<=0||port>=65536)return;let cur={};try{const parsed=JSON.parse(fs9.readFileSync(file,"utf8"));if(parsed!==null&&typeof parsed==="object"&&parsed.lanes!==null&&typeof parsed.lanes==="object")cur=parsed}catch{}atomicWriteJson({lanes:{...cur.lanes??{},[lane]:port}},file)}function lanePreferredPort(lane,env=process.env,file=portZoneFilePath()){return readZonePort(lane,file)??resolveZonePortBase(env)}function findSameLanePredecessor(entries,port,lane,ownFingerprint){if(!lane||!ownFingerprint)return void 0;for(const e of entries){if(e.port!==port||e.lane!==lane)continue;if(!isPidAlive(e.pid))continue;if(e.codeFingerprint!==ownFingerprint)return e}return void 0}var scriptFingerprints=new Map;function entryScriptFingerprint(scriptPath){if(!scriptPath)return void 0;const resolved=path21.resolve(scriptPath);const cached=scriptFingerprints.get(resolved);if(cached!==void 0)return cached;let digest;try{digest=createHash12("sha256").update(fs9.readFileSync(resolved)).digest("hex")}catch{return void 0}scriptFingerprints.set(resolved,digest);return digest}function atomicWriteJson(obj,filePath){fs9.mkdirSync(path21.dirname(filePath),{recursive:true});const tempPath=`${filePath}.${process.pid}.${randomUUID5()}.tmp`;let descriptor;try{descriptor=fs9.openSync(tempPath,"wx",420);fs9.writeSync(descriptor,JSON.stringify(obj)+"\n",null,"utf8");fs9.fsyncSync(descriptor);fs9.closeSync(descriptor);descriptor=void 0;fs9.renameSync(tempPath,filePath)}catch(error){if(descriptor!==void 0){try{fs9.closeSync(descriptor)}catch{}}try{fs9.unlinkSync(tempPath)}catch{}throw error}}function atomicWriteInstanceFile(info,file){atomicWriteJson(info,file??instanceFilePath())}function clearProxyInstanceFile(instanceId,file){const filePath=file??instanceFilePath();const current=readProxyInstanceFile(filePath);if(isProxyInstanceFile(current)&¤t.instanceId===instanceId){try{fs9.unlinkSync(filePath)}catch{}}}function startingMarkerPath(){return path21.join(stateDir(),"proxy-starting")}function readStartingMarker(file){let raw;try{raw=fs9.readFileSync(file??startingMarkerPath(),"utf8")}catch{return void 0}try{const parsed=JSON.parse(raw);if(typeof parsed.token!=="string"||parsed.token==="")return void 0;if(typeof parsed.pid!=="number"||!Number.isInteger(parsed.pid)||parsed.pid<=0)return void 0;if(typeof parsed.startedAt!=="number")return void 0;return{token:parsed.token,pid:parsed.pid,host:typeof parsed.host==="string"?parsed.host:"",port:typeof parsed.port==="number"?parsed.port:0,startedAt:parsed.startedAt,...typeof parsed.lane==="string"&&parsed.lane!==""?{lane:parsed.lane}:{}}}catch{return void 0}}function claimStartingMarker(marker,file){const filePath=file??startingMarkerPath();let descriptor;try{fs9.mkdirSync(path21.dirname(filePath),{recursive:true});descriptor=fs9.openSync(filePath,"wx",420);fs9.writeSync(descriptor,JSON.stringify(marker)+"\n",null,"utf8");fs9.fsyncSync(descriptor);descriptor=void 0;return true}catch{if(descriptor!==void 0){try{fs9.closeSync(descriptor)}catch{}}return false}}function clearStartingMarker(token,file){const filePath=file??startingMarkerPath();const current=readStartingMarker(filePath);if(current&¤t.token===token){try{fs9.unlinkSync(filePath)}catch{}}}function removeStartingMarker(file){try{fs9.unlinkSync(file??startingMarkerPath())}catch{}}function isPidAlive(pid){if(!Number.isInteger(pid)||pid<=0)return false;try{process.kill(pid,0);return true}catch(err2){return err2.code==="EPERM"}}function registryDirPath(){return path21.join(stateDir(),"instances")}function legacyRegistryFilePath(){return path21.join(stateDir(),"instances.json")}var SAFE_NAME_RE=/^[A-Za-z0-9][A-Za-z0-9._-]*$/;function safeRegistryName(instanceId){if(instanceId!=="."&&instanceId!==".."&&instanceId.length<=128&&SAFE_NAME_RE.test(instanceId)){return instanceId}return createHash12("sha256").update(instanceId).digest("hex")}function registryEntryFile(instanceId){return path21.join(registryDirPath(),`${safeRegistryName(instanceId)}.json`)}function safeReadJson2(file){try{return JSON.parse(fs9.readFileSync(file,"utf8"))}catch{return void 0}}function coerceEntry(value){if(!value||typeof value!=="object")return void 0;const o=value;if(typeof o.instanceId!=="string"||o.instanceId==="")return void 0;const windows={};if(o.modelWindows&&typeof o.modelWindows==="object"){for(const[k2,v2]of Object.entries(o.modelWindows)){const n=Number(v2);if(Number.isFinite(n)&&n>0)windows[k2]=n}}const maxOutputs={};if(o.modelMaxOutputs&&typeof o.modelMaxOutputs==="object"){for(const[k2,v2]of Object.entries(o.modelMaxOutputs)){const n=Number(v2);if(Number.isFinite(n)&&n>0)maxOutputs[k2]=n}}return{instanceId:o.instanceId,pid:typeof o.pid==="number"?o.pid:0,port:typeof o.port==="number"?o.port:0,origin:typeof o.origin==="string"?o.origin:"",startedAt:typeof o.startedAt==="number"?o.startedAt:0,...typeof o.host==="string"&&o.host!==""?{host:o.host}:{},...typeof o.passthrough==="boolean"?{passthrough:o.passthrough}:{},...Array.isArray(o.mitmDomains)?{mitmDomains:o.mitmDomains.map(String)}:{},...Object.keys(windows).length>0?{modelWindows:windows}:{},...Object.keys(maxOutputs).length>0?{modelMaxOutputs:maxOutputs}:{},...typeof o.lane==="string"&&o.lane!==""?{lane:o.lane}:{},...typeof o.codeFingerprint==="string"&&o.codeFingerprint!==""?{codeFingerprint:o.codeFingerprint}:{}}}function readMarkerNames(){try{return fs9.readdirSync(registryDirPath())}catch{return[]}}function readAllRegistryEntries(){const seen=new Set;const out=[];for(const name of readMarkerNames()){if(!name.endsWith(".json"))continue;const entry=coerceEntry(safeReadJson2(path21.join(registryDirPath(),name)));if(entry&&!seen.has(entry.instanceId)){seen.add(entry.instanceId);out.push(entry)}}const legacy=safeReadJson2(legacyRegistryFilePath());if(legacy&&Array.isArray(legacy.instances)){for(const raw of legacy.instances){const entry=coerceEntry(raw);if(entry&&!seen.has(entry.instanceId)){seen.add(entry.instanceId);out.push(entry)}}}return out}function listInstances(){return readAllRegistryEntries()}function procMainScript(pid){if(process.platform!=="linux")return void 0;let raw;try{raw=fs9.readFileSync(`/proc/${pid}/cmdline`,"utf8")}catch{return void 0}for(const arg of raw.split("\0")){if(!arg||arg.startsWith("-"))continue;if(arg.includes("/")&&(arg.endsWith(".js")||arg.endsWith(".mjs")||arg.endsWith(".cjs")))return arg}return void 0}function reapDeadMarkers(ours){for(const name of readMarkerNames()){if(!name.endsWith(".json"))continue;const file=path21.join(registryDirPath(),name);const entry=coerceEntry(safeReadJson2(file));if(!entry||entry.instanceId===ours||isPidAlive(entry.pid))continue;try{fs9.unlinkSync(file)}catch{}}}function lanesOverlap(a,b2){return a===void 0||b2===void 0||a===b2}function registerInstanceAndWarn(entry,warn){const others=readAllRegistryEntries().filter(e=>e.instanceId!==entry.instanceId&&isPidAlive(e.pid));for(const other of others){if(!lanesOverlap(entry.lane,other.lane))continue;const laneNote=entry.lane!==void 0&&other.lane!==void 0?` on lane "${entry.lane}"`:"";warn(`another bili instance is running (pid ${other.pid}, ${other.origin})${laneNote} \u2014 both processes will write the same sessions directory; stop one to avoid state pollution (#394)`)}reapDeadMarkers(entry.instanceId);try{atomicWriteJson(entry,registryEntryFile(entry.instanceId))}catch{}}function discoverLiveInstances(){const out=[];for(const e of readAllRegistryEntries()){if(!isPidAlive(e.pid))continue;out.push({origin:e.origin,instanceId:e.instanceId,pid:e.pid,startedAt:e.startedAt,host:e.host??"",port:e.port,passthrough:Boolean(e.passthrough),mitmDomains:e.mitmDomains??[],modelWindows:e.modelWindows??{},modelMaxOutputs:e.modelMaxOutputs,lane:e.lane,codeFingerprint:e.codeFingerprint})}return out}function unregisterInstance(instanceId){try{fs9.unlinkSync(registryEntryFile(instanceId))}catch{}}var SIDE_REQUEST_MAX_TOKENS=200;var SIDE_REQUEST_AGENTS=new Set(["title"]);function isSideRequest(parsed,requestAgent){if(!parsed||typeof parsed!=="object")return false;if(requestAgent!==void 0&&SIDE_REQUEST_AGENTS.has(requestAgent))return true;const p2=parsed;if(Array.isArray(p2.tools)&&p2.tools.length>0)return false;const field=outputBudgetField(parsed);if(!field)return false;const raw=readOutputBudget(p2,field);return typeof raw==="number"&&raw>0&&raw<=SIDE_REQUEST_MAX_TOKENS}var BILI_TOOL_NAMES=new Set([...ACP_TOOL_NAMES,ABSORB_TOOL_NAME,RULE_TOOL_NAME,RETRIEVE_TOOL_NAME,IMAGE_FULL_TOOL_NAME]);function biliToolNamesIn(parsed){const tools=parsed.tools;if(!Array.isArray(tools)||tools.length===0)return null;const names=[];for(const t of tools){if(!t||typeof t!=="object")return null;const o=t;const decls=o.functionDeclarations;if(Array.isArray(decls)){for(const d of decls){if(!d||typeof d!=="object"||typeof d.name!=="string")return null;names.push(d.name)}continue}let name=o.name;if(typeof name!=="string"){const fn=o.function;if(fn&&typeof fn==="object"&&typeof fn.name==="string")name=fn.name}if(typeof name!=="string")return null;names.push(name)}return names}function stripLeakedBiliTools(parsed){if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))return false;const p2=parsed;const names=biliToolNamesIn(p2);if(names===null||!names.every(n=>BILI_TOOL_NAMES.has(n)))return false;const field=outputBudgetField(p2);if(field){const raw=readOutputBudget(p2,field);if(typeof raw==="number"&&raw>0&&raw<=SIDE_REQUEST_MAX_TOKENS)return false}delete p2.tools;return true}function outputBudgetField(parsed){if(!parsed||typeof parsed!=="object")return null;const p2=parsed;for(const field of["max_tokens","max_completion_tokens","max_output_tokens"]){if(typeof p2[field]==="number"&&p2[field]>0)return field}const gen=p2.generationConfig;if(gen&&typeof gen==="object"){const v2=gen.maxOutputTokens;if(typeof v2==="number"&&v2>0)return"generationConfig.maxOutputTokens"}return null}function readOutputBudget(parsed,field){if(field!=="generationConfig.maxOutputTokens"){const v3=parsed[field];return typeof v3==="number"?v3:void 0}const gen=parsed.generationConfig;if(!gen||typeof gen!=="object")return void 0;const v2=gen.maxOutputTokens;return typeof v2==="number"?v2:void 0}function writeOutputBudget(parsed,field,value){if(field!=="generationConfig.maxOutputTokens"){parsed[field]=value;return}const gen=parsed.generationConfig;parsed.generationConfig={...gen&&typeof gen==="object"?gen:{},maxOutputTokens:value}}var warnedNoOutputCeiling=new Set;var WARNED_NO_OUTPUT_CEILING_CAP=4096;function noteNoOutputCeilingWarning(model){if(warnedNoOutputCeiling.has(model))return false;if(warnedNoOutputCeiling.size>=WARNED_NO_OUTPUT_CEILING_CAP)warnedNoOutputCeiling.clear();warnedNoOutputCeiling.add(model);return true}function restoreOutputBudget(parsed,session,log2,outputCeiling){const field=outputBudgetField(parsed);if(!field)return;const p2=parsed;const value=readOutputBudget(p2,field);if(value===void 0)return;if(value>SIDE_REQUEST_MAX_TOKENS){session.metadata.outputBudgetHighWater=value;return}if(!Array.isArray(p2.tools)||p2.tools.length===0)return;const highWaterRaw=session.metadata.outputBudgetHighWater;const highWater=typeof highWaterRaw==="number"&&highWaterRaw>SIDE_REQUEST_MAX_TOKENS?highWaterRaw:void 0;let target=highWater;const ceiling=typeof outputCeiling==="number"&&outputCeiling>SIDE_REQUEST_MAX_TOKENS?outputCeiling:void 0;if(ceiling!==void 0&&(target===void 0||ceiling>target))target=ceiling;const modelName=typeof p2.model==="string"&&p2.model.length>0?p2.model:"?";if(typeof target==="number"){writeOutputBudget(p2,field,target);const note=target===ceiling&&ceiling!==void 0?highWater===void 0?"; no healthy high-water yet \u2014 using known output ceiling (#1665/#1840)":`; high-water ${highWater} below known output ceiling \u2014 floored (#1665/#1840)`:"";log2("info",`[${session.id}] output budget restored ${value} -> ${target} (#546: client shrank it from its raw-history estimate${note})`)}if(ceiling===void 0&¬eNoOutputCeilingWarning(modelName)){log2("warn",`[${session.id}] output-budget restore has NO known output ceiling for model=${modelName}${typeof target==="number"?` (restored ${value} -> ${target})`:` (starved budget ${value} forwarded verbatim)`} \u2014 the target is the client's own last non-starved budget; while it stays pathologically small every turn truncates at max-tokens. Declare the model's max output in the bili config (providers.<url>.models."${modelName}".output) or have the client report it to floor the restore (#1840)`)}}var SIDE_REQUEST_GUARD_TOLERANCE=1.15;function sideRequestGuard(parsed,protocol,modelContextLimit,imageBilling="bytes",configuredCap,headroomCap=1,armedLimit=0,imageReserve){let limit=modelContextLimit;if(armedLimit>0&&(limit<=0||armedLimit<limit))limit=armedLimit;const field=outputBudgetField(parsed);const maxOut=(field?readOutputBudget(parsed,field):void 0)??0;if(limit>0&&shouldReserveOutputHeadroom(protocol))limit=reserveOutputHeadroom(limit,maxOut,headroomCap);const imageMass=imageReserve??imageTokensInParsedBody(protocol,parsed,imageBilling,configuredCap);const estimate=estimateRawBodyTokens(parsed)+imageMass;return{blocked:limit>0&&estimate>=limit*SIDE_REQUEST_GUARD_TOLERANCE,estimate,limit}}var OUTPUT_CLAMP_MARGIN_PCT=.05;var OUTPUT_CLAMP_MIN_MARGIN=2048;var OUTPUT_CLAMP_FLOOR=1024;var EMERGENCY_NUDGE_ESCALATION_PCT=.7;function countSystemAndToolsTokens(systemText,tools){return defaultCountTokens(systemText??"")+defaultCountTokens(JSON.stringify(tools??[]))}function estimateInputTokens(processedMessages,systemText,tools,lastInputTokens,lastInputTokensSource){const est=estimateCoreMessages(processedMessages)+countSystemAndToolsTokens(systemText,tools);const baseline=lastInputTokens>0&&lastInputTokensSource==="usage"?lastInputTokens:0;return Math.max(baseline,est)}function projectThinkingMass(msgs,input){if(!input.measured||!(input.providerInputTokens>0))return 0;const targets=[];for(const m2 of msgs){if(m2.contentType!=="reasoning")continue;if(typeof m2.thinkingSignature!=="string"||m2.thinkingSignature.length===0)continue;if(typeof m2.text==="string"&&m2.text.trim().length>0)continue;targets.push({msg:m2,sig:m2.thinkingSignature.length})}if(targets.length===0)return 0;const overhead=typeof input.storedOverhead==="number"&&Number.isFinite(input.storedOverhead)&&input.storedOverhead>0?input.storedOverhead:countSystemAndToolsTokens(input.systemText,input.tools);const gap=Math.max(0,input.providerInputTokens-estimateCoreMessages(msgs)-overhead-Math.max(0,input.imageTokens));if(gap<=0)return 0;const totalSig=targets.reduce((s3,t)=>s3+t.sig,0);let assigned=0;for(let i=0;i<targets.length;i++){const t=targets[i];const share=i===targets.length-1?gap-assigned:Math.floor(gap*t.sig/totalSig);t.msg.thinkingTokens=share;assigned+=share}return gap}function estimateWireOverhead(protocol,body){let parsed;try{parsed=JSON.parse(typeof body==="string"?body:body.toString("utf8"))}catch{return 0}const sysRaw=protocol==="responses"?parsed.instructions:protocol==="google"?googleSystemText(parsed):parsed.system;let sysText="";if(typeof sysRaw==="string"){sysText=sysRaw}else if(Array.isArray(sysRaw)){sysText=sysRaw.map(part=>typeof part?.text==="string"?part.text:"").join("\n")}if(protocol==="openai"&&Array.isArray(parsed.messages)){const hoisted=parsed.messages.filter(m2=>m2.role==="system"||m2.role==="developer").map(m2=>typeof m2.content==="string"?m2.content:"").join("\n");sysText=sysText?`${sysText}
|
|
2570
|
+
</body></html>`}import{closeSync,existsSync as existsSync5,fsyncSync,mkdirSync as mkdirSync6,openSync,readFileSync as readFileSync5,renameSync as renameSync3,unlinkSync as unlinkSync3,writeFileSync as writeFileSync5}from"fs";import{dirname as dirname5}from"path";import{randomUUID as randomUUID4}from"crypto";function readConfig(){const parsed=safeReadJson(configFile());return parsed&&typeof parsed==="object"&&!Array.isArray(parsed)?parsed:{}}function configParseError(){if(!existsSync5(configFile()))return null;const parsed=safeReadJson(configFile());if(parsed&&typeof parsed==="object"&&!Array.isArray(parsed))return null;return`config file is not valid JSON: ${configFile()}`}function readProviders(){const providers=readConfig().providers;return providers&&typeof providers==="object"&&!Array.isArray(providers)?providers:{}}function readUpstreamSettings(){const config=readConfig();const proxy=typeof config.upstreamProxy==="string"&&config.upstreamProxy.trim()?config.upstreamProxy.trim():void 0;return{mode:parseUpstreamProxyMode(config.upstreamProxyMode??(proxy?"manual":void 0)),...proxy?{proxy}:{}}}function atomicWriteConfig(config){const filePath=configFile();mkdirSync6(dirname5(filePath),{recursive:true});const tempPath=`${filePath}.${process.pid}.${randomUUID4()}.tmp`;let descriptor;try{descriptor=openSync(tempPath,"wx",384);writeFileSync5(descriptor,JSON.stringify(config,null,2)+"\n","utf8");fsyncSync(descriptor);closeSync(descriptor);descriptor=void 0;renameSync3(tempPath,filePath)}catch(error){if(descriptor!==void 0)closeSync(descriptor);try{unlinkSync3(tempPath)}catch{}throw error}}async function handleConfigGet(res){const upstream=readUpstreamSettings();const config=readConfig();const parseError=configParseError();if(parseError)log("warn",`[acp-web] ${parseError} \u2014 showing empty view; PUT is blocked until fixed`);res.writeHead(200,{"content-type":"application/json"});res.end(JSON.stringify({path:configFile(),providers:readProviders(),upstreamProxy:upstream.proxy??null,upstreamProxyMode:upstream.mode,compress:config.compress??null,passthrough:passthroughState(process.env),...existsSync5(configFile())?{raw:readFileSync5(configFile(),"utf8")}:{},...parseError?{parseError}:{}},null,2))}async function handleConfigPut(req,res,onChanged,biliPort=8787){const raw=await readJsonBody(req);if(!raw||typeof raw!=="object"||Array.isArray(raw))return sendError(res,400,"expected JSON object");const parseError=configParseError();if(parseError)return sendError(res,409,`${parseError} \u2014 fix the syntax error by hand, then retry; refusing to overwrite`);const body=raw;const hasProviders=Object.prototype.hasOwnProperty.call(body,"providers");const hasProxy=Object.prototype.hasOwnProperty.call(body,"upstreamProxy");const hasMode=Object.prototype.hasOwnProperty.call(body,"upstreamProxyMode");const hasCompress=Object.prototype.hasOwnProperty.call(body,"compress");const hasPassthrough=Object.prototype.hasOwnProperty.call(body,"passthrough");const hasFile=Object.prototype.hasOwnProperty.call(body,"file");if(!hasProviders&&!hasProxy&&!hasMode&&!hasCompress&&!hasPassthrough&&!hasFile)return sendError(res,400,"expected providers, upstream proxy, compress, passthrough settings, or the full config file");if(hasFile){if(typeof body.file!=="string")return sendError(res,400,"file must be a string (raw config JSON text)");let next;try{const p2=JSON.parse(body.file);if(!p2||typeof p2!=="object"||Array.isArray(p2))throw new Error("top level must be a JSON object");next=p2}catch(error){return sendError(res,400,`file is not valid JSON: ${String(error)}`)}if(next.providers!==void 0){if(typeof next.providers!=="object"||Array.isArray(next.providers))return sendError(res,400,"providers must be an object");for(const[url,value]of Object.entries(next.providers)){const route=parseRouteEntry(value);if(!url||!route)return sendError(res,400,`invalid provider entry: ${url||"(empty)"}`);try{validateHttpProxy(route.proxy,biliPort)}catch(error){return sendError(res,400,`invalid provider proxy for ${url}: ${String(error)}`)}}}if(next.upstreamProxy!==void 0){if(next.upstreamProxy!==null&&typeof next.upstreamProxy!=="string")return sendError(res,400,"upstreamProxy must be a string or null");try{validateHttpProxy(typeof next.upstreamProxy==="string"?next.upstreamProxy.trim()||void 0:void 0,biliPort)}catch(error){return sendError(res,400,String(error))}}if(next.upstreamProxyMode!==void 0&&(typeof next.upstreamProxyMode!=="string"||!["auto","manual","direct"].includes(next.upstreamProxyMode)))return sendError(res,400,"upstreamProxyMode must be auto, manual, or direct");if(next.compress!==void 0&&next.compress!==null&&parseCompressSettings(next.compress)===void 0)return sendError(res,400,"invalid compress settings");if(next.passthrough!==void 0&&next.passthrough!==null&&typeof next.passthrough!=="boolean")return sendError(res,400,"passthrough must be a boolean or null");if(next.passthrough===true&&passthroughState(process.env).source==="env")return sendError(res,409,"passthrough is forced by the ACP_PASSTHROUGH environment variable (or --passthrough flag); unset it and restart to change here");try{atomicWriteConfig(next);onChanged?.()}catch(error){return sendError(res,500,`failed to apply config: ${String(error)}`)}res.writeHead(200,{"content-type":"application/json"});res.end(JSON.stringify({ok:true,applied:["config file"]},null,2));return}let rawProviders;if(hasProviders){if(!body.providers||typeof body.providers!=="object"||Array.isArray(body.providers)){return sendError(res,400,"providers must be an object")}rawProviders={};for(const[url,value]of Object.entries(body.providers)){try{rejectLegacyRoute(url,value)}catch(error){return sendError(res,400,String(error))}const route=parseRouteEntry(value);if(!url||!route)return sendError(res,400,`invalid provider entry: ${url||"(empty)"}`);try{validateHttpProxy(route.proxy,biliPort)}catch(error){return sendError(res,400,`invalid provider proxy for ${url}: ${String(error)}`)}rawProviders[url]=value}}let proxy;if(hasProxy){if(body.upstreamProxy!==null&&typeof body.upstreamProxy!=="string"){return sendError(res,400,"upstreamProxy must be a string or null")}proxy=typeof body.upstreamProxy==="string"?body.upstreamProxy.trim()||void 0:void 0;try{validateHttpProxy(proxy,biliPort)}catch(error){return sendError(res,400,String(error))}}let mode;if(hasMode){if(typeof body.upstreamProxyMode!=="string"||!["auto","manual","direct"].includes(body.upstreamProxyMode)){return sendError(res,400,"upstreamProxyMode must be auto, manual, or direct")}mode=parseUpstreamProxyMode(body.upstreamProxyMode)}if(mode==="manual"&&!proxy&&!readUpstreamSettings().proxy){return sendError(res,400,"manual mode requires an upstream proxy URL")}let compress;if(hasCompress){compress=body.compress===null?{}:parseCompressSettings(body.compress);if(compress===void 0)return sendError(res,400,"invalid compress settings")}if(hasPassthrough){if(body.passthrough!==null&&typeof body.passthrough!=="boolean"){return sendError(res,400,"passthrough must be a boolean or null")}if(passthroughState(process.env).source==="env"){return sendError(res,409,"passthrough is forced by the ACP_PASSTHROUGH environment variable (or --passthrough flag); unset it and restart to change here")}}const config=readConfig();if(hasProviders)config.providers=rawProviders;if(hasProxy){if(proxy)config.upstreamProxy=proxy;else delete config.upstreamProxy}if(hasMode&&mode)config.upstreamProxyMode=mode;if(hasCompress){if(compress&&Object.keys(compress).length>0)config.compress=compress;else delete config.compress}if(hasPassthrough){if(body.passthrough===true)config.passthrough=true;else delete config.passthrough}try{atomicWriteConfig(config);onChanged?.()}catch(error){return sendError(res,500,`failed to apply config: ${String(error)}`)}const changed=[];if(hasProviders)changed.push(`${Object.keys(rawProviders??{}).length} routes`);if(hasProxy||hasMode)changed.push("network");if(hasCompress)changed.push("compress");if(hasPassthrough)changed.push("passthrough");log("info",`[acp-web] configuration updated (${changed.join(", ")||"none"})`);res.writeHead(200,{"content-type":"application/json"});res.end(JSON.stringify({ok:true,providers:hasProviders&&rawProviders?Object.keys(rawProviders).length:void 0}))}function sendError(res,status,message){res.writeHead(status,{"content-type":"application/json"});res.end(JSON.stringify({error:message}))}function readJsonBody(req){return new Promise(resolve=>{const chunks=[];let size=0;req.on("data",chunk=>{size+=chunk.length;if(size>256*1024){req.destroy();resolve(void 0);return}chunks.push(chunk)});req.on("end",()=>{try{resolve(JSON.parse(Buffer.concat(chunks).toString("utf8")))}catch{resolve(void 0)}});req.on("error",()=>resolve(void 0))})}import{mkdirSync as mkdirSync7,writeFileSync as writeFileSync6}from"fs";import path18 from"path";function fmtDate(ms2){return ms2?new Date(ms2).toISOString().replace("T"," ").slice(0,19)+" UTC":"\u2014"}async function listSessions2(opts={}){const store=new SessionStore({dir:opts.dir,enabled:true});const sessions2=[...(await store.loadAll()).values()];sessions2.sort((a,b2)=>latestBlockTime(b2)-latestBlockTime(a));return sessions2.map(s3=>({id:s3.id,title:s3.meta.title,label:s3.meta.label,protocol:s3.meta.protocol,upstreamOrigin:s3.meta.upstreamOrigin,savedAt:latestBlockTime(s3)||void 0,contextTokens:s3.stats.contextTokens,blocks:s3.state.blocks.length}))}function latestBlockTime(s3){let latest=0;for(const b2 of s3.state.blocks)if(b2.createdAt>latest)latest=b2.createdAt;return latest}function renderHandoff2(s3,full){const messages=s3.lastMessages;if(messages&&messages.length>0){const folded=s3.lastMessagesFolded===true;const base=renderHandoff({coreMessages:messages,state:s3.state,full,folded,meta:{title:s3.meta.title,label:s3.meta.label,sessionId:s3.id,contextTokens:s3.stats.contextTokens,extraBullets:[...s3.meta.protocol?[`- protocol: ${s3.meta.protocol}`]:[],...s3.meta.upstreamOrigin?[`- upstream: ${s3.meta.upstreamOrigin}`]:[],`- requests: ${s3.stats.requests}`]}});return base+blockSummariesSection(s3,full&&folded,base)}const lines=[];lines.push(`# billion-context session handoff`);lines.push("");lines.push(`- title: ${s3.meta.title??"(untitled)"}`);if(s3.meta.label)lines.push(`- label: ${s3.meta.label}`);lines.push(`- session id: ${s3.id}`);if(s3.meta.protocol)lines.push(`- protocol: ${s3.meta.protocol}`);if(s3.meta.upstreamOrigin)lines.push(`- upstream: ${s3.meta.upstreamOrigin}`);lines.push(`- requests: ${s3.stats.requests}`);if(s3.stats.contextTokens)lines.push(`- last context tokens: ~${s3.stats.contextTokens}`);lines.push(`- compression blocks: ${s3.state.blocks.length} (active ${s3.state.blocks.filter(b2=>b2.active).length})`);lines.push("");const active=s3.state.blocks.filter(b2=>b2.active);if(active.length===0){lines.push("No active compression blocks and no persisted conversation snapshot (v2 session file). Original messages are only persisted when they are compressed into a block, so this session's conversation content is not available for export.");lines.push("")}for(const b2 of active){lines.push(`## Block ${b2.blockId}${b2.topic?` \u2014 ${b2.topic}`:""}`);lines.push("");lines.push(`tier ${b2.tier} \xB7 ~${b2.compressedTokens} tokens compressed \xB7 ${fmtDate(b2.createdAt)}`);lines.push("");lines.push(b2.summary.trim());lines.push("");const content=s3.blockContents.get(b2.blockId);if(full&&content){lines.push(`### Original messages (${content.full.count})`);lines.push("");lines.push(content.full.text.trim());lines.push("")}}if(active.length>0){lines.push("---");lines.push("");lines.push("Paste the block summaries above into a new session to continue without the proxy.");lines.push("")}return lines.join("\n")}function blockSummariesSection(s3,includeOriginals,priorDoc){const active=s3.state.blocks.filter(b2=>b2.active);if(active.length===0)return"";const lines=[];lines.push(`## Compressed block summaries`);lines.push("");for(const b2 of active){lines.push(`### Block ${b2.blockId}${b2.topic?` \u2014 ${b2.topic}`:""}`);lines.push("");lines.push(`tier ${b2.tier} \xB7 ~${b2.compressedTokens} tokens compressed \xB7 ${fmtDate(b2.createdAt)}`);lines.push("");const summary=b2.summary.trim();if(summary===""){lines.push("_no summary recorded_")}else if(priorDoc.includes(summary)){lines.push("_summary already shown in the conversation view above_")}else{lines.push(summary)}lines.push("");const content=includeOriginals?s3.blockContents.get(b2.blockId):void 0;if(content){lines.push(`#### Original messages (${content.full.count})`);lines.push("");lines.push(content.full.text.trim());lines.push("")}}return lines.join("\n")}function matchSession2(sessions2,selector){return matchSession(sessions2,selector,s3=>s3.meta.label)}async function exportSession(selector,opts={}){const store=new SessionStore({dir:opts.dir,enabled:true});const all=[...(await store.loadAll()).values()];if(all.length===0){return"No persisted sessions found. Sessions are written under the sessions directory once the proxy has served a request (compression state, compressed originals, and a bounded folded-view snapshot of the recent conversation)."}if(!selector){const list=await listSessions2(opts);const rows=list.map(s3=>`${s3.id}${s3.label?` label=${s3.label}`:""}${s3.protocol?` [${s3.protocol}]`:""} blocks=${s3.blocks}${s3.contextTokens?` ctx~${s3.contextTokens}`:""} ${s3.title??""}`);return["Persisted sessions:","",...rows.map(r=>` ${r}`),"","Usage: bili export <session-id|label> [--output handoff.md] [--full]"].join("\n")}const matches=matchSession2(all,selector);if(matches.length===0){throw new Error(`no session matches "${selector}" (run "bili export" to list sessions)`)}if(matches.length>1){const ids=matches.map(s3=>s3.id).join(", ");throw new Error(`selector "${selector}" matches ${matches.length} sessions (${ids}); use the full session id`)}const markdown=renderHandoff2(matches[0],opts.full??false);if(opts.output){mkdirSync7(path18.dirname(path18.resolve(opts.output)),{recursive:true});writeFileSync6(opts.output,markdown,"utf8");return`written to ${opts.output}`}return markdown}function escapeHtml2(s3){return s3.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function inlineMd(s3){let out=escapeHtml2(s3);out=out.replace(/`([^`]+)`/g,(_m,code)=>`<code>${code}</code>`);out=out.replace(/\*\*([^*]+)\*\*/g,"<strong>$1</strong>");out=out.replace(/(^|[^*])\*([^*\n]+)\*/g,"$1<em>$2</em>");out=out.replace(/\[([^\]]+)\]\(([^)\s]+)\)/g,(_m,text,url)=>{if(/^(https?:\/\/|\/)/i.test(url))return`<a href="${url}" target="_blank" rel="noopener noreferrer">${text}</a>`;return text});return out}function markdownToHtml(md){const lines=md.split("\n");const html=[];let i=0;while(i<lines.length){const line=lines[i];if(line.startsWith("```")){const buf=[];i+=1;while(i<lines.length&&!lines[i].startsWith("```")){buf.push(lines[i]);i+=1}i+=1;html.push(`<pre><code>${escapeHtml2(buf.join("\n"))}</code></pre>`);continue}const h=line.match(/^(#{1,6})\s+(.*)$/);if(h){const level=h[1].length;const inner=h[2].trim();const role=level===3&&/^(user|assistant|tool)$/i.test(inner)?inner.toLowerCase():null;html.push(role?`<h3 class="msg-role ${role}">${inlineMd(inner)}</h3>`:`<h${level}>${inlineMd(h[2])}</h${level}>`);i+=1;continue}if(/^\s*(---+|\*\*\*+)\s*$/.test(line)){html.push("<hr/>");i+=1;continue}if(/^\s{2,}\S/.test(line)){const buf=[];let indent=Infinity;while(i<lines.length&&/^\s{2,}\S/.test(lines[i])){buf.push(lines[i]);const m2=lines[i].match(/^\s*/);if(m2&&m2[0].length<indent)indent=m2[0].length;i+=1}const cut=Math.min(indent,4);html.push(`<pre><code>${escapeHtml2(buf.map(l=>l.slice(cut)).join("\n"))}</code></pre>`);continue}if(/^\s*>\s?/.test(line)||/^\s*>\s?/.test(line)){const buf=[];while(i<lines.length&&/^\s*>\s?/.test(lines[i])){buf.push(lines[i].replace(/^\s*>\s?/,""));i+=1}html.push(`<blockquote><p>${inlineMd(buf.join(" "))}</p></blockquote>`);continue}if(/^\s*[-*]\s+/.test(line)){const items=[];while(i<lines.length&&/^\s*[-*]\s+/.test(lines[i])){items.push(`<li>${inlineMd(lines[i].replace(/^\s*[-*]\s+/,""))}</li>`);i+=1}html.push(`<ul>${items.join("")}</ul>`);continue}if(/^\s*\d+[.)]\s+/.test(line)){const items=[];while(i<lines.length&&/^\s*\d+[.)]\s+/.test(lines[i])){items.push(`<li>${inlineMd(lines[i].replace(/^\s*\d+[.)]\s+/,""))}</li>`);i+=1}html.push(`<ol>${items.join("")}</ol>`);continue}if(line.trim()===""){i+=1;continue}const para=[line];i+=1;while(i<lines.length&&lines[i].trim()!==""&&!/^(#{1,6}\s|```|\s*[-*]\s|\s*\d+[.)]\s|\s*>)/.test(lines[i])){para.push(lines[i]);i+=1}html.push(`<p>${para.map(inlineMd).join("<br/>")}</p>`)}return html.join("\n")}var DISK_TTL_MS=5e3;var diskStore=null;function getDiskStore(){if(!diskStore)diskStore=new SessionStore({enabled:true});return diskStore}var diskMemo=null;var diskScan=null;function loadDiskSessions(){if(diskMemo&&Date.now()-diskMemo.at<DISK_TTL_MS)return Promise.resolve(diskMemo.map);if(!diskScan){const run=(async()=>{try{const map=await getDiskStore().loadAll();diskMemo={at:Date.now(),map};return map}catch(error){log("warn",`[acp-web] session disk scan failed: ${String(error)}`);return diskMemo?.map??new Map}})();diskScan=run.finally(()=>{diskScan=null})}return diskScan}function hitPct(input,cached){return input>0?Math.round(cached/input*100):null}function summaryOf(s3,live){const led=s3.metadata["cacheLedger"];const agg=led;const requests=Math.max(s3.stats.requests??0,agg?.agg?.requests??0);const inputTokens=Math.max(s3.stats.inputTokens??0,agg?.agg?.input??0);const cachedTokens=Math.max(s3.stats.cachedTokens??0,agg?.agg?.cached??0);const outputTokens=Math.max(s3.stats.outputTokens??0,agg?.agg?.output??0);const hasLedger=Boolean(agg?.agg&&(agg.agg.requests??0)>0);let hasFolds=false,grossSaved=0,netSaved=0,repayCost=0,summaryCost=0,foldCount=0;for(const f2 of led?.folds??[]){hasFolds=true;foldCount+=1;const S2=f2.S??0,sig=f2.sigma??0,rep=f2.T??0,ra=f2.requestsAfter??0;const avoided=(S2-sig)*ra;grossSaved+=avoided;netSaved+=avoided-rep-sig;repayCost+=rep;summaryCost+=sig}let firstBlockHint="";const fb=s3.state.blocks.find(b2=>b2.topic||b2.summary);if(fb&&(fb.topic||fb.summary)){firstBlockHint=String(fb.topic||fb.summary).replace(/\s+/g," ").trim();if(firstBlockHint.length>48)firstBlockHint=firstBlockHint.slice(0,48)+"\u2026"}const metaRec=s3.metadata;const clientHint=typeof metaRec["pluginAgent"]==="string"&&metaRec["pluginAgent"]?metaRec["pluginAgent"]:typeof metaRec["clientHint"]==="string"&&metaRec["clientHint"]?metaRec["clientHint"]:"";return{id:s3.id,...s3.meta.title?{title:s3.meta.title}:{},...s3.meta.label&&s3.meta.label!==s3.id?{label:s3.meta.label}:{},...s3.meta.protocol?{protocol:s3.meta.protocol}:{},...s3.meta.upstreamOrigin?{upstreamOrigin:s3.meta.upstreamOrigin}:{},live,requests,contextTokens:s3.stats.contextTokens,...s3.stats.contextTokensSource?{contextTokensSource:s3.stats.contextTokensSource}:{},tokensSaved:s3.stats.tokensSaved,inputTokens,cachedTokens,outputTokens,cacheHitPct:hitPct(inputTokens,cachedTokens),blocks:s3.state.blocks.length,...typeof s3.metadata.effectiveContextLimit==="number"?{contextWindow:s3.metadata.effectiveContextLimit}:{},lastSeen:new Date(s3.lastSeen).toISOString(),...s3.restored?{restored:true}:{},...hasLedger?{hasLedger:true}:{},...firstBlockHint?{firstBlockHint}:{},...hasFolds?{grossSaved,netSaved,repayCost,summaryCost,foldCount}:{},...hasLedger?{newContent:agg?.agg?.nc??0,compRepay:agg?.agg?.cr??0,ttlRepay:agg?.agg?.tr??0}:{},...typeof agg?.agg?.input==="number"&&agg.agg.input>0?{missDropNew:Math.round((agg.agg.nc??0)/agg.agg.input*1e3)/10,missDropComp:Math.round((agg.agg.cr??0)/agg.agg.input*1e3)/10,missDropTtl:Math.round((agg.agg.tr??0)/agg.agg.input*1e3)/10}:{},...typeof agg?.agg?.switches==="number"&&agg.agg.switches>0?{modelSwitches:agg.agg.switches,switchMissedTokens:agg?.agg?.switchMissed??0}:{},...clientHint?{clientHint}:{}}}function isEmptyStub(s3){return(s3.requests??0)<=1&&(s3.contextTokens??0)===0&&(s3.blocks??0)===0&&!s3.hasLedger}var lastHiddenEmpty=0;function hiddenEmptyCount(){return lastHiddenEmpty}async function allSummaries(){const disk=await loadDiskSessions();const out=new Map;for(const[id,s3]of disk)out.set(id,summaryOf(s3,false));for(const s3 of listSessions())out.set(s3.id,summaryOf(s3,true));return[...out.values()].sort((a,b2)=>b2.lastSeen.localeCompare(a.lastSeen))}async function buildSessionList(){const all=await allSummaries();const vis=all.filter(s3=>!isEmptyStub(s3));lastHiddenEmpty=all.length-vis.length;return vis}async function buildOverview(){const allAll=await allSummaries();const all=allAll.filter(s3=>!isEmptyStub(s3));let requests=0,input=0,cached=0,output=0,saved=0,savedEstimated=0,blocks=0,live=0;let grossSavedTotal=0,netSavedTotal=0,repayTotal=0,summaryCostTotal=0,hasFoldData=false;let missNewTotal=0,missCompTotal=0,missTtlTotal=0,missInputTotal=0;const protoMap=new Map;for(const s3 of all){requests+=s3.requests;input+=s3.inputTokens;cached+=s3.cachedTokens;output+=s3.outputTokens;saved+=s3.tokensSaved;blocks+=s3.blocks;if(s3.live&&!s3.restored)live+=1;const key2=s3.protocol??"unknown";const row=protoMap.get(key2)??{protocol:key2,sessions:0,requests:0,inputTokens:0,cachedTokens:0,savedNet:0,folds:0,missNew:0,missComp:0,missTtl:0,missInput:0};row.sessions+=1;row.requests+=s3.requests;row.inputTokens+=s3.inputTokens;row.cachedTokens+=s3.cachedTokens;row.savedNet+=s3.hasLedger?s3.netSaved??0:s3.tokensSaved;row.folds+=s3.foldCount??0;protoMap.set(key2,row);if(s3.tokensSaved>0&&!s3.hasLedger)savedEstimated+=s3.tokensSaved;if(s3.hasLedger){missNewTotal+=s3.newContent??0;missCompTotal+=s3.compRepay??0;missTtlTotal+=s3.ttlRepay??0;missInputTotal+=s3.inputTokens;row.missNew+=s3.newContent??0;row.missComp+=s3.compRepay??0;row.missTtl+=s3.ttlRepay??0;row.missInput+=s3.inputTokens}if(s3.hasLedger&&s3.grossSaved!=null){hasFoldData=true;grossSavedTotal+=s3.grossSaved;netSavedTotal+=s3.netSaved??0;repayTotal+=s3.repayCost??0;summaryCostTotal+=s3.summaryCost??0}else if(s3.tokensSaved>0){grossSavedTotal+=s3.tokensSaved}}return{sessions:all.length,live,requests,inputTokens:input,cachedTokens:cached,outputTokens:output,tokensSaved:saved,savedEstimated,grossSavedTotal,netSavedTotal,hasFoldData,repayTotal,summaryCostTotal,missNewTotal,missCompTotal,missTtlTotal,missInputTotal,hitPct:hitPct(input,cached),blocks,byProtocol:[...protoMap.values()].map(r=>{const base=r.missInput||0;const drop=v2=>Math.round(v2/base*1e3)/10;return{protocol:r.protocol,sessions:r.sessions,requests:r.requests,inputTokens:r.inputTokens,cachedTokens:r.cachedTokens,savedNet:r.savedNet,folds:r.folds,hitPct:hitPct(r.inputTokens,r.cachedTokens),...base>0?{missDropNew:drop(r.missNew),missDropComp:drop(r.missComp),missDropTtl:drop(r.missTtl)}:{}}}),recent:all.slice(0,8),hiddenEmpty:allAll.length-all.length}}async function buildSessionDetail(id){const live=listSessions().find(s3=>s3.id===id);let session=live;if(!session){const disk=await loadDiskSessions();session=disk.get(id)}if(!session)return null;let handoffMd="";try{handoffMd=renderHandoff2(session,false)}catch(error){log("warn",`[acp-web] handoff render failed for ${id}: ${String(error)}`)}let handoffTruncated=false;if(handoffMd.length>15e5){handoffMd=handoffMd.slice(0,15e5)+"\n\n\u2026\uFF08\u5185\u5BB9\u8FC7\u957F\u5DF2\u622A\u65AD\uFF0C\u4F7F\u7528 `bili export` \u67E5\u770B\u5B8C\u6574\u4F1A\u8BDD\uFF09\n";handoffTruncated=true}const pluginAgent=typeof session.metadata["pluginAgent"]==="string"?session.metadata["pluginAgent"]:void 0;const clientHint=pluginAgent??(typeof session.metadata["clientHint"]==="string"?session.metadata["clientHint"]:void 0);const sysPrompt=typeof session.metadata["systemPromptTokens"]==="number"?session.metadata["systemPromptTokens"]:0;return{...summaryOf(session,!!live),lastInputTokens:session.stats.lastInputTokens,compressCreditTokens:session.stats.compressCreditTokens,retrieveCalls:session.stats.retrieveCalls,retrieveHits:session.stats.retrieveHits,retrieveMisses:session.stats.retrieveMisses,storedBytes:session.stats.storedBytes,storeBytesSaved:session.stats.storeBytesSaved,...session.meta.activePack?{activePack:session.meta.activePack}:{},...clientHint?{clientHint}:{},...typeof session.metadata["biliVersion"]==="string"?{biliVersion:session.metadata["biliVersion"]}:{},...sysPrompt>0?{systemPromptTokens:sysPrompt}:{},ledger:buildSessionCacheReport(session),handoffMd,handoffHtml:markdownToHtml(handoffMd),handoffTruncated,blockDetails:session.state.blocks.map(b2=>({blockId:b2.blockId,tier:b2.tier,...b2.topic!==void 0?{topic:b2.topic}:{},summary:b2.summary,compressedTokens:b2.compressedTokens,createdAt:b2.createdAt,...b2.startRef!==void 0?{startRef:b2.startRef}:{},...b2.endRef!==void 0?{endRef:b2.endRef}:{},active:b2.active}))}}function renderUI(origin){return renderPage(origin,VERSION)}var ORPHAN_THRESHOLD=3;var orphanStreaks=new WeakMap;function reapOrphanBlocks(session,visible,deactivate){if(session.state.blocks.length===0)return{reaped:[]};const presentIds=new Set(visible.map(m2=>m2.id));const reaped=[];for(const block of session.state.blocks){if(!block.active)continue;const hasHit=block.effectiveMessageIds.some(id=>presentIds.has(id));if(hasHit){orphanStreaks.delete(block);continue}const streak=(orphanStreaks.get(block)??0)+1;orphanStreaks.set(block,streak);if(streak>=ORPHAN_THRESHOLD){reaped.push(block.blockId)}}if(reaped.length===0)return{reaped:[]};session.state=deactivate(session.state,reaped);for(const id of reaped)session.blockContents.delete(id);return{reaped}}import fs8 from"fs";import path20 from"path";import path19 from"path";import{fileURLToPath as fileURLToPath3}from"url";var OMP_FIRST_EVENT_TIMEOUT_ENV="PI_OPENAI_STREAM_FIRST_EVENT_TIMEOUT_MS";var OMP_FIRST_EVENT_TIMEOUT_DEFAULT_MS=18e5;function ompFirstEventTimeoutValue(env){const raw=env[OMP_FIRST_EVENT_TIMEOUT_ENV];if(raw!==void 0&&raw.trim().length>0)return void 0;return String(OMP_FIRST_EVENT_TIMEOUT_DEFAULT_MS)}function applyOmpFirstEventTimeout(env){const value=ompFirstEventTimeoutValue(env);if(value!==void 0)env[OMP_FIRST_EVENT_TIMEOUT_ENV]=value}function isLegacyBcpEntry(entry){const e=entry.trim();const bare=e.replace(/^npm:/,"");return bare==="billion-context-pi"||/^billion-context-pi@/.test(bare)||/(^|[/\\])billion-context-pi([/\\]|$)/.test(e)}function isDesignAbsorbed(finding,pluginAgent){return finding.client==="opencode"&&finding.knownId==="opencode-acp"&&pluginAgent==="opencode"}var SCAN_CACHE_TTL_MS=5*60*1e3;var KEYWORD_RE=/\b(compress\w*|compact\w*|acp|summar\w*)\b/i;var cache4=new Map;function conflictScanEnabled(env=process.env){const v2=env.BILI_CONFLICT_SCAN?.trim().toLowerCase();return!(v2==="0"||v2==="false")}function sniffScanClient(headers){const h=name=>{const v2=headers[name];return Array.isArray(v2)?v2[0]:typeof v2==="string"?v2:void 0};if(h("x-claude-code-session-id"))return"claude";const ua=h("user-agent");if(ua&&isCodexClient({"user-agent":ua}))return void 0;if(h("x-opencode-session"))return"opencode";const affinity=h("x-session-affinity");if(affinity?.startsWith("ses_"))return"opencode";return void 0}function empty(client){return{client,findings:[],sourcesScanned:0}}function add(c,f2){const key2=`${f2.entry}\0${f2.source}`;if(c.seen.has(key2))return;c.seen.add(key2);c.findings.push(f2)}function entryName(entry){let s3=entry.trim();s3=s3.replace(/^npm:/,"");if(s3.startsWith("@")){const at2=s3.indexOf("@",1);if(at2!==-1)s3=s3.slice(0,at2)}else{const at2=s3.indexOf("@");if(at2!==-1)s3=s3.slice(0,at2)}const base=s3.split(/[\\/]/).pop()??s3;return base.replace(/\.(js|ts|mjs|cjs|json)$/i,"")}function isBiliSelf(entry){const name=entryName(entry);if(name==="billion-context")return true;return/[/\\]billion-context([/\\]|$)/.test(entry.trim())}function classifyOpencodeEntry(c,entry,source){if(isBiliSelf(entry))return;const trimmed=entry.trim();if(/^opencode-acp(@|$)/.test(trimmed)||/[/\\]opencode-acp([/\\]|$)/.test(trimmed)){add(c,{client:"opencode",entry,source,match:"known",knownId:"opencode-acp"});return}if(KEYWORD_RE.test(entryName(entry))){add(c,{client:"opencode",entry,source,match:"keyword"})}}function opencodePluginEntries(root,source,c){const arr=root?.plugin;if(!Array.isArray(arr))return;for(const item of arr){if(typeof item==="string"&&item!=="")classifyOpencodeEntry(c,item,source);else if(item&&typeof item==="object"){const name=item.name;if(typeof name==="string"&&name!=="")classifyOpencodeEntry(c,name,source)}}}function scanOpencode(env,cwd){const c={findings:[],sources:0,seen:new Set};try{const root=readOpencodeConfigRoot(env);if(root){opencodePluginEntries(root,"global config",c);c.sources+=1}}catch{}try{const start=path20.resolve(cwd);let gitRoot;let cur=start;for(;;){if(fs8.existsSync(path20.join(cur,".git"))){gitRoot=cur;break}const parent=path20.dirname(cur);if(parent===cur)break;cur=parent}const dirs=[];cur=start;for(;;){dirs.push(cur);if(gitRoot===void 0||cur===gitRoot)break;const parent=path20.dirname(cur);if(parent===cur)break;cur=parent}for(const dir of dirs){for(const file of[...OPENCODE_CONFIG_FILES,...OPENCODE_CONFIG_FILES.map(f2=>`.opencode/${f2}`)]){const full=path20.join(dir,file);let text;try{text=fs8.readFileSync(full,"utf8")}catch{continue}const parsed=parseConfigText(text);if(!parsed)continue;opencodePluginEntries(parsed,full,c);c.sources+=1}}}catch{}return{client:"opencode",findings:c.findings,sourcesScanned:c.sources}}function scanPi(env,cwd){const c={findings:[],sources:0,seen:new Set};const files=[path20.join(resolvePiHome(env),"settings.json"),path20.join(path20.resolve(cwd),".pi","settings.json")];for(const file of files){let obj;try{obj=JSON.parse(fs8.readFileSync(file,"utf8"))}catch{continue}if(!obj||typeof obj!=="object")continue;const packages=obj.packages;if(!Array.isArray(packages))continue;c.sources+=1;for(const p2 of packages){if(typeof p2!=="string"||p2==="")continue;if(isBiliSelf(p2))continue;if(isLegacyBcpEntry(p2)){add(c,{client:"pi",entry:p2,source:file,match:"known",knownId:"billion-context-pi"});continue}if(KEYWORD_RE.test(entryName(p2)))add(c,{client:"pi",entry:p2,source:file,match:"keyword"})}}return{client:"pi",findings:c.findings,sourcesScanned:c.sources}}function scanOmp(env){const c={findings:[],sources:0,seen:new Set};const file=path20.join(resolveOmpHome(env),"config.yml");let text;try{text=fs8.readFileSync(file,"utf8")}catch{return{client:"omp",findings:[],sourcesScanned:0}}c.sources+=1;const lines=text.split(/\r?\n/);let inBlock=false;for(const line of lines){if(/^extensions:(\s+(#.*)?)?$/.test(line)){inBlock=true;continue}if(inBlock){const item=/^\s+-\s+(.*)$/.exec(line);if(item){const entry=item[1].trim().replace(/^["']|["']$/g,"");if(!entry||isBiliSelf(entry))continue;if(KEYWORD_RE.test(entryName(entry)))add(c,{client:"omp",entry,source:file,match:"keyword"});continue}if(/^\S/.test(line))inBlock=false}}return{client:"omp",findings:c.findings,sourcesScanned:c.sources}}function scanKimi(env){const c={findings:[],sources:0,seen:new Set};const pluginsDir=path20.join(resolveKimiHome(env),"plugins");const registry3=path20.join(pluginsDir,"installed.json");let ids=[];try{const parsed=JSON.parse(fs8.readFileSync(registry3,"utf8"));if(Array.isArray(parsed.plugins)){ids=parsed.plugins.map(p2=>typeof p2.id==="string"?p2.id:"").filter(s3=>s3!=="");c.sources+=1}}catch{}if(ids.length===0){try{ids=fs8.readdirSync(pluginsDir,{withFileTypes:true}).filter(e=>e.isDirectory()&&e.name!=="managed"&&e.name!=="node_modules").map(e=>e.name);c.sources+=1}catch{}}for(const id of ids){if(id==="billion-context")continue;if(KEYWORD_RE.test(id))add(c,{client:"kimi",entry:id,source:registry3,match:"keyword"})}return{client:"kimi",findings:c.findings,sourcesScanned:c.sources}}function scanHermes(env){const c={findings:[],sources:0,seen:new Set};const pluginsDir=path20.join(resolveHermesHome(env),"plugins");let entries;try{entries=fs8.readdirSync(pluginsDir,{withFileTypes:true})}catch{return{client:"hermes",findings:[],sourcesScanned:0}}c.sources+=1;for(const e of entries){if(!e.isDirectory()||e.name==="billion-context")continue;if(KEYWORD_RE.test(e.name))add(c,{client:"hermes",entry:e.name,source:path20.join(pluginsDir,e.name),match:"keyword"})}return{client:"hermes",findings:c.findings,sourcesScanned:c.sources}}function scanDsh(env){const c={findings:[],sources:0,seen:new Set};let dirs;try{dirs=dshProfileDirs(env)}catch{return{client:"dsh",findings:[],sourcesScanned:0}}for(const dir of dirs){const file=path20.join(dir,"package.json");let obj;try{obj=JSON.parse(fs8.readFileSync(file,"utf8"))}catch{continue}c.sources+=1;for(const key2 of["dependencies","devDependencies"]){const deps=obj[key2];if(!deps||typeof deps!=="object"||Array.isArray(deps))continue;for(const dep of Object.keys(deps)){if(dep==="billion-context")continue;if(KEYWORD_RE.test(dep))add(c,{client:"dsh",entry:dep,source:file,match:"keyword"})}}}return{client:"dsh",findings:c.findings,sourcesScanned:c.sources}}function claudeSettingsFiles(env,cwd){const home=env.CLAUDE_CONFIG_DIR??path20.join(env.HOME??env.USERPROFILE??".",".claude");return[path20.join(home,"settings.json"),path20.join(path20.resolve(cwd),".claude","settings.json")]}function scanClaude(env,cwd){const c={findings:[],sources:0,seen:new Set};for(const file of claudeSettingsFiles(env,cwd)){let obj;try{obj=JSON.parse(fs8.readFileSync(file,"utf8"))}catch{continue}if(!obj||typeof obj!=="object")continue;c.sources+=1;const enabled=obj.enabledPlugins;if(enabled&&typeof enabled==="object"&&!Array.isArray(enabled)){for(const name of Object.keys(enabled)){if(KEYWORD_RE.test(name))add(c,{client:"claude",entry:name,source:file,match:"keyword"})}}const plugins=obj.plugins;if(Array.isArray(plugins)){for(const p2 of plugins){if(typeof p2==="string"&&p2!==""&&KEYWORD_RE.test(p2))add(c,{client:"claude",entry:p2,source:file,match:"keyword"})}}}try{const dir=path20.join(env.CLAUDE_CONFIG_DIR??path20.join(env.HOME??env.USERPROFILE??".",".claude"),"plugins");for(const e of fs8.readdirSync(dir,{withFileTypes:true})){if(!e.isDirectory())continue;if(KEYWORD_RE.test(e.name))add(c,{client:"claude",entry:e.name,source:path20.join(dir,e.name),match:"keyword"})}}catch{}return{client:"claude",findings:c.findings,sourcesScanned:c.sources}}function scanClientPlugins(client,opts={}){const env=opts.env??process.env;const cwd=opts.cwd??process.cwd();const key2=`${client}\0${cwd}`;const hit=cache4.get(key2);if(hit&&Date.now()-hit.at<SCAN_CACHE_TTL_MS)return hit.result;let result;switch(client){case"opencode":result=scanOpencode(env,cwd);break;case"pi":result=scanPi(env,cwd);break;case"omp":result=scanOmp(env);break;case"kimi":result=scanKimi(env);break;case"hermes":result=scanHermes(env);break;case"dsh":result=scanDsh(env);break;case"claude":result=scanClaude(env,cwd);break;default:result=empty(client);break}cache4.set(key2,{at:Date.now(),result});return result}var TS_RE=/^(\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?Z)/;function parseTs(line){const m2=TS_RE.exec(line);if(!m2)return NaN;const v2=Date.parse(m2[1]);return Number.isFinite(v2)?v2:NaN}function timestampsOf(all){const out=new Array(all.length);let last=NaN;for(let i=0;i<all.length;i++){const p2=parseTs(all[i]);if(Number.isFinite(p2))last=p2;out[i]=last}return out}function queryLogLines(all,q2,opts){const n=Math.max(1,Math.floor(opts.n));const qLower=q2.toLowerCase();const lower=qLower?all.map(l=>l.toLowerCase()):null;const matches=[];if(qLower){for(let i=0;i<all.length;i++)if(lower[i].includes(qLower))matches.push(i)}const total=qLower?matches.length:all.length;if(total===0||all.length===0){return{total,shown:0,omitted:0,lines:[],...qLower?{isMatch:[]}:{}}}let included;if(!qLower){included=[];for(let i=0;i<all.length;i++)included.push(i)}else if(opts.winSec>0){const ts2=timestampsOf(all);const tF=ts2[matches[0]];const tL=ts2[matches[matches.length-1]];if(Number.isFinite(tF)&&Number.isFinite(tL)){const loT=tF-opts.winSec*1e3;const hiT=tL+opts.winSec*1e3;let loIdx=matches[0];while(loIdx>0&&Number.isFinite(ts2[loIdx-1])&&ts2[loIdx-1]>=loT)loIdx--;let hiIdx=matches[matches.length-1];while(hiIdx<all.length-1&&Number.isFinite(ts2[hiIdx+1])&&ts2[hiIdx+1]<=hiT)hiIdx++;included=[];for(let i=loIdx;i<=hiIdx;i++)included.push(i)}else{included=matches.slice()}}else if(opts.ctx>0){const ranges=[];for(const m2 of matches){const lo2=Math.max(0,m2-opts.ctx);const hi2=Math.min(all.length-1,m2+opts.ctx);const lastR=ranges[ranges.length-1];if(lastR&&lo2<=lastR[1]+1)lastR[1]=Math.max(lastR[1],hi2);else ranges.push([lo2,hi2])}included=[];for(const[lo2,hi2]of ranges)for(let i=lo2;i<=hi2;i++)included.push(i)}else{included=matches.slice()}let omitted=0;if(included.length>n){omitted=included.length-n;included=included.slice(-n)}return{total,shown:included.length,omitted,lines:included.map(i=>all[i]),...qLower?{isMatch:included.map(i=>lower[i].includes(qLower))}:{}}}import{createHash as createHash12,randomUUID as randomUUID5}from"crypto";import fs9 from"fs";import path21 from"path";function isProxyInstanceFile(v2){return v2!==void 0&&"instanceId"in v2}function readProxyInstanceFile(file){let raw;try{raw=fs9.readFileSync(file??instanceFilePath(),"utf8").trim()}catch{return void 0}if(raw.startsWith("{")){try{const parsed=JSON.parse(raw);if(typeof parsed.origin==="string"&&/^https?:\/\/\S+$/.test(parsed.origin)){const windows={};if(parsed.modelWindows&&typeof parsed.modelWindows==="object"){for(const[k2,v2]of Object.entries(parsed.modelWindows)){const n=Number(v2);if(Number.isFinite(n)&&n>0)windows[k2]=n}}const maxOutputs={};if(parsed.modelMaxOutputs&&typeof parsed.modelMaxOutputs==="object"){for(const[k2,v2]of Object.entries(parsed.modelMaxOutputs)){const n=Number(v2);if(Number.isFinite(n)&&n>0)maxOutputs[k2]=n}}return{origin:parsed.origin,instanceId:typeof parsed.instanceId==="string"?parsed.instanceId:"",pid:typeof parsed.pid==="number"?parsed.pid:0,startedAt:typeof parsed.startedAt==="number"?parsed.startedAt:0,host:typeof parsed.host==="string"?parsed.host:"",port:typeof parsed.port==="number"?parsed.port:0,passthrough:Boolean(parsed.passthrough),mitmDomains:Array.isArray(parsed.mitmDomains)?parsed.mitmDomains.map(String):[],modelWindows:windows,modelMaxOutputs:Object.keys(maxOutputs).length>0?maxOutputs:void 0,launchToken:typeof parsed.launchToken==="string"?parsed.launchToken:void 0,lane:typeof parsed.lane==="string"&&parsed.lane!==""?parsed.lane:void 0,codeFingerprint:typeof parsed.codeFingerprint==="string"&&parsed.codeFingerprint!==""?parsed.codeFingerprint:void 0}}}catch{}}if(/^https?:\/\/\S+$/.test(raw))return{origin:raw};return void 0}function instanceFilePath(){return path21.join(stateDir(),"proxy-origin")}function portZoneFilePath(){return path21.join(stateDir(),"port-zone.json")}function readZonePort(lane,file=portZoneFilePath()){let raw;try{raw=fs9.readFileSync(file,"utf8")}catch{return void 0}try{const parsed=JSON.parse(raw);const v2=parsed?.lanes?.[lane];if(typeof v2==="number"&&Number.isInteger(v2)&&v2>0&&v2<65536)return v2;return void 0}catch{return void 0}}function writeZonePort(lane,port,file=portZoneFilePath()){if(!Number.isInteger(port)||port<=0||port>=65536)return;let cur={};try{const parsed=JSON.parse(fs9.readFileSync(file,"utf8"));if(parsed!==null&&typeof parsed==="object"&&parsed.lanes!==null&&typeof parsed.lanes==="object")cur=parsed}catch{}atomicWriteJson({lanes:{...cur.lanes??{},[lane]:port}},file)}function lanePreferredPort(lane,env=process.env,file=portZoneFilePath()){return readZonePort(lane,file)??resolveZonePortBase(env)}function findSameLanePredecessor(entries,port,lane,ownFingerprint){if(!lane||!ownFingerprint)return void 0;for(const e of entries){if(e.port!==port||e.lane!==lane)continue;if(!isPidAlive(e.pid))continue;if(e.codeFingerprint!==ownFingerprint)return e}return void 0}var scriptFingerprints=new Map;function entryScriptFingerprint(scriptPath){if(!scriptPath)return void 0;const resolved=path21.resolve(scriptPath);const cached=scriptFingerprints.get(resolved);if(cached!==void 0)return cached;let digest;try{digest=createHash12("sha256").update(fs9.readFileSync(resolved)).digest("hex")}catch{return void 0}scriptFingerprints.set(resolved,digest);return digest}function atomicWriteJson(obj,filePath){fs9.mkdirSync(path21.dirname(filePath),{recursive:true});const tempPath=`${filePath}.${process.pid}.${randomUUID5()}.tmp`;let descriptor;try{descriptor=fs9.openSync(tempPath,"wx",420);fs9.writeSync(descriptor,JSON.stringify(obj)+"\n",null,"utf8");fs9.fsyncSync(descriptor);fs9.closeSync(descriptor);descriptor=void 0;fs9.renameSync(tempPath,filePath)}catch(error){if(descriptor!==void 0){try{fs9.closeSync(descriptor)}catch{}}try{fs9.unlinkSync(tempPath)}catch{}throw error}}function atomicWriteInstanceFile(info,file){atomicWriteJson(info,file??instanceFilePath())}function clearProxyInstanceFile(instanceId,file){const filePath=file??instanceFilePath();const current=readProxyInstanceFile(filePath);if(isProxyInstanceFile(current)&¤t.instanceId===instanceId){try{fs9.unlinkSync(filePath)}catch{}}}function startingMarkerPath(){return path21.join(stateDir(),"proxy-starting")}function readStartingMarker(file){let raw;try{raw=fs9.readFileSync(file??startingMarkerPath(),"utf8")}catch{return void 0}try{const parsed=JSON.parse(raw);if(typeof parsed.token!=="string"||parsed.token==="")return void 0;if(typeof parsed.pid!=="number"||!Number.isInteger(parsed.pid)||parsed.pid<=0)return void 0;if(typeof parsed.startedAt!=="number")return void 0;return{token:parsed.token,pid:parsed.pid,host:typeof parsed.host==="string"?parsed.host:"",port:typeof parsed.port==="number"?parsed.port:0,startedAt:parsed.startedAt,...typeof parsed.lane==="string"&&parsed.lane!==""?{lane:parsed.lane}:{}}}catch{return void 0}}function claimStartingMarker(marker,file){const filePath=file??startingMarkerPath();let descriptor;try{fs9.mkdirSync(path21.dirname(filePath),{recursive:true});descriptor=fs9.openSync(filePath,"wx",420);fs9.writeSync(descriptor,JSON.stringify(marker)+"\n",null,"utf8");fs9.fsyncSync(descriptor);descriptor=void 0;return true}catch{if(descriptor!==void 0){try{fs9.closeSync(descriptor)}catch{}}return false}}function clearStartingMarker(token,file){const filePath=file??startingMarkerPath();const current=readStartingMarker(filePath);if(current&¤t.token===token){try{fs9.unlinkSync(filePath)}catch{}}}function removeStartingMarker(file){try{fs9.unlinkSync(file??startingMarkerPath())}catch{}}function isPidAlive(pid){if(!Number.isInteger(pid)||pid<=0)return false;try{process.kill(pid,0);return true}catch(err2){return err2.code==="EPERM"}}function registryDirPath(){return path21.join(stateDir(),"instances")}function legacyRegistryFilePath(){return path21.join(stateDir(),"instances.json")}var SAFE_NAME_RE=/^[A-Za-z0-9][A-Za-z0-9._-]*$/;function safeRegistryName(instanceId){if(instanceId!=="."&&instanceId!==".."&&instanceId.length<=128&&SAFE_NAME_RE.test(instanceId)){return instanceId}return createHash12("sha256").update(instanceId).digest("hex")}function registryEntryFile(instanceId){return path21.join(registryDirPath(),`${safeRegistryName(instanceId)}.json`)}function safeReadJson2(file){try{return JSON.parse(fs9.readFileSync(file,"utf8"))}catch{return void 0}}function coerceEntry(value){if(!value||typeof value!=="object")return void 0;const o=value;if(typeof o.instanceId!=="string"||o.instanceId==="")return void 0;const windows={};if(o.modelWindows&&typeof o.modelWindows==="object"){for(const[k2,v2]of Object.entries(o.modelWindows)){const n=Number(v2);if(Number.isFinite(n)&&n>0)windows[k2]=n}}const maxOutputs={};if(o.modelMaxOutputs&&typeof o.modelMaxOutputs==="object"){for(const[k2,v2]of Object.entries(o.modelMaxOutputs)){const n=Number(v2);if(Number.isFinite(n)&&n>0)maxOutputs[k2]=n}}return{instanceId:o.instanceId,pid:typeof o.pid==="number"?o.pid:0,port:typeof o.port==="number"?o.port:0,origin:typeof o.origin==="string"?o.origin:"",startedAt:typeof o.startedAt==="number"?o.startedAt:0,...typeof o.host==="string"&&o.host!==""?{host:o.host}:{},...typeof o.passthrough==="boolean"?{passthrough:o.passthrough}:{},...Array.isArray(o.mitmDomains)?{mitmDomains:o.mitmDomains.map(String)}:{},...Object.keys(windows).length>0?{modelWindows:windows}:{},...Object.keys(maxOutputs).length>0?{modelMaxOutputs:maxOutputs}:{},...typeof o.lane==="string"&&o.lane!==""?{lane:o.lane}:{},...typeof o.codeFingerprint==="string"&&o.codeFingerprint!==""?{codeFingerprint:o.codeFingerprint}:{}}}function readMarkerNames(){try{return fs9.readdirSync(registryDirPath())}catch{return[]}}function readAllRegistryEntries(){const seen=new Set;const out=[];for(const name of readMarkerNames()){if(!name.endsWith(".json"))continue;const entry=coerceEntry(safeReadJson2(path21.join(registryDirPath(),name)));if(entry&&!seen.has(entry.instanceId)){seen.add(entry.instanceId);out.push(entry)}}const legacy=safeReadJson2(legacyRegistryFilePath());if(legacy&&Array.isArray(legacy.instances)){for(const raw of legacy.instances){const entry=coerceEntry(raw);if(entry&&!seen.has(entry.instanceId)){seen.add(entry.instanceId);out.push(entry)}}}return out}function listInstances(){return readAllRegistryEntries()}function procMainScript(pid){if(process.platform!=="linux")return void 0;let raw;try{raw=fs9.readFileSync(`/proc/${pid}/cmdline`,"utf8")}catch{return void 0}for(const arg of raw.split("\0")){if(!arg||arg.startsWith("-"))continue;if(arg.includes("/")&&(arg.endsWith(".js")||arg.endsWith(".mjs")||arg.endsWith(".cjs")))return arg}return void 0}function reapDeadMarkers(ours){for(const name of readMarkerNames()){if(!name.endsWith(".json"))continue;const file=path21.join(registryDirPath(),name);const entry=coerceEntry(safeReadJson2(file));if(!entry||entry.instanceId===ours||isPidAlive(entry.pid))continue;try{fs9.unlinkSync(file)}catch{}}}function lanesOverlap(a,b2){return a===void 0||b2===void 0||a===b2}function registerInstanceAndWarn(entry,warn){const others=readAllRegistryEntries().filter(e=>e.instanceId!==entry.instanceId&&isPidAlive(e.pid));for(const other of others){if(!lanesOverlap(entry.lane,other.lane))continue;const laneNote=entry.lane!==void 0&&other.lane!==void 0?` on lane "${entry.lane}"`:"";warn(`another bili instance is running (pid ${other.pid}, ${other.origin})${laneNote} \u2014 both processes will write the same sessions directory; stop one to avoid state pollution (#394)`)}reapDeadMarkers(entry.instanceId);try{atomicWriteJson(entry,registryEntryFile(entry.instanceId))}catch{}}function discoverLiveInstances(){const out=[];for(const e of readAllRegistryEntries()){if(!isPidAlive(e.pid))continue;out.push({origin:e.origin,instanceId:e.instanceId,pid:e.pid,startedAt:e.startedAt,host:e.host??"",port:e.port,passthrough:Boolean(e.passthrough),mitmDomains:e.mitmDomains??[],modelWindows:e.modelWindows??{},modelMaxOutputs:e.modelMaxOutputs,lane:e.lane,codeFingerprint:e.codeFingerprint})}return out}function unregisterInstance(instanceId){try{fs9.unlinkSync(registryEntryFile(instanceId))}catch{}}var SIDE_REQUEST_MAX_TOKENS=200;var SIDE_REQUEST_AGENTS=new Set(["title"]);function isSideRequest(parsed,requestAgent){if(!parsed||typeof parsed!=="object")return false;if(requestAgent!==void 0&&SIDE_REQUEST_AGENTS.has(requestAgent))return true;const p2=parsed;if(Array.isArray(p2.tools)&&p2.tools.length>0)return false;const field=outputBudgetField(parsed);if(!field)return false;const raw=readOutputBudget(p2,field);return typeof raw==="number"&&raw>0&&raw<=SIDE_REQUEST_MAX_TOKENS}var BILI_TOOL_NAMES=new Set([...ACP_TOOL_NAMES,ABSORB_TOOL_NAME,RULE_TOOL_NAME,RETRIEVE_TOOL_NAME,IMAGE_FULL_TOOL_NAME]);function biliToolNamesIn(parsed){const tools=parsed.tools;if(!Array.isArray(tools)||tools.length===0)return null;const names=[];for(const t of tools){if(!t||typeof t!=="object")return null;const o=t;const decls=o.functionDeclarations;if(Array.isArray(decls)){for(const d of decls){if(!d||typeof d!=="object"||typeof d.name!=="string")return null;names.push(d.name)}continue}let name=o.name;if(typeof name!=="string"){const fn=o.function;if(fn&&typeof fn==="object"&&typeof fn.name==="string")name=fn.name}if(typeof name!=="string")return null;names.push(name)}return names}function stripLeakedBiliTools(parsed){if(!parsed||typeof parsed!=="object"||Array.isArray(parsed))return false;const p2=parsed;const names=biliToolNamesIn(p2);if(names===null||!names.every(n=>BILI_TOOL_NAMES.has(n)))return false;const field=outputBudgetField(p2);if(field){const raw=readOutputBudget(p2,field);if(typeof raw==="number"&&raw>0&&raw<=SIDE_REQUEST_MAX_TOKENS)return false}delete p2.tools;return true}function outputBudgetField(parsed){if(!parsed||typeof parsed!=="object")return null;const p2=parsed;for(const field of["max_tokens","max_completion_tokens","max_output_tokens"]){if(typeof p2[field]==="number"&&p2[field]>0)return field}const gen=p2.generationConfig;if(gen&&typeof gen==="object"){const v2=gen.maxOutputTokens;if(typeof v2==="number"&&v2>0)return"generationConfig.maxOutputTokens"}return null}function readOutputBudget(parsed,field){if(field!=="generationConfig.maxOutputTokens"){const v3=parsed[field];return typeof v3==="number"?v3:void 0}const gen=parsed.generationConfig;if(!gen||typeof gen!=="object")return void 0;const v2=gen.maxOutputTokens;return typeof v2==="number"?v2:void 0}function writeOutputBudget(parsed,field,value){const tokens=Number.isInteger(value)?value:Math.floor(value);if(field!=="generationConfig.maxOutputTokens"){parsed[field]=tokens;return}const gen=parsed.generationConfig;parsed.generationConfig={...gen&&typeof gen==="object"?gen:{},maxOutputTokens:tokens}}var warnedNoOutputCeiling=new Set;var WARNED_NO_OUTPUT_CEILING_CAP=4096;function noteNoOutputCeilingWarning(model){if(warnedNoOutputCeiling.has(model))return false;if(warnedNoOutputCeiling.size>=WARNED_NO_OUTPUT_CEILING_CAP)warnedNoOutputCeiling.clear();warnedNoOutputCeiling.add(model);return true}function restoreOutputBudget(parsed,session,log2,outputCeiling){const field=outputBudgetField(parsed);if(!field)return;const p2=parsed;const value=readOutputBudget(p2,field);if(value===void 0)return;if(value>SIDE_REQUEST_MAX_TOKENS){session.metadata.outputBudgetHighWater=value;return}if(!Array.isArray(p2.tools)||p2.tools.length===0)return;const highWaterRaw=session.metadata.outputBudgetHighWater;const highWater=typeof highWaterRaw==="number"&&highWaterRaw>SIDE_REQUEST_MAX_TOKENS?highWaterRaw:void 0;let target=highWater;const ceiling=typeof outputCeiling==="number"&&outputCeiling>SIDE_REQUEST_MAX_TOKENS?outputCeiling:void 0;if(ceiling!==void 0&&(target===void 0||ceiling>target))target=ceiling;const modelName=typeof p2.model==="string"&&p2.model.length>0?p2.model:"?";if(typeof target==="number"){writeOutputBudget(p2,field,target);const note=target===ceiling&&ceiling!==void 0?highWater===void 0?"; no healthy high-water yet \u2014 using known output ceiling (#1665/#1840)":`; high-water ${highWater} below known output ceiling \u2014 floored (#1665/#1840)`:"";log2("info",`[${session.id}] output budget restored ${value} -> ${target} (#546: client shrank it from its raw-history estimate${note})`)}if(ceiling===void 0&¬eNoOutputCeilingWarning(modelName)){log2("warn",`[${session.id}] output-budget restore has NO known output ceiling for model=${modelName}${typeof target==="number"?` (restored ${value} -> ${target})`:` (starved budget ${value} forwarded verbatim)`} \u2014 the target is the client's own last non-starved budget; while it stays pathologically small every turn truncates at max-tokens. Declare the model's max output in the bili config (providers.<url>.models."${modelName}".output) or have the client report it to floor the restore (#1840)`)}}var SIDE_REQUEST_GUARD_TOLERANCE=1.15;function sideRequestGuard(parsed,protocol,modelContextLimit,imageBilling="bytes",configuredCap,headroomCap=1,armedLimit=0,imageReserve){let limit=modelContextLimit;if(armedLimit>0&&(limit<=0||armedLimit<limit))limit=armedLimit;const field=outputBudgetField(parsed);const maxOut=(field?readOutputBudget(parsed,field):void 0)??0;if(limit>0&&shouldReserveOutputHeadroom(protocol))limit=reserveOutputHeadroom(limit,maxOut,headroomCap);const imageMass=imageReserve??imageTokensInParsedBody(protocol,parsed,imageBilling,configuredCap);const estimate=estimateRawBodyTokens(parsed)+imageMass;return{blocked:limit>0&&estimate>=limit*SIDE_REQUEST_GUARD_TOLERANCE,estimate,limit}}var OUTPUT_CLAMP_MARGIN_PCT=.05;var OUTPUT_CLAMP_MIN_MARGIN=2048;var OUTPUT_CLAMP_FLOOR=1024;var EMERGENCY_NUDGE_ESCALATION_PCT=.7;function countSystemAndToolsTokens(systemText,tools){return defaultCountTokens(systemText??"")+defaultCountTokens(JSON.stringify(tools??[]))}function estimateInputTokens(processedMessages,systemText,tools,lastInputTokens,lastInputTokensSource){const est=estimateCoreMessages(processedMessages)+countSystemAndToolsTokens(systemText,tools);const baseline=lastInputTokens>0&&lastInputTokensSource==="usage"?lastInputTokens:0;return Math.max(baseline,est)}function projectThinkingMass(msgs,input){if(!input.measured||!(input.providerInputTokens>0))return 0;const targets=[];for(const m2 of msgs){if(m2.contentType!=="reasoning")continue;if(typeof m2.thinkingSignature!=="string"||m2.thinkingSignature.length===0)continue;if(typeof m2.text==="string"&&m2.text.trim().length>0)continue;targets.push({msg:m2,sig:m2.thinkingSignature.length})}if(targets.length===0)return 0;const overhead=typeof input.storedOverhead==="number"&&Number.isFinite(input.storedOverhead)&&input.storedOverhead>0?input.storedOverhead:countSystemAndToolsTokens(input.systemText,input.tools);const gap=Math.max(0,input.providerInputTokens-estimateCoreMessages(msgs)-overhead-Math.max(0,input.imageTokens));if(gap<=0)return 0;const totalSig=targets.reduce((s3,t)=>s3+t.sig,0);let assigned=0;for(let i=0;i<targets.length;i++){const t=targets[i];const share=i===targets.length-1?gap-assigned:Math.floor(gap*t.sig/totalSig);t.msg.thinkingTokens=share;assigned+=share}return gap}function estimateWireOverhead(protocol,body){let parsed;try{parsed=JSON.parse(typeof body==="string"?body:body.toString("utf8"))}catch{return 0}const sysRaw=protocol==="responses"?parsed.instructions:protocol==="google"?googleSystemText(parsed):parsed.system;let sysText="";if(typeof sysRaw==="string"){sysText=sysRaw}else if(Array.isArray(sysRaw)){sysText=sysRaw.map(part=>typeof part?.text==="string"?part.text:"").join("\n")}if(protocol==="openai"&&Array.isArray(parsed.messages)){const hoisted=parsed.messages.filter(m2=>m2.role==="system"||m2.role==="developer").map(m2=>typeof m2.content==="string"?m2.content:"").join("\n");sysText=sysText?`${sysText}
|
|
2571
2571
|
${hoisted}`:hoisted}if(protocol==="responses"&&Array.isArray(parsed.input)){const hoisted=parsed.input.filter(item=>item.role==="system"||item.role==="developer").map(item=>{const c=item.content;if(typeof c==="string")return c;if(Array.isArray(c)){return c.map(p2=>p2&&typeof p2==="object"&&typeof p2.text==="string"?p2.text:"").join("\n")}return""}).filter(t=>t.length>0).join("\n");if(hoisted)sysText=sysText?`${sysText}
|
|
2572
|
-
${hoisted}`:hoisted}return defaultCountTokens(sysText)+defaultCountTokens(JSON.stringify(parsed.tools??[]))}function clampOutputBudget(requested,inputEstimate,nativeWindow){const margin=Math.max(OUTPUT_CLAMP_MIN_MARGIN,Math.ceil(inputEstimate*OUTPUT_CLAMP_MARGIN_PCT));const cap=nativeWindow-inputEstimate-margin;if(cap<OUTPUT_CLAMP_FLOOR||cap>=requested)return void 0;return cap}function emergencyNudge(nudge,escalationPct=EMERGENCY_NUDGE_ESCALATION_PCT){if(!nudge||nudge.shouldInject)return false;if(nudge.compressibleRanges.length===0)return false;return nudge.contextUsage>=escalationPct}function clampOutgoingOutput(rebuilt,field,ctx,sessionId,log2){const raw=readOutputBudget(rebuilt,field);if(typeof raw!=="number")return;const inputEstimate=estimateInputTokens(ctx.processedMessages,ctx.systemText,ctx.tools,ctx.lastInputTokens,ctx.lastInputTokensSource)+ctx.imageTokens;const capped=clampOutputBudget(raw,inputEstimate,ctx.nativeWindow);if(capped!==void 0){writeOutputBudget(rebuilt,field,capped);log2("info",`[${sessionId}] output budget clamped ${raw} -> ${capped} (input~${inputEstimate}, window=${ctx.nativeWindow}); prevents input+output overflow (#453)`)}}import fs10 from"fs";import path22 from"path";var DEFAULT_MAX_BYTES=2*1024*1024;var failCount=0;var lastFailLog=0;function warnDumpFailure(err2){failCount++;const now=Date.now();if(failCount===1||now-lastFailLog>=6e4){lastFailLog=now;const msg=err2 instanceof Error?err2.message:String(err2);log("warn",`[dump] rejected-body dump failed (total ${failCount}x): ${msg}`)}}function dumpRejectedBody(status,sessionId,body){if(process.env.BILI_DUMP_4XX!=="1")return null;const raw=typeof body==="string"?body:body.toString("utf8");if(!raw)return null;try{const cap=Math.max(1024,Number(process.env.BILI_DUMP_4XX_MAX_BYTES)||DEFAULT_MAX_BYTES);let text;let marker="";if(raw.length>cap){text=raw.slice(0,cap);marker=`
|
|
2572
|
+
${hoisted}`:hoisted}return defaultCountTokens(sysText)+defaultCountTokens(JSON.stringify(parsed.tools??[]))}function clampOutputBudget(requested,inputEstimate,nativeWindow){const margin=Math.max(OUTPUT_CLAMP_MIN_MARGIN,Math.ceil(inputEstimate*OUTPUT_CLAMP_MARGIN_PCT));const cap=Math.floor(nativeWindow-inputEstimate-margin);if(cap<OUTPUT_CLAMP_FLOOR||cap>=requested)return void 0;return cap}function emergencyNudge(nudge,escalationPct=EMERGENCY_NUDGE_ESCALATION_PCT){if(!nudge||nudge.shouldInject)return false;if(nudge.compressibleRanges.length===0)return false;return nudge.contextUsage>=escalationPct}function clampOutgoingOutput(rebuilt,field,ctx,sessionId,log2){const raw=readOutputBudget(rebuilt,field);if(typeof raw!=="number")return;const inputEstimate=estimateInputTokens(ctx.processedMessages,ctx.systemText,ctx.tools,ctx.lastInputTokens,ctx.lastInputTokensSource)+ctx.imageTokens;const capped=clampOutputBudget(raw,inputEstimate,ctx.nativeWindow);if(capped!==void 0){writeOutputBudget(rebuilt,field,capped);log2("info",`[${sessionId}] output budget clamped ${raw} -> ${capped} (input~${inputEstimate}, window=${ctx.nativeWindow}); prevents input+output overflow (#453)`)}}import fs10 from"fs";import path22 from"path";var DEFAULT_MAX_BYTES=2*1024*1024;var failCount=0;var lastFailLog=0;function warnDumpFailure(err2){failCount++;const now=Date.now();if(failCount===1||now-lastFailLog>=6e4){lastFailLog=now;const msg=err2 instanceof Error?err2.message:String(err2);log("warn",`[dump] rejected-body dump failed (total ${failCount}x): ${msg}`)}}function dumpRejectedBody(status,sessionId,body){if(process.env.BILI_DUMP_4XX!=="1")return null;const raw=typeof body==="string"?body:body.toString("utf8");if(!raw)return null;try{const cap=Math.max(1024,Number(process.env.BILI_DUMP_4XX_MAX_BYTES)||DEFAULT_MAX_BYTES);let text;let marker="";if(raw.length>cap){text=raw.slice(0,cap);marker=`
|
|
2573
2573
|
[truncated: ${raw.length-cap} more character(s)]
|
|
2574
2574
|
`}else{try{text=JSON.stringify(JSON.parse(raw),null,2)}catch{text=raw}}const dir=dumpsDir();fs10.mkdirSync(dir,{recursive:true});const sid=sessionId.replace(/[^a-zA-Z0-9_-]/g,"_");const out=path22.join(dir,`err-${Date.now()}-${sid}-${status}.json`);fs10.writeFileSync(out,`${text}${marker}`);log("info",`[dump] upstream ${status} rejected body written to ${out}`);return out}catch(err2){warnDumpFailure(err2);return null}}function isStrictReasoningEcho(session,upstreamOrigin,model){if(session.metadata.strictReasoningEcho===true)return true;if(upstreamOrigin!==void 0&&/deepseek/i.test(upstreamOrigin))return true;return typeof model==="string"&&model.length>0&&/deepseek/i.test(model)}function modelIdOf(body){const m2=body?.model;return typeof m2==="string"?m2:void 0}function normalizeStrictEchoReasoning(messages,enabled,log2,sessionId){if(!enabled)return messages;let patched=0;const out=messages.map(m2=>{if(m2.role!=="assistant")return m2;if(!Array.isArray(m2.tool_calls)||m2.tool_calls.length===0)return m2;if(typeof m2.reasoning_content==="string")return m2;patched++;return{...m2,reasoning_content:""}});if(patched>0){log2("info",`[${sessionId}] strict-echo: injected blank reasoning_content on ${patched} assistant tool-call message(s) (#762)`)}return patched>0?out:messages}function normalizeStrictEchoResponsesInput(input,enabled,log2,sessionId){if(!enabled)return input;let hasReasoning=false;for(const it2 of input){if(it2?.type==="reasoning"){hasReasoning=true;break}}if(!hasReasoning)return input;const insertAt=new Set;let runStart=-1;let runCalls=0;let runReasoning=0;const closeRun=()=>{if(runStart>=0&&runCalls>0&&runReasoning===0)insertAt.add(runStart);runStart=-1;runCalls=0;runReasoning=0};for(let i=0;i<input.length;i++){const it2=input[i];const t=typeof it2?.type==="string"?it2.type:void 0;const inRun=t==="reasoning"||t==="function_call"||t==="custom_tool_call"||t==="function_call_output"||t==="custom_tool_call_output"||t==="message"&&it2?.role==="assistant";if(!inRun){closeRun();continue}if(runStart<0)runStart=i;if(t==="function_call"||t==="custom_tool_call")runCalls++;else if(t==="reasoning")runReasoning++}closeRun();if(insertAt.size===0)return input;const out=[];for(let i=0;i<input.length;i++){if(insertAt.has(i))out.push({type:"reasoning",summary:[{type:"summary_text",text:""}]});out.push(input[i])}log2("info",`[${sessionId}] strict-echo-responses: injected ${insertAt.size} blank reasoning item(s) before tool-call run(s) missing their echo (#1479)`);return out}function normalizeStrictEchoBody(body,enabled,log2,sessionId){if(!enabled)return body;let out=body;if(Array.isArray(body.messages)){const patched=normalizeStrictEchoReasoning(body.messages,true,log2,sessionId);if(patched!==body.messages)out={...out,messages:patched}}if(Array.isArray(body.input)){const patched=normalizeStrictEchoResponsesInput(body.input,true,log2,sessionId);if(patched!==body.input)out={...out,input:patched}}return out}function appendTrailingUserText(protocol,body,text){const raw=typeof body==="string"?body:body.toString("utf8");let obj;try{obj=JSON.parse(raw)}catch{return null}if(protocol==="responses"){const input=obj.input;if(!Array.isArray(input))return null;const arr2=input;const last2=arr2[arr2.length-1];if(last2&&typeof last2==="object"&&last2.role==="user"){const c=last2.content;if(typeof c==="string")last2.content=`${c}
|
|
2575
2575
|
|