kpilot 0.10.8 → 0.10.9

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/README.md CHANGED
@@ -6,7 +6,7 @@ Use `kpilot` directly from your project directory to understand codebases, plan
6
6
 
7
7
  ## Developer Preview
8
8
 
9
- **Current version: 0.10.8**
9
+ **Current version: 0.10.9**
10
10
 
11
11
  kpilot is currently available as a **Developer Preview** and remains under active development.
12
12
 
package/dist/cli.mjs CHANGED
@@ -97,9 +97,9 @@ tool calls: ${JSON.stringify(e.tool_calls)}`:`${e.role}: ${e.content??""}`).join
97
97
  `),b=Et(`AWS4${t.secretAccessKey}`,s),f=Et(b,t.region),y=Et(f,"bedrock"),m=Et(y,"aws4_request"),g=Hr("sha256",m).update(p).digest("hex");return{"content-type":a["content-type"],"x-amz-date":r,...t.sessionToken?{"x-amz-security-token":t.sessionToken}:{},authorization:`AWS4-HMAC-SHA256 Credential=${t.accessKeyId}/${d}, SignedHeaders=${c.join(";")}, Signature=${g}`}}function $i(t){let e=t.filter(o=>o.role==="system").map(o=>o.content).join(`
98
98
 
99
99
  `),n=[];for(let o of t)if(o.role!=="system")if(o.role==="user")n.push({role:"user",content:[{text:o.content}]});else if(o.role==="assistant"){let r=[];o.content&&r.push({text:o.content});for(let s of o.tool_calls??[]){let i={};try{i=JSON.parse(s.function.arguments)}catch{i={raw:s.function.arguments}}r.push({toolUse:{toolUseId:s.id,name:s.function.name,input:i}})}n.push({role:"assistant",content:r})}else{let r;try{r={json:JSON.parse(o.content)}}catch{r={text:o.content}}n.push({role:"user",content:[{toolResult:{toolUseId:o.tool_call_id,content:[r]}}]})}return{...e?{system:[{text:e}]}:{},messages:n}}var Je=class{options;constructor(e){if(!e.model.trim())throw new Error("A Bedrock model ID is required.");if(!e.region)throw new Error("AWS region is required.");if(!e.accessKeyId||!e.secretAccessKey)throw new Error("AWS credentials are required.");this.options={...e,model:e.model,region:e.region,accessKeyId:e.accessKeyId,secretAccessKey:e.secretAccessKey,baseUrl:e.baseUrl??`https://bedrock-runtime.${e.region}.amazonaws.com`,timeoutMs:e.timeoutMs??12e4}}async complete(e,n={}){let o=$i(e.messages),r=JSON.stringify({...o,toolConfig:e.tools.length?{tools:e.tools.map(d=>({toolSpec:{name:d.function.name,description:d.function.description,inputSchema:{json:d.function.parameters}}})),toolChoice:{auto:{}}}:void 0,...this.options.maxOutputTokens===void 0?{}:{inferenceConfig:{maxTokens:this.options.maxOutputTokens}}}),s=new URL(`${this.options.baseUrl.replace(/\/+$/,"")}/model/${encodeURIComponent(this.options.model)}/converse`),i=await te(s.toString(),{method:"POST",headers:Mi(this.options,s,r),body:r},n,this.options.timeoutMs),a=i?.output?.message?.content??[],c=[],l=[];for(let d of a)typeof d?.text=="string"&&c.push(d.text),d?.toolUse?.name&&l.push({id:d.toolUse.toolUseId??`tool_call_${l.length+1}`,type:"function",function:{name:d.toolUse.name,arguments:JSON.stringify(d.toolUse.input??{})}});let u={role:"assistant",content:c.length?c.join(""):null,...l.length?{tool_calls:l}:{}};return await re(i,n),await ne(u,n),{message:u,model:this.options.model,usage:{inputTokens:i?.usage?.inputTokens,outputTokens:i?.usage?.outputTokens}}}};import{spawn as _i}from"node:child_process";async function Wr(t,e,n,o){return await new Promise((r,s)=>{let i=_i(t,e,{cwd:n.rootDir,env:{...process.env,...n.environment},stdio:["ignore","pipe","pipe"]}),a="",c="",l=setTimeout(()=>i.kill("SIGTERM"),n.timeoutMs??3e5),u=()=>{i.kill("SIGTERM")};o.signal?.addEventListener("abort",u,{once:!0}),i.stdout?.on("data",d=>{a+=String(d)}),i.stderr?.on("data",d=>{c+=String(d)}),i.on("error",d=>{clearTimeout(l),o.signal?.removeEventListener("abort",u),s(d)}),i.on("close",d=>{clearTimeout(l),o.signal?.removeEventListener("abort",u),o.signal?.aborted?s(pn(o.signal.reason)):d!==0?s(new Error(`${t} exited with code ${d}: ${c.trim()||a.trim()}`)):r({stdout:a,stderr:c})})})}function Ai(t){let e=t.split(/\r?\n/).filter(Boolean),n=[];for(let o of e)try{let r=JSON.parse(o),s=[r?.item?.text,r?.item?.content,r?.message?.content,r?.message,r?.text,r?.output_text,r?.content];for(let i of s)typeof i=="string"&&i.trim()&&n.push(i.trim())}catch{}return n.at(-1)??t.trim()}var Ke=class{options;constructor(e){this.options=e}async complete(e,n={}){let o=fn(e.messages,e.tools),r=["bash","powershell","list_bash","list_powershell","read_bash","read_powershell","stop_bash","stop_powershell","write_bash","write_powershell","apply_patch","create","edit","list_agents","read_agent","task","write_agent","ask_user","skill","web_fetch"].join(","),s=["-p",o,"-s","--no-ask-user","--allow-tool=read",`--excluded-tools=${r}`,"--disable-builtin-mcps","--no-custom-instructions","--no-experimental","--no-remote","--no-remote-export","--no-auto-update"];this.options.model&&s.push("--model",this.options.model);let{stdout:i}=await Wr(this.options.command||"copilot",s,this.options,n),a=i.trim();if(!a)throw new Error("GitHub Copilot CLI returned no response. Run `copilot login` and verify the subscription.");return await n.onTextDelta?.(a),{message:{role:"assistant",content:a},model:this.options.model}}},Ge=class{options;constructor(e){this.options=e}async complete(e,n={}){let o=fn(e.messages,e.tools),r=["exec","--json","--sandbox","read-only","--skip-git-repo-check"];this.options.model&&r.push("--model",this.options.model),r.push(o);let{stdout:s}=await Wr(this.options.command||"codex",r,this.options,n),i=Ai(s);if(!i)throw new Error("Codex CLI returned no response. Run `codex login` and sign in with ChatGPT.");return await n.onTextDelta?.(i),{message:{role:"assistant",content:i},model:this.options.model}}};var He=class{baseUrl;options;constructor(e){if(this.options=e,!e.accessToken)throw new Error("kpilot login is required to use hosted models. Run `kpilot login`.");this.baseUrl=e.baseUrl.replace(/\/+$/,"")}async complete(e,n={}){let o=new AbortController,r=setTimeout(()=>o.abort("request timeout"),this.options.timeoutMs??18e4),s=()=>o.abort(n.signal?.reason);n.signal?.aborted?o.abort(n.signal.reason):n.signal?.addEventListener("abort",s,{once:!0});let i=await this.options.getAccessToken?.()??this.options.accessToken;try{let a=await fetch(`${this.baseUrl}/v1/ai/responses`,{method:"POST",signal:o.signal,headers:{authorization:`Bearer ${i}`,"content-type":"application/json",...this.options.headers},body:JSON.stringify({route:this.options.route??"auto",...this.options.model?{model:this.options.model}:{},messages:e.messages,tools:e.tools})}),c=await a.text(),l;try{l=c?JSON.parse(c):{}}catch{throw new Error(`Hosted model endpoint returned non-JSON data (HTTP ${a.status}).`)}if(!a.ok){let u=typeof l.message=="string"?l.message:typeof l.error?.message=="string"?l.error.message:`Hosted model endpoint returned HTTP ${a.status}.`,d=typeof l.detail=="string"?l.detail:void 0,p=l.attempts??l.error?.attempts,b=Array.isArray(p)&&p.length>0?p.map(f=>`${f.model??"?"}: ${f.error??"unknown error"}`).join(" | "):void 0;throw new Error([u,d&&d!==u?d:void 0,b].filter(f=>!!(f&&f.trim())).join(" "))}if(l.message?.content&&n.onTextDelta&&await n.onTextDelta(l.message.content),n.onReasoningDelta){let u=Pe(l);u&&await n.onReasoningDelta(u)}return l}finally{clearTimeout(r),n.signal?.removeEventListener("abort",s)}}};import{spawn as Oi}from"node:child_process";function zr(t){if(!t||t.message?.role!=="assistant")throw new Error("External agent response must contain an assistant message.");return t}var We=class{options;constructor(e){if(this.options=e,!e.command&&!e.endpoint)throw new Error("Bring-your-own-agent requires either command or endpoint.")}async complete(e,n={}){return this.options.endpoint?await this.completeHttp(e,n):await this.completeCommand(e,n)}async completeHttp(e,n){let o=await fetch(this.options.endpoint,{method:"POST",signal:n.signal,headers:{"content-type":"application/json",...this.options.accessToken?{authorization:`Bearer ${this.options.accessToken}`}:{}},body:JSON.stringify({protocol:"kpilot-agent-v1",request:e})}),r=await o.text(),s;try{s=JSON.parse(r)}catch{throw new Error(`External agent returned non-JSON data (HTTP ${o.status}).`)}if(!o.ok)throw new Error(s.message??`External agent returned HTTP ${o.status}.`);let i=zr(s);if(n.onReasoningDelta){let a=Pe(s);a&&await n.onReasoningDelta(a)}return i.message.content&&n.onTextDelta&&await n.onTextDelta(i.message.content),i}async completeCommand(e,n){return await new Promise((o,r)=>{let s=Oi(this.options.command,this.options.args??[],{cwd:this.options.rootDir??process.cwd(),env:process.env,stdio:["pipe","pipe","pipe"]}),i=setTimeout(()=>s.kill("SIGTERM"),this.options.timeoutMs??18e4),a="",c="",l=()=>{s.kill("SIGTERM")};n.signal?.addEventListener("abort",l,{once:!0}),s.stdout?.on("data",u=>{a+=String(u)}),s.stderr?.on("data",u=>{c+=String(u)}),s.once("error",r),s.once("close",async u=>{if(clearTimeout(i),n.signal?.removeEventListener("abort",l),n.signal?.aborted)return r(n.signal.reason??new Error("External agent cancelled."));if(u!==0)return r(new Error(`External agent exited with code ${u}: ${c.trim().slice(0,1e3)}`));try{let d=zr(JSON.parse(a.trim()));if(n.onReasoningDelta){let p=Pe(d);p&&await n.onReasoningDelta(p)}d.message.content&&n.onTextDelta&&await n.onTextDelta(d.message.content),o(d)}catch(d){r(d)}}),s.stdin?.end(`${JSON.stringify({protocol:"kpilot-agent-v1",request:e})}
100
- `)})}};import{spawn as Ii}from"node:child_process";var Vr=[{id:"openai-compatible",name:"OpenAI-compatible Chat Completions",protocol:"POST /v1/chat/completions",auth:["none","api-key","bearer-token"],nativeTools:!0,streaming:!0},{id:"openai-responses",name:"OpenAI Responses API",protocol:"POST /v1/responses",auth:["api-key","bearer-token"],nativeTools:!0,streaming:"buffered-fallback",defaultBaseUrl:"https://api.openai.com/v1"},{id:"anthropic",name:"Anthropic Claude API",protocol:"POST /v1/messages",auth:["api-key"],nativeTools:!0,streaming:"buffered-fallback",defaultBaseUrl:"https://api.anthropic.com"},{id:"gemini",name:"Google Gemini Developer API",protocol:"models.generateContent",auth:["api-key"],nativeTools:!0,streaming:"buffered-fallback",defaultBaseUrl:"https://generativelanguage.googleapis.com/v1beta"},{id:"xai",name:"xAI Inference API",protocol:"POST /v1/responses",auth:["api-key"],nativeTools:!0,streaming:"buffered-fallback",defaultBaseUrl:"https://api.x.ai/v1"},{id:"mistral",name:"Mistral AI API",protocol:"POST /v1/chat/completions",auth:["api-key"],nativeTools:!0,streaming:!0,defaultBaseUrl:"https://api.mistral.ai/v1"},{id:"cohere",name:"Cohere v2 Chat API",protocol:"POST /v2/chat",auth:["api-key"],nativeTools:!0,streaming:"buffered-fallback",defaultBaseUrl:"https://api.cohere.com"},{id:"aws-bedrock",name:"Amazon Bedrock Converse API",protocol:"Converse",auth:["aws-sigv4"],nativeTools:!0,streaming:"buffered-fallback"},{id:"google-vertex",name:"Google Vertex AI",protocol:"publishers/google/models:generateContent",auth:["bearer-token"],nativeTools:!0,streaming:"buffered-fallback"},{id:"azure-openai",name:"Azure OpenAI v1 Responses API",protocol:"POST /openai/v1/responses",auth:["api-key","bearer-token"],nativeTools:!0,streaming:"buffered-fallback"},{id:"github-copilot",name:"GitHub Copilot subscription bridge",protocol:"Official Copilot CLI",auth:["github-subscription"],nativeTools:"bridge-limited",streaming:!1,notes:"Uses copilot login or COPILOT_GITHUB_TOKEN/GH_TOKEN/GITHUB_TOKEN. Model calls are read-only text bridges so kpilot governance remains authoritative."},{id:"chatgpt-codex",name:"ChatGPT subscription through Codex CLI",protocol:"Official Codex CLI",auth:["chatgpt-subscription"],nativeTools:"bridge-limited",streaming:!1,notes:"Uses the official Codex CLI signed in with ChatGPT. It does not treat a ChatGPT subscription as an API key."},{id:"kpilot-hosted",name:"kpilot hosted models",protocol:"POST /v1/ai/responses",auth:["kpilot-account"],nativeTools:!0,streaming:"buffered-fallback",defaultBaseUrl:"https://api.kpilot.ai",notes:"Automatically routes prompts to a preferred kpilot model unless a route or model is selected."},{id:"external-agent",name:"Bring-your-own agent",protocol:"kpilot Agent Protocol v1 over HTTP or stdio",auth:["none","bearer-token","external"],nativeTools:!0,streaming:"buffered-fallback",notes:"Runs an operator-provided agent executable or HTTP service."}];function Ee(t){let e=Vr.find(n=>n.id===t);if(!e)throw new Error(`Unknown model provider: ${t}`);return e}async function Di(t,e){return t.length?await new Promise((n,o)=>{let r=Ii(t[0],t.slice(1),{cwd:e,env:process.env,stdio:["ignore","pipe","pipe"]}),s="",i="";r.stdout?.on("data",a=>{s+=String(a)}),r.stderr?.on("data",a=>{i+=String(a)}),r.on("error",o),r.on("close",a=>{a===0?n(s.trim()):o(new Error(`${t.join(" ")} exited with code ${a}: ${i.trim()}`))})}):""}async function ji(t){if(t.accessToken)return t.accessToken;if(t.credentialCommand?.length)return await Di(t.credentialCommand,t.rootDir)}function V(t,e){if(!t)throw new Error(e);return t}async function Ct(t){let e=t.provider??"openai-compatible",n=Ee(e),o=t.model||(e==="github-copilot"||e==="chatgpt-codex"||e==="kpilot-hosted"||e==="external-agent"?"auto":"");if(!o)throw new Error(`A model is required for provider ${e}.`);let r=await ji(t),s;switch(e){case"openai-compatible":s=new ze({baseUrl:t.baseUrl??"https://api.openai.com/v1",model:o,apiKey:t.apiKey??r,headers:t.headers,providerBody:t.providerBody,streaming:t.streaming,timeoutMs:t.timeoutMs,retries:t.retries,maxOutputTokens:t.maxOutputTokens});break;case"openai-responses":s=new ge({baseUrl:t.baseUrl??n.defaultBaseUrl,model:o,apiKey:t.apiKey,accessToken:r,headers:t.headers,timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break;case"anthropic":s=new qe({baseUrl:t.baseUrl,model:o,apiKey:V(t.apiKey,"ANTHROPIC_API_KEY is required."),timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break;case"gemini":s=new Te({baseUrl:t.baseUrl,model:o,apiKey:t.apiKey,accessToken:r,timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break;case"xai":s=new ge({baseUrl:t.baseUrl??n.defaultBaseUrl,model:o,apiKey:V(t.apiKey,"XAI_API_KEY is required."),timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break;case"mistral":s=new ze({baseUrl:t.baseUrl??n.defaultBaseUrl,model:o,apiKey:V(t.apiKey,"MISTRAL_API_KEY is required."),headers:t.headers,streaming:t.streaming,timeoutMs:t.timeoutMs,retries:t.retries,maxOutputTokens:t.maxOutputTokens});break;case"cohere":s=new Fe({baseUrl:t.baseUrl,model:o,apiKey:V(t.apiKey,"COHERE_API_KEY is required."),timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break;case"aws-bedrock":s=new Je({baseUrl:t.baseUrl,model:o,region:V(t.region,"AWS region is required."),accessKeyId:V(t.awsAccessKeyId,"AWS_ACCESS_KEY_ID is required."),secretAccessKey:V(t.awsSecretAccessKey,"AWS_SECRET_ACCESS_KEY is required."),sessionToken:t.awsSessionToken,timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break;case"google-vertex":s=new Te({baseUrl:t.baseUrl,model:o,accessToken:V(r,"Google OAuth access token is required."),project:V(t.project,"Google Cloud project is required."),location:V(t.location,"Vertex AI location is required."),vertex:!0,timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break;case"azure-openai":{let i=V(t.baseUrl,"Azure OpenAI base URL ending in /openai/v1 is required."),a=t.apiKey?{"api-key":t.apiKey,...t.headers}:t.headers;s=new ge({baseUrl:i,model:o,accessToken:r,headers:a,timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break}case"kpilot-hosted":s=new He({baseUrl:t.baseUrl??n.defaultBaseUrl,accessToken:V(r??t.accessToken,"kpilot account access token is required."),route:t.route??(o==="auto"?"auto":void 0),model:o==="auto"?void 0:o,timeoutMs:t.timeoutMs,headers:t.headers,getAccessToken:t.getAccessToken});break;case"external-agent":s=new We({command:t.command,args:t.commandArgs,endpoint:t.endpoint??t.baseUrl,accessToken:r??t.accessToken??t.apiKey,rootDir:t.rootDir,timeoutMs:t.timeoutMs});break;case"github-copilot":s=new Ke({command:t.command??"copilot",model:o==="default"?void 0:o,rootDir:t.rootDir??process.cwd(),timeoutMs:t.timeoutMs});break;case"chatgpt-codex":s=new Ge({command:t.command??"codex",model:o==="default"?void 0:o,rootDir:t.rootDir??process.cwd(),timeoutMs:t.timeoutMs});break}return{gateway:s,provider:n,resolvedConfig:{...t,provider:e,model:o}}}function gn(t){let e=t?.prompt_tokens_details?.cached_tokens;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0}function Ui(t){return t.replace(/\/+$/,"")}function Yr(t,e){return e?.aborted?Promise.reject(Ve(e.reason)):new Promise((n,o)=>{let s=setTimeout(()=>{e?.removeEventListener("abort",i),n()},t),i=()=>{clearTimeout(s),e?.removeEventListener("abort",i),o(Ve(e?.reason))};e?.addEventListener("abort",i,{once:!0})})}function Ve(t){let e=typeof t=="string"&&t.trim()?`: ${t}`:"",n=new Error(`Model request cancelled${e}`);return n.name="AbortError",n}function Li(t){return ie(t).map(e=>e.role==="assistant"?{role:"assistant",content:e.content,...e.tool_calls?{tool_calls:e.tool_calls}:{}}:e.role==="tool"?{role:"tool",tool_call_id:e.tool_call_id,content:e.content}:{role:e.role,content:e.content})}function Ni(t){let e=t.choices?.[0]?.message;if(!e)throw new Error(t.error?.message??"The model response did not contain an assistant message.");let n=e.tool_calls?.map((o,r)=>{if(!o.function?.name)throw new Error(`Tool call ${r+1} is missing a function name.`);return{id:o.id??`tool_call_${r+1}`,type:"function",function:{name:o.function.name,arguments:o.function.arguments??"{}"}}});return{role:"assistant",content:typeof e.content=="string"?e.content:null,...n?.length?{tool_calls:n}:{}}}function Qr(t,e){let n=new AbortController,o=setTimeout(()=>n.abort("request timeout"),t),r=()=>n.abort(e?.reason);return e?.aborted?n.abort(e.reason):e?.addEventListener("abort",r,{once:!0}),{controller:n,cleanup:()=>{clearTimeout(o),e?.removeEventListener("abort",r)}}}function Xr(t,e){if(t instanceof Error&&t.name==="AbortError")return t;let n=t instanceof Error?t.message:String(t);return/fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENOTFOUND|network/i.test(n)?new Error(`Model hub unreachable at ${e} (${n}). Check that llama-server/Cockpit is still running.`):t instanceof Error?t:new Error(n)}function Bi(t){return!/unreachable|fetch failed|ECONNREFUSED|ECONNRESET|ENOTFOUND/i.test(t.message)}var ze=class{options;constructor(e){if(!e.model.trim())throw new Error("A model name is required.");this.options={...e,baseUrl:Ui(e.baseUrl),model:e.model,timeoutMs:e.timeoutMs??12e4,retries:e.retries??2,streaming:e.streaming??!0}}async complete(e,n={}){return this.options.streaming&&n.onTextDelta?await this.completeStreaming(e,n):await this.completeBuffered(e,n)}requestBody(e,n){return{model:this.options.model,messages:Li(e.messages),tools:e.tools,tool_choice:"auto",...this.options.maxOutputTokens===void 0?{}:{max_tokens:this.options.maxOutputTokens},...n?{stream:!0,stream_options:{include_usage:!0}}:{},...this.options.providerBody&&Object.keys(this.options.providerBody).length>0?{provider:this.options.providerBody}:{}}}requestHeaders(){return{"content-type":"application/json",...this.options.apiKey?{authorization:`Bearer ${this.options.apiKey}`}:{},...this.options.headers}}async completeBuffered(e,n){let o;for(let r=0;r<=this.options.retries;r+=1){let s=Qr(this.options.timeoutMs,n.signal);try{let i=await fetch(`${this.options.baseUrl}/chat/completions`,{method:"POST",signal:s.controller.signal,headers:this.requestHeaders(),body:JSON.stringify(this.requestBody(e,!1))}),a=await i.text(),c;try{c=JSON.parse(a)}catch{throw new Error(`Model endpoint returned non-JSON data (HTTP ${i.status}): ${a.slice(0,500)}`)}if(!i.ok){let u=c.error?.message??`HTTP ${i.status}`;if((i.status===408||i.status===409||i.status===429||i.status>=500)&&r<this.options.retries){await Yr(500*2**r,n.signal);continue}throw new Error(`Model request failed: ${u}`)}let l=c.choices?.[0]?.message?.reasoning_content;return l&&n.onReasoningDelta&&await n.onReasoningDelta(l),{message:Ni(c),model:c.model,usage:{inputTokens:c.usage?.prompt_tokens,outputTokens:c.usage?.completion_tokens,...gn(c.usage)===void 0?{}:{cacheReadTokens:gn(c.usage)}}}}catch(i){if(o=n.signal?.aborted?Ve(n.signal.reason):Xr(i,this.options.baseUrl),o.name==="AbortError")break;if(r<this.options.retries&&Bi(o)){await Yr(500*2**r,n.signal);continue}break}finally{s.cleanup()}}throw o??new Error("Model request failed for an unknown reason.")}async completeStreaming(e,n){let o=Qr(this.options.timeoutMs,n.signal);try{let r=await fetch(`${this.options.baseUrl}/chat/completions`,{method:"POST",signal:o.controller.signal,headers:this.requestHeaders(),body:JSON.stringify(this.requestBody(e,!0))});if(!r.ok){let h=await r.text(),w=`HTTP ${r.status}`;try{w=JSON.parse(h).error?.message??w}catch{h&&(w=h.slice(0,500))}throw new Error(`Model request failed: ${w}`)}if(!r.body)throw new Error("Model endpoint returned no streaming response body.");let s=r.body.getReader(),i=new TextDecoder,a="",c="",l="",u,d,p,b,f=new Map,y=async h=>{let w=h.trim();if(!w||w.startsWith(":")||!w.startsWith("data:"))return!1;let k=w.slice(5).trim();if(k==="[DONE]")return!0;let C;try{C=JSON.parse(k)}catch{throw new Error(`Invalid streaming JSON chunk: ${k.slice(0,300)}`)}if(C.error?.message)throw new Error(`Model request failed: ${C.error.message}`);u=C.model??u,d=C.usage?.prompt_tokens??d,p=C.usage?.completion_tokens??p,b=gn(C.usage)??b;let S=C.choices?.[0]?.delta;typeof S?.content=="string"&&S.content&&(c+=S.content,await n.onTextDelta?.(S.content)),typeof S?.reasoning_content=="string"&&S.reasoning_content&&(l+=S.reasoning_content,await n.onReasoningDelta?.(S.reasoning_content));for(let A of S?.tool_calls??[]){let se=A.index??f.size,le=f.get(se)??{id:A.id??`tool_call_${se+1}`,type:"function",function:{name:"",arguments:""}};A.id&&(le.id=A.id),A.function?.name&&(le.function.name+=A.function.name),A.function?.arguments&&(le.function.arguments+=A.function.arguments),f.set(se,le)}return!1},m=!1;for(;!m;){if(n.signal?.aborted)throw Ve(n.signal.reason);let h=await s.read();a+=i.decode(h.value??new Uint8Array,{stream:!h.done});let w=a.split(/\r?\n/);a=w.pop()??"";for(let k of w)if(await y(k)){m=!0;break}if(h.done){a.trim()&&await y(a);break}}let g=[...f.entries()].sort(([h],[w])=>h-w).map(([,h],w)=>{if(!h.function.name)throw new Error(`Streaming tool call ${w+1} is missing a function name.`);return h});return{message:{role:"assistant",content:c||null,...g.length?{tool_calls:g}:{}},model:u,usage:{inputTokens:d,outputTokens:p,...b===void 0?{}:{cacheReadTokens:b}}}}catch(r){throw n.signal?.aborted?Ve(n.signal.reason):Xr(r,this.options.baseUrl)}finally{o.cleanup()}}};var he=["fast","balanced","complex","reasoning","large-context","vision","security"];function Ye(t){return he.includes(t)}var qi=[{route:"vision",score:8,words:["image","screenshot","diagram","visual","ui mockup","photo","video","multimodal"]},{route:"security",score:7,words:["security","security audit","vulnerability","vulnerabilities","threat model","penetration test","xss","csrf","sql injection","authentication bypass","authorization bypass","cryptography","secret leak","owasp"]},{route:"reasoning",score:6,words:["prove","root cause","deep analysis","formal","algorithm","optimize","concurrency","race condition","distributed","debug complex"]},{route:"complex",score:5,words:["architecture","migration","repository-wide","large refactor","multi-service","implement feature","production-ready","redesign","framework upgrade"]},{route:"balanced",score:3,words:["fix","refactor","test","review","implement","bug","api","database","typescript"]},{route:"fast",score:2,words:["rename","explain","summarize","format","typo","comment","small change","documentation"]}];function hn(t,e={}){return e.hasImages?{route:"vision",confidence:.99,reason:"The request includes image input."}:(e.estimatedContextTokens??0)>=18e4||t.length>=8e4?{route:"large-context",confidence:.96,reason:"The request requires an unusually large context window."}:null}function Rt(t,e={}){let n=hn(t,e);if(n)return n;let o=t.toLowerCase(),r=new Map;for(let l of qi)for(let u of l.words)o.includes(u)&&r.set(l.route,(r.get(l.route)??0)+l.score);t.length>12e3&&r.set("large-context",(r.get("large-context")??0)+5),t.length>3e3&&r.set("complex",(r.get("complex")??0)+2),/\b(one[- ]?liner|quick|simple|minor)\b/.test(o)&&r.set("fast",(r.get("fast")??0)+3);let s=[...r.entries()].sort((l,u)=>u[1]-l[1]),i=s[0];if(!i)return{route:"balanced",confidence:.55,reason:"No specialist signal was strong enough; using the balanced coding model."};let a=s[1]?.[1]??0,c=Math.min(.98,.58+Math.max(0,i[1]-a)*.05);return{route:i[0],confidence:c,reason:`Prompt signals matched the ${i[0]} route.`}}import{spawn as Gi}from"node:child_process";var Zr="2025-11-25",eo=new Set([Zr,"2025-06-18","2025-03-26"]);function W(t,e){if(!t||typeof t!="object"||Array.isArray(t))throw new Error(`${e} must be an object.`);return t}function Mt(t){return t.replace(/[^a-zA-Z0-9_-]/g,"_").replace(/^_+|_+$/g,"")||"unnamed"}function to(t){if(!t)return"[MCP tool returned no result]";let e=W(t,"MCP tool result"),n=e.content;if(!Array.isArray(n))return JSON.stringify(t,null,2);let o=[];for(let r of n){if(!r||typeof r!="object"||Array.isArray(r))continue;let s=r;s.type==="text"&&typeof s.text=="string"?o.push(s.text):o.push(JSON.stringify(s))}return e.structuredContent!==void 0&&o.push(JSON.stringify(e.structuredContent,null,2)),o.join(`
101
- `)||JSON.stringify(t,null,2)}var wn=class{name;config;child;nextId=1;buffer="";pending=new Map;initialized=!1;serverInfo={};constructor(e,n){if(!n.command.trim())throw new Error(`MCP server ${e} requires a command.`);this.name=Mt(e),this.config={...n,args:n.args??[],timeoutMs:n.timeoutMs??3e4,enabled:n.enabled??!0}}async connect(e){if(this.initialized)return;if(!this.config.enabled)throw new Error(`MCP server ${this.name} is disabled.`);this.child=Gi(this.config.command,this.config.args,{cwd:this.config.cwd,env:{...process.env,...this.config.env},stdio:["pipe","pipe","pipe"]}),this.child.stdout.setEncoding("utf8"),this.child.stderr.setEncoding("utf8"),this.child.stdout.on("data",r=>this.consume(r)),this.child.stderr.on("data",r=>{}),this.child.once("error",r=>this.failAll(r)),this.child.once("close",r=>{this.initialized=!1,this.failAll(new Error(`MCP server ${this.name} exited with code ${r??1}.`))});let n=W(await this.request("initialize",{protocolVersion:Zr,capabilities:{},clientInfo:{name:"kpilot",title:"kpilot",version:"0.10.8",description:"Local-first AI coding agent"}},e),"MCP initialize result"),o=typeof n.protocolVersion=="string"?n.protocolVersion:"";if(!eo.has(o))throw await this.close(),new Error(`MCP server ${this.name} negotiated unsupported protocol version ${o||"[missing]"}.`);this.serverInfo=W(n.serverInfo,"MCP serverInfo"),this.notify("notifications/initialized",{}),this.initialized=!0}consume(e){this.buffer+=e;let n=this.buffer.split(/\r?\n/);this.buffer=n.pop()??"";for(let o of n){if(!o.trim())continue;let r;try{r=JSON.parse(o)}catch{this.failAll(new Error(`MCP server ${this.name} emitted invalid JSON on stdout.`));continue}if(r.id!==void 0&&(r.result!==void 0||r.error)){let s=this.pending.get(r.id);if(!s)continue;clearTimeout(s.timeout),this.pending.delete(r.id),r.error?s.reject(new Error(`MCP ${this.name}: ${r.error.message??`error ${r.error.code??"unknown"}`}`)):s.resolve(r.result??null)}else r.id!==void 0&&r.method&&this.write({jsonrpc:"2.0",id:r.id,error:{code:-32601,message:`Client method not supported: ${r.method}`}})}}write(e){if(!this.child?.stdin?.writable)throw new Error(`MCP server ${this.name} is not connected.`);this.child.stdin.write(`${JSON.stringify(e)}
102
- `)}notify(e,n){this.write({jsonrpc:"2.0",method:e,params:n})}async request(e,n,o){if(o?.aborted)throw new Error(`MCP request cancelled: ${String(o.reason??"")}`);let r=this.nextId++;return await new Promise((s,i)=>{let a=setTimeout(()=>{this.pending.delete(r),this.notify("notifications/cancelled",{requestId:r,reason:"timeout"}),i(new Error(`MCP ${this.name} request timed out: ${e}`))},this.config.timeoutMs),c=()=>{clearTimeout(a),this.pending.delete(r);try{this.notify("notifications/cancelled",{requestId:r,reason:"user cancellation"})}catch{}i(new Error(`MCP request cancelled: ${e}`))};o?.addEventListener("abort",c,{once:!0}),this.pending.set(r,{resolve:l=>{o?.removeEventListener("abort",c),s(l)},reject:l=>{o?.removeEventListener("abort",c),i(l)},timeout:a});try{this.write({jsonrpc:"2.0",id:r,method:e,params:n})}catch(l){clearTimeout(a),this.pending.delete(r),i(l instanceof Error?l:new Error(String(l)))}})}async listTools(e){await this.connect(e);let n=[],o;do{let r=W(await this.request("tools/list",o?{cursor:o}:{},e),"MCP tools/list result"),s=r.tools;if(!Array.isArray(s))throw new Error(`MCP server ${this.name} returned an invalid tool list.`);for(let i of s){let a=W(i,"MCP tool");if(typeof a.name!="string")throw new Error(`MCP server ${this.name} returned a tool without a name.`);n.push({name:a.name,title:typeof a.title=="string"?a.title:void 0,description:typeof a.description=="string"?a.description:void 0,inputSchema:W(a.inputSchema,`MCP inputSchema for ${a.name}`)})}o=typeof r.nextCursor=="string"?r.nextCursor:void 0}while(o);return n}async callTool(e,n,o){await this.connect(o);let r=await this.request("tools/call",{name:e,arguments:n},o);return{ok:W(r,"MCP tools/call result").isError!==!0,output:to(r),metadata:{server:this.name,tool:e}}}info(){return{name:this.name,serverInfo:this.serverInfo,connected:this.initialized}}failAll(e){for(let n of this.pending.values())clearTimeout(n.timeout),n.reject(e);this.pending.clear()}async close(){if(!this.child)return;let e=this.child;this.child=void 0,this.initialized=!1,await new Promise(n=>{let o=!1,r=()=>{o||(o=!0,clearTimeout(s),clearTimeout(i),clearTimeout(a),n())};e.once("close",r),e.stdin?.end();let s=setTimeout(()=>e.kill("SIGTERM"),300),i=setTimeout(()=>e.kill("SIGKILL"),900),a=setTimeout(r,1200)})}},yn=class{name;config;url;nextId=1;pending=new Map;initialized=!1;serverInfo={};constructor(e,n){if(!n.url?.trim())throw new Error(`MCP server ${e} requires url for ${n.transport??"http"} transport.`);let o=new URL(n.url);if(o.protocol!=="http:"&&o.protocol!=="https:")throw new Error(`MCP server ${e} http transport requires an http(s) url; got ${o.protocol}`);this.name=Mt(e),this.config={...n,timeoutMs:n.timeoutMs??3e4},this.url=o.href}headers(){return{"Content-Type":"application/json",Accept:"application/json, text/event-stream","MCP-Protocol-Version":"2025-06-18",...this.config.token?{Authorization:`Bearer ${this.config.token}`}:{},...this.config.headers}}async connect(e){if(this.initialized)return;if(this.config.enabled===!1)throw new Error(`MCP server ${this.name} is disabled.`);let n=W(await this.request("initialize",{protocolVersion:"2025-06-18",capabilities:{},clientInfo:{name:"kpilot",title:"kpilot",version:"0.10.8",description:"Local-first AI coding agent"}},e),"MCP initialize result"),o=typeof n.protocolVersion=="string"?n.protocolVersion:"";if(!eo.has(o))throw new Error(`MCP server ${this.name} negotiated unsupported protocol version ${o||"[missing]"}.`);this.serverInfo=W(n.serverInfo,"MCP serverInfo"),this.notify("notifications/initialized",{}),this.initialized=!0}async request(e,n,o){if(o?.aborted)throw new Error(`MCP request cancelled: ${String(o.reason??"")}`);let r=this.nextId++;return await new Promise((s,i)=>{let a=setTimeout(()=>{this.pending.delete(r),this.notify("notifications/cancelled",{requestId:r,reason:"timeout"}),i(new Error(`MCP ${this.name} request timed out: ${e}`))},this.config.timeoutMs),c=()=>{clearTimeout(a),this.pending.delete(r);try{this.notify("notifications/cancelled",{requestId:r,reason:"user cancellation"})}catch{}i(new Error(`MCP request cancelled: ${e}`))};o?.addEventListener("abort",c,{once:!0});let l=u=>{o?.removeEventListener("abort",c),u()};this.pending.set(r,{resolve:u=>l(()=>s(u)),reject:u=>l(()=>i(u)),timer:a}),this.postBody({jsonrpc:"2.0",id:r,method:e,params:n}).then(u=>this.consumeResponse(u)).catch(u=>{let d=this.pending.get(r);d&&(clearTimeout(d.timer),this.pending.delete(r),l(()=>i(u instanceof Error?u:new Error(String(u)))))})})}notify(e,n){return this.postBody({jsonrpc:"2.0",method:e,params:n}).then(o=>{o?.body?.cancel().catch(()=>{})}).catch(()=>{})}async postBody(e){return await fetch(this.url,{method:"POST",headers:this.headers(),body:JSON.stringify(e),signal:AbortSignal.timeout(this.config.timeoutMs)})}async consumeResponse(e){let n=e.headers.get("content-type")??"";n.includes("text/event-stream")?await this.consumeSse(e):n.includes("application/json")?await this.consumeJson(e):await e.body?.cancel().catch(()=>{})}async consumeSse(e){if(!e.body)return;let n=e.body.getReader(),o=new TextDecoder,r="";for(;;){let{done:s,value:i}=await n.read();if(s)break;r+=o.decode(i,{stream:!0});let a=r.indexOf(`
100
+ `)})}};import{spawn as Ii}from"node:child_process";var Vr=[{id:"openai-compatible",name:"OpenAI-compatible Chat Completions",protocol:"POST /v1/chat/completions",auth:["none","api-key","bearer-token"],nativeTools:!0,streaming:!0},{id:"openai-responses",name:"OpenAI Responses API",protocol:"POST /v1/responses",auth:["api-key","bearer-token"],nativeTools:!0,streaming:"buffered-fallback",defaultBaseUrl:"https://api.openai.com/v1"},{id:"anthropic",name:"Anthropic Claude API",protocol:"POST /v1/messages",auth:["api-key"],nativeTools:!0,streaming:"buffered-fallback",defaultBaseUrl:"https://api.anthropic.com"},{id:"gemini",name:"Google Gemini Developer API",protocol:"models.generateContent",auth:["api-key"],nativeTools:!0,streaming:"buffered-fallback",defaultBaseUrl:"https://generativelanguage.googleapis.com/v1beta"},{id:"xai",name:"xAI Inference API",protocol:"POST /v1/responses",auth:["api-key"],nativeTools:!0,streaming:"buffered-fallback",defaultBaseUrl:"https://api.x.ai/v1"},{id:"mistral",name:"Mistral AI API",protocol:"POST /v1/chat/completions",auth:["api-key"],nativeTools:!0,streaming:!0,defaultBaseUrl:"https://api.mistral.ai/v1"},{id:"cohere",name:"Cohere v2 Chat API",protocol:"POST /v2/chat",auth:["api-key"],nativeTools:!0,streaming:"buffered-fallback",defaultBaseUrl:"https://api.cohere.com"},{id:"aws-bedrock",name:"Amazon Bedrock Converse API",protocol:"Converse",auth:["aws-sigv4"],nativeTools:!0,streaming:"buffered-fallback"},{id:"google-vertex",name:"Google Vertex AI",protocol:"publishers/google/models:generateContent",auth:["bearer-token"],nativeTools:!0,streaming:"buffered-fallback"},{id:"azure-openai",name:"Azure OpenAI v1 Responses API",protocol:"POST /openai/v1/responses",auth:["api-key","bearer-token"],nativeTools:!0,streaming:"buffered-fallback"},{id:"github-copilot",name:"GitHub Copilot subscription bridge",protocol:"Official Copilot CLI",auth:["github-subscription"],nativeTools:"bridge-limited",streaming:!1,notes:"Uses copilot login or COPILOT_GITHUB_TOKEN/GH_TOKEN/GITHUB_TOKEN. Model calls are read-only text bridges so kpilot governance remains authoritative."},{id:"chatgpt-codex",name:"ChatGPT subscription through Codex CLI",protocol:"Official Codex CLI",auth:["chatgpt-subscription"],nativeTools:"bridge-limited",streaming:!1,notes:"Uses the official Codex CLI signed in with ChatGPT. It does not treat a ChatGPT subscription as an API key."},{id:"kpilot-hosted",name:"kpilot hosted models",protocol:"POST /v1/ai/responses",auth:["kpilot-account"],nativeTools:!0,streaming:"buffered-fallback",defaultBaseUrl:"https://api.konsolepilot.ai",notes:"Automatically routes prompts to a preferred kpilot model unless a route or model is selected."},{id:"external-agent",name:"Bring-your-own agent",protocol:"kpilot Agent Protocol v1 over HTTP or stdio",auth:["none","bearer-token","external"],nativeTools:!0,streaming:"buffered-fallback",notes:"Runs an operator-provided agent executable or HTTP service."}];function Ee(t){let e=Vr.find(n=>n.id===t);if(!e)throw new Error(`Unknown model provider: ${t}`);return e}async function Di(t,e){return t.length?await new Promise((n,o)=>{let r=Ii(t[0],t.slice(1),{cwd:e,env:process.env,stdio:["ignore","pipe","pipe"]}),s="",i="";r.stdout?.on("data",a=>{s+=String(a)}),r.stderr?.on("data",a=>{i+=String(a)}),r.on("error",o),r.on("close",a=>{a===0?n(s.trim()):o(new Error(`${t.join(" ")} exited with code ${a}: ${i.trim()}`))})}):""}async function ji(t){if(t.accessToken)return t.accessToken;if(t.credentialCommand?.length)return await Di(t.credentialCommand,t.rootDir)}function V(t,e){if(!t)throw new Error(e);return t}async function Ct(t){let e=t.provider??"openai-compatible",n=Ee(e),o=t.model||(e==="github-copilot"||e==="chatgpt-codex"||e==="kpilot-hosted"||e==="external-agent"?"auto":"");if(!o)throw new Error(`A model is required for provider ${e}.`);let r=await ji(t),s;switch(e){case"openai-compatible":s=new ze({baseUrl:t.baseUrl??"https://api.openai.com/v1",model:o,apiKey:t.apiKey??r,headers:t.headers,providerBody:t.providerBody,streaming:t.streaming,timeoutMs:t.timeoutMs,retries:t.retries,maxOutputTokens:t.maxOutputTokens});break;case"openai-responses":s=new ge({baseUrl:t.baseUrl??n.defaultBaseUrl,model:o,apiKey:t.apiKey,accessToken:r,headers:t.headers,timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break;case"anthropic":s=new qe({baseUrl:t.baseUrl,model:o,apiKey:V(t.apiKey,"ANTHROPIC_API_KEY is required."),timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break;case"gemini":s=new Te({baseUrl:t.baseUrl,model:o,apiKey:t.apiKey,accessToken:r,timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break;case"xai":s=new ge({baseUrl:t.baseUrl??n.defaultBaseUrl,model:o,apiKey:V(t.apiKey,"XAI_API_KEY is required."),timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break;case"mistral":s=new ze({baseUrl:t.baseUrl??n.defaultBaseUrl,model:o,apiKey:V(t.apiKey,"MISTRAL_API_KEY is required."),headers:t.headers,streaming:t.streaming,timeoutMs:t.timeoutMs,retries:t.retries,maxOutputTokens:t.maxOutputTokens});break;case"cohere":s=new Fe({baseUrl:t.baseUrl,model:o,apiKey:V(t.apiKey,"COHERE_API_KEY is required."),timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break;case"aws-bedrock":s=new Je({baseUrl:t.baseUrl,model:o,region:V(t.region,"AWS region is required."),accessKeyId:V(t.awsAccessKeyId,"AWS_ACCESS_KEY_ID is required."),secretAccessKey:V(t.awsSecretAccessKey,"AWS_SECRET_ACCESS_KEY is required."),sessionToken:t.awsSessionToken,timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break;case"google-vertex":s=new Te({baseUrl:t.baseUrl,model:o,accessToken:V(r,"Google OAuth access token is required."),project:V(t.project,"Google Cloud project is required."),location:V(t.location,"Vertex AI location is required."),vertex:!0,timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break;case"azure-openai":{let i=V(t.baseUrl,"Azure OpenAI base URL ending in /openai/v1 is required."),a=t.apiKey?{"api-key":t.apiKey,...t.headers}:t.headers;s=new ge({baseUrl:i,model:o,accessToken:r,headers:a,timeoutMs:t.timeoutMs,maxOutputTokens:t.maxOutputTokens});break}case"kpilot-hosted":s=new He({baseUrl:t.baseUrl??n.defaultBaseUrl,accessToken:V(r??t.accessToken,"kpilot account access token is required."),route:t.route??(o==="auto"?"auto":void 0),model:o==="auto"?void 0:o,timeoutMs:t.timeoutMs,headers:t.headers,getAccessToken:t.getAccessToken});break;case"external-agent":s=new We({command:t.command,args:t.commandArgs,endpoint:t.endpoint??t.baseUrl,accessToken:r??t.accessToken??t.apiKey,rootDir:t.rootDir,timeoutMs:t.timeoutMs});break;case"github-copilot":s=new Ke({command:t.command??"copilot",model:o==="default"?void 0:o,rootDir:t.rootDir??process.cwd(),timeoutMs:t.timeoutMs});break;case"chatgpt-codex":s=new Ge({command:t.command??"codex",model:o==="default"?void 0:o,rootDir:t.rootDir??process.cwd(),timeoutMs:t.timeoutMs});break}return{gateway:s,provider:n,resolvedConfig:{...t,provider:e,model:o}}}function gn(t){let e=t?.prompt_tokens_details?.cached_tokens;return typeof e=="number"&&Number.isFinite(e)&&e>=0?e:void 0}function Ui(t){return t.replace(/\/+$/,"")}function Yr(t,e){return e?.aborted?Promise.reject(Ve(e.reason)):new Promise((n,o)=>{let s=setTimeout(()=>{e?.removeEventListener("abort",i),n()},t),i=()=>{clearTimeout(s),e?.removeEventListener("abort",i),o(Ve(e?.reason))};e?.addEventListener("abort",i,{once:!0})})}function Ve(t){let e=typeof t=="string"&&t.trim()?`: ${t}`:"",n=new Error(`Model request cancelled${e}`);return n.name="AbortError",n}function Li(t){return ie(t).map(e=>e.role==="assistant"?{role:"assistant",content:e.content,...e.tool_calls?{tool_calls:e.tool_calls}:{}}:e.role==="tool"?{role:"tool",tool_call_id:e.tool_call_id,content:e.content}:{role:e.role,content:e.content})}function Ni(t){let e=t.choices?.[0]?.message;if(!e)throw new Error(t.error?.message??"The model response did not contain an assistant message.");let n=e.tool_calls?.map((o,r)=>{if(!o.function?.name)throw new Error(`Tool call ${r+1} is missing a function name.`);return{id:o.id??`tool_call_${r+1}`,type:"function",function:{name:o.function.name,arguments:o.function.arguments??"{}"}}});return{role:"assistant",content:typeof e.content=="string"?e.content:null,...n?.length?{tool_calls:n}:{}}}function Qr(t,e){let n=new AbortController,o=setTimeout(()=>n.abort("request timeout"),t),r=()=>n.abort(e?.reason);return e?.aborted?n.abort(e.reason):e?.addEventListener("abort",r,{once:!0}),{controller:n,cleanup:()=>{clearTimeout(o),e?.removeEventListener("abort",r)}}}function Xr(t,e){if(t instanceof Error&&t.name==="AbortError")return t;let n=t instanceof Error?t.message:String(t);return/fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|ENOTFOUND|network/i.test(n)?new Error(`Model hub unreachable at ${e} (${n}). Check that llama-server/Cockpit is still running.`):t instanceof Error?t:new Error(n)}function Bi(t){return!/unreachable|fetch failed|ECONNREFUSED|ECONNRESET|ENOTFOUND/i.test(t.message)}var ze=class{options;constructor(e){if(!e.model.trim())throw new Error("A model name is required.");this.options={...e,baseUrl:Ui(e.baseUrl),model:e.model,timeoutMs:e.timeoutMs??12e4,retries:e.retries??2,streaming:e.streaming??!0}}async complete(e,n={}){return this.options.streaming&&n.onTextDelta?await this.completeStreaming(e,n):await this.completeBuffered(e,n)}requestBody(e,n){return{model:this.options.model,messages:Li(e.messages),tools:e.tools,tool_choice:"auto",...this.options.maxOutputTokens===void 0?{}:{max_tokens:this.options.maxOutputTokens},...n?{stream:!0,stream_options:{include_usage:!0}}:{},...this.options.providerBody&&Object.keys(this.options.providerBody).length>0?{provider:this.options.providerBody}:{}}}requestHeaders(){return{"content-type":"application/json",...this.options.apiKey?{authorization:`Bearer ${this.options.apiKey}`}:{},...this.options.headers}}async completeBuffered(e,n){let o;for(let r=0;r<=this.options.retries;r+=1){let s=Qr(this.options.timeoutMs,n.signal);try{let i=await fetch(`${this.options.baseUrl}/chat/completions`,{method:"POST",signal:s.controller.signal,headers:this.requestHeaders(),body:JSON.stringify(this.requestBody(e,!1))}),a=await i.text(),c;try{c=JSON.parse(a)}catch{throw new Error(`Model endpoint returned non-JSON data (HTTP ${i.status}): ${a.slice(0,500)}`)}if(!i.ok){let u=c.error?.message??`HTTP ${i.status}`;if((i.status===408||i.status===409||i.status===429||i.status>=500)&&r<this.options.retries){await Yr(500*2**r,n.signal);continue}throw new Error(`Model request failed: ${u}`)}let l=c.choices?.[0]?.message?.reasoning_content;return l&&n.onReasoningDelta&&await n.onReasoningDelta(l),{message:Ni(c),model:c.model,usage:{inputTokens:c.usage?.prompt_tokens,outputTokens:c.usage?.completion_tokens,...gn(c.usage)===void 0?{}:{cacheReadTokens:gn(c.usage)}}}}catch(i){if(o=n.signal?.aborted?Ve(n.signal.reason):Xr(i,this.options.baseUrl),o.name==="AbortError")break;if(r<this.options.retries&&Bi(o)){await Yr(500*2**r,n.signal);continue}break}finally{s.cleanup()}}throw o??new Error("Model request failed for an unknown reason.")}async completeStreaming(e,n){let o=Qr(this.options.timeoutMs,n.signal);try{let r=await fetch(`${this.options.baseUrl}/chat/completions`,{method:"POST",signal:o.controller.signal,headers:this.requestHeaders(),body:JSON.stringify(this.requestBody(e,!0))});if(!r.ok){let h=await r.text(),w=`HTTP ${r.status}`;try{w=JSON.parse(h).error?.message??w}catch{h&&(w=h.slice(0,500))}throw new Error(`Model request failed: ${w}`)}if(!r.body)throw new Error("Model endpoint returned no streaming response body.");let s=r.body.getReader(),i=new TextDecoder,a="",c="",l="",u,d,p,b,f=new Map,y=async h=>{let w=h.trim();if(!w||w.startsWith(":")||!w.startsWith("data:"))return!1;let k=w.slice(5).trim();if(k==="[DONE]")return!0;let C;try{C=JSON.parse(k)}catch{throw new Error(`Invalid streaming JSON chunk: ${k.slice(0,300)}`)}if(C.error?.message)throw new Error(`Model request failed: ${C.error.message}`);u=C.model??u,d=C.usage?.prompt_tokens??d,p=C.usage?.completion_tokens??p,b=gn(C.usage)??b;let S=C.choices?.[0]?.delta;typeof S?.content=="string"&&S.content&&(c+=S.content,await n.onTextDelta?.(S.content)),typeof S?.reasoning_content=="string"&&S.reasoning_content&&(l+=S.reasoning_content,await n.onReasoningDelta?.(S.reasoning_content));for(let A of S?.tool_calls??[]){let se=A.index??f.size,le=f.get(se)??{id:A.id??`tool_call_${se+1}`,type:"function",function:{name:"",arguments:""}};A.id&&(le.id=A.id),A.function?.name&&(le.function.name+=A.function.name),A.function?.arguments&&(le.function.arguments+=A.function.arguments),f.set(se,le)}return!1},m=!1;for(;!m;){if(n.signal?.aborted)throw Ve(n.signal.reason);let h=await s.read();a+=i.decode(h.value??new Uint8Array,{stream:!h.done});let w=a.split(/\r?\n/);a=w.pop()??"";for(let k of w)if(await y(k)){m=!0;break}if(h.done){a.trim()&&await y(a);break}}let g=[...f.entries()].sort(([h],[w])=>h-w).map(([,h],w)=>{if(!h.function.name)throw new Error(`Streaming tool call ${w+1} is missing a function name.`);return h});return{message:{role:"assistant",content:c||null,...g.length?{tool_calls:g}:{}},model:u,usage:{inputTokens:d,outputTokens:p,...b===void 0?{}:{cacheReadTokens:b}}}}catch(r){throw n.signal?.aborted?Ve(n.signal.reason):Xr(r,this.options.baseUrl)}finally{o.cleanup()}}};var he=["fast","balanced","complex","reasoning","large-context","vision","security"];function Ye(t){return he.includes(t)}var qi=[{route:"vision",score:8,words:["image","screenshot","diagram","visual","ui mockup","photo","video","multimodal"]},{route:"security",score:7,words:["security","security audit","vulnerability","vulnerabilities","threat model","penetration test","xss","csrf","sql injection","authentication bypass","authorization bypass","cryptography","secret leak","owasp"]},{route:"reasoning",score:6,words:["prove","root cause","deep analysis","formal","algorithm","optimize","concurrency","race condition","distributed","debug complex"]},{route:"complex",score:5,words:["architecture","migration","repository-wide","large refactor","multi-service","implement feature","production-ready","redesign","framework upgrade"]},{route:"balanced",score:3,words:["fix","refactor","test","review","implement","bug","api","database","typescript"]},{route:"fast",score:2,words:["rename","explain","summarize","format","typo","comment","small change","documentation"]}];function hn(t,e={}){return e.hasImages?{route:"vision",confidence:.99,reason:"The request includes image input."}:(e.estimatedContextTokens??0)>=18e4||t.length>=8e4?{route:"large-context",confidence:.96,reason:"The request requires an unusually large context window."}:null}function Rt(t,e={}){let n=hn(t,e);if(n)return n;let o=t.toLowerCase(),r=new Map;for(let l of qi)for(let u of l.words)o.includes(u)&&r.set(l.route,(r.get(l.route)??0)+l.score);t.length>12e3&&r.set("large-context",(r.get("large-context")??0)+5),t.length>3e3&&r.set("complex",(r.get("complex")??0)+2),/\b(one[- ]?liner|quick|simple|minor)\b/.test(o)&&r.set("fast",(r.get("fast")??0)+3);let s=[...r.entries()].sort((l,u)=>u[1]-l[1]),i=s[0];if(!i)return{route:"balanced",confidence:.55,reason:"No specialist signal was strong enough; using the balanced coding model."};let a=s[1]?.[1]??0,c=Math.min(.98,.58+Math.max(0,i[1]-a)*.05);return{route:i[0],confidence:c,reason:`Prompt signals matched the ${i[0]} route.`}}import{spawn as Gi}from"node:child_process";var Zr="2025-11-25",eo=new Set([Zr,"2025-06-18","2025-03-26"]);function W(t,e){if(!t||typeof t!="object"||Array.isArray(t))throw new Error(`${e} must be an object.`);return t}function Mt(t){return t.replace(/[^a-zA-Z0-9_-]/g,"_").replace(/^_+|_+$/g,"")||"unnamed"}function to(t){if(!t)return"[MCP tool returned no result]";let e=W(t,"MCP tool result"),n=e.content;if(!Array.isArray(n))return JSON.stringify(t,null,2);let o=[];for(let r of n){if(!r||typeof r!="object"||Array.isArray(r))continue;let s=r;s.type==="text"&&typeof s.text=="string"?o.push(s.text):o.push(JSON.stringify(s))}return e.structuredContent!==void 0&&o.push(JSON.stringify(e.structuredContent,null,2)),o.join(`
101
+ `)||JSON.stringify(t,null,2)}var wn=class{name;config;child;nextId=1;buffer="";pending=new Map;initialized=!1;serverInfo={};constructor(e,n){if(!n.command.trim())throw new Error(`MCP server ${e} requires a command.`);this.name=Mt(e),this.config={...n,args:n.args??[],timeoutMs:n.timeoutMs??3e4,enabled:n.enabled??!0}}async connect(e){if(this.initialized)return;if(!this.config.enabled)throw new Error(`MCP server ${this.name} is disabled.`);this.child=Gi(this.config.command,this.config.args,{cwd:this.config.cwd,env:{...process.env,...this.config.env},stdio:["pipe","pipe","pipe"]}),this.child.stdout.setEncoding("utf8"),this.child.stderr.setEncoding("utf8"),this.child.stdout.on("data",r=>this.consume(r)),this.child.stderr.on("data",r=>{}),this.child.once("error",r=>this.failAll(r)),this.child.once("close",r=>{this.initialized=!1,this.failAll(new Error(`MCP server ${this.name} exited with code ${r??1}.`))});let n=W(await this.request("initialize",{protocolVersion:Zr,capabilities:{},clientInfo:{name:"kpilot",title:"kpilot",version:"0.10.9",description:"Local-first AI coding agent"}},e),"MCP initialize result"),o=typeof n.protocolVersion=="string"?n.protocolVersion:"";if(!eo.has(o))throw await this.close(),new Error(`MCP server ${this.name} negotiated unsupported protocol version ${o||"[missing]"}.`);this.serverInfo=W(n.serverInfo,"MCP serverInfo"),this.notify("notifications/initialized",{}),this.initialized=!0}consume(e){this.buffer+=e;let n=this.buffer.split(/\r?\n/);this.buffer=n.pop()??"";for(let o of n){if(!o.trim())continue;let r;try{r=JSON.parse(o)}catch{this.failAll(new Error(`MCP server ${this.name} emitted invalid JSON on stdout.`));continue}if(r.id!==void 0&&(r.result!==void 0||r.error)){let s=this.pending.get(r.id);if(!s)continue;clearTimeout(s.timeout),this.pending.delete(r.id),r.error?s.reject(new Error(`MCP ${this.name}: ${r.error.message??`error ${r.error.code??"unknown"}`}`)):s.resolve(r.result??null)}else r.id!==void 0&&r.method&&this.write({jsonrpc:"2.0",id:r.id,error:{code:-32601,message:`Client method not supported: ${r.method}`}})}}write(e){if(!this.child?.stdin?.writable)throw new Error(`MCP server ${this.name} is not connected.`);this.child.stdin.write(`${JSON.stringify(e)}
102
+ `)}notify(e,n){this.write({jsonrpc:"2.0",method:e,params:n})}async request(e,n,o){if(o?.aborted)throw new Error(`MCP request cancelled: ${String(o.reason??"")}`);let r=this.nextId++;return await new Promise((s,i)=>{let a=setTimeout(()=>{this.pending.delete(r),this.notify("notifications/cancelled",{requestId:r,reason:"timeout"}),i(new Error(`MCP ${this.name} request timed out: ${e}`))},this.config.timeoutMs),c=()=>{clearTimeout(a),this.pending.delete(r);try{this.notify("notifications/cancelled",{requestId:r,reason:"user cancellation"})}catch{}i(new Error(`MCP request cancelled: ${e}`))};o?.addEventListener("abort",c,{once:!0}),this.pending.set(r,{resolve:l=>{o?.removeEventListener("abort",c),s(l)},reject:l=>{o?.removeEventListener("abort",c),i(l)},timeout:a});try{this.write({jsonrpc:"2.0",id:r,method:e,params:n})}catch(l){clearTimeout(a),this.pending.delete(r),i(l instanceof Error?l:new Error(String(l)))}})}async listTools(e){await this.connect(e);let n=[],o;do{let r=W(await this.request("tools/list",o?{cursor:o}:{},e),"MCP tools/list result"),s=r.tools;if(!Array.isArray(s))throw new Error(`MCP server ${this.name} returned an invalid tool list.`);for(let i of s){let a=W(i,"MCP tool");if(typeof a.name!="string")throw new Error(`MCP server ${this.name} returned a tool without a name.`);n.push({name:a.name,title:typeof a.title=="string"?a.title:void 0,description:typeof a.description=="string"?a.description:void 0,inputSchema:W(a.inputSchema,`MCP inputSchema for ${a.name}`)})}o=typeof r.nextCursor=="string"?r.nextCursor:void 0}while(o);return n}async callTool(e,n,o){await this.connect(o);let r=await this.request("tools/call",{name:e,arguments:n},o);return{ok:W(r,"MCP tools/call result").isError!==!0,output:to(r),metadata:{server:this.name,tool:e}}}info(){return{name:this.name,serverInfo:this.serverInfo,connected:this.initialized}}failAll(e){for(let n of this.pending.values())clearTimeout(n.timeout),n.reject(e);this.pending.clear()}async close(){if(!this.child)return;let e=this.child;this.child=void 0,this.initialized=!1,await new Promise(n=>{let o=!1,r=()=>{o||(o=!0,clearTimeout(s),clearTimeout(i),clearTimeout(a),n())};e.once("close",r),e.stdin?.end();let s=setTimeout(()=>e.kill("SIGTERM"),300),i=setTimeout(()=>e.kill("SIGKILL"),900),a=setTimeout(r,1200)})}},yn=class{name;config;url;nextId=1;pending=new Map;initialized=!1;serverInfo={};constructor(e,n){if(!n.url?.trim())throw new Error(`MCP server ${e} requires url for ${n.transport??"http"} transport.`);let o=new URL(n.url);if(o.protocol!=="http:"&&o.protocol!=="https:")throw new Error(`MCP server ${e} http transport requires an http(s) url; got ${o.protocol}`);this.name=Mt(e),this.config={...n,timeoutMs:n.timeoutMs??3e4},this.url=o.href}headers(){return{"Content-Type":"application/json",Accept:"application/json, text/event-stream","MCP-Protocol-Version":"2025-06-18",...this.config.token?{Authorization:`Bearer ${this.config.token}`}:{},...this.config.headers}}async connect(e){if(this.initialized)return;if(this.config.enabled===!1)throw new Error(`MCP server ${this.name} is disabled.`);let n=W(await this.request("initialize",{protocolVersion:"2025-06-18",capabilities:{},clientInfo:{name:"kpilot",title:"kpilot",version:"0.10.9",description:"Local-first AI coding agent"}},e),"MCP initialize result"),o=typeof n.protocolVersion=="string"?n.protocolVersion:"";if(!eo.has(o))throw new Error(`MCP server ${this.name} negotiated unsupported protocol version ${o||"[missing]"}.`);this.serverInfo=W(n.serverInfo,"MCP serverInfo"),this.notify("notifications/initialized",{}),this.initialized=!0}async request(e,n,o){if(o?.aborted)throw new Error(`MCP request cancelled: ${String(o.reason??"")}`);let r=this.nextId++;return await new Promise((s,i)=>{let a=setTimeout(()=>{this.pending.delete(r),this.notify("notifications/cancelled",{requestId:r,reason:"timeout"}),i(new Error(`MCP ${this.name} request timed out: ${e}`))},this.config.timeoutMs),c=()=>{clearTimeout(a),this.pending.delete(r);try{this.notify("notifications/cancelled",{requestId:r,reason:"user cancellation"})}catch{}i(new Error(`MCP request cancelled: ${e}`))};o?.addEventListener("abort",c,{once:!0});let l=u=>{o?.removeEventListener("abort",c),u()};this.pending.set(r,{resolve:u=>l(()=>s(u)),reject:u=>l(()=>i(u)),timer:a}),this.postBody({jsonrpc:"2.0",id:r,method:e,params:n}).then(u=>this.consumeResponse(u)).catch(u=>{let d=this.pending.get(r);d&&(clearTimeout(d.timer),this.pending.delete(r),l(()=>i(u instanceof Error?u:new Error(String(u)))))})})}notify(e,n){return this.postBody({jsonrpc:"2.0",method:e,params:n}).then(o=>{o?.body?.cancel().catch(()=>{})}).catch(()=>{})}async postBody(e){return await fetch(this.url,{method:"POST",headers:this.headers(),body:JSON.stringify(e),signal:AbortSignal.timeout(this.config.timeoutMs)})}async consumeResponse(e){let n=e.headers.get("content-type")??"";n.includes("text/event-stream")?await this.consumeSse(e):n.includes("application/json")?await this.consumeJson(e):await e.body?.cancel().catch(()=>{})}async consumeSse(e){if(!e.body)return;let n=e.body.getReader(),o=new TextDecoder,r="";for(;;){let{done:s,value:i}=await n.read();if(s)break;r+=o.decode(i,{stream:!0});let a=r.indexOf(`
103
103
  `);for(;a!==-1;){let c=r.slice(0,a).trim();if(r=r.slice(a+1),c.startsWith("data:")){let l=c.slice(5).trim();l&&this.routeMessage(this.safelyParse(l))}a=r.indexOf(`
104
104
  `)}}}async consumeJson(e){let n=await e.text();n.trim()&&this.routeMessage(this.safelyParse(n))}safelyParse(e){try{return JSON.parse(e)}catch{return null}}routeMessage(e){if(!e||e.id===void 0||typeof e.id!="number"||!("result"in e)&&!e.error)return;let n=this.pending.get(e.id);n&&(clearTimeout(n.timer),this.pending.delete(e.id),e.error?n.reject(new Error(`MCP ${this.name}: ${e.error.message??`error ${e.error.code??"unknown"}`}`)):n.resolve(e.result??null))}async listTools(e){await this.connect(e);let n=[],o;do{let r=W(await this.request("tools/list",o?{cursor:o}:{},e),"MCP tools/list result"),s=r.tools;if(!Array.isArray(s))throw new Error(`MCP server ${this.name} returned an invalid tool list.`);for(let i of s){let a=W(i,"MCP tool");if(typeof a.name!="string")throw new Error(`MCP server ${this.name} returned a tool without a name.`);n.push({name:a.name,title:typeof a.title=="string"?a.title:void 0,description:typeof a.description=="string"?a.description:void 0,inputSchema:W(a.inputSchema,`MCP inputSchema for ${a.name}`)})}o=typeof r.nextCursor=="string"?r.nextCursor:void 0}while(o);return n}async callTool(e,n,o){await this.connect(o);let r=await this.request("tools/call",{name:e,arguments:n},o);return{ok:W(r,"MCP tools/call result").isError!==!0,output:to(r),metadata:{server:this.name,tool:e}}}info(){return{name:this.name,serverInfo:this.serverInfo,connected:this.initialized}}async close(){this.initialized=!1;for(let e of this.pending.values())clearTimeout(e.timer),e.reject(new Error("MCP client closed."));this.pending.clear()}},we=class t{tools=new Map;clients;constructor(e){this.clients=e}static async connect(e,n){let o=Object.entries(e).filter(([,s])=>s.enabled!==!1).map(([s,i])=>(i.transport??"stdio")==="stdio"?new wn(s,i):new yn(s,i)),r=new t(o);for(let s of o){let i=await s.listTools(n);for(let a of i){let c=`mcp_${Mt(s.name)}_${Mt(a.name)}`;if(r.tools.has(c))throw new Error(`Duplicate MCP tool name: ${c}`);r.tools.set(c,{client:s,remoteName:a.name,definition:{type:"function",function:{name:c,description:`[MCP:${s.name}] ${a.description??a.title??a.name}`,parameters:a.inputSchema}}})}}return r}definitions(){return[...this.tools.values()].map(e=>e.definition)}async execute(e,n,o){let r=this.tools.get(e);return r?await r.client.callTool(r.remoteName,n,o.signal):{ok:!1,output:`Unknown MCP tool: ${e}`}}list(){return[...this.tools.entries()].map(([e,n])=>({exposedName:e,server:n.client.name,remoteName:n.remoteName,description:n.definition.function.description}))}async close(){await Promise.all(this.clients.map(e=>e.close()))}};var Hi="2025-11-25",Wi=["2025-11-25","2025-06-18","2025-03-26"];function zi(t){return t.map(e=>({name:e.function.name,description:e.function.description,inputSchema:e.function.parameters??{type:"object",properties:{}}}))}function no(t,e){if(!t||typeof t!="object"||Array.isArray(t))throw new Error(`${e} must be an object.`);return t}var $t=class{name;version;rootDir;mode;runtime;initialized=!1;constructor(e,n){this.runtime=e,this.name=n.name??"kpilot",this.version=n.version??"0.0.0",this.rootDir=n.rootDir,this.mode=n.mode??"write"}async dispatch(e){let n=e.id,o=e.method;if(!(typeof n=="number"||typeof n=="string"))return o==="notifications/initialized"&&(this.initialized=!0),null;let s=no(e.params??{},`${o} params`);try{let i=await this.handleMethod(String(o??""),s);return o==="initialize"&&(this.initialized=!0),{jsonrpc:"2.0",id:n,result:i}}catch(i){let a=i instanceof Error?i.message:String(i);return{jsonrpc:"2.0",id:n,error:{code:o==="tools/call"?-32603:-32601,message:a}}}}async handleMethod(e,n){switch(e){case"initialize":{let o=typeof n.protocolVersion=="string"?n.protocolVersion:"";return{protocolVersion:Wi.includes(o)?o:Hi,capabilities:{tools:{listChanged:!1}},serverInfo:{name:this.name,version:this.version}}}case"ping":return{};case"tools/list":{let o=zi(this.runtime.definitions());return typeof n.cursor=="string"?{tools:[],nextCursor:void 0}:{tools:o}}case"tools/call":{let o=typeof n.name=="string"?n.name:"";if(!o)throw new Error("tools/call requires a name.");let r=no(n.arguments??{},"tools/call arguments"),s={rootDir:this.rootDir,mode:this.mode},i=await this.runtime.execute(o,r,s);return{content:[{type:"text",text:i.output??""}],isError:i.ok!==!0}}default:throw new Error(`Method not found: ${e}`)}}};function ro(t){if(!t.trim())return null;try{let e=JSON.parse(t);return e&&typeof e=="object"&&!Array.isArray(e)?e:null}catch{return null}}async function so(t){await new Promise((e,n)=>{let o="";process.stdin.setEncoding("utf8");let r=(s,i=!1)=>{o+=s;let a=o.indexOf(`
105
105
  `);for(;a!==-1;){let c=o.slice(0,a);o=o.slice(a+1);let l=ro(c);l&&oo(t,l),a=o.indexOf(`
@@ -155,7 +155,7 @@ ${i.task}`,mode:"plan",rootDir:this.options.rootDir,maxSteps:this.options.maxSte
155
155
 
156
156
  `),metadata:{count:s.length,successful:s.filter(i=>i.ok).length,tasks:s.map(i=>({role:i.role,ok:i.ok,...i.route?{route:i.route}:{},...i.model?{model:i.model}:{}}))}}}};import{mkdir as xc,realpath as st,rm as Sc,stat as Pc}from"node:fs/promises";import ce from"node:path";import{spawn as Tc}from"node:child_process";function it(t,e){return new Promise((n,o)=>{let r=Tc("git",e,{cwd:t,stdio:["ignore","pipe","pipe"]}),s="",i="";r.stdout.setEncoding("utf8"),r.stderr.setEncoding("utf8"),r.stdout.on("data",a=>{s+=a}),r.stderr.on("data",a=>{i+=a}),r.once("error",o),r.once("close",a=>n({code:a??1,stdout:s,stderr:i}))})}function Bo(t){let e=t.trim();if(!/^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$/.test(e))throw new Error("Worktree name must use 1\u201364 letters, numbers, dots, underscores, or hyphens.");return e}async function qo(t){try{return await Pc(t),!0}catch{return!1}}var at=class{rootDir;storageDir;constructor(e){this.rootDir=ce.resolve(e),this.storageDir=ce.join(ce.dirname(this.rootDir),`.${ce.basename(this.rootDir)}-kpilot-worktrees`)}async assertRepository(){let e=await it(this.rootDir,["rev-parse","--show-toplevel"]);if(e.code!==0)throw new Error(e.stderr.trim()||"Not a Git repository.");let n=ce.resolve(e.stdout.trim()),o=await st(this.rootDir);if(n!==o)throw new Error(`Use the repository root as --cwd: ${n}`)}pathFor(e){return ce.join(this.storageDir,Bo(e))}async create(e,n={}){await this.assertRepository();let o=Bo(e),r=this.pathFor(o);if(await qo(r))throw new Error(`Worktree path already exists: ${r}`);await xc(this.storageDir,{recursive:!0});let s=n.branch?.trim()||`kpilot/${o}`,i=n.base?.trim()||"HEAD",a=await it(this.rootDir,["worktree","add","-b",s,r,i]);if(a.code!==0)throw new Error(a.stderr.trim()||a.stdout.trim()||"Unable to create worktree.");let c=await this.list(),l=await st(r).catch(()=>r),u=c.find(d=>d.path===l||d.path===r);if(!u)throw new Error("Git created the worktree, but it could not be discovered afterward.");return u}async list(){await this.assertRepository();let e=await it(this.rootDir,["worktree","list","--porcelain"]);if(e.code!==0)throw new Error(e.stderr.trim()||"Unable to list worktrees.");let n=await st(this.storageDir).catch(()=>this.storageDir),o=[],r;for(let s of e.stdout.split(/\r?\n/))if(s.startsWith("worktree ")){r&&o.push(r);let i=s.slice(9),a=await st(i).catch(()=>i),c=ce.relative(n,a),l=c!==""&&!c.startsWith("..")&&!ce.isAbsolute(c);r={path:a,bare:!1,detached:!1,managed:l,name:l?c.split(ce.sep)[0]:void 0}}else{if(!r||!s)continue;s.startsWith("HEAD ")?r.head=s.slice(5):s.startsWith("branch ")?r.branch=s.slice(7).replace(/^refs\/heads\//,""):s==="bare"?r.bare=!0:s==="detached"?r.detached=!0:s.startsWith("locked")?r.locked=s.slice(6).trim()||"locked":s.startsWith("prunable")&&(r.prunable=s.slice(8).trim()||"prunable")}return r&&o.push(r),o}async remove(e,n=!1){await this.assertRepository();let o=this.pathFor(e),r=await st(o).catch(()=>o);if(!(await this.list()).find(l=>l.managed&&l.path===r))throw new Error(`Managed worktree not found: ${e}`);let a=["worktree","remove"];n&&a.push("--force"),a.push(o);let c=await it(this.rootDir,a);if(c.code!==0)throw new Error(c.stderr.trim()||c.stdout.trim()||"Unable to remove worktree.");await qo(o)&&await Sc(o,{recursive:!0,force:!0})}async prune(){await this.assertRepository();let e=await it(this.rootDir,["worktree","prune"]);if(e.code!==0)throw new Error(e.stderr.trim()||"Unable to prune worktrees.")}};import{appendFile as Ec,mkdir as Fo,readFile as Cc,rm as Jo,stat as Go}from"node:fs/promises";import{createHash as Rc,randomUUID as Mc}from"node:crypto";import{hostname as $c,userInfo as _c}from"node:os";import Nt from"node:path";function Hn(t){if(Array.isArray(t))return`[${t.map(Hn).join(",")}]`;if(t&&typeof t=="object"){let e=t;return`{${Object.keys(e).sort().map(n=>`${JSON.stringify(n)}:${Hn(e[n])}`).join(",")}}`}return JSON.stringify(t)}function Ko(t){return Rc("sha256").update(Hn(t)).digest("hex")}async function Ac(t){try{return await Go(t),!0}catch{return!1}}function Oc(){try{return _c().username||"unknown"}catch{return"unknown"}}var Bt=class{rootDir;filePath;lockPath;constructor(e){this.rootDir=Nt.resolve(e),this.filePath=Nt.join(this.rootDir,x,"audit","audit.jsonl"),this.lockPath=Nt.join(this.rootDir,x,"audit",".append-lock")}async parseAll(){if(!await Ac(this.filePath))return[];let e=await Cc(this.filePath,"utf8"),n=[];for(let[o,r]of e.split(/\r?\n/).entries()){if(!r.trim())continue;let s;try{s=JSON.parse(r)}catch(i){throw new Error(`Invalid audit JSON at line ${o+1}: ${i instanceof Error?i.message:String(i)}`)}if(!s||typeof s!="object"||Array.isArray(s))throw new Error(`Invalid audit record at line ${o+1}.`);n.push(s)}return n}async acquireLock(e=5e3){await Fo(Nt.dirname(this.lockPath),{recursive:!0});let n=Date.now();for(;;)try{return await Fo(this.lockPath),async()=>{await Jo(this.lockPath,{recursive:!0,force:!0})}}catch(o){if(o.code!=="EEXIST")throw o;try{let s=await Go(this.lockPath);if(Date.now()-s.mtimeMs>3e4){await Jo(this.lockPath,{recursive:!0,force:!0});continue}}catch{continue}if(Date.now()-n>=e)throw new Error("Timed out waiting for the audit append lock.");await new Promise(s=>setTimeout(s,25))}}async append(e){if(!e.action.trim())throw new Error("Audit action cannot be empty.");let n=await this.acquireLock();try{let r=(await this.parseAll()).at(-1)?.hash??"GENESIS",s={schemaVersion:1,id:Mc(),timestamp:new Date().toISOString(),actor:e.actor?.trim()||Oc(),host:$c(),action:e.action.trim(),outcome:e.outcome,...e.category?{category:e.category}:{},...e.sessionId?{sessionId:e.sessionId}:{},...e.details?{details:e.details}:{},previousHash:r},i={...s,hash:Ko(s)};return await Ec(this.filePath,`${JSON.stringify(i)}
157
157
  `,{encoding:"utf8",mode:384}),i}finally{await n()}}async list(e=50){if(!Number.isInteger(e)||e<1||e>1e3)throw new Error("Audit limit must be between 1 and 1000.");return(await this.parseAll()).slice(-e).reverse()}async verify(){let e;try{e=await this.parseAll()}catch(o){return{valid:!1,records:0,firstInvalidLine:1,reason:o instanceof Error?o.message:String(o),headHash:"GENESIS"}}let n="GENESIS";for(let[o,r]of e.entries()){if(r.schemaVersion!==1)return{valid:!1,records:e.length,firstInvalidLine:o+1,reason:"Unsupported audit schema.",headHash:n};if(r.previousHash!==n)return{valid:!1,records:e.length,firstInvalidLine:o+1,reason:"Previous hash mismatch.",headHash:n};let{hash:s,...i}=r,a=Ko(i);if(s!==a)return{valid:!1,records:e.length,firstInvalidLine:o+1,reason:"Record hash mismatch.",headHash:n};n=s}return{valid:!0,records:e.length,headHash:n}}};import{appendFile as Ic,mkdir as Dc,readFile as jc,stat as Uc}from"node:fs/promises";import{randomUUID as Lc}from"node:crypto";import Wn from"node:path";async function Nc(t){try{return await Uc(t),!0}catch{return!1}}function qt(t,e){if(t!==void 0){if(!Number.isInteger(t)||t<0)throw new Error(`${e} must be a non-negative integer.`);return t}}function Bc(t){let e={dailyInputTokens:qt(t.dailyInputTokens,"dailyInputTokens"),dailyOutputTokens:qt(t.dailyOutputTokens,"dailyOutputTokens"),dailyTotalTokens:qt(t.dailyTotalTokens,"dailyTotalTokens"),perRunTotalTokens:qt(t.perRunTotalTokens,"perRunTotalTokens"),dailyEstimatedCostUsd:t.dailyEstimatedCostUsd,warnAtPercent:t.warnAtPercent??80};if(e.dailyEstimatedCostUsd!==void 0&&(!Number.isFinite(e.dailyEstimatedCostUsd)||e.dailyEstimatedCostUsd<0))throw new Error("dailyEstimatedCostUsd must be a non-negative number.");if(!Number.isFinite(e.warnAtPercent)||e.warnAtPercent<1||e.warnAtPercent>100)throw new Error("warnAtPercent must be between 1 and 100.");return e}var Ft=class{rootDir;filePath;constructor(e){this.rootDir=Wn.resolve(e),this.filePath=Wn.join(this.rootDir,x,"usage","usage.jsonl")}async records(){return await Nc(this.filePath)?(await jc(this.filePath,"utf8")).split(/\r?\n/).filter(Boolean).map((n,o)=>{try{return JSON.parse(n)}catch(r){throw new Error(`Invalid usage JSON at line ${o+1}: ${r instanceof Error?r.message:String(r)}`)}}):[]}async record(e){let n=Math.max(0,Math.trunc(e.inputTokens??0)),o=Math.max(0,Math.trunc(e.outputTokens??0)),r=Math.max(0,Math.trunc(e.cacheReadTokens??0)),s=e.price?.cacheReadPerMillionUsd??e.price?.inputPerMillionUsd??0,i=n/1e6*(e.price?.inputPerMillionUsd??0)+r/1e6*s+o/1e6*(e.price?.outputPerMillionUsd??0),a={schemaVersion:1,id:Lc(),timestamp:new Date().toISOString(),...e.sessionId?{sessionId:e.sessionId}:{},model:e.model,inputTokens:n,outputTokens:o,...r>0?{cacheReadTokens:r}:{},totalTokens:n+o+r,estimatedCostUsd:Number(i.toFixed(8))};return await Dc(Wn.dirname(this.filePath),{recursive:!0}),await Ic(this.filePath,`${JSON.stringify(a)}
158
- `,{encoding:"utf8",mode:384}),a}async summarize(e=new Date().toISOString().slice(0,10)){return(await this.records()).filter(o=>o.timestamp.slice(0,10)===e).reduce((o,r)=>({date:e,inputTokens:o.inputTokens+r.inputTokens,outputTokens:o.outputTokens+r.outputTokens,cacheReadTokens:o.cacheReadTokens+(r.cacheReadTokens??0),totalTokens:o.totalTokens+r.totalTokens,estimatedCostUsd:Number((o.estimatedCostUsd+r.estimatedCostUsd).toFixed(8)),runs:o.runs+1}),{date:e,inputTokens:0,outputTokens:0,cacheReadTokens:0,totalTokens:0,estimatedCostUsd:0,runs:0})}async list(e=50){if(!Number.isInteger(e)||e<1||e>1e3)throw new Error("Usage limit must be between 1 and 1000.");return(await this.records()).slice(-e).reverse()}async check(e,n=0){let o=Bc(e),r=await this.summarize(),s=[],i=[],a=[["daily input tokens",r.inputTokens,o.dailyInputTokens],["daily output tokens",r.outputTokens,o.dailyOutputTokens],["daily total tokens",r.totalTokens+n,o.dailyTotalTokens],["daily estimated cost",r.estimatedCostUsd,o.dailyEstimatedCostUsd]];for(let[c,l,u]of a)u===void 0||u===0||(l>=u?s.push(`${c} limit reached (${l}/${u}).`):l/u*100>=o.warnAtPercent&&i.push(`${c} is at ${Math.round(l/u*100)}% (${l}/${u}).`));return o.perRunTotalTokens&&n>o.perRunTotalTokens&&s.push(`per-run token limit exceeded (${n}/${o.perRunTotalTokens}).`),{allowed:s.length===0,warnings:i,violations:s,summary:r}}};import{chmod as qc,mkdir as Fc,readFile as Jc,rename as Kc,rm as Gc,writeFile as Hc}from"node:fs/promises";import{homedir as Wc,hostname as zc}from"node:os";import zn from"node:path";var ct=class extends Error{status;code;constructor(e,n,o){super(e),this.name="ControlPlaneError",this.status=n,this.code=o}};function Vc(t){let e=new URL(t);if(e.protocol!=="https:"&&e.hostname!=="localhost"&&e.hostname!=="127.0.0.1")throw new Error("Control-plane URL must use HTTPS outside localhost.");return t.replace(/\/+$/,"")}var Z=class{baseUrl;userAgent;constructor(e="https://api.kpilot.ai",n="kpilot CLI"){this.baseUrl=Vc(e),this.userAgent=n}async request(e,n={}){let o=await fetch(`${this.baseUrl}${e}`,{method:n.method??(n.body===void 0?"GET":"POST"),headers:{accept:"application/json","content-type":"application/json","user-agent":this.userAgent,...n.accessToken?{authorization:`Bearer ${n.accessToken}`}:{}},...n.body===void 0?{}:{body:JSON.stringify(n.body)},...n.signal?{signal:n.signal}:{}}),r=await o.text(),s={};if(r)try{s=JSON.parse(r)}catch{s={message:r}}if(!o.ok)throw new ct(s.message??`Control plane returned HTTP ${o.status}.`,o.status,s.code);return s}createDeviceCode(e={}){return this.request("/v1/device/code",{body:{client_name:"kpilot CLI",device_name:e.deviceName??zc(),platform:e.platform??process.platform},signal:e.signal})}async pollDeviceToken(e,n={}){let o=Date.now(),r=n.expiresInSeconds??600,s=Math.max(1,n.intervalSeconds??5),i=0;for(;(Date.now()-o)/1e3<r;){if(n.signal?.aborted)throw n.signal.reason??new Error("Login cancelled.");i+=1;try{return await this.request("/v1/device/token",{body:{device_code:e},signal:n.signal})}catch(a){if(!(a instanceof ct))throw a;if(a.code==="authorization_pending")n.onPending?.(i);else if(a.code==="slow_down")s+=2;else throw a}await new Promise((a,c)=>{let l=setTimeout(()=>a(),s*1e3);n.signal?.addEventListener("abort",()=>{clearTimeout(l),c(n.signal?.reason??new Error("Login cancelled."))},{once:!0})})}throw new Error("Device authorization expired. Run `kpilot login` again.")}profile(e){return this.request("/v1/me",{accessToken:e})}refresh(e){return this.request("/v1/auth/refresh",{body:{refresh_token:e}})}logout(e){return this.request("/v1/auth/logout",{body:{refresh_token:e}})}catalog(e){return this.request("/v1/ai/models",{accessToken:e})}ingestUsage(e,n){return this.request("/v1/usage/events",{body:{events:n},accessToken:e})}checkBudget(e,n=0){return this.request("/v1/usage/preflight",{body:{projectedTokens:n},accessToken:e})}},Y=class{filePath;constructor(e=zn.join(Wc(),".config","kpilot","cloud-auth.json")){this.filePath=zn.resolve(e)}async load(){try{let e=JSON.parse(await Jc(this.filePath,"utf8"));if(!e.accessToken||!e.refreshToken||!e.controlPlaneUrl)throw new Error("Cloud credential file is incomplete.");return e}catch(e){if(e?.code==="ENOENT")return;throw e}}async save(e){await Fc(zn.dirname(this.filePath),{recursive:!0,mode:448});let n=`${this.filePath}.${process.pid??"tmp"}.tmp`;await Hc(n,`${JSON.stringify(e,null,2)}
158
+ `,{encoding:"utf8",mode:384}),a}async summarize(e=new Date().toISOString().slice(0,10)){return(await this.records()).filter(o=>o.timestamp.slice(0,10)===e).reduce((o,r)=>({date:e,inputTokens:o.inputTokens+r.inputTokens,outputTokens:o.outputTokens+r.outputTokens,cacheReadTokens:o.cacheReadTokens+(r.cacheReadTokens??0),totalTokens:o.totalTokens+r.totalTokens,estimatedCostUsd:Number((o.estimatedCostUsd+r.estimatedCostUsd).toFixed(8)),runs:o.runs+1}),{date:e,inputTokens:0,outputTokens:0,cacheReadTokens:0,totalTokens:0,estimatedCostUsd:0,runs:0})}async list(e=50){if(!Number.isInteger(e)||e<1||e>1e3)throw new Error("Usage limit must be between 1 and 1000.");return(await this.records()).slice(-e).reverse()}async check(e,n=0){let o=Bc(e),r=await this.summarize(),s=[],i=[],a=[["daily input tokens",r.inputTokens,o.dailyInputTokens],["daily output tokens",r.outputTokens,o.dailyOutputTokens],["daily total tokens",r.totalTokens+n,o.dailyTotalTokens],["daily estimated cost",r.estimatedCostUsd,o.dailyEstimatedCostUsd]];for(let[c,l,u]of a)u===void 0||u===0||(l>=u?s.push(`${c} limit reached (${l}/${u}).`):l/u*100>=o.warnAtPercent&&i.push(`${c} is at ${Math.round(l/u*100)}% (${l}/${u}).`));return o.perRunTotalTokens&&n>o.perRunTotalTokens&&s.push(`per-run token limit exceeded (${n}/${o.perRunTotalTokens}).`),{allowed:s.length===0,warnings:i,violations:s,summary:r}}};import{chmod as qc,mkdir as Fc,readFile as Jc,rename as Kc,rm as Gc,writeFile as Hc}from"node:fs/promises";import{homedir as Wc,hostname as zc}from"node:os";import zn from"node:path";var ct=class extends Error{status;code;constructor(e,n,o){super(e),this.name="ControlPlaneError",this.status=n,this.code=o}};function Vc(t){let e=new URL(t);if(e.protocol!=="https:"&&e.hostname!=="localhost"&&e.hostname!=="127.0.0.1")throw new Error("Control-plane URL must use HTTPS outside localhost.");return t.replace(/\/+$/,"")}var Z=class{baseUrl;userAgent;constructor(e="https://api.konsolepilot.ai",n="kpilot CLI"){this.baseUrl=Vc(e),this.userAgent=n}async request(e,n={}){let o=await fetch(`${this.baseUrl}${e}`,{method:n.method??(n.body===void 0?"GET":"POST"),headers:{accept:"application/json","content-type":"application/json","user-agent":this.userAgent,...n.accessToken?{authorization:`Bearer ${n.accessToken}`}:{}},...n.body===void 0?{}:{body:JSON.stringify(n.body)},...n.signal?{signal:n.signal}:{}}),r=await o.text(),s={};if(r)try{s=JSON.parse(r)}catch{s={message:r}}if(!o.ok)throw new ct(s.message??`Control plane returned HTTP ${o.status}.`,o.status,s.code);return s}createDeviceCode(e={}){return this.request("/v1/device/code",{body:{client_name:"kpilot CLI",device_name:e.deviceName??zc(),platform:e.platform??process.platform},signal:e.signal})}async pollDeviceToken(e,n={}){let o=Date.now(),r=n.expiresInSeconds??600,s=Math.max(1,n.intervalSeconds??5),i=0;for(;(Date.now()-o)/1e3<r;){if(n.signal?.aborted)throw n.signal.reason??new Error("Login cancelled.");i+=1;try{return await this.request("/v1/device/token",{body:{device_code:e},signal:n.signal})}catch(a){if(!(a instanceof ct))throw a;if(a.code==="authorization_pending")n.onPending?.(i);else if(a.code==="slow_down")s+=2;else throw a}await new Promise((a,c)=>{let l=setTimeout(()=>a(),s*1e3);n.signal?.addEventListener("abort",()=>{clearTimeout(l),c(n.signal?.reason??new Error("Login cancelled."))},{once:!0})})}throw new Error("Device authorization expired. Run `kpilot login` again.")}profile(e){return this.request("/v1/me",{accessToken:e})}refresh(e){return this.request("/v1/auth/refresh",{body:{refresh_token:e}})}logout(e){return this.request("/v1/auth/logout",{body:{refresh_token:e}})}catalog(e){return this.request("/v1/ai/models",{accessToken:e})}ingestUsage(e,n){return this.request("/v1/usage/events",{body:{events:n},accessToken:e})}checkBudget(e,n=0){return this.request("/v1/usage/preflight",{body:{projectedTokens:n},accessToken:e})}},Y=class{filePath;constructor(e=zn.join(Wc(),".config","kpilot","cloud-auth.json")){this.filePath=zn.resolve(e)}async load(){try{let e=JSON.parse(await Jc(this.filePath,"utf8"));if(!e.accessToken||!e.refreshToken||!e.controlPlaneUrl)throw new Error("Cloud credential file is incomplete.");return e}catch(e){if(e?.code==="ENOENT")return;throw e}}async save(e){await Fc(zn.dirname(this.filePath),{recursive:!0,mode:448});let n=`${this.filePath}.${process.pid??"tmp"}.tmp`;await Hc(n,`${JSON.stringify(e,null,2)}
159
159
  `,{encoding:"utf8",mode:384}),await Kc(n,this.filePath),await qc(this.filePath,384)}async clear(){try{await Gc(this.filePath,{force:!0})}catch(e){if(e?.code!=="ENOENT")throw e}}async validAccessToken(e){let n=await this.load();if(!n)return;let o=e??new Z(n.controlPlaneUrl);if(new Date(n.expiresAt).getTime()>Date.now()+3e4)return{tokens:n,client:o};try{let r=await o.refresh(n.refreshToken);return await this.save(r),{tokens:r,client:o}}catch(r){throw r instanceof ct&&r.status>=400&&r.status<500?(await this.clear(),new Error("Your kpilot session has expired or was revoked. Run `kpilot login` to sign in again.")):r}}};import{lstat as Yc,mkdir as Ho,readFile as Vn,readdir as Qc,stat as Qo,writeFile as Wo}from"node:fs/promises";import{createCipheriv as Xc,createDecipheriv as Zc,randomBytes as zo,scryptSync as el}from"node:crypto";import K from"node:path";var tl=[`${x}/instructions.md`,`${x}/memory.json`,`${x}/preferences.json`,`${x}/team-policy.json`,`${x}/skills`];async function Jt(t){try{return await Qo(t),!0}catch{return!1}}async function Yn(t,e,n){let o=K.join(t,e);if(!await Jt(o))return;let r=await Qc(o,{withFileTypes:!0});for(let s of r){let i=K.posix.join(e.replaceAll("\\","/"),s.name);if(s.isDirectory())await Yn(t,i,n);else if(s.isFile()){let a=await Vn(K.join(t,i));n.push({path:i,contentBase64:a.toString("base64")})}}}function nl(t){let e=t.replaceAll("\\","/");if(e.startsWith(".konsolepilot/")&&(e=`${x}/${e.slice(14)}`),!e.startsWith(`${x}/`)||e.includes("../")||K.isAbsolute(e))throw new Error(`Unsafe bundle path: ${t}`);return e}async function rl(t,e){let n=e.split("/").filter(Boolean),o=t;for(let r of n.slice(0,-1)){if(o=K.join(o,r),!await Jt(o))continue;if((await Yc(o)).isSymbolicLink())throw new Error(`Refusing to import through symbolic link: ${K.relative(t,o)}`)}}function Vo(t){return Buffer.from(JSON.stringify({schemaVersion:t.schemaVersion,format:t.format,createdAt:t.createdAt,projectName:t.projectName,includeSessions:t.includeSessions,algorithm:t.encryption.algorithm,kdf:t.encryption.kdf,salt:t.encryption.salt,iv:t.encryption.iv}),"utf8")}function Yo(t,e){if(t.length<12)throw new Error("Sync passphrase must contain at least 12 characters.");return el(t,e,32,{N:32768,r:8,p:1,maxmem:64*1024*1024})}var Kt=class{rootDir;constructor(e){this.rootDir=K.resolve(e)}async exportBundle(e,n,o=!1){let r=[];for(let f of tl){let y=K.join(this.rootDir,f);if(!await Jt(y))continue;(await Qo(y)).isDirectory()?await Yn(this.rootDir,f,r):r.push({path:f,contentBase64:(await Vn(y)).toString("base64")})}o&&await Yn(this.rootDir,`${x}/sessions`,r),r.sort((f,y)=>f.path.localeCompare(y.path));let s={schemaVersion:1,files:r},i=zo(16),a=zo(12),c=Yo(n,i),l={schemaVersion:1,format:"kpilot-encrypted-sync",createdAt:new Date().toISOString(),projectName:K.basename(this.rootDir),includeSessions:o,encryption:{algorithm:"aes-256-gcm",kdf:"scrypt",salt:i.toString("base64"),iv:a.toString("base64"),tag:""}},u=Xc("aes-256-gcm",c,a);u.setAAD(Vo(l));let d=Buffer.concat([u.update(JSON.stringify(s),"utf8"),u.final()]),p={...l,encryption:{...l.encryption,tag:u.getAuthTag().toString("base64")},ciphertext:d.toString("base64")},b=K.resolve(e);return await Ho(K.dirname(b),{recursive:!0}),await Wo(b,`${JSON.stringify(p,null,2)}
160
160
  `,{encoding:"utf8",mode:384}),p}async inspectBundle(e){let n=await this.readEnvelope(e),{ciphertext:o,...r}=n;return r}async importBundle(e,n,o=!1){let r=await this.readEnvelope(e),s=Buffer.from(r.encryption.salt,"base64"),i=Buffer.from(r.encryption.iv,"base64"),a=Buffer.from(r.encryption.tag,"base64"),c=Yo(n,s),l;try{let b=Zc("aes-256-gcm",c,i);b.setAuthTag(a);let{ciphertext:f,...y}=r;b.setAAD(Vo(y)),l=Buffer.concat([b.update(Buffer.from(r.ciphertext,"base64")),b.final()])}catch{throw new Error("Unable to decrypt sync bundle. The passphrase is incorrect or the bundle was modified.")}let u;try{u=JSON.parse(l.toString("utf8"))}catch{throw new Error("Decrypted sync bundle payload is invalid JSON.")}if(u.schemaVersion!==1||!Array.isArray(u.files))throw new Error("Unsupported sync payload schema.");let d=[],p=[];for(let b of u.files){let f=nl(b.path),y=K.join(this.rootDir,f);if(await rl(this.rootDir,f),!o&&await Jt(y)){p.push(f);continue}await Ho(K.dirname(y),{recursive:!0}),await Wo(y,Buffer.from(b.contentBase64,"base64"),{mode:384}),d.push(f)}return{imported:d,skipped:p}}async readEnvelope(e){let n;try{n=JSON.parse(await Vn(K.resolve(e),"utf8"))}catch(r){throw new Error(`Invalid sync bundle: ${r instanceof Error?r.message:String(r)}`)}if(!n||typeof n!="object"||Array.isArray(n))throw new Error("Sync bundle must be a JSON object.");let o=n;if(o.schemaVersion!==1||o.format!=="kpilot-encrypted-sync")throw new Error("Unsupported sync bundle format.");if(o.encryption?.algorithm!=="aes-256-gcm"||o.encryption?.kdf!=="scrypt")throw new Error("Unsupported sync bundle encryption.");return o}};import{mkdir as Xo,readFile as ol,stat as sl,writeFile as Zo}from"node:fs/promises";import Gt from"node:path";async function es(t){try{return await sl(t),!0}catch{return!1}}function ts(t){let e=[],n=[];t.schemaVersion!==1&&e.push("schemaVersion must be 1."),t.maximumSteps!==void 0&&(!Number.isInteger(t.maximumSteps)||t.maximumSteps<1||t.maximumSteps>50)&&e.push("maximumSteps must be an integer between 1 and 50."),t.allowedModels&&((!Array.isArray(t.allowedModels)||t.allowedModels.some(r=>typeof r!="string"||!r.trim()))&&e.push("allowedModels must contain non-empty strings."),t.allowedModels.length===0&&n.push("allowedModels is empty; no model can run.")),t.allowedMcpServers?.some(r=>typeof r!="string"||!r.trim())&&e.push("allowedMcpServers must contain non-empty strings.");let o=new Set(["allow","ask","deny"]);for(let[r,s]of Object.entries(t.permissions??{}))for(let[i,a]of Object.entries(s??{}))o.has(a)||e.push(`permissions.${r}.${i} must be allow, ask, or deny.`);return{valid:e.length===0,errors:e,warnings:n}}var ke=class{rootDir;filePath;constructor(e){this.rootDir=Gt.resolve(e),this.filePath=Gt.join(this.rootDir,x,"team-policy.json")}async load(){if(!await es(this.filePath))return;let e;try{e=JSON.parse(await ol(this.filePath,"utf8"))}catch(r){throw new Error(`Invalid team policy JSON: ${r instanceof Error?r.message:String(r)}`)}if(!e||typeof e!="object"||Array.isArray(e))throw new Error("Team policy must be a JSON object.");let n=e,o=ts(n);if(!o.valid)throw new Error(`Invalid team policy: ${o.errors.join(" ")}`);return n}async initialize(e,n=[]){if(await es(this.filePath))throw new Error(`${x}/team-policy.json already exists.`);let o={schemaVersion:1,...e?.trim()?{organization:e.trim()}:{},allowedModels:[...new Set(n.map(r=>r.trim()).filter(Boolean))],allowWriteMode:!0,requireSandbox:!0,requireNetworkIsolation:!0,allowedMcpServers:[],permissions:{}};return await Xo(Gt.dirname(this.filePath),{recursive:!0}),await Zo(this.filePath,`${JSON.stringify(o,null,2)}
161
161
  `,"utf8"),o}async save(e){let n=ts(e);if(!n.valid)throw new Error(`Invalid team policy: ${n.errors.join(" ")}`);await Xo(Gt.dirname(this.filePath),{recursive:!0}),await Zo(this.filePath,`${JSON.stringify(e,null,2)}
@@ -211,7 +211,7 @@ See \`package.json\` scripts above (or README). Prefer the repo's documented pac
211
211
  `)}
212
212
  `;let c=xe(t);return await zt(c,{recursive:!0,mode:493}),await Xn(tr(t),`# Logbook learnings
213
213
 
214
- ${a}`,{encoding:"utf8",mode:420}),await dt(t,{lastLearnedAt:new Date().toISOString()}),s}function kl(t){let e=[],n=t.prompt.trim();if(!n||n===Vt)return[];let o=s=>{if(!s)return;let i=or(s);!i||i.length<8||e.some(a=>a.toLowerCase()===i.toLowerCase())||e.length>=ss||e.push(i)},r=[/\b(?:please\s+)?remember(?:\s+that)?\s+(.+)$/im,/\b(?:from now on|going forward)[,:]?\s+(.+)$/im,/\balways\s+(.+)$/im,/\bnever\s+(.+)$/im,/\b(?:prefer|use)\s+(.+?)(?:\s+instead\b|\s+for\b|\.|$)/im,/\bdon'?t\s+(.+)$/im,/\bdo not\s+(.+)$/im,/\bnote that\s+(.+)$/im,/\bin this (?:repo|project|codebase)[,:]?\s+(.+)$/im];for(let s of r){let i=s.exec(n);i?.[1]&&o(i[1])}if(t.changed&&t.diffAfter){let s=t.diffAfter;/\bpnpm-lock\.yaml\b/.test(s)||/\bpnpm-workspace\.yaml\b/.test(s)?o("Use pnpm for installs and scripts in this repository."):/\bpackage-lock\.json\b/.test(s)?o("Use npm for installs and scripts in this repository."):/\byarn\.lock\b/.test(s)?o("Use yarn for installs and scripts in this repository."):/\bbun\.lockb?\b/.test(s)&&o("Use bun for installs and scripts in this repository."),/\.spec\.(ts|tsx|js|jsx)\b/.test(s)&&!/\.test\.(ts|tsx|js|jsx)\b/.test(s)?o("Tests in this repository often use *.spec.* filenames."):/\.test\.(ts|tsx|js|jsx)\b/.test(s)&&!/\.spec\.(ts|tsx|js|jsx)\b/.test(s)&&o("Tests in this repository often use *.test.* filenames.")}return e.slice(0,ss)}async function ms(t){if(!await mt(t.rootDir))return[];if(t.prompt.trim()===Vt)return[];let e=kl(t);return e.length?vl(t.rootDir,e):[]}function ps(t){let e=t.replace(/\\/g,"/");return e===".kpilot"||e.startsWith(".kpilot/")||e.includes("/.kpilot/")}var B="0.10.8",ir=[26,0,0];function Tl(){let t=process.version.replace(/^v/,"").split(".").slice(0,3).map(Number);if(!ir.every((n,o)=>{for(let r=0;r<o;r+=1)if((t[r]??0)!==ir[r])return!0;return(t[o]??0)>=n})&&process.env.KPILOT_ALLOW_UNSUPPORTED_NODE!=="1")throw new Error(`kpilot requires Node.js ${ir.join(".")} or newer; detected ${process.version}.`)}var M={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",cyan:"\x1B[36m",green:"\x1B[32m",yellow:"\x1B[33m",red:"\x1B[31m",magenta:"\x1B[35m"},hr=[{name:"help",usage:"/help",description:"Show slash commands"},{name:"mode",usage:"/mode plan|write",description:"Change mode without deleting history",choices:[{value:"plan",label:"plan",description:"Inspect and reason only"},{value:"write",label:"write",description:"Allow file and command changes"}]},{name:"status",usage:"/status",description:"Show Git status"},{name:"diff",usage:"/diff",description:"Show Git diff"},{name:"clear",usage:"/clear",description:"Clear current conversation history"},{name:"save",usage:"/save",description:"Persist the current session"},{name:"sessions",usage:"/sessions",description:"Switch session (selectable list)"},{name:"resume",usage:"/resume [id]",description:"Switch session by id or picker"},{name:"new",usage:"/new [title]",description:"Start a new session"},{name:"logbook",usage:"/logbook [skip]",description:"Build or refresh .kpilot/logbook/project.md",aliases:["understand"],choices:[{value:"capture",label:"capture",description:"Inspect repo and write project.md",default:!0},{value:"skip",label:"skip",description:"Do not auto-offer Logbook again"}]},{name:"learn",usage:"/learn [on|off|status]",description:"Continuous Logbook learning",choices:[{value:"status",label:"status",description:"Show learning state and facts",default:!0},{value:"on",label:"on",description:"Enable continuous learning"},{value:"off",label:"off",description:"Disable continuous learning"}]},{name:"memory",usage:"/memory",description:"List project memory"},{name:"remember",usage:"/remember <text>",description:"Add persistent project memory",needsArgs:!0,argPrompt:"Memory text \u203A "},{name:"forget",usage:"/forget <id>",description:"Remove a memory entry",needsArgs:!0,argPrompt:"Memory id \u203A "},{name:"skills",usage:"/skills",description:"List reusable skills"},{name:"skill",usage:"/skill <name> [args]",description:"Run a skill",needsArgs:!0,argPrompt:"Skill name [args] \u203A "},{name:"preferences",usage:"/preferences",description:"List learned preferences"},{name:"feedback",usage:"/feedback <outcome> [note]",description:"Record accepted, rejected, or edited feedback",choices:[{value:"accepted",label:"accepted",description:"Mark last run accepted"},{value:"rejected",label:"rejected",description:"Mark last run rejected"},{value:"edited",label:"edited",description:"Mark last run edited"}]},{name:"models",usage:"/models",description:"Show active models and select one",aliases:["model"]},{name:"agent",usage:"/agent",description:"Show external agent configuration"},{name:"mcp",usage:"/mcp",description:"List connected MCP tools"},{name:"worktrees",usage:"/worktrees",description:"List Git worktrees"},{name:"policy",usage:"/policy",description:"Show team policy"},{name:"usage",usage:"/usage",description:"Show usage summary"},{name:"audit",usage:"/audit",description:"Verify audit chain"},{name:"admin",usage:"/admin",description:"Show admin/control-plane status"},{name:"exit",usage:"/exit",description:"End session (also: exit, quit)",aliases:["quit"]}],ks=new Set(hr.flatMap(t=>[t.name,...t.aliases??[]]));function El(t){if(!t.startsWith("/")||t==="/")return!1;let[e="",...n]=t.slice(1).split(/\s+/);return!e||n.length>0?!1:!ks.has(e)}function $(t,e){return process.stdout.isTTY?`${t}${e}${M.reset}`:e}function je(t){if(!Number.isFinite(t)||t<1e3)return String(Math.round(t));let e=["K","M","B","T"],n=Math.min(Math.floor(Math.log10(t)/3),e.length),o=t/10**(n*3),r=o>=100?0:o>=10?1:2;return`${o.toFixed(r)}${e[n-1]}`}function xs(t){if(t)return{pause:()=>{t.closed||t.pause()},resume:()=>{t.closed||t.resume()}}}function Cl(){console.log($(M.bold,"Slash commands")),console.log($(M.dim,"Type / for arrow-key command picker (or /help)."));for(let t of hr)console.log(` ${$(M.cyan,t.usage.padEnd(28))} ${t.description}`);console.log(` ${$(M.cyan,"/<skill-name> [args]".padEnd(28))} Run a skill directly`)}async function Rl(t){let e=(t.skillNames??[]).map(s=>({name:s,usage:`/${s}`,description:`Run skill \u201C${s}\u201D`})),n=[...hr,...e],o=await G({title:"Select a slash command:",question:t.question,pauseResume:t.pauseResume,typeahead:!0,initialQuery:t.initialQuery??"",choices:n.map(s=>({value:s.name,label:s.usage,description:s.description,aliases:s.aliases}))});if(!o)return null;let r=n.find(s=>s.name===o);if(!r)return null;if(r.choices&&r.choices.length>0){let s=await G({title:`${r.usage} \u2014 choose an action:`,question:t.question,pauseResume:t.pauseResume,choices:r.choices});if(!s)return P("Cancelled."),null;if(r.name==="logbook"&&s==="capture")return"/logbook";if(r.name==="feedback"){let i=(await t.question("Optional note \u203A ")).trim();return i?`/feedback ${s} ${i}`:`/feedback ${s}`}return`/${r.name} ${s}`}if(r.needsArgs){let s=(await t.question(r.argPrompt??"Args \u203A ")).trim();return s?`/${r.name} ${s}`:(P("Cancelled."),null)}return`/${r.name}`}function P(t){console.log(`${$(M.cyan,"\u25C6")} ${t}`)}function v(t){console.log(`${$(M.green,"\u2713")} ${t}`)}function R(t){console.log(`${$(M.yellow,"!")} ${t}`)}function F(t){console.error(`${$(M.red,"\u2717")} ${t}`)}function Ml(){return _.join(ys(),".config","kpilot","installed-version")}function $l(t,e){let n=s=>s.split(".").map(i=>Number(i)||0),o=n(t),r=n(e);for(let s=0;s<3;s+=1)if((o[s]??0)!==(r[s]??0))return(o[s]??0)<(r[s]??0)?-1:1;return 0}async function _l(){if(process.env.KPILOT_SILENT_VERSION_NOTICE==="1")return;let t=Ml(),e;try{e=(await gr(t,"utf8")).trim()||void 0}catch{e=void 0}if(e!==B){if(e){let n=$l(e,B)<0?"Updated":"Changed";P(`kpilot CLI ${n}: ${e} \u2192 ${B}`)}else P(`kpilot CLI installed: ${B}`);try{await gt(_.dirname(t),{recursive:!0}),await me(t,`${B}
214
+ ${a}`,{encoding:"utf8",mode:420}),await dt(t,{lastLearnedAt:new Date().toISOString()}),s}function kl(t){let e=[],n=t.prompt.trim();if(!n||n===Vt)return[];let o=s=>{if(!s)return;let i=or(s);!i||i.length<8||e.some(a=>a.toLowerCase()===i.toLowerCase())||e.length>=ss||e.push(i)},r=[/\b(?:please\s+)?remember(?:\s+that)?\s+(.+)$/im,/\b(?:from now on|going forward)[,:]?\s+(.+)$/im,/\balways\s+(.+)$/im,/\bnever\s+(.+)$/im,/\b(?:prefer|use)\s+(.+?)(?:\s+instead\b|\s+for\b|\.|$)/im,/\bdon'?t\s+(.+)$/im,/\bdo not\s+(.+)$/im,/\bnote that\s+(.+)$/im,/\bin this (?:repo|project|codebase)[,:]?\s+(.+)$/im];for(let s of r){let i=s.exec(n);i?.[1]&&o(i[1])}if(t.changed&&t.diffAfter){let s=t.diffAfter;/\bpnpm-lock\.yaml\b/.test(s)||/\bpnpm-workspace\.yaml\b/.test(s)?o("Use pnpm for installs and scripts in this repository."):/\bpackage-lock\.json\b/.test(s)?o("Use npm for installs and scripts in this repository."):/\byarn\.lock\b/.test(s)?o("Use yarn for installs and scripts in this repository."):/\bbun\.lockb?\b/.test(s)&&o("Use bun for installs and scripts in this repository."),/\.spec\.(ts|tsx|js|jsx)\b/.test(s)&&!/\.test\.(ts|tsx|js|jsx)\b/.test(s)?o("Tests in this repository often use *.spec.* filenames."):/\.test\.(ts|tsx|js|jsx)\b/.test(s)&&!/\.spec\.(ts|tsx|js|jsx)\b/.test(s)&&o("Tests in this repository often use *.test.* filenames.")}return e.slice(0,ss)}async function ms(t){if(!await mt(t.rootDir))return[];if(t.prompt.trim()===Vt)return[];let e=kl(t);return e.length?vl(t.rootDir,e):[]}function ps(t){let e=t.replace(/\\/g,"/");return e===".kpilot"||e.startsWith(".kpilot/")||e.includes("/.kpilot/")}var B="0.10.9",ir=[26,0,0];function Tl(){let t=process.version.replace(/^v/,"").split(".").slice(0,3).map(Number);if(!ir.every((n,o)=>{for(let r=0;r<o;r+=1)if((t[r]??0)!==ir[r])return!0;return(t[o]??0)>=n})&&process.env.KPILOT_ALLOW_UNSUPPORTED_NODE!=="1")throw new Error(`kpilot requires Node.js ${ir.join(".")} or newer; detected ${process.version}.`)}var M={reset:"\x1B[0m",bold:"\x1B[1m",dim:"\x1B[2m",cyan:"\x1B[36m",green:"\x1B[32m",yellow:"\x1B[33m",red:"\x1B[31m",magenta:"\x1B[35m"},hr=[{name:"help",usage:"/help",description:"Show slash commands"},{name:"mode",usage:"/mode plan|write",description:"Change mode without deleting history",choices:[{value:"plan",label:"plan",description:"Inspect and reason only"},{value:"write",label:"write",description:"Allow file and command changes"}]},{name:"status",usage:"/status",description:"Show Git status"},{name:"diff",usage:"/diff",description:"Show Git diff"},{name:"clear",usage:"/clear",description:"Clear current conversation history"},{name:"save",usage:"/save",description:"Persist the current session"},{name:"sessions",usage:"/sessions",description:"Switch session (selectable list)"},{name:"resume",usage:"/resume [id]",description:"Switch session by id or picker"},{name:"new",usage:"/new [title]",description:"Start a new session"},{name:"logbook",usage:"/logbook [skip]",description:"Build or refresh .kpilot/logbook/project.md",aliases:["understand"],choices:[{value:"capture",label:"capture",description:"Inspect repo and write project.md",default:!0},{value:"skip",label:"skip",description:"Do not auto-offer Logbook again"}]},{name:"learn",usage:"/learn [on|off|status]",description:"Continuous Logbook learning",choices:[{value:"status",label:"status",description:"Show learning state and facts",default:!0},{value:"on",label:"on",description:"Enable continuous learning"},{value:"off",label:"off",description:"Disable continuous learning"}]},{name:"memory",usage:"/memory",description:"List project memory"},{name:"remember",usage:"/remember <text>",description:"Add persistent project memory",needsArgs:!0,argPrompt:"Memory text \u203A "},{name:"forget",usage:"/forget <id>",description:"Remove a memory entry",needsArgs:!0,argPrompt:"Memory id \u203A "},{name:"skills",usage:"/skills",description:"List reusable skills"},{name:"skill",usage:"/skill <name> [args]",description:"Run a skill",needsArgs:!0,argPrompt:"Skill name [args] \u203A "},{name:"preferences",usage:"/preferences",description:"List learned preferences"},{name:"feedback",usage:"/feedback <outcome> [note]",description:"Record accepted, rejected, or edited feedback",choices:[{value:"accepted",label:"accepted",description:"Mark last run accepted"},{value:"rejected",label:"rejected",description:"Mark last run rejected"},{value:"edited",label:"edited",description:"Mark last run edited"}]},{name:"models",usage:"/models",description:"Show active models and select one",aliases:["model"]},{name:"agent",usage:"/agent",description:"Show external agent configuration"},{name:"mcp",usage:"/mcp",description:"List connected MCP tools"},{name:"worktrees",usage:"/worktrees",description:"List Git worktrees"},{name:"policy",usage:"/policy",description:"Show team policy"},{name:"usage",usage:"/usage",description:"Show usage summary"},{name:"audit",usage:"/audit",description:"Verify audit chain"},{name:"admin",usage:"/admin",description:"Show admin/control-plane status"},{name:"exit",usage:"/exit",description:"End session (also: exit, quit)",aliases:["quit"]}],ks=new Set(hr.flatMap(t=>[t.name,...t.aliases??[]]));function El(t){if(!t.startsWith("/")||t==="/")return!1;let[e="",...n]=t.slice(1).split(/\s+/);return!e||n.length>0?!1:!ks.has(e)}function $(t,e){return process.stdout.isTTY?`${t}${e}${M.reset}`:e}function je(t){if(!Number.isFinite(t)||t<1e3)return String(Math.round(t));let e=["K","M","B","T"],n=Math.min(Math.floor(Math.log10(t)/3),e.length),o=t/10**(n*3),r=o>=100?0:o>=10?1:2;return`${o.toFixed(r)}${e[n-1]}`}function xs(t){if(t)return{pause:()=>{t.closed||t.pause()},resume:()=>{t.closed||t.resume()}}}function Cl(){console.log($(M.bold,"Slash commands")),console.log($(M.dim,"Type / for arrow-key command picker (or /help)."));for(let t of hr)console.log(` ${$(M.cyan,t.usage.padEnd(28))} ${t.description}`);console.log(` ${$(M.cyan,"/<skill-name> [args]".padEnd(28))} Run a skill directly`)}async function Rl(t){let e=(t.skillNames??[]).map(s=>({name:s,usage:`/${s}`,description:`Run skill \u201C${s}\u201D`})),n=[...hr,...e],o=await G({title:"Select a slash command:",question:t.question,pauseResume:t.pauseResume,typeahead:!0,initialQuery:t.initialQuery??"",choices:n.map(s=>({value:s.name,label:s.usage,description:s.description,aliases:s.aliases}))});if(!o)return null;let r=n.find(s=>s.name===o);if(!r)return null;if(r.choices&&r.choices.length>0){let s=await G({title:`${r.usage} \u2014 choose an action:`,question:t.question,pauseResume:t.pauseResume,choices:r.choices});if(!s)return P("Cancelled."),null;if(r.name==="logbook"&&s==="capture")return"/logbook";if(r.name==="feedback"){let i=(await t.question("Optional note \u203A ")).trim();return i?`/feedback ${s} ${i}`:`/feedback ${s}`}return`/${r.name} ${s}`}if(r.needsArgs){let s=(await t.question(r.argPrompt??"Args \u203A ")).trim();return s?`/${r.name} ${s}`:(P("Cancelled."),null)}return`/${r.name}`}function P(t){console.log(`${$(M.cyan,"\u25C6")} ${t}`)}function v(t){console.log(`${$(M.green,"\u2713")} ${t}`)}function R(t){console.log(`${$(M.yellow,"!")} ${t}`)}function F(t){console.error(`${$(M.red,"\u2717")} ${t}`)}function Ml(){return _.join(ys(),".config","kpilot","installed-version")}function $l(t,e){let n=s=>s.split(".").map(i=>Number(i)||0),o=n(t),r=n(e);for(let s=0;s<3;s+=1)if((o[s]??0)!==(r[s]??0))return(o[s]??0)<(r[s]??0)?-1:1;return 0}async function _l(){if(process.env.KPILOT_SILENT_VERSION_NOTICE==="1")return;let t=Ml(),e;try{e=(await gr(t,"utf8")).trim()||void 0}catch{e=void 0}if(e!==B){if(e){let n=$l(e,B)<0?"Updated":"Changed";P(`kpilot CLI ${n}: ${e} \u2192 ${B}`)}else P(`kpilot CLI installed: ${B}`);try{await gt(_.dirname(t),{recursive:!0}),await me(t,`${B}
215
215
  `,{mode:384})}catch{}}}function Al(){return`${$(M.bold,`kpilot ${B}`)} \u2014 governed engineering agent
216
216
 
217
217
  All requests go through kpilot \u2014 sign in once, and kpilot handles the rest.
@@ -253,7 +253,7 @@ Options:
253
253
  --include-sessions Include private sessions in sync export
254
254
  --overwrite Replace files during sync import
255
255
  --organization <name> Organization name for policy initialization
256
- --control-plane-url <url> Account API URL (default: https://api.kpilot.ai)
256
+ --control-plane-url <url> Account API URL (default: https://api.konsolepilot.ai)
257
257
  --no-cloud-sync Keep usage records local for this invocation
258
258
  --no-browser Do not open a browser during \`kpilot login\`
259
259
  --limit <number> Row limit for usage and audit lists
@@ -275,7 +275,7 @@ Interactive additions:
275
275
  `)}
276
276
  `,"utf8"):await me(n,`${s.join(`
277
277
  `)}
278
- `,"utf8"),v(`Updated .gitignore with ${s.length} kpilot runtime path(s).`)}async function Ul(t){await L(t);let e=_.join(t,x),n=_.join(e,"config.json"),o=_.join(e,"instructions.md"),r=_.join(e,"skills","review","SKILL.md");await gt(_.dirname(r),{recursive:!0}),await Ue(n)?R(`${_.relative(t,n)} already exists; left unchanged.`):(await me(n,`${JSON.stringify({model:{provider:"kpilot-hosted",baseUrl:"https://api.kpilot.ai",model:"auto",route:"auto",streaming:!0},agent:{mode:"write"},sandbox:{mode:"portable",allowNetwork:!1,passEnvironment:[]},subagents:{enabled:!0,maxParallel:4},mcp:{servers:{}},preferences:{minimumConfidence:.55},usage:{pricing:{}},permissions:X},null,2)}
278
+ `,"utf8"),v(`Updated .gitignore with ${s.length} kpilot runtime path(s).`)}async function Ul(t){await L(t);let e=_.join(t,x),n=_.join(e,"config.json"),o=_.join(e,"instructions.md"),r=_.join(e,"skills","review","SKILL.md");await gt(_.dirname(r),{recursive:!0}),await Ue(n)?R(`${_.relative(t,n)} already exists; left unchanged.`):(await me(n,`${JSON.stringify({model:{provider:"kpilot-hosted",baseUrl:"https://api.konsolepilot.ai",model:"auto",route:"auto",streaming:!0},agent:{mode:"write"},sandbox:{mode:"portable",allowNetwork:!1,passEnvironment:[]},subagents:{enabled:!0,maxParallel:4},mcp:{servers:{}},preferences:{minimumConfidence:.55},usage:{pricing:{}},permissions:X},null,2)}
279
279
  `,{encoding:"utf8",mode:384}),await Qt(n,384),v(`Created ${_.relative(t,n)}.`)),await Ue(o)?R(`${_.relative(t,o)} already exists; left unchanged.`):(await me(o,`# Project instructions
280
280
 
281
281
  - Follow the repository's existing architecture and naming conventions.
@@ -288,7 +288,7 @@ description: Inspect a change for correctness, safety, and missing validation.
288
288
  Inspect the relevant implementation and its diff. Prioritize correctness defects, security problems, regressions, missing tests, and inaccurate claims. Report findings by severity with exact file references. Do not modify files unless the invocation explicitly requests fixes.
289
289
  `,"utf8"),v(`Created ${_.relative(t,r)}.`)),await jl(t,[`${x}/sessions/`,`${x}/memory.json`,`${x}/preferences.json`,`${x}/audit/`,`${x}/usage/`,`${x}/run/`,`${x}/cache/`,`${x}/logbook/meta.json`]),P(`kpilot ${B} initialized. Connect your account with \`kpilot login\`; bring your own agent via \`kpilot agents\`.`),P("Log in with `kpilot login` and kpilot handles the rest."),P("On first chat, kpilot can inspect the repo and save a Logbook entry under `.kpilot/logbook/project.md`.")}async function Ll(t){let e=t.args[0]??"routes";if(e==="routes"||e==="list"||e==="show"){let n=await lr();if(!n.length){console.log("No kpilot capabilities are configured for this account yet.");return}console.log($(M.bold,"kpilot capabilities"));for(let o of n){let r=o.isDefault?"default":o.routeKeys.length?`routes: ${o.routeKeys.join(", ")}`:"available";console.log(`${o.model.padEnd(52)} ${o.provider} ${$(M.dim,r)}`)}console.log("For help, contact your kpilot administrator.");return}if(e==="route"){let n=t.args.slice(1).join(" ").trim();if(!n)throw new Error("Usage: kpilot models route <prompt>");let o=Rt(n),s=(await lr()).find(i=>i.routeKeys.includes(o.route))?.model??null;console.log(JSON.stringify({...o,selected:s},null,2));return}throw new Error("Usage: kpilot models [routes|route] [prompt]")}async function lr(){let e=await new Y().validAccessToken();if(!e)throw new Error("kpilot needs an account. Run `kpilot login`.");let n=await e.client.catalog(e.tokens.accessToken),o=new Map;for(let[r,s]of Object.entries(n.routeCandidates??{}))for(let i of s){let a=o.get(i.model)??{provider:i.provider,isDefault:i.isDefault,routeKeys:[]};a.routeKeys.push(r),i.isDefault&&(a.isDefault=!0),o.set(i.model,a)}return[...o.entries()].map(([r,s])=>({model:r,provider:s.provider,isDefault:s.isDefault,routeKeys:s.routeKeys}))}async function Ss(t){await L(t.cwd);let e=_.join(t.cwd,x,"config.json"),n=await cr(e),o=t.args[0]??"show";if(o==="show"){if(n.model?.provider!=="external-agent"){console.log("[no project external agent configured]");return}console.log(JSON.stringify({provider:n.model.provider,command:n.model.command,commandArgs:n.model.commandArgs,endpoint:n.model.endpoint,timeoutMs:n.model.timeoutMs},null,2));return}if(o==="use-http"){let r=t.args[1];if(!r)throw new Error("Usage: kpilot agents use-http <http-or-https-endpoint>");let s=new URL(r);if(!["http:","https:"].includes(s.protocol))throw new Error("External-agent endpoint must use HTTP or HTTPS.");let i=n.model??{},{command:a,commandArgs:c,endpoint:l,...u}=i;n.model={...u,provider:"external-agent",model:"external-agent",endpoint:s.toString()},await gt(_.dirname(e),{recursive:!0}),await me(e,`${JSON.stringify(n,null,2)}
290
290
  `,{encoding:"utf8",mode:384}),await Qt(e,384),v(`Configured project external agent endpoint ${s.toString()}.`);return}if(o==="use-command"){let r=t.args[1];if(!r)throw new Error("Usage: kpilot agents use-command <executable> [args...]");let s=n.model??{},{command:i,commandArgs:a,endpoint:c,...l}=s;n.model={...l,provider:"external-agent",model:"external-agent",command:r,commandArgs:t.args.slice(2)},await gt(_.dirname(e),{recursive:!0}),await me(e,`${JSON.stringify(n,null,2)}
291
- `,{encoding:"utf8",mode:384}),await Qt(e,384),v(`Configured project external agent command ${r}.`);return}if(o==="clear"){n.model={provider:"kpilot-hosted",baseUrl:"https://api.kpilot.ai",model:"auto",route:"auto",streaming:!0},await gt(_.dirname(e),{recursive:!0}),await me(e,`${JSON.stringify(n,null,2)}
291
+ `,{encoding:"utf8",mode:384}),await Qt(e,384),v(`Configured project external agent command ${r}.`);return}if(o==="clear"){n.model={provider:"kpilot-hosted",baseUrl:"https://api.konsolepilot.ai",model:"auto",route:"auto",streaming:!0},await gt(_.dirname(e),{recursive:!0}),await me(e,`${JSON.stringify(n,null,2)}
292
292
  `,{encoding:"utf8",mode:384}),await Qt(e,384),v("Removed the project external agent and restored kpilot automatic routing.");return}throw new Error("Usage: kpilot agents [show|use-http|use-command|clear] [endpoint-or-command] [args...]")}async function ar(t){return await new Promise(e=>{let n=process.platform==="win32"?"where":"sh",o=process.platform==="win32"?[t]:["-lc",`command -v "${t}" >/dev/null 2>&1`],r=bs(n,o,{stdio:"ignore"});r.once("error",()=>e(!1)),r.once("close",s=>e(s===0))})}async function Nl(t){await L(t.cwd);let e=await oe(t.cwd),n=z(t.cwd),o=await n.policy.load(),r=Le(t,e,o),s=0,i=Number(process.version.slice(1).split(".")[0]);console.log($(M.bold,`kpilot doctor \u2014 ${t.cwd}`)),i>=26?v(`Node.js ${process.version}`):(F(`Node.js ${process.version}; Node.js 26 or newer is required.`),s+=1),await ar("git")?v("Git is available."):R("Git is unavailable; status, diff, and feedback evidence will be limited."),await ar("rg")?v("ripgrep is available."):R("ripgrep is unavailable; search_text will use the slower built-in fallback.");let a=r.model&&r.model!=="auto"?`kpilot capability: ${r.model}`:"kpilot automatic routing (kpilot chooses for you).";v(a);let c=Ee(r.provider);v(`Authenticated: ${c.name} (${c.id}).`),r.provider==="kpilot-hosted"?await new Y().load()?v("Your kpilot account is connected."):(F("kpilot needs an account. Run `kpilot login`."),s+=1):r.provider==="external-agent"&&(r.modelConfig.endpoint?v(`External agent endpoint configured: ${r.modelConfig.endpoint}`):r.modelConfig.command&&await ar(r.modelConfig.command)?v(`External agent command is available: ${r.modelConfig.command}`):(F("External agent requires a reachable endpoint or available command."),s+=1)),v(`${(await n.sessions.list()).length} persistent session(s) readable.`),v(`${(await n.memory.list()).length} project memory entr${(await n.memory.list()).length===1?"y":"ies"} readable.`),v(`${(await n.skills.list()).length} reusable skill(s) discovered.`),v(`${(await n.preferences.listRules()).length} learned preference rule(s) readable.`),o?v(`Team policy loaded${o.organization?` for ${o.organization}`:""}.`):P("Team policy: not configured.");let l=await n.usage.check(r.usageBudget);l.allowed?v(`Usage budget available: ${je(l.summary.totalTokens)} token(s) used today.`):(F(`Usage budget blocked: ${l.violations.join(" ")}`),s+=1);let u=await n.audit.verify();u.valid?v(`Audit chain valid: ${u.records} record(s).`):(F(`Audit chain invalid: ${u.reason??"unknown failure"}`),s+=1);let d=new ae(t.cwd,{sandbox:e.sandbox});try{v(`Sandbox: ${await d.sandbox.describe()}.`)}catch(f){F(f instanceof Error?f.message:String(f)),s+=1}let p=Object.entries(e.mcp?.servers??{}).filter(([f,y])=>y.enabled!==!1&&(!o?.allowedMcpServers||o.allowedMcpServers.includes(f)));if(p.length===0)P("MCP: no enabled servers configured.");else try{let f=await we.connect(Object.fromEntries(p));v(`MCP: ${p.length} server(s), ${f.list().length} tool(s) available.`),await f.close()}catch(f){F(`MCP: ${f instanceof Error?f.message:String(f)}`),s+=1}r.baseUrl&&P(`Endpoint: ${r.baseUrl}`);let b=r.maxSteps===void 0?"unlimited":String(r.maxSteps);return P(`Mode: ${r.mode}; max steps: ${b}; streaming: ${r.streaming?"on":"off"}`),s===0?0:1}var ur;function de(){ur?.stop(),ur=void 0}function Bl(t){return"kpilot"}function wr(t){return $(M.green,Bl(t))}function De(t){t.lineOpen&&(process.stdout.write(`
293
293
  `),t.lineOpen=!1)}function ql(t,e,n,o){let r=wr(n);return s=>{if((s.type==="assistant_delta"||s.type==="assistant_text"||s.type==="tool_start"||s.type==="permission"||s.type==="cancelled")&&(de(),e.thinking=void 0),s.type==="reasoning_delta"){o?.reasoningDelta(s.delta);return}if(s.type==="step"){o?.setStep(s.current,s.maximum);return}if(s.type==="assistant_delta")e.lineOpen||(de(),process.stdout.isTTY||process.stdout.write(`
294
294
  `),process.stdout.write(`${r} \u203A `),e.lineOpen=!0),e.streamed=!0,process.stdout.write(s.delta);else if(s.type==="tool_start")De(e),o?.clearReasoning(),o?.activity("start",s.call.function.name,on(s.args,s.call.function.name)),o?.start();else if(s.type==="tool_result"){De(e);let i=s.result.ok?s.result.metadata&&Object.keys(s.result.metadata).length?JSON.stringify(s.result.metadata).slice(0,60):"":"\u2717";o?.activity("result",s.call.function.name,i),(t||!s.result.ok)&&console.log($(M.dim,s.result.output))}else if(s.type==="permission"&&s.request.decision!=="allow"){De(e);let i=s.approved?$(M.green,"approved"):$(M.red,"denied");console.log(`${$(M.yellow,"permission")} ${s.request.category}: ${i}`)}else s.type==="usage"?(e.inputTokens+=s.inputTokens,e.outputTokens+=s.outputTokens,o?.addUsage(s.inputTokens,s.outputTokens)):s.type==="cancelled"&&(De(e),o?.finish(),R(s.reason))}}async function yr(t){let e=new AbortController,n=()=>e.abort("Ctrl+C");process.once("SIGINT",n);try{return await t(e.signal)}finally{process.removeListener("SIGINT",n)}}function Fl(t){return`Approve ${t.category}?
@@ -308,7 +308,7 @@ ${n.instructions}`:void 0}}async function br(t){let e={streamed:!1,lineOpen:!1,i
308
308
  ${r}
309
309
  ${s}
310
310
  ${r}
311
- ${i}\x1B[2A\r`);try{return await Yl(t,s,n)}finally{process.stdout.write("\x1B[2B\r")}}function Rs(t){return t.controlPlaneUrl??process.env.KPILOT_CONTROL_PLANE_URL??"https://api.kpilot.ai"}async function Zl(t){let e=process.platform,n=e==="darwin"?"open":e==="win32"?"cmd":"xdg-open",o=e==="darwin"?[t]:e==="win32"?["/c","start","",t]:[t];return await new Promise(r=>{let s=bs(n,o,{stdio:"ignore",detached:!0});s.unref(),s.once("error",()=>r(!1)),s.once("spawn",()=>r(!0))})}async function eu(t){let e=new Y,n=await e.load(),o=new Z(t.controlPlaneUrl??n?.controlPlaneUrl??Rs(t),`kpilot/${B}`);if(n?await e.validAccessToken(o):void 0)return;if(!process.stdin.isTTY)throw new Error("kpilot needs an account to continue. Run `kpilot login`.");if(P("kpilot needs your account to continue. Starting sign-in\u2026"),await Ms(t),!await e.load())throw new Error("kpilot needs an account to continue. Run `kpilot login`.")}async function Ms(t){let e=new Z(Rs(t),`kpilot/${B}`),n=new Y,o=await n.load();if(o&&!t.force)throw new Error(`Already signed in as ${o.user.email}. Run \`kpilot logout\` first, or use --force.`);let r=await e.createDeviceCode(),s=r.verification_uri_complete||`${r.verification_uri}?code=${encodeURIComponent(r.user_code)}`,i=t.noBrowser||process.env.KPILOT_NO_BROWSER==="1",a=!1;i||(a=await Zl(s)),a?(console.log(`
311
+ ${i}\x1B[2A\r`);try{return await Yl(t,s,n)}finally{process.stdout.write("\x1B[2B\r")}}function Rs(t){return t.controlPlaneUrl??process.env.KPILOT_CONTROL_PLANE_URL??"https://api.konsolepilot.ai"}async function Zl(t){let e=process.platform,n=e==="darwin"?"open":e==="win32"?"cmd":"xdg-open",o=e==="darwin"?[t]:e==="win32"?["/c","start","",t]:[t];return await new Promise(r=>{let s=bs(n,o,{stdio:"ignore",detached:!0});s.unref(),s.once("error",()=>r(!1)),s.once("spawn",()=>r(!0))})}async function eu(t){let e=new Y,n=await e.load(),o=new Z(t.controlPlaneUrl??n?.controlPlaneUrl??Rs(t),`kpilot/${B}`);if(n?await e.validAccessToken(o):void 0)return;if(!process.stdin.isTTY)throw new Error("kpilot needs an account to continue. Run `kpilot login`.");if(P("kpilot needs your account to continue. Starting sign-in\u2026"),await Ms(t),!await e.load())throw new Error("kpilot needs an account to continue. Run `kpilot login`.")}async function Ms(t){let e=new Z(Rs(t),`kpilot/${B}`),n=new Y,o=await n.load();if(o&&!t.force)throw new Error(`Already signed in as ${o.user.email}. Run \`kpilot logout\` first, or use --force.`);let r=await e.createDeviceCode(),s=r.verification_uri_complete||`${r.verification_uri}?code=${encodeURIComponent(r.user_code)}`,i=t.noBrowser||process.env.KPILOT_NO_BROWSER==="1",a=!1;i||(a=await Zl(s)),a?(console.log(`
312
312
  Opened ${s}`),console.log(`Confirm code ${$(M.bold,r.user_code)} in your browser if prompted.
313
313
  `),P("Approve the device in your browser. Press Ctrl+C to cancel.")):(console.log(`
314
314
  Open: ${s}`),console.log(`Code: ${$(M.bold,r.user_code)}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kpilot",
3
- "version": "0.10.8",
3
+ "version": "0.10.9",
4
4
  "description": "Proprietary terminal AI coding pilot with hosted automatic model routing, account management, and billing.",
5
5
  "type": "module",
6
6
  "license": "UNLICENSED",