mu-agent 0.2.1 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,50 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.2.3] - 2026-10-24
6
+
7
+ **0.2.3 adds `mu judge model` for decision models from Hugging Face, makes mu decide when a mid-run message reaches the work, and makes Sign in with ChatGPT cope with a busy port 1455.**
8
+
9
+ ### Added
10
+
11
+ - `mu judge model`: other decision models from Hugging Face, next to mude 1.0. `mu judge model add <link or owner/name>[@revision]` looks the model up on Hugging Face and pins the commit and every file (sha256 for files in LFS, the git hash for the others). It then downloads the model with progress and checks every file, resuming after a stop like `mu judge mude install`. It sets the model up in mude's Python environment, starts its server on 127.0.0.1 and makes it the judge, with the judges from before behind it unless `--local-only`. `list`, `use <name>` (`use mude` switches back), `start`, `stop`, `status`, `disable` and `remove` manage them, and `--json` gives one JSON object per line, as for `mu judge mude`. A model must be packaged like mude 1.0's MLX edition, with its own `d3_server_mac.py`; a repository without one is refused before anything is downloaded. One decision model runs at a time: switching stops the other's server, and mu starts the one that is the judge before a session, as it does mude.
12
+ - `mu judge mude uninstall` keeps the Python environment when models added with `mu judge model` still use it.
13
+ - `mu auth login <provider> --paste` signs in without listening on the callback port: you sign in in the browser, then paste the address it ends on. That works whichever program holds the port.
14
+
15
+ ### Changed
16
+
17
+ - Less small print: `mu --help` no longer says "Formerly KYRN", `mu setup` drops its header line, the sign-in location sentence and the closing footer, and its judge question fits on one line; `mu ledger` drops its help footer, and the kernel part of the in-session `/help` keeps only the Esc and expand keys.
18
+ - mu now decides when a message you send during a run reaches the work: `input.interjection` is active by default (it was in shadow). Enter still sends a steer and Alt+Enter a follow-up, and the judge can move the message. A correction reaches the model at its next step, even when you queued it. Extra work and unrelated questions wait until the run is done, even when you sent them with Enter. Anything else goes the way you sent it. The message waits up to 1.5 s for the verdict (`features.interjection.waitMs`). It goes as sent when the verdict is late, when the judge fails or is off, and when the run ends during the wait. Messages you send in quick succession arrive in the order you sent them, however long each verdict takes. 34 of the 40 decision points now act from the start. To keep the old behavior, put `"input.interjection": "shadow"` under `modes` in `~/.mu/agent/mu.json`.
19
+
20
+ ### Fixed
21
+
22
+ - Sign in with ChatGPT (`/login` and `mu auth login openai`, which the desktop app runs) no longer fails with "Port 1455 is in use" when the port is held by another sign-in of mu or pi. Port 1455 is fixed by OpenAI, and a sign-in keeps it until it ends. Before, a second sign-in started while the first still waited (two in a row from the app, a `/login` left open in a terminal) failed with that message. Now the new sign-in asks the earlier one to let go: the earlier one stops with "Sign-in stopped: a newer sign-in started and took over port 1455", and the new one listens. The Codex CLI's own login takes the port over the same way, with the request it already sends to an older login server.
23
+ - When another program keeps port 1455 (the Codex CLI or the Codex app, while its own login waits), the sign-in now names it: "Port 1455 is in use by codex (process 4321), probably for its own sign-in … Finish or cancel that sign-in, then try again". That program is left alone. `mu auth` passes this on with `code: "port_in_use"`, the port and the program, so the app can say it in its own words. The program is looked up with `lsof` (or `ss`, or `netstat` on Windows); where none answers, the message says "another program".
24
+ - Every way a ChatGPT sign-in ends now gives port 1455 back at once: success, an error, a cancel (Escape in `/login`, `cancel` or the input closing for `mu auth`), SIGTERM to `mu auth` (the app quitting or ending it), and a prompt that never answers. A sign-in nobody finishes stops listening after 15 minutes. The older ChatGPT sign-in through the Codex login (`openai-codex`) takes the port over from an earlier sign-in of mu the same way. When another program keeps the port, it still falls back to the pasted address, and now says which program it is.
25
+ - A mid-run message that the judge moves to the other queue is now expanded like any other: a prompt template or a skill (`/name …`) reaches the model expanded, not as you typed it.
26
+ - A session in RPC mode (each conversation of the desktop app) now checks `get_available_models` and `set_model` against the credential store, so a sign-in or sign-out made by another process counts at once: `mu auth logout`, or `/logout` in another terminal. Before, a signed-out subscription's models stayed listed until the session restarted.
27
+ - `/logout` moves the session off the signed-out provider's model, to the default model (else a provider's default, else the first model available), and says so: "Logged out of ChatGPT. Switched to openai/gpt-5.5." Before, the next prompt failed with "No API key". With no model left, it says to use `/login`.
28
+ - `mu auth logout google-antigravity` also drops the list of models the account gave from `models-store.json`, so the next sign-in starts from its own.
29
+
30
+ ## [0.2.2] - 2026-10-24
31
+
32
+ **0.2.2 makes `mu judge mude install` cope with a full disk, a stop at any step and two installs at once.**
33
+
34
+ ### Changed
35
+
36
+ - English pass on the strings added since 0.1.10, against `docs/writing-style.md`: `mu judge mude` messages say how to resume ("Run mu judge mude install to resume"); errors say what happened and what to do next ("Couldn't create the Python environment (uv venv)", "Hugging Face returned 404 for …", the disk-space error); the kernel's settings descriptions read naturally (their translations kept); `mu --help` describes `mu judge mude install` as "install mude 1.0, mu's own decision model for coding, and make it the judge on this Mac".
37
+
38
+ ### Fixed
39
+
40
+ - `mu judge mude install`: Ctrl-C (or SIGTERM) during the wait between tries after a dropped connection now stops the download at once. It prints "Stopped with X of 1.8 GB downloaded. Run mu judge mude install to resume". Before, the wait (up to 30 s) ran on, and the command ended 5 s later with no message. What was downloaded was kept either way.
41
+ - `mu judge mude install`, disk space and stops:
42
+ - A full disk (ENOSPC or EDQUOT) during the download now ends the install at once with "The disk is full: couldn't write <file>. Free up some space, then run mu judge mude install to resume". Before, it was retried as a network error for about two minutes, and the desktop app said it couldn't reach Hugging Face.
43
+ - The free-space check before a download counts only the bytes still to come. Before, it counted the whole of every unfinished file, even when most of it was on the disk already.
44
+ - Ctrl-C (or SIGTERM) while the Python environment is being set up now says "Stopped while setting up the Python environment. Run mu judge mude install to resume", instead of "mude's Python packages could not be installed".
45
+ - `mu judge mude install` on a Mac without uv: downloading the pinned uv (about 20 MB, from GitHub) had no time limit and ignored a stop. It now ends after 5 minutes with "uv could not be downloaded from GitHub (no answer in 300 s): run mu judge mude install again", and Ctrl-C or the app's Cancel ends it at once ("Stopped while setting up the Python environment").
46
+ - `mu judge mude install` (also from `mu setup` and the desktop app) takes `local-judge/mude/install.lock`. A second install while one runs now stops at once with "Another mude 1.0 install is running (process N). Wait for it to finish, or stop it, then run mu judge mude install again". Before, both downloaded into the same `.part` files, and the second failed with `ENOENT … .part` when the first renamed a finished file. The lock records the process's pid and start time, so a lock left by a power cut or a kill is taken over, even if the pid has since been reused.
47
+ - `mu judge mude install`, `enable` and `start`: a stop (Ctrl-C, or SIGTERM from the app's Cancel) while waiting for the server's `/health` now ends the wait at once. It also stops the server if this command started it, with "Stopped while the mude 1.0 server was starting, and stopped the server too. Run mu judge mude install again to finish". Before, the wait ran on until the CLI's 5 s exit timer, with no message. The server is started `detached`, so it survived both that exit and the app's process-group kill, and kept about 4 GB of memory while mude was not the judge. A server that was already running before the command is left running: "Stopped waiting for the mude 1.0 server, which is still starting…".
48
+
5
49
  ## [0.2.1] - 2026-10-24
6
50
 
7
51
  **0.2.1 makes mude 1.0 the recommended judge on a Mac, set up from `mu setup`, and its install survives a power cut.**
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  **A coding agent with a judgment kernel.** It hands its routine decisions to a small, fast judge model, so the main model can keep its attention on the work.
4
4
 
5
- > Source, docs and the desktop app: [github.com/qybaihe/mu](https://github.com/qybaihe/mu) (README in English, 简体中文, 繁體中文, 日本語 and 한국어).
5
+ > Source, docs and the desktop app: [github.com/qybaihe/mu](https://github.com/qybaihe/mu).
6
6
 
7
7
  ## Install
8
8
 
@@ -13,7 +13,7 @@ mu
13
13
 
14
14
  You need Node.js 22.19 or newer. The package is `mu-agent`; the command is `mu`. It runs on macOS, Linux, Windows and WSL.
15
15
 
16
- `mu setup` connects a model from your shell. Paste an API key and mu detects the service from the key's format (OpenAI, Anthropic, Google Gemini, xAI, OpenRouter, OpenCode Zen, DeepSeek, Qwen, Kimi, GLM, SiliconFlow, StepFun), or pick Ollama or your own endpoint. It checks the key with one request, picks a starting model and sets up the judge. To use a ChatGPT, Grok or Google subscription instead, choose it there and mu starts on `/login`. If no model is set up yet, the first `mu` run offers to start setup.
16
+ `mu setup` connects a model from your shell. Paste an API key and mu detects the service from the key's format (OpenAI, Anthropic, Google Gemini, xAI, OpenRouter, OpenCode Zen, DeepSeek, Qwen, Kimi, GLM, SiliconFlow, StepFun), or pick Ollama or your own endpoint. It checks the key with one request, picks a starting model and sets up the judge. To use a ChatGPT, Grok or Google subscription instead, choose it there and mu starts on `/login`.
17
17
 
18
18
  Inside mu, `/login` signs in to a provider or a subscription and `/model` switches models. `/help` lists everything. `mu doctor` checks your setup from the shell.
19
19
 
@@ -36,7 +36,7 @@ Out of the box, the judge is Jev 1.13, TypeSafe's hosted judge model, free on Op
36
36
  - **Laya** (local, macOS on Apple silicon): `mu judge setup` installs it into `~/.mu/local-judge`. It downloads about 930 MB, and only when you run that command.
37
37
  - **Any model you already use:** `/mu judge llm:<provider>/<model>`.
38
38
 
39
- 33 of the 40 decision points act on their verdicts from the start (`active`); `context.compact` and `output.drift` belong to features that are off until you turn them on, `capability.disclosure` and `swarm.patch` are `off`, and `notify.routing`, `input.interjection` and `turn.drift` are in `shadow`. To only record what the judge would do, run `/mu mode default shadow`, or put `"modes": { "default": "shadow" }` in `~/.mu/agent/mu.json`.
39
+ 34 of the 40 decision points act on their verdicts from the start (`active`). To only record what the judge would do, run `/mu mode default shadow`, or put `"modes": { "default": "shadow" }` in `~/.mu/agent/mu.json`.
40
40
 
41
41
  ## Commands
42
42
 
@@ -58,10 +58,6 @@ mu help | version show this help | print the version
58
58
 
59
59
  Everything else goes to pi unchanged: `mu --help` also shows pi's options. mu keeps its files in `~/.mu`, separate from a regular pi install in `~/.pi`.
60
60
 
61
- ## Themes
62
-
63
- In the terminal, mu uses its own themes, `mu-dark` or `mu-light` to match your terminal, until you pick a theme in `/settings`. Choose `system` there to use your terminal's own palette.
64
-
65
61
  ## Update and remove
66
62
 
67
63
  ```bash
@@ -83,4 +83,4 @@ var __require=(x=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(x,{get:(
83
83
  ${details?`<div class="details">${details}</div>`:""}
84
84
  </main>
85
85
  </body>
86
- </html>`}function oauthSuccessHtml(message){return renderPage({heading:"Signed in",message})}function oauthErrorHtml(message,details){return renderPage({heading:"Sign-in did not complete",message,details})}function sendPage(response,status,html){response.writeHead(status,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),response.end(html)}async function startOAuthCallbackServer(options){let{providerName,signal}=options;if(signal?.aborted)throw new Error("Login cancelled");let resolveWait=()=>{},rejectWait=()=>{},waitPromise=new Promise((resolve,reject)=>{resolveWait=resolve,rejectWait=reject});waitPromise.catch(()=>{});let claimed=!1,settled=!1,timer,onAbort=()=>finish({error:new Error("Login cancelled")}),finish=result=>{settled||(settled=!0,timer&&clearTimeout(timer),signal?.removeEventListener("abort",onAbort),"error"in result?rejectWait(result.error):resolveWait(result.value))},server=createServer((request,response)=>{(async()=>{let url=new URL(request.url??"/","http://localhost");if(request.method!=="GET"||url.pathname!==options.path){sendPage(response,404,oauthErrorHtml("Callback route not found."));return}if(options.state!==void 0&&url.searchParams.get("state")!==options.state){sendPage(response,400,oauthErrorHtml("State mismatch."));return}if(claimed||settled){sendPage(response,409,oauthErrorHtml("This sign-in has already been handled."));return}let error=url.searchParams.get("error");if(error){let description=url.searchParams.get("error_description")??error;sendPage(response,400,oauthErrorHtml(`${providerName} authorization failed.`,description)),finish({error:new Error(`${providerName} authorization failed: ${description}`)});return}let code=url.searchParams.get("code");if(!code){sendPage(response,400,oauthErrorHtml("Missing authorization code."));return}claimed=!0;try{let value=await options.complete(code);sendPage(response,200,oauthSuccessHtml(`Signed in to ${providerName}. You may now close this page.`)),finish({value})}catch(error2){let failure=error2 instanceof Error?error2:new Error(String(error2));sendPage(response,502,oauthErrorHtml(`${providerName} sign-in failed.`,failure.message)),finish({error:failure})}})()});await new Promise((resolve,reject)=>{server.once("error",reject),server.listen(options.port,options.host,()=>{server.off("error",reject),resolve()})});let address=server.address();if(!address||typeof address=="string")throw server.close(),new Error("OAuth callback server did not bind to TCP");server.on("error",error=>finish({error})),signal?.addEventListener("abort",onAbort,{once:!0}),options.timeoutMs!==void 0&&(timer=setTimeout(()=>finish({error:new Error(`${providerName} sign-in timed out`)}),options.timeoutMs));let redirectHost=options.redirectHost??options.host;return{redirectUri:`http://${redirectHost.includes(":")?`[${redirectHost}]`:redirectHost}:${address.port}${options.path}`,wait:()=>waitPromise,cancel:()=>{claimed||finish({value:void 0})},close:()=>{finish({error:new Error("OAuth callback server closed")}),server.close()}}}async function waitForCallbackOrManualInput(interaction,callback,prompt){let manualAbort=new AbortController,manualError,manual=interaction.prompt({type:"manual_code",...prompt,signal:manualAbort.signal}).then(input=>(callback?.cancel(),input)).catch(error=>{manualError=error instanceof Error?error:new Error(String(error)),callback?.cancel()});try{let value=await callback?.wait();if(manualError)throw manualError;if(value!==void 0)return{type:"callback",value};let input=await manual;if(manualError)throw manualError;return{type:"manual",input:input??""}}finally{manualAbort.abort()}}function base64urlEncode(bytes){let binary="";for(let byte of bytes)binary+=String.fromCharCode(byte);return btoa(binary).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function generatePKCE(){let verifierBytes=new Uint8Array(32);crypto.getRandomValues(verifierBytes);let verifier=base64urlEncode(verifierBytes),data=new TextEncoder().encode(verifier),hashBuffer=await crypto.subtle.digest("SHA-256",data),challenge=base64urlEncode(new Uint8Array(hashBuffer));return{verifier,challenge}}var decode=s=>atob(s),CLIENT_ID=decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl"),AUTHORIZE_URL="https://claude.ai/oauth/authorize",TOKEN_URL="https://platform.claude.com/v1/oauth/token",CALLBACK_HOST=getProviderEnvValue("PI_OAUTH_CALLBACK_HOST")||"127.0.0.1",CALLBACK_PORT=53692,CALLBACK_PATH="/callback",REDIRECT_URI=`http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`,COPY_CODE_REDIRECT_URI="https://platform.claude.com/oauth/code/callback",ANTHROPIC_BROWSER_LOGIN_METHOD="browser",ANTHROPIC_COPY_CODE_LOGIN_METHOD="copy_code",SCOPES="org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload";function parseAuthorizationInput(input){let value=input.trim();if(!value)return{};try{let url=new URL(value);return{code:url.searchParams.get("code")??void 0,state:url.searchParams.get("state")??void 0}}catch{}if(value.includes("#")){let[code,state]=value.split("#",2);return{code,state}}if(value.includes("code=")){let params=new URLSearchParams(value);return{code:params.get("code")??void 0,state:params.get("state")??void 0}}return{code:value}}function formatErrorDetails(error){if(error instanceof Error){let details=[`${error.name}: ${error.message}`],errorWithCode=error;return errorWithCode.code&&details.push(`code=${errorWithCode.code}`),typeof errorWithCode.errno<"u"&&details.push(`errno=${String(errorWithCode.errno)}`),typeof error.cause<"u"&&details.push(`cause=${formatErrorDetails(error.cause)}`),error.stack&&details.push(`stack=${error.stack}`),details.join("; ")}return String(error)}async function postJson(url,body,signal){let response=await fetch(url,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(body),signal:AbortSignal.any([signal,AbortSignal.timeout(3e4)])}),responseBody=await response.text();if(!response.ok)throw new Error(`HTTP request failed. status=${response.status}; url=${url}; body=${responseBody}`);return responseBody}async function exchangeAuthorizationCode(code,state,verifier,redirectUri,signal){let responseBody;try{responseBody=await postJson(TOKEN_URL,{grant_type:"authorization_code",client_id:CLIENT_ID,code,state,redirect_uri:redirectUri,code_verifier:verifier},signal)}catch(error){throw new Error(`Token exchange request failed. url=${TOKEN_URL}; redirect_uri=${redirectUri}; response_type=authorization_code; details=${formatErrorDetails(error)}`)}let tokenData;try{tokenData=JSON.parse(responseBody)}catch(error){throw new Error(`Token exchange returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`)}return{type:"oauth",refresh:tokenData.refresh_token,access:tokenData.access_token,expires:Date.now()+tokenData.expires_in*1e3-300*1e3}}async function loginAnthropic(interaction){let{verifier,challenge}=await generatePKCE(),startCallbackServer=port=>startOAuthCallbackServer({providerName:"Anthropic",host:CALLBACK_HOST,port,path:CALLBACK_PATH,redirectHost:"localhost",state:verifier,complete:async code=>code,signal:interaction.signal}),callback=await startCallbackServer(CALLBACK_PORT).catch(()=>startCallbackServer(0)).catch(()=>{}),redirectUri=callback?.redirectUri??REDIRECT_URI;try{let authParams=new URLSearchParams({code:"true",client_id:CLIENT_ID,response_type:"code",redirect_uri:redirectUri,scope:SCOPES,code_challenge:challenge,code_challenge_method:"S256",state:verifier});interaction.notify({type:"auth_url",url:`${AUTHORIZE_URL}?${authParams.toString()}`,instructions:"Complete login in your browser. If the browser is on another machine, paste the final redirect URL here."});let result=await waitForCallbackOrManualInput(interaction,callback,{message:"Complete login in your browser, or paste the authorization code / redirect URL here:",placeholder:redirectUri}),code,state=verifier;if(result.type==="callback")code=result.value;else{let parsed=parseAuthorizationInput(result.input);if(parsed.state&&parsed.state!==verifier)throw new Error("OAuth state mismatch");code=parsed.code,state=parsed.state??verifier}if(!code)throw new Error("Missing authorization code");return interaction.notify({type:"progress",message:"Exchanging authorization code for tokens..."}),await exchangeAuthorizationCode(code,state,verifier,redirectUri,interaction.signal)}finally{callback?.close()}}async function loginAnthropicCopyCode(interaction){let{verifier,challenge}=await generatePKCE(),authParams=new URLSearchParams({code:"true",client_id:CLIENT_ID,response_type:"code",redirect_uri:COPY_CODE_REDIRECT_URI,scope:SCOPES,code_challenge:challenge,code_challenge_method:"S256",state:verifier});interaction.notify({type:"auth_url",url:`${AUTHORIZE_URL}?${authParams.toString()}`,instructions:"Complete login in your browser, then copy the code Anthropic shows and paste it here."});let input=await interaction.prompt({type:"manual_code",message:"Paste the code Anthropic shows after you sign in:",placeholder:"code#state",signal:interaction.signal}),parsed=parseAuthorizationInput(input);if(parsed.state&&parsed.state!==verifier)throw new Error("OAuth state mismatch");if(!parsed.code)throw new Error("Missing authorization code");return interaction.notify({type:"progress",message:"Exchanging authorization code for tokens..."}),await exchangeAuthorizationCode(parsed.code,parsed.state??verifier,verifier,COPY_CODE_REDIRECT_URI,interaction.signal)}async function refreshAnthropicToken(refreshToken,signal){let responseBody;try{responseBody=await postJson(TOKEN_URL,{grant_type:"refresh_token",client_id:CLIENT_ID,refresh_token:refreshToken},signal)}catch(error){throw new Error(`Anthropic token refresh request failed. url=${TOKEN_URL}; details=${formatErrorDetails(error)}`)}let data;try{data=JSON.parse(responseBody)}catch(error){throw new Error(`Anthropic token refresh returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`)}return{type:"oauth",refresh:data.refresh_token,access:data.access_token,expires:Date.now()+data.expires_in*1e3-300*1e3}}var anthropicOAuth={name:"Anthropic (Claude Pro/Max)",isSubscription:!0,async login(interaction){let method=await interaction.prompt({type:"select",message:"Select Anthropic login method:",options:[{id:ANTHROPIC_BROWSER_LOGIN_METHOD,label:"Browser login (default)"},{id:ANTHROPIC_COPY_CODE_LOGIN_METHOD,label:"Copy code login (headless)"}]});if(method===ANTHROPIC_COPY_CODE_LOGIN_METHOD)return loginAnthropicCopyCode(interaction);if(method!==ANTHROPIC_BROWSER_LOGIN_METHOD)throw new Error(`Unknown Anthropic login method: ${method}`);return loginAnthropic(interaction)},refresh:(credential,signal)=>refreshAnthropicToken(credential.refresh,signal),async toAuth(credential){return{apiKey:credential.access}}};export{anthropicOAuth};
86
+ </html>`}function oauthSuccessHtml(message){return renderPage({heading:"Signed in",message})}function oauthErrorHtml(message,details){return renderPage({heading:"Sign-in did not complete",message,details})}import{execFile}from"node:child_process";import{request}from"node:http";var LOGIN_PROBE_PATH="/pi-login",LOGIN_TAKE_OVER_PATH="/pi-login/take-over",CODEX_CANCEL_PATH="/cancel",MARKER_HEADER="x-pi-login",OLD_PI_NOT_FOUND="Callback route not found.",SETTLE_MS=2500,RETRY_MS=100,REQUEST_MS=1e3,LOOKUP_MS=2e3;function describeHolder(holder){let pid=holder?.pid?`process ${holder.pid}`:void 0;return holder?.command?pid?`${holder.command} (${pid})`:holder.command:pid??"another program"}var CallbackPortInUseError=class extends Error{code="port_in_use";port;holder;constructor(port,holder){super(holder?.pi?`Port ${port} is held by an unfinished sign-in in another pi or mu session (${describeHolder(holder)}), which did not hand it over. Finish or cancel that sign-in, then try again.`:`Port ${port} is in use by ${describeHolder(holder)}, probably for its own sign-in (the Codex CLI and the Codex app use this port). Finish or cancel that sign-in, then try again.`),this.name="CallbackPortInUseError",this.port=port,this.holder=holder}},LoginTakenOverError=class extends Error{code="login_taken_over";constructor(port,by){super(by==="codex"?`Sign-in stopped: the Codex CLI started its own sign-in on port ${port}.`:`Sign-in stopped: a newer sign-in started and took over port ${port}.`),this.name="LoginTakenOverError"}};function answerLoginControl(request2,response,takeOver){let path=new URL(request2.url??"/","http://localhost").pathname,fromBrowser=request2.headers.origin!==void 0||request2.headers["sec-fetch-site"]!==void 0;if(request2.method==="GET"&&path===LOGIN_PROBE_PATH)return response.writeHead(200,{"content-type":"application/json","cache-control":"no-store",[MARKER_HEADER]:"pi"}),response.end(JSON.stringify({pi:!0,pid:process.pid})),!0;let ours=request2.method==="POST"&&path===LOGIN_TAKE_OVER_PATH&&request2.headers[MARKER_HEADER]==="take-over"&&!fromBrowser,codex=request2.method==="GET"&&path===CODEX_CANCEL_PATH&&!fromBrowser;return!ours&&!codex?!1:(response.once("close",()=>takeOver(ours?"pi":"codex")),response.writeHead(200,{"content-type":"text/plain; charset=utf-8","cache-control":"no-store"}),response.end("Login cancelled"),!0)}function closeCallbackServer(server){server.close(),server.closeAllConnections()}function localRequest(host,port,method,path,headers){return new Promise(resolve=>{let outgoing=request({host,port,method,path,headers,timeout:REQUEST_MS,agent:!1},incoming=>{let body="";incoming.setEncoding("utf8"),incoming.on("data",chunk=>{body.length<16384&&(body+=chunk)}),incoming.on("end",()=>resolve({status:incoming.statusCode??0,headers:incoming.headers,body})),incoming.on("error",()=>resolve({status:incoming.statusCode??0,headers:incoming.headers,body}))});outgoing.on("timeout",()=>outgoing.destroy(new Error("timeout"))),outgoing.on("error",error=>resolve({error:error.code??error.message})),outgoing.end()})}async function probeHolder(host,port){let answer=await localRequest(host,port,"GET",LOGIN_PROBE_PATH,{[MARKER_HEADER]:"probe"});if("error"in answer)return answer.error==="ECONNREFUSED"?{kind:"none"}:{kind:"other"};if(answer.status===200&&answer.headers[MARKER_HEADER]==="pi")try{let pid=JSON.parse(answer.body).pid;return{kind:"pi",pid:typeof pid=="number"?pid:void 0}}catch{return{kind:"pi"}}return answer.status===404&&answer.body.includes(OLD_PI_NOT_FOUND)?{kind:"old-pi"}:{kind:"other"}}function tryListen(server,port,host){return new Promise(resolve=>{let onError=error=>{server.off("listening",onListening),resolve(error)},onListening=()=>{server.off("error",onError),resolve(void 0)};server.once("error",onError),server.once("listening",onListening),server.listen(port,host)})}function cancelled(){return new Error("Login cancelled")}function pause(ms,signal){return new Promise((resolve,reject)=>{if(signal?.aborted){reject(cancelled());return}let onAbort=()=>{clearTimeout(timer),reject(cancelled())},timer=setTimeout(()=>{signal?.removeEventListener("abort",onAbort),resolve()},ms);signal?.addEventListener("abort",onAbort,{once:!0})})}async function listenOnLoginPort(server,options){let{port,host,signal}=options,settleMs=options.settleMs??SETTLE_MS,deadline=Date.now()+settleMs,askedToLetGo=!1,probe;for(;;){if(signal?.aborted)throw cancelled();let error=await tryListen(server,port,host);if(!error){if(signal?.aborted)throw closeCallbackServer(server),cancelled();return}if(error.code!=="EADDRINUSE")throw error;if(!askedToLetGo&&probe?.kind!=="other"&&probe?.kind!=="old-pi"&&(probe=await probeHolder(host,port),probe.kind==="pi"&&(await localRequest(host,port,"POST",LOGIN_TAKE_OVER_PATH,{[MARKER_HEADER]:"take-over"}),askedToLetGo=!0,deadline=Date.now()+settleMs)),Date.now()>=deadline)break;await pause(RETRY_MS,signal)}let found=await(options.findHolder??findPortHolder)(port).catch(()=>{}),holder={...found,pid:found?.pid??(probe?.kind==="pi"?probe.pid:void 0),...probe?.kind==="pi"||probe?.kind==="old-pi"?{pi:!0}:{}};throw new CallbackPortInUseError(port,holder.pid||holder.command||holder.pi?holder:void 0)}function run(command,args){return new Promise(resolve=>{execFile(command,args,{timeout:LOOKUP_MS,windowsHide:!0,encoding:"utf8"},(error,stdout)=>{resolve(error&&error.code==="ENOENT"?void 0:String(stdout??""))})})}function parseLsof(output){let holder;for(let line of output.split(/\r?\n/))if(line.startsWith("p")){if(holder)break;let pid=Number(line.slice(1));holder=Number.isInteger(pid)&&pid>0?{pid}:{}}else line.startsWith("c")&&holder&&(holder.command=line.slice(1));return holder}function parseSs(output){let match=/users:\(\("([^"]*)",pid=(\d+)/.exec(output);return match?{command:match[1],pid:Number(match[2])}:void 0}function parseNetstat(output,port){for(let line of output.split(/\r?\n/)){let columns=line.trim().split(/\s+/);if(columns.length<5||columns[0]?.toUpperCase()!=="TCP"||!columns[1]?.endsWith(`:${port}`)||columns[3]?.toUpperCase()!=="LISTENING")continue;let pid=Number(columns[4]);if(Number.isInteger(pid)&&pid>0)return pid}}function parseTasklist(output){return/^"([^"]+)"/.exec(output.trim())?.[1]?.replace(/\.exe$/i,"")}async function findPortHolder(port){if(process.platform==="win32"){let pid=parseNetstat(await run("netstat",["-ano","-p","TCP"])??"",port);if(!pid)return;let command=parseTasklist(await run("tasklist",["/FI",`PID eq ${pid}`,"/FO","CSV","/NH"])??"");return command?{pid,command}:{pid}}for(let lsof of["lsof","/usr/sbin/lsof","/usr/bin/lsof"]){let output=await run(lsof,["-nP",`-iTCP:${port}`,"-sTCP:LISTEN","-Fpc"]);if(output!==void 0)return parseLsof(output)}if(process.platform==="linux")return parseSs(await run("ss",["-Hltnp",`sport = :${port}`])??"")}function sendPage(response,status,html){response.writeHead(status,{"content-type":"text/html; charset=utf-8","cache-control":"no-store"}),response.end(html)}async function startOAuthCallbackServer(options){let{providerName,signal}=options;if(signal?.aborted)throw new Error("Login cancelled");let resolveWait=()=>{},rejectWait=()=>{},waitPromise=new Promise((resolve,reject)=>{resolveWait=resolve,rejectWait=reject});waitPromise.catch(()=>{});let claimed=!1,settled=!1,timer,onAbort=()=>finish({error:new Error("Login cancelled")}),finish=result=>{settled||(settled=!0,timer&&clearTimeout(timer),signal?.removeEventListener("abort",onAbort),"error"in result?rejectWait(result.error):resolveWait(result.value))},server=createServer((request2,response)=>{(async()=>{let takeOver=by=>{finish({error:new LoginTakenOverError(options.port,by)}),closeCallbackServer(server)};if(options.sharedPort&&answerLoginControl(request2,response,takeOver))return;let url=new URL(request2.url??"/","http://localhost");if(request2.method!=="GET"||url.pathname!==options.path){sendPage(response,404,oauthErrorHtml("Callback route not found."));return}if(options.state!==void 0&&url.searchParams.get("state")!==options.state){sendPage(response,400,oauthErrorHtml("State mismatch."));return}if(claimed||settled){sendPage(response,409,oauthErrorHtml("This sign-in has already been handled."));return}let error=url.searchParams.get("error");if(error){let description=url.searchParams.get("error_description")??error;sendPage(response,400,oauthErrorHtml(`${providerName} authorization failed.`,description)),finish({error:new Error(`${providerName} authorization failed: ${description}`)});return}let code=url.searchParams.get("code");if(!code){sendPage(response,400,oauthErrorHtml("Missing authorization code."));return}claimed=!0;try{let value=await options.complete(code);sendPage(response,200,oauthSuccessHtml(`Signed in to ${providerName}. You may now close this page.`)),finish({value})}catch(error2){let failure=error2 instanceof Error?error2:new Error(String(error2));sendPage(response,502,oauthErrorHtml(`${providerName} sign-in failed.`,failure.message)),finish({error:failure})}})()});options.sharedPort?await listenOnLoginPort(server,{port:options.port,host:options.host,signal}):await new Promise((resolve,reject)=>{server.once("error",reject),server.listen(options.port,options.host,()=>{server.off("error",reject),resolve()})});let address=server.address();if(!address||typeof address=="string")throw server.close(),new Error("OAuth callback server did not bind to TCP");server.on("error",error=>finish({error})),signal?.addEventListener("abort",onAbort,{once:!0}),options.timeoutMs!==void 0&&(timer=setTimeout(()=>finish({error:new Error(`${providerName} sign-in timed out`)}),options.timeoutMs));let redirectHost=options.redirectHost??options.host;return{redirectUri:`http://${redirectHost.includes(":")?`[${redirectHost}]`:redirectHost}:${address.port}${options.path}`,wait:()=>waitPromise,cancel:()=>{claimed||finish({value:void 0})},close:()=>{finish({error:new Error("OAuth callback server closed")}),options.sharedPort?closeCallbackServer(server):server.close()}}}async function waitForCallbackOrManualInput(interaction,callback,prompt){let manualAbort=new AbortController,manualError,manual=interaction.prompt({type:"manual_code",...prompt,signal:manualAbort.signal}).then(input=>(callback?.cancel(),input)).catch(error=>{manualError=error instanceof Error?error:new Error(String(error)),callback?.cancel()});try{let value=await callback?.wait();if(manualError)throw manualError;if(value!==void 0)return{type:"callback",value};let input=await manual;if(manualError)throw manualError;return{type:"manual",input:input??""}}finally{manualAbort.abort()}}function base64urlEncode(bytes){let binary="";for(let byte of bytes)binary+=String.fromCharCode(byte);return btoa(binary).replace(/\+/g,"-").replace(/\//g,"_").replace(/=/g,"")}async function generatePKCE(){let verifierBytes=new Uint8Array(32);crypto.getRandomValues(verifierBytes);let verifier=base64urlEncode(verifierBytes),data=new TextEncoder().encode(verifier),hashBuffer=await crypto.subtle.digest("SHA-256",data),challenge=base64urlEncode(new Uint8Array(hashBuffer));return{verifier,challenge}}var decode=s=>atob(s),CLIENT_ID=decode("OWQxYzI1MGEtZTYxYi00NGQ5LTg4ZWQtNTk0NGQxOTYyZjVl"),AUTHORIZE_URL="https://claude.ai/oauth/authorize",TOKEN_URL="https://platform.claude.com/v1/oauth/token",CALLBACK_HOST=getProviderEnvValue("PI_OAUTH_CALLBACK_HOST")||"127.0.0.1",CALLBACK_PORT=53692,CALLBACK_PATH="/callback",REDIRECT_URI=`http://localhost:${CALLBACK_PORT}${CALLBACK_PATH}`,COPY_CODE_REDIRECT_URI="https://platform.claude.com/oauth/code/callback",ANTHROPIC_BROWSER_LOGIN_METHOD="browser",ANTHROPIC_COPY_CODE_LOGIN_METHOD="copy_code",SCOPES="org:create_api_key user:profile user:inference user:sessions:claude_code user:mcp_servers user:file_upload";function parseAuthorizationInput(input){let value=input.trim();if(!value)return{};try{let url=new URL(value);return{code:url.searchParams.get("code")??void 0,state:url.searchParams.get("state")??void 0}}catch{}if(value.includes("#")){let[code,state]=value.split("#",2);return{code,state}}if(value.includes("code=")){let params=new URLSearchParams(value);return{code:params.get("code")??void 0,state:params.get("state")??void 0}}return{code:value}}function formatErrorDetails(error){if(error instanceof Error){let details=[`${error.name}: ${error.message}`],errorWithCode=error;return errorWithCode.code&&details.push(`code=${errorWithCode.code}`),typeof errorWithCode.errno<"u"&&details.push(`errno=${String(errorWithCode.errno)}`),typeof error.cause<"u"&&details.push(`cause=${formatErrorDetails(error.cause)}`),error.stack&&details.push(`stack=${error.stack}`),details.join("; ")}return String(error)}async function postJson(url,body,signal){let response=await fetch(url,{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(body),signal:AbortSignal.any([signal,AbortSignal.timeout(3e4)])}),responseBody=await response.text();if(!response.ok)throw new Error(`HTTP request failed. status=${response.status}; url=${url}; body=${responseBody}`);return responseBody}async function exchangeAuthorizationCode(code,state,verifier,redirectUri,signal){let responseBody;try{responseBody=await postJson(TOKEN_URL,{grant_type:"authorization_code",client_id:CLIENT_ID,code,state,redirect_uri:redirectUri,code_verifier:verifier},signal)}catch(error){throw new Error(`Token exchange request failed. url=${TOKEN_URL}; redirect_uri=${redirectUri}; response_type=authorization_code; details=${formatErrorDetails(error)}`)}let tokenData;try{tokenData=JSON.parse(responseBody)}catch(error){throw new Error(`Token exchange returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`)}return{type:"oauth",refresh:tokenData.refresh_token,access:tokenData.access_token,expires:Date.now()+tokenData.expires_in*1e3-300*1e3}}async function loginAnthropic(interaction){let{verifier,challenge}=await generatePKCE(),startCallbackServer=port=>startOAuthCallbackServer({providerName:"Anthropic",host:CALLBACK_HOST,port,path:CALLBACK_PATH,redirectHost:"localhost",state:verifier,complete:async code=>code,signal:interaction.signal}),callback=await startCallbackServer(CALLBACK_PORT).catch(()=>startCallbackServer(0)).catch(()=>{}),redirectUri=callback?.redirectUri??REDIRECT_URI;try{let authParams=new URLSearchParams({code:"true",client_id:CLIENT_ID,response_type:"code",redirect_uri:redirectUri,scope:SCOPES,code_challenge:challenge,code_challenge_method:"S256",state:verifier});interaction.notify({type:"auth_url",url:`${AUTHORIZE_URL}?${authParams.toString()}`,instructions:"Complete login in your browser. If the browser is on another machine, paste the final redirect URL here."});let result=await waitForCallbackOrManualInput(interaction,callback,{message:"Complete login in your browser, or paste the authorization code / redirect URL here:",placeholder:redirectUri}),code,state=verifier;if(result.type==="callback")code=result.value;else{let parsed=parseAuthorizationInput(result.input);if(parsed.state&&parsed.state!==verifier)throw new Error("OAuth state mismatch");code=parsed.code,state=parsed.state??verifier}if(!code)throw new Error("Missing authorization code");return interaction.notify({type:"progress",message:"Exchanging authorization code for tokens..."}),await exchangeAuthorizationCode(code,state,verifier,redirectUri,interaction.signal)}finally{callback?.close()}}async function loginAnthropicCopyCode(interaction){let{verifier,challenge}=await generatePKCE(),authParams=new URLSearchParams({code:"true",client_id:CLIENT_ID,response_type:"code",redirect_uri:COPY_CODE_REDIRECT_URI,scope:SCOPES,code_challenge:challenge,code_challenge_method:"S256",state:verifier});interaction.notify({type:"auth_url",url:`${AUTHORIZE_URL}?${authParams.toString()}`,instructions:"Complete login in your browser, then copy the code Anthropic shows and paste it here."});let input=await interaction.prompt({type:"manual_code",message:"Paste the code Anthropic shows after you sign in:",placeholder:"code#state",signal:interaction.signal}),parsed=parseAuthorizationInput(input);if(parsed.state&&parsed.state!==verifier)throw new Error("OAuth state mismatch");if(!parsed.code)throw new Error("Missing authorization code");return interaction.notify({type:"progress",message:"Exchanging authorization code for tokens..."}),await exchangeAuthorizationCode(parsed.code,parsed.state??verifier,verifier,COPY_CODE_REDIRECT_URI,interaction.signal)}async function refreshAnthropicToken(refreshToken,signal){let responseBody;try{responseBody=await postJson(TOKEN_URL,{grant_type:"refresh_token",client_id:CLIENT_ID,refresh_token:refreshToken},signal)}catch(error){throw new Error(`Anthropic token refresh request failed. url=${TOKEN_URL}; details=${formatErrorDetails(error)}`)}let data;try{data=JSON.parse(responseBody)}catch(error){throw new Error(`Anthropic token refresh returned invalid JSON. url=${TOKEN_URL}; body=${responseBody}; details=${formatErrorDetails(error)}`)}return{type:"oauth",refresh:data.refresh_token,access:data.access_token,expires:Date.now()+data.expires_in*1e3-300*1e3}}var anthropicOAuth={name:"Anthropic (Claude Pro/Max)",isSubscription:!0,async login(interaction){let method=await interaction.prompt({type:"select",message:"Select Anthropic login method:",options:[{id:ANTHROPIC_BROWSER_LOGIN_METHOD,label:"Browser login (default)"},{id:ANTHROPIC_COPY_CODE_LOGIN_METHOD,label:"Copy code login (headless)"}]});if(method===ANTHROPIC_COPY_CODE_LOGIN_METHOD)return loginAnthropicCopyCode(interaction);if(method!==ANTHROPIC_BROWSER_LOGIN_METHOD)throw new Error(`Unknown Anthropic login method: ${method}`);return loginAnthropic(interaction)},refresh:(credential,signal)=>refreshAnthropicToken(credential.refresh,signal),async toAuth(credential){return{apiKey:credential.access}}};export{anthropicOAuth};
@@ -0,0 +1,2 @@
1
+ import { createRequire as __piCreateRequire } from "node:module"; const require = __piCreateRequire(import.meta.url);
2
+ import{AgentSession,AgentSessionRuntime,AssistantMessageComponent,BashExecutionComponent,BorderedLoader,BranchSummaryMessageComponent,CURRENT_SESSION_VERSION,CompactionSummaryMessageComponent,CredentialSynchronizationError,CustomEditor,CustomMessageComponent,DEFAULT_COMPACTION_SETTINGS,DefaultPackageManager,DefaultResourceLoader,DynamicBorder,ExtensionEditorComponent,ExtensionInputComponent,ExtensionRunner,ExtensionSelectorComponent,FileModelsStore,FooterComponent,InteractiveMode,LoginDialogComponent,MCP_CONNECTION_EVENT,ModelRegistry,ModelRuntime,ModelSelectorComponent,OAuthSelectorComponent,RpcClient,SessionManager,SessionSelectorComponent,SettingsManager,SettingsSelectorComponent,SkillInvocationMessageComponent,ThinkingSelectorComponent,ToolExecutionComponent,TreeSelectorComponent,UserMessageComponent,UserMessageSelectorComponent,VIRTUAL_MODEL_STATE_ENTRY,applyHttpProxySettings,buildContextEntries,buildSessionContext,buildSessionProjection,calculateContextTokens,collectEntriesForBranchSummary,compact,configureHttpDispatcher,convertToLlm,convertToPng,copyToClipboard,createAgentSession,createAgentSessionFromServices,createAgentSessionRuntime,createAgentSessionServices,createBashTool,createBashToolDefinition,createCodemodeExtension,createCodingTools,createEditTool,createEditToolDefinition,createEventBus,createExtensionRuntime,createFindTool,createFindToolDefinition,createGrepTool,createGrepToolDefinition,createLocalBashOperations,createLocalPowerShellOperations,createLsTool,createLsToolDefinition,createMcpExtension,createPowerShellTool,createPowerShellToolDefinition,createReadOnlyTools,createReadTool,createReadToolDefinition,createSyntheticSourceInfo,createToolSearchExtension,createWriteTool,createWriteToolDefinition,defaultModelPerProvider,defineTool,detectSupportedImageMimeTypeFromFile,discoverAndLoadExtensions,estimateTokens,findCutPoint,findTurnStartIndex,formatDimensionNote,formatSkillsForPrompt,generateBranchSummary,generateDiffString,generateSummary,generateSummaryWithUsage,generateUnifiedPatch,getLastAssistantUsage,getLatestCompactionEntry,isBashToolResult,isEditToolResult,isFindToolResult,isGrepToolResult,isLsToolResult,isPowerShellToolResult,isReadToolResult,isToolCallEventType,isWriteToolResult,loadProjectContextFiles,loadSkills,loadSkillsFromDir,main,migrateSessionEntries,parseArgs,parseFrontmatter,parseSessionEntries,parseSkillBlock,prepareBranchEntries,renderDiff,resizeImage,resolveCliModel,resolveModelScopeWithDiagnostics,runPrintMode,runRpcMode,serializeConversation,sessionEntryToContextMessages,setupCli,shouldCompact,stdioRpcTransport,stripFrontmatter,withFileMutationQueue,wrapRegisteredTool,wrapRegisteredTools}from"./chunk-HPQUXAZK.js";import{DEFAULT_MAX_BYTES,DEFAULT_MAX_LINES,formatReadLineRange,formatSize,truncateHead,truncateLine,truncateTail,truncateToVisualLines}from"./chunk-DYTENXHX.js";import{ArminComponent}from"./chunk-FLHKNMLQ.js";import{Container,SelectList,Theme,getAvailableThemes,getLanguageFromPath,getMarkdownTheme,getSelectListTheme,getSettingsListTheme,highlightCode,initTheme,keyHint,keyText,rawKeyHint}from"./chunk-LT2C56HV.js";import{ProjectTrustStore,hasTrustRequiringProjectResources,loadMcpConfig}from"./chunk-6Z2347ML.js";import{readStoredCredential}from"./chunk-MF3VB62R.js";import{getPowerShellConfig,getShellConfig}from"./chunk-URBBMV3M.js";import{CONFIG_DIR_NAME,VERSION,getAgentDir,getDocsPath,getExamplesPath,getPackageDir,getReadmePath}from"./chunk-LHRPMXVI.js";import{__export}from"./chunk-JXWJOIH4.js";var dist_exports={};__export(dist_exports,{AgentSession:()=>AgentSession,AgentSessionRuntime:()=>AgentSessionRuntime,ArminComponent:()=>ArminComponent,AssistantMessageComponent:()=>AssistantMessageComponent,BashExecutionComponent:()=>BashExecutionComponent,BorderedLoader:()=>BorderedLoader,BranchSummaryMessageComponent:()=>BranchSummaryMessageComponent,CONFIG_DIR_NAME:()=>CONFIG_DIR_NAME,CURRENT_SESSION_VERSION:()=>CURRENT_SESSION_VERSION,CompactionSummaryMessageComponent:()=>CompactionSummaryMessageComponent,CredentialSynchronizationError:()=>CredentialSynchronizationError,CustomEditor:()=>CustomEditor,CustomMessageComponent:()=>CustomMessageComponent,DEFAULT_COMPACTION_SETTINGS:()=>DEFAULT_COMPACTION_SETTINGS,DEFAULT_MAX_BYTES:()=>DEFAULT_MAX_BYTES,DEFAULT_MAX_LINES:()=>DEFAULT_MAX_LINES,DefaultPackageManager:()=>DefaultPackageManager,DefaultResourceLoader:()=>DefaultResourceLoader,DynamicBorder:()=>DynamicBorder,ExtensionEditorComponent:()=>ExtensionEditorComponent,ExtensionInputComponent:()=>ExtensionInputComponent,ExtensionRunner:()=>ExtensionRunner,ExtensionSelectorComponent:()=>ExtensionSelectorComponent,FileModelsStore:()=>FileModelsStore,FooterComponent:()=>FooterComponent,InteractiveMode:()=>InteractiveMode,LoginDialogComponent:()=>LoginDialogComponent,MCP_CONNECTION_EVENT:()=>MCP_CONNECTION_EVENT,ModelRegistry:()=>ModelRegistry,ModelRuntime:()=>ModelRuntime,ModelSelectorComponent:()=>ModelSelectorComponent,OAuthSelectorComponent:()=>OAuthSelectorComponent,ProjectTrustStore:()=>ProjectTrustStore,RpcClient:()=>RpcClient,SessionManager:()=>SessionManager,SessionSelectorComponent:()=>SessionSelectorComponent,SettingsManager:()=>SettingsManager,SettingsSelectorComponent:()=>SettingsSelectorComponent,ShowImagesSelectorComponent:()=>ShowImagesSelectorComponent,SkillInvocationMessageComponent:()=>SkillInvocationMessageComponent,Theme:()=>Theme,ThemeSelectorComponent:()=>ThemeSelectorComponent,ThinkingSelectorComponent:()=>ThinkingSelectorComponent,ToolExecutionComponent:()=>ToolExecutionComponent,TreeSelectorComponent:()=>TreeSelectorComponent,UserMessageComponent:()=>UserMessageComponent,UserMessageSelectorComponent:()=>UserMessageSelectorComponent,VERSION:()=>VERSION,VIRTUAL_MODEL_STATE_ENTRY:()=>VIRTUAL_MODEL_STATE_ENTRY,applyHttpProxySettings:()=>applyHttpProxySettings,buildContextEntries:()=>buildContextEntries,buildSessionContext:()=>buildSessionContext,buildSessionProjection:()=>buildSessionProjection,calculateContextTokens:()=>calculateContextTokens,collectEntriesForBranchSummary:()=>collectEntriesForBranchSummary,compact:()=>compact,configureHttpDispatcher:()=>configureHttpDispatcher,convertToLlm:()=>convertToLlm,convertToPng:()=>convertToPng,copyToClipboard:()=>copyToClipboard,createAgentSession:()=>createAgentSession,createAgentSessionFromServices:()=>createAgentSessionFromServices,createAgentSessionRuntime:()=>createAgentSessionRuntime,createAgentSessionServices:()=>createAgentSessionServices,createBashTool:()=>createBashTool,createBashToolDefinition:()=>createBashToolDefinition,createCodemodeExtension:()=>createCodemodeExtension,createCodingTools:()=>createCodingTools,createEditTool:()=>createEditTool,createEditToolDefinition:()=>createEditToolDefinition,createEventBus:()=>createEventBus,createExtensionRuntime:()=>createExtensionRuntime,createFindTool:()=>createFindTool,createFindToolDefinition:()=>createFindToolDefinition,createGrepTool:()=>createGrepTool,createGrepToolDefinition:()=>createGrepToolDefinition,createLocalBashOperations:()=>createLocalBashOperations,createLocalPowerShellOperations:()=>createLocalPowerShellOperations,createLsTool:()=>createLsTool,createLsToolDefinition:()=>createLsToolDefinition,createMcpExtension:()=>createMcpExtension,createPowerShellTool:()=>createPowerShellTool,createPowerShellToolDefinition:()=>createPowerShellToolDefinition,createReadOnlyTools:()=>createReadOnlyTools,createReadTool:()=>createReadTool,createReadToolDefinition:()=>createReadToolDefinition,createSyntheticSourceInfo:()=>createSyntheticSourceInfo,createToolSearchExtension:()=>createToolSearchExtension,createWriteTool:()=>createWriteTool,createWriteToolDefinition:()=>createWriteToolDefinition,defaultModelPerProvider:()=>defaultModelPerProvider,defineTool:()=>defineTool,detectSupportedImageMimeTypeFromFile:()=>detectSupportedImageMimeTypeFromFile,discoverAndLoadExtensions:()=>discoverAndLoadExtensions,estimateTokens:()=>estimateTokens,findCutPoint:()=>findCutPoint,findTurnStartIndex:()=>findTurnStartIndex,formatDimensionNote:()=>formatDimensionNote,formatReadLineRange:()=>formatReadLineRange,formatSize:()=>formatSize,formatSkillsForPrompt:()=>formatSkillsForPrompt,generateBranchSummary:()=>generateBranchSummary,generateDiffString:()=>generateDiffString,generateSummary:()=>generateSummary,generateSummaryWithUsage:()=>generateSummaryWithUsage,generateUnifiedPatch:()=>generateUnifiedPatch,getAgentDir:()=>getAgentDir,getDocsPath:()=>getDocsPath,getExamplesPath:()=>getExamplesPath,getLanguageFromPath:()=>getLanguageFromPath,getLastAssistantUsage:()=>getLastAssistantUsage,getLatestCompactionEntry:()=>getLatestCompactionEntry,getMarkdownTheme:()=>getMarkdownTheme,getPackageDir:()=>getPackageDir,getPowerShellConfig:()=>getPowerShellConfig,getReadmePath:()=>getReadmePath,getSelectListTheme:()=>getSelectListTheme,getSettingsListTheme:()=>getSettingsListTheme,getShellConfig:()=>getShellConfig,hasTrustRequiringProjectResources:()=>hasTrustRequiringProjectResources,highlightCode:()=>highlightCode,initTheme:()=>initTheme,isBashToolResult:()=>isBashToolResult,isEditToolResult:()=>isEditToolResult,isFindToolResult:()=>isFindToolResult,isGrepToolResult:()=>isGrepToolResult,isLsToolResult:()=>isLsToolResult,isPowerShellToolResult:()=>isPowerShellToolResult,isReadToolResult:()=>isReadToolResult,isToolCallEventType:()=>isToolCallEventType,isWriteToolResult:()=>isWriteToolResult,keyHint:()=>keyHint,keyText:()=>keyText,loadMcpConfig:()=>loadMcpConfig,loadProjectContextFiles:()=>loadProjectContextFiles,loadSkills:()=>loadSkills,loadSkillsFromDir:()=>loadSkillsFromDir,main:()=>main,migrateSessionEntries:()=>migrateSessionEntries,parseArgs:()=>parseArgs,parseFrontmatter:()=>parseFrontmatter,parseSessionEntries:()=>parseSessionEntries,parseSkillBlock:()=>parseSkillBlock,prepareBranchEntries:()=>prepareBranchEntries,rawKeyHint:()=>rawKeyHint,readStoredCredential:()=>readStoredCredential,renderDiff:()=>renderDiff,resizeImage:()=>resizeImage,resolveCliModel:()=>resolveCliModel,resolveModelScopeWithDiagnostics:()=>resolveModelScopeWithDiagnostics,runPrintMode:()=>runPrintMode,runRpcMode:()=>runRpcMode,serializeConversation:()=>serializeConversation,sessionEntryToContextMessages:()=>sessionEntryToContextMessages,setupCli:()=>setupCli,shouldCompact:()=>shouldCompact,stdioRpcTransport:()=>stdioRpcTransport,stripFrontmatter:()=>stripFrontmatter,truncateHead:()=>truncateHead,truncateLine:()=>truncateLine,truncateTail:()=>truncateTail,truncateToVisualLines:()=>truncateToVisualLines,withFileMutationQueue:()=>withFileMutationQueue,wrapRegisteredTool:()=>wrapRegisteredTool,wrapRegisteredTools:()=>wrapRegisteredTools});var SHOW_IMAGES_SELECT_LIST_LAYOUT={minPrimaryColumnWidth:12,maxPrimaryColumnWidth:32},ShowImagesSelectorComponent=class extends Container{selectList;constructor(currentValue,onSelect,onCancel){super();let items=[{value:"yes",label:"Yes",description:"Show images inline in terminal"},{value:"no",label:"No",description:"Show text placeholder instead"}];this.addChild(new DynamicBorder),this.selectList=new SelectList(items,5,getSelectListTheme(),SHOW_IMAGES_SELECT_LIST_LAYOUT),this.selectList.setSelectedIndex(currentValue?0:1),this.selectList.onSelect=item=>{onSelect(item.value==="yes")},this.selectList.onCancel=()=>{onCancel()},this.addChild(this.selectList),this.addChild(new DynamicBorder)}getSelectList(){return this.selectList}};var THEME_SELECT_LIST_LAYOUT={minPrimaryColumnWidth:12,maxPrimaryColumnWidth:32},ThemeSelectorComponent=class extends Container{selectList;onPreview;constructor(currentTheme,onSelect,onCancel,onPreview){super(),this.onPreview=onPreview;let themes=getAvailableThemes(),themeItems=themes.map(name=>({value:name,label:name,description:name===currentTheme?"(current)":void 0}));this.addChild(new DynamicBorder),this.selectList=new SelectList(themeItems,10,getSelectListTheme(),THEME_SELECT_LIST_LAYOUT);let currentIndex=themes.indexOf(currentTheme);currentIndex!==-1&&this.selectList.setSelectedIndex(currentIndex),this.selectList.onSelect=item=>{onSelect(item.value)},this.selectList.onCancel=()=>{onCancel()},this.selectList.onSelectionChange=item=>{this.onPreview(item.value)},this.addChild(this.selectList),this.addChild(new DynamicBorder)}getSelectList(){return this.selectList}};export{ShowImagesSelectorComponent,ThemeSelectorComponent,dist_exports};