@astralyn/pi 1.4.0 → 1.4.1
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/CHANGELOG.md +6 -0
- package/dist/bundle/chunks/{chunk-BMTEURL3.js → chunk-KSKBY3VV.js} +62 -7
- package/dist/bundle/chunks/{chunk-TJIPCBZF.js → chunk-N77PYEXG.js} +1 -1
- package/dist/bundle/chunks/{virtual-modules-3CTTTQQN.js → virtual-modules-XNEYDLXF.js} +1 -1
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +5 -5
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/extensions/cached-compaction/index.d.ts +3 -0
- package/dist/extensions/cached-compaction/index.d.ts.map +1 -0
- package/dist/extensions/cached-compaction/index.js +91 -0
- package/dist/extensions/cached-compaction/index.js.map +1 -0
- package/dist/extensions/cached-compaction/render.d.ts +11 -0
- package/dist/extensions/cached-compaction/render.d.ts.map +1 -0
- package/dist/extensions/cached-compaction/render.js +19 -0
- package/dist/extensions/cached-compaction/render.js.map +1 -0
- package/dist/extensions/cached-compaction/summary.d.ts +15 -0
- package/dist/extensions/cached-compaction/summary.d.ts.map +1 -0
- package/dist/extensions/cached-compaction/summary.js +131 -0
- package/dist/extensions/cached-compaction/summary.js.map +1 -0
- package/dist/extensions/index.d.ts.map +1 -1
- package/dist/extensions/index.js +2 -0
- package/dist/extensions/index.js.map +1 -1
- package/docs/bundled/extensions/cached-compaction.md +35 -0
- package/docs/compaction.md +1 -1
- package/docs/docs.json +4 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
|
@@ -728,7 +728,7 @@ ${sections.join(`
|
|
|
728
728
|
|
|
729
729
|
`)}var SUMMARIZATION_SYSTEM_PROMPT=`You are a context summarization assistant. Your task is to read a conversation between a user and an AI assistant, then produce a structured summary following the exact format specified.
|
|
730
730
|
|
|
731
|
-
Do NOT continue the conversation. Do NOT respond to any questions in the conversation. ONLY output the structured summary.`;function createUsageTotals(){return{input:0,output:0,cacheRead:0,cacheWrite:0,cost:0}}function addUsageToTotals(totals,usage){totals.input+=usage.input,totals.output+=usage.output,totals.cacheRead+=usage.cacheRead,totals.cacheWrite+=usage.cacheWrite,totals.cost+=usage.cost.total}function combineUsage(first,second){return{input:first.input+second.input,output:first.output+second.output,cacheRead:first.cacheRead+second.cacheRead,cacheWrite:first.cacheWrite+second.cacheWrite,...first.cacheWrite1h!==void 0||second.cacheWrite1h!==void 0?{cacheWrite1h:(first.cacheWrite1h??0)+(second.cacheWrite1h??0)}:{},...first.reasoning!==void 0||second.reasoning!==void 0?{reasoning:(first.reasoning??0)+(second.reasoning??0)}:{},totalTokens:first.totalTokens+second.totalTokens,cost:{input:first.cost.input+second.cost.input,output:first.cost.output+second.cost.output,cacheRead:first.cost.cacheRead+second.cost.cacheRead,cacheWrite:first.cost.cacheWrite+second.cost.cacheWrite,total:first.cost.total+second.cost.total}}}var TASK_USAGE_TYPE="task-usage";function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function isUsageValue(value){return typeof value=="number"&&Number.isFinite(value)&&value>=0}function getTaskUsageRecord(entry){if(entry.type!=="custom"||entry.customType!==TASK_USAGE_TYPE)return;let data=entry.data;if(!isRecord(data)||data.version!==1||typeof data.taskId!="string"||!data.taskId.trim())return;let usage=data.usage;if(!isRecord(usage)||!isRecord(usage.cost))return;let{input:input2,output,cacheRead,cacheWrite,totalTokens,reasoning,cacheWrite1h}=usage,cost=usage.cost;if(!(!isUsageValue(input2)||!isUsageValue(output)||!isUsageValue(cacheRead)||!isUsageValue(cacheWrite)||!isUsageValue(totalTokens)||!isUsageValue(cost.input)||!isUsageValue(cost.output)||!isUsageValue(cost.cacheRead)||!isUsageValue(cost.cacheWrite)||!isUsageValue(cost.total)||reasoning!==void 0&&!isUsageValue(reasoning)||cacheWrite1h!==void 0&&!isUsageValue(cacheWrite1h)))return{version:1,taskId:data.taskId,usage:{input:input2,output,cacheRead,cacheWrite,totalTokens,...reasoning===void 0?{}:{reasoning},...cacheWrite1h===void 0?{}:{cacheWrite1h},cost:{input:cost.input,output:cost.output,cacheRead:cost.cacheRead,cacheWrite:cost.cacheWrite,total:cost.total}}}}function*accountedUsageEntries(entries){let backgroundTasks=new Set;for(let entry of entries)if(entry.type==="message"&&entry.message.role==="assistant")yield{key:`${entry.message.provider}/${entry.message.responseModel??entry.message.model}`,usage:entry.message.usage};else if(entry.type==="usage")yield{key:`${entry.provider}/${entry.model}`,usage:entry.usage};else if(entry.type==="message"&&entry.message.role==="toolResult"&&entry.message.usage)yield{key:"Tools/summaries",usage:entry.message.usage};else if((entry.type==="branch_summary"||entry.type==="compaction")&&entry.usage)yield{key:"Tools/summaries",usage:entry.usage};else{let record=getTaskUsageRecord(entry);if(!record||backgroundTasks.has(record.taskId))continue;backgroundTasks.add(record.taskId),yield{key:"Tools/summaries",usage:record.usage}}}function getAccountedUsages(entries){return Array.from(accountedUsageEntries(entries),({usage})=>usage)}function getUsageCostBreakdown(entries){let totalsByKey=new Map;for(let{key,usage}of accountedUsageEntries(entries)){let totals=totalsByKey.get(key);totals||(totals=createUsageTotals(),totalsByKey.set(key,totals)),addUsageToTotals(totals,usage)}return Array.from(totalsByKey,([key,totals])=>({key,cost:totals.cost,tokens:totals.input+totals.output+totals.cacheRead+totals.cacheWrite})).filter(entry=>entry.cost>0||entry.tokens>0).sort((a,b2)=>b2.cost-a.cost)}function extractFileOperations(messages,entries,prevCompactionIndex){let fileOps=createFileOps();if(prevCompactionIndex>=0){let prevCompaction=entries[prevCompactionIndex];if(!prevCompaction.fromHook&&prevCompaction.details){let details=prevCompaction.details;if(Array.isArray(details.readFiles))for(let f2 of details.readFiles)fileOps.read.add(f2);if(Array.isArray(details.modifiedFiles))for(let f2 of details.modifiedFiles)fileOps.edited.add(f2)}}for(let msg of messages)extractFileOpsFromMessage(msg,fileOps);return fileOps}function getMessagesFromProjectedEntryForCompaction(entry){return entry.sourceEntry.type==="compaction"?[]:entry.messages.filter(message=>message.role!=="system")}var DEFAULT_COMPACTION_SETTINGS={enabled:!0,reserveTokens:16384,keepRecentTokens:2e4};function calculateContextTokens(usage){return usage.totalTokens||usage.input+usage.output+usage.cacheRead+usage.cacheWrite}function getAssistantUsage(msg){if(msg.role==="assistant"&&"usage"in msg){let assistantMsg=msg;if(assistantMsg.stopReason!=="aborted"&&assistantMsg.stopReason!=="error"&&assistantMsg.usage&&calculateContextTokens(assistantMsg.usage)>0)return assistantMsg.usage}}function getLastAssistantUsage(entries){for(let i=entries.length-1;i>=0;i--){let entry=entries[i];if(entry.type==="message"){let usage=getAssistantUsage(entry.message);if(usage)return usage}}}function getLastAssistantUsageInfo(messages){for(let i=messages.length-1;i>=0;i--){let usage=getAssistantUsage(messages[i]);if(usage)return{usage,index:i}}}function estimateContextTokens2(messages){let usageInfo=getLastAssistantUsageInfo(messages);if(!usageInfo){let estimated=0;for(let message of messages)estimated+=estimateTokens2(message);return{tokens:estimated,usageTokens:0,trailingTokens:estimated,lastUsageIndex:null}}let usageTokens=calculateContextTokens(usageInfo.usage),trailingTokens=0;for(let i=usageInfo.index+1;i<messages.length;i++)trailingTokens+=estimateTokens2(messages[i]);return{tokens:usageTokens+trailingTokens,usageTokens,trailingTokens,lastUsageIndex:usageInfo.index}}function estimateProjectedContextTokens(projection,branchEntries){let estimate=estimateContextTokens2(projection.messages);if(estimate.lastUsageIndex!==null){let projectedMessageIndex=0,usageEntryId;for(let entry of projection.entries){let nextMessageIndex=projectedMessageIndex+entry.messages.length;if(estimate.lastUsageIndex<nextMessageIndex){usageEntryId=entry.sourceEntry.id;break}projectedMessageIndex=nextMessageIndex}let usageEntryIndex=usageEntryId?branchEntries.findIndex(entry=>entry.id===usageEntryId):-1,latestInvalidatingEntryIndex=-1;for(let i=branchEntries.length-1;i>=0;i--){let entry=branchEntries[i];if(entry.type==="context_edit"||entry.type==="compaction"){latestInvalidatingEntryIndex=i;break}}if(usageEntryIndex>latestInvalidatingEntryIndex)return estimate}let currentSystem=getCurrentSystemMessage(projection.messages),tokens2=currentSystem?estimateTokens2(currentSystem):0;for(let message of projection.messages)message.role!=="system"&&(tokens2+=estimateTokens2(message));return{tokens:tokens2,usageTokens:0,trailingTokens:tokens2,lastUsageIndex:null}}function shouldCompact(contextTokens,contextWindow,settings2){return settings2.enabled?contextTokens>contextWindow-settings2.reserveTokens:!1}var ESTIMATED_IMAGE_CHARS=4800;function estimateTextAndImageContentChars(content){if(typeof content=="string")return content.length;let chars=0;for(let block of content)block.type==="text"&&block.text?chars+=block.text.length:block.type==="image"&&(chars+=ESTIMATED_IMAGE_CHARS);return chars}function estimateTokens2(message){let chars=0;switch(message.role){case"system":{let system=message;if(chars=estimateTextAndImageContentChars(system.content),system.sections)for(let section of Object.values(system.sections))section&&(chars+=section.length);return system.toolsAdded&&(chars+=JSON.stringify(system.toolsAdded).length),Math.ceil(chars/4)}case"user":return chars=estimateTextAndImageContentChars(message.content),Math.ceil(chars/4);case"assistant":{let assistant=message;for(let block of assistant.content)block.type==="text"?chars+=block.text.length:block.type==="thinking"?chars+=block.thinking.length:block.type==="toolCall"&&(chars+=block.name.length+JSON.stringify(block.arguments).length);return Math.ceil(chars/4)}case"custom":case"toolResult":return chars=estimateTextAndImageContentChars(message.content),Math.ceil(chars/4);case"bashExecution":return chars=message.command.length+message.output.length,Math.ceil(chars/4);case"branchSummary":case"compactionSummary":return chars=message.summary.length,Math.ceil(chars/4)}return 0}function isCutPointMessage(message){switch(message.role){case"user":case"assistant":case"bashExecution":case"custom":case"branchSummary":case"compactionSummary":return!0;case"toolResult":return!1}return!1}function isTurnStartMessage(message){switch(message.role){case"user":case"bashExecution":case"custom":case"branchSummary":case"compactionSummary":return!0;case"assistant":case"toolResult":return!1}return!1}function isTurnStartEntry(entry){return entry.type==="compaction"?!1:sessionEntryToContextMessages(entry).some(isTurnStartMessage)}function findValidCutPoints(entries,startIndex,endIndex){let cutPoints=[];for(let i=startIndex;i<endIndex;i++){let entry=entries[i];entry.type!=="compaction"&&sessionEntryToContextMessages(entry).some(isCutPointMessage)&&cutPoints.push(i)}return cutPoints}function findTurnStartIndex(entries,entryIndex,startIndex){for(let i=entryIndex;i>=startIndex;i--)if(isTurnStartEntry(entries[i]))return i;return-1}function findCutPoint(entries,startIndex,endIndex,keepRecentTokens){let cutPoints=findValidCutPoints(entries,startIndex,endIndex);if(cutPoints.length===0)return{firstKeptEntryIndex:startIndex,turnStartIndex:-1,isSplitTurn:!1};let accumulatedTokens=0,cutIndex=cutPoints[0];for(let i=endIndex-1;i>=startIndex;i--){let entry=entries[i],messageTokens=sessionEntryToContextMessages(entry).reduce((sum,message)=>sum+estimateTokens2(message),0);if(messageTokens!==0&&(accumulatedTokens+=messageTokens,accumulatedTokens>=keepRecentTokens)){cutIndex=cutPoints.find(candidate=>candidate>=i)??cutPoints[cutPoints.length-1];break}}for(;cutIndex>startIndex;){let prevEntry=entries[cutIndex-1];if(prevEntry.type==="compaction"||sessionEntryToContextMessages(prevEntry).length>0)break;cutIndex--}let cutEntry=entries[cutIndex],startsTurn=isTurnStartEntry(cutEntry),turnStartIndex=startsTurn?-1:findTurnStartIndex(entries,cutIndex,startIndex);return{firstKeptEntryIndex:cutIndex,turnStartIndex,isSplitTurn:!startsTurn&&turnStartIndex!==-1}}var SUMMARIZATION_PROMPT=`The messages above are a conversation to summarize. Create a structured context checkpoint summary that another LLM will use to continue the work.
|
|
731
|
+
Do NOT continue the conversation. Do NOT respond to any questions in the conversation. ONLY output the structured summary.`;function createUsageTotals(){return{input:0,output:0,cacheRead:0,cacheWrite:0,cost:0}}function addUsageToTotals(totals,usage){totals.input+=usage.input,totals.output+=usage.output,totals.cacheRead+=usage.cacheRead,totals.cacheWrite+=usage.cacheWrite,totals.cost+=usage.cost.total}function combineUsage(first,second){return{input:first.input+second.input,output:first.output+second.output,cacheRead:first.cacheRead+second.cacheRead,cacheWrite:first.cacheWrite+second.cacheWrite,...first.cacheWrite1h!==void 0||second.cacheWrite1h!==void 0?{cacheWrite1h:(first.cacheWrite1h??0)+(second.cacheWrite1h??0)}:{},...first.reasoning!==void 0||second.reasoning!==void 0?{reasoning:(first.reasoning??0)+(second.reasoning??0)}:{},totalTokens:first.totalTokens+second.totalTokens,cost:{input:first.cost.input+second.cost.input,output:first.cost.output+second.cost.output,cacheRead:first.cost.cacheRead+second.cost.cacheRead,cacheWrite:first.cost.cacheWrite+second.cost.cacheWrite,total:first.cost.total+second.cost.total}}}var TASK_USAGE_TYPE="task-usage";function isRecord(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function isUsageValue(value){return typeof value=="number"&&Number.isFinite(value)&&value>=0}function getTaskUsageRecord(entry){if(entry.type!=="custom"||entry.customType!==TASK_USAGE_TYPE)return;let data=entry.data;if(!isRecord(data)||data.version!==1||typeof data.taskId!="string"||!data.taskId.trim())return;let usage=data.usage;if(!isRecord(usage)||!isRecord(usage.cost))return;let{input:input2,output,cacheRead,cacheWrite,totalTokens,reasoning,cacheWrite1h}=usage,cost=usage.cost;if(!(!isUsageValue(input2)||!isUsageValue(output)||!isUsageValue(cacheRead)||!isUsageValue(cacheWrite)||!isUsageValue(totalTokens)||!isUsageValue(cost.input)||!isUsageValue(cost.output)||!isUsageValue(cost.cacheRead)||!isUsageValue(cost.cacheWrite)||!isUsageValue(cost.total)||reasoning!==void 0&&!isUsageValue(reasoning)||cacheWrite1h!==void 0&&!isUsageValue(cacheWrite1h)))return{version:1,taskId:data.taskId,usage:{input:input2,output,cacheRead,cacheWrite,totalTokens,...reasoning===void 0?{}:{reasoning},...cacheWrite1h===void 0?{}:{cacheWrite1h},cost:{input:cost.input,output:cost.output,cacheRead:cost.cacheRead,cacheWrite:cost.cacheWrite,total:cost.total}}}}function*accountedUsageEntries(entries){let backgroundTasks=new Set;for(let entry of entries)if(entry.type==="message"&&entry.message.role==="assistant")yield{key:`${entry.message.provider}/${entry.message.responseModel??entry.message.model}`,usage:entry.message.usage};else if(entry.type==="usage")yield{key:`${entry.provider}/${entry.model}`,usage:entry.usage};else if(entry.type==="message"&&entry.message.role==="toolResult"&&entry.message.usage)yield{key:"Tools/summaries",usage:entry.message.usage};else if((entry.type==="branch_summary"||entry.type==="compaction")&&entry.usage)yield{key:"Tools/summaries",usage:entry.usage};else{let record=getTaskUsageRecord(entry);if(!record||backgroundTasks.has(record.taskId))continue;backgroundTasks.add(record.taskId),yield{key:"Tools/summaries",usage:record.usage}}}function getAccountedUsages(entries){return Array.from(accountedUsageEntries(entries),({usage})=>usage)}function getUsageCostBreakdown(entries){let totalsByKey=new Map;for(let{key,usage}of accountedUsageEntries(entries)){let totals=totalsByKey.get(key);totals||(totals=createUsageTotals(),totalsByKey.set(key,totals)),addUsageToTotals(totals,usage)}return Array.from(totalsByKey,([key,totals])=>({key,cost:totals.cost,tokens:totals.input+totals.output+totals.cacheRead+totals.cacheWrite})).filter(entry=>entry.cost>0||entry.tokens>0).sort((a,b2)=>b2.cost-a.cost)}function extractFileOperations(messages,entries,prevCompactionIndex){let fileOps=createFileOps();if(prevCompactionIndex>=0){let prevCompaction=entries[prevCompactionIndex];if(prevCompaction.details){let details=prevCompaction.details;if(Array.isArray(details.readFiles))for(let f2 of details.readFiles)typeof f2=="string"&&fileOps.read.add(f2);if(Array.isArray(details.modifiedFiles))for(let f2 of details.modifiedFiles)typeof f2=="string"&&fileOps.edited.add(f2)}}for(let msg of messages)extractFileOpsFromMessage(msg,fileOps);return fileOps}function getMessagesFromProjectedEntryForCompaction(entry){return entry.sourceEntry.type==="compaction"?[]:entry.messages.filter(message=>message.role!=="system")}var DEFAULT_COMPACTION_SETTINGS={enabled:!0,reserveTokens:16384,keepRecentTokens:2e4};function calculateContextTokens(usage){return usage.totalTokens||usage.input+usage.output+usage.cacheRead+usage.cacheWrite}function getAssistantUsage(msg){if(msg.role==="assistant"&&"usage"in msg){let assistantMsg=msg;if(assistantMsg.stopReason!=="aborted"&&assistantMsg.stopReason!=="error"&&assistantMsg.usage&&calculateContextTokens(assistantMsg.usage)>0)return assistantMsg.usage}}function getLastAssistantUsage(entries){for(let i=entries.length-1;i>=0;i--){let entry=entries[i];if(entry.type==="message"){let usage=getAssistantUsage(entry.message);if(usage)return usage}}}function getLastAssistantUsageInfo(messages){for(let i=messages.length-1;i>=0;i--){let usage=getAssistantUsage(messages[i]);if(usage)return{usage,index:i}}}function estimateContextTokens2(messages){let usageInfo=getLastAssistantUsageInfo(messages);if(!usageInfo){let estimated=0;for(let message of messages)estimated+=estimateTokens2(message);return{tokens:estimated,usageTokens:0,trailingTokens:estimated,lastUsageIndex:null}}let usageTokens=calculateContextTokens(usageInfo.usage),trailingTokens=0;for(let i=usageInfo.index+1;i<messages.length;i++)trailingTokens+=estimateTokens2(messages[i]);return{tokens:usageTokens+trailingTokens,usageTokens,trailingTokens,lastUsageIndex:usageInfo.index}}function estimateProjectedContextTokens(projection,branchEntries){let estimate=estimateContextTokens2(projection.messages);if(estimate.lastUsageIndex!==null){let projectedMessageIndex=0,usageEntryId;for(let entry of projection.entries){let nextMessageIndex=projectedMessageIndex+entry.messages.length;if(estimate.lastUsageIndex<nextMessageIndex){usageEntryId=entry.sourceEntry.id;break}projectedMessageIndex=nextMessageIndex}let usageEntryIndex=usageEntryId?branchEntries.findIndex(entry=>entry.id===usageEntryId):-1,latestInvalidatingEntryIndex=-1;for(let i=branchEntries.length-1;i>=0;i--){let entry=branchEntries[i];if(entry.type==="context_edit"||entry.type==="compaction"){latestInvalidatingEntryIndex=i;break}}if(usageEntryIndex>latestInvalidatingEntryIndex)return estimate}let currentSystem=getCurrentSystemMessage(projection.messages),tokens2=currentSystem?estimateTokens2(currentSystem):0;for(let message of projection.messages)message.role!=="system"&&(tokens2+=estimateTokens2(message));return{tokens:tokens2,usageTokens:0,trailingTokens:tokens2,lastUsageIndex:null}}function shouldCompact(contextTokens,contextWindow,settings2){return settings2.enabled?contextTokens>contextWindow-settings2.reserveTokens:!1}var ESTIMATED_IMAGE_CHARS=4800;function estimateTextAndImageContentChars(content){if(typeof content=="string")return content.length;let chars=0;for(let block of content)block.type==="text"&&block.text?chars+=block.text.length:block.type==="image"&&(chars+=ESTIMATED_IMAGE_CHARS);return chars}function estimateTokens2(message){let chars=0;switch(message.role){case"system":{let system=message;if(chars=estimateTextAndImageContentChars(system.content),system.sections)for(let section of Object.values(system.sections))section&&(chars+=section.length);return system.toolsAdded&&(chars+=JSON.stringify(system.toolsAdded).length),Math.ceil(chars/4)}case"user":return chars=estimateTextAndImageContentChars(message.content),Math.ceil(chars/4);case"assistant":{let assistant=message;for(let block of assistant.content)block.type==="text"?chars+=block.text.length:block.type==="thinking"?chars+=block.thinking.length:block.type==="toolCall"&&(chars+=block.name.length+JSON.stringify(block.arguments).length);return Math.ceil(chars/4)}case"custom":case"toolResult":return chars=estimateTextAndImageContentChars(message.content),Math.ceil(chars/4);case"bashExecution":return chars=message.command.length+message.output.length,Math.ceil(chars/4);case"branchSummary":case"compactionSummary":return chars=message.summary.length,Math.ceil(chars/4)}return 0}function isCutPointMessage(message){switch(message.role){case"user":case"assistant":case"bashExecution":case"custom":case"branchSummary":case"compactionSummary":return!0;case"toolResult":return!1}return!1}function isTurnStartMessage(message){switch(message.role){case"user":case"bashExecution":case"custom":case"branchSummary":case"compactionSummary":return!0;case"assistant":case"toolResult":return!1}return!1}function isTurnStartEntry(entry){return entry.type==="compaction"?!1:sessionEntryToContextMessages(entry).some(isTurnStartMessage)}function findValidCutPoints(entries,startIndex,endIndex){let cutPoints=[];for(let i=startIndex;i<endIndex;i++){let entry=entries[i];entry.type!=="compaction"&&sessionEntryToContextMessages(entry).some(isCutPointMessage)&&cutPoints.push(i)}return cutPoints}function findTurnStartIndex(entries,entryIndex,startIndex){for(let i=entryIndex;i>=startIndex;i--)if(isTurnStartEntry(entries[i]))return i;return-1}function findCutPoint(entries,startIndex,endIndex,keepRecentTokens){let cutPoints=findValidCutPoints(entries,startIndex,endIndex);if(cutPoints.length===0)return{firstKeptEntryIndex:startIndex,turnStartIndex:-1,isSplitTurn:!1};let accumulatedTokens=0,cutIndex=cutPoints[0];for(let i=endIndex-1;i>=startIndex;i--){let entry=entries[i],messageTokens=sessionEntryToContextMessages(entry).reduce((sum,message)=>sum+estimateTokens2(message),0);if(messageTokens!==0&&(accumulatedTokens+=messageTokens,accumulatedTokens>=keepRecentTokens)){cutIndex=cutPoints.find(candidate=>candidate>=i)??cutPoints[cutPoints.length-1];break}}for(;cutIndex>startIndex;){let prevEntry=entries[cutIndex-1];if(prevEntry.type==="compaction"||sessionEntryToContextMessages(prevEntry).length>0)break;cutIndex--}let cutEntry=entries[cutIndex],startsTurn=isTurnStartEntry(cutEntry),turnStartIndex=startsTurn?-1:findTurnStartIndex(entries,cutIndex,startIndex);return{firstKeptEntryIndex:cutIndex,turnStartIndex,isSplitTurn:!startsTurn&&turnStartIndex!==-1}}var SUMMARIZATION_PROMPT=`The messages above are a conversation to summarize. Create a structured context checkpoint summary that another LLM will use to continue the work.
|
|
732
732
|
|
|
733
733
|
Use this EXACT format:
|
|
734
734
|
|
|
@@ -878,7 +878,7 @@ Hint: ${hints.join(`
|
|
|
878
878
|
Hint: `)}`:head;if(markerIndex!==-1){let bounded=truncateHead(received,{maxBytes:RECEIVED_ARGUMENTS_MAX_BYTES,maxLines:RECEIVED_ARGUMENTS_MAX_LINES});enriched+=`${RECEIVED_ARGUMENTS_MARKER}${bounded.content}`,bounded.truncated&&(enriched+=`
|
|
879
879
|
\u2026 (arguments truncated)`)}return new Error(enriched)}function wrapPrepareArguments(definition){let tool={name:definition.name,description:definition.description,parameters:definition.parameters};return raw=>{let args=definition.prepareArguments?definition.prepareArguments(raw):raw;try{validateToolArguments(tool,{type:"toolCall",id:"",name:definition.name,arguments:args})}catch(error){throw enrichValidationError(error,definition.parameters,args)}return args}}function wrapToolDefinition(definition,ctxFactory){return{name:definition.name,label:definition.label,description:definition.description,parameters:definition.parameters,outputSchema:definition.outputSchema,constrainedSampling:definition.constrainedSampling,prepareArguments:wrapPrepareArguments(definition),executionMode:definition.executionMode,execute:(toolCallId,params,signal,onUpdate,ctx)=>definition.execute(toolCallId,params,signal,onUpdate,ctx??ctxFactory?.(toolCallId,signal))}}function createToolDefinitionFromAgentTool(tool){return{name:tool.name,label:tool.label,description:tool.description,parameters:tool.parameters,outputSchema:tool.outputSchema,constrainedSampling:tool.constrainedSampling,prepareArguments:tool.prepareArguments,executionMode:tool.executionMode,execute:async(toolCallId,params,signal,onUpdate)=>tool.execute(toolCallId,params,signal,onUpdate)}}function wrapRegisteredTool(registeredTool,runner){return wrapToolDefinition(registeredTool.definition,(toolCallId,signal)=>runner.createToolContext(toolCallId,signal))}function wrapRegisteredTools(registeredTools,runner){return registeredTools.map(tool=>wrapRegisteredTool(tool,runner))}import*as fs5 from"node:fs";import{createRequire as createRequire5}from"node:module";import*as path7 from"node:path";import{fileURLToPath as fileURLToPath5}from"node:url";import{spawn as spawn3}from"node:child_process";async function execCommand(command,args,cwd,options){return new Promise(resolve20=>{let proc=spawn3(command,args,{cwd,shell:!1,stdio:["ignore","pipe","pipe"]}),stdout="",stderr="",killed=!1,timeoutId,killProcess=()=>{killed||(killed=!0,proc.kill("SIGTERM"),setTimeout(()=>{proc.killed||proc.kill("SIGKILL")},5e3))};options?.signal&&(options.signal.aborted?killProcess():options.signal.addEventListener("abort",killProcess,{once:!0})),options?.timeout&&options.timeout>0&&(timeoutId=setTimeout(()=>{killProcess()},options.timeout)),proc.stdout?.on("data",data=>{stdout+=data.toString()}),proc.stderr?.on("data",data=>{stderr+=data.toString()}),waitForChildProcess(proc).then(code=>{timeoutId&&clearTimeout(timeoutId),options?.signal&&options.signal.removeEventListener("abort",killProcess),resolve20({stdout,stderr,code:code??0,killed})}).catch(_err=>{timeoutId&&clearTimeout(timeoutId),options?.signal&&options.signal.removeEventListener("abort",killProcess),resolve20({stdout,stderr,code:1,killed})})})}function toolPatternRegExp(pattern){let source=pattern.split("*").map(part=>part.replace(/[.+?^${}()|[\]\\]/g,"\\$&")).join(".*");return new RegExp(`^${source}$`)}function createToolNameMatcher(entries){let names2=new Set(entries.filter(entry=>!entry.includes("*"))),patterns=entries.filter(entry=>entry.includes("*")).map(toolPatternRegExp);return name=>names2.has(name)||patterns.some(pattern=>pattern.test(name))}var LIST_MCP_RESOURCES_TOOL="list_mcp_resources",LIST_MCP_RESOURCE_TEMPLATES_TOOL="list_mcp_resource_templates",READ_MCP_RESOURCE_TOOL="read_mcp_resource",MCP_RESOURCE_TOOLS=new Set([LIST_MCP_RESOURCES_TOOL,LIST_MCP_RESOURCE_TEMPLATES_TOOL,READ_MCP_RESOURCE_TOOL]);function isMcpToolName(name){return name.startsWith("mcp__")||MCP_RESOURCE_TOOLS.has(name)}var MCP_EXPOSURES=["codemode","deferred","direct","hidden"],MCP_EXPOSURE_ALIASES={"codemode-deferred":"codemode"},LOOPBACK_HOSTS=["localhost","127.0.0.1","[::1]"];function isLoopbackRedirectUri(value){if(!URL.canParse(value))return!1;let url=new URL(value);return url.protocol==="http:"&&LOOPBACK_HOSTS.includes(url.hostname)&&url.search===""&&url.hash===""}var SERVER_NAME=/^[A-Za-z0-9_-]+$/;function mcpNamespace(server){return`mcp__${server.replace(/-/g,"_")}`}function isRecord3(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function isStringRecord(value){return isRecord3(value)&&Object.values(value).every(entry=>typeof entry=="string")}function validateOAuth(value){if(value===void 0)return;if(!isRecord3(value))return"oauth must be an object";if(value.clientId!==void 0&&typeof value.clientId!="string")return"oauth.clientId must be a string";if(value.clientSecret!==void 0&&typeof value.clientSecret!="string")return"oauth.clientSecret must be a string";let port=value.callbackPort;if(port!==void 0&&(typeof port!="number"||!Number.isInteger(port)||port<1||port>65535))return"oauth.callbackPort must be a port number";if(value.callbackUrl!==void 0){if(typeof value.callbackUrl!="string"||!isLoopbackRedirectUri(value.callbackUrl))return"oauth.callbackUrl must be an http URI on localhost, 127.0.0.1, or [::1] without query or fragment";let urlPort=new URL(value.callbackUrl).port;if(urlPort&&port!==void 0&&Number(urlPort)!==port)return"oauth.callbackUrl and oauth.callbackPort name different ports"}if(value.scope!==void 0&&typeof value.scope!="string")return"oauth.scope must be a string";if(value.clientName!==void 0&&(typeof value.clientName!="string"||!value.clientName.trim()))return"oauth.clientName must be a non-empty string";if(value.clientRegistration!==void 0&&value.clientRegistration!=="dcr"){if(value.clientRegistration!=="cimd")return'oauth.clientRegistration must be "dcr" or "cimd"';if(value.clientId!==void 0||value.clientName!==void 0)return'oauth.clientRegistration "cimd" cannot be combined with oauth.clientId or oauth.clientName';let callback=typeof value.callbackUrl=="string"?new URL(value.callbackUrl):void 0;if(callback&&(callback.hostname==="[::1]"||callback.pathname!=="/callback"))return'oauth.clientRegistration "cimd" requires oauth.callbackUrl on localhost or 127.0.0.1 with path /callback'}let metadataUrl=value.authServerMetadataUrl;if(metadataUrl!==void 0){let url=typeof metadataUrl=="string"&&URL.canParse(metadataUrl)?new URL(metadataUrl):void 0;if(!url||!(url.protocol==="https:"||url.protocol==="http:"&&LOOPBACK_HOSTS.includes(url.hostname)))return"oauth.authServerMetadataUrl must be an https URL, or http on localhost, 127.0.0.1, or [::1]"}}function isExposure(value){return typeof value=="string"&&MCP_EXPOSURES.includes(value)}function resolveExposureAlias(value){return typeof value=="string"?MCP_EXPOSURE_ALIASES[value]??value:value}function resolveExposureAliases(value){let{exposure,toolExposure}=value,resolved={...value};return exposure!==void 0&&(resolved.exposure=resolveExposureAlias(exposure)),isRecord3(toolExposure)&&(resolved.toolExposure=Object.fromEntries(Object.entries(toolExposure).map(([tool,entry])=>[tool,resolveExposureAlias(entry)]))),resolved}function getMcpToolExposure(config,toolName){let overrides=config.toolExposure??{},exact=overrides[toolName];if(exact!==void 0)return exact;for(let[pattern,exposure]of Object.entries(overrides))if(pattern.includes("*")&&toolPatternRegExp(pattern).test(toolName))return exposure;return config.exposure??"codemode"}function validateMcpServerConfig(name,raw){if(!SERVER_NAME.test(name))return`invalid server name "${name}" (use letters, digits, "_" and "-")`;if(!isRecord3(raw))return`server "${name}" must be an object`;let value=resolveExposureAliases(raw),{type,exposure,enabled,timeout,toolExposure,description}=value,exposures=MCP_EXPOSURES.map(value2=>`"${value2}"`).join(", ");if(exposure!==void 0&&!isExposure(exposure))return`server "${name}": exposure must be one of ${exposures}`;if(toolExposure!==void 0){if(!isRecord3(toolExposure))return`server "${name}": toolExposure must map tool names to exposures`;for(let[tool,value2]of Object.entries(toolExposure))if(!isExposure(value2))return`server "${name}": toolExposure "${tool}" must be one of ${exposures}`}if(enabled!==void 0&&typeof enabled!="boolean")return`server "${name}": enabled must be a boolean`;if(description!==void 0&&typeof description!="string")return`server "${name}": description must be a string`;if(timeout!==void 0&&(typeof timeout!="number"||!(timeout>0)))return`server "${name}": timeout must be a positive number of seconds`;if(type==="sse")return`server "${name}": legacy SSE transport is not supported; use the streamable HTTP URL`;if(typeof value.url=="string"&&(type===void 0||type==="http"||type==="streamable-http")){if(!URL.canParse(value.url)||!/^https?:$/.test(new URL(value.url).protocol))return`server "${name}": url must be an http or https URL`;if(value.headers!==void 0&&!isStringRecord(value.headers))return`server "${name}": headers must map names to strings`;let oauthError=validateOAuth(value.oauth);if(oauthError)return`server "${name}": ${oauthError}`;if(value.auth!==void 0){if(!isRecord3(value.auth)||typeof value.auth.provider!="string"||!value.auth.provider)return`server "${name}": auth.provider must be a provider name`;let url=new URL(value.url);if(url.protocol!=="https:"&&!LOOPBACK_HOSTS.includes(url.hostname))return`server "${name}": auth requires an https URL, or http on localhost, 127.0.0.1, or [::1]`}return value}return typeof value.command=="string"&&(type===void 0||type==="stdio")?value.args!==void 0&&!(Array.isArray(value.args)&&value.args.every(arg=>typeof arg=="string"))?`server "${name}": args must be an array of strings`:value.env!==void 0&&!isStringRecord(value.env)?`server "${name}": env must map names to strings`:value.cwd!==void 0&&typeof value.cwd!="string"?`server "${name}": cwd must be a string`:value:`server "${name}" needs either "command" (stdio) or "url" (streamable HTTP)`}var McpServerRegistry=class{constructor(){this.servers=new Map}register(server){this.servers.set(server.name,server),this.changeListener?.()}unregister(name,extensionPath){this.servers.get(name)?.extensionPath===extensionPath&&(this.servers.delete(name),this.changeListener?.())}get(name){return this.servers.get(name)}list(){return[...this.servers.values()].map(server=>({...server,config:structuredClone(server.config)}))}setChangeListener(listener){this.changeListener=listener}};var ENABLED=process.env.PI_TIMING==="1",timingNamespaces=new Map;function resetTimings(namespace="main"){ENABLED&&timingNamespaces.set(namespace,{timings:[],lastTime:Date.now()})}function time(label,namespace="main"){if(!ENABLED)return;let now=Date.now();timingNamespaces.has(namespace)||resetTimings(namespace);let timingNamespace=timingNamespaces.get(namespace);timingNamespace.timings.push({label,ms:now-timingNamespace.lastTime}),timingNamespace.lastTime=now}function printTimingGroup(title,timings){let printableTimings=timings.filter(timing=>timing.ms>=0);if(printableTimings.length!==0){console.error(`
|
|
880
880
|
--- ${title} ---`);for(let t of printableTimings)console.error(` ${t.label}: ${t.ms}ms`);console.error(` TOTAL: ${printableTimings.reduce((a,b2)=>a+b2.ms,0)}ms`),console.error(`${"-".repeat(title.length+8)}
|
|
881
|
-
`)}}function printTimings(){if(ENABLED)for(let[namespace,timingNamespace]of timingNamespaces)printTimingGroup(`Startup Timings: ${namespace}`,timingNamespace.timings)}var require3=createRequire5(import.meta.url),isNodeSeaBinary="sea"in process.features&&process.features.sea===!0||process.getBuiltinModule("node:sea")?.isSea()===!0,isTypeScriptSourceRuntime=!isBunBinary&&path7.extname(fileURLToPath5(import.meta.url))===".ts",usesEmbeddedModules=isBunBinary||isNodeSeaBinary||isBundledNode,createJitiPromise;function getCreateJiti(){return createJitiPromise??=(usesEmbeddedModules?import("./jiti-static-loader-CLT3YR3B.js"):import("./jiti-loader-BFSSLU7G.js")).then(module=>module.createJiti),createJitiPromise}var virtualModulesPromise;function getVirtualModules(){return virtualModulesPromise??=import("./virtual-modules-3CTTTQQN.js").then(module=>module.VIRTUAL_MODULES),virtualModulesPromise}var _aliases=null;function getAliases(){if(_aliases)return _aliases;let __dirname2=path7.dirname(fileURLToPath5(import.meta.url)),packageIndex=path7.resolve(__dirname2,"../..","index.js"),typeboxEntry=require3.resolve("typebox"),typeboxCompileEntry=require3.resolve("typebox/compile"),typeboxValueEntry=require3.resolve("typebox/value"),resolveImport=specifier=>fileURLToPath5(import.meta.resolve(specifier)),piCodingAgentEntry=packageIndex,piAgentCoreEntry=resolveImport("@earendil-works/pi-agent-core"),piTuiEntry=resolveImport("@earendil-works/pi-tui"),piAiCompatEntry=resolveImport("@earendil-works/pi-ai/compat"),piAiModelsEntry=resolveImport("@earendil-works/pi-ai/models"),piAiOauthEntry=resolveImport("@earendil-works/pi-ai/oauth"),piAiProvidersEntry=resolveImport("@earendil-works/pi-ai/providers/all");return _aliases={"@earendil-works/pi-coding-agent":piCodingAgentEntry,[DISTRIBUTION_PACKAGE_NAME]:piCodingAgentEntry,"@earendil-works/pi-agent-core":piAgentCoreEntry,"@earendil-works/pi-tui":piTuiEntry,"@earendil-works/pi-ai/providers/all":piAiProvidersEntry,"@earendil-works/pi-ai/compat":piAiCompatEntry,"@earendil-works/pi-ai/models":piAiModelsEntry,"@earendil-works/pi-ai/oauth":piAiOauthEntry,"@earendil-works/pi-ai":piAiCompatEntry,"@mariozechner/pi-coding-agent":piCodingAgentEntry,"@mariozechner/pi-agent-core":piAgentCoreEntry,"@mariozechner/pi-tui":piTuiEntry,"@mariozechner/pi-ai/providers/all":piAiProvidersEntry,"@mariozechner/pi-ai/compat":piAiCompatEntry,"@mariozechner/pi-ai/models":piAiModelsEntry,"@mariozechner/pi-ai/oauth":piAiOauthEntry,"@mariozechner/pi-ai":piAiCompatEntry,typebox:typeboxEntry,"typebox/compile":typeboxCompileEntry,"typebox/value":typeboxValueEntry,"@sinclair/typebox":typeboxEntry,"@sinclair/typebox/compile":typeboxCompileEntry,"@sinclair/typebox/value":typeboxValueEntry},_aliases}var extensionCacheCwd,extensionCacheGeneration=0,extensionCache=new Map;function clearExtensionCache(){extensionCache.clear(),extensionCacheCwd=void 0,extensionCacheGeneration++}function useExtensionCacheCwd(cwd){let resolvedCwd=resolvePath(cwd);return extensionCacheCwd!==void 0&&extensionCacheCwd!==resolvedCwd&&clearExtensionCache(),extensionCacheCwd=resolvedCwd,{cwd:resolvedCwd,generation:extensionCacheGeneration}}function createExtensionRuntime(){let notInitialized=()=>{throw new Error("Extension runtime not initialized. Action methods cannot be called during extension loading.")},state2={},eventBusUnsubscribers=new Set,assertActive=()=>{if(state2.staleMessage)throw new Error(state2.staleMessage)},runtime={sendMessage:notInitialized,sendUserMessage:notInitialized,appendEntry:notInitialized,setSessionName:notInitialized,getSessionName:notInitialized,setLabel:notInitialized,getActiveTools:notInitialized,getAllTools:notInitialized,getSettings:notInitialized,setActiveTools:notInitialized,refreshTools:()=>{},getCommands:notInitialized,setModel:()=>Promise.reject(new Error("Extension runtime not initialized")),getThinkingLevel:notInitialized,setThinkingLevel:notInitialized,flagValues:new Map,pendingProviderRegistrations:[],pendingNativeProviderRegistrations:[],mcpServers:new McpServerRegistry,pendingVirtualModelRegistrations:[],createContext:notInitialized,assertActive,invalidate:message=>{if(!state2.staleMessage){state2.staleMessage=message??"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().";for(let unsubscribe of eventBusUnsubscribers)unsubscribe();eventBusUnsubscribers.clear()}},trackEventBusSubscription:unsubscribe=>{let active=!0,trackedUnsubscribe=()=>{active&&(active=!1,eventBusUnsubscribers.delete(trackedUnsubscribe),unsubscribe())};return eventBusUnsubscribers.add(trackedUnsubscribe),trackedUnsubscribe},registerProvider:(name,config,extensionPath="<unknown>")=>{runtime.pendingProviderRegistrations.push({name,config,extensionPath})},registerNativeProvider:(provider,extensionPath="<unknown>")=>{runtime.pendingNativeProviderRegistrations.push({provider,extensionPath})},unregisterProvider:name=>{runtime.pendingProviderRegistrations=runtime.pendingProviderRegistrations.filter(r=>r.name!==name),runtime.pendingNativeProviderRegistrations=runtime.pendingNativeProviderRegistrations.filter(r=>r.provider.id!==name)},registerVirtualModel:(definition,extensionPath="<unknown>")=>{runtime.pendingVirtualModelRegistrations.push({definition,extensionPath})},unregisterVirtualModel:(provider,id)=>{runtime.pendingVirtualModelRegistrations=runtime.pendingVirtualModelRegistrations.filter(({definition})=>definition.provider!==provider||definition.id!==id)}};return runtime}function createExtensionAPI(extension,runtime,cwd,eventBus){let pendingFlagValues=new Map,pendingRuntimeChanges=[],loadingUnsubscribers=[],state2="loading",assertActive=()=>{if(state2==="failed")throw new Error(`Extension "${extension.path}" failed to load and its API is no longer active.`);runtime.assertActive()},applyRuntimeChange=change=>{state2==="loading"?pendingRuntimeChanges.push(change):change()},clearPending=()=>{pendingFlagValues.clear(),pendingRuntimeChanges.length=0,loadingUnsubscribers.length=0};return{api:{on(event,handler){assertActive();let registeredHandler=(...args)=>handler(...args),list2=extension.handlers.get(event)??[];return list2.push(registeredHandler),extension.handlers.set(event,list2),()=>{let handlers=extension.handlers.get(event);if(!handlers)return;let handlerIndex=handlers.indexOf(registeredHandler);handlerIndex!==-1&&(handlers.splice(handlerIndex,1),handlers.length===0&&extension.handlers.delete(event))}},registerTool(tool){if(assertActive(),typeof tool.parameters!="object"||tool.parameters===null||Array.isArray(tool.parameters))throw new Error(`Tool "${tool.name}" registered by extension "${extension.path}" must define an object parameter schema.`);extension.tools.set(tool.name,{definition:tool,sourceInfo:extension.sourceInfo}),runtime.refreshTools()},registerCommand(name,options){if(assertActive(),typeof name!="string"||name.length===0)throw new Error(`Command registered by extension "${extension.path}" must have a non-empty string name. Use pi.registerCommand("name", { description, handler }).`);if(typeof options?.handler!="function")throw new Error(`Command "/${name}" registered by extension "${extension.path}" must define handler().`);extension.commands.set(name,{name,sourceInfo:extension.sourceInfo,...options})},registerShortcut(shortcut,options){assertActive(),extension.shortcuts.set(shortcut,{shortcut,extensionPath:extension.path,...options})},registerFlag(name,options){if(assertActive(),options.default!==void 0&&typeof options.default!==options.type)throw new Error(`Invalid default for flag "${name}": expected ${options.type}, got ${typeof options.default}`);extension.flags.set(name,{name,extensionPath:extension.path,...options}),options.default!==void 0&&!runtime.flagValues.has(name)&&(state2==="loading"?pendingFlagValues.has(name)||pendingFlagValues.set(name,options.default):runtime.flagValues.set(name,options.default))},registerMessageRenderer(customType,renderer){assertActive(),extension.messageRenderers.set(customType,renderer)},registerMarkdownTransformer(transformer){assertActive(),extension.markdownTransformer=transformer},registerEntryRenderer(customType,renderer){assertActive(),extension.entryRenderers??=new Map,extension.entryRenderers.set(customType,renderer)},registerToolRenderer(resolver){assertActive(),extension.toolRenderers??=[],extension.toolRenderers.push(resolver)},getFlag(name){if(assertActive(),!!extension.flags.has(name))return runtime.flagValues.has(name)?runtime.flagValues.get(name):pendingFlagValues.get(name)},sendMessage(message,options){assertActive(),runtime.sendMessage(message,options)},sendUserMessage(content,options){assertActive(),runtime.sendUserMessage(content,options)},appendEntry(customType,data){assertActive(),runtime.appendEntry(customType,data)},setSessionName(name){assertActive(),runtime.setSessionName(name)},getSessionName(){return assertActive(),runtime.getSessionName()},setLabel(entryId,label){assertActive(),runtime.setLabel(entryId,label)},exec(command,args,options){return assertActive(),execCommand(command,args,options?.cwd??cwd,options)},getActiveTools(){return assertActive(),runtime.getActiveTools()},getAllTools(){return assertActive(),runtime.getAllTools()},getSettings(){return assertActive(),runtime.getSettings()},setActiveTools(toolNames){assertActive(),runtime.setActiveTools(toolNames)},getCommands(){return assertActive(),runtime.getCommands()},setModel(model){return assertActive(),runtime.setModel(model)},getThinkingLevel(){return assertActive(),runtime.getThinkingLevel()},setThinkingLevel(level){assertActive(),runtime.setThinkingLevel(level)},registerProvider(providerOrName,config){if(assertActive(),typeof providerOrName=="string"){if(!config)throw new Error("Provider config is required when registering by name");applyRuntimeChange(()=>runtime.registerProvider(providerOrName,config,extension.path));return}applyRuntimeChange(()=>runtime.registerNativeProvider(providerOrName,extension.path))},unregisterProvider(name){assertActive(),applyRuntimeChange(()=>runtime.unregisterProvider(name,extension.path))},registerMcpServer(name,config){assertActive();let validated=validateMcpServerConfig(name,config);if(typeof validated=="string")throw new Error(`Invalid MCP server registered by extension "${extension.path}": ${validated}`);let owner=runtime.mcpServers.get(name)?.extensionPath;if(owner!==void 0&&owner!==extension.path)throw new Error(`MCP server "${name}" is already registered by extension "${owner}"`);let clash=runtime.mcpServers.list().find(server2=>server2.name!==name&&mcpNamespace(server2.name)===mcpNamespace(name));if(clash)throw new Error(`MCP server "${name}" conflicts with registered server "${clash.name}"`);let server={name,config:structuredClone(validated),extensionPath:extension.path};applyRuntimeChange(()=>runtime.mcpServers.register(server))},unregisterMcpServer(name){assertActive(),applyRuntimeChange(()=>runtime.mcpServers.unregister(name,extension.path))},getMcpServers(){return assertActive(),runtime.mcpServers.list()},registerVirtualModel(model){assertActive();let definition={...model,route:request=>model.route(request,runtime.createContext())};applyRuntimeChange(()=>runtime.registerVirtualModel(definition,extension.path))},unregisterVirtualModel(provider,id){assertActive(),applyRuntimeChange(()=>runtime.unregisterVirtualModel(provider,id))},events:{emit(channel,data){assertActive(),eventBus.emit(channel,data)},on(channel,handler){assertActive();let unsubscribe=runtime.trackEventBusSubscription(eventBus.on(channel,handler));return state2==="loading"&&loadingUnsubscribers.push(unsubscribe),unsubscribe}}},commit:()=>{if(state2==="loading"){runtime.assertActive();for(let[name,value]of pendingFlagValues)runtime.flagValues.has(name)||runtime.flagValues.set(name,value);for(let apply of pendingRuntimeChanges)apply();state2="active",clearPending()}},discard:()=>{if(state2==="loading"){state2="failed";for(let unsubscribe of loadingUnsubscribers)unsubscribe();clearPending()}}}}function isCurrentCacheToken(cacheToken){return cacheToken!==void 0&&extensionCacheCwd===cacheToken.cwd&&extensionCacheGeneration===cacheToken.generation}async function loadExtensionModule(extensionPath,cacheToken){if(isCurrentCacheToken(cacheToken)){let cachedFactory=extensionCache.get(extensionPath);if(cachedFactory)return cachedFactory}let createJitiImpl=await getCreateJiti(),resolutionOptions=usesEmbeddedModules?{virtualModules:await getVirtualModules(),tryNative:!1}:isTypeScriptSourceRuntime?{virtualModules:await getVirtualModules(),tsconfigPaths:!0}:{alias:getAliases()},factory=await createJitiImpl(import.meta.url,{moduleCache:!1,...resolutionOptions}).import(extensionPath,{default:!0});if(typeof factory=="function")return isCurrentCacheToken(cacheToken)&&extensionCache.set(extensionPath,factory),factory}function createExtension(extensionPath,resolvedPath){let source=getSyntheticPathSource(extensionPath)??"local",baseDir=isSyntheticPath(extensionPath)?void 0:path7.dirname(resolvedPath);return{path:extensionPath,resolvedPath,sourceInfo:createSyntheticSourceInfo(extensionPath,{source,baseDir}),handlers:new Map,tools:new Map,messageRenderers:new Map,entryRenderers:new Map,commands:new Map,flags:new Map,shortcuts:new Map}}async function initializeExtension(factory,extensionPath,resolvedPath,cwd,eventBus,runtime){let extension=createExtension(extensionPath,resolvedPath),load=createExtensionAPI(extension,runtime,cwd,eventBus);try{await factory(load.api),load.commit()}catch(error){throw load.discard(),error}return time(`${extensionPath} factory`,"extensions"),extension}async function loadExtension(extensionPath,cwd,eventBus,runtime,cacheToken){let resolvedPath=resolvePath(extensionPath,cwd,{normalizeUnicodeSpaces:!0});try{let factory=await loadExtensionModule(resolvedPath,cacheToken);return time(`${extensionPath} module import`,"extensions"),factory?{extension:await initializeExtension(factory,extensionPath,resolvedPath,cwd,eventBus,runtime),error:null}:{extension:null,error:`Extension does not export a valid factory function: ${extensionPath}`}}catch(err){return{extension:null,error:`Failed to load extension: ${err instanceof Error?err.message:String(err)}`}}}async function loadExtensionFromFactory(factory,cwd,eventBus,runtime,extensionPath="<inline>"){let resolvedCwd=resolvePath(cwd);return initializeExtension(factory,extensionPath,extensionPath,resolvedCwd,eventBus,runtime)}async function loadExtensionsInternal(paths,cwd,eventBus,runtime,useCache=!1){let extensions=[],errors=[],warnings=[],cacheToken=useCache?useExtensionCacheCwd(cwd):void 0,resolvedCwd=cacheToken?.cwd??resolvePath(cwd),resolvedEventBus=eventBus??createEventBus(),resolvedRuntime=runtime??createExtensionRuntime();for(let extPath of paths){let{extension,error}=await loadExtension(extPath,resolvedCwd,resolvedEventBus,resolvedRuntime,cacheToken);if(error){errors.push({path:extPath,error});continue}extension&&extensions.push(extension)}return{extensions,errors,warnings,runtime:resolvedRuntime}}async function loadExtensions(paths,cwd,eventBus,runtime){return loadExtensionsInternal(paths,cwd,eventBus,runtime)}async function loadExtensionsCached(paths,cwd,eventBus,runtime){return loadExtensionsInternal(paths,cwd,eventBus,runtime,!0)}function isExtensionFile(name){return name.endsWith(".ts")||name.endsWith(".js")}function resolveExtensionEntries2(dir){let packageJsonPath=path7.join(dir,"package.json");if(fs5.existsSync(packageJsonPath)){let manifest=readPiManifest(packageJsonPath);if(manifest?.extensions?.length){let entries=[];for(let extPath of manifest.extensions){let resolvedExtPath=path7.resolve(dir,extPath);fs5.existsSync(resolvedExtPath)&&entries.push(resolvedExtPath)}if(entries.length>0)return entries}}let indexTs=path7.join(dir,"index.ts"),indexJs=path7.join(dir,"index.js");return fs5.existsSync(indexTs)?[indexTs]:fs5.existsSync(indexJs)?[indexJs]:null}function discoverExtensionsInDir(dir){if(!fs5.existsSync(dir))return[];let discovered=[];try{let entries=fs5.readdirSync(dir,{withFileTypes:!0});for(let entry of entries){let entryPath=path7.join(dir,entry.name);if((entry.isFile()||entry.isSymbolicLink())&&isExtensionFile(entry.name)){discovered.push(entryPath);continue}if(entry.isDirectory()||entry.isSymbolicLink()){let entries2=resolveExtensionEntries2(entryPath);entries2&&discovered.push(...entries2)}}}catch{return[]}return discovered}async function discoverAndLoadExtensions(configuredPaths,cwd,agentDir=getAgentDir(),eventBus){let resolvedCwd=resolvePath(cwd),resolvedAgentDir=resolvePath(agentDir),allPaths=[],seen=new Set,addPaths=paths=>{for(let p of paths){let resolved=path7.resolve(p);seen.has(resolved)||(seen.add(resolved),allPaths.push(p))}},localExtDir=path7.join(resolvedCwd,CONFIG_DIR_NAME,"extensions");addPaths(discoverExtensionsInDir(localExtDir));let globalExtDir=path7.join(resolvedAgentDir,"extensions");addPaths(discoverExtensionsInDir(globalExtDir));for(let p of configuredPaths){let resolved=resolvePath(p,resolvedCwd,{normalizeUnicodeSpaces:!0});if(fs5.existsSync(resolved)&&fs5.statSync(resolved).isDirectory()){let entries=resolveExtensionEntries2(resolved);if(entries){addPaths(entries);continue}addPaths(discoverExtensionsInDir(resolved));continue}addPaths([resolved])}return loadExtensions(allPaths,resolvedCwd,eventBus)}var ModelRegistry=class{constructor(runtime){this.runtime=runtime}getRuntime(){return this.runtime}refresh(options){return this.runtime.refresh(options)}getError(){return this.runtime.getError()}getAll(){return[...this.runtime.getModels()]}getAvailable(){return[...this.runtime.getAvailableSnapshot()]}find(provider,modelId){return this.runtime.getModel(provider,modelId)}findOfType(type,provider,modelId){return this.runtime.getModelOfType(type,provider,modelId)}hasConfiguredAuth(model){return this.runtime.hasConfiguredAuth(model.provider)}async getApiKeyAndHeaders(model){try{let resolution=await this.runtime.getAuth(model);if(!resolution){let compatibility=this.runtime.getCompatibilityRequestConfig(model);return compatibility.authHeader?{ok:!1,error:`No API key found for "${model.provider}"`}:{ok:!0,headers:compatibility.headers}}return{ok:!0,apiKey:resolution.auth.apiKey,headers:resolution.auth.headers,...resolution.auth.baseUrl?{baseUrl:resolution.auth.baseUrl}:{},env:resolution.env}}catch(error){let cause=error instanceof Error?error.cause:void 0,message=cause instanceof Error?cause.message:error instanceof Error?error.message:String(error);return{ok:!1,error:message==="authHeader requires a resolved API key"?`No API key found for "${model.provider}"`:message}}}getProviderAuthStatus(provider){return this.runtime.getProviderAuthStatus(provider)}getProvider(provider){return this.runtime.getProvider(provider)}stream(model,context,options){return this.runtime.stream(model,context,options)}streamSimple(model,context,options){return this.runtime.streamSimple(model,context,options)}complete(model,context,options){return this.runtime.complete(model,context,options)}getModelsOfType(type,provider){return this.runtime.getModelsOfType(type,provider)}getAvailableOfType(type,provider,options){return this.runtime.getAvailableOfType(type,provider,options)}getModelOfType(type,provider,modelId){return this.runtime.getModelOfType(type,provider,modelId)}classify(model,context,options){return this.runtime.classify(model,context,options)}generateImages(model,context,options){return this.runtime.generateImages(model,context,options)}getProviderDisplayName(provider){return this.runtime.getProvider(provider)?.name??provider}getProviderAuth(provider){return this.runtime.getAuth(provider)}async getApiKeyForProvider(provider){try{return(await this.runtime.getAuth(provider))?.auth.apiKey}catch{return}}isUsingOAuth(model){return this.runtime.isUsingOAuth(model.provider)}registerProvider(providerOrName,config){if(typeof providerOrName=="string"){if(!config)throw new Error("Provider config is required when registering by name");this.runtime.registerProvider(providerOrName,config);return}this.runtime.registerNativeProvider(providerOrName)}unregisterProvider(providerName){this.runtime.unregisterProvider(providerName)}registerVirtualModel(definition){this.runtime.registerVirtualModel(definition)}unregisterVirtualModel(providerName,id){this.runtime.unregisterVirtualModel(providerName,id)}getRegisteredProviderConfig(providerName){return this.runtime.getRegisteredProviderConfig(providerName)}getRegisteredNativeProvider(providerName){return this.runtime.getRegisteredNativeProvider(providerName)}getRegisteredProviderIds(){return this.runtime.getRegisteredProviderIds()}};function truncateToVisualLines(text2,maxVisualLines,width,paddingX=0,keep="end"){if(!text2)return{visualLines:[],skippedCount:0};let allVisualLines=new Text(text2,paddingX,0).render(width);if(allVisualLines.length<=maxVisualLines)return{visualLines:allVisualLines,skippedCount:0};let truncatedLines=keep==="start"?allVisualLines.slice(0,maxVisualLines):allVisualLines.slice(-maxVisualLines),skippedCount=allVisualLines.length-maxVisualLines;return{visualLines:truncatedLines,skippedCount}}var VisualLinePreview=class{constructor(options){this.options=options}render(width){if(this.cachedLines===void 0||this.cachedWidth!==width){let{text:text2,maxVisualLines,keep,formatHint}=this.options,preview=truncateToVisualLines(text2,maxVisualLines,width,0,keep),lines=preview.visualLines;if(preview.skippedCount>0){let hint=truncateToWidth(formatHint(preview.skippedCount),width,"...");this.cachedLines=keep==="start"?[...lines,hint]:[hint,...lines]}else this.cachedLines=lines;this.cachedWidth=width}return this.cachedLines}invalidate(){this.cachedWidth=void 0,this.cachedLines=void 0}};import*as os4 from"node:os";import{pathToFileURL as pathToFileURL2}from"node:url";var ST="(?:\\u0007|\\u001B\\u005C|\\u009C)",OSC_START="\\u001B\\]",CSI_START="[\\u001B\\u009B][[\\]()#;?]*(?:\\d{1,4}(?:[;:]\\d{0,4})*)?",CSI_FINAL="[\\dA-PR-TZcf-nq-uy=><~]",ansiRegex=new RegExp(`(?:${OSC_START}[\\s\\S]*?${ST})|${CSI_START}${CSI_FINAL}`,"g"),unfinishedAnsiAtEndRegex=new RegExp(`(?:${OSC_START}(?:[^\\u0007\\u009C\\u001B]|\\u001B(?!\\\\))*|${CSI_START})$`),MAX_PENDING_ANSI_LENGTH=256;function splitIncompleteAnsiSuffix(value){if(!value.includes("\x1B")&&!value.includes("\x9B"))return{complete:value,pending:""};let windowStart=Math.max(0,value.length-MAX_PENDING_ANSI_LENGTH),match2=unfinishedAnsiAtEndRegex.exec(value.slice(windowStart));if(!match2)return{complete:value,pending:""};let splitAt=windowStart+match2.index;return{complete:value.slice(0,splitAt),pending:value.slice(splitAt)}}function stripAnsi(value){if(typeof value!="string")throw new TypeError(`Expected a \`string\`, got \`${typeof value}\``);return!value.includes("\x1B")&&!value.includes("\x9B")?value:value.replace(ansiRegex,"")}function shortenPath2(path14){if(typeof path14!="string")return"";let home=os4.homedir();return path14.startsWith(home)?`~${path14.slice(home.length)}`:path14}function linkPath(styledText,rawPath,cwd){if(!getCapabilities().hyperlinks)return styledText;let absolutePath=resolvePath(rawPath,cwd);return hyperlink(styledText,pathToFileURL2(absolutePath).href)}function str(value){return typeof value=="string"?value:value==null?"":null}function parseLineNumber(value){return typeof value=="string"&&value.trim()!==""&&(value=Number(value)),typeof value=="number"&&Number.isFinite(value)?value:void 0}function formatReadLineRange(offset,limit){if(offset==null&&limit==null)return"";let start=offset==null?1:parseLineNumber(offset);if(start===void 0)return"";if(limit==null)return`:${start}`;let count=parseLineNumber(limit);if(count===void 0)return"";let end=start+count-1;return`:${start}${end?`-${end}`:""}`}function replaceTabs(text2){return text2.replace(/\t/g," ")}function normalizeDisplayText(text2){return text2.replace(/\r/g,"")}function getTextOutput(result2,showImages){if(!result2)return"";let textBlocks=result2.content.filter(c=>c.type==="text"),imageBlocks=result2.content.filter(c=>c.type==="image"),output=textBlocks.map(c=>sanitizeBinaryOutput(stripAnsi(c.text||"")).replace(/\r/g,"")).join(`
|
|
881
|
+
`)}}function printTimings(){if(ENABLED)for(let[namespace,timingNamespace]of timingNamespaces)printTimingGroup(`Startup Timings: ${namespace}`,timingNamespace.timings)}var require3=createRequire5(import.meta.url),isNodeSeaBinary="sea"in process.features&&process.features.sea===!0||process.getBuiltinModule("node:sea")?.isSea()===!0,isTypeScriptSourceRuntime=!isBunBinary&&path7.extname(fileURLToPath5(import.meta.url))===".ts",usesEmbeddedModules=isBunBinary||isNodeSeaBinary||isBundledNode,createJitiPromise;function getCreateJiti(){return createJitiPromise??=(usesEmbeddedModules?import("./jiti-static-loader-CLT3YR3B.js"):import("./jiti-loader-BFSSLU7G.js")).then(module=>module.createJiti),createJitiPromise}var virtualModulesPromise;function getVirtualModules(){return virtualModulesPromise??=import("./virtual-modules-XNEYDLXF.js").then(module=>module.VIRTUAL_MODULES),virtualModulesPromise}var _aliases=null;function getAliases(){if(_aliases)return _aliases;let __dirname2=path7.dirname(fileURLToPath5(import.meta.url)),packageIndex=path7.resolve(__dirname2,"../..","index.js"),typeboxEntry=require3.resolve("typebox"),typeboxCompileEntry=require3.resolve("typebox/compile"),typeboxValueEntry=require3.resolve("typebox/value"),resolveImport=specifier=>fileURLToPath5(import.meta.resolve(specifier)),piCodingAgentEntry=packageIndex,piAgentCoreEntry=resolveImport("@earendil-works/pi-agent-core"),piTuiEntry=resolveImport("@earendil-works/pi-tui"),piAiCompatEntry=resolveImport("@earendil-works/pi-ai/compat"),piAiModelsEntry=resolveImport("@earendil-works/pi-ai/models"),piAiOauthEntry=resolveImport("@earendil-works/pi-ai/oauth"),piAiProvidersEntry=resolveImport("@earendil-works/pi-ai/providers/all");return _aliases={"@earendil-works/pi-coding-agent":piCodingAgentEntry,[DISTRIBUTION_PACKAGE_NAME]:piCodingAgentEntry,"@earendil-works/pi-agent-core":piAgentCoreEntry,"@earendil-works/pi-tui":piTuiEntry,"@earendil-works/pi-ai/providers/all":piAiProvidersEntry,"@earendil-works/pi-ai/compat":piAiCompatEntry,"@earendil-works/pi-ai/models":piAiModelsEntry,"@earendil-works/pi-ai/oauth":piAiOauthEntry,"@earendil-works/pi-ai":piAiCompatEntry,"@mariozechner/pi-coding-agent":piCodingAgentEntry,"@mariozechner/pi-agent-core":piAgentCoreEntry,"@mariozechner/pi-tui":piTuiEntry,"@mariozechner/pi-ai/providers/all":piAiProvidersEntry,"@mariozechner/pi-ai/compat":piAiCompatEntry,"@mariozechner/pi-ai/models":piAiModelsEntry,"@mariozechner/pi-ai/oauth":piAiOauthEntry,"@mariozechner/pi-ai":piAiCompatEntry,typebox:typeboxEntry,"typebox/compile":typeboxCompileEntry,"typebox/value":typeboxValueEntry,"@sinclair/typebox":typeboxEntry,"@sinclair/typebox/compile":typeboxCompileEntry,"@sinclair/typebox/value":typeboxValueEntry},_aliases}var extensionCacheCwd,extensionCacheGeneration=0,extensionCache=new Map;function clearExtensionCache(){extensionCache.clear(),extensionCacheCwd=void 0,extensionCacheGeneration++}function useExtensionCacheCwd(cwd){let resolvedCwd=resolvePath(cwd);return extensionCacheCwd!==void 0&&extensionCacheCwd!==resolvedCwd&&clearExtensionCache(),extensionCacheCwd=resolvedCwd,{cwd:resolvedCwd,generation:extensionCacheGeneration}}function createExtensionRuntime(){let notInitialized=()=>{throw new Error("Extension runtime not initialized. Action methods cannot be called during extension loading.")},state2={},eventBusUnsubscribers=new Set,assertActive=()=>{if(state2.staleMessage)throw new Error(state2.staleMessage)},runtime={sendMessage:notInitialized,sendUserMessage:notInitialized,appendEntry:notInitialized,setSessionName:notInitialized,getSessionName:notInitialized,setLabel:notInitialized,getActiveTools:notInitialized,getAllTools:notInitialized,getSettings:notInitialized,setActiveTools:notInitialized,refreshTools:()=>{},getCommands:notInitialized,setModel:()=>Promise.reject(new Error("Extension runtime not initialized")),getThinkingLevel:notInitialized,setThinkingLevel:notInitialized,flagValues:new Map,pendingProviderRegistrations:[],pendingNativeProviderRegistrations:[],mcpServers:new McpServerRegistry,pendingVirtualModelRegistrations:[],createContext:notInitialized,assertActive,invalidate:message=>{if(!state2.staleMessage){state2.staleMessage=message??"This extension ctx is stale after session replacement or reload. Do not use a captured pi or command ctx after ctx.newSession(), ctx.fork(), ctx.switchSession(), or ctx.reload(). For newSession, fork, and switchSession, move post-replacement work into withSession and use the ctx passed to withSession. For reload, do not use the old ctx after await ctx.reload().";for(let unsubscribe of eventBusUnsubscribers)unsubscribe();eventBusUnsubscribers.clear()}},trackEventBusSubscription:unsubscribe=>{let active=!0,trackedUnsubscribe=()=>{active&&(active=!1,eventBusUnsubscribers.delete(trackedUnsubscribe),unsubscribe())};return eventBusUnsubscribers.add(trackedUnsubscribe),trackedUnsubscribe},registerProvider:(name,config,extensionPath="<unknown>")=>{runtime.pendingProviderRegistrations.push({name,config,extensionPath})},registerNativeProvider:(provider,extensionPath="<unknown>")=>{runtime.pendingNativeProviderRegistrations.push({provider,extensionPath})},unregisterProvider:name=>{runtime.pendingProviderRegistrations=runtime.pendingProviderRegistrations.filter(r=>r.name!==name),runtime.pendingNativeProviderRegistrations=runtime.pendingNativeProviderRegistrations.filter(r=>r.provider.id!==name)},registerVirtualModel:(definition,extensionPath="<unknown>")=>{runtime.pendingVirtualModelRegistrations.push({definition,extensionPath})},unregisterVirtualModel:(provider,id)=>{runtime.pendingVirtualModelRegistrations=runtime.pendingVirtualModelRegistrations.filter(({definition})=>definition.provider!==provider||definition.id!==id)}};return runtime}function createExtensionAPI(extension,runtime,cwd,eventBus){let pendingFlagValues=new Map,pendingRuntimeChanges=[],loadingUnsubscribers=[],state2="loading",assertActive=()=>{if(state2==="failed")throw new Error(`Extension "${extension.path}" failed to load and its API is no longer active.`);runtime.assertActive()},applyRuntimeChange=change=>{state2==="loading"?pendingRuntimeChanges.push(change):change()},clearPending=()=>{pendingFlagValues.clear(),pendingRuntimeChanges.length=0,loadingUnsubscribers.length=0};return{api:{on(event,handler){assertActive();let registeredHandler=(...args)=>handler(...args),list2=extension.handlers.get(event)??[];return list2.push(registeredHandler),extension.handlers.set(event,list2),()=>{let handlers=extension.handlers.get(event);if(!handlers)return;let handlerIndex=handlers.indexOf(registeredHandler);handlerIndex!==-1&&(handlers.splice(handlerIndex,1),handlers.length===0&&extension.handlers.delete(event))}},registerTool(tool){if(assertActive(),typeof tool.parameters!="object"||tool.parameters===null||Array.isArray(tool.parameters))throw new Error(`Tool "${tool.name}" registered by extension "${extension.path}" must define an object parameter schema.`);extension.tools.set(tool.name,{definition:tool,sourceInfo:extension.sourceInfo}),runtime.refreshTools()},registerCommand(name,options){if(assertActive(),typeof name!="string"||name.length===0)throw new Error(`Command registered by extension "${extension.path}" must have a non-empty string name. Use pi.registerCommand("name", { description, handler }).`);if(typeof options?.handler!="function")throw new Error(`Command "/${name}" registered by extension "${extension.path}" must define handler().`);extension.commands.set(name,{name,sourceInfo:extension.sourceInfo,...options})},registerShortcut(shortcut,options){assertActive(),extension.shortcuts.set(shortcut,{shortcut,extensionPath:extension.path,...options})},registerFlag(name,options){if(assertActive(),options.default!==void 0&&typeof options.default!==options.type)throw new Error(`Invalid default for flag "${name}": expected ${options.type}, got ${typeof options.default}`);extension.flags.set(name,{name,extensionPath:extension.path,...options}),options.default!==void 0&&!runtime.flagValues.has(name)&&(state2==="loading"?pendingFlagValues.has(name)||pendingFlagValues.set(name,options.default):runtime.flagValues.set(name,options.default))},registerMessageRenderer(customType,renderer){assertActive(),extension.messageRenderers.set(customType,renderer)},registerMarkdownTransformer(transformer){assertActive(),extension.markdownTransformer=transformer},registerEntryRenderer(customType,renderer){assertActive(),extension.entryRenderers??=new Map,extension.entryRenderers.set(customType,renderer)},registerToolRenderer(resolver){assertActive(),extension.toolRenderers??=[],extension.toolRenderers.push(resolver)},getFlag(name){if(assertActive(),!!extension.flags.has(name))return runtime.flagValues.has(name)?runtime.flagValues.get(name):pendingFlagValues.get(name)},sendMessage(message,options){assertActive(),runtime.sendMessage(message,options)},sendUserMessage(content,options){assertActive(),runtime.sendUserMessage(content,options)},appendEntry(customType,data){assertActive(),runtime.appendEntry(customType,data)},setSessionName(name){assertActive(),runtime.setSessionName(name)},getSessionName(){return assertActive(),runtime.getSessionName()},setLabel(entryId,label){assertActive(),runtime.setLabel(entryId,label)},exec(command,args,options){return assertActive(),execCommand(command,args,options?.cwd??cwd,options)},getActiveTools(){return assertActive(),runtime.getActiveTools()},getAllTools(){return assertActive(),runtime.getAllTools()},getSettings(){return assertActive(),runtime.getSettings()},setActiveTools(toolNames){assertActive(),runtime.setActiveTools(toolNames)},getCommands(){return assertActive(),runtime.getCommands()},setModel(model){return assertActive(),runtime.setModel(model)},getThinkingLevel(){return assertActive(),runtime.getThinkingLevel()},setThinkingLevel(level){assertActive(),runtime.setThinkingLevel(level)},registerProvider(providerOrName,config){if(assertActive(),typeof providerOrName=="string"){if(!config)throw new Error("Provider config is required when registering by name");applyRuntimeChange(()=>runtime.registerProvider(providerOrName,config,extension.path));return}applyRuntimeChange(()=>runtime.registerNativeProvider(providerOrName,extension.path))},unregisterProvider(name){assertActive(),applyRuntimeChange(()=>runtime.unregisterProvider(name,extension.path))},registerMcpServer(name,config){assertActive();let validated=validateMcpServerConfig(name,config);if(typeof validated=="string")throw new Error(`Invalid MCP server registered by extension "${extension.path}": ${validated}`);let owner=runtime.mcpServers.get(name)?.extensionPath;if(owner!==void 0&&owner!==extension.path)throw new Error(`MCP server "${name}" is already registered by extension "${owner}"`);let clash=runtime.mcpServers.list().find(server2=>server2.name!==name&&mcpNamespace(server2.name)===mcpNamespace(name));if(clash)throw new Error(`MCP server "${name}" conflicts with registered server "${clash.name}"`);let server={name,config:structuredClone(validated),extensionPath:extension.path};applyRuntimeChange(()=>runtime.mcpServers.register(server))},unregisterMcpServer(name){assertActive(),applyRuntimeChange(()=>runtime.mcpServers.unregister(name,extension.path))},getMcpServers(){return assertActive(),runtime.mcpServers.list()},registerVirtualModel(model){assertActive();let definition={...model,route:request=>model.route(request,runtime.createContext())};applyRuntimeChange(()=>runtime.registerVirtualModel(definition,extension.path))},unregisterVirtualModel(provider,id){assertActive(),applyRuntimeChange(()=>runtime.unregisterVirtualModel(provider,id))},events:{emit(channel,data){assertActive(),eventBus.emit(channel,data)},on(channel,handler){assertActive();let unsubscribe=runtime.trackEventBusSubscription(eventBus.on(channel,handler));return state2==="loading"&&loadingUnsubscribers.push(unsubscribe),unsubscribe}}},commit:()=>{if(state2==="loading"){runtime.assertActive();for(let[name,value]of pendingFlagValues)runtime.flagValues.has(name)||runtime.flagValues.set(name,value);for(let apply of pendingRuntimeChanges)apply();state2="active",clearPending()}},discard:()=>{if(state2==="loading"){state2="failed";for(let unsubscribe of loadingUnsubscribers)unsubscribe();clearPending()}}}}function isCurrentCacheToken(cacheToken){return cacheToken!==void 0&&extensionCacheCwd===cacheToken.cwd&&extensionCacheGeneration===cacheToken.generation}async function loadExtensionModule(extensionPath,cacheToken){if(isCurrentCacheToken(cacheToken)){let cachedFactory=extensionCache.get(extensionPath);if(cachedFactory)return cachedFactory}let createJitiImpl=await getCreateJiti(),resolutionOptions=usesEmbeddedModules?{virtualModules:await getVirtualModules(),tryNative:!1}:isTypeScriptSourceRuntime?{virtualModules:await getVirtualModules(),tsconfigPaths:!0}:{alias:getAliases()},factory=await createJitiImpl(import.meta.url,{moduleCache:!1,...resolutionOptions}).import(extensionPath,{default:!0});if(typeof factory=="function")return isCurrentCacheToken(cacheToken)&&extensionCache.set(extensionPath,factory),factory}function createExtension(extensionPath,resolvedPath){let source=getSyntheticPathSource(extensionPath)??"local",baseDir=isSyntheticPath(extensionPath)?void 0:path7.dirname(resolvedPath);return{path:extensionPath,resolvedPath,sourceInfo:createSyntheticSourceInfo(extensionPath,{source,baseDir}),handlers:new Map,tools:new Map,messageRenderers:new Map,entryRenderers:new Map,commands:new Map,flags:new Map,shortcuts:new Map}}async function initializeExtension(factory,extensionPath,resolvedPath,cwd,eventBus,runtime){let extension=createExtension(extensionPath,resolvedPath),load=createExtensionAPI(extension,runtime,cwd,eventBus);try{await factory(load.api),load.commit()}catch(error){throw load.discard(),error}return time(`${extensionPath} factory`,"extensions"),extension}async function loadExtension(extensionPath,cwd,eventBus,runtime,cacheToken){let resolvedPath=resolvePath(extensionPath,cwd,{normalizeUnicodeSpaces:!0});try{let factory=await loadExtensionModule(resolvedPath,cacheToken);return time(`${extensionPath} module import`,"extensions"),factory?{extension:await initializeExtension(factory,extensionPath,resolvedPath,cwd,eventBus,runtime),error:null}:{extension:null,error:`Extension does not export a valid factory function: ${extensionPath}`}}catch(err){return{extension:null,error:`Failed to load extension: ${err instanceof Error?err.message:String(err)}`}}}async function loadExtensionFromFactory(factory,cwd,eventBus,runtime,extensionPath="<inline>"){let resolvedCwd=resolvePath(cwd);return initializeExtension(factory,extensionPath,extensionPath,resolvedCwd,eventBus,runtime)}async function loadExtensionsInternal(paths,cwd,eventBus,runtime,useCache=!1){let extensions=[],errors=[],warnings=[],cacheToken=useCache?useExtensionCacheCwd(cwd):void 0,resolvedCwd=cacheToken?.cwd??resolvePath(cwd),resolvedEventBus=eventBus??createEventBus(),resolvedRuntime=runtime??createExtensionRuntime();for(let extPath of paths){let{extension,error}=await loadExtension(extPath,resolvedCwd,resolvedEventBus,resolvedRuntime,cacheToken);if(error){errors.push({path:extPath,error});continue}extension&&extensions.push(extension)}return{extensions,errors,warnings,runtime:resolvedRuntime}}async function loadExtensions(paths,cwd,eventBus,runtime){return loadExtensionsInternal(paths,cwd,eventBus,runtime)}async function loadExtensionsCached(paths,cwd,eventBus,runtime){return loadExtensionsInternal(paths,cwd,eventBus,runtime,!0)}function isExtensionFile(name){return name.endsWith(".ts")||name.endsWith(".js")}function resolveExtensionEntries2(dir){let packageJsonPath=path7.join(dir,"package.json");if(fs5.existsSync(packageJsonPath)){let manifest=readPiManifest(packageJsonPath);if(manifest?.extensions?.length){let entries=[];for(let extPath of manifest.extensions){let resolvedExtPath=path7.resolve(dir,extPath);fs5.existsSync(resolvedExtPath)&&entries.push(resolvedExtPath)}if(entries.length>0)return entries}}let indexTs=path7.join(dir,"index.ts"),indexJs=path7.join(dir,"index.js");return fs5.existsSync(indexTs)?[indexTs]:fs5.existsSync(indexJs)?[indexJs]:null}function discoverExtensionsInDir(dir){if(!fs5.existsSync(dir))return[];let discovered=[];try{let entries=fs5.readdirSync(dir,{withFileTypes:!0});for(let entry of entries){let entryPath=path7.join(dir,entry.name);if((entry.isFile()||entry.isSymbolicLink())&&isExtensionFile(entry.name)){discovered.push(entryPath);continue}if(entry.isDirectory()||entry.isSymbolicLink()){let entries2=resolveExtensionEntries2(entryPath);entries2&&discovered.push(...entries2)}}}catch{return[]}return discovered}async function discoverAndLoadExtensions(configuredPaths,cwd,agentDir=getAgentDir(),eventBus){let resolvedCwd=resolvePath(cwd),resolvedAgentDir=resolvePath(agentDir),allPaths=[],seen=new Set,addPaths=paths=>{for(let p of paths){let resolved=path7.resolve(p);seen.has(resolved)||(seen.add(resolved),allPaths.push(p))}},localExtDir=path7.join(resolvedCwd,CONFIG_DIR_NAME,"extensions");addPaths(discoverExtensionsInDir(localExtDir));let globalExtDir=path7.join(resolvedAgentDir,"extensions");addPaths(discoverExtensionsInDir(globalExtDir));for(let p of configuredPaths){let resolved=resolvePath(p,resolvedCwd,{normalizeUnicodeSpaces:!0});if(fs5.existsSync(resolved)&&fs5.statSync(resolved).isDirectory()){let entries=resolveExtensionEntries2(resolved);if(entries){addPaths(entries);continue}addPaths(discoverExtensionsInDir(resolved));continue}addPaths([resolved])}return loadExtensions(allPaths,resolvedCwd,eventBus)}var ModelRegistry=class{constructor(runtime){this.runtime=runtime}getRuntime(){return this.runtime}refresh(options){return this.runtime.refresh(options)}getError(){return this.runtime.getError()}getAll(){return[...this.runtime.getModels()]}getAvailable(){return[...this.runtime.getAvailableSnapshot()]}find(provider,modelId){return this.runtime.getModel(provider,modelId)}findOfType(type,provider,modelId){return this.runtime.getModelOfType(type,provider,modelId)}hasConfiguredAuth(model){return this.runtime.hasConfiguredAuth(model.provider)}async getApiKeyAndHeaders(model){try{let resolution=await this.runtime.getAuth(model);if(!resolution){let compatibility=this.runtime.getCompatibilityRequestConfig(model);return compatibility.authHeader?{ok:!1,error:`No API key found for "${model.provider}"`}:{ok:!0,headers:compatibility.headers}}return{ok:!0,apiKey:resolution.auth.apiKey,headers:resolution.auth.headers,...resolution.auth.baseUrl?{baseUrl:resolution.auth.baseUrl}:{},env:resolution.env}}catch(error){let cause=error instanceof Error?error.cause:void 0,message=cause instanceof Error?cause.message:error instanceof Error?error.message:String(error);return{ok:!1,error:message==="authHeader requires a resolved API key"?`No API key found for "${model.provider}"`:message}}}getProviderAuthStatus(provider){return this.runtime.getProviderAuthStatus(provider)}getProvider(provider){return this.runtime.getProvider(provider)}stream(model,context,options){return this.runtime.stream(model,context,options)}streamSimple(model,context,options){return this.runtime.streamSimple(model,context,options)}complete(model,context,options){return this.runtime.complete(model,context,options)}getModelsOfType(type,provider){return this.runtime.getModelsOfType(type,provider)}getAvailableOfType(type,provider,options){return this.runtime.getAvailableOfType(type,provider,options)}getModelOfType(type,provider,modelId){return this.runtime.getModelOfType(type,provider,modelId)}classify(model,context,options){return this.runtime.classify(model,context,options)}generateImages(model,context,options){return this.runtime.generateImages(model,context,options)}getProviderDisplayName(provider){return this.runtime.getProvider(provider)?.name??provider}getProviderAuth(provider){return this.runtime.getAuth(provider)}async getApiKeyForProvider(provider){try{return(await this.runtime.getAuth(provider))?.auth.apiKey}catch{return}}isUsingOAuth(model){return this.runtime.isUsingOAuth(model.provider)}registerProvider(providerOrName,config){if(typeof providerOrName=="string"){if(!config)throw new Error("Provider config is required when registering by name");this.runtime.registerProvider(providerOrName,config);return}this.runtime.registerNativeProvider(providerOrName)}unregisterProvider(providerName){this.runtime.unregisterProvider(providerName)}registerVirtualModel(definition){this.runtime.registerVirtualModel(definition)}unregisterVirtualModel(providerName,id){this.runtime.unregisterVirtualModel(providerName,id)}getRegisteredProviderConfig(providerName){return this.runtime.getRegisteredProviderConfig(providerName)}getRegisteredNativeProvider(providerName){return this.runtime.getRegisteredNativeProvider(providerName)}getRegisteredProviderIds(){return this.runtime.getRegisteredProviderIds()}};function truncateToVisualLines(text2,maxVisualLines,width,paddingX=0,keep="end"){if(!text2)return{visualLines:[],skippedCount:0};let allVisualLines=new Text(text2,paddingX,0).render(width);if(allVisualLines.length<=maxVisualLines)return{visualLines:allVisualLines,skippedCount:0};let truncatedLines=keep==="start"?allVisualLines.slice(0,maxVisualLines):allVisualLines.slice(-maxVisualLines),skippedCount=allVisualLines.length-maxVisualLines;return{visualLines:truncatedLines,skippedCount}}var VisualLinePreview=class{constructor(options){this.options=options}render(width){if(this.cachedLines===void 0||this.cachedWidth!==width){let{text:text2,maxVisualLines,keep,formatHint}=this.options,preview=truncateToVisualLines(text2,maxVisualLines,width,0,keep),lines=preview.visualLines;if(preview.skippedCount>0){let hint=truncateToWidth(formatHint(preview.skippedCount),width,"...");this.cachedLines=keep==="start"?[...lines,hint]:[hint,...lines]}else this.cachedLines=lines;this.cachedWidth=width}return this.cachedLines}invalidate(){this.cachedWidth=void 0,this.cachedLines=void 0}};import*as os4 from"node:os";import{pathToFileURL as pathToFileURL2}from"node:url";var ST="(?:\\u0007|\\u001B\\u005C|\\u009C)",OSC_START="\\u001B\\]",CSI_START="[\\u001B\\u009B][[\\]()#;?]*(?:\\d{1,4}(?:[;:]\\d{0,4})*)?",CSI_FINAL="[\\dA-PR-TZcf-nq-uy=><~]",ansiRegex=new RegExp(`(?:${OSC_START}[\\s\\S]*?${ST})|${CSI_START}${CSI_FINAL}`,"g"),unfinishedAnsiAtEndRegex=new RegExp(`(?:${OSC_START}(?:[^\\u0007\\u009C\\u001B]|\\u001B(?!\\\\))*|${CSI_START})$`),MAX_PENDING_ANSI_LENGTH=256;function splitIncompleteAnsiSuffix(value){if(!value.includes("\x1B")&&!value.includes("\x9B"))return{complete:value,pending:""};let windowStart=Math.max(0,value.length-MAX_PENDING_ANSI_LENGTH),match2=unfinishedAnsiAtEndRegex.exec(value.slice(windowStart));if(!match2)return{complete:value,pending:""};let splitAt=windowStart+match2.index;return{complete:value.slice(0,splitAt),pending:value.slice(splitAt)}}function stripAnsi(value){if(typeof value!="string")throw new TypeError(`Expected a \`string\`, got \`${typeof value}\``);return!value.includes("\x1B")&&!value.includes("\x9B")?value:value.replace(ansiRegex,"")}function shortenPath2(path14){if(typeof path14!="string")return"";let home=os4.homedir();return path14.startsWith(home)?`~${path14.slice(home.length)}`:path14}function linkPath(styledText,rawPath,cwd){if(!getCapabilities().hyperlinks)return styledText;let absolutePath=resolvePath(rawPath,cwd);return hyperlink(styledText,pathToFileURL2(absolutePath).href)}function str(value){return typeof value=="string"?value:value==null?"":null}function parseLineNumber(value){return typeof value=="string"&&value.trim()!==""&&(value=Number(value)),typeof value=="number"&&Number.isFinite(value)?value:void 0}function formatReadLineRange(offset,limit){if(offset==null&&limit==null)return"";let start=offset==null?1:parseLineNumber(offset);if(start===void 0)return"";if(limit==null)return`:${start}`;let count=parseLineNumber(limit);if(count===void 0)return"";let end=start+count-1;return`:${start}${end?`-${end}`:""}`}function replaceTabs(text2){return text2.replace(/\t/g," ")}function normalizeDisplayText(text2){return text2.replace(/\r/g,"")}function getTextOutput(result2,showImages){if(!result2)return"";let textBlocks=result2.content.filter(c=>c.type==="text"),imageBlocks=result2.content.filter(c=>c.type==="image"),output=textBlocks.map(c=>sanitizeBinaryOutput(stripAnsi(c.text||"")).replace(/\r/g,"")).join(`
|
|
882
882
|
`),caps=getCapabilities();if(imageBlocks.length>0&&(!caps.images||!showImages)){let imageIndicators=imageBlocks.map(img=>{let mimeType=img.mimeType??"image/unknown",dims=img.data&&img.mimeType?getImageDimensions(img.data,img.mimeType)??void 0:void 0;return imageFallback(mimeType,dims)}).join(`
|
|
883
883
|
`);output=output?`${output}
|
|
884
884
|
${imageIndicators}`:imageIndicators}return output}var COLLAPSED_ARGS_CHARS=100;function formatToolCallWithArgs(title,args,theme2,expanded){let header2=theme2.fg("toolTitle",theme2.bold(title));if(args==null)return header2;let entries=typeof args=="object"&&!Array.isArray(args)?Object.entries(args):[["args",args]];if(entries.length===0)return header2;if(expanded){let lines=entries.map(([key,value])=>{let text2=typeof value=="string"?value:JSON.stringify(value,null,2)??String(value);return` ${key}: ${replaceTabs(text2).replace(/\r/g,"").split(`
|
|
@@ -1975,7 +1975,62 @@ This conversation is temporary: it is not added to the original conversation and
|
|
|
1975
1975
|
|
|
1976
1976
|
[Display truncated]`}var BtwAgent=class{constructor(snapshot,runtime,onChange){this.turns=[],this.usage=emptyUsage(),this.blockedTools=0,this.disposed=!1,this.onChange=onChange;let outputReserve=Math.min(32768,snapshot.model.maxTokens,Math.max(1024,Math.floor(snapshot.model.contextWindow/8)));this.inputBudget=snapshot.model.contextWindow-outputReserve-4096;let tools=snapshot.tools.map(tool=>({...structuredClone(tool),label:tool.name,execute:async()=>{throw new Error(TOOL_DENIAL)}}));this.agent=new Agent({initialState:{model:snapshot.model,thinkingLevel:snapshot.thinkingLevel,systemPrompt:snapshot.systemPrompt,tools,messages:createBtwMessages(snapshot)},sessionId:snapshot.streamOptions.sessionId??snapshot.sessionId,transport:snapshot.streamOptions.transport,thinkingBudgets:snapshot.streamOptions.thinkingBudgets,maxRetryDelayMs:snapshot.streamOptions.maxRetryDelayMs,onPayload:snapshot.streamOptions.onPayload,onResponse:snapshot.streamOptions.onResponse,streamFn:(model,context,options)=>runtime.streamSimple(model,context,{...snapshot.streamOptions,...options}),beforeToolCall:async()=>({block:!0,reason:TOOL_DENIAL}),finishTurn:({message,toolResults,context})=>{let question2=this.active;if(!(!question2||this.disposed||message.stopReason==="error"||message.stopReason==="aborted")&&(question2.steps++,!!toolResults.length&&(question2.steps>=3||!this.fits(context.messages))))return question2.turn.status="error",question2.turn.notice=question2.steps>=3?"Stopped after repeated tool requests. BTW can only answer from its snapshot.":"Context limit reached. Reopen /btw for a new conversation.",{action:"end"}}}),this.unsubscribe=this.agent.subscribe(event=>this.handleEvent(event))}get busy(){return this.active!==void 0}validate(text2){if(this.disposed)return"This BTW conversation is closed.";if(this.busy)return"BTW is still answering. Your question is kept in the editor.";if(this.turns.length>=24)return"BTW conversation limit reached. Reopen /btw to start a new one.";if(text2.length>32e3)return`BTW questions are limited to ${32e3.toLocaleString()} characters.`;let question2={role:"user",content:text2,timestamp:Date.now()};if(!this.fits([...this.agent.state.messages,question2]))return"Not enough context space for this BTW question. Compact the main conversation, then reopen /btw."}startQuestion(text2){let error=this.validate(text2);if(error)return{error};let question2={turn:{question:text2,answer:"",thinking:"",status:"streaming",startedAt:Date.now(),elapsedMs:0},steps:0,completedAnswer:"",responseChars:0};return this.active=question2,this.turns.push(question2.turn),{completion:this.runQuestion(question2)}}async runQuestion({turn}){try{this.onChange(),await this.agent.prompt(turn.question),turn.status==="streaming"?(turn.status="done",turn.answer||(turn.notice="The model returned no answer text.")):turn.status==="cancelling"&&(turn.status="cancelled")}catch(error){turn.status="error",turn.notice=displayText(error instanceof Error?error.message:String(error))}finally{this.active=void 0,turn.elapsedMs=Date.now()-turn.startedAt,this.disposed?this.agent.reset():this.onChange()}}cancel(){!this.active||this.disposed||(this.active.turn.status="cancelling",this.agent.abort(),this.onChange())}dispose(){this.disposed||(this.disposed=!0,this.unsubscribe(),this.agent.abort(),this.turns.length=0,this.busy||this.agent.reset())}fits(messages){return estimateContextTokens(normalizeContext({systemPrompt:this.agent.state.systemPrompt,tools:this.agent.state.tools,messages:messages.filter(message=>message.role==="user"||message.role==="assistant"||message.role==="toolResult")})).tokens<this.inputBudget}handleEvent(event){let question2=this.active;if(this.disposed||!question2||event.type!=="message_update"&&event.type!=="message_end"||event.message.role!=="assistant")return;let{turn}=question2,message=event.message;if(this.updateAnswer(question2,message),event.type==="message_end"){question2.completedAnswer=turn.answer,question2.responseChars+=message.content.reduce((sum,part)=>sum+(part.type==="text"?part.text.length:part.type==="thinking"?part.thinking.length:JSON.stringify(part.arguments).length),0),this.blockedTools+=message.content.filter(part=>part.type==="toolCall").length;let usage=message.usage,promptTokens=usage.input+usage.cacheRead+usage.cacheWrite;this.latestCacheHitPercent=(usage.cacheRead>0||usage.cacheWrite>0)&&promptTokens>0?usage.cacheRead/promptTokens*100:void 0;for(let key of["input","output","cacheRead","cacheWrite","totalTokens"])this.usage[key]+=usage[key];for(let key of["input","output","cacheRead","cacheWrite","total"])this.usage.cost[key]+=usage.cost[key];(message.stopReason==="error"||message.stopReason==="aborted")&&(turn.status=message.stopReason==="aborted"?"cancelled":"error",turn.notice??=message.stopReason==="aborted"?"Stopped. You can ask another question.":displayText(message.errorMessage??"The request failed."))}this.onChange()}updateAnswer(question2,message){let{turn}=question2,text2=message.content.filter(part=>part.type==="text").map(part=>part.text).join(""),thinking=message.content.filter(part=>part.type==="thinking").map(part=>part.thinking).join("");text2&&turn.firstAnswerMs===void 0&&(turn.firstAnswerMs=Date.now()-turn.startedAt),turn.answer=displayText([question2.completedAnswer,text2].filter(Boolean).join(`
|
|
1977
1977
|
|
|
1978
|
-
`)),turn.thinking=thinking.slice(-2e3),question2.responseChars+JSON.stringify(message.content).length>512e3&&(turn.notice="Stopped at the BTW response size limit. You can ask a shorter follow-up.",this.agent.abort())}};function tokens(value){return value<1e3?String(value):value<1e4?`${(value/1e3).toFixed(1)}k`:value<1e6?`${Math.round(value/1e3)}k`:value<1e7?`${(value/1e6).toFixed(1)}M`:`${Math.round(value/1e6)}M`}var BtwPanel=class{constructor(tui,getTheme,getState){this.answers=new Map,this.follow=!0,this.offset=0,this.maxOffset=0,this.heldHeight=0,this.disposed=!1,this.tui=tui,this.getTheme=getTheme,this.getState=getState}invalidate(){this.answers.clear()}changed(){if(this.disposed)return;this.tui.requestRender();let state2=this.getState(),busy=state2.phase==="ready"&&state2.conversation.busy;busy&&!this.timer?(this.timer=setTimeout(()=>{this.timer=void 0,this.changed()},150),this.timer.unref?.()):!busy&&this.timer&&(clearTimeout(this.timer),this.timer=void 0)}followTail(){this.follow=!0,this.changed()}scroll(delta){return this.maxOffset===0?!1:(this.offset=Math.max(0,Math.min(this.maxOffset,this.offset+delta)),this.follow=this.offset===this.maxOffset,this.tui.requestRender(),!0)}dispose(){this.disposed=!0,this.timer&&clearTimeout(this.timer),this.timer=void 0,this.answers.clear()}render(width){if(this.disposed||width<1)return[];let state2=this.getState(),busy=state2.phase==="ready"&&state2.conversation.busy,theme2=this.getTheme(),innerWidth=Math.max(1,width-4),lines=this.body(state2,innerWidth,theme2),cap=Math.max(1,Math.floor(this.tui.terminal.rows/3)-2),needed=Math.min(cap,Math.max(1,lines.length));this.heldHeight=busy?Math.min(cap,Math.max(this.heldHeight,needed)):needed,this.maxOffset=Math.max(0,lines.length-this.heldHeight),this.offset=this.follow?this.maxOffset:Math.min(this.offset,this.maxOffset);let body2=lines.slice(this.offset,this.offset+this.heldHeight);for(;body2.length<this.heldHeight;)body2.push("");let close=keyLabel("app.btw.close"),cancel=keyLabel("app.btw.cancel"),title=[theme2.fg("accent",theme2.bold("BTW")),close&&theme2.fg("text",close)+theme2.fg("muted"," close"),busy&&cancel&&theme2.fg("text",cancel)+theme2.fg("muted"," stop")].filter(Boolean).join(theme2.fg("muted"," \xB7 ")),footer=this.footer(state2,theme2);return width<6?body2.map(line=>truncateToWidth(line,width)):[this.border(title,width,!0,theme2),...body2.map(line=>theme2.fg("borderAccent","\u2502 ")+truncateToWidth(line,innerWidth,"\u2026",!0)+theme2.fg("borderAccent"," \u2502")),this.border(footer,width,!1,theme2)]}body(state2,width,theme2){if(state2.phase==="opening")return[theme2.fg("muted","Capturing context\u2026")];if(state2.phase==="error")return new Text(theme2.fg("error",state2.error),0,0).render(width);if(!state2.conversation.turns.length)return[...new Text(theme2.fg("text","Ask a side question in the editor below."),0,0).render(width),...new Text(theme2.fg("muted",`Context at ${new Date(state2.capturedAt).toTimeString().slice(0,8)} \xB7 ${state2.model}`),0,0).render(width)];let lines=[];for(let[index3,turn]of state2.conversation.turns.entries()){if(index3>0&&lines.push(""),lines.push(...new Text(theme2.fg("accent",theme2.bold(`Q${index3+1}: `))+theme2.fg("text",turn.question),0,0).render(width)),turn.answer){let answer=this.answers.get(turn);answer?answer.text!==turn.answer&&(answer.text=turn.answer,answer.markdown.setText(turn.answer)):(answer={text:turn.answer,markdown:new Markdown(turn.answer,0,0,getMarkdownTheme(),{color:text2=>theme2.fg("text",text2)})},this.answers.set(turn,answer)),lines.push(...answer.markdown.render(width))}else turn.thinking&&(turn.status==="streaming"||turn.status==="cancelling")&&lines.push(...wrapTextWithAnsi(theme2.fg("muted",turn.thinking.trimEnd()),width).slice(-2));if(turn.status==="streaming"||turn.status==="cancelling"){let elapsed=((Date.now()-turn.startedAt)/1e3).toFixed(1);lines.push(theme2.fg("muted",`${turn.status==="cancelling"?"Stopping":"Answering"}\u2026 ${elapsed}s`))}turn.notice&&lines.push(...new Text(theme2.fg(turn.status==="error"?"error":"muted",turn.notice),0,0).render(width))}return lines}footer(state2,theme2){let parts=[],label=text2=>theme2.fg("muted",text2),value=text2=>theme2.fg("text",text2);if(this.maxOffset>0){let keys=[keyLabel("app.btw.scrollUp"),keyLabel("app.btw.scrollDown")].filter(Boolean).join("/");parts.push(value(keys)+label(" scroll ")+value(`${this.offset+1}\u2013${this.offset+this.heldHeight}/${this.maxOffset+this.heldHeight}`))}if(state2.phase==="ready"){let{conversation}=state2,{usage}=conversation,stats=[];usage.input>0&&stats.push(`\u2191${tokens(usage.input)}`),usage.output>0&&stats.push(`\u2193${tokens(usage.output)}`),usage.cacheRead>0&&stats.push(`R${tokens(usage.cacheRead)}`),usage.cacheWrite>0&&stats.push(`W${tokens(usage.cacheWrite)}`),conversation.latestCacheHitPercent!==void 0&&stats.push(`CH${conversation.latestCacheHitPercent.toFixed(1)}%`),usage.cost.total>0&&stats.push(`$${usage.cost.total.toFixed(3)}${state2.usesSubscription?" (sub)":""}`),stats.length&&parts.push(value(stats.join(" "))),conversation.blockedTools&&parts.push(value(String(conversation.blockedTools))+label(" tools blocked"));let turn=conversation.turns.at(-1);turn&&!conversation.busy&&(parts.push(value(`${(turn.elapsedMs/1e3).toFixed(1)}s`)),turn.firstAnswerMs!==void 0&&parts.push(label("first ")+value(`${(turn.firstAnswerMs/1e3).toFixed(1)}s`)))}return parts.join(label(" \xB7 "))}border(label,width,top,theme2){let text2=label?` ${truncateToWidth(label,Math.max(0,width-4))} `:"";return theme2.fg("borderAccent",top?"\u256D":"\u2570")+text2+theme2.fg("borderAccent",`${"\u2500".repeat(Math.max(0,width-visibleWidth(text2)-2))}${top?"\u256E":"\u256F"}`)}};var BtwController=class{async open(question2,ctx){let editorHost=ctx.ui.editorHost;if(!editorHost){ctx.ui.notify("/btw is available in interactive mode.","warning");return}this.close(),ctx.ui.setEditorText("");let conversation={ctx,state:{phase:"opening"}};this.current=conversation;try{let pendingSnapshot=ctx.getContextSnapshot();ctx.ui.setWidget("btw",tui=>{let panel=new BtwPanel(tui,()=>ctx.ui.theme,()=>conversation.state);return conversation.panel=panel,panel},{placement:"aboveEditor"}),conversation.unsubscribeKeys=editorHost.onInput(data=>this.handleKey(conversation,data));let snapshot=await pendingSnapshot;if(this.current!==conversation)return;let usesSubscription=ctx.modelRegistry.isUsingOAuth(snapshot.model);if(conversation.state={phase:"ready",capturedAt:snapshot.capturedAt,model:`${snapshot.model.provider}/${snapshot.model.id}`,usesSubscription,conversation:new BtwAgent(snapshot,ctx.modelRuntime,()=>{this.current===conversation&&conversation.panel?.changed()})},conversation.panel?.changed(),question2.trim()){let result2=this.submit(conversation,question2.trim());result2.editorText&&!ctx.ui.getEditorText()&&ctx.ui.setEditorText(result2.editorText)}}catch(error){if(this.current!==conversation)return;conversation.state.phase==="ready"&&conversation.state.conversation.dispose(),conversation.state={phase:"error",error:error instanceof Error?error.message:String(error)},conversation.panel?.changed(),question2&&!ctx.ui.getEditorText()&&ctx.ui.setEditorText(question2)}}intercept(event,ctx){let command=/^\/btw(?:\s+([\s\S]*))?$/.exec(event.text);if(command)return this.open(command[1]??"",ctx),{handled:!0};if(!(!this.current||event.kind!=="prompt"))return this.submit(this.current,event.text)}close(){let conversation=this.current;conversation&&(this.current=void 0,conversation.unsubscribeKeys?.(),conversation.panel?.dispose(),conversation.state.phase==="ready"&&conversation.state.conversation.dispose(),conversation.ctx.ui.setWidget("btw",void 0),conversation.ctx.ui.setEditorText(""))}submit(conversation,text2){let{state:state2}=conversation,result2=state2.phase==="ready"?state2.conversation.startQuestion(text2):{error:"BTW is not ready. Reopen /btw if context preparation failed."};return"error"in result2?(conversation.ctx.ui.notify(result2.error,"warning"),{handled:!0,editorText:text2}):(conversation.panel?.followTail(),result2.completion.catch(error=>{this.current===conversation&&(conversation.ctx.ui.notify(error instanceof Error?error.message:String(error),"error"),conversation.ctx.ui.getEditorText()||conversation.ctx.ui.setEditorText(text2))}),{handled:!0})}handleKey(conversation,data){if(this.current!==conversation)return;let keys=getKeybindings();if(keys.matches(data,"app.btw.close"))return this.close(),{consume:!0};if(keys.matches(data,"app.btw.cancel"))return conversation.state.phase==="ready"&&conversation.state.conversation.busy?conversation.state.conversation.cancel():this.close(),{consume:!0};if(keys.matches(data,"tui.editor.historyPrevious")||keys.matches(data,"tui.editor.historyNext"))return{consume:!0};let direction=keys.matches(data,"app.btw.scrollUp")?-1:keys.matches(data,"app.btw.scrollDown")?1:0,cursorUp=keys.matches(data,"tui.editor.cursorUp"),cursorDown=keys.matches(data,"tui.editor.cursorDown");if(conversation.ctx.ui.getEditorText()){if(cursorUp||cursorDown){let cursor=conversation.ctx.ui.editorHost?.getCursor();if(!cursor||cursorUp&&cursor.line===0&&cursor.col===0)return{consume:!0}}}else if(direction&&conversation.panel?.scroll(direction),direction||cursorUp||cursorDown)return{consume:!0}}};function btwExtension(pi){let controller=new BtwController,unsubscribeSubmit;pi.registerCommand("btw",{description:"Ask a temporary side question using the current context",handler:async(args,ctx)=>{await controller.open(args,ctx)}}),pi.on("session_start",(_event,ctx)=>{unsubscribeSubmit?.(),controller.close(),unsubscribeSubmit=ctx.ui.editorHost?.onSubmit(event=>controller.intercept(event,ctx))}),pi.on("session_tree",()=>controller.close()),pi.on("session_shutdown",()=>{unsubscribeSubmit?.(),unsubscribeSubmit=void 0,controller.close()})}var DEEPWIKI_TOOL_NAME="deepwiki",DEEPWIKI_LABEL="DeepWiki",DEEPWIKI_DESCRIPTION="Query DeepWiki's AI-generated documentation for indexed public GitHub repositories. structure lists a repo's wiki pages; contents reads one page, or the whole wiki truncated past ~120k chars when page is omitted; question answers a focused query about one repo, or across up to 10 repos for a comparison. Results are indexed public snapshots and may cite sources. A repository that is not indexed fails every action with a repository-not-found error.",DEEPWIKI_PROMPT_SNIPPET="Query AI-generated docs for public GitHub repos: architecture, APIs, implementation patterns",DEEPWIKI_PROMPT_GUIDELINES=["Run `deepwiki` action `structure` first for a repo; a repository-not-found error means it is not indexed, so do not retry that repo with `contents` or `question`.","Do not use `deepwiki` for local workspace files, private repos, exact current HEAD, or freshness-sensitive facts (releases, pricing, advisories); use local tools or current primary sources instead."];var PAGE_HEADER_RE=/^#\s+Page:\s+(.+)$/;function pageOffsets(text2){let re=new RegExp(PAGE_HEADER_RE.source,"gm"),chunks=[],match2=re.exec(text2);for(;match2!==null;)chunks.push({title:match2[1].trim(),start:match2.index}),match2=re.exec(text2);return chunks}function cutAtLineBoundary(text2,budget){if(text2.length<=budget)return text2;let slice=text2.slice(0,budget),lastNewline=slice.lastIndexOf(`
|
|
1978
|
+
`)),turn.thinking=thinking.slice(-2e3),question2.responseChars+JSON.stringify(message.content).length>512e3&&(turn.notice="Stopped at the BTW response size limit. You can ask a shorter follow-up.",this.agent.abort())}};function tokens(value){return value<1e3?String(value):value<1e4?`${(value/1e3).toFixed(1)}k`:value<1e6?`${Math.round(value/1e3)}k`:value<1e7?`${(value/1e6).toFixed(1)}M`:`${Math.round(value/1e6)}M`}var BtwPanel=class{constructor(tui,getTheme,getState){this.answers=new Map,this.follow=!0,this.offset=0,this.maxOffset=0,this.heldHeight=0,this.disposed=!1,this.tui=tui,this.getTheme=getTheme,this.getState=getState}invalidate(){this.answers.clear()}changed(){if(this.disposed)return;this.tui.requestRender();let state2=this.getState(),busy=state2.phase==="ready"&&state2.conversation.busy;busy&&!this.timer?(this.timer=setTimeout(()=>{this.timer=void 0,this.changed()},150),this.timer.unref?.()):!busy&&this.timer&&(clearTimeout(this.timer),this.timer=void 0)}followTail(){this.follow=!0,this.changed()}scroll(delta){return this.maxOffset===0?!1:(this.offset=Math.max(0,Math.min(this.maxOffset,this.offset+delta)),this.follow=this.offset===this.maxOffset,this.tui.requestRender(),!0)}dispose(){this.disposed=!0,this.timer&&clearTimeout(this.timer),this.timer=void 0,this.answers.clear()}render(width){if(this.disposed||width<1)return[];let state2=this.getState(),busy=state2.phase==="ready"&&state2.conversation.busy,theme2=this.getTheme(),innerWidth=Math.max(1,width-4),lines=this.body(state2,innerWidth,theme2),cap=Math.max(1,Math.floor(this.tui.terminal.rows/3)-2),needed=Math.min(cap,Math.max(1,lines.length));this.heldHeight=busy?Math.min(cap,Math.max(this.heldHeight,needed)):needed,this.maxOffset=Math.max(0,lines.length-this.heldHeight),this.offset=this.follow?this.maxOffset:Math.min(this.offset,this.maxOffset);let body2=lines.slice(this.offset,this.offset+this.heldHeight);for(;body2.length<this.heldHeight;)body2.push("");let close=keyLabel("app.btw.close"),cancel=keyLabel("app.btw.cancel"),title=[theme2.fg("accent",theme2.bold("BTW")),close&&theme2.fg("text",close)+theme2.fg("muted"," close"),busy&&cancel&&theme2.fg("text",cancel)+theme2.fg("muted"," stop")].filter(Boolean).join(theme2.fg("muted"," \xB7 ")),footer=this.footer(state2,theme2);return width<6?body2.map(line=>truncateToWidth(line,width)):[this.border(title,width,!0,theme2),...body2.map(line=>theme2.fg("borderAccent","\u2502 ")+truncateToWidth(line,innerWidth,"\u2026",!0)+theme2.fg("borderAccent"," \u2502")),this.border(footer,width,!1,theme2)]}body(state2,width,theme2){if(state2.phase==="opening")return[theme2.fg("muted","Capturing context\u2026")];if(state2.phase==="error")return new Text(theme2.fg("error",state2.error),0,0).render(width);if(!state2.conversation.turns.length)return[...new Text(theme2.fg("text","Ask a side question in the editor below."),0,0).render(width),...new Text(theme2.fg("muted",`Context at ${new Date(state2.capturedAt).toTimeString().slice(0,8)} \xB7 ${state2.model}`),0,0).render(width)];let lines=[];for(let[index3,turn]of state2.conversation.turns.entries()){if(index3>0&&lines.push(""),lines.push(...new Text(theme2.fg("accent",theme2.bold(`Q${index3+1}: `))+theme2.fg("text",turn.question),0,0).render(width)),turn.answer){let answer=this.answers.get(turn);answer?answer.text!==turn.answer&&(answer.text=turn.answer,answer.markdown.setText(turn.answer)):(answer={text:turn.answer,markdown:new Markdown(turn.answer,0,0,getMarkdownTheme(),{color:text2=>theme2.fg("text",text2)})},this.answers.set(turn,answer)),lines.push(...answer.markdown.render(width))}else turn.thinking&&(turn.status==="streaming"||turn.status==="cancelling")&&lines.push(...wrapTextWithAnsi(theme2.fg("muted",turn.thinking.trimEnd()),width).slice(-2));if(turn.status==="streaming"||turn.status==="cancelling"){let elapsed=((Date.now()-turn.startedAt)/1e3).toFixed(1);lines.push(theme2.fg("muted",`${turn.status==="cancelling"?"Stopping":"Answering"}\u2026 ${elapsed}s`))}turn.notice&&lines.push(...new Text(theme2.fg(turn.status==="error"?"error":"muted",turn.notice),0,0).render(width))}return lines}footer(state2,theme2){let parts=[],label=text2=>theme2.fg("muted",text2),value=text2=>theme2.fg("text",text2);if(this.maxOffset>0){let keys=[keyLabel("app.btw.scrollUp"),keyLabel("app.btw.scrollDown")].filter(Boolean).join("/");parts.push(value(keys)+label(" scroll ")+value(`${this.offset+1}\u2013${this.offset+this.heldHeight}/${this.maxOffset+this.heldHeight}`))}if(state2.phase==="ready"){let{conversation}=state2,{usage}=conversation,stats=[];usage.input>0&&stats.push(`\u2191${tokens(usage.input)}`),usage.output>0&&stats.push(`\u2193${tokens(usage.output)}`),usage.cacheRead>0&&stats.push(`R${tokens(usage.cacheRead)}`),usage.cacheWrite>0&&stats.push(`W${tokens(usage.cacheWrite)}`),conversation.latestCacheHitPercent!==void 0&&stats.push(`CH${conversation.latestCacheHitPercent.toFixed(1)}%`),usage.cost.total>0&&stats.push(`$${usage.cost.total.toFixed(3)}${state2.usesSubscription?" (sub)":""}`),stats.length&&parts.push(value(stats.join(" "))),conversation.blockedTools&&parts.push(value(String(conversation.blockedTools))+label(" tools blocked"));let turn=conversation.turns.at(-1);turn&&!conversation.busy&&(parts.push(value(`${(turn.elapsedMs/1e3).toFixed(1)}s`)),turn.firstAnswerMs!==void 0&&parts.push(label("first ")+value(`${(turn.firstAnswerMs/1e3).toFixed(1)}s`)))}return parts.join(label(" \xB7 "))}border(label,width,top,theme2){let text2=label?` ${truncateToWidth(label,Math.max(0,width-4))} `:"";return theme2.fg("borderAccent",top?"\u256D":"\u2570")+text2+theme2.fg("borderAccent",`${"\u2500".repeat(Math.max(0,width-visibleWidth(text2)-2))}${top?"\u256E":"\u256F"}`)}};var BtwController=class{async open(question2,ctx){let editorHost=ctx.ui.editorHost;if(!editorHost){ctx.ui.notify("/btw is available in interactive mode.","warning");return}this.close(),ctx.ui.setEditorText("");let conversation={ctx,state:{phase:"opening"}};this.current=conversation;try{let pendingSnapshot=ctx.getContextSnapshot();ctx.ui.setWidget("btw",tui=>{let panel=new BtwPanel(tui,()=>ctx.ui.theme,()=>conversation.state);return conversation.panel=panel,panel},{placement:"aboveEditor"}),conversation.unsubscribeKeys=editorHost.onInput(data=>this.handleKey(conversation,data));let snapshot=await pendingSnapshot;if(this.current!==conversation)return;let usesSubscription=ctx.modelRegistry.isUsingOAuth(snapshot.model);if(conversation.state={phase:"ready",capturedAt:snapshot.capturedAt,model:`${snapshot.model.provider}/${snapshot.model.id}`,usesSubscription,conversation:new BtwAgent(snapshot,ctx.modelRuntime,()=>{this.current===conversation&&conversation.panel?.changed()})},conversation.panel?.changed(),question2.trim()){let result2=this.submit(conversation,question2.trim());result2.editorText&&!ctx.ui.getEditorText()&&ctx.ui.setEditorText(result2.editorText)}}catch(error){if(this.current!==conversation)return;conversation.state.phase==="ready"&&conversation.state.conversation.dispose(),conversation.state={phase:"error",error:error instanceof Error?error.message:String(error)},conversation.panel?.changed(),question2&&!ctx.ui.getEditorText()&&ctx.ui.setEditorText(question2)}}intercept(event,ctx){let command=/^\/btw(?:\s+([\s\S]*))?$/.exec(event.text);if(command)return this.open(command[1]??"",ctx),{handled:!0};if(!(!this.current||event.kind!=="prompt"))return this.submit(this.current,event.text)}close(){let conversation=this.current;conversation&&(this.current=void 0,conversation.unsubscribeKeys?.(),conversation.panel?.dispose(),conversation.state.phase==="ready"&&conversation.state.conversation.dispose(),conversation.ctx.ui.setWidget("btw",void 0),conversation.ctx.ui.setEditorText(""))}submit(conversation,text2){let{state:state2}=conversation,result2=state2.phase==="ready"?state2.conversation.startQuestion(text2):{error:"BTW is not ready. Reopen /btw if context preparation failed."};return"error"in result2?(conversation.ctx.ui.notify(result2.error,"warning"),{handled:!0,editorText:text2}):(conversation.panel?.followTail(),result2.completion.catch(error=>{this.current===conversation&&(conversation.ctx.ui.notify(error instanceof Error?error.message:String(error),"error"),conversation.ctx.ui.getEditorText()||conversation.ctx.ui.setEditorText(text2))}),{handled:!0})}handleKey(conversation,data){if(this.current!==conversation)return;let keys=getKeybindings();if(keys.matches(data,"app.btw.close"))return this.close(),{consume:!0};if(keys.matches(data,"app.btw.cancel"))return conversation.state.phase==="ready"&&conversation.state.conversation.busy?conversation.state.conversation.cancel():this.close(),{consume:!0};if(keys.matches(data,"tui.editor.historyPrevious")||keys.matches(data,"tui.editor.historyNext"))return{consume:!0};let direction=keys.matches(data,"app.btw.scrollUp")?-1:keys.matches(data,"app.btw.scrollDown")?1:0,cursorUp=keys.matches(data,"tui.editor.cursorUp"),cursorDown=keys.matches(data,"tui.editor.cursorDown");if(conversation.ctx.ui.getEditorText()){if(cursorUp||cursorDown){let cursor=conversation.ctx.ui.editorHost?.getCursor();if(!cursor||cursorUp&&cursor.line===0&&cursor.col===0)return{consume:!0}}}else if(direction&&conversation.panel?.scroll(direction),direction||cursorUp||cursorDown)return{consume:!0}}};function btwExtension(pi){let controller=new BtwController,unsubscribeSubmit;pi.registerCommand("btw",{description:"Ask a temporary side question using the current context",handler:async(args,ctx)=>{await controller.open(args,ctx)}}),pi.on("session_start",(_event,ctx)=>{unsubscribeSubmit?.(),controller.close(),unsubscribeSubmit=ctx.ui.editorHost?.onSubmit(event=>controller.intercept(event,ctx))}),pi.on("session_tree",()=>controller.close()),pi.on("session_shutdown",()=>{unsubscribeSubmit?.(),unsubscribeSubmit=void 0,controller.close()})}function formatTokens2(count){return count>=1e6?`${(count/1e6).toFixed(1)}m`:count>=1e3?`${(count/1e3).toFixed(1)}k`:String(count)}var renderCachedCompactionEntry=(entry,_options,theme2)=>{let data=entry.data;if(!data)return;let promptTokens=data.input+data.cacheRead+data.cacheWrite,percentage=promptTokens>0?(100*data.cacheRead/promptTokens).toFixed(1):"0.0",title=`Cached compaction \xB7 ${data.reason==="manual"?"manual":"automatic"}`,stats=`Cache ${formatTokens2(data.cacheRead)}/${formatTokens2(promptTokens)} (${percentage}%) \xB7 output ${formatTokens2(data.output)} \xB7 ${(data.durationMs/1e3).toFixed(1)}s`;return new Text(`${theme2.fg("accent",title)}
|
|
1979
|
+
${theme2.fg("dim",stats)}`,1,0)};function sameMessage(candidate,projected){let serialized=JSON.stringify(candidate);return convertToLlm([projected]).some(message=>JSON.stringify(message)===serialized)}function messagePreview(message){let text2;if(message.role==="user"?text2=contentText(message.content):message.role==="assistant"&&(text2=message.content.flatMap(block=>block.type==="text"?[block.text]:block.type==="toolCall"?[`[tool call: ${block.name} ${JSON.stringify(block.arguments)}]`]:[]).join(`
|
|
1980
|
+
`)),text2=text2?.trim(),!!text2)return text2.length>400?`${text2.slice(0,400)}\u2026`:text2}function keptStart(entries,firstKeptEntryId,conversation){let projected=buildSessionProjection(entries).entries,start=projected.findIndex(entry=>entry.sourceEntry.id===firstKeptEntryId);if(start===-1)return;let at2=-1;for(let message of projected.slice(start).flatMap(entry=>entry.messages))if(at2=conversation.findLastIndex(candidate=>sameMessage(candidate,message)),at2!==-1)break;if(at2===-1)return;let previews=conversation.slice(at2).map(messagePreview),text2=previews[0];return text2?{text:text2,fromEnd:previews.filter(preview=>preview===text2).length,count:previews.length}:void 0}function summaryInstruction(kept,customInstructions){let repeated=kept.fromEnd>1?` Several retained messages begin with this text. The boundary is occurrence ${kept.fromEnd}, counting backward from the end of the conversation.`:"",toolCalls=kept.text.includes("[tool call: ")?" Tool calls are written as [tool call: name arguments].":"",focus=customInstructions?.trim()?`
|
|
1981
|
+
|
|
1982
|
+
Additional focus from the user:
|
|
1983
|
+
${customInstructions.trim()}`:"";return`Stop working on the current task. Do not call any tools.
|
|
1984
|
+
|
|
1985
|
+
Write a structured context checkpoint summary of the earlier part of this conversation. Another LLM will continue the task from your summary, followed by the last ${kept.count} messages, which will remain in context verbatim.
|
|
1986
|
+
|
|
1987
|
+
The retained messages begin with the message that starts with this text.${repeated}${toolCalls}
|
|
1988
|
+
|
|
1989
|
+
<kept-start>
|
|
1990
|
+
${kept.text}
|
|
1991
|
+
</kept-start>
|
|
1992
|
+
|
|
1993
|
+
Summarize only the messages before that boundary, as if the conversation had ended immediately before it. Work occurring at or after the boundary has not happened as far as this summary is concerned: do not list it as completed. If it was already planned, include it under Next Steps instead.
|
|
1994
|
+
|
|
1995
|
+
If the conversation contains an earlier checkpoint summary, fold its still-relevant facts into this summary and update its progress and next steps.
|
|
1996
|
+
|
|
1997
|
+
Use exactly this structure:
|
|
1998
|
+
|
|
1999
|
+
## Goal
|
|
2000
|
+
[What the user is trying to accomplish. Include multiple goals if applicable.]
|
|
2001
|
+
|
|
2002
|
+
## Constraints & Preferences
|
|
2003
|
+
- [Requirements, preferences, and explicit constraints from the user]
|
|
2004
|
+
- [Use "(none)" when appropriate]
|
|
2005
|
+
|
|
2006
|
+
## Progress
|
|
2007
|
+
### Done
|
|
2008
|
+
- [x] [Work completed before the boundary]
|
|
2009
|
+
|
|
2010
|
+
### In Progress
|
|
2011
|
+
- [ ] [Work underway at the boundary]
|
|
2012
|
+
|
|
2013
|
+
### Blocked
|
|
2014
|
+
- [Issues preventing progress, or "(none)"]
|
|
2015
|
+
|
|
2016
|
+
## Key Decisions
|
|
2017
|
+
- **[Decision]**: [Rationale]
|
|
2018
|
+
|
|
2019
|
+
## Next Steps
|
|
2020
|
+
1. [Ordered steps needed to continue]
|
|
2021
|
+
|
|
2022
|
+
## Critical Context
|
|
2023
|
+
- [Exact information needed to continue: file paths, symbols, commands, important tool results, error messages, and relevant technical details]
|
|
2024
|
+
|
|
2025
|
+
Be concise but preserve information required to continue without rereading the original conversation. Keep exact file paths, function names, commands, and error messages. Do not include file-operation lists; they will be added automatically. Return only the summary.${focus}`}function isPlainObject(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function checkpointSummary(text2,fileOps,entries){let read=new Set(fileOps.read),modified=new Set([...fileOps.written,...fileOps.edited]),previousDetails=getLatestCompactionEntry(entries)?.details;if(isPlainObject(previousDetails)){let{readFiles,modifiedFiles}=previousDetails;if(Array.isArray(readFiles))for(let file of readFiles)typeof file=="string"&&read.add(file);if(Array.isArray(modifiedFiles))for(let file of modifiedFiles)typeof file=="string"&&modified.add(file)}let details={readFiles:[...read].filter(file=>!modified.has(file)).sort(),modifiedFiles:[...modified].sort()};return{summary:[text2.replace(/<(read-files|modified-files)>[\s\S]*?<\/\1>/g,"").trim(),details.readFiles.length>0?`<read-files>
|
|
2026
|
+
${details.readFiles.join(`
|
|
2027
|
+
`)}
|
|
2028
|
+
</read-files>`:"",details.modifiedFiles.length>0?`<modified-files>
|
|
2029
|
+
${details.modifiedFiles.join(`
|
|
2030
|
+
`)}
|
|
2031
|
+
</modified-files>`:""].filter(Boolean).join(`
|
|
2032
|
+
|
|
2033
|
+
`),details}}var CARD_TYPE="cached-compaction";function cachedCompaction(pi){let completed,pendingCard;pi.registerEntryRenderer(CARD_TYPE,renderCachedCompactionEntry),pi.on("session_before_compact",async(event,ctx)=>{if(completed=void 0,event.reason==="overflow")return;let startedAt=Date.now();try{let snapshot=await ctx.getContextSnapshot(),kept=keptStart(event.branchEntries,event.preparation.firstKeptEntryId,snapshot.messages);if(!kept)return;let response=await ctx.modelRegistry.streamSimple(snapshot.model,{messages:[...snapshot.messages,{role:"user",content:[{type:"text",text:summaryInstruction(kept,event.customInstructions)}],timestamp:Date.now()}]},{...snapshot.streamOptions,reasoning:snapshot.thinkingLevel==="off"?void 0:snapshot.thinkingLevel,signal:event.signal}).result();if(response.stopReason==="aborted")return{cancel:!0};if(response.stopReason!=="stop"||response.content.some(block=>block.type==="toolCall"))return;let text2=contentText(response.content).trim();if(!text2)return;let checkpoint=checkpointSummary(text2,event.preparation.fileOps,event.branchEntries);return completed={reason:event.reason,cacheRead:response.usage.cacheRead,input:response.usage.input,cacheWrite:response.usage.cacheWrite,output:response.usage.output,durationMs:Date.now()-startedAt},{compaction:{summary:checkpoint.summary,firstKeptEntryId:event.preparation.firstKeptEntryId,tokensBefore:event.preparation.tokensBefore,usage:response.usage,details:checkpoint.details}}}catch{return event.signal.aborted?{cancel:!0}:void 0}}),pi.on("session_compact",event=>{if(!event.fromExtension||!completed)return;let card=completed;completed=void 0,pendingCard=card,setTimeout(()=>{if(pendingCard===card){pendingCard=void 0;try{pi.appendEntry(CARD_TYPE,card)}catch{}}},0)}),pi.on("session_compact_failed",()=>{completed=void 0}),pi.on("session_shutdown",()=>{completed=void 0,pendingCard=void 0})}var DEEPWIKI_TOOL_NAME="deepwiki",DEEPWIKI_LABEL="DeepWiki",DEEPWIKI_DESCRIPTION="Query DeepWiki's AI-generated documentation for indexed public GitHub repositories. structure lists a repo's wiki pages; contents reads one page, or the whole wiki truncated past ~120k chars when page is omitted; question answers a focused query about one repo, or across up to 10 repos for a comparison. Results are indexed public snapshots and may cite sources. A repository that is not indexed fails every action with a repository-not-found error.",DEEPWIKI_PROMPT_SNIPPET="Query AI-generated docs for public GitHub repos: architecture, APIs, implementation patterns",DEEPWIKI_PROMPT_GUIDELINES=["Run `deepwiki` action `structure` first for a repo; a repository-not-found error means it is not indexed, so do not retry that repo with `contents` or `question`.","Do not use `deepwiki` for local workspace files, private repos, exact current HEAD, or freshness-sensitive facts (releases, pricing, advisories); use local tools or current primary sources instead."];var PAGE_HEADER_RE=/^#\s+Page:\s+(.+)$/;function pageOffsets(text2){let re=new RegExp(PAGE_HEADER_RE.source,"gm"),chunks=[],match2=re.exec(text2);for(;match2!==null;)chunks.push({title:match2[1].trim(),start:match2.index}),match2=re.exec(text2);return chunks}function cutAtLineBoundary(text2,budget){if(text2.length<=budget)return text2;let slice=text2.slice(0,budget),lastNewline=slice.lastIndexOf(`
|
|
1979
2034
|
`);return lastNewline>=Math.floor(budget*.4)?slice.slice(0,lastNewline):slice}function buildNotice(opts){let lines=[`[DeepWiki contents truncated \u2014 ${opts.totalPages>0?`showing ${opts.shownPages} of ${opts.totalPages} pages`:"showing the beginning"} (${opts.keptChars} of ${opts.fullChars} chars).`];if(opts.partialLastPage&&lines.push("The last shown page is itself truncated."),opts.omittedTitles.length>0){let shown=opts.omittedTitles.slice(0,20).join("; "),more=opts.omittedTitles.length-20;lines.push(`Omitted pages: ${shown}${more>0?` \u2026 +${more} more`:""}.`),lines.push('Read an omitted page with {action: "contents", page: "<title>"}, or use action "question" for a targeted answer.]')}else lines.push('For the missing remainder, use action "question" with a focused question.]');return lines.join(`
|
|
1980
2035
|
`)}function truncateContentsByPages(text2,budget=12e4){let chunks=pageOffsets(text2),totalPages=chunks.length;if(text2.length<=budget)return{text:text2,truncated:!1,totalPages,shownPages:totalPages,truncatedChars:0};let kept,shownPages,partialLastPage=!1;if(totalPages===0)kept=cutAtLineBoundary(text2,budget),shownPages=0;else{let preambleEnd=chunks[0].start;shownPages=0;let end=preambleEnd;for(let i=0;i<chunks.length;i++){let pageEnd=i+1<chunks.length?chunks[i+1].start:text2.length;if(pageEnd>budget)break;end=pageEnd,shownPages++}shownPages===0?(kept=cutAtLineBoundary(text2,budget),shownPages=1,partialLastPage=!0):kept=text2.slice(0,end)}let omittedTitles=chunks.slice(shownPages).map(chunk=>chunk.title),notice=buildNotice({shownPages,totalPages,keptChars:kept.length,fullChars:text2.length,omittedTitles,partialLastPage});return{text:`${kept}
|
|
1981
2036
|
|
|
@@ -2006,11 +2061,11 @@ ${approval} at:
|
|
|
2006
2061
|
https://huggingface.co/${details.id}
|
|
2007
2062
|
|
|
2008
2063
|
The llama.cpp server needs HF_TOKEN with access.`,["Continue","Back"])!=="Continue")return}let quantization=parsed.quantization;if(!quantization&&details.quantizations.length>0){let options=details.quantizations.map(entry=>{let detail=[entry.size===void 0?void 0:formatBytes(entry.size),entry.name==="Q4_K_M"?"recommended":void 0].filter(value=>!!value).join(" \xB7 ");return detail?`${entry.name} \xB7 ${detail}`:entry.name}),choice=await ui.select(`Select quantization
|
|
2009
|
-
${details.id}`,options);if(!choice||(quantization=details.quantizations[options.indexOf(choice)]?.name,!quantization))return}let model=quantization?`${details.id}:${quantization}`:details.id,result2=await runWithProgress(ui,{title:"Downloading model",model,initialMessage:"Starting\u2026",cancelTitle:"Stop download?",cancelMessage:model,run:(signal,update)=>client.downloadAndWait(model,update,signal),cancel:()=>client.unload(model)});result2.cancelled||(await syncCatalog(ctx,client,result2.value),ctx.ui.notify(`Downloaded ${model}`))};pi.registerCommand("llama",{description:"Manage llama.cpp router models",handler:async(_args,ctx)=>{if(ctx.mode!=="tui"){ctx.ui.notify("/llama is available in interactive mode","warning");return}let client=await configuredClient(ctx);client&&await showLlamaUi(ctx,async ui=>{let readCatalog2=async()=>{for(;;)try{return await syncCatalog(ctx,client)}catch(error){if(await ui.connectionError(client.serverUrl,connectionErrorMessage(error))==="close")return}},catalog=await readCatalog2();if(catalog)for(;;){let action=await ui.showModels(client.serverUrl,catalog);if(action.type==="close")return;let actionError;try{action.type==="download"?await downloadModel(ctx,ui,client):modelIsLoaded(action.model)?await unloadModel(ctx,ui,client,action.model):action.model.status.value==="unloaded"?await loadModel(ctx,ui,client,catalog,action.model):ctx.ui.notify(`${action.model.id} is ${action.model.status.value}`,"warning")}catch(error){actionError=error}let refreshed=await readCatalog2();if(!refreshed)return;catalog=refreshed,actionError&&!isConnectionError(actionError)&&ctx.ui.notify(actionError instanceof Error?actionError.message:String(actionError),"error")}})}})}var COMMAND_NAME="provider",COMMAND_DESCRIPTION="Manage models.json providers: connection, API type, and models",NO_UI_WARNING="/provider requires interactive TUI mode.",NO_MODELS_FILE_WARNING="models.json is disabled for this runtime (custom SDK configuration), so /provider is unavailable.",API_TYPES=["openai-responses","openai-completions","anthropic-messages","google-generative-ai","azure-openai-responses","openai-codex-responses","mistral-conversations","google-vertex","bedrock-converse-stream","pi-messages"],INPUT_TYPES=["text","image"],THINKING_LEVELS4=["off","minimal","low","medium","high","xhigh","max"],PROBE_LIMITS={timeoutMs:1e4,maxBodyBytes:4194304,maxErrorBytes:4096,maxErrorChars:400,maxModels:2e3,maxPages:5},MAX_CANDIDATES=8,REFRESH_TIMEOUT_MS=15e3;function formatError2(error){return error instanceof Error?error.message:String(error)}function plural(count,word){return count===1?word:word.endsWith("y")?`${word.slice(0,-1)}ies`:`${word}s`}function truncate3(value,max){return value.length<=max?value:`${value.slice(0,Math.max(0,max-1))}\u2026`}function maskApiKey(value){return!value||value.startsWith("$")||value.startsWith("!")?value:value.length<=8?"\u2022\u2022\u2022\u2022\u2022\u2022":`\u2022\u2022\u2022\u2022\u2022\u2022${value.slice(-4)}`}var import_proper_lockfile5=__toESM(require_proper_lockfile(),1);import{randomUUID as randomUUID9}from"node:crypto";import{mkdir,readFile as readFile6,realpath as realpath2,rename,rm,writeFile as writeFile3}from"node:fs/promises";import{dirname as dirname25,join as join45}from"node:path";var indexCache;function builtinCatalogIndex(){if(indexCache)return indexCache;let entries=[];for(let providerId of getBuiltinProviders())for(let model of getBuiltinModels(providerId))entries.push({providerId,model});return indexCache=entries,entries}function isBuiltinProviderId(providerId){return getBuiltinProviders().includes(providerId)}function builtinDefaults(providerId,modelId,api){if(!isBuiltinProviderId(providerId))return{};let models=getBuiltinModels(providerId);if(models.length===0)return{};let found=(modelId?models.find(model=>model.id===modelId):void 0)??(api?models.find(model=>model.api===api):void 0)??models.find(model=>model.api==="openai-completions")??models[0];return{api:found.api,baseUrl:found.baseUrl}}function normalizeId(id){return(id.includes("/")?id.slice(id.lastIndexOf("/")+1):id).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}function sortTier(matches,preferredApi){return matches.sort((a,b2)=>{if(preferredApi){let aPreferred=a.entry.model.api===preferredApi?0:1,bPreferred=b2.entry.model.api===preferredApi?0:1;if(aPreferred!==bPreferred)return aPreferred-bPreferred}return a.entry.model.id.localeCompare(b2.entry.model.id)})}function matchBuiltinModels(query,preferredApi,max=MAX_CANDIDATES){let trimmed=query.trim();if(!trimmed)return[];let index3=builtinCatalogIndex(),normalizedQuery=normalizeId(trimmed),exact=[],normalized=[],consumed=new Set;for(let entry of index3)entry.model.id===trimmed?(exact.push({entry,tier:"exact"}),consumed.add(entry)):normalizeId(entry.model.id)===normalizedQuery&&(normalized.push({entry,tier:"normalized"}),consumed.add(entry));let remaining=sortTier(index3.filter(entry=>!consumed.has(entry)).map(entry=>({entry,tier:"fuzzy"})),preferredApi),fuzzy=fuzzyFilter(remaining,trimmed,({entry})=>`${entry.model.id} ${entry.model.name} ${entry.providerId}`);return[...sortTier(exact,preferredApi),...sortTier(normalized,preferredApi),...fuzzy].slice(0,max)}var DEFAULT_CONTEXT_WINDOW=128e3,DEFAULT_MAX_TOKENS=16384;function formatCostRates(cost){return`$${cost.input} / $${cost.output} in/out (cache $${cost.cacheRead} / $${cost.cacheWrite})`}function computeFieldChanges(current,reference,effectiveApi){let changes=[],unset=key=>current[key]===void 0;changes.push({field:"name",patches:[{path:["name"],value:reference.name}],checked:unset("name")&&reference.name!==reference.id,applicable:!0,currentText:current.name??`not set (falls back to id${current.id?` "${current.id}"`:""})`,referenceText:reference.name}),changes.push({field:"reasoning",patches:[{path:["reasoning"],value:reference.reasoning}],checked:unset("reasoning")&&reference.reasoning===!0,applicable:!0,currentText:current.reasoning===void 0?"false (default)":String(current.reasoning),referenceText:String(reference.reasoning)}),changes.push({field:"input",patches:[{path:["input"],value:reference.input}],checked:unset("input"),applicable:!0,currentText:current.input?current.input.join(", "):"text (default)",referenceText:reference.input.join(", ")}),changes.push({field:"contextWindow",patches:[{path:["contextWindow"],value:reference.contextWindow}],checked:unset("contextWindow"),applicable:!0,currentText:current.contextWindow===void 0?`${DEFAULT_CONTEXT_WINDOW} (default)`:String(current.contextWindow),referenceText:String(reference.contextWindow)}),changes.push({field:"maxTokens",patches:[{path:["maxTokens"],value:reference.maxTokens}],checked:unset("maxTokens"),applicable:!0,currentText:current.maxTokens===void 0?`${DEFAULT_MAX_TOKENS} (default)`:String(current.maxTokens),referenceText:String(reference.maxTokens)});let sameApi=effectiveApi!==void 0&&reference.api===effectiveApi;if(reference.thinkingLevelMap&&Object.keys(reference.thinkingLevelMap).length>0){let details=Object.entries(reference.thinkingLevelMap).map(([level,target])=>`${level}: ${target===null?"null (hidden)":target}`);changes.push({field:"thinkingLevelMap",patches:sameApi?Object.entries(reference.thinkingLevelMap).map(([level,value])=>({path:["thinkingLevelMap",level],value})):[],checked:!1,applicable:sameApi,currentText:current.thinkingLevelMap?`${Object.keys(current.thinkingLevelMap).length} ${plural(Object.keys(current.thinkingLevelMap).length,"mapping")}`:"not set",referenceText:`${details.length} ${plural(details.length,"mapping")}`,referenceDetails:details})}if(reference.compat&&Object.keys(reference.compat).length>0){let patches=[];if(sameApi)for(let[key,value]of Object.entries(reference.compat))if(["chatTemplateKwargs","chatTemplateArgs","openRouterRouting","vercelGatewayRouting"].includes(key)&&value!==null&&typeof value=="object"&&!Array.isArray(value))for(let[entry,item]of Object.entries(value))patches.push({path:["compat",key,entry],value:item});else patches.push({path:["compat",key],value});let details=Object.entries(reference.compat).map(([key,value])=>`${key}: ${JSON.stringify(value)}`);changes.push({field:"compat",patches,checked:!1,applicable:sameApi,currentText:current.compat?`${Object.keys(current.compat).length} ${plural(Object.keys(current.compat).length,"entry")}`:"not set",referenceText:`${details.length} ${plural(details.length,"entry")}`,referenceDetails:details})}if(reference.cost){let{input:input2,output,cacheRead,cacheWrite}=reference.cost,rates={input:input2,output,cacheRead,cacheWrite};changes.push({field:"cost",patches:current.cost?Object.entries(rates).map(([rate,value])=>({path:["cost",rate],value})):[{path:["cost"],value:rates}],checked:!1,applicable:!0,currentText:current.cost?formatCostRates(current.cost):"all 0 (default)",referenceText:formatCostRates(reference.cost),referenceDetails:[`input: $${reference.cost.input} / M tokens`,`output: $${reference.cost.output} / M tokens`,`cacheRead: $${reference.cost.cacheRead} / M tokens`,`cacheWrite: $${reference.cost.cacheWrite} / M tokens`],referenceHasTiers:Array.isArray(reference.cost.tiers)&&reference.cost.tiers.length>0})}return changes}function hasProviderSettings(provider){return!!(provider&&(provider.baseUrl||provider.apiKey||provider.headers||provider.compat||provider.oauth||provider.authHeader!==void 0||provider.models?.length||Object.keys(provider.modelOverrides??{}).length))}function effectiveModelSettings(providerId,provider,model={}){let fallback=builtinDefaults(providerId,model.id,model.api??provider?.api);return{api:model.api??provider?.api??fallback.api,baseUrl:model.baseUrl??provider?.baseUrl??fallback.baseUrl}}var DELETE=Symbol("provider-store-delete");function setPath(root,path14,value){let current=root;for(let segment2 of path14.slice(0,-1)){let next=Object.hasOwn(current,segment2)?current[segment2]:void 0;if(typeof next=="object"&&next!==null&&!Array.isArray(next))current=next;else{let created={};Object.defineProperty(current,segment2,{value:created,writable:!0,enumerable:!0,configurable:!0}),current=created}}let leaf=path14[path14.length-1];value===DELETE?delete current[leaf]:Object.defineProperty(current,leaf,{value:structuredClone(value),writable:!0,enumerable:!0,configurable:!0})}function isPlainObject(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function jsonEquals(a,b2){if(a===b2)return!0;if(Array.isArray(a)&&Array.isArray(b2))return a.length===b2.length&&a.every((entry,index3)=>jsonEquals(entry,b2[index3]));if(isPlainObject(a)&&isPlainObject(b2)){let aKeys=Object.keys(a).sort(),bKeys=Object.keys(b2).sort();return aKeys.length===bKeys.length&&aKeys.every((key,index3)=>key===bKeys[index3]&&jsonEquals(a[key],b2[key]))}return!1}function cloneValue(value){return value===DELETE?value:structuredClone(value)}async function readDocument(path14){let rawText;try{rawText=await readFile6(path14,"utf8")}catch(error){if(error.code==="ENOENT")return{exists:!1,doc:{providers:{}}};throw error}let parsed=JSON.parse(stripJsonComments(stripBom(rawText)));if(!isPlainObject(parsed))throw new Error("models.json root must be a JSON object.");let doc=parsed;if(!isPlainObject(doc.providers))throw new Error('models.json "providers" must be an object.');return{exists:!0,doc,rawText}}var ModelsJsonStore=class _ModelsJsonStore{constructor(path14,baseline){this.ops=[],this.seq=0,this.backedUp=!1,this.batching=!1,this.saveChain=Promise.resolve(),this.drafts=new Set,this.lastSaveResult={kind:"clean"},this.path=path14,this.baseline=baseline,this.view=structuredClone(baseline)}static async load(path14){let normalized=normalizePath(path14),disk;try{normalized=await realpath2(normalized).catch(error=>{if(error.code==="ENOENT")return normalized;throw error}),disk=await readDocument(normalized)}catch(error){return{ok:!1,error:`Failed to parse models.json: ${formatError2(error)}
|
|
2064
|
+
${details.id}`,options);if(!choice||(quantization=details.quantizations[options.indexOf(choice)]?.name,!quantization))return}let model=quantization?`${details.id}:${quantization}`:details.id,result2=await runWithProgress(ui,{title:"Downloading model",model,initialMessage:"Starting\u2026",cancelTitle:"Stop download?",cancelMessage:model,run:(signal,update)=>client.downloadAndWait(model,update,signal),cancel:()=>client.unload(model)});result2.cancelled||(await syncCatalog(ctx,client,result2.value),ctx.ui.notify(`Downloaded ${model}`))};pi.registerCommand("llama",{description:"Manage llama.cpp router models",handler:async(_args,ctx)=>{if(ctx.mode!=="tui"){ctx.ui.notify("/llama is available in interactive mode","warning");return}let client=await configuredClient(ctx);client&&await showLlamaUi(ctx,async ui=>{let readCatalog2=async()=>{for(;;)try{return await syncCatalog(ctx,client)}catch(error){if(await ui.connectionError(client.serverUrl,connectionErrorMessage(error))==="close")return}},catalog=await readCatalog2();if(catalog)for(;;){let action=await ui.showModels(client.serverUrl,catalog);if(action.type==="close")return;let actionError;try{action.type==="download"?await downloadModel(ctx,ui,client):modelIsLoaded(action.model)?await unloadModel(ctx,ui,client,action.model):action.model.status.value==="unloaded"?await loadModel(ctx,ui,client,catalog,action.model):ctx.ui.notify(`${action.model.id} is ${action.model.status.value}`,"warning")}catch(error){actionError=error}let refreshed=await readCatalog2();if(!refreshed)return;catalog=refreshed,actionError&&!isConnectionError(actionError)&&ctx.ui.notify(actionError instanceof Error?actionError.message:String(actionError),"error")}})}})}var COMMAND_NAME="provider",COMMAND_DESCRIPTION="Manage models.json providers: connection, API type, and models",NO_UI_WARNING="/provider requires interactive TUI mode.",NO_MODELS_FILE_WARNING="models.json is disabled for this runtime (custom SDK configuration), so /provider is unavailable.",API_TYPES=["openai-responses","openai-completions","anthropic-messages","google-generative-ai","azure-openai-responses","openai-codex-responses","mistral-conversations","google-vertex","bedrock-converse-stream","pi-messages"],INPUT_TYPES=["text","image"],THINKING_LEVELS4=["off","minimal","low","medium","high","xhigh","max"],PROBE_LIMITS={timeoutMs:1e4,maxBodyBytes:4194304,maxErrorBytes:4096,maxErrorChars:400,maxModels:2e3,maxPages:5},MAX_CANDIDATES=8,REFRESH_TIMEOUT_MS=15e3;function formatError2(error){return error instanceof Error?error.message:String(error)}function plural(count,word){return count===1?word:word.endsWith("y")?`${word.slice(0,-1)}ies`:`${word}s`}function truncate3(value,max){return value.length<=max?value:`${value.slice(0,Math.max(0,max-1))}\u2026`}function maskApiKey(value){return!value||value.startsWith("$")||value.startsWith("!")?value:value.length<=8?"\u2022\u2022\u2022\u2022\u2022\u2022":`\u2022\u2022\u2022\u2022\u2022\u2022${value.slice(-4)}`}var import_proper_lockfile5=__toESM(require_proper_lockfile(),1);import{randomUUID as randomUUID9}from"node:crypto";import{mkdir,readFile as readFile6,realpath as realpath2,rename,rm,writeFile as writeFile3}from"node:fs/promises";import{dirname as dirname25,join as join45}from"node:path";var indexCache;function builtinCatalogIndex(){if(indexCache)return indexCache;let entries=[];for(let providerId of getBuiltinProviders())for(let model of getBuiltinModels(providerId))entries.push({providerId,model});return indexCache=entries,entries}function isBuiltinProviderId(providerId){return getBuiltinProviders().includes(providerId)}function builtinDefaults(providerId,modelId,api){if(!isBuiltinProviderId(providerId))return{};let models=getBuiltinModels(providerId);if(models.length===0)return{};let found=(modelId?models.find(model=>model.id===modelId):void 0)??(api?models.find(model=>model.api===api):void 0)??models.find(model=>model.api==="openai-completions")??models[0];return{api:found.api,baseUrl:found.baseUrl}}function normalizeId(id){return(id.includes("/")?id.slice(id.lastIndexOf("/")+1):id).toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}function sortTier(matches,preferredApi){return matches.sort((a,b2)=>{if(preferredApi){let aPreferred=a.entry.model.api===preferredApi?0:1,bPreferred=b2.entry.model.api===preferredApi?0:1;if(aPreferred!==bPreferred)return aPreferred-bPreferred}return a.entry.model.id.localeCompare(b2.entry.model.id)})}function matchBuiltinModels(query,preferredApi,max=MAX_CANDIDATES){let trimmed=query.trim();if(!trimmed)return[];let index3=builtinCatalogIndex(),normalizedQuery=normalizeId(trimmed),exact=[],normalized=[],consumed=new Set;for(let entry of index3)entry.model.id===trimmed?(exact.push({entry,tier:"exact"}),consumed.add(entry)):normalizeId(entry.model.id)===normalizedQuery&&(normalized.push({entry,tier:"normalized"}),consumed.add(entry));let remaining=sortTier(index3.filter(entry=>!consumed.has(entry)).map(entry=>({entry,tier:"fuzzy"})),preferredApi),fuzzy=fuzzyFilter(remaining,trimmed,({entry})=>`${entry.model.id} ${entry.model.name} ${entry.providerId}`);return[...sortTier(exact,preferredApi),...sortTier(normalized,preferredApi),...fuzzy].slice(0,max)}var DEFAULT_CONTEXT_WINDOW=128e3,DEFAULT_MAX_TOKENS=16384;function formatCostRates(cost){return`$${cost.input} / $${cost.output} in/out (cache $${cost.cacheRead} / $${cost.cacheWrite})`}function computeFieldChanges(current,reference,effectiveApi){let changes=[],unset=key=>current[key]===void 0;changes.push({field:"name",patches:[{path:["name"],value:reference.name}],checked:unset("name")&&reference.name!==reference.id,applicable:!0,currentText:current.name??`not set (falls back to id${current.id?` "${current.id}"`:""})`,referenceText:reference.name}),changes.push({field:"reasoning",patches:[{path:["reasoning"],value:reference.reasoning}],checked:unset("reasoning")&&reference.reasoning===!0,applicable:!0,currentText:current.reasoning===void 0?"false (default)":String(current.reasoning),referenceText:String(reference.reasoning)}),changes.push({field:"input",patches:[{path:["input"],value:reference.input}],checked:unset("input"),applicable:!0,currentText:current.input?current.input.join(", "):"text (default)",referenceText:reference.input.join(", ")}),changes.push({field:"contextWindow",patches:[{path:["contextWindow"],value:reference.contextWindow}],checked:unset("contextWindow"),applicable:!0,currentText:current.contextWindow===void 0?`${DEFAULT_CONTEXT_WINDOW} (default)`:String(current.contextWindow),referenceText:String(reference.contextWindow)}),changes.push({field:"maxTokens",patches:[{path:["maxTokens"],value:reference.maxTokens}],checked:unset("maxTokens"),applicable:!0,currentText:current.maxTokens===void 0?`${DEFAULT_MAX_TOKENS} (default)`:String(current.maxTokens),referenceText:String(reference.maxTokens)});let sameApi=effectiveApi!==void 0&&reference.api===effectiveApi;if(reference.thinkingLevelMap&&Object.keys(reference.thinkingLevelMap).length>0){let details=Object.entries(reference.thinkingLevelMap).map(([level,target])=>`${level}: ${target===null?"null (hidden)":target}`);changes.push({field:"thinkingLevelMap",patches:sameApi?Object.entries(reference.thinkingLevelMap).map(([level,value])=>({path:["thinkingLevelMap",level],value})):[],checked:!1,applicable:sameApi,currentText:current.thinkingLevelMap?`${Object.keys(current.thinkingLevelMap).length} ${plural(Object.keys(current.thinkingLevelMap).length,"mapping")}`:"not set",referenceText:`${details.length} ${plural(details.length,"mapping")}`,referenceDetails:details})}if(reference.compat&&Object.keys(reference.compat).length>0){let patches=[];if(sameApi)for(let[key,value]of Object.entries(reference.compat))if(["chatTemplateKwargs","chatTemplateArgs","openRouterRouting","vercelGatewayRouting"].includes(key)&&value!==null&&typeof value=="object"&&!Array.isArray(value))for(let[entry,item]of Object.entries(value))patches.push({path:["compat",key,entry],value:item});else patches.push({path:["compat",key],value});let details=Object.entries(reference.compat).map(([key,value])=>`${key}: ${JSON.stringify(value)}`);changes.push({field:"compat",patches,checked:!1,applicable:sameApi,currentText:current.compat?`${Object.keys(current.compat).length} ${plural(Object.keys(current.compat).length,"entry")}`:"not set",referenceText:`${details.length} ${plural(details.length,"entry")}`,referenceDetails:details})}if(reference.cost){let{input:input2,output,cacheRead,cacheWrite}=reference.cost,rates={input:input2,output,cacheRead,cacheWrite};changes.push({field:"cost",patches:current.cost?Object.entries(rates).map(([rate,value])=>({path:["cost",rate],value})):[{path:["cost"],value:rates}],checked:!1,applicable:!0,currentText:current.cost?formatCostRates(current.cost):"all 0 (default)",referenceText:formatCostRates(reference.cost),referenceDetails:[`input: $${reference.cost.input} / M tokens`,`output: $${reference.cost.output} / M tokens`,`cacheRead: $${reference.cost.cacheRead} / M tokens`,`cacheWrite: $${reference.cost.cacheWrite} / M tokens`],referenceHasTiers:Array.isArray(reference.cost.tiers)&&reference.cost.tiers.length>0})}return changes}function hasProviderSettings(provider){return!!(provider&&(provider.baseUrl||provider.apiKey||provider.headers||provider.compat||provider.oauth||provider.authHeader!==void 0||provider.models?.length||Object.keys(provider.modelOverrides??{}).length))}function effectiveModelSettings(providerId,provider,model={}){let fallback=builtinDefaults(providerId,model.id,model.api??provider?.api);return{api:model.api??provider?.api??fallback.api,baseUrl:model.baseUrl??provider?.baseUrl??fallback.baseUrl}}var DELETE=Symbol("provider-store-delete");function setPath(root,path14,value){let current=root;for(let segment2 of path14.slice(0,-1)){let next=Object.hasOwn(current,segment2)?current[segment2]:void 0;if(typeof next=="object"&&next!==null&&!Array.isArray(next))current=next;else{let created={};Object.defineProperty(current,segment2,{value:created,writable:!0,enumerable:!0,configurable:!0}),current=created}}let leaf=path14[path14.length-1];value===DELETE?delete current[leaf]:Object.defineProperty(current,leaf,{value:structuredClone(value),writable:!0,enumerable:!0,configurable:!0})}function isPlainObject2(value){return typeof value=="object"&&value!==null&&!Array.isArray(value)}function jsonEquals(a,b2){if(a===b2)return!0;if(Array.isArray(a)&&Array.isArray(b2))return a.length===b2.length&&a.every((entry,index3)=>jsonEquals(entry,b2[index3]));if(isPlainObject2(a)&&isPlainObject2(b2)){let aKeys=Object.keys(a).sort(),bKeys=Object.keys(b2).sort();return aKeys.length===bKeys.length&&aKeys.every((key,index3)=>key===bKeys[index3]&&jsonEquals(a[key],b2[key]))}return!1}function cloneValue(value){return value===DELETE?value:structuredClone(value)}async function readDocument(path14){let rawText;try{rawText=await readFile6(path14,"utf8")}catch(error){if(error.code==="ENOENT")return{exists:!1,doc:{providers:{}}};throw error}let parsed=JSON.parse(stripJsonComments(stripBom(rawText)));if(!isPlainObject2(parsed))throw new Error("models.json root must be a JSON object.");let doc=parsed;if(!isPlainObject2(doc.providers))throw new Error('models.json "providers" must be an object.');return{exists:!0,doc,rawText}}var ModelsJsonStore=class _ModelsJsonStore{constructor(path14,baseline){this.ops=[],this.seq=0,this.backedUp=!1,this.batching=!1,this.saveChain=Promise.resolve(),this.drafts=new Set,this.lastSaveResult={kind:"clean"},this.path=path14,this.baseline=baseline,this.view=structuredClone(baseline)}static async load(path14){let normalized=normalizePath(path14),disk;try{normalized=await realpath2(normalized).catch(error=>{if(error.code==="ENOENT")return normalized;throw error}),disk=await readDocument(normalized)}catch(error){return{ok:!1,error:`Failed to parse models.json: ${formatError2(error)}
|
|
2010
2065
|
|
|
2011
2066
|
File: ${normalized}`}}if(disk.exists){let validationError=(await ModelConfig.load(normalized)).getError();if(validationError)return{ok:!1,error:validationError}}return{ok:!0,store:new _ModelsJsonStore(normalized,disk.doc)}}getDoc(){return this.view}getProviderIds(){return[...new Set([...Object.keys(this.view.providers),...this.ops.map(op=>op.providerId)])]}getProvider(providerId){return Object.hasOwn(this.view.providers,providerId)?this.view.providers[providerId]:void 0}ensureProviderView(providerId){Object.hasOwn(this.view.providers,providerId)||(this.drafts.add(providerId),this.recomputeView())}isDraftProvider(providerId){return!Object.hasOwn(this.baseline.providers,providerId)&&Object.hasOwn(this.view.providers,providerId)}getModels(providerId){let provider=this.getProvider(providerId);return Array.isArray(provider?.models)?provider.models:[]}getModel(providerId,modelId){return this.getModels(providerId).find(model=>model.id===modelId)}get pendingCount(){return this.ops.length}getPendingError(providerId){let pending=this.ops.filter(op=>providerId===void 0||op.providerId===providerId);if(pending.length!==0)return this.lastSaveResult.kind==="error"||this.lastSaveResult.kind==="invalid"?this.lastSaveResult.error:`${pending.length} change(s) are not saved; retry or discard before continuing.`}retrySave(){this.ops.length>0&&this.scheduleSave()}discardPending(){this.ops=[],this.drafts.clear(),this.recomputeView()}enqueue(op){this.ops.push(op),this.recomputeView(),this.scheduleSave()}nextSeq(){return++this.seq}setProviderField(providerId,path14,value){this.enqueue({kind:"set",seq:this.nextSeq(),providerId,path:path14,value:cloneValue(value),createProvider:!Object.hasOwn(this.baseline.providers,providerId)})}setModelField(providerId,modelId,path14,value){this.enqueue({kind:"set",seq:this.nextSeq(),providerId,modelId,path:path14,value:cloneValue(value),createProvider:!Object.hasOwn(this.baseline.providers,providerId)})}addModel(providerId,model){this.enqueue({kind:"addModel",seq:this.nextSeq(),providerId,model:structuredClone(model),createProvider:!Object.hasOwn(this.baseline.providers,providerId)})}removeModel(providerId,modelId){this.enqueue({kind:"removeModel",seq:this.nextSeq(),providerId,modelId})}async renameModel(providerId,oldId,newId){await this.flush();let pendingError=this.getPendingError(providerId);if(pendingError)return pendingError;let before=this.getModel(providerId,oldId);if(!before)return"The model no longer exists.";let seq=this.nextSeq();if(this.enqueue({kind:"renameModel",seq,providerId,oldId,newId}),await this.flush(),this.ops.some(op=>op.seq===seq))return this.ops=this.ops.filter(op=>op.seq!==seq),this.recomputeView(),this.getPendingError(providerId)??"Failed to save models.json.";let renamed=this.getModel(providerId,newId);return renamed&&jsonEquals(renamed,{...before,id:newId})?void 0:"The model changed on disk; reopen it before renaming."}removeProvider(providerId){this.enqueue({kind:"removeProvider",seq:this.nextSeq(),providerId})}batch(mutate){this.batching=!0;try{mutate()}finally{this.batching=!1}this.ops.length>0&&this.scheduleSave()}discardProviderDraft(providerId){this.drafts.delete(providerId),!Object.hasOwn(this.baseline.providers,providerId)&&(this.ops=this.ops.filter(op=>op.providerId!==providerId),this.recomputeView())}recomputeView(){let view=structuredClone(this.baseline);for(let id of this.drafts)ensureProvider(view,id);for(let op of this.ops)applyOp(view,op);this.view=view}scheduleSave(){this.batching||(this.saveChain=this.saveChain.catch(()=>{}).then(async()=>{let result2=await this.save();this.lastSaveResult=result2,result2.kind!=="clean"&&this.onSaveResult?.(result2)}))}async flush(){let pending;do pending=this.saveChain,await pending;while(pending!==this.saveChain)}async save(){if(this.ops.length===0)return{kind:"clean"};try{return await withFileMutationQueue(this.path,async()=>{await mkdir(dirname25(this.path),{recursive:!0});let compromised,release2=await import_proper_lockfile5.default.lock(this.path,{realpath:!1,stale:3e4,retries:{retries:20,factor:1.2,minTimeout:50,maxTimeout:250},onCompromised:error=>{compromised=error}}),result2;try{result2=await this.saveLocked(()=>{if(compromised)throw compromised})}catch(error){result2={kind:"error",error:`Failed to save models.json: ${formatError2(error)}`}}try{await release2()}catch(error){!compromised&&result2.kind!=="error"&&result2.kind!=="invalid"&&(result2={kind:"error",error:`Could not release the models.json lock: ${formatError2(error)}`})}return result2})}catch(error){return{kind:"error",error:`Failed to access models.json for saving: ${formatError2(error)}`}}}async saveLocked(assertLock){let tempPath=join45(dirname25(this.path),`.models.${randomUUID9()}.tmp`);try{assertLock();let disk;try{disk=await readDocument(this.path)}catch(error){return{kind:"error",error:`models.json changed on disk and is unreadable: ${formatError2(error)}`}}let working=structuredClone(disk.doc),batch=this.ops.filter(op=>{let provider=this.getProvider(op.providerId);return Object.hasOwn(disk.doc.providers,op.providerId)||!provider||Object.keys(provider).length===0||hasProviderSettings(provider)});for(let op of batch)applyOp(working,op);pruneEmptyNewProviders(working,disk.doc);let settle=()=>{let settled=new Set(batch.map(op=>op.seq));this.ops=this.ops.filter(op=>!settled.has(op.seq)),this.recomputeView()};if(jsonEquals(working,disk.doc))return this.baseline=disk.doc,settle(),{kind:"saved",applied:batch.length};let candidate=`${JSON.stringify(working,null,2)}
|
|
2012
|
-
`;await writeFile3(tempPath,candidate,{encoding:"utf8",mode:384});let validationError=(await ModelConfig.load(tempPath)).getError();if(validationError)return{kind:"invalid",error:validationError};let latest=await readDocument(this.path);if(latest.exists!==disk.exists||latest.rawText!==disk.rawText)throw new Error("models.json changed while saving; the edits were kept for retry.");return!this.backedUp&&disk.exists&&disk.rawText!==void 0&&(await writeFile3(`${this.path}.bak`,disk.rawText,{encoding:"utf8",mode:384}),this.backedUp=!0),assertLock(),await rename(tempPath,this.path),this.baseline=working,settle(),{kind:"saved",applied:batch.length}}finally{await rm(tempPath,{force:!0}).catch(()=>{})}}};function ensureProvider(doc,providerId){let existing=Object.hasOwn(doc.providers,providerId)?doc.providers[providerId]:void 0;if(existing)return existing;let created={};return Object.defineProperty(doc.providers,providerId,{value:created,writable:!0,enumerable:!0,configurable:!0}),created}function applyOp(doc,op){switch(op.kind){case"set":{let provider=ensureProvider(doc,op.providerId);if(op.modelId===void 0){setPath(provider,op.path,op.value);return}let model=(Array.isArray(provider.models)?provider.models:[]).find(entry=>entry.id===op.modelId);model&&setPath(model,op.path,op.value);return}case"addModel":{let provider=ensureProvider(doc,op.providerId),models=Array.isArray(provider.models)?provider.models:[],index3=models.findIndex(entry=>entry.id===op.model.id),clone=structuredClone(op.model);index3>=0?models[index3]=clone:models.push(clone),provider.models=models;return}case"removeModel":{let provider=doc.providers[op.providerId],models=Array.isArray(provider?.models)?provider.models:void 0;if(!provider||!models)return;provider.models=models.filter(entry=>entry.id!==op.modelId);return}case"renameModel":{let provider=doc.providers[op.providerId],models=Array.isArray(provider?.models)?provider.models:void 0;if(!models)return;let model=models.find(entry=>entry.id===op.oldId);model&&!models.some(entry=>entry.id===op.newId)&&(model.id=op.newId);return}case"removeProvider":{delete doc.providers[op.providerId];return}}}function pruneEmptyNewProviders(working,disk){for(let[providerId,provider]of Object.entries(working.providers))Object.hasOwn(disk.providers,providerId)||isPlainObject(provider)&&Object.keys(provider).length===0&&delete working.providers[providerId]}var RefreshCoordinator=class{constructor(runtime){this.pending=new Map,this.changed=new Set,this.revision=0,this.runtime=runtime}touch(providerId){this.pending.set(providerId,++this.revision),this.changed.add(providerId)}get touchedProviders(){return[...this.changed]}async refreshNow(providerId,signal){return this.run([providerId],signal)}async flush(signal){let providers=[...this.pending.keys()];return providers.length===0?{ok:!0,aborted:!1,errors:[]}:this.run(providers,signal)}async run(providers,signal){let revisions=new Map(providers.map(id=>[id,this.pending.get(id)])),combined=AbortSignal.any([...signal?[signal]:[],AbortSignal.timeout(REFRESH_TIMEOUT_MS)]),errors=[];try{let result2=await this.runtime.refresh({allowNetwork:!1,providers,signal:combined});for(let[providerId,error]of result2.errors)errors.push(`${providerId}: ${formatError2(error)}`);let configError=this.runtime.getError();configError&&errors.push(configError);let aborted=result2.aborted||combined.aborted;aborted&&errors.length===0&&errors.push("Refresh was cancelled or timed out.");let ok=errors.length===0&&!aborted;if(ok)for(let id of providers)this.pending.get(id)===revisions.get(id)&&this.pending.delete(id);return{ok,aborted,errors}}catch(error){return errors.push(formatError2(error)),{ok:!1,aborted:combined.aborted,errors}}}};function registerListKeybindings(){registerKeybindings({"app.list.toggle":{defaultKeys:"space",description:"Toggle selected list item"}})}registerListKeybindings();registerKeybindings({"app.provider.switchPaneLeft":{defaultKeys:"left",description:"/provider: focus the left pane"},"app.provider.switchPaneRight":{defaultKeys:"right",description:"/provider: focus the right pane"},"app.provider.removeEntry":{defaultKeys:"ctrl+x",description:"/provider: remove the selected compat or dictionary entry"}});async function probeProviderModels(opts){let baseUrl;try{baseUrl=new URL(opts.baseUrl)}catch{return{ok:!1,error:"Base URL is not a valid URL."}}if(baseUrl.protocol!=="http:"&&baseUrl.protocol!=="https:")return{ok:!1,error:`Unsupported protocol: ${baseUrl.protocol}`};if(baseUrl.username||baseUrl.password||baseUrl.hash)return{ok:!1,error:"Base URL must not contain credentials or a fragment."};if(opts.signal?.aborted)return{ok:!1,error:"Cancelled."};let controller=new AbortController,timeoutMs=opts.timeoutMs??PROBE_LIMITS.timeoutMs,timer=setTimeout(()=>controller.abort(),timeoutMs),onOuterAbort=()=>controller.abort();opts.signal?.addEventListener("abort",onOuterAbort,{once:!0});let doFetch=opts.fetch??globalThis.fetch,getPage=async(url,headers)=>{let response=await doFetch(url,{method:"GET",headers,signal:controller.signal});if(!response.ok){let body2=await readResponseTextBounded(response,{maxBytes:PROBE_LIMITS.maxErrorBytes,signal:controller.signal});return{ok:!1,status:response.status,error:`HTTP ${response.status}${body2?`: ${safeErrorText(body2,opts.auth).slice(0,PROBE_LIMITS.maxErrorChars)}`:""}`}}let text2=await readResponseTextBounded(response,{maxBytes:PROBE_LIMITS.maxBodyBytes,overflowMessage:`Response exceeds ${PROBE_LIMITS.maxBodyBytes} bytes.`,signal:controller.signal});try{return{ok:!0,json:JSON.parse(text2)}}catch{return{ok:!1,error:"Model catalog response is not JSON."}}};try{let url=modelCatalogUrl(baseUrl,opts.api),headers=buildHeaders(opts.auth,opts.api),page=await getPage(url,headers),retry=page.ok?void 0:openAIStyleRetry(baseUrl,opts.auth,opts.api,{url,headers,status:page.status});if(!page.ok&&retry){let retried=await getPage(retry.url,retry.headers);if(!retried.ok)return{ok:!1,error:safeErrorText(`${url.href} \u2192 HTTP ${page.status}; OpenAI-style retry ${retry.url.href} \u2192 ${retried.error}`,opts.auth)};({url,headers}=retry),page=retried}if(!page.ok)return{ok:!1,error:page.error};let models=parseCatalogModels(page.json);if(models===null)return{ok:!1,error:"JSON has no supported OpenAI-style data[] or models[] catalog with model ids. Add models manually if this endpoint uses another catalog format."};let json=page.json;for(let pages=1;opts.api==="anthropic-messages"&&pages<PROBE_LIMITS.maxPages&&models.length<PROBE_LIMITS.maxModels;pages++){let cursor=nextPageCursor(json);if(!cursor)break;let nextUrl=new URL(url.href);nextUrl.searchParams.set("after_id",cursor),nextUrl.searchParams.set("limit","1000");let next=await getPage(nextUrl,headers),more=next.ok?parseCatalogModels(next.json):null;if(!next.ok||!more||(models.push(...more),nextPageCursor(next.json)===cursor))break;json=next.json}let sorted=dedupeSort(models),truncated=sorted.length>PROBE_LIMITS.maxModels||declaresMorePages(json);return{ok:!0,models:sorted.slice(0,PROBE_LIMITS.maxModels),truncated}}catch(error){return controller.signal.aborted?{ok:!1,error:opts.signal?.aborted?"Cancelled.":`Timed out after ${timeoutMs}ms.`}:{ok:!1,error:safeErrorText(formatError2(error),opts.auth)}}finally{clearTimeout(timer),opts.signal?.removeEventListener("abort",onOuterAbort)}}function modelCatalogUrl(base,api){let url=new URL(base.href),path14=url.pathname.replace(/\/+$/,"");return url.pathname=api==="anthropic-messages"&&!path14.endsWith("/v1")?`${path14}/v1/models`:`${path14}/models`,url}function openAIStyleRetry(base,auth,api,first){if(api!=="anthropic-messages"||![401,403,404].includes(first.status??0)||Object.keys(auth?.headers??{}).some(key=>key.toLowerCase()==="authorization"))return;let root=new URL(base.href);root.pathname=root.pathname.replace(/\/+$/,"").replace(/\/anthropic$/i,"");let url=modelCatalogUrl(root,api),headers=buildHeaders(auth,void 0);return url.href===first.url.href&&headers.get("authorization")===first.headers.get("authorization")?void 0:{url,headers}}function safeErrorText(text2,auth){for(let value of[auth?.apiKey,...Object.values(auth?.headers??{})]){if(typeof value!="string"||!value)continue;text2=text2.replaceAll(value,"[redacted]");let token=value.replace(/^Bearer\s+/i,"");token!==value&&token&&(text2=text2.replaceAll(token,"[redacted]"))}return stripTerminalSequences(text2)}function buildHeaders(auth,api){let headers=new Headers;headers.set("accept","application/json");let configured=auth?.headers??{};api==="anthropic-messages"&&headers.set("anthropic-version","2023-06-01");let hasAuthorization=!1;for(let[key,value]of Object.entries(configured))key.toLowerCase()==="authorization"&&(hasAuthorization=!0),typeof value=="string"?headers.set(key,value):value===null&&headers.delete(key);if(!auth?.apiKey||hasAuthorization)return headers;let lower=name=>Object.keys(configured).some(key=>key.toLowerCase()===name);return api==="anthropic-messages"?(auth.apiKey.includes("sk-ant-oat")?headers.set("authorization",`Bearer ${auth.apiKey}`):(lower("x-api-key")||headers.set("x-api-key",auth.apiKey),lower("anthropic-version")||headers.set("anthropic-version","2023-06-01")),headers):api==="google-generative-ai"||api==="google-vertex"?(lower("x-goog-api-key")||headers.set("x-goog-api-key",auth.apiKey),headers):(headers.set("authorization",`Bearer ${auth.apiKey}`),headers)}function declaresMorePages(json){return typeof json=="object"&&json!==null&&"has_more"in json&&json.has_more===!0}function nextPageCursor(json){if(!declaresMorePages(json))return;let lastId=json.last_id;return typeof lastId=="string"&&lastId?lastId:void 0}var CONTEXT_WINDOW_FIELDS=["context_window","context_window.tokens","context_length","top_provider.context_length","max_input_tokens","max_context_length","max_model_len","context_size","metadata.context_length"],MAX_TOKENS_FIELDS=["max_output_tokens","max_completion_tokens","top_provider.max_completion_tokens","max_tokens","max_output_length"],INPUT_MODALITY_FIELDS=["input_modalities","architecture.input_modalities","modalities.input"],IMAGE_FLAG_FIELDS=["supports_vision","enable_vision_input","capabilities.vision","capabilities.image_input.supported"],REASONING_FLAG_FIELDS=["reasoning","supports_reasoning","enable_reason","capabilities.reasoning","capabilities.thinking.supported"],REASONING_LEVEL_FIELDS=["effort.supported_levels","reasoning_effort_support_list"],CAPABILITY_LIST_FIELDS=["supported_parameters","tags","features","supported_features","metadata.tags"];function fieldAt(record,path14){let value=record;for(let key of path14.split(".")){if(!value||typeof value!="object"||Array.isArray(value))return;value=value[key]}return value}function listAt(record,path14){let value=fieldAt(record,path14);return Array.isArray(value)?value.filter(entry=>typeof entry=="string").map(entry=>entry.toLowerCase()):[]}function declaredLimit(record,paths){let limit;for(let path14 of paths){let value=fieldAt(record,path14);typeof value=="number"&&Number.isSafeInteger(value)&&value>0&&(limit=Math.min(limit??value,value))}return limit}function declaresImageInput(record){return INPUT_MODALITY_FIELDS.some(path14=>listAt(record,path14).includes("image"))||IMAGE_FLAG_FIELDS.some(path14=>fieldAt(record,path14)===!0)||CAPABILITY_LIST_FIELDS.some(path14=>listAt(record,path14).includes("vision"))}function declaresReasoning(record){return REASONING_FLAG_FIELDS.some(path14=>fieldAt(record,path14)===!0)||REASONING_LEVEL_FIELDS.some(path14=>listAt(record,path14).length>0)||CAPABILITY_LIST_FIELDS.some(path14=>listAt(record,path14).includes("reasoning"))}function parseCatalogModels(json){if(!json||typeof json!="object")return null;let payload=json,data=Array.isArray(json)?json:Array.isArray(payload.models)?payload.models:payload.data;if(!Array.isArray(data))return null;let models=[];for(let item of data){if(!item||typeof item!="object")continue;let record=item,id=(typeof record.id=="string"?record.id.trim():"")||(typeof record.slug=="string"?record.slug.trim():"");if(!id)continue;let displayName=typeof record.name=="string"&&record.name.trim()?record.name.trim():void 0,anthropicName=typeof record.display_name=="string"&&record.display_name.trim()?record.display_name.trim():typeof record.displayName=="string"?record.displayName.trim():void 0,name=(displayName??anthropicName)!==id?displayName??anthropicName:void 0,model=name?{id,name}:{id},contextWindow=declaredLimit(record,CONTEXT_WINDOW_FIELDS);contextWindow&&(model.contextWindow=contextWindow);let maxTokens=declaredLimit(record,MAX_TOKENS_FIELDS);maxTokens&&(model.maxTokens=maxTokens),declaresImageInput(record)&&(model.input=["text","image"]),declaresReasoning(record)&&(model.reasoning=!0),models.push(model)}return data.length>0&&models.length===0?null:models}function dedupeSort(models){let map=new Map;for(let model of models)map.has(model.id)||map.set(model.id,model);return[...map.values()].sort((a,b2)=>a.id.localeCompare(b2.id))}async function fetchProviderModels(options,signal){let{store,refresher,runtime,providerId}=options,deadline=AbortSignal.any([signal,AbortSignal.timeout(PROBE_LIMITS.timeoutMs)]);try{await raceWithAbortSignal(store.flush(),deadline);let unsaved=store.getPendingError(providerId);if(unsaved)return{ok:!1,error:`Save the provider changes before fetching: ${unsaved}`};let provider=store.getProvider(providerId),settings2=effectiveModelSettings(providerId,provider);if(!settings2.baseUrl)return{ok:!1,error:"Set a baseUrl under API Auth first."};let sync=await refresher.refreshNow(providerId,deadline);if(deadline.throwIfAborted(),!sync.ok)return{ok:!1,error:`The provider did not reload: ${sync.errors.join("; ")}`};let resolved=await raceWithAbortSignal(runtime.getAuth(providerId,{signal:deadline}),deadline),configured=provider?.apiKey!==void 0||provider?.authHeader===!0||Object.keys(provider?.headers??{}).length>0||runtime.getProviderAuthStatus(providerId).configured;if(!resolved&&configured)return{ok:!1,error:"Configured credentials or headers did not resolve; check the provider authentication."};let result2=await probeProviderModels({baseUrl:resolved?.auth.baseUrl??settings2.baseUrl,auth:resolved?.auth,api:settings2.api,signal:deadline});return deadline.throwIfAborted(),result2}catch(error){return deadline.aborted?{ok:!1,error:signal.aborted?"Cancelled.":"Timed out while preparing or fetching the model catalog."}:{ok:!1,error:formatError2(error)}}}async function importProviderModels(options,models,signal){let{store,refresher,providerId}=options;await raceWithAbortSignal(store.flush(),signal);let unsaved=store.getPendingError(providerId);if(unsaved)return unsaved;let settings2=effectiveModelSettings(providerId,store.getProvider(providerId));if(!settings2.api||!settings2.baseUrl)return"Set baseUrl and API Type under API Auth before importing models.";let existing=new Set(store.getModels(providerId).map(model=>model.id)),fresh=models.filter(model=>existing.has(model.id)?!1:(existing.add(model.id),!0));if(fresh.length===0)return;signal.throwIfAborted(),options.edits.addModels(fresh),await store.flush();let saveError=store.getPendingError(providerId);if(saveError)return saveError;let outcome=await refresher.refreshNow(providerId,signal);if(!outcome.ok)return`Models were saved, but refresh failed: ${outcome.errors.join("; ")}`}var ProviderEdits=class{constructor(store,providerId,refresher,refresh){this.renaming=!1,this.store=store,this.providerId=providerId,this.refresher=refresher,this.refresh=refresh}changed(){(!this.store.isDraftProvider(this.providerId)||hasProviderSettings(this.store.getProvider(this.providerId)))&&this.refresher.touch(this.providerId),this.refresh()}setProviderField(path14,value){this.store.setProviderField(this.providerId,path14,value),this.changed()}removeProvider(){this.store.removeProvider(this.providerId),this.changed()}removeModel(modelId){this.store.removeModel(this.providerId,modelId),this.changed()}batch(apply){this.store.batch(apply)}addModels(models){this.store.batch(()=>{for(let model of models)this.store.addModel(this.providerId,model)}),models.length>0&&this.changed()}draft(){let fields={};return{isDraft:!0,read:()=>fields,setField:(path14,value)=>{setPath(fields,path14,value),this.refresh()}}}commitDraft(draft){let fields=draft.read(),id=(fields.id??"").trim();if(!id)return"Model id is required.";if(this.store.getModel(this.providerId,id))return`Model "${id}" already exists.`;let settings2=effectiveModelSettings(this.providerId,this.store.getProvider(this.providerId),fields);if(!settings2.api)return"Cannot resolve an api \u2014 set one under Model-Specific API or the provider's API Auth.";if(!settings2.baseUrl)return"Cannot resolve a baseUrl \u2014 set one under Model-Specific API or the provider's API Auth.";this.store.addModel(this.providerId,{...fields,id}),this.changed()}model(modelId,onRename){let id=modelId,snapshot;return{isDraft:!1,read:()=>snapshot??this.store.getModel(this.providerId,id)??{id},setField:(path14,value)=>{this.store.setModelField(this.providerId,id,path14,value),this.changed()},rename:async newId=>{let oldId=id;snapshot=this.store.getModel(this.providerId,id),this.renaming=!0;try{let error=await this.store.renameModel(this.providerId,id,newId);if(error)return error;id=newId,this.changed();return}finally{snapshot=void 0,this.renaming=!1,onRename(oldId,id)}}}}};var CURSOR2="\u203A",PASTE_START="\x1B[200~",PASTE_END="\x1B[201~",ValueEditor=class{constructor(callbacks){this.input=new Input({prompt:""}),this.input.onSubmit=callbacks.onCommit,this.input.onEscape=callbacks.onCancel}beginOverwrite(firstData){this.input.setValue(""),firstData&&this.input.handleInput(firstData)}reset(value){this.beginTweak(value)}beginTweak(current){this.input.setValue(""),this.input.handleInput(PASTE_START+current+PASTE_END),this.input.setValue(current)}get value(){return this.input.getValue()}handleInput(data){this.input.handleInput(data)}renderLine(width){return this.input.render(Math.max(1,width))[0]??""}get focused(){return this.input.focused}set focused(value){this.input.focused=value}};function renderKeyValueLine(theme2,opts){let lit=opts.active&&opts.paneFocused,marker=lit?theme2.fg("accent",`${CURSOR2} `):" ",keyPrefix=opts.keyLabel===void 0?"":`${opts.keyLabel}: `,keyColor=lit?"accent":"text",note=opts.note?theme2.fg("dim",` ${opts.note}`):"";if(opts.editing){let body2=opts.editing.renderLine(Math.max(1,opts.width-visibleWidth(marker)-visibleWidth(keyPrefix)));return truncateToWidth(marker+theme2.fg(keyColor,keyPrefix)+theme2.fg(keyColor,body2)+note,opts.width)}let valueColor=opts.unset?"dim":keyColor,line=marker+theme2.fg(keyColor,keyPrefix)+theme2.fg(valueColor,opts.valueText??"")+note;return truncateToWidth(line,opts.width)}function renderPlainLine(theme2,text2,opts){let lit=(opts.active??!1)&&(opts.paneFocused??!1),marker=lit?theme2.fg("accent",`${CURSOR2} `):" ",check=opts.checked===void 0?"":opts.checked?"[x] ":"[ ] ",color2=opts.dim?"dim":lit?"accent":"text",note=opts.note?theme2.fg("dim",` ${opts.note}`):"",line=marker+theme2.fg(color2,check+text2)+note;return truncateToWidth(line,opts.width)}function renderInfoLine(theme2,text2,width){return truncateToWidth(theme2.fg("dim",text2),width)}function windowLines(theme2,lines,height,scroll,indicator){let top=Math.max(0,Math.min(scroll?.top??0,lines.length)),bottom=Math.max(0,Math.min(scroll?.bottom??0,lines.length-top)),head=lines.slice(0,top),tail2=bottom>0?lines.slice(lines.length-bottom):[],middle=lines.slice(top,lines.length-bottom),cursor=Math.max(0,Math.min((scroll?.cursor??0)-top,Math.max(0,middle.length-1))),padToHeight=rows=>{let out=rows.slice(0,height);for(;out.length<height;)out.push("");return out},avail=height-head.length-tail2.length;if(middle.length<=avail)return padToHeight([...head,...middle,...tail2]);let slots=Math.max(1,avail-1),start=Math.max(0,Math.min(cursor-Math.floor(slots/2),middle.length-slots)),note=indicator?.(cursor+1,middle.length)??theme2.fg("dim",` (${cursor+1}/${middle.length})`);return padToHeight([...head,...middle.slice(start,start+slots),note,...tail2])}function isPrintableInput(data){if(!data)return!1;if(data.startsWith(PASTE_START)||decodeKittyPrintable(data)!==void 0)return!0;if(data.includes("\x1B")||data.includes("\r")||data.includes(`
|
|
2013
|
-
`))return!1;for(let char of data){let code=char.codePointAt(0);if(code<32||code===127)return!1}return!0}function truncateMiddle2(text2,maxWidth){if(visibleWidth(text2)<=maxWidth)return text2;if(maxWidth<=4)return truncateToWidth(text2,maxWidth);let headWidth=Math.ceil((maxWidth-1)/2),tailWidth=maxWidth-1-headWidth,head="",headUsed=0;for(let char of text2){let charWidth=visibleWidth(char);if(headUsed+charWidth>headWidth)break;head+=char,headUsed+=charWidth}let tail2="",tailUsed=0;for(let char of[...text2].reverse()){let charWidth=visibleWidth(char);if(tailUsed+charWidth>tailWidth)break;tail2=char+tail2,tailUsed+=charWidth}return`${head}\u2026${tail2}`}var InfoPane=class{constructor(host,lines,onConfirm){this.focused=!1,this.host=host,this.lines=lines,this.onConfirm=onConfirm}render(width){return this.focused&&this.onConfirm?this.lines.map((line,index3)=>index3>0?renderInfoLine(this.host.theme,line,width):truncateToWidth(this.host.theme.fg("accent",`${CURSOR2} `)+this.host.theme.fg("text",line),width)):this.lines.map(line=>renderInfoLine(this.host.theme,line,width))}handleInput(data){if(this.host.keybindings.matches(data,"tui.select.cancel")){this.host.popPane();return}this.onConfirm&&this.host.keybindings.matches(data,"tui.select.confirm")&&this.onConfirm()}setFocused(focused){this.focused=focused}hints(){let hints=[];return this.onConfirm&&hints.push(keyHint("tui.select.confirm","proceed")),hints.push(keyHint("tui.select.cancel","back")),hints.join(" ")}},ConfirmPane=class{constructor(host,message,actionLabel,action){this.crumb="Confirm",this.index=1,this.focused=!1,this.host=host,this.message=message,this.actionLabel=actionLabel,this.action=action}render(width){let theme2=this.host.theme;return[truncateToWidth(theme2.fg("warning",this.message),width),renderPlainLine(theme2,this.actionLabel,{active:this.index===0,paneFocused:this.focused,width}),renderPlainLine(theme2,"Cancel",{active:this.index===1,paneFocused:this.focused,width})]}handleInput(data){let kb=this.host.keybindings;if(kb.matches(data,"tui.select.up")||kb.matches(data,"tui.select.down")){this.index=this.index===0?1:0,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}kb.matches(data,"tui.select.confirm")&&(this.index===0?this.action():this.host.popPane())}setFocused(focused){this.focused=focused}hints(){return[keyHint("tui.select.confirm","choose"),keyHint("tui.select.cancel","cancel")].join(" ")}};function moveSelection(keys,data,index3,count){let delta=keys.matches(data,"tui.select.up")?-1:keys.matches(data,"tui.select.down")?1:void 0;return delta===void 0?void 0:count===0?0:(index3+delta+count)%count}var ChoicePane=class{constructor(host,crumb,options){this.focused=!1,this.host=host,this.crumb=crumb,this.options=options,this.index=Math.max(0,options.choices().findIndex(choice=>choice.value===options.current()))}render(width){let lines=this.options.choices().map((choice,index3)=>renderPlainLine(this.host.theme,`${choice.value===this.options.current()?"\u25CF":"\u25CB"} ${choice.label}`,{active:index3===this.index,paneFocused:this.focused,dim:choice.dim,width}));return this.error&&lines.push(renderInfoLine(this.host.theme,this.error,width)),lines}scrollWindow(){return{cursor:this.index,bottom:this.error?1:0}}handleInput(data){let choices=this.options.choices(),next=moveSelection(this.host.keybindings,data,this.index,choices.length);if(next!==void 0)this.index=next,this.host.refresh();else if(this.host.keybindings.matches(data,"tui.select.cancel"))this.host.popPane();else if(this.host.keybindings.matches(data,"tui.select.confirm")||this.host.keybindings.matches(data,"app.list.toggle")){let choice=choices[this.index];if(!choice)return;this.error=this.options.choose(choice.value),this.error?this.host.refresh():this.host.popPane()}}setFocused(focused){this.focused=focused}hints(){return[rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm","select"),keyHint("tui.select.cancel","back")].join(" ")}},InlineEdit=class{constructor(refresh){this.refresh=refresh}get editing(){return this.active!==void 0}editor(key){return this.active?.key===key?this.active.editor:void 0}setFocused(focused){this.active&&(this.active.editor.focused=focused)}begin(key,current,mode,focused,commit,firstData){let editor=new ValueEditor({onCommit:value=>{this.error=commit(value),this.error||(this.active=void 0),this.refresh()},onCancel:()=>{this.active=void 0,this.error=void 0,this.refresh()}});this.active={key,editor},editor.focused=focused,mode==="overwrite"?editor.beginOverwrite(firstData):editor.beginTweak(current),this.refresh()}handleInput(data,keys){return this.active?(!keys.matches(data,"tui.select.up")&&!keys.matches(data,"tui.select.down")&&this.active.editor.handleInput(data),this.refresh(),!0):!1}};function formatTokens2(count){return count<1e3?count.toString():count<1e4?`${(count/1e3).toFixed(1)}k`:count<1e6?`${Math.round(count/1e3)}k`:count<1e7?`${(count/1e6).toFixed(1)}M`:`${Math.round(count/1e6)}M`}function metadataNote(model){let parts=[model.contextWindow?`${formatTokens2(model.contextWindow)} ctx`:"",model.maxTokens?`${formatTokens2(model.maxTokens)} out`:"",model.input?.includes("image")?"img":"",model.reasoning?"think":""].filter(Boolean);return parts.length>0?`\xB7 ${parts.join(" \xB7 ")}`:void 0}var FetchModelsPane=class{constructor(host){this.state={type:"idle"},this.query="",this.index=0,this.checked=new Set,this.focused=!1,this.disposed=!1,this.host=host,this.search=new ValueEditor({onCommit:()=>this.importChecked(),onCancel:()=>this.exitResults()})}start(){if(this.disposed||this.state.type==="loading"||this.state.type==="importing"||!this.catalogUrl())return;let controller=new AbortController;this.state={type:"loading",controller},this.host.refresh(),this.host.runFetch(controller.signal).then(result2=>{if(!(this.disposed||controller.signal.aborted||this.state.type!=="loading"||this.state.controller!==controller)){if(result2.ok)this.state={type:"results",catalog:result2},this.checked=new Set,this.query="",this.search.reset(""),this.index=0,this.search.focused=this.focused,this.host.setFetchStatus(`\xB7 ${result2.models.length} models`);else{if(result2.error==="Cancelled.")return;this.state={type:"error",message:result2.error},this.host.setFetchStatus("\xB7 failed")}this.host.refresh()}}).catch(error=>{this.disposed||controller.signal.aborted||this.state.type!=="loading"||this.state.controller!==controller||(this.state={type:"error",message:error instanceof Error?error.message:String(error)},this.host.setFetchStatus("\xB7 failed"),this.host.refresh())})}existingIds(){return new Set(this.host.store.getModels(this.host.providerId).map(model=>model.id))}catalogUrl(){let baseUrl=this.host.store.getProvider(this.host.providerId)?.baseUrl;try{return baseUrl?modelCatalogUrl(new URL(baseUrl),this.host.effectiveApi()).href:void 0}catch{return}}rows(){if(this.state.type!=="results"&&this.state.type!=="importing")return[];let existing=this.existingIds(),rows=this.state.catalog.models.map(model=>({model,added:existing.has(model.id)})),query=this.query.trim().toLowerCase();return query?rows.filter(row=>row.model.id.toLowerCase().includes(query)||row.model.name?.toLowerCase().includes(query)):rows}render(width){let theme2=this.host.theme,catalogUrl=this.catalogUrl();switch(this.state.type){case"idle":return catalogUrl?[renderPlainLine(theme2,"Fetch Models",{active:!0,paneFocused:this.focused,note:`\xB7 from ${truncateMiddle2(catalogUrl,Math.max(10,width-22))}`,width})]:[renderInfoLine(theme2,"Set a baseUrl under API Auth first.",width)];case"loading":return[renderInfoLine(theme2,`Fetching ${catalogUrl??""} \u2026`,width),renderInfoLine(theme2,"Esc cancels the request.",width)];case"error":return[theme2.fg("error",truncate3(this.state.message,Math.max(10,width-2))),renderInfoLine(theme2,"Enter retries; Esc goes back.",width)];case"importing":case"results":{let lines=[];this.state.catalog.truncated&&lines.push(renderInfoLine(theme2,"The catalog was truncated; refine manually if a model is missing.",width)),lines.push(this.search.renderLine(width));let rows=this.rows();for(let[rowIndex,row]of rows.entries()){if(row.added){lines.push(renderPlainLine(theme2,row.model.id,{active:rowIndex===this.index,paneFocused:this.focused,dim:!0,note:"\xB7 Added",width}));continue}lines.push(renderPlainLine(theme2,row.model.name?`${row.model.id} \xB7 ${row.model.name}`:row.model.id,{checked:this.checked.has(row.model.id),active:rowIndex===this.index,paneFocused:this.focused,note:metadataNote(row.model),width}))}rows.length===0&&lines.push(renderInfoLine(theme2,"No matching models.",width));let addedCount=rows.filter(row=>row.added).length;return lines.push(renderInfoLine(theme2,`${this.checked.size} selected \xB7 ${rows.length} shown${addedCount?` \xB7 ${addedCount} already added`:""}`,width)),this.state.type==="importing"&&lines.push(renderInfoLine(theme2,"Importing\u2026",width)),this.state.type==="results"&&this.state.error&&lines.push(theme2.fg("error",truncate3(this.state.error,Math.max(10,width-2)))),lines}}}scrollWindow(){if(this.state.type!=="results"&&this.state.type!=="importing")return{};let top=(this.state.catalog.truncated?1:0)+1,bottom=1+(this.state.type==="importing"||this.state.error?1:0);return{top,bottom,cursor:top+this.index}}handleInput(data){let kb=this.host.keybindings;switch(this.state.type){case"idle":if(kb.matches(data,"tui.select.confirm")){this.start();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}return;case"loading":if(kb.matches(data,"tui.select.cancel")){this.state.controller.abort(),this.state={type:"idle"},this.host.refresh();return}return;case"error":if(kb.matches(data,"tui.select.confirm")){this.start();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}return;case"importing":case"results":this.handleResultsInput(data);return}}handleResultsInput(data){let kb=this.host.keybindings,rows=this.rows(),next=moveSelection(kb,data,this.index,rows.length);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"app.list.toggle")){let row=rows[this.index];if(!row||row.added||this.state.type==="importing")return;this.checked.has(row.model.id)?this.checked.delete(row.model.id):this.checked.add(row.model.id),this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.exitResults();return}if(kb.matches(data,"tui.select.confirm")){this.importChecked();return}let before=this.query;this.search.handleInput(data),this.query=this.search.value,this.query!==before&&(this.index=0),this.host.refresh()}importChecked(){if(this.state.type!=="results")return;let chosen;if(this.checked.size===0){let row=this.rows()[this.index];if(!row||row.added)return;chosen=[row.model]}else chosen=this.state.catalog.models.filter(model=>this.checked.has(model.id));let controller=new AbortController,catalog=this.state.catalog;this.state={type:"importing",catalog,controller},this.host.refresh(),this.host.importModels(chosen,controller.signal).then(error=>{if(!(this.disposed||controller.signal.aborted||this.state.type!=="importing"||this.state.controller!==controller)){if(error)return this.state={type:"results",catalog,error},this.host.setFetchStatus("\xB7 import failed"),this.host.refresh();this.host.setFetchStatus(`\xB7 ${this.host.store.getModels(this.host.providerId).length} models`),this.state={type:"idle"},this.host.popPane()}}).catch(error=>{this.disposed||controller.signal.aborted||this.state.type!=="importing"||this.state.controller!==controller||(this.state={type:"results",catalog,error:error instanceof Error?error.message:String(error)},this.host.refresh())})}exitResults(){(this.state.type==="loading"||this.state.type==="importing")&&this.state.controller.abort(),this.state={type:"idle"},this.checked=new Set,this.host.popPane()}setFocused(focused){this.focused=focused,this.search.focused=focused&&(this.state.type==="results"||this.state.type==="importing")}isEditing(){return this.state.type==="results"||this.state.type==="importing"}dispose(){this.disposed=!0,(this.state.type==="loading"||this.state.type==="importing")&&this.state.controller.abort()}hints(){switch(this.state.type){case"loading":return keyHint("tui.select.cancel","cancel request");case"importing":case"results":return[rawKeyHint("type","filter"),keyHint("app.list.toggle","check"),keyHint("tui.select.confirm","import"),keyHint("tui.select.cancel","discard")].join(" ");case"error":return[keyHint("tui.select.confirm","retry"),keyHint("tui.select.cancel","back")].join(" ");default:return this.catalogUrl()?[keyHint("tui.select.confirm","fetch"),keyHint("tui.select.cancel","back")].join(" "):keyHint("tui.select.cancel","back")}}};function formatContext(model){let ctx=model.contextWindow>=1e3?`${Math.round(model.contextWindow/1024)}k`:String(model.contextWindow);return`${model.api} \xB7 ${ctx} ctx${model.reasoning?" \xB7 reasoning":""}`}var BuiltinCandidatesPane=class{constructor(host,model){this.crumb="Use Built-in Data",this.index=0,this.focused=!1,this.host=host,this.model=model,this.query=this.model.read().id??"",this.search=new ValueEditor({onCommit:()=>this.pickCurrent(),onCancel:()=>this.host.popPane()}),this.search.reset(this.query)}candidates(){return matchBuiltinModels(this.query,this.host.effectiveApi(this.model.read()))}render(width){let theme2=this.host.theme,lines=[this.search.renderLine(width)],matches=this.candidates();matches.length===0&&lines.push(renderInfoLine(theme2,"No builtin candidates \u2014 keep configuring manually.",width));for(let[rowIndex,match2]of matches.entries()){let{providerId,model}=match2.entry,label=`${providerId} / ${model.id}`,note=(match2.tier==="exact"?"exact \xB7 ":"")+`${model.name!==model.id?`${model.name} \xB7 `:""}${formatContext(model)}`;lines.push(renderPlainLine(theme2,label,{active:rowIndex===this.index,paneFocused:this.focused,note,width}))}return lines.push(renderInfoLine(theme2,"Candidates are a reference only; the configured id is never rewritten.",width)),lines}scrollWindow(){return{top:1,bottom:1,cursor:1+this.index}}pickCurrent(){let entry=this.candidates()[this.index]?.entry;entry&&this.host.pushPane(new BuiltinPreviewPane(this.host,this.model,entry))}handleInput(data){let kb=this.host.keybindings,count=this.candidates().length,next=moveSelection(kb,data,this.index,count);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"tui.select.confirm")){this.pickCurrent();return}let before=this.query;this.search.handleInput(data),this.query=this.search.value,this.query!==before&&(this.index=0),this.host.refresh()}setFocused(focused){this.focused=focused,this.search.focused=focused}isEditing(){return!0}hints(){return[rawKeyHint("type","filter"),rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm","preview"),keyHint("tui.select.cancel","back")].join(" ")}},BuiltinPreviewPane=class{constructor(host,model,reference){this.crumb="Use Built-in Data \xB7 preview",this.index=0,this.focused=!1,this.host=host,this.model=model,this.reference=reference;let current=model.read();this.snapshot=structuredClone(current),this.snapshotApi=host.effectiveApi(current),this.changes=computeFieldChanges(current,reference.model,host.effectiveApi(current)),this.checked=this.changes.map(change=>change.checked&&change.applicable)}rowCount(){return this.changes.length+1}render(width){let theme2=this.host.theme,lines=[renderInfoLine(theme2,`reference: ${this.reference.providerId} / ${this.reference.model.id}`,width)];for(let[rowIndex,change]of this.changes.entries()){let active=rowIndex===this.index,expandable=change.referenceDetails!==void 0,note=change.applicable?void 0:"\xB7 view only";if(lines.push(renderPlainLine(theme2,`${change.field}: ${change.currentText} \u2192 ${change.referenceText}`,{checked:change.applicable?this.checked[rowIndex]:void 0,active,paneFocused:this.focused,note,width})),this.expanded===rowIndex&&expandable){for(let detail of change.referenceDetails)lines.push(renderInfoLine(theme2,` ${detail}`,width));change.referenceHasTiers&&lines.push(renderInfoLine(theme2," reference has cost tiers \u2014 tiers are never imported.",width))}}return lines.push(renderPlainLine(theme2,"Apply Selected Fields",{active:this.index===this.changes.length,paneFocused:this.focused,width})),this.error&&lines.push(theme2.fg("error",truncate3(this.error,Math.max(10,width-2)))),lines}scrollWindow(){let cursor=1+this.index;if(this.expanded!==void 0&&this.expanded<this.index){let change=this.changes[this.expanded];change.referenceDetails&&(cursor+=change.referenceDetails.length+(change.referenceHasTiers?1:0))}return{top:1,bottom:this.error?1:0,cursor}}handleInput(data){let kb=this.host.keybindings,next=moveSelection(kb,data,this.index,this.rowCount());if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"app.list.toggle")){let change=this.changes[this.index];if(!change)return;if(!change.applicable){this.expanded=this.expanded===this.index?void 0:this.index,this.host.refresh();return}this.checked[this.index]=!this.checked[this.index],this.host.refresh();return}if(kb.matches(data,"tui.select.confirm")){if(this.index===this.changes.length){this.apply();return}let change=this.changes[this.index];change.referenceDetails?this.expanded=this.expanded===this.index?void 0:this.index:change.applicable&&(this.checked[this.index]=!this.checked[this.index]),this.host.refresh();return}}apply(){let current=this.model.read();if(this.host.effectiveApi(current)!==this.snapshotApi){this.error="The API changed since this preview opened; reopen to continue.",this.host.refresh();return}if(!current.id||!jsonEquals(current,this.snapshot)){this.error="The model changed since this preview opened; reopen to continue.",this.host.refresh();return}let chosen=this.changes.filter((_2,rowIndex)=>this.checked[rowIndex]&&this.changes[rowIndex].applicable);if(chosen.length===0){this.host.popPane();return}this.host.edits.batch(()=>{for(let change of chosen)for(let patch of change.patches)this.model.setField(patch.path,patch.value)}),this.host.notify(`Applied ${chosen.length} field${chosen.length===1?"":"s"} from ${this.reference.providerId} / ${this.reference.model.id}.`,"info"),this.host.popPane(),this.host.popPane()}setFocused(focused){this.focused=focused}hints(){return[keyHint("app.list.toggle","check"),keyHint("tui.select.confirm","details / apply"),keyHint("tui.select.cancel","back")].join(" ")}};var THINKING_VARIABLES=["thinking.enabled","thinking.effort","thinking.budget"],SESSION_AFFINITY=["openai","openai-nosession","openrouter"],OPENAI_COMPLETIONS_FIELDS=[{key:"supportsStore",kind:"boolean",note:"Accepts the `store` parameter"},{key:"supportsDeveloperRole",kind:"boolean",note:"Accepts `developer` role messages"},{key:"supportsReasoningEffort",kind:"boolean",note:"Accepts `reasoning_effort`"},{key:"supportsUsageInStreaming",kind:"boolean",note:"Streams usage chunks"},{key:"supportsFinishReason",kind:"boolean",note:"Reports finish reasons"},{key:"maxTokensField",kind:"enum",options:["max_completion_tokens","max_tokens"],note:"Token limit field name"},{key:"requiresToolResultName",kind:"boolean",note:"Tool results need a `name`"},{key:"requiresAssistantAfterToolResult",kind:"boolean",note:"Needs assistant message after tool results"},{key:"requiresThinkingAsText",kind:"boolean",note:"Thinking must be plain text"},{key:"requiresReasoningContentOnAssistantMessages",kind:"boolean",note:"Assistant messages must carry reasoning content"},{key:"thinkingFormat",kind:"enum",options:["openai","openrouter","together","baseten","deepseek","zai","qwen","chat-template","qwen-chat-template","string-thinking","ant-ling"],note:"Reasoning payload format"},{key:"chatTemplateKwargs",kind:"stringMap",note:"Extra chat-template kwargs (open dictionary)"},{key:"chatTemplateArgs",kind:"stringMap",note:"Extra chat-template args (open dictionary)"},{key:"cacheControlFormat",kind:"enum",options:["anthropic"],note:"Cache-control payload format"},{key:"openRouterRouting",kind:"json",note:"OpenRouter routing preferences object"},{key:"vercelGatewayRouting",kind:"json",note:"Vercel AI Gateway routing object"},{key:"supportsOpenAIGrammarTools",kind:"boolean",note:"Grammar-constrained tool calls"},{key:"supportsStrictMode",kind:"boolean",note:"Strict tool schemas"},{key:"sendSessionAffinityHeaders",kind:"boolean",note:"Send session affinity headers"},{key:"supportsMidConvoSystemMessages",kind:"boolean",note:"Accepts mid-conversation system messages"},{key:"supportsMidConvoToolAdditions",kind:"boolean",note:"System messages can add tools mid-conversation"},{key:"sessionAffinityFormat",kind:"enum",options:SESSION_AFFINITY,note:"Affinity header format"},{key:"supportsLongCacheRetention",kind:"boolean",note:"Long-lived prompt cache retention"},{key:"vllmPriority",kind:"number",note:"vLLM scheduling priority"},{key:"zaiToolStream",kind:"boolean",note:"Z.AI streaming tool calls"},{key:"supportsThinkingTokenBudget",kind:"boolean",note:"Enable the thinking-token budget alias"},{key:"thinkingTokenBudgetField",kind:"enum",options:["thinking_token_budget","thinking_budget","thinking_budget_tokens"],note:"Thinking budget field"}],OPENAI_RESPONSES_FIELDS=[{key:"supportsDeveloperRole",kind:"boolean",note:"Accepts `developer` role messages"},{key:"sessionAffinityFormat",kind:"enum",options:SESSION_AFFINITY,note:"Affinity header format"},{key:"supportsLongCacheRetention",kind:"boolean",note:"Long-lived prompt cache retention"},{key:"supportsStrictMode",kind:"boolean",note:"Strict tool schemas"},{key:"supportsOpenAIGrammarTools",kind:"boolean",note:"Grammar-constrained tool calls"},{key:"supportsAdditionalTools",kind:"boolean",note:"Accepts additional hosted tools"},{key:"supportsToolSearch",kind:"boolean",note:"Tool search support"},{key:"supportsMaxOutputTokens",kind:"boolean",note:"Accepts `max_output_tokens`"},{key:"supportsExplicitPromptCacheMode",kind:"boolean",note:"Explicit prompt caching"}],ANTHROPIC_MESSAGES_FIELDS=[{key:"supportsEagerToolInputStreaming",kind:"boolean",note:"Streams tool input eagerly"},{key:"supportsLongCacheRetention",kind:"boolean",note:"Long-lived prompt cache retention"},{key:"sendSessionAffinityHeaders",kind:"boolean",note:"Send session affinity headers"},{key:"supportsCacheControlOnTools",kind:"boolean",note:"Cache control on tool definitions"},{key:"supportsTemperature",kind:"boolean",note:"Accepts `temperature`"},{key:"forceAdaptiveThinking",kind:"boolean",note:"Force adaptive thinking mode"},{key:"allowEmptySignature",kind:"boolean",note:"Tolerate empty thinking signatures"},{key:"supportsStrictTools",kind:"boolean",note:"Strict tool schemas"},{key:"supportsMidConvoEffort",kind:"boolean",note:"Effort changes mid-conversation"},{key:"supportsMidConvoSystemMessages",kind:"boolean",note:"Accepts mid-conversation system messages"},{key:"supportsMidConvoToolChanges",kind:"boolean",note:"Accepts mid-conversation tool changes"},{key:"allowedFallbackModels",kind:"json",note:"Server-side refusal fallback models"}],BEDROCK_FIELDS=[{key:"supportsStrictMode",kind:"boolean",note:"Strict tool schemas"}];function compatFieldsForApi(api){switch(api){case"openai-completions":return OPENAI_COMPLETIONS_FIELDS;case"openai-responses":return OPENAI_RESPONSES_FIELDS;case"azure-openai-responses":return OPENAI_RESPONSES_FIELDS.filter(field5=>["supportsDeveloperRole","supportsStrictMode","supportsOpenAIGrammarTools"].includes(field5.key));case"openai-codex-responses":return OPENAI_RESPONSES_FIELDS.filter(field5=>["supportsStrictMode","supportsOpenAIGrammarTools","supportsAdditionalTools","supportsToolSearch"].includes(field5.key));case"anthropic-messages":return ANTHROPIC_MESSAGES_FIELDS;case"bedrock-converse-stream":return BEDROCK_FIELDS;default:return[]}}function compatFieldFor(api,key){return compatFieldsForApi(api).find(field5=>field5.key===key)}var completionsCompatValidator=Compile(OpenAICompletionsCompatSchema);function validateCompletionsCompat(value){if(!completionsCompatValidator.Check(value))return completionsCompatValidator.Errors(value).slice(0,5).map(error=>{let path14=error.instancePath.replace(/^\//,"").replace(/\//g,"."),required=error.keyword==="required"?error.params.requiredProperties?.[0]:void 0;return`${required?path14?`${path14}.${required}`:required:path14||"root"}: ${error.message}`}).join("; ")}function validateJsonCompatValue(key,text2){let value;try{value=JSON.parse(text2)}catch{return"Value is not valid JSON."}return validateCompletionsCompat({[key]:value})}function validateChatTemplateKwarg(value){if(value!==null&&typeof value=="object"&&!Array.isArray(value)&&!Object.keys(value).every(key=>key==="$var"||key==="omitWhenOff"))return'Only "$var" and "omitWhenOff" are allowed.';let error=validateCompletionsCompat({chatTemplateKwargs:{value}});return error?`Value must be a scalar or valid $var reference: ${error}`:void 0}function compatObject(handle){let compat=handle.read().compat;return typeof compat=="object"&&compat!==null&&!Array.isArray(compat)?compat:{}}function scalarText(value){return value===null?"null":typeof value=="string"||typeof value=="number"||typeof value=="boolean"?String(value):JSON.stringify(value)??String(value)}var DICT_VALUE_KINDS=["string","number","boolean","null","$var"],VAR_OPTIONS=THINKING_VARIABLES,DictPane=class{constructor(host,model,dictKey){this.index=0,this.mode={type:"list"},this.focused=!1,this.host=host,this.model=model,this.dictKey=dictKey,this.crumb=`compat \xB7 ${dictKey}`}dict(){let value=compatObject(this.model)[this.dictKey];return typeof value=="object"&&value!==null&&!Array.isArray(value)?value:{}}entries(){return Object.entries(this.dict())}render(width){let theme2=this.host.theme,lines=[renderInfoLine(theme2,"free-form keys; values: string \xB7 number \xB7 boolean \xB7 null \xB7 $var",width)];if(this.mode.type!=="list")return lines.push(...this.renderMode(width)),this.error&&lines.push(renderInfoLine(theme2,this.error,width)),lines;let entries=this.entries();for(let[rowIndex,[key,value]]of entries.entries()){let active=rowIndex===this.index;lines.push(renderKeyValueLine(theme2,{keyLabel:key,valueText:scalarText(value),active,paneFocused:this.focused,width}))}return lines.push(renderPlainLine(theme2,"+ Add Entry",{active:this.index===entries.length&&this.mode.type==="list",paneFocused:this.focused,width})),this.error&&lines.push(theme2.fg("error",truncate3(this.error,Math.max(10,width-2)))),lines}scrollWindow(){return this.mode.type!=="list"?{top:1,bottom:this.error?1:0}:{top:1,bottom:this.error?1:0,cursor:1+this.index}}renderMode(width){let theme2=this.host.theme,mode=this.mode;switch(mode.type){case"keyEdit":return[renderInfoLine(theme2,"new key:",width),mode.editor.renderLine(width)];case"kindPick":return[renderInfoLine(theme2,`${mode.key} \xB7 value kind`,width),...DICT_VALUE_KINDS.map((kind,kindIndex)=>renderPlainLine(theme2,kind,{active:kindIndex===mode.index,paneFocused:this.focused,width}))];case"valueEdit":return[renderInfoLine(theme2,`${mode.key} \xB7 ${mode.kind}`,width),renderKeyValueLine(theme2,{keyLabel:mode.key,active:!0,paneFocused:this.focused,editing:mode.editor,width})];case"boolPick":return[renderInfoLine(theme2,`${mode.key} \xB7 boolean`,width),...["true","false"].map((option,optionIndex)=>renderPlainLine(theme2,option,{active:optionIndex===mode.index,paneFocused:this.focused,width}))];case"varPick":return[renderInfoLine(theme2,`${mode.key} \xB7 $var`,width),...VAR_OPTIONS.map((option,optionIndex)=>renderPlainLine(theme2,option,{active:optionIndex===mode.index,paneFocused:this.focused,width}))];case"omitPick":return[renderInfoLine(theme2,`${mode.key} \xB7 omitWhenOff`,width),...["default","true","false"].map((option,optionIndex)=>renderPlainLine(theme2,option,{active:optionIndex===mode.index,paneFocused:this.focused,width}))];default:return[]}}handleInput(data){let kb=this.host.keybindings,mode=this.mode;switch(mode.type){case"keyEdit":case"valueEdit":if(kb.matches(data,"tui.select.up")||kb.matches(data,"tui.select.down"))return;mode.editor.handleInput(data),this.host.refresh();return;case"kindPick":this.handlePick(data,mode,DICT_VALUE_KINDS.length,index3=>{let key=mode.key,kind=DICT_VALUE_KINDS[index3];this.startValueForKind(key,kind)});return;case"boolPick":this.handlePick(data,mode,2,index3=>{let key=mode.key;this.mode={type:"list"},this.writeEntry(key,index3===0)});return;case"varPick":this.handlePick(data,mode,VAR_OPTIONS.length,index3=>{let key=mode.key;this.mode={type:"omitPick",key,$var:VAR_OPTIONS[index3],index:0},this.host.refresh()});return;case"omitPick":this.handlePick(data,mode,3,index3=>{this.mode={type:"list"},this.writeEntry(mode.key,index3===0?{$var:mode.$var}:{$var:mode.$var,omitWhenOff:index3===1})});return;case"list":this.handleList(data);return}}handlePick(data,mode,count,choose2){let kb=this.host.keybindings,index3=mode.index;if(kb.matches(data,"tui.select.up")){mode.index=index3===0?count-1:index3-1,this.host.refresh();return}if(kb.matches(data,"tui.select.down")){mode.index=(index3+1)%count,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.mode={type:"list"},this.host.refresh();return}kb.matches(data,"tui.select.confirm")&&choose2(index3)}handleList(data){let kb=this.host.keybindings,rowCount=this.entries().length+1,next=moveSelection(kb,data,this.index,rowCount);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"app.provider.removeEntry")){let entry=this.entries()[this.index];if(!entry)return;this.model.setField(["compat",this.dictKey,entry[0]],DELETE),this.index=Math.max(0,Math.min(this.index,this.entries().length-1));return}if(kb.matches(data,"tui.select.confirm")||kb.matches(data,"app.list.toggle")){let entry=this.entries()[this.index];if(!entry){let editor2=new ValueEditor({onCommit:raw=>{let key2=raw.trim();if(!key2)return this.error="Key must be non-empty.",this.host.refresh();if(Object.hasOwn(this.dict(),key2))return this.error=`"${key2}" already exists.`,this.host.refresh();this.error=void 0,this.mode={type:"kindPick",key:key2,index:0},this.host.refresh()},onCancel:()=>{this.mode={type:"list"},this.error=void 0,this.host.refresh()}});editor2.focused=this.focused,this.mode={type:"keyEdit",editor:editor2},this.host.refresh();return}let[key,value]=entry;if(typeof value=="boolean"){this.writeEntry(key,!value);return}if(value===null)return;if(typeof value=="object"){let record=value;if(record.$var==="thinking.enabled"||record.$var==="thinking.effort"||record.$var==="thinking.budget"){this.mode={type:"omitPick",key,$var:record.$var,index:record.omitWhenOff===void 0?0:record.omitWhenOff?1:2},this.host.refresh();return}return}let kind=typeof value=="number"?"number":"string",editor=new ValueEditor({onCommit:raw=>this.commitScalar(key,kind,raw),onCancel:()=>{this.mode={type:"list"},this.error=void 0,this.host.refresh()}});editor.beginTweak(String(value)),editor.focused=this.focused,this.mode={type:"valueEdit",key,kind,editor},this.host.refresh();return}}startValueForKind(key,kind){switch(kind){case"string":case"number":{let editor=new ValueEditor({onCommit:raw=>this.commitScalar(key,kind,raw),onCancel:()=>{this.mode={type:"list"},this.error=void 0,this.host.refresh()}});editor.focused=this.focused,this.mode={type:"valueEdit",key,kind,editor},this.host.refresh();return}case"boolean":this.mode={type:"boolPick",key,index:0},this.host.refresh();return;case"null":this.mode={type:"list"},this.writeEntry(key,null);return;case"$var":this.mode={type:"varPick",key,index:0},this.host.refresh();return}}commitScalar(key,kind,raw){let value=raw;if(kind==="number"){let parsed=Number(raw.trim());if(!Number.isFinite(parsed)){this.error=`${key} must be a number.`,this.host.refresh();return}value=parsed}let invalid2=validateChatTemplateKwarg(value);if(invalid2){this.error=invalid2,this.host.refresh();return}this.error=void 0,this.mode={type:"list"},this.writeEntry(key,value)}writeEntry(key,value){let invalid2=validateChatTemplateKwarg(value);if(invalid2){this.error=invalid2,this.host.refresh();return}this.model.setField(["compat",this.dictKey,key],value)}setFocused(focused){this.focused=focused,(this.mode.type==="keyEdit"||this.mode.type==="valueEdit")&&(this.mode.editor.focused=focused)}isEditing(){return this.mode.type==="keyEdit"||this.mode.type==="valueEdit"}hints(){switch(this.mode.type){case"keyEdit":case"valueEdit":return[keyHint("tui.input.submit","save"),keyHint("tui.select.cancel","cancel")].join(" ");case"list":return[keyHint("tui.select.confirm","edit / add"),keyHint("app.provider.removeEntry","remove"),keyHint("tui.select.cancel","back")].join(" ");default:return[rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm","choose"),keyHint("tui.select.cancel","cancel")].join(" ")}}};function compatObject2(handle){let compat=handle.read().compat;return typeof compat=="object"&&compat!==null&&!Array.isArray(compat)?compat:{}}function scalarText2(value){return value===null?"null":typeof value=="string"||typeof value=="number"||typeof value=="boolean"?String(value):JSON.stringify(value)??String(value)}var CompatPane=class{constructor(host,model){this.crumb="compat",this.index=0,this.mode={type:"list"},this.focused=!1,this.host=host,this.model=model}entries(){return Object.entries(compatObject2(this.model))}effectiveApi(){return this.host.effectiveApi(this.model.read())}rowCount(){return this.entries().length+1}render(width){let theme2=this.host.theme,api=this.effectiveApi(),lines=[renderInfoLine(theme2,api?`effective api: ${api}`:"effective api: unresolved \u2014 set API Type",width)];if(this.mode.type==="chooseValue"){let mode=this.mode;lines.push(renderKeyValueLine(theme2,{keyLabel:mode.key,valueText:"choose a value",active:!0,paneFocused:this.focused,width}));for(let[index3,option]of mode.options.entries())lines.push(renderPlainLine(theme2,option,{active:index3===mode.index,paneFocused:this.focused,width}));return lines}let known=api?compatFieldsForApi(api):[],entries=this.entries(),editingKey=this.mode.type==="list"?void 0:this.mode.key;editingKey!==void 0&&!entries.some(([key])=>key===editingKey)&&entries.push([editingKey,void 0]),known.length===0&&entries.length===0&&lines.push(renderInfoLine(theme2,`No compat fields are known for ${api??"this api"}.`,width));for(let[rowIndex,[key,value]]of entries.entries()){let active=rowIndex===this.index,field5=api?compatFieldFor(api,key):void 0,editing=this.mode.type==="editValue"&&this.mode.key===key?this.mode.editor:void 0,note=field5?void 0:`\xB7 not used by ${api??"this api"}`;lines.push(renderKeyValueLine(theme2,{keyLabel:key,valueText:value===void 0?"not set":scalarText2(value),active,paneFocused:this.focused,editing,note,width}))}return lines.push(renderPlainLine(theme2,"+ Add Entry",{active:this.index===entries.length&&this.mode.type==="list",paneFocused:this.focused,width})),this.error&&lines.push(theme2.fg("error",truncate3(this.error,Math.max(10,width-2)))),lines}scrollWindow(){return this.mode.type==="chooseValue"?{top:1,cursor:2+this.mode.index}:{top:1,bottom:this.error?1:0,cursor:1+this.index}}handleInput(data){let kb=this.host.keybindings;if(this.mode.type==="editValue"){if(kb.matches(data,"tui.select.up")||kb.matches(data,"tui.select.down"))return;this.mode.editor.handleInput(data),this.host.refresh();return}if(this.mode.type==="chooseValue"){let mode=this.mode;if(kb.matches(data,"tui.select.up")){this.mode={...mode,index:mode.index===0?mode.options.length-1:mode.index-1},this.host.refresh();return}if(kb.matches(data,"tui.select.down")){this.mode={...mode,index:(mode.index+1)%mode.options.length},this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.mode={type:"list"},this.host.refresh();return}if(kb.matches(data,"tui.select.confirm")){let option=mode.options[mode.index];this.mode={type:"list"},this.writeValue(mode.key,this.parseChosen(option))}return}let next=moveSelection(kb,data,this.index,this.rowCount());if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"app.provider.removeEntry")){let entry=this.entries()[this.index];if(!entry)return;let[key]=entry;this.model.setField(["compat",key],DELETE),this.index=Math.min(this.index,this.rowCount()-2<0?0:this.rowCount()-2);return}if(kb.matches(data,"app.list.toggle")||kb.matches(data,"tui.select.confirm")){this.activateRow();return}}activateRow(){let entries=this.entries();if(this.index===entries.length){let api=this.effectiveApi();if(!api){this.fail("Set API Type first \u2014 compat fields depend on the effective api.");return}if(compatFieldsForApi(api).length===0){this.fail(`No compat fields are known for ${api}.`);return}let taken=new Set(entries.map(([key2])=>key2));this.host.pushPane(new CompatKeyPickerPane(this.host,api,taken,key2=>this.beginValueEntry(key2)));return}let[key,value]=entries[this.index],field5=this.effectiveApi()?compatFieldFor(this.effectiveApi(),key):void 0;if(!field5){this.beginJsonEdit(key,value);return}switch(field5.kind){case"boolean":this.writeValue(key,value!==!0);return;case"enum":this.mode={type:"chooseValue",key,options:field5.options,index:0},this.host.refresh();return;case"number":this.beginTextEdit(key,value);return;case"json":this.beginJsonEdit(key,value);return;case"stringMap":this.host.pushPane(new DictPane(this.host,this.model,key));return}}beginValueEntry(key){let api=this.effectiveApi(),field5=compatFieldFor(api,key);switch(field5.kind){case"boolean":this.mode={type:"chooseValue",key,options:["true","false"],index:0},this.host.refresh();return;case"enum":this.mode={type:"chooseValue",key,options:field5.options,index:0},this.host.refresh();return;case"number":this.beginTextEdit(key,void 0);return;case"json":this.beginJsonEdit(key,void 0);return;case"stringMap":this.writeValue(key,{}),this.host.pushPane(new DictPane(this.host,this.model,key));return}}beginTextEdit(key,current){let editor=new ValueEditor({onCommit:raw=>{let parsed=Number(raw.trim());if(!Number.isFinite(parsed))return this.error=`${key} must be a number.`,this.host.refresh();this.error=void 0,this.mode={type:"list"},this.writeValue(key,parsed)},onCancel:()=>{this.mode={type:"list"},this.error=void 0,this.host.refresh()}});current!==void 0&&editor.beginTweak(String(current)),editor.focused=this.focused,this.mode={type:"editValue",key,editor},this.host.refresh()}beginJsonEdit(key,current){let editor=new ValueEditor({onCommit:raw=>{let text2=raw.trim();if(!text2){this.mode={type:"list"},this.writeValue(key,DELETE);return}let shapeError=validateJsonCompatValue(key,text2);if(shapeError)return this.error=shapeError,this.host.refresh();this.error=void 0,this.mode={type:"list"},this.writeValue(key,JSON.parse(text2))},onCancel:()=>{this.mode={type:"list"},this.error=void 0,this.host.refresh()}});current!==void 0&&editor.beginTweak(JSON.stringify(current)),editor.focused=this.focused,this.mode={type:"editValue",key,editor},this.host.refresh()}parseChosen(option){return option==="true"?!0:option==="false"?!1:option}writeValue(key,value){this.model.setField(["compat",key],value)}fail(message){this.error=message,this.host.refresh()}setFocused(focused){this.focused=focused,this.mode.type==="editValue"&&(this.mode.editor.focused=focused)}isEditing(){return this.mode.type==="editValue"}hints(){return this.mode.type==="editValue"?[keyHint("tui.input.submit","save"),keyHint("tui.select.cancel","cancel")].join(" "):this.mode.type==="chooseValue"?[rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm","set"),keyHint("tui.select.cancel","cancel")].join(" "):[keyHint("tui.select.confirm","edit"),keyHint("app.list.toggle","toggle"),keyHint("app.provider.removeEntry","remove"),keyHint("tui.select.cancel","back")].join(" ")}},CompatKeyPickerPane=class{constructor(host,api,taken,onPick){this.crumb="compat \xB7 new entry",this.query="",this.index=0,this.focused=!1,this.host=host,this.api=api,this.taken=taken,this.onPick=onPick,this.editor=new ValueEditor({onCommit:()=>this.pickCurrent(),onCancel:()=>this.host.popPane()})}candidates(){let available=compatFieldsForApi(this.api).filter(field5=>!this.taken.has(field5.key)),query=this.query.trim();return query?fuzzyFilter(available,query,field5=>`${field5.key} ${field5.note??""}`):available}render(width){let theme2=this.host.theme,lines=[this.editor.renderLine(width)],candidates=this.candidates();candidates.length===0&&lines.push(renderInfoLine(theme2,"No remaining known fields.",width));for(let[rowIndex,field5]of candidates.entries())lines.push(renderPlainLine(theme2,field5.key,{active:rowIndex===this.index,paneFocused:this.focused,note:field5.note?`\xB7 ${field5.kind} \u2014 ${truncate3(field5.note,30)}`:`\xB7 ${field5.kind}`,width}));return lines}scrollWindow(){return{top:1,cursor:1+this.index}}pickCurrent(){let field5=this.candidates()[this.index];field5&&(this.host.popPane(),this.onPick(field5.key))}handleInput(data){let kb=this.host.keybindings;if(kb.matches(data,"tui.select.up")){let count=this.candidates().length;count>0&&(this.index=this.index===0?count-1:this.index-1),this.host.refresh();return}if(kb.matches(data,"tui.select.down")){let count=this.candidates().length;count>0&&(this.index=(this.index+1)%count),this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"tui.select.confirm")){this.pickCurrent();return}let before=this.query;this.editor.handleInput(data),this.query=this.editor.value,this.query!==before&&(this.index=0),this.host.refresh()}setFocused(focused){this.focused=focused,this.editor.focused=focused}isEditing(){return!0}hints(){return[rawKeyHint("type","filter"),rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm","choose"),keyHint("tui.select.cancel","back")].join(" ")}};function baseUrlHint(api){switch(api){case"openai-responses":case"openai-completions":case"openai-codex-responses":return"baseUrl includes the version path, e.g. https://api.openai.com/v1";case"anthropic-messages":return"baseUrl is the bare origin \u2014 /v1/messages is added automatically";case"mistral-conversations":return"baseUrl is the bare origin \u2014 /v1 is added automatically";case"google-generative-ai":return"baseUrl includes the version path, e.g. https://generativelanguage.googleapis.com/v1beta";default:return}}function validateBaseUrlValue(value){let url;try{url=new URL(value)}catch{return"baseUrl must be a valid URL."}if(url.protocol!=="http:"&&url.protocol!=="https:")return`Unsupported protocol: ${url.protocol}`;if(url.username||url.password||url.hash)return"baseUrl must not contain credentials or a fragment."}var ApiAuthPane=class{constructor(host,registry){this.rows=["baseUrl","apiKey","apiType"],this.index=0,this.focused=!1,this.host=host,this.edit=new InlineEdit(()=>host.refresh()),this.registry=registry}provider(){return this.host.store.getProvider(this.host.providerId)}scrollWindow(){return{cursor:this.index,bottom:this.bottomNoteCount()}}bottomNoteCount(){let status=this.registry.getProviderAuthStatus(this.host.providerId),hint=baseUrlHint(this.provider()?.api);return(this.edit.error?1:0)+(status.configured?1:0)+1+(hint?1:0)}render(width){let theme2=this.host.theme,provider=this.provider(),lines=[];for(let[rowIndex,row]of this.rows.entries()){let active=rowIndex===this.index,value=provider?.[row==="apiType"?"api":row];lines.push(renderKeyValueLine(theme2,{keyLabel:row==="apiType"?"API Type":row,valueText:value?row==="apiKey"?maskApiKey(value):value:"not set",unset:!value,active,paneFocused:this.focused,editing:row==="apiType"?void 0:this.edit.editor(row),width}))}this.edit.error&&lines.push(theme2.fg("error",truncate3(this.edit.error,Math.max(10,width-2))));let status=this.registry.getProviderAuthStatus(this.host.providerId);status.configured&&status.source==="stored"?lines.push(renderInfoLine(theme2,"A stored credential (auth.json) takes precedence over the apiKey here.",width)):status.configured&&status.source==="environment"&&lines.push(renderInfoLine(theme2,`An environment variable (${status.label??"env"}) currently provides the key.`,width)),lines.push(renderInfoLine(theme2,"Values are stored raw; $VAR / !command references resolve at request time.",width));let hint=baseUrlHint(provider?.api);return hint&&lines.push(renderInfoLine(theme2,hint,width)),lines}handleInput(data){let kb=this.host.keybindings;if(this.edit.handleInput(data,kb))return;let next=moveSelection(kb,data,this.index,this.rows.length);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"tui.select.confirm")){this.rows[this.index]==="apiType"?this.host.pushPane(createProviderApiPane(this.host)):this.beginEdit("tweak");return}if(isPrintableInput(data)){if(this.rows[this.index]==="apiType")return;this.beginEdit("overwrite",data);return}}beginEdit(mode,firstData){let row=this.rows[this.index];row!=="apiType"&&this.edit.begin(row,this.provider()?.[row]??"",mode,this.focused,value=>this.commit(row,value),firstData)}commit(row,raw){let value=raw.trim();if(row==="baseUrl"&&value){let invalid2=validateBaseUrlValue(value);if(invalid2)return invalid2}if(row==="baseUrl"&&!value){let builtin=builtinDefaults(this.host.providerId).baseUrl!==void 0,modelsCovered=this.host.store.getModels(this.host.providerId).every(model=>model.baseUrl!==void 0);if(!builtin&&!modelsCovered&&this.host.store.getModels(this.host.providerId).length>0)return"baseUrl cannot be removed while models rely on it."}this.host.edits.setProviderField([row],value===""?DELETE:value)}setFocused(focused){this.focused=focused,this.edit.setFocused(focused)}isEditing(){return this.edit.editing}hints(){return this.edit.editing?[keyHint("tui.input.submit","save"),keyHint("tui.select.cancel","cancel")].join(" "):[rawKeyHint("type","overwrite"),keyHint("tui.select.confirm","edit / open"),keyHint("tui.select.cancel","back")].join(" ")}};function createProviderApiPane(host){let current=()=>host.store.getProvider(host.providerId)?.api;return new ChoicePane(host,"API Type",{current,choices:()=>{let fallback=builtinDefaults(host.providerId).api,label=fallback?`not set (built-in default: ${fallback})`:"not set (models define their own)",values=[void 0,...API_TYPES],value=current();return value&&!values.includes(value)&&values.push(value),values.map(value2=>({value:value2,label:value2??label,dim:value2===void 0}))},choose:api=>{if(api===void 0){let uncovered=host.store.getModels(host.providerId).filter(model=>!model.api&&!builtinDefaults(host.providerId,model.id).api);if(uncovered.length)return uncovered.length===1?`Model "${uncovered[0].id}" resolves its API from here \u2014 give it a model-level API first.`:`${uncovered.length} ${plural(uncovered.length,"model")} resolve their API from here \u2014 give them model-level APIs first.`}host.edits.setProviderField(["api"],api??DELETE)}})}var REASONING_OPTIONS=[{label:"true",value:!0},{label:"false",value:!1},{label:"default (false)",value:void 0}];function createReasoningPane(host,model){return new ChoicePane(host,"reasoning",{current:()=>model.read().reasoning,choices:()=>REASONING_OPTIONS.map(option=>({...option,dim:option.value===void 0})),choose:value=>{model.setField(["reasoning"],value===void 0?DELETE:value)}})}var InputTypesPane=class{constructor(host,model){this.crumb="input",this.index=0,this.focused=!1,this.host=host,this.model=model}selected(){return new Set(this.model.read().input??["text"])}render(width){let theme2=this.host.theme,selected=this.selected(),lines=INPUT_TYPES.map((type,rowIndex)=>renderPlainLine(theme2,type,{checked:selected.has(type),active:rowIndex===this.index,paneFocused:this.focused,width}));return this.model.read().input===void 0&&lines.push(renderInfoLine(theme2,"Not set \u2014 the runtime default is [text].",width)),this.error&&lines.push(theme2.fg("error",truncate3(this.error,Math.max(10,width-2)))),lines}handleInput(data){let kb=this.host.keybindings,next=moveSelection(kb,data,this.index,INPUT_TYPES.length);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"app.list.toggle")){let type=INPUT_TYPES[this.index],selected=this.selected();if(selected.has(type)){if(selected.size===1){this.error="At least one input type must stay selected.",this.host.refresh();return}selected.delete(type)}else selected.add(type);this.error=void 0;let next2=INPUT_TYPES.filter(entry=>selected.has(entry));this.model.setField(["input"],[...next2]);return}if(kb.matches(data,"tui.select.confirm")||kb.matches(data,"tui.select.cancel")){this.host.popPane();return}}setFocused(focused){this.focused=focused}hints(){return[keyHint("app.list.toggle","toggle"),keyHint("tui.select.confirm","done"),keyHint("tui.select.cancel","back")].join(" ")}},COST_RATES=["input","output","cacheRead","cacheWrite"],CostPane=class{constructor(host,model){this.crumb="cost",this.index=0,this.focused=!1,this.host=host,this.edit=new InlineEdit(()=>host.refresh()),this.model=model}cost(){let cost=this.model.read().cost;if(cost)return{input:cost.input,output:cost.output,cacheRead:cost.cacheRead,cacheWrite:cost.cacheWrite}}render(width){let theme2=this.host.theme,cost=this.cost(),lines=[];for(let[rowIndex,rate]of COST_RATES.entries()){let value=cost?.[rate];lines.push(renderKeyValueLine(theme2,{keyLabel:rate,valueText:value===void 0?"0 (default)":`$${value} / M tokens`,unset:value===void 0,active:rowIndex===this.index,paneFocused:this.focused,editing:this.edit.editor(rate),width}))}let tiers=this.model.read().cost?.tiers;return tiers&&tiers.length>0&&lines.push(renderInfoLine(theme2,`tiers: ${tiers.length} (read-only; kept as-is)`,width)),this.edit.error&&lines.push(theme2.fg("error",truncate3(this.edit.error,Math.max(10,width-2)))),lines}handleInput(data){let kb=this.host.keybindings;if(this.edit.handleInput(data,kb))return;let next=moveSelection(kb,data,this.index,COST_RATES.length);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"tui.select.confirm")){this.beginEdit("tweak");return}if(isPrintableInput(data)){this.beginEdit("overwrite",data);return}}beginEdit(mode,firstData){let rate=COST_RATES[this.index],current=this.cost()?.[rate];this.edit.begin(rate,current===void 0?"":String(current),mode,this.focused,value=>this.commit(rate,value),firstData)}commit(rate,raw){let value=raw.trim(),parsed=value===""?0:Number(value);if(!Number.isFinite(parsed)||parsed<0)return"cost rates must be finite non-negative numbers.";this.model.read().cost?this.model.setField(["cost",rate],parsed):this.model.setField(["cost"],{input:0,output:0,cacheRead:0,cacheWrite:0,[rate]:parsed})}setFocused(focused){this.focused=focused,this.edit.setFocused(focused)}isEditing(){return this.edit.editing}hints(){return this.edit.editing?[keyHint("tui.input.submit","save"),keyHint("tui.select.cancel","cancel")].join(" "):[rawKeyHint("type","overwrite"),keyHint("tui.select.confirm","edit"),keyHint("tui.select.cancel","back")].join(" ")}},ModelSpecificApiPane=class{constructor(host,model){this.crumb="Model-Specific API",this.rows=["baseUrl","apiType"],this.index=0,this.focused=!1,this.host=host,this.edit=new InlineEdit(()=>host.refresh()),this.model=model}inherited(key){let provider=this.host.store.getProvider(this.host.providerId),providerValue=key==="api"?provider?.api:provider?.baseUrl;if(providerValue)return{value:providerValue,via:"provider"};let current=this.model.read(),effective=key==="api"?this.host.effectiveApi(current):this.host.effectiveBaseUrl(current);return effective?{value:effective,via:"built-in"}:void 0}render(width){let theme2=this.host.theme,current=this.model.read(),lines=[];for(let[rowIndex,row]of this.rows.entries()){let active=rowIndex===this.index,key=row==="apiType"?"api":row,override=current[key],inherited=override?void 0:this.inherited(key);lines.push(renderKeyValueLine(theme2,{keyLabel:row==="apiType"?"API Type":row,valueText:override??inherited?.value??"not set",unset:!override,note:inherited?`\xB7 ${inherited.via}`:void 0,active,paneFocused:this.focused,editing:row==="baseUrl"?this.edit.editor(row):void 0,width}))}this.edit.error&&lines.push(theme2.fg("error",truncate3(this.edit.error,Math.max(10,width-2))));let hint=baseUrlHint(this.host.effectiveApi(current));return hint&&lines.push(renderInfoLine(theme2,hint,width)),lines}handleInput(data){let kb=this.host.keybindings;if(this.edit.handleInput(data,kb))return;let next=moveSelection(kb,data,this.index,this.rows.length);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"tui.select.confirm")){this.rows[this.index]==="apiType"?this.host.pushPane(createModelApiPane(this.host,this.model)):this.beginEdit("tweak");return}if(isPrintableInput(data)){if(this.rows[this.index]==="apiType")return;this.beginEdit("overwrite",data);return}}beginEdit(mode,firstData){let base=this.model.read().baseUrl??this.inherited("baseUrl")?.value??"";this.edit.begin("baseUrl",base,mode,this.focused,value=>this.commit(value),firstData)}commit(raw){let value=raw.trim();if(value){let invalid2=validateBaseUrlValue(value);if(invalid2)return invalid2}this.model.setField(["baseUrl"],value===""?DELETE:value)}setFocused(focused){this.focused=focused,this.edit.setFocused(focused)}isEditing(){return this.edit.editing}hints(){return this.edit.editing?[keyHint("tui.input.submit","save"),keyHint("tui.select.cancel","cancel")].join(" "):[rawKeyHint("type","overwrite"),keyHint("tui.select.confirm","edit / open"),keyHint("tui.select.cancel","back")].join(" ")}};function createModelApiPane(host,model){let fallback=()=>{let provider=host.store.getProvider(host.providerId);return provider?.api??builtinDefaults(host.providerId,model.read().id,provider?.api).api};return new ChoicePane(host,"API Type",{current:()=>model.read().api,choices:()=>{let providerApi=host.store.getProvider(host.providerId)?.api,inherited=fallback(),label=providerApi?`provider: ${providerApi}`:inherited?`built-in: ${inherited}`:"no provider or built-in API",values=[void 0,...API_TYPES],current=model.read().api;return current&&!values.includes(current)&&values.push(current),values.map(value=>({value,label:value??label,dim:value===void 0}))},choose:value=>{if(value===void 0&&!fallback())return"Nothing to inherit \u2014 pick an API.";model.setField(["api"],value??DELETE)}})}var ThinkingMapPane=class{constructor(host,model){this.crumb="thinkingLevelMap",this.mode={type:"levels"},this.index=0,this.focused=!1,this.host=host,this.model=model}map(){return this.model.read().thinkingLevelMap??{}}render(width){let theme2=this.host.theme,lines=[];if(this.model.read().reasoning!==!0&&lines.push(renderInfoLine(theme2,"reasoning is not true \u2014 the map is stored but currently has no effect.",width)),this.mode.type==="levels")for(let[rowIndex,level]of THINKING_LEVELS4.entries()){let value=this.map()[level],status=value===void 0?"default":value===null?"null (hidden)":value;lines.push(renderKeyValueLine(theme2,{keyLabel:level,valueText:status,unset:value===void 0,active:rowIndex===this.index,paneFocused:this.focused,width}))}else if(this.mode.type==="choice"){lines.push(renderInfoLine(theme2,`${this.mode.level} \xB7 mapping`,width));for(let[choiceIndex,label]of["String target (provider effort)","Hidden (null)","Default (remove key)"].entries())lines.push(renderPlainLine(theme2,label,{active:choiceIndex===this.mode.index,paneFocused:this.focused,width}))}else lines.push(renderInfoLine(theme2,`${this.mode.level} \xB7 non-empty provider effort`,width)),lines.push(renderKeyValueLine(theme2,{keyLabel:this.mode.level,active:!0,paneFocused:this.focused,editing:this.editor,width}));return this.error&&lines.push(theme2.fg("error",truncate3(this.error,Math.max(10,width-2)))),lines}handleInput(data){let kb=this.host.keybindings;if(this.mode.type==="target"){if(kb.matches(data,"tui.select.up")||kb.matches(data,"tui.select.down"))return;this.editor?.handleInput(data),this.host.refresh();return}if(this.mode.type==="choice"){if(kb.matches(data,"tui.select.up")){this.mode={...this.mode,index:this.mode.index===0?2:this.mode.index-1},this.host.refresh();return}if(kb.matches(data,"tui.select.down")){this.mode={...this.mode,index:(this.mode.index+1)%3},this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.mode={type:"levels"},this.host.refresh();return}if(kb.matches(data,"tui.select.confirm")){let{level,index:index3}=this.mode;if(index3===0){let editor=new ValueEditor({onCommit:value=>{let target=value.trim();if(!target)return this.error="A string target must be non-empty; use Hidden for null.",this.host.refresh();this.error=void 0,this.mode={type:"levels"},this.editor=void 0,this.model.setField(["thinkingLevelMap",level],target)},onCancel:()=>{this.editor=void 0,this.mode={type:"levels"},this.host.refresh()}});this.editor=editor,editor.focused=this.focused;let existing=this.map()[level];typeof existing=="string"&&editor.beginTweak(existing),this.mode={type:"target",level},this.host.refresh();return}this.mode={type:"levels"},this.model.setField(["thinkingLevelMap",level],index3===1?null:DELETE);return}return}let next=moveSelection(kb,data,this.index,THINKING_LEVELS4.length);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.confirm")){this.mode={type:"choice",level:THINKING_LEVELS4[this.index],index:0},this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}}setFocused(focused){this.focused=focused,this.editor&&(this.editor.focused=focused&&this.mode.type==="target")}isEditing(){return this.mode.type==="target"}hints(){return this.mode.type==="target"?[keyHint("tui.input.submit","save"),keyHint("tui.select.cancel","back")].join(" "):[rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm",this.mode.type==="choice"?"set":"edit"),keyHint("tui.select.cancel","back")].join(" ")}};var DEFAULT_CONTEXT_WINDOW2=128e3,DEFAULT_MAX_TOKENS2=16384,ModelFieldsPane=class{constructor(host,model){this.index=0,this.focused=!1,this.renaming=!1,this.disposed=!1,this.host=host,this.model=model;let rows=[{kind:"text",key:"id"},{kind:"text",key:"name"},{kind:"reasoning"},{kind:"subpage",key:"thinkingLevelMap"},{kind:"subpage",key:"input"},{kind:"subpage",key:"cost"},{kind:"number",key:"contextWindow"},{kind:"number",key:"maxTokens"},{kind:"subpage",key:"compat"}];model.isDraft?rows.push({kind:"modelApi"}):rows.push({kind:"builtin"},{kind:"modelApi"},{kind:"deleteModel"}),this.rows=rows}startEditingId(){this.index=0,this.beginEdit("overwrite")}draftEmpty(){return this.model.isDraft&&Object.keys(this.model.read()).length===0}render(width){let theme2=this.host.theme,current=this.model.read(),lines=[],api=this.host.effectiveApi(current);lines.push(renderInfoLine(theme2,api?`api: ${api}${current.api?" (model)":""}`:"api: none resolved \u2014 see Model-Specific API below",width));for(let[rowIndex,row]of this.rows.entries()){let active=rowIndex===this.index;lines.push(this.renderRow(row,current,active,width))}return this.error&&lines.push(theme2.fg("error",truncate3(this.error,Math.max(10,width-2)))),this.renaming&&lines.push(renderInfoLine(theme2,"Saving model id\u2026",width)),lines}scrollWindow(){return{top:1,bottom:(this.error?1:0)+(this.renaming?1:0),cursor:1+this.index}}renderRow(row,current,active,width){let theme2=this.host.theme,editing=this.editingRow===row?this.editing:void 0;switch(row.kind){case"text":{let value=current[row.key],unsetText=row.key==="id"?"required":"falls back to id";return renderKeyValueLine(theme2,{keyLabel:row.key,valueText:value??`not set (${unsetText})`,unset:!value,active,paneFocused:this.focused,editing,width})}case"reasoning":{let value=current.reasoning;return renderKeyValueLine(theme2,{keyLabel:"reasoning",valueText:value===void 0?"false (default)":String(value),unset:value===void 0,active,paneFocused:this.focused,width})}case"subpage":{let summary=this.subpageSummary(row.key,current);return renderKeyValueLine(theme2,{keyLabel:row.key,valueText:summary.text,unset:summary.unset,active,paneFocused:this.focused,width})}case"number":{let value=current[row.key],fallback=row.key==="contextWindow"?DEFAULT_CONTEXT_WINDOW2:DEFAULT_MAX_TOKENS2;return renderKeyValueLine(theme2,{keyLabel:row.key,valueText:value===void 0?`${fallback} (default)`:String(value),unset:value===void 0,active,paneFocused:this.focused,editing,width})}case"builtin":{let id=current.id,count=id?matchBuiltinModels(id,this.host.effectiveApi(current)).length:0;return renderKeyValueLine(theme2,{valueText:"Use Built-in Data",active,paneFocused:this.focused,note:id?`\xB7 ${count} ${plural(count,"candidate")}`:"\xB7 set id first",width})}case"modelApi":return renderKeyValueLine(theme2,{valueText:"Model-Specific API",active,paneFocused:this.focused,note:`\xB7 ${this.modelApiSummary(current)}`,width});case"deleteModel":return renderKeyValueLine(theme2,{valueText:"Delete Model",active,paneFocused:this.focused,width})}}modelApiSummary(current){let overrides=[current.baseUrl?"baseUrl":"",current.api?"API Type":""].filter(Boolean);if(overrides.length>0)return overrides.join(" + ");let provider=this.host.store.getProvider(this.host.providerId);return provider?.api||provider?.baseUrl?"provider defaults":this.host.effectiveApi(current)||this.host.effectiveBaseUrl(current)?"built-in defaults":"not set"}subpageSummary(key,current){switch(key){case"thinkingLevelMap":{let map=current.thinkingLevelMap,count=map?Object.keys(map).length:0;return count>0?{text:`${count} ${plural(count,"mapping")}`,unset:!1}:{text:"default",unset:!0}}case"input":return current.input?{text:`[${current.input.join(", ")}]`,unset:!1}:{text:"[text] (default)",unset:!0};case"cost":{let cost=current.cost;return cost?{text:`$${cost.input} / $${cost.output} in/out`,unset:!1}:{text:"all 0 (default)",unset:!0}}case"compat":{let compat=current.compat,count=compat?Object.keys(compat).length:0;if(count>0)return{text:`${count} ${count===1?"entry":"entries"}`,unset:!1};let inherited=this.host.store.getProvider(this.host.providerId)?.compat,inheritedCount=inherited?Object.keys(inherited).length:0;return inheritedCount>0?{text:`${inheritedCount} from provider`,unset:!0}:{text:"none",unset:!0}}}}handleInput(data){if(this.renaming||this.disposed)return;let kb=this.host.keybindings;if(this.editing){if(kb.matches(data,"tui.select.up")||kb.matches(data,"tui.select.down"))return;this.editing.handleInput(data),this.host.refresh();return}let next=moveSelection(kb,data,this.index,this.rows.length);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){if(!this.model.isDraft){this.host.popPane();return}if(this.draftEmpty()){this.host.discardModelDraft();return}let label=this.model.read().name??this.model.read().id??"New Model";this.host.confirm(`Discard the new model "${label}"? Its fields are not saved.`,"Discard Model",()=>this.host.discardModelDraft());return}if(kb.matches(data,"app.list.toggle")){this.toggleRow();return}if(kb.matches(data,"tui.select.confirm")){this.enterRow();return}if(isPrintableInput(data)){this.overwriteRow(data);return}}toggleRow(){if(this.rows[this.index].kind!=="reasoning")return;let current=this.model.read().reasoning;this.model.setField(["reasoning"],current!==!0)}enterRow(){let row=this.rows[this.index];switch(row.kind){case"text":case"number":this.beginEdit("tweak");return;case"reasoning":this.host.pushPane(createReasoningPane(this.host,this.model));return;case"subpage":this.pushSubpage(row.key);return;case"modelApi":this.host.pushPane(new ModelSpecificApiPane(this.host,this.model));return;case"builtin":{if(!this.model.read().id){this.host.notify("Set the model id first.","warning");return}this.host.pushPane(new BuiltinCandidatesPane(this.host,this.model));return}case"deleteModel":{let id=this.model.read().id;if(!id)return;if(this.host.isCurrentModel(id)){this.host.notify("The current model cannot be deleted; switch models with /model first.","error");return}this.host.confirm(`Delete model "${id}" from ${this.host.providerId}?`,"Delete Model",()=>{this.host.edits.removeModel(id),this.host.onModelRemoved(id)});return}}}overwriteRow(data){let row=this.rows[this.index];if(row.kind==="text"||row.kind==="number"){this.beginEdit("overwrite",data);return}}beginEdit(mode,firstData){let row=this.rows[this.index];if(row.kind!=="text"&&row.kind!=="number")return;let current=this.model.read()[row.key],editor=new ValueEditor({onCommit:value=>this.commitText(row,value),onCancel:()=>{if(this.editing=void 0,this.editingRow=void 0,this.error=void 0,this.draftEmpty()){this.host.discardModelDraft();return}this.host.refresh()}});this.editing=editor,this.editingRow=row,editor.focused=this.focused,mode==="overwrite"?editor.beginOverwrite(firstData):editor.beginTweak(current===void 0?"":String(current)),this.host.refresh()}commitText(row,raw){let value=raw.trim(),finish=error=>{if(this.error=error,error){this.host.refresh();return}this.editing=void 0,this.editingRow=void 0,this.host.refresh()};if(row.key==="id"){if(!value){finish("id is required and cannot be empty.");return}if(this.model.isDraft){this.model.setField(["id"],value),finish(this.host.commitModelDraft());return}let current=this.model.read().id;if(!current){finish("Missing current id.");return}if(value===current){finish();return}if(this.host.isCurrentModel(current)){finish("The current model's id cannot be renamed; switch models with /model first.");return}if(this.host.store.getModel(this.host.providerId,value)){finish(`Model "${value}" already exists.`);return}this.renaming=!0,this.host.refresh(),this.model.rename(value).then(error=>{this.renaming=!1,this.disposed||finish(error)},error=>{this.renaming=!1,this.disposed||finish(error instanceof Error?error.message:String(error))});return}if(row.key==="name"){this.model.setField(["name"],value===""?DELETE:value),finish();return}if(value===""){this.model.setField([row.key],DELETE),finish();return}let parsed=Number(value);if(!Number.isSafeInteger(parsed)||parsed<=0){finish(`${row.key} must be a positive integer.`);return}this.model.setField([row.key],parsed),finish()}pushSubpage(key){switch(key){case"thinkingLevelMap":this.host.pushPane(new ThinkingMapPane(this.host,this.model));return;case"input":this.host.pushPane(new InputTypesPane(this.host,this.model));return;case"cost":this.host.pushPane(new CostPane(this.host,this.model));return;case"compat":this.host.pushPane(new CompatPane(this.host,this.model));return}}setFocused(focused){this.focused=focused,this.editing&&(this.editing.focused=focused)}isEditing(){return this.editing!==void 0||this.renaming}dispose(){this.disposed=!0}hints(){return this.editing?[keyHint("tui.input.submit","save"),keyHint("tui.select.cancel","cancel")].join(" "):[rawKeyHint("type","overwrite"),keyHint("tui.select.confirm","edit / open"),keyHint("app.list.toggle","toggle"),keyHint("tui.select.cancel",this.model.isDraft?"discard":"back")].join(" ")}};var LEFT_WIDTH_MIN=16,LEFT_WIDTH_MAX=40,BODY_ROWS=14,MIN_WIDTH=56;function padTo(line,width){let missing=width-visibleWidth(line);return missing>0?line+" ".repeat(missing):line}function leftItemKey(item){return item?item.kind==="model"?`model:${item.modelId}`:item.kind:""}var ProviderEditorScreen=class{constructor(tui,theme2,keybindings,done,options){this.leftItems=[],this.leftIndex=0,this.focusPane="left",this.stack=[],this.disposed=!1,this._focused=!1,this.tui=tui,this.theme=theme2,this.keybindings=keybindings,this.done=done,this.options=options,this.edits=new ProviderEdits(options.store,options.providerId,options.refresher,()=>this.refresh()),this.host=this.createHost(),this.rebuildLeftItems(),this.resetRightStack()}get focused(){return this._focused}set focused(value){this._focused=value,this.topPane()?.setFocused(value&&this.focusPane==="right")}invalidate(){this.cache=void 0}dispose(){if(!this.disposed){this.disposed=!0;for(let pane of this.stack)pane.dispose?.();this.stack=[],hasProviderSettings(this.options.store.getProvider(this.options.providerId))||this.options.store.discardProviderDraft(this.options.providerId)}}render(width){if(this.cache&&this.cache.width===width)return this.cache.lines;let lines=this.renderFrame(width);return this.cache={width,lines},lines}handleInput(data){if(this.focusPane==="right"){let pane=this.topPane();if(pane&&!pane.isEditing?.()&&this.keybindings.matches(data,"app.provider.switchPaneLeft")){pane.setFocused(!1),this.focusPane="left",this.refresh();return}pane?.handleInput(data);return}let kb=this.keybindings;if(kb.matches(data,"tui.select.up")){this.moveLeft(-1);return}if(kb.matches(data,"tui.select.down")){this.moveLeft(1);return}if(kb.matches(data,"app.provider.switchPaneRight")){this.activateLeftItem("inspect");return}if(kb.matches(data,"tui.select.confirm")){this.activateLeftItem("activate");return}kb.matches(data,"tui.select.cancel")&&this.done("back")}syncFromStore(){if(this.disposed||this.edits.renaming)return;let selected=this.leftItems[this.leftIndex],selectedKey=leftItemKey(selected);this.rebuildLeftItems();let nextIndex=this.leftItems.findIndex(item=>leftItemKey(item)===selectedKey);this.leftIndex=nextIndex>=0?nextIndex:Math.min(this.leftIndex,this.selectableIndex(0)),nextIndex<0&&selected?.kind==="model"&&this.resetRightStack(),this.refresh()}rebuildLeftItems(){let items=[{kind:"apiAuth"},{kind:"fetch"},{kind:"separator"}];for(let model of this.options.store.getModels(this.options.providerId))items.push({kind:"model",modelId:model.id});this.draft&&items.push({kind:"draft"}),items.push({kind:"separator"},{kind:"addModel"},{kind:"deleteProvider"}),this.leftItems=items}selectableIndex(start){let index3=this.leftItems.findIndex((item,i)=>i>=start&&item.kind!=="separator");return index3>=0?index3:0}moveLeft(delta){let selectable=this.leftItems.map((item,index3)=>({item,index:index3})).filter(entry=>entry.item.kind!=="separator");if(selectable.length===0)return;let position=selectable.findIndex(entry=>entry.index===this.leftIndex),next=selectable[(position+delta+selectable.length)%selectable.length];next.index!==this.leftIndex&&(this.leftIndex=next.index,this.resetRightStack(),this.refresh())}activateLeftItem(via){let item=this.leftItems[this.leftIndex];if(item)switch(item.kind){case"apiAuth":case"model":case"draft":this.focusPane="right",this.topPane()?.setFocused(this._focused),this.refresh();return;case"fetch":if(this.focusPane="right",via==="activate"){let pane=this.topPane();pane instanceof FetchModelsPane&&pane.start()}this.topPane()?.setFocused(this._focused),this.refresh();return;case"addModel":{if(via==="inspect"){this.focusPane="right",this.topPane()?.setFocused(this._focused),this.refresh();return}this.draft||(this.draft=this.edits.draft(),this.rebuildLeftItems());let draftIndex=this.leftItems.findIndex(entry=>entry.kind==="draft");draftIndex>=0&&(this.leftIndex=draftIndex),this.resetRightStack(),this.focusPane="right";let pane=this.topPane();pane?.setFocused(this._focused),pane instanceof ModelFieldsPane&&!this.draft.read().id&&pane.startEditingId(),this.refresh();return}case"deleteProvider":{if(via==="inspect"){this.focusPane="right",this.topPane()?.setFocused(this._focused),this.refresh();return}if(this.host.isCurrentProvider()){this.host.notify("The current model's provider cannot be deleted; switch models with /model first.","error");return}let builtin=isBuiltinProviderId(this.options.providerId);this.host.confirm(`Delete provider "${this.options.providerId}" from models.json?`+(builtin?" The built-in catalog remains and its models may reappear.":"")+" Stored credentials in auth.json are kept.","Delete Provider",()=>{this.edits.removeProvider(),this.done("deleted")});return}default:return}}renderLeft(width){let theme2=this.theme,focused=this.focusPane==="left",rows=[],renderRow=index3=>{let item=this.leftItems[index3];return item.kind==="separator"?theme2.fg("borderMuted",` ${"\u2500".repeat(Math.max(1,width-4))}`):this.renderLeftItem(item,index3===this.leftIndex,focused,width)};if(this.leftItems.length<=BODY_ROWS)for(let index3=0;index3<this.leftItems.length;index3++)rows.push(renderRow(index3));else{let slots=BODY_ROWS-1,start=Math.max(0,Math.min(this.leftIndex-Math.floor(slots/2),this.leftItems.length-slots));for(let index3=start;index3<start+slots;index3++)rows.push(renderRow(index3));let selectable=this.leftItems.filter(item=>item.kind!=="separator"),position=selectable.indexOf(this.leftItems[this.leftIndex]);rows.push(theme2.fg("dim",` (${position+1}/${selectable.length})`))}for(;rows.length<BODY_ROWS;)rows.push("");return rows}leftItemContent(item){let store=this.options.store,text2,note;switch(item.kind){case"apiAuth":text2="API Auth";break;case"fetch":text2="Fetch Models",note=this.fetchStatus;break;case"model":{let model=store.getModel(this.options.providerId,item.modelId);text2=model?modelDisplayName(model):item.modelId;break}case"draft":{text2=this.draft?.read().name??this.draft?.read().id??"New Model",note="\xB7 draft";break}case"addModel":text2="+ Add Model";break;case"deleteProvider":text2="Delete Provider";break;default:text2=""}let dim=item.kind==="draft"&&!this.draft?.read().name&&!this.draft?.read().id;return{text:text2,note,dim}}renderLeftItem(item,active,focused,width){let theme2=this.theme,lit=active&&focused,marker=lit?theme2.fg("accent",`${CURSOR2} `):" ",style=(text3,dim2=!1)=>theme2.fg(lit?"accent":dim2?"dim":"text",text3),{text:label,note,dim}=this.leftItemContent(item),text2=label;if(item.kind==="model"||item.kind==="draft"){let budget=Math.max(8,width-2-(note?visibleWidth(note)+1:0));text2=truncateMiddle2(text2,budget)}let noteText=note?theme2.fg("dim",` ${note}`):"";return truncateToWidth(marker+style(text2,dim)+noteText,width)}topPane(){return this.stack[this.stack.length-1]}pushPane(pane){this.topPane()?.setFocused(!1),this.focusPane="right",this.stack.push(pane),pane.setFocused(this._focused&&this.focusPane==="right"),this.refresh()}popPane(){if(this.stack.length<=1){this.topPane()?.setFocused(!1),this.focusPane="left",this.refresh();return}let pane=this.stack.pop();pane?.setFocused(!1),pane?.dispose?.(),this.topPane()?.setFocused(this._focused&&this.focusPane==="right"),this.refresh()}resetRightStack(){for(let pane of this.stack)pane.dispose?.();let item=this.leftItems[this.leftIndex];this.stack=[this.createBasePane(item)],this.topPane()?.setFocused(this._focused&&this.focusPane==="right")}createBasePane(item){switch(item?.kind){case"apiAuth":return new ApiAuthPane(this.host,this.options.registry);case"fetch":return new FetchModelsPane(this.host);case"model":return new ModelFieldsPane(this.host,this.persistedHandle(item.modelId));case"draft":return new ModelFieldsPane(this.host,this.draft);case"addModel":return new InfoPane(this.host,["Press Enter to create a model.","A draft is kept in memory until its id is set; Esc on the draft discards it."],()=>this.activateLeftItem("activate"));case"deleteProvider":return new InfoPane(this.host,["Press Enter to delete this provider from models.json."],()=>this.activateLeftItem("activate"));default:return new InfoPane(this.host,[])}}persistedHandle(modelId){return this.edits.model(modelId,(oldId,newId)=>{let selected=this.leftItems[this.leftIndex];selected?.kind==="model"&&selected.modelId===oldId&&(selected.modelId=newId),this.syncFromStore()})}createHost(){let store=this.options.store,providerId=this.options.providerId;return{tui:this.tui,theme:this.theme,keybindings:this.keybindings,store,edits:this.edits,providerId,pushPane:pane=>this.pushPane(pane),popPane:()=>this.popPane(),refresh:()=>this.refresh(),notify:(message,type)=>this.options.notify(message,type),effectiveApi:model=>effectiveModelSettings(providerId,store.getProvider(providerId),model).api,effectiveBaseUrl:model=>effectiveModelSettings(providerId,store.getProvider(providerId),model).baseUrl,commitModelDraft:()=>this.commitModelDraft(),discardModelDraft:()=>this.discardModelDraft(),isCurrentModel:modelId=>this.options.currentModel?.provider===providerId&&this.options.currentModel.id===modelId,isCurrentProvider:()=>this.options.currentModel?.provider===providerId,setFetchStatus:status=>{this.fetchStatus=status,this.refresh()},runFetch:signal=>fetchProviderModels(this.options,signal),importModels:async(models,signal)=>{let error=await importProviderModels({...this.options,edits:this.edits},models,signal);return this.disposed||this.syncFromStore(),error},confirm:(message,actionLabel,action)=>this.pushPane(new ConfirmPane(this.host,message,actionLabel,action)),onModelRemoved:()=>{for(this.rebuildLeftItems(),this.leftIndex=Math.min(this.leftIndex,this.leftItems.length-1);this.leftIndex>0&&this.leftItems[this.leftIndex]?.kind==="separator";)this.leftIndex--;this.leftItems[this.leftIndex]?.kind==="separator"&&(this.leftIndex=this.selectableIndex(0)),this.focusPane="left",this.resetRightStack(),this.refresh()}}}discardModelDraft(){if(!this.draft)return;this.draft=void 0,this.rebuildLeftItems();let addIndex=this.leftItems.findIndex(item=>item.kind==="addModel");this.leftIndex=addIndex>=0?addIndex:this.selectableIndex(0),this.focusPane="left",this.resetRightStack(),this.refresh()}commitModelDraft(){let draft=this.draft;if(!draft)return"No model draft.";let error=this.edits.commitDraft(draft);if(error)return error;let id=draft.read().id.trim();this.draft=void 0,this.rebuildLeftItems();let index3=this.leftItems.findIndex(item=>item.kind==="model"&&item.modelId===id);index3>=0&&(this.leftIndex=index3),this.resetRightStack(),this.refresh()}refresh(){this.invalidate(),this.tui.requestRender()}renderFrame(width){let theme2=this.theme,border=new DynamicBorder(text2=>theme2.fg("border",text2)).render(width)[0];if(width<MIN_WIDTH)return[border,truncateToWidth(theme2.fg("warning",` /provider needs at least ${MIN_WIDTH} columns`),width),border];let leftWidth=this.computeLeftWidth(width),rightWidth=width-leftWidth-3,separator=theme2.fg("border"," \u2502 "),title=this.renderTitle(width),crumb=truncateToWidth(this.theme.fg("muted",this.topPane()?.crumb??""),rightWidth),leftLines=this.renderLeft(leftWidth),pane=this.topPane(),paneLines=pane?windowLines(theme2,pane.render(rightWidth),BODY_ROWS-1,pane.scrollWindow?.()):[],rightLines=[crumb,...paneLines],body2=[];for(let row=0;row<BODY_ROWS;row++){let left=padTo(truncateToWidth(leftLines[row]??"",leftWidth),leftWidth),right=truncateToWidth(rightLines[row]??"",rightWidth);body2.push(left+separator+right)}let footerLines=this.renderFooter(width);return[border,title,border,...body2,border,...footerLines,border]}computeLeftWidth(width){let longest=12;for(let item of this.leftItems){if(item.kind==="separator")continue;let{text:text2,note}=this.leftItemContent(item),label=text2+(note?` ${note}`:"");longest=Math.max(longest,visibleWidth(label))}let fit=Math.max(LEFT_WIDTH_MIN,Math.min(LEFT_WIDTH_MAX,longest+2));return Math.min(fit,Math.max(LEFT_WIDTH_MIN,Math.floor(width*.45)))}renderTitle(width){let theme2=this.theme,title=` /provider \xB7 ${this.options.providerId}`;return isBuiltinProviderId(this.options.providerId)&&(title+=" \xB7 overlays built-in catalog"),truncateToWidth(theme2.fg("accent",theme2.bold(title)),width)}renderFooter(width){if(this.focusPane==="right"){let hints2=[this.topPane()?.hints()??"",keyHint("app.provider.switchPaneLeft","focus left")].filter(Boolean).join(" ");return[truncateToWidth(hints2,width)]}let hints=[rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm",this.leftActivateLabel()),keyHint("app.provider.switchPaneRight","focus right"),keyHint("tui.select.cancel","back")].join(" ");return[truncateToWidth(hints,width)]}leftActivateLabel(){switch(this.leftItems[this.leftIndex]?.kind){case"fetch":return"fetch";case"addModel":return"create";case"deleteProvider":return"delete";default:return"open"}}};function modelDisplayName(model){return model.name??model.id}var LIST_ROWS=12,ProviderListScreen=class{constructor(tui,theme2,keybindings,done,store){this.mode="list",this.query="",this.index=0,this.active=!1,this.tui=tui,this.theme=theme2,this.keybindings=keybindings,this.done=done,this.store=store,this.input=new ValueEditor({onCommit:()=>this.confirm(),onCancel:()=>this.cancel()})}get focused(){return this.active}set focused(value){this.active=value,this.input.focused=value}invalidate(){}filtered(){let ids=this.store.getProviderIds();return this.query.trim()?fuzzyFilter(ids,this.query,id=>id):ids}render(width){let theme2=this.theme,border=new DynamicBorder(text2=>theme2.fg("border",text2)).render(width)[0]??"",lines=[border,truncateToWidth(theme2.fg("accent",theme2.bold(" /provider \u2014 models.json providers")),width),border,renderKeyValueLine(theme2,{keyLabel:this.mode==="list"?"Search":"Provider id",active:!1,paneFocused:this.active,editing:this.input,width}),""],area=[];if(this.mode==="list"){let entries=this.filtered(),total=entries.length+1;this.index=Math.min(this.index,total-1);let rows=[];for(let row=0;row<total;row++){let id=entries[row-1],provider=id===void 0?void 0:this.store.getProvider(id),note=id===void 0?void 0:provider?[`${String(provider.models?.length??0)} ${plural(provider.models?.length??0,"model")}`,provider.api].filter(Boolean).join(" \xB7 "):"pending deletion";rows.push(renderPlainLine(theme2,row===0?"+ Add Provider":id,{active:row===this.index,paneFocused:this.active,note,width}))}entries.length===0&&rows.push(renderInfoLine(theme2,this.query?"No matching providers.":"No providers yet.",width)),area.push(...windowLines(theme2,rows,LIST_ROWS,{cursor:this.index}))}else this.error&&area.push(truncateToWidth(theme2.fg("error",this.error),width));for(;area.length<LIST_ROWS;)area.push("");let hints=this.mode==="newProvider"?[keyHint("tui.input.submit","create"),keyHint("tui.select.cancel","cancel")]:[rawKeyHint("type","filter"),rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm","open"),keyHint("tui.select.cancel","close")];return[...lines,...area,border,truncateToWidth(hints.join(" "),width),border]}handleInput(data){let kb=this.keybindings;if(kb.matches(data,"tui.select.cancel")){this.cancel();return}if(this.mode==="list"){let total=this.filtered().length+1;if(kb.matches(data,"tui.select.up"))this.index=(this.index+total-1)%total;else if(kb.matches(data,"tui.select.down"))this.index=(this.index+1)%total;else if(kb.matches(data,"tui.select.confirm")){this.confirm();return}else{let previous=this.query;this.input.handleInput(data),this.query=this.input.value,this.query!==previous&&(this.index=this.query&&this.filtered().length>0?1:0)}}else this.input.handleInput(data);this.tui.requestRender()}confirm(){if(this.mode==="newProvider"){let id=this.input.value.trim();if(!id)this.error="Provider id must be non-empty.";else if(this.store.getProviderIds().includes(id))this.error="This provider id already exists.";else{this.store.ensureProviderView(id),this.done({kind:"open",providerId:id});return}}else if(this.index===0)this.mode="newProvider",this.error=void 0,this.input.reset(this.query);else{let id=this.filtered()[this.index-1];id&&this.done({kind:"open",providerId:id})}this.tui.requestRender()}cancel(){if(this.mode==="list"){this.done({kind:"close"});return}this.mode="list",this.error=void 0,this.input.reset(this.query),this.tui.requestRender()}};var ProviderTuiSession=class extends Container{constructor(tui){super(),this.controller=new AbortController,this.active=!1,this.tui=tui}get signal(){return this.controller.signal}get focused(){return this.active}set focused(value){this.active=value,this.screen&&isFocusable(this.screen)&&(this.screen.focused=value)}setScreen(screen){if(this.signal.aborted){screen.dispose?.();return}this.disposeScreen(),this.screen=screen,this.clear(),this.addChild(screen),this.tui.setFocus(this),this.tui.requestRender()}handleInput(data){this.signal.aborted||this.screen?.handleInput?.(data)}dispose(){this.signal.aborted||(this.controller.abort(),this.disposeScreen(),this.clear())}disposeScreen(){let previous=this.screen;this.screen=void 0,previous&&isFocusable(previous)&&(previous.focused=!1),previous?.dispose?.()}};var SavingScreen=class extends Container{constructor(theme2,keybindings,onCancel){super(),this.keybindings=keybindings,this.onCancel=onCancel,this.addChild(new DynamicBorder(text2=>theme2.fg("border",text2))),this.addChild(new Text(theme2.fg("muted","Saving provider changes and updating models\u2026"),1,1)),this.addChild(new Text(keyHint("tui.select.cancel","return to providers"),1,0)),this.addChild(new DynamicBorder(text2=>theme2.fg("border",text2)))}handleInput(data){this.keybindings.matches(data,"tui.select.cancel")&&this.onCancel()}};function createProviderErrorScreen(tui,done,error){return new ExtensionSelectorComponent("models.json cannot be edited",["Back"],done,done,{tui,description:`${truncate3(error,2400)}
|
|
2067
|
+
`;await writeFile3(tempPath,candidate,{encoding:"utf8",mode:384});let validationError=(await ModelConfig.load(tempPath)).getError();if(validationError)return{kind:"invalid",error:validationError};let latest=await readDocument(this.path);if(latest.exists!==disk.exists||latest.rawText!==disk.rawText)throw new Error("models.json changed while saving; the edits were kept for retry.");return!this.backedUp&&disk.exists&&disk.rawText!==void 0&&(await writeFile3(`${this.path}.bak`,disk.rawText,{encoding:"utf8",mode:384}),this.backedUp=!0),assertLock(),await rename(tempPath,this.path),this.baseline=working,settle(),{kind:"saved",applied:batch.length}}finally{await rm(tempPath,{force:!0}).catch(()=>{})}}};function ensureProvider(doc,providerId){let existing=Object.hasOwn(doc.providers,providerId)?doc.providers[providerId]:void 0;if(existing)return existing;let created={};return Object.defineProperty(doc.providers,providerId,{value:created,writable:!0,enumerable:!0,configurable:!0}),created}function applyOp(doc,op){switch(op.kind){case"set":{let provider=ensureProvider(doc,op.providerId);if(op.modelId===void 0){setPath(provider,op.path,op.value);return}let model=(Array.isArray(provider.models)?provider.models:[]).find(entry=>entry.id===op.modelId);model&&setPath(model,op.path,op.value);return}case"addModel":{let provider=ensureProvider(doc,op.providerId),models=Array.isArray(provider.models)?provider.models:[],index3=models.findIndex(entry=>entry.id===op.model.id),clone=structuredClone(op.model);index3>=0?models[index3]=clone:models.push(clone),provider.models=models;return}case"removeModel":{let provider=doc.providers[op.providerId],models=Array.isArray(provider?.models)?provider.models:void 0;if(!provider||!models)return;provider.models=models.filter(entry=>entry.id!==op.modelId);return}case"renameModel":{let provider=doc.providers[op.providerId],models=Array.isArray(provider?.models)?provider.models:void 0;if(!models)return;let model=models.find(entry=>entry.id===op.oldId);model&&!models.some(entry=>entry.id===op.newId)&&(model.id=op.newId);return}case"removeProvider":{delete doc.providers[op.providerId];return}}}function pruneEmptyNewProviders(working,disk){for(let[providerId,provider]of Object.entries(working.providers))Object.hasOwn(disk.providers,providerId)||isPlainObject2(provider)&&Object.keys(provider).length===0&&delete working.providers[providerId]}var RefreshCoordinator=class{constructor(runtime){this.pending=new Map,this.changed=new Set,this.revision=0,this.runtime=runtime}touch(providerId){this.pending.set(providerId,++this.revision),this.changed.add(providerId)}get touchedProviders(){return[...this.changed]}async refreshNow(providerId,signal){return this.run([providerId],signal)}async flush(signal){let providers=[...this.pending.keys()];return providers.length===0?{ok:!0,aborted:!1,errors:[]}:this.run(providers,signal)}async run(providers,signal){let revisions=new Map(providers.map(id=>[id,this.pending.get(id)])),combined=AbortSignal.any([...signal?[signal]:[],AbortSignal.timeout(REFRESH_TIMEOUT_MS)]),errors=[];try{let result2=await this.runtime.refresh({allowNetwork:!1,providers,signal:combined});for(let[providerId,error]of result2.errors)errors.push(`${providerId}: ${formatError2(error)}`);let configError=this.runtime.getError();configError&&errors.push(configError);let aborted=result2.aborted||combined.aborted;aborted&&errors.length===0&&errors.push("Refresh was cancelled or timed out.");let ok=errors.length===0&&!aborted;if(ok)for(let id of providers)this.pending.get(id)===revisions.get(id)&&this.pending.delete(id);return{ok,aborted,errors}}catch(error){return errors.push(formatError2(error)),{ok:!1,aborted:combined.aborted,errors}}}};function registerListKeybindings(){registerKeybindings({"app.list.toggle":{defaultKeys:"space",description:"Toggle selected list item"}})}registerListKeybindings();registerKeybindings({"app.provider.switchPaneLeft":{defaultKeys:"left",description:"/provider: focus the left pane"},"app.provider.switchPaneRight":{defaultKeys:"right",description:"/provider: focus the right pane"},"app.provider.removeEntry":{defaultKeys:"ctrl+x",description:"/provider: remove the selected compat or dictionary entry"}});async function probeProviderModels(opts){let baseUrl;try{baseUrl=new URL(opts.baseUrl)}catch{return{ok:!1,error:"Base URL is not a valid URL."}}if(baseUrl.protocol!=="http:"&&baseUrl.protocol!=="https:")return{ok:!1,error:`Unsupported protocol: ${baseUrl.protocol}`};if(baseUrl.username||baseUrl.password||baseUrl.hash)return{ok:!1,error:"Base URL must not contain credentials or a fragment."};if(opts.signal?.aborted)return{ok:!1,error:"Cancelled."};let controller=new AbortController,timeoutMs=opts.timeoutMs??PROBE_LIMITS.timeoutMs,timer=setTimeout(()=>controller.abort(),timeoutMs),onOuterAbort=()=>controller.abort();opts.signal?.addEventListener("abort",onOuterAbort,{once:!0});let doFetch=opts.fetch??globalThis.fetch,getPage=async(url,headers)=>{let response=await doFetch(url,{method:"GET",headers,signal:controller.signal});if(!response.ok){let body2=await readResponseTextBounded(response,{maxBytes:PROBE_LIMITS.maxErrorBytes,signal:controller.signal});return{ok:!1,status:response.status,error:`HTTP ${response.status}${body2?`: ${safeErrorText(body2,opts.auth).slice(0,PROBE_LIMITS.maxErrorChars)}`:""}`}}let text2=await readResponseTextBounded(response,{maxBytes:PROBE_LIMITS.maxBodyBytes,overflowMessage:`Response exceeds ${PROBE_LIMITS.maxBodyBytes} bytes.`,signal:controller.signal});try{return{ok:!0,json:JSON.parse(text2)}}catch{return{ok:!1,error:"Model catalog response is not JSON."}}};try{let url=modelCatalogUrl(baseUrl,opts.api),headers=buildHeaders(opts.auth,opts.api),page=await getPage(url,headers),retry=page.ok?void 0:openAIStyleRetry(baseUrl,opts.auth,opts.api,{url,headers,status:page.status});if(!page.ok&&retry){let retried=await getPage(retry.url,retry.headers);if(!retried.ok)return{ok:!1,error:safeErrorText(`${url.href} \u2192 HTTP ${page.status}; OpenAI-style retry ${retry.url.href} \u2192 ${retried.error}`,opts.auth)};({url,headers}=retry),page=retried}if(!page.ok)return{ok:!1,error:page.error};let models=parseCatalogModels(page.json);if(models===null)return{ok:!1,error:"JSON has no supported OpenAI-style data[] or models[] catalog with model ids. Add models manually if this endpoint uses another catalog format."};let json=page.json;for(let pages=1;opts.api==="anthropic-messages"&&pages<PROBE_LIMITS.maxPages&&models.length<PROBE_LIMITS.maxModels;pages++){let cursor=nextPageCursor(json);if(!cursor)break;let nextUrl=new URL(url.href);nextUrl.searchParams.set("after_id",cursor),nextUrl.searchParams.set("limit","1000");let next=await getPage(nextUrl,headers),more=next.ok?parseCatalogModels(next.json):null;if(!next.ok||!more||(models.push(...more),nextPageCursor(next.json)===cursor))break;json=next.json}let sorted=dedupeSort(models),truncated=sorted.length>PROBE_LIMITS.maxModels||declaresMorePages(json);return{ok:!0,models:sorted.slice(0,PROBE_LIMITS.maxModels),truncated}}catch(error){return controller.signal.aborted?{ok:!1,error:opts.signal?.aborted?"Cancelled.":`Timed out after ${timeoutMs}ms.`}:{ok:!1,error:safeErrorText(formatError2(error),opts.auth)}}finally{clearTimeout(timer),opts.signal?.removeEventListener("abort",onOuterAbort)}}function modelCatalogUrl(base,api){let url=new URL(base.href),path14=url.pathname.replace(/\/+$/,"");return url.pathname=api==="anthropic-messages"&&!path14.endsWith("/v1")?`${path14}/v1/models`:`${path14}/models`,url}function openAIStyleRetry(base,auth,api,first){if(api!=="anthropic-messages"||![401,403,404].includes(first.status??0)||Object.keys(auth?.headers??{}).some(key=>key.toLowerCase()==="authorization"))return;let root=new URL(base.href);root.pathname=root.pathname.replace(/\/+$/,"").replace(/\/anthropic$/i,"");let url=modelCatalogUrl(root,api),headers=buildHeaders(auth,void 0);return url.href===first.url.href&&headers.get("authorization")===first.headers.get("authorization")?void 0:{url,headers}}function safeErrorText(text2,auth){for(let value of[auth?.apiKey,...Object.values(auth?.headers??{})]){if(typeof value!="string"||!value)continue;text2=text2.replaceAll(value,"[redacted]");let token=value.replace(/^Bearer\s+/i,"");token!==value&&token&&(text2=text2.replaceAll(token,"[redacted]"))}return stripTerminalSequences(text2)}function buildHeaders(auth,api){let headers=new Headers;headers.set("accept","application/json");let configured=auth?.headers??{};api==="anthropic-messages"&&headers.set("anthropic-version","2023-06-01");let hasAuthorization=!1;for(let[key,value]of Object.entries(configured))key.toLowerCase()==="authorization"&&(hasAuthorization=!0),typeof value=="string"?headers.set(key,value):value===null&&headers.delete(key);if(!auth?.apiKey||hasAuthorization)return headers;let lower=name=>Object.keys(configured).some(key=>key.toLowerCase()===name);return api==="anthropic-messages"?(auth.apiKey.includes("sk-ant-oat")?headers.set("authorization",`Bearer ${auth.apiKey}`):(lower("x-api-key")||headers.set("x-api-key",auth.apiKey),lower("anthropic-version")||headers.set("anthropic-version","2023-06-01")),headers):api==="google-generative-ai"||api==="google-vertex"?(lower("x-goog-api-key")||headers.set("x-goog-api-key",auth.apiKey),headers):(headers.set("authorization",`Bearer ${auth.apiKey}`),headers)}function declaresMorePages(json){return typeof json=="object"&&json!==null&&"has_more"in json&&json.has_more===!0}function nextPageCursor(json){if(!declaresMorePages(json))return;let lastId=json.last_id;return typeof lastId=="string"&&lastId?lastId:void 0}var CONTEXT_WINDOW_FIELDS=["context_window","context_window.tokens","context_length","top_provider.context_length","max_input_tokens","max_context_length","max_model_len","context_size","metadata.context_length"],MAX_TOKENS_FIELDS=["max_output_tokens","max_completion_tokens","top_provider.max_completion_tokens","max_tokens","max_output_length"],INPUT_MODALITY_FIELDS=["input_modalities","architecture.input_modalities","modalities.input"],IMAGE_FLAG_FIELDS=["supports_vision","enable_vision_input","capabilities.vision","capabilities.image_input.supported"],REASONING_FLAG_FIELDS=["reasoning","supports_reasoning","enable_reason","capabilities.reasoning","capabilities.thinking.supported"],REASONING_LEVEL_FIELDS=["effort.supported_levels","reasoning_effort_support_list"],CAPABILITY_LIST_FIELDS=["supported_parameters","tags","features","supported_features","metadata.tags"];function fieldAt(record,path14){let value=record;for(let key of path14.split(".")){if(!value||typeof value!="object"||Array.isArray(value))return;value=value[key]}return value}function listAt(record,path14){let value=fieldAt(record,path14);return Array.isArray(value)?value.filter(entry=>typeof entry=="string").map(entry=>entry.toLowerCase()):[]}function declaredLimit(record,paths){let limit;for(let path14 of paths){let value=fieldAt(record,path14);typeof value=="number"&&Number.isSafeInteger(value)&&value>0&&(limit=Math.min(limit??value,value))}return limit}function declaresImageInput(record){return INPUT_MODALITY_FIELDS.some(path14=>listAt(record,path14).includes("image"))||IMAGE_FLAG_FIELDS.some(path14=>fieldAt(record,path14)===!0)||CAPABILITY_LIST_FIELDS.some(path14=>listAt(record,path14).includes("vision"))}function declaresReasoning(record){return REASONING_FLAG_FIELDS.some(path14=>fieldAt(record,path14)===!0)||REASONING_LEVEL_FIELDS.some(path14=>listAt(record,path14).length>0)||CAPABILITY_LIST_FIELDS.some(path14=>listAt(record,path14).includes("reasoning"))}function parseCatalogModels(json){if(!json||typeof json!="object")return null;let payload=json,data=Array.isArray(json)?json:Array.isArray(payload.models)?payload.models:payload.data;if(!Array.isArray(data))return null;let models=[];for(let item of data){if(!item||typeof item!="object")continue;let record=item,id=(typeof record.id=="string"?record.id.trim():"")||(typeof record.slug=="string"?record.slug.trim():"");if(!id)continue;let displayName=typeof record.name=="string"&&record.name.trim()?record.name.trim():void 0,anthropicName=typeof record.display_name=="string"&&record.display_name.trim()?record.display_name.trim():typeof record.displayName=="string"?record.displayName.trim():void 0,name=(displayName??anthropicName)!==id?displayName??anthropicName:void 0,model=name?{id,name}:{id},contextWindow=declaredLimit(record,CONTEXT_WINDOW_FIELDS);contextWindow&&(model.contextWindow=contextWindow);let maxTokens=declaredLimit(record,MAX_TOKENS_FIELDS);maxTokens&&(model.maxTokens=maxTokens),declaresImageInput(record)&&(model.input=["text","image"]),declaresReasoning(record)&&(model.reasoning=!0),models.push(model)}return data.length>0&&models.length===0?null:models}function dedupeSort(models){let map=new Map;for(let model of models)map.has(model.id)||map.set(model.id,model);return[...map.values()].sort((a,b2)=>a.id.localeCompare(b2.id))}async function fetchProviderModels(options,signal){let{store,refresher,runtime,providerId}=options,deadline=AbortSignal.any([signal,AbortSignal.timeout(PROBE_LIMITS.timeoutMs)]);try{await raceWithAbortSignal(store.flush(),deadline);let unsaved=store.getPendingError(providerId);if(unsaved)return{ok:!1,error:`Save the provider changes before fetching: ${unsaved}`};let provider=store.getProvider(providerId),settings2=effectiveModelSettings(providerId,provider);if(!settings2.baseUrl)return{ok:!1,error:"Set a baseUrl under API Auth first."};let sync=await refresher.refreshNow(providerId,deadline);if(deadline.throwIfAborted(),!sync.ok)return{ok:!1,error:`The provider did not reload: ${sync.errors.join("; ")}`};let resolved=await raceWithAbortSignal(runtime.getAuth(providerId,{signal:deadline}),deadline),configured=provider?.apiKey!==void 0||provider?.authHeader===!0||Object.keys(provider?.headers??{}).length>0||runtime.getProviderAuthStatus(providerId).configured;if(!resolved&&configured)return{ok:!1,error:"Configured credentials or headers did not resolve; check the provider authentication."};let result2=await probeProviderModels({baseUrl:resolved?.auth.baseUrl??settings2.baseUrl,auth:resolved?.auth,api:settings2.api,signal:deadline});return deadline.throwIfAborted(),result2}catch(error){return deadline.aborted?{ok:!1,error:signal.aborted?"Cancelled.":"Timed out while preparing or fetching the model catalog."}:{ok:!1,error:formatError2(error)}}}async function importProviderModels(options,models,signal){let{store,refresher,providerId}=options;await raceWithAbortSignal(store.flush(),signal);let unsaved=store.getPendingError(providerId);if(unsaved)return unsaved;let settings2=effectiveModelSettings(providerId,store.getProvider(providerId));if(!settings2.api||!settings2.baseUrl)return"Set baseUrl and API Type under API Auth before importing models.";let existing=new Set(store.getModels(providerId).map(model=>model.id)),fresh=models.filter(model=>existing.has(model.id)?!1:(existing.add(model.id),!0));if(fresh.length===0)return;signal.throwIfAborted(),options.edits.addModels(fresh),await store.flush();let saveError=store.getPendingError(providerId);if(saveError)return saveError;let outcome=await refresher.refreshNow(providerId,signal);if(!outcome.ok)return`Models were saved, but refresh failed: ${outcome.errors.join("; ")}`}var ProviderEdits=class{constructor(store,providerId,refresher,refresh){this.renaming=!1,this.store=store,this.providerId=providerId,this.refresher=refresher,this.refresh=refresh}changed(){(!this.store.isDraftProvider(this.providerId)||hasProviderSettings(this.store.getProvider(this.providerId)))&&this.refresher.touch(this.providerId),this.refresh()}setProviderField(path14,value){this.store.setProviderField(this.providerId,path14,value),this.changed()}removeProvider(){this.store.removeProvider(this.providerId),this.changed()}removeModel(modelId){this.store.removeModel(this.providerId,modelId),this.changed()}batch(apply){this.store.batch(apply)}addModels(models){this.store.batch(()=>{for(let model of models)this.store.addModel(this.providerId,model)}),models.length>0&&this.changed()}draft(){let fields={};return{isDraft:!0,read:()=>fields,setField:(path14,value)=>{setPath(fields,path14,value),this.refresh()}}}commitDraft(draft){let fields=draft.read(),id=(fields.id??"").trim();if(!id)return"Model id is required.";if(this.store.getModel(this.providerId,id))return`Model "${id}" already exists.`;let settings2=effectiveModelSettings(this.providerId,this.store.getProvider(this.providerId),fields);if(!settings2.api)return"Cannot resolve an api \u2014 set one under Model-Specific API or the provider's API Auth.";if(!settings2.baseUrl)return"Cannot resolve a baseUrl \u2014 set one under Model-Specific API or the provider's API Auth.";this.store.addModel(this.providerId,{...fields,id}),this.changed()}model(modelId,onRename){let id=modelId,snapshot;return{isDraft:!1,read:()=>snapshot??this.store.getModel(this.providerId,id)??{id},setField:(path14,value)=>{this.store.setModelField(this.providerId,id,path14,value),this.changed()},rename:async newId=>{let oldId=id;snapshot=this.store.getModel(this.providerId,id),this.renaming=!0;try{let error=await this.store.renameModel(this.providerId,id,newId);if(error)return error;id=newId,this.changed();return}finally{snapshot=void 0,this.renaming=!1,onRename(oldId,id)}}}}};var CURSOR2="\u203A",PASTE_START="\x1B[200~",PASTE_END="\x1B[201~",ValueEditor=class{constructor(callbacks){this.input=new Input({prompt:""}),this.input.onSubmit=callbacks.onCommit,this.input.onEscape=callbacks.onCancel}beginOverwrite(firstData){this.input.setValue(""),firstData&&this.input.handleInput(firstData)}reset(value){this.beginTweak(value)}beginTweak(current){this.input.setValue(""),this.input.handleInput(PASTE_START+current+PASTE_END),this.input.setValue(current)}get value(){return this.input.getValue()}handleInput(data){this.input.handleInput(data)}renderLine(width){return this.input.render(Math.max(1,width))[0]??""}get focused(){return this.input.focused}set focused(value){this.input.focused=value}};function renderKeyValueLine(theme2,opts){let lit=opts.active&&opts.paneFocused,marker=lit?theme2.fg("accent",`${CURSOR2} `):" ",keyPrefix=opts.keyLabel===void 0?"":`${opts.keyLabel}: `,keyColor=lit?"accent":"text",note=opts.note?theme2.fg("dim",` ${opts.note}`):"";if(opts.editing){let body2=opts.editing.renderLine(Math.max(1,opts.width-visibleWidth(marker)-visibleWidth(keyPrefix)));return truncateToWidth(marker+theme2.fg(keyColor,keyPrefix)+theme2.fg(keyColor,body2)+note,opts.width)}let valueColor=opts.unset?"dim":keyColor,line=marker+theme2.fg(keyColor,keyPrefix)+theme2.fg(valueColor,opts.valueText??"")+note;return truncateToWidth(line,opts.width)}function renderPlainLine(theme2,text2,opts){let lit=(opts.active??!1)&&(opts.paneFocused??!1),marker=lit?theme2.fg("accent",`${CURSOR2} `):" ",check=opts.checked===void 0?"":opts.checked?"[x] ":"[ ] ",color2=opts.dim?"dim":lit?"accent":"text",note=opts.note?theme2.fg("dim",` ${opts.note}`):"",line=marker+theme2.fg(color2,check+text2)+note;return truncateToWidth(line,opts.width)}function renderInfoLine(theme2,text2,width){return truncateToWidth(theme2.fg("dim",text2),width)}function windowLines(theme2,lines,height,scroll,indicator){let top=Math.max(0,Math.min(scroll?.top??0,lines.length)),bottom=Math.max(0,Math.min(scroll?.bottom??0,lines.length-top)),head=lines.slice(0,top),tail2=bottom>0?lines.slice(lines.length-bottom):[],middle=lines.slice(top,lines.length-bottom),cursor=Math.max(0,Math.min((scroll?.cursor??0)-top,Math.max(0,middle.length-1))),padToHeight=rows=>{let out=rows.slice(0,height);for(;out.length<height;)out.push("");return out},avail=height-head.length-tail2.length;if(middle.length<=avail)return padToHeight([...head,...middle,...tail2]);let slots=Math.max(1,avail-1),start=Math.max(0,Math.min(cursor-Math.floor(slots/2),middle.length-slots)),note=indicator?.(cursor+1,middle.length)??theme2.fg("dim",` (${cursor+1}/${middle.length})`);return padToHeight([...head,...middle.slice(start,start+slots),note,...tail2])}function isPrintableInput(data){if(!data)return!1;if(data.startsWith(PASTE_START)||decodeKittyPrintable(data)!==void 0)return!0;if(data.includes("\x1B")||data.includes("\r")||data.includes(`
|
|
2068
|
+
`))return!1;for(let char of data){let code=char.codePointAt(0);if(code<32||code===127)return!1}return!0}function truncateMiddle2(text2,maxWidth){if(visibleWidth(text2)<=maxWidth)return text2;if(maxWidth<=4)return truncateToWidth(text2,maxWidth);let headWidth=Math.ceil((maxWidth-1)/2),tailWidth=maxWidth-1-headWidth,head="",headUsed=0;for(let char of text2){let charWidth=visibleWidth(char);if(headUsed+charWidth>headWidth)break;head+=char,headUsed+=charWidth}let tail2="",tailUsed=0;for(let char of[...text2].reverse()){let charWidth=visibleWidth(char);if(tailUsed+charWidth>tailWidth)break;tail2=char+tail2,tailUsed+=charWidth}return`${head}\u2026${tail2}`}var InfoPane=class{constructor(host,lines,onConfirm){this.focused=!1,this.host=host,this.lines=lines,this.onConfirm=onConfirm}render(width){return this.focused&&this.onConfirm?this.lines.map((line,index3)=>index3>0?renderInfoLine(this.host.theme,line,width):truncateToWidth(this.host.theme.fg("accent",`${CURSOR2} `)+this.host.theme.fg("text",line),width)):this.lines.map(line=>renderInfoLine(this.host.theme,line,width))}handleInput(data){if(this.host.keybindings.matches(data,"tui.select.cancel")){this.host.popPane();return}this.onConfirm&&this.host.keybindings.matches(data,"tui.select.confirm")&&this.onConfirm()}setFocused(focused){this.focused=focused}hints(){let hints=[];return this.onConfirm&&hints.push(keyHint("tui.select.confirm","proceed")),hints.push(keyHint("tui.select.cancel","back")),hints.join(" ")}},ConfirmPane=class{constructor(host,message,actionLabel,action){this.crumb="Confirm",this.index=1,this.focused=!1,this.host=host,this.message=message,this.actionLabel=actionLabel,this.action=action}render(width){let theme2=this.host.theme;return[truncateToWidth(theme2.fg("warning",this.message),width),renderPlainLine(theme2,this.actionLabel,{active:this.index===0,paneFocused:this.focused,width}),renderPlainLine(theme2,"Cancel",{active:this.index===1,paneFocused:this.focused,width})]}handleInput(data){let kb=this.host.keybindings;if(kb.matches(data,"tui.select.up")||kb.matches(data,"tui.select.down")){this.index=this.index===0?1:0,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}kb.matches(data,"tui.select.confirm")&&(this.index===0?this.action():this.host.popPane())}setFocused(focused){this.focused=focused}hints(){return[keyHint("tui.select.confirm","choose"),keyHint("tui.select.cancel","cancel")].join(" ")}};function moveSelection(keys,data,index3,count){let delta=keys.matches(data,"tui.select.up")?-1:keys.matches(data,"tui.select.down")?1:void 0;return delta===void 0?void 0:count===0?0:(index3+delta+count)%count}var ChoicePane=class{constructor(host,crumb,options){this.focused=!1,this.host=host,this.crumb=crumb,this.options=options,this.index=Math.max(0,options.choices().findIndex(choice=>choice.value===options.current()))}render(width){let lines=this.options.choices().map((choice,index3)=>renderPlainLine(this.host.theme,`${choice.value===this.options.current()?"\u25CF":"\u25CB"} ${choice.label}`,{active:index3===this.index,paneFocused:this.focused,dim:choice.dim,width}));return this.error&&lines.push(renderInfoLine(this.host.theme,this.error,width)),lines}scrollWindow(){return{cursor:this.index,bottom:this.error?1:0}}handleInput(data){let choices=this.options.choices(),next=moveSelection(this.host.keybindings,data,this.index,choices.length);if(next!==void 0)this.index=next,this.host.refresh();else if(this.host.keybindings.matches(data,"tui.select.cancel"))this.host.popPane();else if(this.host.keybindings.matches(data,"tui.select.confirm")||this.host.keybindings.matches(data,"app.list.toggle")){let choice=choices[this.index];if(!choice)return;this.error=this.options.choose(choice.value),this.error?this.host.refresh():this.host.popPane()}}setFocused(focused){this.focused=focused}hints(){return[rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm","select"),keyHint("tui.select.cancel","back")].join(" ")}},InlineEdit=class{constructor(refresh){this.refresh=refresh}get editing(){return this.active!==void 0}editor(key){return this.active?.key===key?this.active.editor:void 0}setFocused(focused){this.active&&(this.active.editor.focused=focused)}begin(key,current,mode,focused,commit,firstData){let editor=new ValueEditor({onCommit:value=>{this.error=commit(value),this.error||(this.active=void 0),this.refresh()},onCancel:()=>{this.active=void 0,this.error=void 0,this.refresh()}});this.active={key,editor},editor.focused=focused,mode==="overwrite"?editor.beginOverwrite(firstData):editor.beginTweak(current),this.refresh()}handleInput(data,keys){return this.active?(!keys.matches(data,"tui.select.up")&&!keys.matches(data,"tui.select.down")&&this.active.editor.handleInput(data),this.refresh(),!0):!1}};function formatTokens3(count){return count<1e3?count.toString():count<1e4?`${(count/1e3).toFixed(1)}k`:count<1e6?`${Math.round(count/1e3)}k`:count<1e7?`${(count/1e6).toFixed(1)}M`:`${Math.round(count/1e6)}M`}function metadataNote(model){let parts=[model.contextWindow?`${formatTokens3(model.contextWindow)} ctx`:"",model.maxTokens?`${formatTokens3(model.maxTokens)} out`:"",model.input?.includes("image")?"img":"",model.reasoning?"think":""].filter(Boolean);return parts.length>0?`\xB7 ${parts.join(" \xB7 ")}`:void 0}var FetchModelsPane=class{constructor(host){this.state={type:"idle"},this.query="",this.index=0,this.checked=new Set,this.focused=!1,this.disposed=!1,this.host=host,this.search=new ValueEditor({onCommit:()=>this.importChecked(),onCancel:()=>this.exitResults()})}start(){if(this.disposed||this.state.type==="loading"||this.state.type==="importing"||!this.catalogUrl())return;let controller=new AbortController;this.state={type:"loading",controller},this.host.refresh(),this.host.runFetch(controller.signal).then(result2=>{if(!(this.disposed||controller.signal.aborted||this.state.type!=="loading"||this.state.controller!==controller)){if(result2.ok)this.state={type:"results",catalog:result2},this.checked=new Set,this.query="",this.search.reset(""),this.index=0,this.search.focused=this.focused,this.host.setFetchStatus(`\xB7 ${result2.models.length} models`);else{if(result2.error==="Cancelled.")return;this.state={type:"error",message:result2.error},this.host.setFetchStatus("\xB7 failed")}this.host.refresh()}}).catch(error=>{this.disposed||controller.signal.aborted||this.state.type!=="loading"||this.state.controller!==controller||(this.state={type:"error",message:error instanceof Error?error.message:String(error)},this.host.setFetchStatus("\xB7 failed"),this.host.refresh())})}existingIds(){return new Set(this.host.store.getModels(this.host.providerId).map(model=>model.id))}catalogUrl(){let baseUrl=this.host.store.getProvider(this.host.providerId)?.baseUrl;try{return baseUrl?modelCatalogUrl(new URL(baseUrl),this.host.effectiveApi()).href:void 0}catch{return}}rows(){if(this.state.type!=="results"&&this.state.type!=="importing")return[];let existing=this.existingIds(),rows=this.state.catalog.models.map(model=>({model,added:existing.has(model.id)})),query=this.query.trim().toLowerCase();return query?rows.filter(row=>row.model.id.toLowerCase().includes(query)||row.model.name?.toLowerCase().includes(query)):rows}render(width){let theme2=this.host.theme,catalogUrl=this.catalogUrl();switch(this.state.type){case"idle":return catalogUrl?[renderPlainLine(theme2,"Fetch Models",{active:!0,paneFocused:this.focused,note:`\xB7 from ${truncateMiddle2(catalogUrl,Math.max(10,width-22))}`,width})]:[renderInfoLine(theme2,"Set a baseUrl under API Auth first.",width)];case"loading":return[renderInfoLine(theme2,`Fetching ${catalogUrl??""} \u2026`,width),renderInfoLine(theme2,"Esc cancels the request.",width)];case"error":return[theme2.fg("error",truncate3(this.state.message,Math.max(10,width-2))),renderInfoLine(theme2,"Enter retries; Esc goes back.",width)];case"importing":case"results":{let lines=[];this.state.catalog.truncated&&lines.push(renderInfoLine(theme2,"The catalog was truncated; refine manually if a model is missing.",width)),lines.push(this.search.renderLine(width));let rows=this.rows();for(let[rowIndex,row]of rows.entries()){if(row.added){lines.push(renderPlainLine(theme2,row.model.id,{active:rowIndex===this.index,paneFocused:this.focused,dim:!0,note:"\xB7 Added",width}));continue}lines.push(renderPlainLine(theme2,row.model.name?`${row.model.id} \xB7 ${row.model.name}`:row.model.id,{checked:this.checked.has(row.model.id),active:rowIndex===this.index,paneFocused:this.focused,note:metadataNote(row.model),width}))}rows.length===0&&lines.push(renderInfoLine(theme2,"No matching models.",width));let addedCount=rows.filter(row=>row.added).length;return lines.push(renderInfoLine(theme2,`${this.checked.size} selected \xB7 ${rows.length} shown${addedCount?` \xB7 ${addedCount} already added`:""}`,width)),this.state.type==="importing"&&lines.push(renderInfoLine(theme2,"Importing\u2026",width)),this.state.type==="results"&&this.state.error&&lines.push(theme2.fg("error",truncate3(this.state.error,Math.max(10,width-2)))),lines}}}scrollWindow(){if(this.state.type!=="results"&&this.state.type!=="importing")return{};let top=(this.state.catalog.truncated?1:0)+1,bottom=1+(this.state.type==="importing"||this.state.error?1:0);return{top,bottom,cursor:top+this.index}}handleInput(data){let kb=this.host.keybindings;switch(this.state.type){case"idle":if(kb.matches(data,"tui.select.confirm")){this.start();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}return;case"loading":if(kb.matches(data,"tui.select.cancel")){this.state.controller.abort(),this.state={type:"idle"},this.host.refresh();return}return;case"error":if(kb.matches(data,"tui.select.confirm")){this.start();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}return;case"importing":case"results":this.handleResultsInput(data);return}}handleResultsInput(data){let kb=this.host.keybindings,rows=this.rows(),next=moveSelection(kb,data,this.index,rows.length);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"app.list.toggle")){let row=rows[this.index];if(!row||row.added||this.state.type==="importing")return;this.checked.has(row.model.id)?this.checked.delete(row.model.id):this.checked.add(row.model.id),this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.exitResults();return}if(kb.matches(data,"tui.select.confirm")){this.importChecked();return}let before=this.query;this.search.handleInput(data),this.query=this.search.value,this.query!==before&&(this.index=0),this.host.refresh()}importChecked(){if(this.state.type!=="results")return;let chosen;if(this.checked.size===0){let row=this.rows()[this.index];if(!row||row.added)return;chosen=[row.model]}else chosen=this.state.catalog.models.filter(model=>this.checked.has(model.id));let controller=new AbortController,catalog=this.state.catalog;this.state={type:"importing",catalog,controller},this.host.refresh(),this.host.importModels(chosen,controller.signal).then(error=>{if(!(this.disposed||controller.signal.aborted||this.state.type!=="importing"||this.state.controller!==controller)){if(error)return this.state={type:"results",catalog,error},this.host.setFetchStatus("\xB7 import failed"),this.host.refresh();this.host.setFetchStatus(`\xB7 ${this.host.store.getModels(this.host.providerId).length} models`),this.state={type:"idle"},this.host.popPane()}}).catch(error=>{this.disposed||controller.signal.aborted||this.state.type!=="importing"||this.state.controller!==controller||(this.state={type:"results",catalog,error:error instanceof Error?error.message:String(error)},this.host.refresh())})}exitResults(){(this.state.type==="loading"||this.state.type==="importing")&&this.state.controller.abort(),this.state={type:"idle"},this.checked=new Set,this.host.popPane()}setFocused(focused){this.focused=focused,this.search.focused=focused&&(this.state.type==="results"||this.state.type==="importing")}isEditing(){return this.state.type==="results"||this.state.type==="importing"}dispose(){this.disposed=!0,(this.state.type==="loading"||this.state.type==="importing")&&this.state.controller.abort()}hints(){switch(this.state.type){case"loading":return keyHint("tui.select.cancel","cancel request");case"importing":case"results":return[rawKeyHint("type","filter"),keyHint("app.list.toggle","check"),keyHint("tui.select.confirm","import"),keyHint("tui.select.cancel","discard")].join(" ");case"error":return[keyHint("tui.select.confirm","retry"),keyHint("tui.select.cancel","back")].join(" ");default:return this.catalogUrl()?[keyHint("tui.select.confirm","fetch"),keyHint("tui.select.cancel","back")].join(" "):keyHint("tui.select.cancel","back")}}};function formatContext(model){let ctx=model.contextWindow>=1e3?`${Math.round(model.contextWindow/1024)}k`:String(model.contextWindow);return`${model.api} \xB7 ${ctx} ctx${model.reasoning?" \xB7 reasoning":""}`}var BuiltinCandidatesPane=class{constructor(host,model){this.crumb="Use Built-in Data",this.index=0,this.focused=!1,this.host=host,this.model=model,this.query=this.model.read().id??"",this.search=new ValueEditor({onCommit:()=>this.pickCurrent(),onCancel:()=>this.host.popPane()}),this.search.reset(this.query)}candidates(){return matchBuiltinModels(this.query,this.host.effectiveApi(this.model.read()))}render(width){let theme2=this.host.theme,lines=[this.search.renderLine(width)],matches=this.candidates();matches.length===0&&lines.push(renderInfoLine(theme2,"No builtin candidates \u2014 keep configuring manually.",width));for(let[rowIndex,match2]of matches.entries()){let{providerId,model}=match2.entry,label=`${providerId} / ${model.id}`,note=(match2.tier==="exact"?"exact \xB7 ":"")+`${model.name!==model.id?`${model.name} \xB7 `:""}${formatContext(model)}`;lines.push(renderPlainLine(theme2,label,{active:rowIndex===this.index,paneFocused:this.focused,note,width}))}return lines.push(renderInfoLine(theme2,"Candidates are a reference only; the configured id is never rewritten.",width)),lines}scrollWindow(){return{top:1,bottom:1,cursor:1+this.index}}pickCurrent(){let entry=this.candidates()[this.index]?.entry;entry&&this.host.pushPane(new BuiltinPreviewPane(this.host,this.model,entry))}handleInput(data){let kb=this.host.keybindings,count=this.candidates().length,next=moveSelection(kb,data,this.index,count);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"tui.select.confirm")){this.pickCurrent();return}let before=this.query;this.search.handleInput(data),this.query=this.search.value,this.query!==before&&(this.index=0),this.host.refresh()}setFocused(focused){this.focused=focused,this.search.focused=focused}isEditing(){return!0}hints(){return[rawKeyHint("type","filter"),rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm","preview"),keyHint("tui.select.cancel","back")].join(" ")}},BuiltinPreviewPane=class{constructor(host,model,reference){this.crumb="Use Built-in Data \xB7 preview",this.index=0,this.focused=!1,this.host=host,this.model=model,this.reference=reference;let current=model.read();this.snapshot=structuredClone(current),this.snapshotApi=host.effectiveApi(current),this.changes=computeFieldChanges(current,reference.model,host.effectiveApi(current)),this.checked=this.changes.map(change=>change.checked&&change.applicable)}rowCount(){return this.changes.length+1}render(width){let theme2=this.host.theme,lines=[renderInfoLine(theme2,`reference: ${this.reference.providerId} / ${this.reference.model.id}`,width)];for(let[rowIndex,change]of this.changes.entries()){let active=rowIndex===this.index,expandable=change.referenceDetails!==void 0,note=change.applicable?void 0:"\xB7 view only";if(lines.push(renderPlainLine(theme2,`${change.field}: ${change.currentText} \u2192 ${change.referenceText}`,{checked:change.applicable?this.checked[rowIndex]:void 0,active,paneFocused:this.focused,note,width})),this.expanded===rowIndex&&expandable){for(let detail of change.referenceDetails)lines.push(renderInfoLine(theme2,` ${detail}`,width));change.referenceHasTiers&&lines.push(renderInfoLine(theme2," reference has cost tiers \u2014 tiers are never imported.",width))}}return lines.push(renderPlainLine(theme2,"Apply Selected Fields",{active:this.index===this.changes.length,paneFocused:this.focused,width})),this.error&&lines.push(theme2.fg("error",truncate3(this.error,Math.max(10,width-2)))),lines}scrollWindow(){let cursor=1+this.index;if(this.expanded!==void 0&&this.expanded<this.index){let change=this.changes[this.expanded];change.referenceDetails&&(cursor+=change.referenceDetails.length+(change.referenceHasTiers?1:0))}return{top:1,bottom:this.error?1:0,cursor}}handleInput(data){let kb=this.host.keybindings,next=moveSelection(kb,data,this.index,this.rowCount());if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"app.list.toggle")){let change=this.changes[this.index];if(!change)return;if(!change.applicable){this.expanded=this.expanded===this.index?void 0:this.index,this.host.refresh();return}this.checked[this.index]=!this.checked[this.index],this.host.refresh();return}if(kb.matches(data,"tui.select.confirm")){if(this.index===this.changes.length){this.apply();return}let change=this.changes[this.index];change.referenceDetails?this.expanded=this.expanded===this.index?void 0:this.index:change.applicable&&(this.checked[this.index]=!this.checked[this.index]),this.host.refresh();return}}apply(){let current=this.model.read();if(this.host.effectiveApi(current)!==this.snapshotApi){this.error="The API changed since this preview opened; reopen to continue.",this.host.refresh();return}if(!current.id||!jsonEquals(current,this.snapshot)){this.error="The model changed since this preview opened; reopen to continue.",this.host.refresh();return}let chosen=this.changes.filter((_2,rowIndex)=>this.checked[rowIndex]&&this.changes[rowIndex].applicable);if(chosen.length===0){this.host.popPane();return}this.host.edits.batch(()=>{for(let change of chosen)for(let patch of change.patches)this.model.setField(patch.path,patch.value)}),this.host.notify(`Applied ${chosen.length} field${chosen.length===1?"":"s"} from ${this.reference.providerId} / ${this.reference.model.id}.`,"info"),this.host.popPane(),this.host.popPane()}setFocused(focused){this.focused=focused}hints(){return[keyHint("app.list.toggle","check"),keyHint("tui.select.confirm","details / apply"),keyHint("tui.select.cancel","back")].join(" ")}};var THINKING_VARIABLES=["thinking.enabled","thinking.effort","thinking.budget"],SESSION_AFFINITY=["openai","openai-nosession","openrouter"],OPENAI_COMPLETIONS_FIELDS=[{key:"supportsStore",kind:"boolean",note:"Accepts the `store` parameter"},{key:"supportsDeveloperRole",kind:"boolean",note:"Accepts `developer` role messages"},{key:"supportsReasoningEffort",kind:"boolean",note:"Accepts `reasoning_effort`"},{key:"supportsUsageInStreaming",kind:"boolean",note:"Streams usage chunks"},{key:"supportsFinishReason",kind:"boolean",note:"Reports finish reasons"},{key:"maxTokensField",kind:"enum",options:["max_completion_tokens","max_tokens"],note:"Token limit field name"},{key:"requiresToolResultName",kind:"boolean",note:"Tool results need a `name`"},{key:"requiresAssistantAfterToolResult",kind:"boolean",note:"Needs assistant message after tool results"},{key:"requiresThinkingAsText",kind:"boolean",note:"Thinking must be plain text"},{key:"requiresReasoningContentOnAssistantMessages",kind:"boolean",note:"Assistant messages must carry reasoning content"},{key:"thinkingFormat",kind:"enum",options:["openai","openrouter","together","baseten","deepseek","zai","qwen","chat-template","qwen-chat-template","string-thinking","ant-ling"],note:"Reasoning payload format"},{key:"chatTemplateKwargs",kind:"stringMap",note:"Extra chat-template kwargs (open dictionary)"},{key:"chatTemplateArgs",kind:"stringMap",note:"Extra chat-template args (open dictionary)"},{key:"cacheControlFormat",kind:"enum",options:["anthropic"],note:"Cache-control payload format"},{key:"openRouterRouting",kind:"json",note:"OpenRouter routing preferences object"},{key:"vercelGatewayRouting",kind:"json",note:"Vercel AI Gateway routing object"},{key:"supportsOpenAIGrammarTools",kind:"boolean",note:"Grammar-constrained tool calls"},{key:"supportsStrictMode",kind:"boolean",note:"Strict tool schemas"},{key:"sendSessionAffinityHeaders",kind:"boolean",note:"Send session affinity headers"},{key:"supportsMidConvoSystemMessages",kind:"boolean",note:"Accepts mid-conversation system messages"},{key:"supportsMidConvoToolAdditions",kind:"boolean",note:"System messages can add tools mid-conversation"},{key:"sessionAffinityFormat",kind:"enum",options:SESSION_AFFINITY,note:"Affinity header format"},{key:"supportsLongCacheRetention",kind:"boolean",note:"Long-lived prompt cache retention"},{key:"vllmPriority",kind:"number",note:"vLLM scheduling priority"},{key:"zaiToolStream",kind:"boolean",note:"Z.AI streaming tool calls"},{key:"supportsThinkingTokenBudget",kind:"boolean",note:"Enable the thinking-token budget alias"},{key:"thinkingTokenBudgetField",kind:"enum",options:["thinking_token_budget","thinking_budget","thinking_budget_tokens"],note:"Thinking budget field"}],OPENAI_RESPONSES_FIELDS=[{key:"supportsDeveloperRole",kind:"boolean",note:"Accepts `developer` role messages"},{key:"sessionAffinityFormat",kind:"enum",options:SESSION_AFFINITY,note:"Affinity header format"},{key:"supportsLongCacheRetention",kind:"boolean",note:"Long-lived prompt cache retention"},{key:"supportsStrictMode",kind:"boolean",note:"Strict tool schemas"},{key:"supportsOpenAIGrammarTools",kind:"boolean",note:"Grammar-constrained tool calls"},{key:"supportsAdditionalTools",kind:"boolean",note:"Accepts additional hosted tools"},{key:"supportsToolSearch",kind:"boolean",note:"Tool search support"},{key:"supportsMaxOutputTokens",kind:"boolean",note:"Accepts `max_output_tokens`"},{key:"supportsExplicitPromptCacheMode",kind:"boolean",note:"Explicit prompt caching"}],ANTHROPIC_MESSAGES_FIELDS=[{key:"supportsEagerToolInputStreaming",kind:"boolean",note:"Streams tool input eagerly"},{key:"supportsLongCacheRetention",kind:"boolean",note:"Long-lived prompt cache retention"},{key:"sendSessionAffinityHeaders",kind:"boolean",note:"Send session affinity headers"},{key:"supportsCacheControlOnTools",kind:"boolean",note:"Cache control on tool definitions"},{key:"supportsTemperature",kind:"boolean",note:"Accepts `temperature`"},{key:"forceAdaptiveThinking",kind:"boolean",note:"Force adaptive thinking mode"},{key:"allowEmptySignature",kind:"boolean",note:"Tolerate empty thinking signatures"},{key:"supportsStrictTools",kind:"boolean",note:"Strict tool schemas"},{key:"supportsMidConvoEffort",kind:"boolean",note:"Effort changes mid-conversation"},{key:"supportsMidConvoSystemMessages",kind:"boolean",note:"Accepts mid-conversation system messages"},{key:"supportsMidConvoToolChanges",kind:"boolean",note:"Accepts mid-conversation tool changes"},{key:"allowedFallbackModels",kind:"json",note:"Server-side refusal fallback models"}],BEDROCK_FIELDS=[{key:"supportsStrictMode",kind:"boolean",note:"Strict tool schemas"}];function compatFieldsForApi(api){switch(api){case"openai-completions":return OPENAI_COMPLETIONS_FIELDS;case"openai-responses":return OPENAI_RESPONSES_FIELDS;case"azure-openai-responses":return OPENAI_RESPONSES_FIELDS.filter(field5=>["supportsDeveloperRole","supportsStrictMode","supportsOpenAIGrammarTools"].includes(field5.key));case"openai-codex-responses":return OPENAI_RESPONSES_FIELDS.filter(field5=>["supportsStrictMode","supportsOpenAIGrammarTools","supportsAdditionalTools","supportsToolSearch"].includes(field5.key));case"anthropic-messages":return ANTHROPIC_MESSAGES_FIELDS;case"bedrock-converse-stream":return BEDROCK_FIELDS;default:return[]}}function compatFieldFor(api,key){return compatFieldsForApi(api).find(field5=>field5.key===key)}var completionsCompatValidator=Compile(OpenAICompletionsCompatSchema);function validateCompletionsCompat(value){if(!completionsCompatValidator.Check(value))return completionsCompatValidator.Errors(value).slice(0,5).map(error=>{let path14=error.instancePath.replace(/^\//,"").replace(/\//g,"."),required=error.keyword==="required"?error.params.requiredProperties?.[0]:void 0;return`${required?path14?`${path14}.${required}`:required:path14||"root"}: ${error.message}`}).join("; ")}function validateJsonCompatValue(key,text2){let value;try{value=JSON.parse(text2)}catch{return"Value is not valid JSON."}return validateCompletionsCompat({[key]:value})}function validateChatTemplateKwarg(value){if(value!==null&&typeof value=="object"&&!Array.isArray(value)&&!Object.keys(value).every(key=>key==="$var"||key==="omitWhenOff"))return'Only "$var" and "omitWhenOff" are allowed.';let error=validateCompletionsCompat({chatTemplateKwargs:{value}});return error?`Value must be a scalar or valid $var reference: ${error}`:void 0}function compatObject(handle){let compat=handle.read().compat;return typeof compat=="object"&&compat!==null&&!Array.isArray(compat)?compat:{}}function scalarText(value){return value===null?"null":typeof value=="string"||typeof value=="number"||typeof value=="boolean"?String(value):JSON.stringify(value)??String(value)}var DICT_VALUE_KINDS=["string","number","boolean","null","$var"],VAR_OPTIONS=THINKING_VARIABLES,DictPane=class{constructor(host,model,dictKey){this.index=0,this.mode={type:"list"},this.focused=!1,this.host=host,this.model=model,this.dictKey=dictKey,this.crumb=`compat \xB7 ${dictKey}`}dict(){let value=compatObject(this.model)[this.dictKey];return typeof value=="object"&&value!==null&&!Array.isArray(value)?value:{}}entries(){return Object.entries(this.dict())}render(width){let theme2=this.host.theme,lines=[renderInfoLine(theme2,"free-form keys; values: string \xB7 number \xB7 boolean \xB7 null \xB7 $var",width)];if(this.mode.type!=="list")return lines.push(...this.renderMode(width)),this.error&&lines.push(renderInfoLine(theme2,this.error,width)),lines;let entries=this.entries();for(let[rowIndex,[key,value]]of entries.entries()){let active=rowIndex===this.index;lines.push(renderKeyValueLine(theme2,{keyLabel:key,valueText:scalarText(value),active,paneFocused:this.focused,width}))}return lines.push(renderPlainLine(theme2,"+ Add Entry",{active:this.index===entries.length&&this.mode.type==="list",paneFocused:this.focused,width})),this.error&&lines.push(theme2.fg("error",truncate3(this.error,Math.max(10,width-2)))),lines}scrollWindow(){return this.mode.type!=="list"?{top:1,bottom:this.error?1:0}:{top:1,bottom:this.error?1:0,cursor:1+this.index}}renderMode(width){let theme2=this.host.theme,mode=this.mode;switch(mode.type){case"keyEdit":return[renderInfoLine(theme2,"new key:",width),mode.editor.renderLine(width)];case"kindPick":return[renderInfoLine(theme2,`${mode.key} \xB7 value kind`,width),...DICT_VALUE_KINDS.map((kind,kindIndex)=>renderPlainLine(theme2,kind,{active:kindIndex===mode.index,paneFocused:this.focused,width}))];case"valueEdit":return[renderInfoLine(theme2,`${mode.key} \xB7 ${mode.kind}`,width),renderKeyValueLine(theme2,{keyLabel:mode.key,active:!0,paneFocused:this.focused,editing:mode.editor,width})];case"boolPick":return[renderInfoLine(theme2,`${mode.key} \xB7 boolean`,width),...["true","false"].map((option,optionIndex)=>renderPlainLine(theme2,option,{active:optionIndex===mode.index,paneFocused:this.focused,width}))];case"varPick":return[renderInfoLine(theme2,`${mode.key} \xB7 $var`,width),...VAR_OPTIONS.map((option,optionIndex)=>renderPlainLine(theme2,option,{active:optionIndex===mode.index,paneFocused:this.focused,width}))];case"omitPick":return[renderInfoLine(theme2,`${mode.key} \xB7 omitWhenOff`,width),...["default","true","false"].map((option,optionIndex)=>renderPlainLine(theme2,option,{active:optionIndex===mode.index,paneFocused:this.focused,width}))];default:return[]}}handleInput(data){let kb=this.host.keybindings,mode=this.mode;switch(mode.type){case"keyEdit":case"valueEdit":if(kb.matches(data,"tui.select.up")||kb.matches(data,"tui.select.down"))return;mode.editor.handleInput(data),this.host.refresh();return;case"kindPick":this.handlePick(data,mode,DICT_VALUE_KINDS.length,index3=>{let key=mode.key,kind=DICT_VALUE_KINDS[index3];this.startValueForKind(key,kind)});return;case"boolPick":this.handlePick(data,mode,2,index3=>{let key=mode.key;this.mode={type:"list"},this.writeEntry(key,index3===0)});return;case"varPick":this.handlePick(data,mode,VAR_OPTIONS.length,index3=>{let key=mode.key;this.mode={type:"omitPick",key,$var:VAR_OPTIONS[index3],index:0},this.host.refresh()});return;case"omitPick":this.handlePick(data,mode,3,index3=>{this.mode={type:"list"},this.writeEntry(mode.key,index3===0?{$var:mode.$var}:{$var:mode.$var,omitWhenOff:index3===1})});return;case"list":this.handleList(data);return}}handlePick(data,mode,count,choose2){let kb=this.host.keybindings,index3=mode.index;if(kb.matches(data,"tui.select.up")){mode.index=index3===0?count-1:index3-1,this.host.refresh();return}if(kb.matches(data,"tui.select.down")){mode.index=(index3+1)%count,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.mode={type:"list"},this.host.refresh();return}kb.matches(data,"tui.select.confirm")&&choose2(index3)}handleList(data){let kb=this.host.keybindings,rowCount=this.entries().length+1,next=moveSelection(kb,data,this.index,rowCount);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"app.provider.removeEntry")){let entry=this.entries()[this.index];if(!entry)return;this.model.setField(["compat",this.dictKey,entry[0]],DELETE),this.index=Math.max(0,Math.min(this.index,this.entries().length-1));return}if(kb.matches(data,"tui.select.confirm")||kb.matches(data,"app.list.toggle")){let entry=this.entries()[this.index];if(!entry){let editor2=new ValueEditor({onCommit:raw=>{let key2=raw.trim();if(!key2)return this.error="Key must be non-empty.",this.host.refresh();if(Object.hasOwn(this.dict(),key2))return this.error=`"${key2}" already exists.`,this.host.refresh();this.error=void 0,this.mode={type:"kindPick",key:key2,index:0},this.host.refresh()},onCancel:()=>{this.mode={type:"list"},this.error=void 0,this.host.refresh()}});editor2.focused=this.focused,this.mode={type:"keyEdit",editor:editor2},this.host.refresh();return}let[key,value]=entry;if(typeof value=="boolean"){this.writeEntry(key,!value);return}if(value===null)return;if(typeof value=="object"){let record=value;if(record.$var==="thinking.enabled"||record.$var==="thinking.effort"||record.$var==="thinking.budget"){this.mode={type:"omitPick",key,$var:record.$var,index:record.omitWhenOff===void 0?0:record.omitWhenOff?1:2},this.host.refresh();return}return}let kind=typeof value=="number"?"number":"string",editor=new ValueEditor({onCommit:raw=>this.commitScalar(key,kind,raw),onCancel:()=>{this.mode={type:"list"},this.error=void 0,this.host.refresh()}});editor.beginTweak(String(value)),editor.focused=this.focused,this.mode={type:"valueEdit",key,kind,editor},this.host.refresh();return}}startValueForKind(key,kind){switch(kind){case"string":case"number":{let editor=new ValueEditor({onCommit:raw=>this.commitScalar(key,kind,raw),onCancel:()=>{this.mode={type:"list"},this.error=void 0,this.host.refresh()}});editor.focused=this.focused,this.mode={type:"valueEdit",key,kind,editor},this.host.refresh();return}case"boolean":this.mode={type:"boolPick",key,index:0},this.host.refresh();return;case"null":this.mode={type:"list"},this.writeEntry(key,null);return;case"$var":this.mode={type:"varPick",key,index:0},this.host.refresh();return}}commitScalar(key,kind,raw){let value=raw;if(kind==="number"){let parsed=Number(raw.trim());if(!Number.isFinite(parsed)){this.error=`${key} must be a number.`,this.host.refresh();return}value=parsed}let invalid2=validateChatTemplateKwarg(value);if(invalid2){this.error=invalid2,this.host.refresh();return}this.error=void 0,this.mode={type:"list"},this.writeEntry(key,value)}writeEntry(key,value){let invalid2=validateChatTemplateKwarg(value);if(invalid2){this.error=invalid2,this.host.refresh();return}this.model.setField(["compat",this.dictKey,key],value)}setFocused(focused){this.focused=focused,(this.mode.type==="keyEdit"||this.mode.type==="valueEdit")&&(this.mode.editor.focused=focused)}isEditing(){return this.mode.type==="keyEdit"||this.mode.type==="valueEdit"}hints(){switch(this.mode.type){case"keyEdit":case"valueEdit":return[keyHint("tui.input.submit","save"),keyHint("tui.select.cancel","cancel")].join(" ");case"list":return[keyHint("tui.select.confirm","edit / add"),keyHint("app.provider.removeEntry","remove"),keyHint("tui.select.cancel","back")].join(" ");default:return[rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm","choose"),keyHint("tui.select.cancel","cancel")].join(" ")}}};function compatObject2(handle){let compat=handle.read().compat;return typeof compat=="object"&&compat!==null&&!Array.isArray(compat)?compat:{}}function scalarText2(value){return value===null?"null":typeof value=="string"||typeof value=="number"||typeof value=="boolean"?String(value):JSON.stringify(value)??String(value)}var CompatPane=class{constructor(host,model){this.crumb="compat",this.index=0,this.mode={type:"list"},this.focused=!1,this.host=host,this.model=model}entries(){return Object.entries(compatObject2(this.model))}effectiveApi(){return this.host.effectiveApi(this.model.read())}rowCount(){return this.entries().length+1}render(width){let theme2=this.host.theme,api=this.effectiveApi(),lines=[renderInfoLine(theme2,api?`effective api: ${api}`:"effective api: unresolved \u2014 set API Type",width)];if(this.mode.type==="chooseValue"){let mode=this.mode;lines.push(renderKeyValueLine(theme2,{keyLabel:mode.key,valueText:"choose a value",active:!0,paneFocused:this.focused,width}));for(let[index3,option]of mode.options.entries())lines.push(renderPlainLine(theme2,option,{active:index3===mode.index,paneFocused:this.focused,width}));return lines}let known=api?compatFieldsForApi(api):[],entries=this.entries(),editingKey=this.mode.type==="list"?void 0:this.mode.key;editingKey!==void 0&&!entries.some(([key])=>key===editingKey)&&entries.push([editingKey,void 0]),known.length===0&&entries.length===0&&lines.push(renderInfoLine(theme2,`No compat fields are known for ${api??"this api"}.`,width));for(let[rowIndex,[key,value]]of entries.entries()){let active=rowIndex===this.index,field5=api?compatFieldFor(api,key):void 0,editing=this.mode.type==="editValue"&&this.mode.key===key?this.mode.editor:void 0,note=field5?void 0:`\xB7 not used by ${api??"this api"}`;lines.push(renderKeyValueLine(theme2,{keyLabel:key,valueText:value===void 0?"not set":scalarText2(value),active,paneFocused:this.focused,editing,note,width}))}return lines.push(renderPlainLine(theme2,"+ Add Entry",{active:this.index===entries.length&&this.mode.type==="list",paneFocused:this.focused,width})),this.error&&lines.push(theme2.fg("error",truncate3(this.error,Math.max(10,width-2)))),lines}scrollWindow(){return this.mode.type==="chooseValue"?{top:1,cursor:2+this.mode.index}:{top:1,bottom:this.error?1:0,cursor:1+this.index}}handleInput(data){let kb=this.host.keybindings;if(this.mode.type==="editValue"){if(kb.matches(data,"tui.select.up")||kb.matches(data,"tui.select.down"))return;this.mode.editor.handleInput(data),this.host.refresh();return}if(this.mode.type==="chooseValue"){let mode=this.mode;if(kb.matches(data,"tui.select.up")){this.mode={...mode,index:mode.index===0?mode.options.length-1:mode.index-1},this.host.refresh();return}if(kb.matches(data,"tui.select.down")){this.mode={...mode,index:(mode.index+1)%mode.options.length},this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.mode={type:"list"},this.host.refresh();return}if(kb.matches(data,"tui.select.confirm")){let option=mode.options[mode.index];this.mode={type:"list"},this.writeValue(mode.key,this.parseChosen(option))}return}let next=moveSelection(kb,data,this.index,this.rowCount());if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"app.provider.removeEntry")){let entry=this.entries()[this.index];if(!entry)return;let[key]=entry;this.model.setField(["compat",key],DELETE),this.index=Math.min(this.index,this.rowCount()-2<0?0:this.rowCount()-2);return}if(kb.matches(data,"app.list.toggle")||kb.matches(data,"tui.select.confirm")){this.activateRow();return}}activateRow(){let entries=this.entries();if(this.index===entries.length){let api=this.effectiveApi();if(!api){this.fail("Set API Type first \u2014 compat fields depend on the effective api.");return}if(compatFieldsForApi(api).length===0){this.fail(`No compat fields are known for ${api}.`);return}let taken=new Set(entries.map(([key2])=>key2));this.host.pushPane(new CompatKeyPickerPane(this.host,api,taken,key2=>this.beginValueEntry(key2)));return}let[key,value]=entries[this.index],field5=this.effectiveApi()?compatFieldFor(this.effectiveApi(),key):void 0;if(!field5){this.beginJsonEdit(key,value);return}switch(field5.kind){case"boolean":this.writeValue(key,value!==!0);return;case"enum":this.mode={type:"chooseValue",key,options:field5.options,index:0},this.host.refresh();return;case"number":this.beginTextEdit(key,value);return;case"json":this.beginJsonEdit(key,value);return;case"stringMap":this.host.pushPane(new DictPane(this.host,this.model,key));return}}beginValueEntry(key){let api=this.effectiveApi(),field5=compatFieldFor(api,key);switch(field5.kind){case"boolean":this.mode={type:"chooseValue",key,options:["true","false"],index:0},this.host.refresh();return;case"enum":this.mode={type:"chooseValue",key,options:field5.options,index:0},this.host.refresh();return;case"number":this.beginTextEdit(key,void 0);return;case"json":this.beginJsonEdit(key,void 0);return;case"stringMap":this.writeValue(key,{}),this.host.pushPane(new DictPane(this.host,this.model,key));return}}beginTextEdit(key,current){let editor=new ValueEditor({onCommit:raw=>{let parsed=Number(raw.trim());if(!Number.isFinite(parsed))return this.error=`${key} must be a number.`,this.host.refresh();this.error=void 0,this.mode={type:"list"},this.writeValue(key,parsed)},onCancel:()=>{this.mode={type:"list"},this.error=void 0,this.host.refresh()}});current!==void 0&&editor.beginTweak(String(current)),editor.focused=this.focused,this.mode={type:"editValue",key,editor},this.host.refresh()}beginJsonEdit(key,current){let editor=new ValueEditor({onCommit:raw=>{let text2=raw.trim();if(!text2){this.mode={type:"list"},this.writeValue(key,DELETE);return}let shapeError=validateJsonCompatValue(key,text2);if(shapeError)return this.error=shapeError,this.host.refresh();this.error=void 0,this.mode={type:"list"},this.writeValue(key,JSON.parse(text2))},onCancel:()=>{this.mode={type:"list"},this.error=void 0,this.host.refresh()}});current!==void 0&&editor.beginTweak(JSON.stringify(current)),editor.focused=this.focused,this.mode={type:"editValue",key,editor},this.host.refresh()}parseChosen(option){return option==="true"?!0:option==="false"?!1:option}writeValue(key,value){this.model.setField(["compat",key],value)}fail(message){this.error=message,this.host.refresh()}setFocused(focused){this.focused=focused,this.mode.type==="editValue"&&(this.mode.editor.focused=focused)}isEditing(){return this.mode.type==="editValue"}hints(){return this.mode.type==="editValue"?[keyHint("tui.input.submit","save"),keyHint("tui.select.cancel","cancel")].join(" "):this.mode.type==="chooseValue"?[rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm","set"),keyHint("tui.select.cancel","cancel")].join(" "):[keyHint("tui.select.confirm","edit"),keyHint("app.list.toggle","toggle"),keyHint("app.provider.removeEntry","remove"),keyHint("tui.select.cancel","back")].join(" ")}},CompatKeyPickerPane=class{constructor(host,api,taken,onPick){this.crumb="compat \xB7 new entry",this.query="",this.index=0,this.focused=!1,this.host=host,this.api=api,this.taken=taken,this.onPick=onPick,this.editor=new ValueEditor({onCommit:()=>this.pickCurrent(),onCancel:()=>this.host.popPane()})}candidates(){let available=compatFieldsForApi(this.api).filter(field5=>!this.taken.has(field5.key)),query=this.query.trim();return query?fuzzyFilter(available,query,field5=>`${field5.key} ${field5.note??""}`):available}render(width){let theme2=this.host.theme,lines=[this.editor.renderLine(width)],candidates=this.candidates();candidates.length===0&&lines.push(renderInfoLine(theme2,"No remaining known fields.",width));for(let[rowIndex,field5]of candidates.entries())lines.push(renderPlainLine(theme2,field5.key,{active:rowIndex===this.index,paneFocused:this.focused,note:field5.note?`\xB7 ${field5.kind} \u2014 ${truncate3(field5.note,30)}`:`\xB7 ${field5.kind}`,width}));return lines}scrollWindow(){return{top:1,cursor:1+this.index}}pickCurrent(){let field5=this.candidates()[this.index];field5&&(this.host.popPane(),this.onPick(field5.key))}handleInput(data){let kb=this.host.keybindings;if(kb.matches(data,"tui.select.up")){let count=this.candidates().length;count>0&&(this.index=this.index===0?count-1:this.index-1),this.host.refresh();return}if(kb.matches(data,"tui.select.down")){let count=this.candidates().length;count>0&&(this.index=(this.index+1)%count),this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"tui.select.confirm")){this.pickCurrent();return}let before=this.query;this.editor.handleInput(data),this.query=this.editor.value,this.query!==before&&(this.index=0),this.host.refresh()}setFocused(focused){this.focused=focused,this.editor.focused=focused}isEditing(){return!0}hints(){return[rawKeyHint("type","filter"),rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm","choose"),keyHint("tui.select.cancel","back")].join(" ")}};function baseUrlHint(api){switch(api){case"openai-responses":case"openai-completions":case"openai-codex-responses":return"baseUrl includes the version path, e.g. https://api.openai.com/v1";case"anthropic-messages":return"baseUrl is the bare origin \u2014 /v1/messages is added automatically";case"mistral-conversations":return"baseUrl is the bare origin \u2014 /v1 is added automatically";case"google-generative-ai":return"baseUrl includes the version path, e.g. https://generativelanguage.googleapis.com/v1beta";default:return}}function validateBaseUrlValue(value){let url;try{url=new URL(value)}catch{return"baseUrl must be a valid URL."}if(url.protocol!=="http:"&&url.protocol!=="https:")return`Unsupported protocol: ${url.protocol}`;if(url.username||url.password||url.hash)return"baseUrl must not contain credentials or a fragment."}var ApiAuthPane=class{constructor(host,registry){this.rows=["baseUrl","apiKey","apiType"],this.index=0,this.focused=!1,this.host=host,this.edit=new InlineEdit(()=>host.refresh()),this.registry=registry}provider(){return this.host.store.getProvider(this.host.providerId)}scrollWindow(){return{cursor:this.index,bottom:this.bottomNoteCount()}}bottomNoteCount(){let status=this.registry.getProviderAuthStatus(this.host.providerId),hint=baseUrlHint(this.provider()?.api);return(this.edit.error?1:0)+(status.configured?1:0)+1+(hint?1:0)}render(width){let theme2=this.host.theme,provider=this.provider(),lines=[];for(let[rowIndex,row]of this.rows.entries()){let active=rowIndex===this.index,value=provider?.[row==="apiType"?"api":row];lines.push(renderKeyValueLine(theme2,{keyLabel:row==="apiType"?"API Type":row,valueText:value?row==="apiKey"?maskApiKey(value):value:"not set",unset:!value,active,paneFocused:this.focused,editing:row==="apiType"?void 0:this.edit.editor(row),width}))}this.edit.error&&lines.push(theme2.fg("error",truncate3(this.edit.error,Math.max(10,width-2))));let status=this.registry.getProviderAuthStatus(this.host.providerId);status.configured&&status.source==="stored"?lines.push(renderInfoLine(theme2,"A stored credential (auth.json) takes precedence over the apiKey here.",width)):status.configured&&status.source==="environment"&&lines.push(renderInfoLine(theme2,`An environment variable (${status.label??"env"}) currently provides the key.`,width)),lines.push(renderInfoLine(theme2,"Values are stored raw; $VAR / !command references resolve at request time.",width));let hint=baseUrlHint(provider?.api);return hint&&lines.push(renderInfoLine(theme2,hint,width)),lines}handleInput(data){let kb=this.host.keybindings;if(this.edit.handleInput(data,kb))return;let next=moveSelection(kb,data,this.index,this.rows.length);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"tui.select.confirm")){this.rows[this.index]==="apiType"?this.host.pushPane(createProviderApiPane(this.host)):this.beginEdit("tweak");return}if(isPrintableInput(data)){if(this.rows[this.index]==="apiType")return;this.beginEdit("overwrite",data);return}}beginEdit(mode,firstData){let row=this.rows[this.index];row!=="apiType"&&this.edit.begin(row,this.provider()?.[row]??"",mode,this.focused,value=>this.commit(row,value),firstData)}commit(row,raw){let value=raw.trim();if(row==="baseUrl"&&value){let invalid2=validateBaseUrlValue(value);if(invalid2)return invalid2}if(row==="baseUrl"&&!value){let builtin=builtinDefaults(this.host.providerId).baseUrl!==void 0,modelsCovered=this.host.store.getModels(this.host.providerId).every(model=>model.baseUrl!==void 0);if(!builtin&&!modelsCovered&&this.host.store.getModels(this.host.providerId).length>0)return"baseUrl cannot be removed while models rely on it."}this.host.edits.setProviderField([row],value===""?DELETE:value)}setFocused(focused){this.focused=focused,this.edit.setFocused(focused)}isEditing(){return this.edit.editing}hints(){return this.edit.editing?[keyHint("tui.input.submit","save"),keyHint("tui.select.cancel","cancel")].join(" "):[rawKeyHint("type","overwrite"),keyHint("tui.select.confirm","edit / open"),keyHint("tui.select.cancel","back")].join(" ")}};function createProviderApiPane(host){let current=()=>host.store.getProvider(host.providerId)?.api;return new ChoicePane(host,"API Type",{current,choices:()=>{let fallback=builtinDefaults(host.providerId).api,label=fallback?`not set (built-in default: ${fallback})`:"not set (models define their own)",values=[void 0,...API_TYPES],value=current();return value&&!values.includes(value)&&values.push(value),values.map(value2=>({value:value2,label:value2??label,dim:value2===void 0}))},choose:api=>{if(api===void 0){let uncovered=host.store.getModels(host.providerId).filter(model=>!model.api&&!builtinDefaults(host.providerId,model.id).api);if(uncovered.length)return uncovered.length===1?`Model "${uncovered[0].id}" resolves its API from here \u2014 give it a model-level API first.`:`${uncovered.length} ${plural(uncovered.length,"model")} resolve their API from here \u2014 give them model-level APIs first.`}host.edits.setProviderField(["api"],api??DELETE)}})}var REASONING_OPTIONS=[{label:"true",value:!0},{label:"false",value:!1},{label:"default (false)",value:void 0}];function createReasoningPane(host,model){return new ChoicePane(host,"reasoning",{current:()=>model.read().reasoning,choices:()=>REASONING_OPTIONS.map(option=>({...option,dim:option.value===void 0})),choose:value=>{model.setField(["reasoning"],value===void 0?DELETE:value)}})}var InputTypesPane=class{constructor(host,model){this.crumb="input",this.index=0,this.focused=!1,this.host=host,this.model=model}selected(){return new Set(this.model.read().input??["text"])}render(width){let theme2=this.host.theme,selected=this.selected(),lines=INPUT_TYPES.map((type,rowIndex)=>renderPlainLine(theme2,type,{checked:selected.has(type),active:rowIndex===this.index,paneFocused:this.focused,width}));return this.model.read().input===void 0&&lines.push(renderInfoLine(theme2,"Not set \u2014 the runtime default is [text].",width)),this.error&&lines.push(theme2.fg("error",truncate3(this.error,Math.max(10,width-2)))),lines}handleInput(data){let kb=this.host.keybindings,next=moveSelection(kb,data,this.index,INPUT_TYPES.length);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"app.list.toggle")){let type=INPUT_TYPES[this.index],selected=this.selected();if(selected.has(type)){if(selected.size===1){this.error="At least one input type must stay selected.",this.host.refresh();return}selected.delete(type)}else selected.add(type);this.error=void 0;let next2=INPUT_TYPES.filter(entry=>selected.has(entry));this.model.setField(["input"],[...next2]);return}if(kb.matches(data,"tui.select.confirm")||kb.matches(data,"tui.select.cancel")){this.host.popPane();return}}setFocused(focused){this.focused=focused}hints(){return[keyHint("app.list.toggle","toggle"),keyHint("tui.select.confirm","done"),keyHint("tui.select.cancel","back")].join(" ")}},COST_RATES=["input","output","cacheRead","cacheWrite"],CostPane=class{constructor(host,model){this.crumb="cost",this.index=0,this.focused=!1,this.host=host,this.edit=new InlineEdit(()=>host.refresh()),this.model=model}cost(){let cost=this.model.read().cost;if(cost)return{input:cost.input,output:cost.output,cacheRead:cost.cacheRead,cacheWrite:cost.cacheWrite}}render(width){let theme2=this.host.theme,cost=this.cost(),lines=[];for(let[rowIndex,rate]of COST_RATES.entries()){let value=cost?.[rate];lines.push(renderKeyValueLine(theme2,{keyLabel:rate,valueText:value===void 0?"0 (default)":`$${value} / M tokens`,unset:value===void 0,active:rowIndex===this.index,paneFocused:this.focused,editing:this.edit.editor(rate),width}))}let tiers=this.model.read().cost?.tiers;return tiers&&tiers.length>0&&lines.push(renderInfoLine(theme2,`tiers: ${tiers.length} (read-only; kept as-is)`,width)),this.edit.error&&lines.push(theme2.fg("error",truncate3(this.edit.error,Math.max(10,width-2)))),lines}handleInput(data){let kb=this.host.keybindings;if(this.edit.handleInput(data,kb))return;let next=moveSelection(kb,data,this.index,COST_RATES.length);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"tui.select.confirm")){this.beginEdit("tweak");return}if(isPrintableInput(data)){this.beginEdit("overwrite",data);return}}beginEdit(mode,firstData){let rate=COST_RATES[this.index],current=this.cost()?.[rate];this.edit.begin(rate,current===void 0?"":String(current),mode,this.focused,value=>this.commit(rate,value),firstData)}commit(rate,raw){let value=raw.trim(),parsed=value===""?0:Number(value);if(!Number.isFinite(parsed)||parsed<0)return"cost rates must be finite non-negative numbers.";this.model.read().cost?this.model.setField(["cost",rate],parsed):this.model.setField(["cost"],{input:0,output:0,cacheRead:0,cacheWrite:0,[rate]:parsed})}setFocused(focused){this.focused=focused,this.edit.setFocused(focused)}isEditing(){return this.edit.editing}hints(){return this.edit.editing?[keyHint("tui.input.submit","save"),keyHint("tui.select.cancel","cancel")].join(" "):[rawKeyHint("type","overwrite"),keyHint("tui.select.confirm","edit"),keyHint("tui.select.cancel","back")].join(" ")}},ModelSpecificApiPane=class{constructor(host,model){this.crumb="Model-Specific API",this.rows=["baseUrl","apiType"],this.index=0,this.focused=!1,this.host=host,this.edit=new InlineEdit(()=>host.refresh()),this.model=model}inherited(key){let provider=this.host.store.getProvider(this.host.providerId),providerValue=key==="api"?provider?.api:provider?.baseUrl;if(providerValue)return{value:providerValue,via:"provider"};let current=this.model.read(),effective=key==="api"?this.host.effectiveApi(current):this.host.effectiveBaseUrl(current);return effective?{value:effective,via:"built-in"}:void 0}render(width){let theme2=this.host.theme,current=this.model.read(),lines=[];for(let[rowIndex,row]of this.rows.entries()){let active=rowIndex===this.index,key=row==="apiType"?"api":row,override=current[key],inherited=override?void 0:this.inherited(key);lines.push(renderKeyValueLine(theme2,{keyLabel:row==="apiType"?"API Type":row,valueText:override??inherited?.value??"not set",unset:!override,note:inherited?`\xB7 ${inherited.via}`:void 0,active,paneFocused:this.focused,editing:row==="baseUrl"?this.edit.editor(row):void 0,width}))}this.edit.error&&lines.push(theme2.fg("error",truncate3(this.edit.error,Math.max(10,width-2))));let hint=baseUrlHint(this.host.effectiveApi(current));return hint&&lines.push(renderInfoLine(theme2,hint,width)),lines}handleInput(data){let kb=this.host.keybindings;if(this.edit.handleInput(data,kb))return;let next=moveSelection(kb,data,this.index,this.rows.length);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}if(kb.matches(data,"tui.select.confirm")){this.rows[this.index]==="apiType"?this.host.pushPane(createModelApiPane(this.host,this.model)):this.beginEdit("tweak");return}if(isPrintableInput(data)){if(this.rows[this.index]==="apiType")return;this.beginEdit("overwrite",data);return}}beginEdit(mode,firstData){let base=this.model.read().baseUrl??this.inherited("baseUrl")?.value??"";this.edit.begin("baseUrl",base,mode,this.focused,value=>this.commit(value),firstData)}commit(raw){let value=raw.trim();if(value){let invalid2=validateBaseUrlValue(value);if(invalid2)return invalid2}this.model.setField(["baseUrl"],value===""?DELETE:value)}setFocused(focused){this.focused=focused,this.edit.setFocused(focused)}isEditing(){return this.edit.editing}hints(){return this.edit.editing?[keyHint("tui.input.submit","save"),keyHint("tui.select.cancel","cancel")].join(" "):[rawKeyHint("type","overwrite"),keyHint("tui.select.confirm","edit / open"),keyHint("tui.select.cancel","back")].join(" ")}};function createModelApiPane(host,model){let fallback=()=>{let provider=host.store.getProvider(host.providerId);return provider?.api??builtinDefaults(host.providerId,model.read().id,provider?.api).api};return new ChoicePane(host,"API Type",{current:()=>model.read().api,choices:()=>{let providerApi=host.store.getProvider(host.providerId)?.api,inherited=fallback(),label=providerApi?`provider: ${providerApi}`:inherited?`built-in: ${inherited}`:"no provider or built-in API",values=[void 0,...API_TYPES],current=model.read().api;return current&&!values.includes(current)&&values.push(current),values.map(value=>({value,label:value??label,dim:value===void 0}))},choose:value=>{if(value===void 0&&!fallback())return"Nothing to inherit \u2014 pick an API.";model.setField(["api"],value??DELETE)}})}var ThinkingMapPane=class{constructor(host,model){this.crumb="thinkingLevelMap",this.mode={type:"levels"},this.index=0,this.focused=!1,this.host=host,this.model=model}map(){return this.model.read().thinkingLevelMap??{}}render(width){let theme2=this.host.theme,lines=[];if(this.model.read().reasoning!==!0&&lines.push(renderInfoLine(theme2,"reasoning is not true \u2014 the map is stored but currently has no effect.",width)),this.mode.type==="levels")for(let[rowIndex,level]of THINKING_LEVELS4.entries()){let value=this.map()[level],status=value===void 0?"default":value===null?"null (hidden)":value;lines.push(renderKeyValueLine(theme2,{keyLabel:level,valueText:status,unset:value===void 0,active:rowIndex===this.index,paneFocused:this.focused,width}))}else if(this.mode.type==="choice"){lines.push(renderInfoLine(theme2,`${this.mode.level} \xB7 mapping`,width));for(let[choiceIndex,label]of["String target (provider effort)","Hidden (null)","Default (remove key)"].entries())lines.push(renderPlainLine(theme2,label,{active:choiceIndex===this.mode.index,paneFocused:this.focused,width}))}else lines.push(renderInfoLine(theme2,`${this.mode.level} \xB7 non-empty provider effort`,width)),lines.push(renderKeyValueLine(theme2,{keyLabel:this.mode.level,active:!0,paneFocused:this.focused,editing:this.editor,width}));return this.error&&lines.push(theme2.fg("error",truncate3(this.error,Math.max(10,width-2)))),lines}handleInput(data){let kb=this.host.keybindings;if(this.mode.type==="target"){if(kb.matches(data,"tui.select.up")||kb.matches(data,"tui.select.down"))return;this.editor?.handleInput(data),this.host.refresh();return}if(this.mode.type==="choice"){if(kb.matches(data,"tui.select.up")){this.mode={...this.mode,index:this.mode.index===0?2:this.mode.index-1},this.host.refresh();return}if(kb.matches(data,"tui.select.down")){this.mode={...this.mode,index:(this.mode.index+1)%3},this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.mode={type:"levels"},this.host.refresh();return}if(kb.matches(data,"tui.select.confirm")){let{level,index:index3}=this.mode;if(index3===0){let editor=new ValueEditor({onCommit:value=>{let target=value.trim();if(!target)return this.error="A string target must be non-empty; use Hidden for null.",this.host.refresh();this.error=void 0,this.mode={type:"levels"},this.editor=void 0,this.model.setField(["thinkingLevelMap",level],target)},onCancel:()=>{this.editor=void 0,this.mode={type:"levels"},this.host.refresh()}});this.editor=editor,editor.focused=this.focused;let existing=this.map()[level];typeof existing=="string"&&editor.beginTweak(existing),this.mode={type:"target",level},this.host.refresh();return}this.mode={type:"levels"},this.model.setField(["thinkingLevelMap",level],index3===1?null:DELETE);return}return}let next=moveSelection(kb,data,this.index,THINKING_LEVELS4.length);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.confirm")){this.mode={type:"choice",level:THINKING_LEVELS4[this.index],index:0},this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){this.host.popPane();return}}setFocused(focused){this.focused=focused,this.editor&&(this.editor.focused=focused&&this.mode.type==="target")}isEditing(){return this.mode.type==="target"}hints(){return this.mode.type==="target"?[keyHint("tui.input.submit","save"),keyHint("tui.select.cancel","back")].join(" "):[rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm",this.mode.type==="choice"?"set":"edit"),keyHint("tui.select.cancel","back")].join(" ")}};var DEFAULT_CONTEXT_WINDOW2=128e3,DEFAULT_MAX_TOKENS2=16384,ModelFieldsPane=class{constructor(host,model){this.index=0,this.focused=!1,this.renaming=!1,this.disposed=!1,this.host=host,this.model=model;let rows=[{kind:"text",key:"id"},{kind:"text",key:"name"},{kind:"reasoning"},{kind:"subpage",key:"thinkingLevelMap"},{kind:"subpage",key:"input"},{kind:"subpage",key:"cost"},{kind:"number",key:"contextWindow"},{kind:"number",key:"maxTokens"},{kind:"subpage",key:"compat"}];model.isDraft?rows.push({kind:"modelApi"}):rows.push({kind:"builtin"},{kind:"modelApi"},{kind:"deleteModel"}),this.rows=rows}startEditingId(){this.index=0,this.beginEdit("overwrite")}draftEmpty(){return this.model.isDraft&&Object.keys(this.model.read()).length===0}render(width){let theme2=this.host.theme,current=this.model.read(),lines=[],api=this.host.effectiveApi(current);lines.push(renderInfoLine(theme2,api?`api: ${api}${current.api?" (model)":""}`:"api: none resolved \u2014 see Model-Specific API below",width));for(let[rowIndex,row]of this.rows.entries()){let active=rowIndex===this.index;lines.push(this.renderRow(row,current,active,width))}return this.error&&lines.push(theme2.fg("error",truncate3(this.error,Math.max(10,width-2)))),this.renaming&&lines.push(renderInfoLine(theme2,"Saving model id\u2026",width)),lines}scrollWindow(){return{top:1,bottom:(this.error?1:0)+(this.renaming?1:0),cursor:1+this.index}}renderRow(row,current,active,width){let theme2=this.host.theme,editing=this.editingRow===row?this.editing:void 0;switch(row.kind){case"text":{let value=current[row.key],unsetText=row.key==="id"?"required":"falls back to id";return renderKeyValueLine(theme2,{keyLabel:row.key,valueText:value??`not set (${unsetText})`,unset:!value,active,paneFocused:this.focused,editing,width})}case"reasoning":{let value=current.reasoning;return renderKeyValueLine(theme2,{keyLabel:"reasoning",valueText:value===void 0?"false (default)":String(value),unset:value===void 0,active,paneFocused:this.focused,width})}case"subpage":{let summary=this.subpageSummary(row.key,current);return renderKeyValueLine(theme2,{keyLabel:row.key,valueText:summary.text,unset:summary.unset,active,paneFocused:this.focused,width})}case"number":{let value=current[row.key],fallback=row.key==="contextWindow"?DEFAULT_CONTEXT_WINDOW2:DEFAULT_MAX_TOKENS2;return renderKeyValueLine(theme2,{keyLabel:row.key,valueText:value===void 0?`${fallback} (default)`:String(value),unset:value===void 0,active,paneFocused:this.focused,editing,width})}case"builtin":{let id=current.id,count=id?matchBuiltinModels(id,this.host.effectiveApi(current)).length:0;return renderKeyValueLine(theme2,{valueText:"Use Built-in Data",active,paneFocused:this.focused,note:id?`\xB7 ${count} ${plural(count,"candidate")}`:"\xB7 set id first",width})}case"modelApi":return renderKeyValueLine(theme2,{valueText:"Model-Specific API",active,paneFocused:this.focused,note:`\xB7 ${this.modelApiSummary(current)}`,width});case"deleteModel":return renderKeyValueLine(theme2,{valueText:"Delete Model",active,paneFocused:this.focused,width})}}modelApiSummary(current){let overrides=[current.baseUrl?"baseUrl":"",current.api?"API Type":""].filter(Boolean);if(overrides.length>0)return overrides.join(" + ");let provider=this.host.store.getProvider(this.host.providerId);return provider?.api||provider?.baseUrl?"provider defaults":this.host.effectiveApi(current)||this.host.effectiveBaseUrl(current)?"built-in defaults":"not set"}subpageSummary(key,current){switch(key){case"thinkingLevelMap":{let map=current.thinkingLevelMap,count=map?Object.keys(map).length:0;return count>0?{text:`${count} ${plural(count,"mapping")}`,unset:!1}:{text:"default",unset:!0}}case"input":return current.input?{text:`[${current.input.join(", ")}]`,unset:!1}:{text:"[text] (default)",unset:!0};case"cost":{let cost=current.cost;return cost?{text:`$${cost.input} / $${cost.output} in/out`,unset:!1}:{text:"all 0 (default)",unset:!0}}case"compat":{let compat=current.compat,count=compat?Object.keys(compat).length:0;if(count>0)return{text:`${count} ${count===1?"entry":"entries"}`,unset:!1};let inherited=this.host.store.getProvider(this.host.providerId)?.compat,inheritedCount=inherited?Object.keys(inherited).length:0;return inheritedCount>0?{text:`${inheritedCount} from provider`,unset:!0}:{text:"none",unset:!0}}}}handleInput(data){if(this.renaming||this.disposed)return;let kb=this.host.keybindings;if(this.editing){if(kb.matches(data,"tui.select.up")||kb.matches(data,"tui.select.down"))return;this.editing.handleInput(data),this.host.refresh();return}let next=moveSelection(kb,data,this.index,this.rows.length);if(next!==void 0){this.index=next,this.host.refresh();return}if(kb.matches(data,"tui.select.cancel")){if(!this.model.isDraft){this.host.popPane();return}if(this.draftEmpty()){this.host.discardModelDraft();return}let label=this.model.read().name??this.model.read().id??"New Model";this.host.confirm(`Discard the new model "${label}"? Its fields are not saved.`,"Discard Model",()=>this.host.discardModelDraft());return}if(kb.matches(data,"app.list.toggle")){this.toggleRow();return}if(kb.matches(data,"tui.select.confirm")){this.enterRow();return}if(isPrintableInput(data)){this.overwriteRow(data);return}}toggleRow(){if(this.rows[this.index].kind!=="reasoning")return;let current=this.model.read().reasoning;this.model.setField(["reasoning"],current!==!0)}enterRow(){let row=this.rows[this.index];switch(row.kind){case"text":case"number":this.beginEdit("tweak");return;case"reasoning":this.host.pushPane(createReasoningPane(this.host,this.model));return;case"subpage":this.pushSubpage(row.key);return;case"modelApi":this.host.pushPane(new ModelSpecificApiPane(this.host,this.model));return;case"builtin":{if(!this.model.read().id){this.host.notify("Set the model id first.","warning");return}this.host.pushPane(new BuiltinCandidatesPane(this.host,this.model));return}case"deleteModel":{let id=this.model.read().id;if(!id)return;if(this.host.isCurrentModel(id)){this.host.notify("The current model cannot be deleted; switch models with /model first.","error");return}this.host.confirm(`Delete model "${id}" from ${this.host.providerId}?`,"Delete Model",()=>{this.host.edits.removeModel(id),this.host.onModelRemoved(id)});return}}}overwriteRow(data){let row=this.rows[this.index];if(row.kind==="text"||row.kind==="number"){this.beginEdit("overwrite",data);return}}beginEdit(mode,firstData){let row=this.rows[this.index];if(row.kind!=="text"&&row.kind!=="number")return;let current=this.model.read()[row.key],editor=new ValueEditor({onCommit:value=>this.commitText(row,value),onCancel:()=>{if(this.editing=void 0,this.editingRow=void 0,this.error=void 0,this.draftEmpty()){this.host.discardModelDraft();return}this.host.refresh()}});this.editing=editor,this.editingRow=row,editor.focused=this.focused,mode==="overwrite"?editor.beginOverwrite(firstData):editor.beginTweak(current===void 0?"":String(current)),this.host.refresh()}commitText(row,raw){let value=raw.trim(),finish=error=>{if(this.error=error,error){this.host.refresh();return}this.editing=void 0,this.editingRow=void 0,this.host.refresh()};if(row.key==="id"){if(!value){finish("id is required and cannot be empty.");return}if(this.model.isDraft){this.model.setField(["id"],value),finish(this.host.commitModelDraft());return}let current=this.model.read().id;if(!current){finish("Missing current id.");return}if(value===current){finish();return}if(this.host.isCurrentModel(current)){finish("The current model's id cannot be renamed; switch models with /model first.");return}if(this.host.store.getModel(this.host.providerId,value)){finish(`Model "${value}" already exists.`);return}this.renaming=!0,this.host.refresh(),this.model.rename(value).then(error=>{this.renaming=!1,this.disposed||finish(error)},error=>{this.renaming=!1,this.disposed||finish(error instanceof Error?error.message:String(error))});return}if(row.key==="name"){this.model.setField(["name"],value===""?DELETE:value),finish();return}if(value===""){this.model.setField([row.key],DELETE),finish();return}let parsed=Number(value);if(!Number.isSafeInteger(parsed)||parsed<=0){finish(`${row.key} must be a positive integer.`);return}this.model.setField([row.key],parsed),finish()}pushSubpage(key){switch(key){case"thinkingLevelMap":this.host.pushPane(new ThinkingMapPane(this.host,this.model));return;case"input":this.host.pushPane(new InputTypesPane(this.host,this.model));return;case"cost":this.host.pushPane(new CostPane(this.host,this.model));return;case"compat":this.host.pushPane(new CompatPane(this.host,this.model));return}}setFocused(focused){this.focused=focused,this.editing&&(this.editing.focused=focused)}isEditing(){return this.editing!==void 0||this.renaming}dispose(){this.disposed=!0}hints(){return this.editing?[keyHint("tui.input.submit","save"),keyHint("tui.select.cancel","cancel")].join(" "):[rawKeyHint("type","overwrite"),keyHint("tui.select.confirm","edit / open"),keyHint("app.list.toggle","toggle"),keyHint("tui.select.cancel",this.model.isDraft?"discard":"back")].join(" ")}};var LEFT_WIDTH_MIN=16,LEFT_WIDTH_MAX=40,BODY_ROWS=14,MIN_WIDTH=56;function padTo(line,width){let missing=width-visibleWidth(line);return missing>0?line+" ".repeat(missing):line}function leftItemKey(item){return item?item.kind==="model"?`model:${item.modelId}`:item.kind:""}var ProviderEditorScreen=class{constructor(tui,theme2,keybindings,done,options){this.leftItems=[],this.leftIndex=0,this.focusPane="left",this.stack=[],this.disposed=!1,this._focused=!1,this.tui=tui,this.theme=theme2,this.keybindings=keybindings,this.done=done,this.options=options,this.edits=new ProviderEdits(options.store,options.providerId,options.refresher,()=>this.refresh()),this.host=this.createHost(),this.rebuildLeftItems(),this.resetRightStack()}get focused(){return this._focused}set focused(value){this._focused=value,this.topPane()?.setFocused(value&&this.focusPane==="right")}invalidate(){this.cache=void 0}dispose(){if(!this.disposed){this.disposed=!0;for(let pane of this.stack)pane.dispose?.();this.stack=[],hasProviderSettings(this.options.store.getProvider(this.options.providerId))||this.options.store.discardProviderDraft(this.options.providerId)}}render(width){if(this.cache&&this.cache.width===width)return this.cache.lines;let lines=this.renderFrame(width);return this.cache={width,lines},lines}handleInput(data){if(this.focusPane==="right"){let pane=this.topPane();if(pane&&!pane.isEditing?.()&&this.keybindings.matches(data,"app.provider.switchPaneLeft")){pane.setFocused(!1),this.focusPane="left",this.refresh();return}pane?.handleInput(data);return}let kb=this.keybindings;if(kb.matches(data,"tui.select.up")){this.moveLeft(-1);return}if(kb.matches(data,"tui.select.down")){this.moveLeft(1);return}if(kb.matches(data,"app.provider.switchPaneRight")){this.activateLeftItem("inspect");return}if(kb.matches(data,"tui.select.confirm")){this.activateLeftItem("activate");return}kb.matches(data,"tui.select.cancel")&&this.done("back")}syncFromStore(){if(this.disposed||this.edits.renaming)return;let selected=this.leftItems[this.leftIndex],selectedKey=leftItemKey(selected);this.rebuildLeftItems();let nextIndex=this.leftItems.findIndex(item=>leftItemKey(item)===selectedKey);this.leftIndex=nextIndex>=0?nextIndex:Math.min(this.leftIndex,this.selectableIndex(0)),nextIndex<0&&selected?.kind==="model"&&this.resetRightStack(),this.refresh()}rebuildLeftItems(){let items=[{kind:"apiAuth"},{kind:"fetch"},{kind:"separator"}];for(let model of this.options.store.getModels(this.options.providerId))items.push({kind:"model",modelId:model.id});this.draft&&items.push({kind:"draft"}),items.push({kind:"separator"},{kind:"addModel"},{kind:"deleteProvider"}),this.leftItems=items}selectableIndex(start){let index3=this.leftItems.findIndex((item,i)=>i>=start&&item.kind!=="separator");return index3>=0?index3:0}moveLeft(delta){let selectable=this.leftItems.map((item,index3)=>({item,index:index3})).filter(entry=>entry.item.kind!=="separator");if(selectable.length===0)return;let position=selectable.findIndex(entry=>entry.index===this.leftIndex),next=selectable[(position+delta+selectable.length)%selectable.length];next.index!==this.leftIndex&&(this.leftIndex=next.index,this.resetRightStack(),this.refresh())}activateLeftItem(via){let item=this.leftItems[this.leftIndex];if(item)switch(item.kind){case"apiAuth":case"model":case"draft":this.focusPane="right",this.topPane()?.setFocused(this._focused),this.refresh();return;case"fetch":if(this.focusPane="right",via==="activate"){let pane=this.topPane();pane instanceof FetchModelsPane&&pane.start()}this.topPane()?.setFocused(this._focused),this.refresh();return;case"addModel":{if(via==="inspect"){this.focusPane="right",this.topPane()?.setFocused(this._focused),this.refresh();return}this.draft||(this.draft=this.edits.draft(),this.rebuildLeftItems());let draftIndex=this.leftItems.findIndex(entry=>entry.kind==="draft");draftIndex>=0&&(this.leftIndex=draftIndex),this.resetRightStack(),this.focusPane="right";let pane=this.topPane();pane?.setFocused(this._focused),pane instanceof ModelFieldsPane&&!this.draft.read().id&&pane.startEditingId(),this.refresh();return}case"deleteProvider":{if(via==="inspect"){this.focusPane="right",this.topPane()?.setFocused(this._focused),this.refresh();return}if(this.host.isCurrentProvider()){this.host.notify("The current model's provider cannot be deleted; switch models with /model first.","error");return}let builtin=isBuiltinProviderId(this.options.providerId);this.host.confirm(`Delete provider "${this.options.providerId}" from models.json?`+(builtin?" The built-in catalog remains and its models may reappear.":"")+" Stored credentials in auth.json are kept.","Delete Provider",()=>{this.edits.removeProvider(),this.done("deleted")});return}default:return}}renderLeft(width){let theme2=this.theme,focused=this.focusPane==="left",rows=[],renderRow=index3=>{let item=this.leftItems[index3];return item.kind==="separator"?theme2.fg("borderMuted",` ${"\u2500".repeat(Math.max(1,width-4))}`):this.renderLeftItem(item,index3===this.leftIndex,focused,width)};if(this.leftItems.length<=BODY_ROWS)for(let index3=0;index3<this.leftItems.length;index3++)rows.push(renderRow(index3));else{let slots=BODY_ROWS-1,start=Math.max(0,Math.min(this.leftIndex-Math.floor(slots/2),this.leftItems.length-slots));for(let index3=start;index3<start+slots;index3++)rows.push(renderRow(index3));let selectable=this.leftItems.filter(item=>item.kind!=="separator"),position=selectable.indexOf(this.leftItems[this.leftIndex]);rows.push(theme2.fg("dim",` (${position+1}/${selectable.length})`))}for(;rows.length<BODY_ROWS;)rows.push("");return rows}leftItemContent(item){let store=this.options.store,text2,note;switch(item.kind){case"apiAuth":text2="API Auth";break;case"fetch":text2="Fetch Models",note=this.fetchStatus;break;case"model":{let model=store.getModel(this.options.providerId,item.modelId);text2=model?modelDisplayName(model):item.modelId;break}case"draft":{text2=this.draft?.read().name??this.draft?.read().id??"New Model",note="\xB7 draft";break}case"addModel":text2="+ Add Model";break;case"deleteProvider":text2="Delete Provider";break;default:text2=""}let dim=item.kind==="draft"&&!this.draft?.read().name&&!this.draft?.read().id;return{text:text2,note,dim}}renderLeftItem(item,active,focused,width){let theme2=this.theme,lit=active&&focused,marker=lit?theme2.fg("accent",`${CURSOR2} `):" ",style=(text3,dim2=!1)=>theme2.fg(lit?"accent":dim2?"dim":"text",text3),{text:label,note,dim}=this.leftItemContent(item),text2=label;if(item.kind==="model"||item.kind==="draft"){let budget=Math.max(8,width-2-(note?visibleWidth(note)+1:0));text2=truncateMiddle2(text2,budget)}let noteText=note?theme2.fg("dim",` ${note}`):"";return truncateToWidth(marker+style(text2,dim)+noteText,width)}topPane(){return this.stack[this.stack.length-1]}pushPane(pane){this.topPane()?.setFocused(!1),this.focusPane="right",this.stack.push(pane),pane.setFocused(this._focused&&this.focusPane==="right"),this.refresh()}popPane(){if(this.stack.length<=1){this.topPane()?.setFocused(!1),this.focusPane="left",this.refresh();return}let pane=this.stack.pop();pane?.setFocused(!1),pane?.dispose?.(),this.topPane()?.setFocused(this._focused&&this.focusPane==="right"),this.refresh()}resetRightStack(){for(let pane of this.stack)pane.dispose?.();let item=this.leftItems[this.leftIndex];this.stack=[this.createBasePane(item)],this.topPane()?.setFocused(this._focused&&this.focusPane==="right")}createBasePane(item){switch(item?.kind){case"apiAuth":return new ApiAuthPane(this.host,this.options.registry);case"fetch":return new FetchModelsPane(this.host);case"model":return new ModelFieldsPane(this.host,this.persistedHandle(item.modelId));case"draft":return new ModelFieldsPane(this.host,this.draft);case"addModel":return new InfoPane(this.host,["Press Enter to create a model.","A draft is kept in memory until its id is set; Esc on the draft discards it."],()=>this.activateLeftItem("activate"));case"deleteProvider":return new InfoPane(this.host,["Press Enter to delete this provider from models.json."],()=>this.activateLeftItem("activate"));default:return new InfoPane(this.host,[])}}persistedHandle(modelId){return this.edits.model(modelId,(oldId,newId)=>{let selected=this.leftItems[this.leftIndex];selected?.kind==="model"&&selected.modelId===oldId&&(selected.modelId=newId),this.syncFromStore()})}createHost(){let store=this.options.store,providerId=this.options.providerId;return{tui:this.tui,theme:this.theme,keybindings:this.keybindings,store,edits:this.edits,providerId,pushPane:pane=>this.pushPane(pane),popPane:()=>this.popPane(),refresh:()=>this.refresh(),notify:(message,type)=>this.options.notify(message,type),effectiveApi:model=>effectiveModelSettings(providerId,store.getProvider(providerId),model).api,effectiveBaseUrl:model=>effectiveModelSettings(providerId,store.getProvider(providerId),model).baseUrl,commitModelDraft:()=>this.commitModelDraft(),discardModelDraft:()=>this.discardModelDraft(),isCurrentModel:modelId=>this.options.currentModel?.provider===providerId&&this.options.currentModel.id===modelId,isCurrentProvider:()=>this.options.currentModel?.provider===providerId,setFetchStatus:status=>{this.fetchStatus=status,this.refresh()},runFetch:signal=>fetchProviderModels(this.options,signal),importModels:async(models,signal)=>{let error=await importProviderModels({...this.options,edits:this.edits},models,signal);return this.disposed||this.syncFromStore(),error},confirm:(message,actionLabel,action)=>this.pushPane(new ConfirmPane(this.host,message,actionLabel,action)),onModelRemoved:()=>{for(this.rebuildLeftItems(),this.leftIndex=Math.min(this.leftIndex,this.leftItems.length-1);this.leftIndex>0&&this.leftItems[this.leftIndex]?.kind==="separator";)this.leftIndex--;this.leftItems[this.leftIndex]?.kind==="separator"&&(this.leftIndex=this.selectableIndex(0)),this.focusPane="left",this.resetRightStack(),this.refresh()}}}discardModelDraft(){if(!this.draft)return;this.draft=void 0,this.rebuildLeftItems();let addIndex=this.leftItems.findIndex(item=>item.kind==="addModel");this.leftIndex=addIndex>=0?addIndex:this.selectableIndex(0),this.focusPane="left",this.resetRightStack(),this.refresh()}commitModelDraft(){let draft=this.draft;if(!draft)return"No model draft.";let error=this.edits.commitDraft(draft);if(error)return error;let id=draft.read().id.trim();this.draft=void 0,this.rebuildLeftItems();let index3=this.leftItems.findIndex(item=>item.kind==="model"&&item.modelId===id);index3>=0&&(this.leftIndex=index3),this.resetRightStack(),this.refresh()}refresh(){this.invalidate(),this.tui.requestRender()}renderFrame(width){let theme2=this.theme,border=new DynamicBorder(text2=>theme2.fg("border",text2)).render(width)[0];if(width<MIN_WIDTH)return[border,truncateToWidth(theme2.fg("warning",` /provider needs at least ${MIN_WIDTH} columns`),width),border];let leftWidth=this.computeLeftWidth(width),rightWidth=width-leftWidth-3,separator=theme2.fg("border"," \u2502 "),title=this.renderTitle(width),crumb=truncateToWidth(this.theme.fg("muted",this.topPane()?.crumb??""),rightWidth),leftLines=this.renderLeft(leftWidth),pane=this.topPane(),paneLines=pane?windowLines(theme2,pane.render(rightWidth),BODY_ROWS-1,pane.scrollWindow?.()):[],rightLines=[crumb,...paneLines],body2=[];for(let row=0;row<BODY_ROWS;row++){let left=padTo(truncateToWidth(leftLines[row]??"",leftWidth),leftWidth),right=truncateToWidth(rightLines[row]??"",rightWidth);body2.push(left+separator+right)}let footerLines=this.renderFooter(width);return[border,title,border,...body2,border,...footerLines,border]}computeLeftWidth(width){let longest=12;for(let item of this.leftItems){if(item.kind==="separator")continue;let{text:text2,note}=this.leftItemContent(item),label=text2+(note?` ${note}`:"");longest=Math.max(longest,visibleWidth(label))}let fit=Math.max(LEFT_WIDTH_MIN,Math.min(LEFT_WIDTH_MAX,longest+2));return Math.min(fit,Math.max(LEFT_WIDTH_MIN,Math.floor(width*.45)))}renderTitle(width){let theme2=this.theme,title=` /provider \xB7 ${this.options.providerId}`;return isBuiltinProviderId(this.options.providerId)&&(title+=" \xB7 overlays built-in catalog"),truncateToWidth(theme2.fg("accent",theme2.bold(title)),width)}renderFooter(width){if(this.focusPane==="right"){let hints2=[this.topPane()?.hints()??"",keyHint("app.provider.switchPaneLeft","focus left")].filter(Boolean).join(" ");return[truncateToWidth(hints2,width)]}let hints=[rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm",this.leftActivateLabel()),keyHint("app.provider.switchPaneRight","focus right"),keyHint("tui.select.cancel","back")].join(" ");return[truncateToWidth(hints,width)]}leftActivateLabel(){switch(this.leftItems[this.leftIndex]?.kind){case"fetch":return"fetch";case"addModel":return"create";case"deleteProvider":return"delete";default:return"open"}}};function modelDisplayName(model){return model.name??model.id}var LIST_ROWS=12,ProviderListScreen=class{constructor(tui,theme2,keybindings,done,store){this.mode="list",this.query="",this.index=0,this.active=!1,this.tui=tui,this.theme=theme2,this.keybindings=keybindings,this.done=done,this.store=store,this.input=new ValueEditor({onCommit:()=>this.confirm(),onCancel:()=>this.cancel()})}get focused(){return this.active}set focused(value){this.active=value,this.input.focused=value}invalidate(){}filtered(){let ids=this.store.getProviderIds();return this.query.trim()?fuzzyFilter(ids,this.query,id=>id):ids}render(width){let theme2=this.theme,border=new DynamicBorder(text2=>theme2.fg("border",text2)).render(width)[0]??"",lines=[border,truncateToWidth(theme2.fg("accent",theme2.bold(" /provider \u2014 models.json providers")),width),border,renderKeyValueLine(theme2,{keyLabel:this.mode==="list"?"Search":"Provider id",active:!1,paneFocused:this.active,editing:this.input,width}),""],area=[];if(this.mode==="list"){let entries=this.filtered(),total=entries.length+1;this.index=Math.min(this.index,total-1);let rows=[];for(let row=0;row<total;row++){let id=entries[row-1],provider=id===void 0?void 0:this.store.getProvider(id),note=id===void 0?void 0:provider?[`${String(provider.models?.length??0)} ${plural(provider.models?.length??0,"model")}`,provider.api].filter(Boolean).join(" \xB7 "):"pending deletion";rows.push(renderPlainLine(theme2,row===0?"+ Add Provider":id,{active:row===this.index,paneFocused:this.active,note,width}))}entries.length===0&&rows.push(renderInfoLine(theme2,this.query?"No matching providers.":"No providers yet.",width)),area.push(...windowLines(theme2,rows,LIST_ROWS,{cursor:this.index}))}else this.error&&area.push(truncateToWidth(theme2.fg("error",this.error),width));for(;area.length<LIST_ROWS;)area.push("");let hints=this.mode==="newProvider"?[keyHint("tui.input.submit","create"),keyHint("tui.select.cancel","cancel")]:[rawKeyHint("type","filter"),rawKeyHint("\u2191\u2193","move"),keyHint("tui.select.confirm","open"),keyHint("tui.select.cancel","close")];return[...lines,...area,border,truncateToWidth(hints.join(" "),width),border]}handleInput(data){let kb=this.keybindings;if(kb.matches(data,"tui.select.cancel")){this.cancel();return}if(this.mode==="list"){let total=this.filtered().length+1;if(kb.matches(data,"tui.select.up"))this.index=(this.index+total-1)%total;else if(kb.matches(data,"tui.select.down"))this.index=(this.index+1)%total;else if(kb.matches(data,"tui.select.confirm")){this.confirm();return}else{let previous=this.query;this.input.handleInput(data),this.query=this.input.value,this.query!==previous&&(this.index=this.query&&this.filtered().length>0?1:0)}}else this.input.handleInput(data);this.tui.requestRender()}confirm(){if(this.mode==="newProvider"){let id=this.input.value.trim();if(!id)this.error="Provider id must be non-empty.";else if(this.store.getProviderIds().includes(id))this.error="This provider id already exists.";else{this.store.ensureProviderView(id),this.done({kind:"open",providerId:id});return}}else if(this.index===0)this.mode="newProvider",this.error=void 0,this.input.reset(this.query);else{let id=this.filtered()[this.index-1];id&&this.done({kind:"open",providerId:id})}this.tui.requestRender()}cancel(){if(this.mode==="list"){this.done({kind:"close"});return}this.mode="list",this.error=void 0,this.input.reset(this.query),this.tui.requestRender()}};var ProviderTuiSession=class extends Container{constructor(tui){super(),this.controller=new AbortController,this.active=!1,this.tui=tui}get signal(){return this.controller.signal}get focused(){return this.active}set focused(value){this.active=value,this.screen&&isFocusable(this.screen)&&(this.screen.focused=value)}setScreen(screen){if(this.signal.aborted){screen.dispose?.();return}this.disposeScreen(),this.screen=screen,this.clear(),this.addChild(screen),this.tui.setFocus(this),this.tui.requestRender()}handleInput(data){this.signal.aborted||this.screen?.handleInput?.(data)}dispose(){this.signal.aborted||(this.controller.abort(),this.disposeScreen(),this.clear())}disposeScreen(){let previous=this.screen;this.screen=void 0,previous&&isFocusable(previous)&&(previous.focused=!1),previous?.dispose?.()}};var SavingScreen=class extends Container{constructor(theme2,keybindings,onCancel){super(),this.keybindings=keybindings,this.onCancel=onCancel,this.addChild(new DynamicBorder(text2=>theme2.fg("border",text2))),this.addChild(new Text(theme2.fg("muted","Saving provider changes and updating models\u2026"),1,1)),this.addChild(new Text(keyHint("tui.select.cancel","return to providers"),1,0)),this.addChild(new DynamicBorder(text2=>theme2.fg("border",text2)))}handleInput(data){this.keybindings.matches(data,"tui.select.cancel")&&this.onCancel()}};function createProviderErrorScreen(tui,done,error){return new ExtensionSelectorComponent("models.json cannot be edited",["Back"],done,done,{tui,description:`${truncate3(error,2400)}
|
|
2014
2069
|
|
|
2015
2070
|
Fix the file manually and open /provider again.`})}function createProviderApp(tui,theme2,keybindings,done,options){let{store,registry,runtime}=options,session=new ProviderTuiSession(tui),refresher=new RefreshCoordinator(runtime),activeEditor,closing;function notify(message,type){session.signal.aborted||options.notify(message,type)}store.onSaveResult=result2=>{session.signal.aborted||((result2.kind==="invalid"||result2.kind==="error")&¬ify(result2.error,"error"),activeEditor?.syncFromStore(),tui.requestRender())};function showList(){session.signal.aborted||(activeEditor=void 0,session.setScreen(new ProviderListScreen(tui,theme2,keybindings,result2=>{result2.kind==="close"?requestClose():openProvider(result2.providerId)},store)))}function openProvider(providerId){if(!store.getProviderIds().includes(providerId)){notify(`No provider ${JSON.stringify(providerId)} in models.json.`,"warning"),showList();return}activeEditor=new ProviderEditorScreen(tui,theme2,keybindings,showList,{store,refresher,providerId,registry,runtime,currentModel:options.getCurrentModel(),notify}),session.setScreen(activeEditor)}function showUnsaved(error){let back="Return to providers",retry="Retry saving",discard3="Discard unsaved changes and close";session.setScreen(new ExtensionSelectorComponent("Some changes are not saved",[back,retry,discard3],choice=>{if(choice===back){showList();return}choice===retry&&store.retrySave(),choice===discard3&&store.discardPending(),requestClose()},showList,{tui,description:truncate3(error,2400)}))}function requestClose(){if(closing||session.signal.aborted)return;let controller=new AbortController;closing=controller;let signal=AbortSignal.any([session.signal,controller.signal]);activeEditor=void 0,session.setScreen(new SavingScreen(theme2,keybindings,()=>{controller.abort(),closing=void 0,showList()})),finishClose(controller,signal)}async function finishClose(controller,signal){try{if(await store.flush(),signal.aborted)return;let unsaved=store.getPendingError();if(unsaved){closing=void 0,showUnsaved(unsaved);return}let outcome=await refresher.flush(signal);if(signal.aborted)return;outcome.ok||notify(`Changes saved, but model refresh failed: ${outcome.errors.join("; ")}`,"warning");let current=options.getCurrentModel();if(current&&refresher.touchedProviders.includes(current.provider)){let refreshed=registry.find(current.provider,current.id);refreshed&&!await options.setModel(refreshed)&¬ify("Reselect the current model with /model to apply its updated configuration.","warning"),refreshed||notify("The current model is no longer available; select another with /model.","warning")}signal.aborted||done()}catch(error){signal.aborted||(notify(formatError2(error),"error"),showList())}finally{closing===controller&&(closing=void 0)}}return options.initialProviderId?openProvider(options.initialProviderId):showList(),session}function providerExtension(pi){let modelsPath;pi.on("session_start",(_event,ctx)=>{modelsPath=ctx.modelRuntime.getModelsPath()}),pi.registerCommand(COMMAND_NAME,{description:COMMAND_DESCRIPTION,getArgumentCompletions:async prefix=>{if(!modelsPath)return null;let load=await ModelsJsonStore.load(modelsPath);if(!load.ok)return null;let query=prefix.trim().toLowerCase(),items=load.store.getProviderIds().filter(id=>id.toLowerCase().startsWith(query)).map(id=>{let count=load.store.getModels(id).length;return{value:id,label:id,description:`${String(count)} ${plural(count,"model")}`}});return items.length?items:null},handler:async(args,ctx)=>{if(!ctx.hasUI||ctx.mode!=="tui"){ctx.ui.notify(NO_UI_WARNING,"warning");return}let path14=ctx.modelRuntime.getModelsPath();if(modelsPath=path14,!path14){ctx.ui.notify(NO_MODELS_FILE_WARNING,"warning");return}try{let load=await ModelsJsonStore.load(path14);if(!load.ok){await ctx.ui.custom((tui,_theme,_keybindings,done)=>createProviderErrorScreen(tui,done,load.error));return}await ctx.ui.custom((tui,theme2,keybindings,done)=>createProviderApp(tui,theme2,keybindings,done,{store:load.store,runtime:ctx.modelRuntime,registry:ctx.modelRegistry,getCurrentModel:()=>ctx.model,setModel:model=>pi.setModel(model),notify:(message,type)=>ctx.ui.notify(message,type),initialProviderId:args.trim()||void 0}))}catch(error){ctx.ui.notify(formatError2(error),"error")}}})}var QUESTION_TOOL_NAME="question",QUESTION_LABEL="Question",QUESTION_DESCRIPTION="Ask the user 1-4 structured multiple-choice questions and return their selections. Never author an 'Other'-style option or a vague label like 'Option A' \u2014 the UI adds a custom-answer path itself. If you recommend an option, put it first and append ' (Recommended)' to its label.",QUESTION_PROMPT_SNIPPET="Ask the user structured multiple-choice questions when blocked on a decision only they can make",QUESTION_PROMPT_GUIDELINES=["Use `question` only for decisions you cannot resolve from the request, the code, or sensible defaults (direction, preference, permissions, destructive choices); for everything else choose a reasonable default and state it.","Batch related decisions into one `question` call (1-4 questions); ask no more than needed to unblock the next step.","Treat `question` answers as decisions: act on them without re-litigating, and do not re-ask unless circumstances change."];registerListKeybindings();var DetailPane=class{constructor(){this.key="",this.offset=0,this.maxOffset=0,this.pageRows=1,this.pendingPages=0}reset(){this.key="",this.offset=0,this.maxOffset=0,this.pendingPages=0}page(key,direction){this.key!==key&&this.reset(),this.key=key,this.pendingPages+=direction}render(key,title,content,width,rows,scrollHint,theme2){this.key!==key&&(this.reset(),this.key=key);let bodyRows=Math.max(1,rows-2),wasAtEnd=this.maxOffset>0&&this.offset===this.maxOffset;this.maxOffset=Math.max(0,content.length-bodyRows),this.pageRows=Math.max(1,bodyRows-1);let anchored2=wasAtEnd?this.maxOffset:this.offset;this.offset=Math.max(0,Math.min(this.maxOffset,anchored2+this.pendingPages*this.pageRows)),this.pendingPages=0;let body2=content.slice(this.offset,this.offset+bodyRows);if(rows<3)return body2.slice(0,rows);let lines=[theme2.fg("muted",truncateToWidth(` ${title.replace(/\s+/gu," ")}`,width)),...body2];if(this.maxOffset>0){for(;lines.length<rows-1;)lines.push("");let range2=`${this.offset+1}\u2013${this.offset+body2.length}/${content.length}`;lines.push(theme2.fg("dim",truncateToWidth(` ${range2}${scrollHint?` \u2022 ${scrollHint}`:""}`,width)))}return lines}};function ruleBorder(theme2,width,color2="accent"){return theme2.fg(color2,"\u2500".repeat(Math.max(0,width)))}function wrapWithPrefix(prefix,text2,width,outputLines){let prefixWidth=visibleWidth(prefix);if(prefixWidth>=width){for(let line of wrapTextWithAnsi(prefix+text2,width))outputLines.push(line);return}let wrappedLines=wrapTextWithAnsi(text2,width-prefixWidth),continuationPrefix=" ".repeat(prefixWidth);for(let lineIndex=0;lineIndex<wrappedLines.length;lineIndex++)outputLines.push(`${lineIndex===0?prefix:continuationPrefix}${wrappedLines[lineIndex]}`)}function moreOptionsHint(direction,count){let arrow=direction==="up"?"\u2191":"\u2193";return count<=0?`${arrow} more ${direction==="up"?"above":"below"}`:`${arrow} ${count} more option${count===1?"":"s"}`}function windowItems(items,focus,rows){let count=items.length,total=items.reduce((sum,item)=>sum+item.height,0),build=(first,last,contentRows)=>({first,last,contentRows,showAbove:first>0,showBelow:last<count-1,hiddenAbove:items.slice(0,first).filter(item=>item.countsAsOption).length,hiddenBelow:items.slice(last+1).filter(item=>item.countsAsOption).length});if(total<=rows)return build(0,count-1,rows);let windowFor=contentRows=>{let first=focus,last=focus,used=items[focus].height;for(let grew=!0;grew;)grew=!1,last+1<count&&used+items[last+1].height<=contentRows&&(last++,used+=items[last].height,grew=!0),first>0&&used+items[first-1].height<=contentRows&&(first--,used+=items[first].height,grew=!0);return build(first,last,contentRows)};if(rows<=2)return{...windowFor(Math.max(1,rows)),showAbove:!1,showBelow:!1};let window2=windowFor(rows-2);return window2.first===0||window2.last===count-1?windowFor(rows-1):window2}var PreviewLinesCache=class{constructor(){this.cache=new Map}get(previewText,width,compute){let byWidth=this.cache.get(previewText);byWidth||(byWidth=new Map,this.cache.set(previewText,byWidth));let lines=byWidth.get(width);return lines||(lines=compute(),byWidth.set(width,lines)),lines}},WidthCachedRender=class{invalidate(){this.cachedLines=void 0}get(width,height,compute){return this.cachedLines!==void 0&&this.cachedWidth===width&&this.cachedHeight===height?this.cachedLines:(this.cachedLines=compute(width,height),this.cachedWidth=width,this.cachedHeight=height,this.cachedLines)}};var QUESTION_LIMITS={questionChars:400,headerChars:32,optionLabelChars:80,optionDescriptionChars:300,previewChars:8e3,userTextChars:4e3,modelResultChars:12e3},TRUNCATION_FOLLOW_UP="Ask the user a focused follow-up question to clarify the omitted portion.";var DECLINE_MESSAGE="User declined to answer the questions.",CLARIFICATION_MESSAGE="The user wants to discuss these questions before choosing an answer.",ENVELOPE_PREFIX="User decisions:",ENVELOPE_SUFFIX="Continue with these decisions in mind.",CLARIFICATION_FOLLOW_UP="Explain the trade-offs or ask what the user would like clarified.",SHORTENED_NOTICE=`
|
|
2016
2071
|
|
|
@@ -2156,7 +2211,7 @@ ${lines.join(`
|
|
|
2156
2211
|
|
|
2157
2212
|
${blocks.join(`
|
|
2158
2213
|
|
|
2159
|
-
`)}`).content}function search(pi){pi.registerTool({name:"code_search",label:"Code Search",description:"Find where behavior lives in the local repository from a description of it. Returns candidate files with line ranges.",promptSnippet:"Find code by describing its behavior",promptGuidelines:["Use `code_search` when you cannot name the file or symbol you need; use `read`, `grep`, or `find` when you can.","Read the returned ranges before editing; the locations are candidates, not answers."],parameters:CodeSearchParams,renderCall:renderCodeSearchCall,renderResult:renderCodeSearchResult,async execute(_toolCallId,params,signal,onUpdate,ctx){let root=resolve17(ctx.cwd,params.path??".");if(!isInside(ctx.cwd,root))throw new Error(`path must be inside the working directory (${ctx.cwd}).`);let locations=await withDevin(apiKey=>codeSearch({apiKey,query:params.query.trim(),root,cwd:ctx.cwd,signal,onProgress:text2=>onUpdate?.({content:[{type:"text",text:text2}],details:{locations:[]}})}));return{content:[{type:"text",text:formatLocations(locations)}],details:{locations}}}});let currentMonth=new Date().toLocaleDateString("en-US",{month:"long",year:"numeric"});pi.registerTool({name:"web_search",label:"Web Search",description:"Search the live web for current information. Returns titles, URLs, and the page excerpts that match the query.",promptSnippet:"Search the live web for current information",promptGuidelines:["Use `web_search` for information beyond your knowledge cutoff.",`It is ${currentMonth}; put this year in \`web_search\` queries for recent releases, versions, or events, not the year your training data suggests.`,"When an answer relies on `web_search` results, cite each result you used as a markdown link: [Title](URL)."],parameters:WebSearchParams,renderCall:renderWebSearchCall,renderResult:renderWebSearchResult,async execute(_toolCallId,params,signal){let query=params.query.trim(),results=await withDevin(apiKey=>webSearch(apiKey,query,params.max_results??5,signal));return{content:[{type:"text",text:formatWebResults(query,results)}],details:{results:results.map(({url,title})=>({url,title}))}}}}),registerSearchCommand(pi),pi.on("session_start",async()=>syncTools(pi))}var CONTEXT_WARNING_PERCENT=40,CONTEXT_ERROR_PERCENT=80,MIN_GAP=1;function formatWorkingDirectory(cwd,home){let homeDirectory=home.replace(/[\\/]+$/,"");if(!homeDirectory)return cwd;let normalizePath3=filePath=>filePath.replace(/\\/g,"/").replace(/\/+$/,"").toLowerCase(),normalizedHomeDirectory=normalizePath3(homeDirectory),normalizedCwd=normalizePath3(cwd);return normalizedCwd===normalizedHomeDirectory?"~":normalizedCwd.startsWith(`${normalizedHomeDirectory}/`)?`~${cwd.slice(homeDirectory.length).replace(/\\/g,"/")}`:cwd}function pathBasename(displayPath2){let normalized=displayPath2.replace(/\\/g,"/").replace(/\/+$/,"");if(!normalized||normalized==="~")return normalized||displayPath2;let slash=normalized.lastIndexOf("/");if(slash<0)return normalized;let base=normalized.slice(slash+1);return normalized.startsWith("~/")?`~/${base}`:base}function formatTokenCount2(count){return count<1e3?`${count}`:count<1e4?`${(count/1e3).toFixed(1)}k`:count<1e6?`${Math.round(count/1e3)}k`:count<1e7?`${(count/1e6).toFixed(1)}M`:`${Math.round(count/1e6)}M`}function joinSegments(segments,separator){return segments.filter(Boolean).join(separator)}function formatContextUsage(data,theme2){let contextWindow=data.contextUsage?.contextWindow??data.model?.contextWindow,suffix=contextWindow?`/${formatTokenCount2(contextWindow)}`:"",percent=data.contextUsage?.percent,label=`CTX ${percent==null?"?":percent.toFixed(1)}%${suffix}`;return percent!=null&&percent>CONTEXT_ERROR_PERCENT?theme2.fg("error",label):percent!=null&&percent>CONTEXT_WARNING_PERCENT?theme2.fg("warning",label):theme2.fg("accent",label)}function formatUsageCandidates(summary,subscription,theme2){let tokens2=[summary.input>0?`\u2191${formatTokenCount2(summary.input)}`:"",summary.output>0?`\u2193${formatTokenCount2(summary.output)}`:""],read=summary.cacheRead>0?`R${formatTokenCount2(summary.cacheRead)}`:"",write=summary.cacheWrite>0?`W${formatTokenCount2(summary.cacheWrite)}`:"",suffix=[summary.latestCacheHitPercent===void 0?"":`CH${summary.latestCacheHitPercent.toFixed(1)}%`,summary.cost>0?`$${summary.cost.toFixed(3)}${subscription?" (sub)":""}`:""],candidates=[[read,write],[read],[]].map(cache=>joinSegments([...tokens2,...cache,...suffix]," "));return[...new Set(candidates.filter(Boolean))].map(text2=>theme2.fg("dim",text2))}function formatExtensionStatuses(statuses,theme2){return[...statuses.entries()].sort(([first],[second])=>first.localeCompare(second)).map(([,text2])=>text2.replace(/[\r\n\t]/g," ").replace(/ +/g," ").trim()).filter(Boolean).map(text2=>text2.includes("\x1B[")?text2:theme2.fg("muted",text2)).join(" ")}function fitsLeftRight(left,right,width){return visibleWidth(left)+visibleWidth(right)+(left&&right?MIN_GAP:0)<=width}function layoutLeftRight(left,right,width,ellipsis){if(width<=0)return"";if(!right)return truncateToWidth(left,width,ellipsis);let rightWidth=visibleWidth(right);if(!left)return`${" ".repeat(Math.max(0,width-rightWidth))}${truncateToWidth(right,width,ellipsis)}`;let leftWidth=visibleWidth(left);if(leftWidth+rightWidth+MIN_GAP>width){let maxRightWidth=Math.min(rightWidth,Math.max(8,Math.floor(width*.45)));right=truncateToWidth(right,maxRightWidth,ellipsis),rightWidth=visibleWidth(right);let maxLeftWidth=width-rightWidth-MIN_GAP;if(maxLeftWidth<1)return truncateToWidth(right,width,ellipsis);left=truncateToWidth(left,maxLeftWidth,ellipsis),leftWidth=visibleWidth(left)}return`${left}${" ".repeat(Math.max(MIN_GAP,width-leftWidth-rightWidth))}${right}`}function layoutSecondaryLine(left,status,right,width,ellipsis){let leftWidth=visibleWidth(left),statusWidth=visibleWidth(status),rightWidth=visibleWidth(right),free=width-leftWidth-statusWidth-rightWidth;if(!status||free<MIN_GAP*2)return layoutLeftRight(left,right,width,ellipsis);let leftPad=Math.floor((width-statusWidth)/2)-leftWidth;return(leftPad<MIN_GAP||free-leftPad<MIN_GAP)&&(leftPad=Math.floor(free/2)),`${left}${" ".repeat(leftPad)}${status}${" ".repeat(free-leftPad)}${right}`}function renderPrimaryLine(data,theme2,width,ellipsis){let{model,thinkingLevel}=data,name=theme2.fg("toolTitle",theme2.bold(model?.name??model?.id??"no-model")),provider=model?.provider?theme2.fg("muted",`(${model.provider})`):"",effort=model?.reasoning&&thinkingLevel!=="off"?theme2.getThinkingBorderColor(thinkingLevel)(thinkingLevel):"",separator=theme2.fg("dim"," \xB7 "),rich=joinSegments([joinSegments([name,provider]," "),effort],separator),plain=joinSegments([name,effort],separator),cwd=formatWorkingDirectory(data.cwd,data.home),full=theme2.fg("success",cwd),short=theme2.fg("success",pathBasename(cwd)),branch=data.gitBranch?theme2.fg("accent",data.gitBranch):"",chosen=[{left:rich,right:joinSegments([full,branch],separator)},{left:rich,right:full},{left:rich,right:joinSegments([short,branch],separator)},{left:rich,right:short},{left:plain,right:joinSegments([short,branch],separator)},{left:plain,right:short},{left:plain,right:""}].find(({left,right})=>fitsLeftRight(left,right,width))??{left:plain,right:short};return layoutLeftRight(chosen.left,chosen.right,width,ellipsis)}function renderStatusline(data,theme2,width){let ellipsis=theme2.fg("dim","..."),primary=renderPrimaryLine(data,theme2,width,ellipsis),context=formatContextUsage(data,theme2),status=formatExtensionStatuses(data.statuses,theme2),candidates=formatUsageCandidates(data.usage,data.usesSubscription,theme2),usage=candidates.find(candidate=>fitsLeftRight(context,candidate,width)),secondary=candidates.length>0&&usage===void 0?layoutLeftRight(context,candidates[0],width,ellipsis):layoutSecondaryLine(context,status,usage??"",width,ellipsis);return[primary,secondary]}var BranchUsage=class{invalidate(){this.cached=void 0}read(manager){let sessionId=manager.getSessionId(),leafId=manager.getLeafId();if(this.cached?.manager===manager&&this.cached.sessionId===sessionId&&this.cached.leafId===leafId)return this.cached.usage;let entries=manager.getBranch(),totals=createUsageTotals();for(let usage2 of getAccountedUsages(entries))addUsageToTotals(totals,usage2);let latestCacheHitPercent;for(let index3=entries.length-1;index3>=0;index3--){let entry=entries[index3];if(entry.type!=="message"||entry.message.role!=="assistant")continue;let{input:input2,cacheRead,cacheWrite}=entry.message.usage,promptTokens=input2+cacheRead+cacheWrite;(cacheRead>0||cacheWrite>0)&&promptTokens>0&&(latestCacheHitPercent=cacheRead/promptTokens*100);break}let usage={...totals,latestCacheHitPercent};return this.cached={manager,sessionId,leafId,usage},usage}};function statusline(pi){pi.on("session_start",(_event,ctx)=>{ctx.mode==="tui"&&ctx.ui.setFooter((tui,theme2,footerData)=>{let usage=new BranchUsage;return{dispose:footerData.onBranchChange(()=>tui.requestRender()),invalidate(){usage.invalidate()},render(width){let model=ctx.model;return renderStatusline({model,thinkingLevel:ctx.thinkingLevel??"off",cwd:ctx.cwd,home:process.env.USERPROFILE||process.env.HOME||"",gitBranch:footerData.getGitBranch(),contextUsage:ctx.getContextUsage(),usage:usage.read(ctx.sessionManager),usesSubscription:model?ctx.modelRegistry.isUsingOAuth(model):!1,statuses:footerData.getExtensionStatuses()},theme2,width)}}})}),pi.on("session_shutdown",(_event,ctx)=>{ctx.mode==="tui"&&ctx.ui.setFooter(void 0)})}var builtInExtensions=[{name:"codemode",factory:codemode_default,replaceable:!0,builtin:!0},{name:"mcp",factory:mcp_default,replaceable:!0,builtin:!0},{name:"tool-search",factory:tool_search_default,replaceable:!0,builtin:!0},{name:"llama.cpp",factory:llamaExtension,builtin:!0},{name:"btw",factory:btwExtension,builtin:!0},{name:"deepwiki",factory:deepwiki,builtin:!0},{name:"provider",factory:providerExtension,builtin:!0},{name:"question",factory:question,builtin:!0},{name:"statusline",factory:statusline,builtin:!0},{name:"search",factory:search,builtin:!0}];var cli_exports={};__export(cli_exports,{runMcpCommand:()=>runMcpCommand});import{existsSync as existsSync26}from"node:fs";import{join as join47}from"node:path";import{createInterface as createInterface5}from"node:readline/promises";var HELP=`${source_default.bold("Usage:")}
|
|
2214
|
+
`)}`).content}function search(pi){pi.registerTool({name:"code_search",label:"Code Search",description:"Find where behavior lives in the local repository from a description of it. Returns candidate files with line ranges.",promptSnippet:"Find code by describing its behavior",promptGuidelines:["Use `code_search` when you cannot name the file or symbol you need; use `read`, `grep`, or `find` when you can.","Read the returned ranges before editing; the locations are candidates, not answers."],parameters:CodeSearchParams,renderCall:renderCodeSearchCall,renderResult:renderCodeSearchResult,async execute(_toolCallId,params,signal,onUpdate,ctx){let root=resolve17(ctx.cwd,params.path??".");if(!isInside(ctx.cwd,root))throw new Error(`path must be inside the working directory (${ctx.cwd}).`);let locations=await withDevin(apiKey=>codeSearch({apiKey,query:params.query.trim(),root,cwd:ctx.cwd,signal,onProgress:text2=>onUpdate?.({content:[{type:"text",text:text2}],details:{locations:[]}})}));return{content:[{type:"text",text:formatLocations(locations)}],details:{locations}}}});let currentMonth=new Date().toLocaleDateString("en-US",{month:"long",year:"numeric"});pi.registerTool({name:"web_search",label:"Web Search",description:"Search the live web for current information. Returns titles, URLs, and the page excerpts that match the query.",promptSnippet:"Search the live web for current information",promptGuidelines:["Use `web_search` for information beyond your knowledge cutoff.",`It is ${currentMonth}; put this year in \`web_search\` queries for recent releases, versions, or events, not the year your training data suggests.`,"When an answer relies on `web_search` results, cite each result you used as a markdown link: [Title](URL)."],parameters:WebSearchParams,renderCall:renderWebSearchCall,renderResult:renderWebSearchResult,async execute(_toolCallId,params,signal){let query=params.query.trim(),results=await withDevin(apiKey=>webSearch(apiKey,query,params.max_results??5,signal));return{content:[{type:"text",text:formatWebResults(query,results)}],details:{results:results.map(({url,title})=>({url,title}))}}}}),registerSearchCommand(pi),pi.on("session_start",async()=>syncTools(pi))}var CONTEXT_WARNING_PERCENT=40,CONTEXT_ERROR_PERCENT=80,MIN_GAP=1;function formatWorkingDirectory(cwd,home){let homeDirectory=home.replace(/[\\/]+$/,"");if(!homeDirectory)return cwd;let normalizePath3=filePath=>filePath.replace(/\\/g,"/").replace(/\/+$/,"").toLowerCase(),normalizedHomeDirectory=normalizePath3(homeDirectory),normalizedCwd=normalizePath3(cwd);return normalizedCwd===normalizedHomeDirectory?"~":normalizedCwd.startsWith(`${normalizedHomeDirectory}/`)?`~${cwd.slice(homeDirectory.length).replace(/\\/g,"/")}`:cwd}function pathBasename(displayPath2){let normalized=displayPath2.replace(/\\/g,"/").replace(/\/+$/,"");if(!normalized||normalized==="~")return normalized||displayPath2;let slash=normalized.lastIndexOf("/");if(slash<0)return normalized;let base=normalized.slice(slash+1);return normalized.startsWith("~/")?`~/${base}`:base}function formatTokenCount2(count){return count<1e3?`${count}`:count<1e4?`${(count/1e3).toFixed(1)}k`:count<1e6?`${Math.round(count/1e3)}k`:count<1e7?`${(count/1e6).toFixed(1)}M`:`${Math.round(count/1e6)}M`}function joinSegments(segments,separator){return segments.filter(Boolean).join(separator)}function formatContextUsage(data,theme2){let contextWindow=data.contextUsage?.contextWindow??data.model?.contextWindow,suffix=contextWindow?`/${formatTokenCount2(contextWindow)}`:"",percent=data.contextUsage?.percent,label=`CTX ${percent==null?"?":percent.toFixed(1)}%${suffix}`;return percent!=null&&percent>CONTEXT_ERROR_PERCENT?theme2.fg("error",label):percent!=null&&percent>CONTEXT_WARNING_PERCENT?theme2.fg("warning",label):theme2.fg("accent",label)}function formatUsageCandidates(summary,subscription,theme2){let tokens2=[summary.input>0?`\u2191${formatTokenCount2(summary.input)}`:"",summary.output>0?`\u2193${formatTokenCount2(summary.output)}`:""],read=summary.cacheRead>0?`R${formatTokenCount2(summary.cacheRead)}`:"",write=summary.cacheWrite>0?`W${formatTokenCount2(summary.cacheWrite)}`:"",suffix=[summary.latestCacheHitPercent===void 0?"":`CH${summary.latestCacheHitPercent.toFixed(1)}%`,summary.cost>0?`$${summary.cost.toFixed(3)}${subscription?" (sub)":""}`:""],candidates=[[read,write],[read],[]].map(cache=>joinSegments([...tokens2,...cache,...suffix]," "));return[...new Set(candidates.filter(Boolean))].map(text2=>theme2.fg("dim",text2))}function formatExtensionStatuses(statuses,theme2){return[...statuses.entries()].sort(([first],[second])=>first.localeCompare(second)).map(([,text2])=>text2.replace(/[\r\n\t]/g," ").replace(/ +/g," ").trim()).filter(Boolean).map(text2=>text2.includes("\x1B[")?text2:theme2.fg("muted",text2)).join(" ")}function fitsLeftRight(left,right,width){return visibleWidth(left)+visibleWidth(right)+(left&&right?MIN_GAP:0)<=width}function layoutLeftRight(left,right,width,ellipsis){if(width<=0)return"";if(!right)return truncateToWidth(left,width,ellipsis);let rightWidth=visibleWidth(right);if(!left)return`${" ".repeat(Math.max(0,width-rightWidth))}${truncateToWidth(right,width,ellipsis)}`;let leftWidth=visibleWidth(left);if(leftWidth+rightWidth+MIN_GAP>width){let maxRightWidth=Math.min(rightWidth,Math.max(8,Math.floor(width*.45)));right=truncateToWidth(right,maxRightWidth,ellipsis),rightWidth=visibleWidth(right);let maxLeftWidth=width-rightWidth-MIN_GAP;if(maxLeftWidth<1)return truncateToWidth(right,width,ellipsis);left=truncateToWidth(left,maxLeftWidth,ellipsis),leftWidth=visibleWidth(left)}return`${left}${" ".repeat(Math.max(MIN_GAP,width-leftWidth-rightWidth))}${right}`}function layoutSecondaryLine(left,status,right,width,ellipsis){let leftWidth=visibleWidth(left),statusWidth=visibleWidth(status),rightWidth=visibleWidth(right),free=width-leftWidth-statusWidth-rightWidth;if(!status||free<MIN_GAP*2)return layoutLeftRight(left,right,width,ellipsis);let leftPad=Math.floor((width-statusWidth)/2)-leftWidth;return(leftPad<MIN_GAP||free-leftPad<MIN_GAP)&&(leftPad=Math.floor(free/2)),`${left}${" ".repeat(leftPad)}${status}${" ".repeat(free-leftPad)}${right}`}function renderPrimaryLine(data,theme2,width,ellipsis){let{model,thinkingLevel}=data,name=theme2.fg("toolTitle",theme2.bold(model?.name??model?.id??"no-model")),provider=model?.provider?theme2.fg("muted",`(${model.provider})`):"",effort=model?.reasoning&&thinkingLevel!=="off"?theme2.getThinkingBorderColor(thinkingLevel)(thinkingLevel):"",separator=theme2.fg("dim"," \xB7 "),rich=joinSegments([joinSegments([name,provider]," "),effort],separator),plain=joinSegments([name,effort],separator),cwd=formatWorkingDirectory(data.cwd,data.home),full=theme2.fg("success",cwd),short=theme2.fg("success",pathBasename(cwd)),branch=data.gitBranch?theme2.fg("accent",data.gitBranch):"",chosen=[{left:rich,right:joinSegments([full,branch],separator)},{left:rich,right:full},{left:rich,right:joinSegments([short,branch],separator)},{left:rich,right:short},{left:plain,right:joinSegments([short,branch],separator)},{left:plain,right:short},{left:plain,right:""}].find(({left,right})=>fitsLeftRight(left,right,width))??{left:plain,right:short};return layoutLeftRight(chosen.left,chosen.right,width,ellipsis)}function renderStatusline(data,theme2,width){let ellipsis=theme2.fg("dim","..."),primary=renderPrimaryLine(data,theme2,width,ellipsis),context=formatContextUsage(data,theme2),status=formatExtensionStatuses(data.statuses,theme2),candidates=formatUsageCandidates(data.usage,data.usesSubscription,theme2),usage=candidates.find(candidate=>fitsLeftRight(context,candidate,width)),secondary=candidates.length>0&&usage===void 0?layoutLeftRight(context,candidates[0],width,ellipsis):layoutSecondaryLine(context,status,usage??"",width,ellipsis);return[primary,secondary]}var BranchUsage=class{invalidate(){this.cached=void 0}read(manager){let sessionId=manager.getSessionId(),leafId=manager.getLeafId();if(this.cached?.manager===manager&&this.cached.sessionId===sessionId&&this.cached.leafId===leafId)return this.cached.usage;let entries=manager.getBranch(),totals=createUsageTotals();for(let usage2 of getAccountedUsages(entries))addUsageToTotals(totals,usage2);let latestCacheHitPercent;for(let index3=entries.length-1;index3>=0;index3--){let entry=entries[index3];if(entry.type!=="message"||entry.message.role!=="assistant")continue;let{input:input2,cacheRead,cacheWrite}=entry.message.usage,promptTokens=input2+cacheRead+cacheWrite;(cacheRead>0||cacheWrite>0)&&promptTokens>0&&(latestCacheHitPercent=cacheRead/promptTokens*100);break}let usage={...totals,latestCacheHitPercent};return this.cached={manager,sessionId,leafId,usage},usage}};function statusline(pi){pi.on("session_start",(_event,ctx)=>{ctx.mode==="tui"&&ctx.ui.setFooter((tui,theme2,footerData)=>{let usage=new BranchUsage;return{dispose:footerData.onBranchChange(()=>tui.requestRender()),invalidate(){usage.invalidate()},render(width){let model=ctx.model;return renderStatusline({model,thinkingLevel:ctx.thinkingLevel??"off",cwd:ctx.cwd,home:process.env.USERPROFILE||process.env.HOME||"",gitBranch:footerData.getGitBranch(),contextUsage:ctx.getContextUsage(),usage:usage.read(ctx.sessionManager),usesSubscription:model?ctx.modelRegistry.isUsingOAuth(model):!1,statuses:footerData.getExtensionStatuses()},theme2,width)}}})}),pi.on("session_shutdown",(_event,ctx)=>{ctx.mode==="tui"&&ctx.ui.setFooter(void 0)})}var builtInExtensions=[{name:"codemode",factory:codemode_default,replaceable:!0,builtin:!0},{name:"mcp",factory:mcp_default,replaceable:!0,builtin:!0},{name:"tool-search",factory:tool_search_default,replaceable:!0,builtin:!0},{name:"cached-compaction",factory:cachedCompaction,replaceable:!0,builtin:!0},{name:"llama.cpp",factory:llamaExtension,builtin:!0},{name:"btw",factory:btwExtension,builtin:!0},{name:"deepwiki",factory:deepwiki,builtin:!0},{name:"provider",factory:providerExtension,builtin:!0},{name:"question",factory:question,builtin:!0},{name:"statusline",factory:statusline,builtin:!0},{name:"search",factory:search,builtin:!0}];var cli_exports={};__export(cli_exports,{runMcpCommand:()=>runMcpCommand});import{existsSync as existsSync26}from"node:fs";import{join as join47}from"node:path";import{createInterface as createInterface5}from"node:readline/promises";var HELP=`${source_default.bold("Usage:")}
|
|
2160
2215
|
${APP_NAME} mcp add <server> [options] -- <command> [args...]
|
|
2161
2216
|
${APP_NAME} mcp add <server> [options] --url <url>
|
|
2162
2217
|
${APP_NAME} mcp remove <server> [-l]
|