@vibeapi/cli 0.0.149 → 0.0.151

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.
Files changed (37) hide show
  1. package/README.md +22 -17
  2. package/components.json +1 -1
  3. package/dist/commands/config.js +1 -1
  4. package/dist/commands/setup.js +1 -1
  5. package/dist/components.json +1 -1
  6. package/dist/lib/app-update.js +1 -1
  7. package/dist/lib/claude-code-manager.d.ts +4 -0
  8. package/dist/lib/claude-code-manager.js +1 -1
  9. package/dist/lib/command.d.ts +0 -5
  10. package/dist/lib/command.js +1 -1
  11. package/dist/lib/config.d.ts +2 -0
  12. package/dist/lib/config.js +1 -1
  13. package/dist/lib/env-cleanup.d.ts +36 -26
  14. package/dist/lib/env-cleanup.js +1 -1
  15. package/dist/lib/gateway-addresses.d.ts +4 -0
  16. package/dist/lib/gateway-addresses.js +1 -1
  17. package/dist/lib/model-registry.d.ts +2 -0
  18. package/dist/lib/model-registry.js +1 -1
  19. package/dist/lib/post-apply.d.ts +5 -0
  20. package/dist/lib/post-apply.js +1 -1
  21. package/dist/lib/tool-manager.d.ts +3 -0
  22. package/dist/lib/tool-manager.js +1 -1
  23. package/dist/lib/tools/claude-code.js +1 -1
  24. package/dist/lib/tools/claude-desktop.d.ts +1 -1
  25. package/dist/lib/tools/claude-desktop.js +1 -1
  26. package/dist/lib/tools/codex.js +1 -1
  27. package/dist/lib/tools/desktop-app-installer.d.ts +5 -1
  28. package/dist/lib/tools/desktop-app-installer.js +1 -1
  29. package/dist/lib/tools/types.d.ts +15 -0
  30. package/dist/lib/wizard.js +1 -1
  31. package/dist/lib/write-plan.d.ts +2 -0
  32. package/dist/lib/write-plan.js +1 -1
  33. package/dist/lib/written-values.d.ts +21 -0
  34. package/dist/lib/written-values.js +1 -0
  35. package/dist/locales/en_US.json +24 -1
  36. package/dist/locales/zh_CN.json +24 -1
  37. package/package.json +1 -1
@@ -1 +1 @@
1
- import{existsSync as e,readFileSync as n,writeFileSync as r}from"fs";import{join as o}from"path";import{logger as t}from"../utils/logger.js";import{toolHome as s}from"./tools/types.js";import{broadcastEnvChange as c,deleteWindowsEnv as i,readWindowsEnv as l}from"./windows-env.js";export const ANTHROPIC_ENV_VARS=["ANTHROPIC_API_KEY","ANTHROPIC_BASE_URL","ANTHROPIC_DEFAULT_HAIKU_MODEL","ANTHROPIC_DEFAULT_SONNET_MODEL","ANTHROPIC_DEFAULT_OPUS_MODEL","ANTHROPIC_DEFAULT_FABLE_MODEL","ANTHROPIC_MODEL","ANTHROPIC_REASONING_MODEL"];export function getShellRcFilePath(){if("win32"===process.platform)return null;const e=s();switch((process.env.SHELL||"").split("/").pop()||""){case"bash":return o(e,".bashrc");case"zsh":return o(e,".zshrc");case"fish":return o(e,".config","fish","config.fish");default:return o(e,".profile")}}export function cleanupShellRcEnvVars(){if("win32"===process.platform)return!1;try{const o=getShellRcFilePath();if(!o||!e(o))return!1;let s=n(o,"utf-8");const c=s,i=[...ANTHROPIC_ENV_VARS.map(e=>new RegExp(String.raw`^\s*export\s+${e}=.*$`,"gm")),/^\s*#\s*Claude Code environment variables\s*$/gm];for(const e of i)s=s.replace(e,"");if(s!==c)return r(o,s,"utf-8"),t.info(`Cleaned up ANTHROPIC_* environment variables from ${o}`),!0}catch(e){t.warn("Failed to cleanup shell environment variables:",e),t.logError("envCleanup.cleanupShellRcEnvVars",e)}return!1}export function cleanupWindowsEnvVars(f){const a=[];if("win32"!==process.platform||0===f.length)return{machineLeft:a,changed:!1};let p=!1;const u=[];for(const e of f)for(const n of["user","machine"])if(void 0!==l(n,e))try{i(n,e),u.push(`${n}:${e}`)}catch(r){"machine"===n&&a.push(e),t.logError("envCleanup.cleanupWindowsEnvVars",r)}u.length>0&&(p=!0,c(),t.info(`Windows env cleanup: ${u.join(" ")}`));for(const c of function(){const e=s(),n=[];for(const r of[o(e,"Documents"),o(e,"OneDrive","Documents"),o(e,"OneDrive","文档")])for(const e of["PowerShell","WindowsPowerShell"])n.push(o(r,e,"Microsoft.PowerShell_profile.ps1"),o(r,e,"profile.ps1"));return n}())try{if(!e(c))continue;const o=n(c,"utf-8");let s=o;for(const e of f)s=s.replace(new RegExp(String.raw`^[ \t]*\$env:${e}[ \t]*=.*(\r?\n)?`,"gim"),"");s!==o&&(r(c,s,"utf-8"),p=!0,t.info(`Removed ANTHROPIC_* assignments from ${c}`))}catch(e){t.logError("envCleanup.powerShellProfile",e)}return{machineLeft:a,changed:p}}export function cleanupAnthropicEnvVars(){const e=ANTHROPIC_ENV_VARS.filter(e=>!!process.env[e]);if(0===e.length)return[];const n=cleanupShellRcEnvVars(),r=cleanupWindowsEnvVars(e);f=r.machineLeft,a=n||r.changed;for(const n of e)delete process.env[n];return[...e]}let f=[],a=!1;export function envCleanupChangedProfile(){return a}export function machineEnvVarsLeft(){return f}
1
+ import{existsSync as e,mkdirSync as o,readFileSync as r,writeFileSync as n}from"fs";import{join as t}from"path";import{logger as s}from"../utils/logger.js";import{toolHome as c}from"./tools/types.js";import{backupBeforeWrite as i}from"./tools/backup.js";import{configManager as u,savedApiKeys as f}from"./config.js";import{isOurGatewayUrl as l}from"./gateway-addresses.js";import{broadcastEnvChange as a,deleteWindowsEnv as p,readWindowsEnv as m}from"./windows-env.js";export const ANTHROPIC_ENV_VARS=["ANTHROPIC_API_KEY","ANTHROPIC_AUTH_TOKEN","ANTHROPIC_BASE_URL","ANTHROPIC_DEFAULT_HAIKU_MODEL","ANTHROPIC_DEFAULT_SONNET_MODEL","ANTHROPIC_DEFAULT_OPUS_MODEL","ANTHROPIC_DEFAULT_FABLE_MODEL","ANTHROPIC_MODEL","ANTHROPIC_REASONING_MODEL"];export function getShellRcFilePath(){if("win32"===process.platform)return null;const e=c();switch((process.env.SHELL||"").split("/").pop()||""){case"bash":return t(e,".bashrc");case"zsh":return t(e,".zshrc");case"fish":return t(e,".config","fish","config.fish");default:return t(e,".profile")}}function h(e){const o=e.trim().replace(/\s+#.*$/,""),r=o.match(/^(['"])(.*)\1$/);return r?r[2]:o}const v=e=>new RegExp(String.raw`^\s*export\s+${e}=(.*)$`,"gm"),E=e=>new RegExp(String.raw`^[ \t]*\$env:${e}[ \t]*=(.*)$`,"gim");function g(e){if(l(e.ANTHROPIC_BASE_URL))return!0;const o=f();return[e.ANTHROPIC_API_KEY,e.ANTHROPIC_AUTH_TOKEN].some(e=>Boolean(e)&&o.includes(e.trim()))}export function anthropicEnvSources(){const o=[],n=(n,t)=>{if(n&&e(n))try{const e=function(e,o){const r={};for(const n of ANTHROPIC_ENV_VARS)for(const t of e.matchAll(o(n)))r[n]=h(t[1]);return r}(r(n,"utf-8"),t);Object.keys(e).length>0&&o.push({kind:"file",location:n,vars:e,ours:g(e)})}catch(e){s.logError("envCleanup.read",e)}};if("win32"!==process.platform)return n(getShellRcFilePath(),v),o;for(const e of["user","machine"]){const r={};for(const o of ANTHROPIC_ENV_VARS){const n=m(e,o);void 0!==n&&(r[o]=n)}Object.keys(r).length>0&&o.push({kind:"user"===e?"windows-user":"windows-machine",location:"user"===e?"HKCU\\Environment":"HKLM\\SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment",vars:r,ours:g(r)})}for(const e of function(){const e=c(),o=[];for(const r of[t(e,"Documents"),t(e,"OneDrive","Documents"),t(e,"OneDrive","文档")])for(const e of["PowerShell","WindowsPowerShell"])o.push(t(r,e,"Microsoft.PowerShell_profile.ps1"),t(r,e,"profile.ps1"));return o}())n(e,E);return o}function O(e,o,t){const c=r(e,"utf-8");let u=c;for(const e of o)u=u.replace(new RegExp(t(e).source+String.raw`(\r?\n)?`,t(e).flags),"");return t===v&&(u=u.replace(/^\s*#\s*Claude Code environment variables\s*$\n?/gm,"")),u!==c&&(i(e),n(e,u,"utf-8"),s.debug(`Removed ${o.join(", ")} from ${e}`),!0)}function _(e,r){try{const s=t(u.getConfigDir(),"backups");o(s,{recursive:!0});const c=t(s,`windows-env-${e}-${(new Date).toISOString().replace(/[:.]/g,"-")}.json`);return n(c,JSON.stringify(r,null,2)+"\n",{mode:384}),c}catch(e){return s.logError("envCleanup.backupWindowsValues",e),null}}let A={removed:[],foreign:[],machineLeft:[]};export function cleanupAnthropicEnvVars(){const e=anthropicEnvSources(),o=removeEnvSources(e.filter(e=>e.ours));return o.foreign=e.filter(e=>!e.ours),A=o,o}export function removeEnvSources(e){const o={removed:[],foreign:[],machineLeft:[]};let r=!1;for(const n of e){const e=Object.keys(n.vars);try{if("file"===n.kind){O(n.location,e,n.location.endsWith(".ps1")?E:v)&&o.removed.push(n);continue}const t="windows-user"===n.kind?"user":"machine";_(t,n.vars);const c=[];for(const r of e)try{p(t,r),c.push(r)}catch(e){"machine"===t&&o.machineLeft.push(r),s.logError("envCleanup.deleteWindowsEnv",e)}c.length>0&&(r=!0,o.removed.push({...n,vars:Object.fromEntries(c.map(e=>[e,n.vars[e]]))}))}catch(e){s.logError("envCleanup.removeEnvSources",e)}}r&&a();for(const e of o.removed)for(const[o,r]of Object.entries(e.vars))process.env[o]===r&&delete process.env[o];return o}export function lastEnvCleanup(){return A}export function envCleanupPlan(){return anthropicEnvSources().filter(e=>e.ours)}
@@ -33,6 +33,10 @@ export declare function rememberPublishedAddresses(statusData: unknown, source:
33
33
  * gateway's order. A built-in address takes the gateway's label when it has one.
34
34
  */
35
35
  export declare function gatewayAddresses(): GatewayAddress[];
36
+ /** `url` is one of this gateway's addresses (built-in, published, or the configured one). */
37
+ export declare function isOurGatewayUrl(url: unknown): boolean;
38
+ /** Remember an address vibecli is about to write into a tool, so `isOurGatewayUrl` knows it later. */
39
+ export declare function noteWrittenGatewayUrl(url: string): void;
36
40
  export interface ProbeOptions {
37
41
  /** With a key the probe lists the models (`GET /v1/models`): the whole relay path works, not just the front page. */
38
42
  apiKey?: string;
@@ -1 +1 @@
1
- import{existsSync as r,mkdirSync as e,readFileSync as t,writeFileSync as o}from"fs";import{join as s}from"path";import{configManager as n}from"./config.js";import{getBuiltinGatewayAddresses as a}from"./model-registry.js";import{logger as i}from"../utils/logger.js";const l=new Set(["SELF_SIGNED_CERT_IN_CHAIN","DEPTH_ZERO_SELF_SIGNED_CERT","UNABLE_TO_VERIFY_LEAF_SIGNATURE","UNABLE_TO_GET_ISSUER_CERT_LOCALLY","CERT_HAS_EXPIRED","CERT_NOT_YET_VALID","ERR_TLS_CERT_ALTNAME_INVALID"]);function u(){return s(n.getConfigDir(),"gateway-addresses.json")}export function normalizeBaseUrl(r){let e,t=r.trim();if(!t)return null;/^[a-z][a-z0-9+.-]*:\/\//i.test(t)||(t=`https://${t}`);try{e=new URL(t)}catch{return null}if("https:"!==e.protocol&&"http:"!==e.protocol)return null;const o=e.pathname.replace(/\/+$/,"").replace(/\/v1$/i,"");return`${e.protocol}//${e.host}${o}`}export function parsePublishedAddresses(r){if(!Array.isArray(r))return[];const e=new Set,t=[];for(const o of r){if(!o||"object"!=typeof o)continue;const{url:r,route:s,description:n}=o,a="string"==typeof r?normalizeBaseUrl(r):null;if(!a?.startsWith("https://")||e.has(a))continue;e.add(a);const i="string"==typeof s?s.trim():"",l="string"==typeof n?n.trim():"";t.push({url:a,label:i&&l?`${i}(${l})`:i||l})}return t}export function rememberPublishedAddresses(r,t){if(!r||"object"!=typeof r)return;if(!a().some(r=>normalizeBaseUrl(r.url)===t))return;const s=r;if(!1===s.api_info_enabled)return;const l=parsePublishedAddresses(s.api_info);if(0!==l.length)try{e(n.getConfigDir(),{recursive:!0}),o(u(),JSON.stringify({addresses:l},null,2)+"\n")}catch(r){i.logError("rememberPublishedAddresses",r)}}export function gatewayAddresses(){const e=function(){const e=u();if(!r(e))return[];try{const r=JSON.parse(t(e,"utf-8"));return(Array.isArray(r.addresses)?r.addresses:[]).flatMap(r=>{const e="string"==typeof r?.url?normalizeBaseUrl(r.url):null;return e?[{url:e,label:"string"==typeof r.label?r.label:""}]:[]})}catch{return[]}}(),o=[];for(const r of a()){const t=normalizeBaseUrl(r.url);if(!t||o.some(r=>r.url===t))continue;const s=e.find(r=>r.url===t)?.label||r.label;o.push({url:t,label:s})}for(const r of e)o.some(e=>e.url===r.url)||o.push(r);return o}function c(r){const e=r?.cause,t="string"==typeof e?.code?e.code:"",o="string"==typeof e?.message?e.message:r instanceof Error?r.message:String(r);return r instanceof Error&&"AbortError"===r.name?{error:"timeout",detail:o}:l.has(t)||/certificate/i.test(o)?{error:"certificate",detail:t||o}:{error:"network",detail:t||o}}export async function probeGatewayAddress(r,e={}){e.apiKey&&!function(r){return r===n.getBaseUrl()||a().some(e=>normalizeBaseUrl(e.url)===r)}(r)&&(e={...e,apiKey:void 0});const t=Math.max(1,e.samples??1),o=[];let s;for(let n=0;n<t;n+=1){const t=await f(r,e);if(!t.ok)return t;o.push(t.ms),s=t.models}return o.sort((r,e)=>r-e),{url:r,ok:!0,ms:o[Math.floor(o.length/2)],...void 0===s?{}:{models:s}}}async function f(r,e){const{apiKey:t,timeoutMs:o=8e3,fetchFn:s=fetch}=e,n=new AbortController,a=setTimeout(()=>n.abort(),o),i=Date.now();try{const e=await s(t?`${r}/v1/models`:`${r}/api/status`,{method:"GET",headers:t?{Authorization:`Bearer ${t}`}:void 0,signal:n.signal});let o;try{o=(await e.json())?.data}catch{o=void 0}const a=Date.now()-i;return!t||401!==e.status&&403!==e.status?t?e.ok&&Array.isArray(o)?{url:r,ok:!0,ms:a,models:o.length}:{url:r,ok:!1,ms:a,error:"not_gateway",detail:`HTTP ${e.status}`}:e.ok&&o&&"object"==typeof o?(rememberPublishedAddresses(o,r),{url:r,ok:!0,ms:a}):{url:r,ok:!1,ms:a,error:"not_gateway",detail:`HTTP ${e.status}`}:{url:r,ok:!1,ms:a,error:"key_rejected",detail:`HTTP ${e.status}`}}catch(e){return{url:r,ok:!1,ms:Date.now()-i,...c(e)}}finally{clearTimeout(a)}}
1
+ import{existsSync as r,mkdirSync as e,readFileSync as t,writeFileSync as o}from"fs";import{join as s}from"path";import{configManager as n}from"./config.js";import{noteGatewayUrl as a,wroteGatewayUrl as i}from"./written-values.js";import{getBuiltinGatewayAddresses as l}from"./model-registry.js";import{logger as u}from"../utils/logger.js";const c=new Set(["SELF_SIGNED_CERT_IN_CHAIN","DEPTH_ZERO_SELF_SIGNED_CERT","UNABLE_TO_VERIFY_LEAF_SIGNATURE","UNABLE_TO_GET_ISSUER_CERT_LOCALLY","CERT_HAS_EXPIRED","CERT_NOT_YET_VALID","ERR_TLS_CERT_ALTNAME_INVALID"]);function f(){return s(n.getConfigDir(),"gateway-addresses.json")}export function normalizeBaseUrl(r){let e,t=r.trim();if(!t)return null;/^[a-z][a-z0-9+.-]*:\/\//i.test(t)||(t=`https://${t}`);try{e=new URL(t)}catch{return null}if("https:"!==e.protocol&&"http:"!==e.protocol)return null;const o=e.pathname.replace(/\/+$/,"").replace(/\/v1$/i,"");return`${e.protocol}//${e.host}${o}`}export function parsePublishedAddresses(r){if(!Array.isArray(r))return[];const e=new Set,t=[];for(const o of r){if(!o||"object"!=typeof o)continue;const{url:r,route:s,description:n}=o,a="string"==typeof r?normalizeBaseUrl(r):null;if(!a?.startsWith("https://")||e.has(a))continue;e.add(a);const i="string"==typeof s?s.trim():"",l="string"==typeof n?n.trim():"";t.push({url:a,label:i&&l?`${i}(${l})`:i||l})}return t}export function rememberPublishedAddresses(r,t){if(!r||"object"!=typeof r)return;if(!l().some(r=>normalizeBaseUrl(r.url)===t))return;const s=r;if(!1===s.api_info_enabled)return;const a=parsePublishedAddresses(s.api_info);if(0!==a.length)try{e(n.getConfigDir(),{recursive:!0}),o(f(),JSON.stringify({addresses:a},null,2)+"\n")}catch(r){u.logError("rememberPublishedAddresses",r)}}export function gatewayAddresses(){const e=function(){const e=f();if(!r(e))return[];try{const r=JSON.parse(t(e,"utf-8"));return(Array.isArray(r.addresses)?r.addresses:[]).flatMap(r=>{const e="string"==typeof r?.url?normalizeBaseUrl(r.url):null;return e?[{url:e,label:"string"==typeof r.label?r.label:""}]:[]})}catch{return[]}}(),o=[];for(const r of l()){const t=normalizeBaseUrl(r.url);if(!t||o.some(r=>r.url===t))continue;const s=e.find(r=>r.url===t)?.label||r.label;o.push({url:t,label:s})}for(const r of e)o.some(e=>e.url===r.url)||o.push(r);return o}export function isOurGatewayUrl(r){if("string"!=typeof r)return!1;const e=normalizeBaseUrl(r);return!!e&&(gatewayAddresses().some(r=>r.url===e)||e===normalizeBaseUrl(n.getBaseUrl())||i(e))}export function noteWrittenGatewayUrl(r){const e=normalizeBaseUrl(r);e&&a(e)}function m(r){const e=r?.cause,t="string"==typeof e?.code?e.code:"",o="string"==typeof e?.message?e.message:r instanceof Error?r.message:String(r);return r instanceof Error&&"AbortError"===r.name?{error:"timeout",detail:o}:c.has(t)||/certificate/i.test(o)?{error:"certificate",detail:t||o}:{error:"network",detail:t||o}}export async function probeGatewayAddress(r,e={}){e.apiKey&&!function(r){return r===n.getBaseUrl()||l().some(e=>normalizeBaseUrl(e.url)===r)}(r)&&(e={...e,apiKey:void 0});const t=Math.max(1,e.samples??1),o=[];let s;for(let n=0;n<t;n+=1){const t=await d(r,e);if(!t.ok)return t;o.push(t.ms),s=t.models}return o.sort((r,e)=>r-e),{url:r,ok:!0,ms:o[Math.floor(o.length/2)],...void 0===s?{}:{models:s}}}async function d(r,e){const{apiKey:t,timeoutMs:o=8e3,fetchFn:s=fetch}=e,n=new AbortController,a=setTimeout(()=>n.abort(),o),i=Date.now();try{const e=await s(t?`${r}/v1/models`:`${r}/api/status`,{method:"GET",headers:t?{Authorization:`Bearer ${t}`}:void 0,signal:n.signal});let o;try{o=(await e.json())?.data}catch{o=void 0}const a=Date.now()-i;return!t||401!==e.status&&403!==e.status?t?e.ok&&Array.isArray(o)?{url:r,ok:!0,ms:a,models:o.length}:{url:r,ok:!1,ms:a,error:"not_gateway",detail:`HTTP ${e.status}`}:e.ok&&o&&"object"==typeof o?(rememberPublishedAddresses(o,r),{url:r,ok:!0,ms:a}):{url:r,ok:!1,ms:a,error:"not_gateway",detail:`HTTP ${e.status}`}:{url:r,ok:!1,ms:a,error:"key_rejected",detail:`HTTP ${e.status}`}}catch(e){return{url:r,ok:!1,ms:Date.now()-i,...m(e)}}finally{clearTimeout(a)}}
@@ -102,6 +102,8 @@ export declare function overlayClientSection(base: ModelRegistryData, v: ClientS
102
102
  export declare function getDefaultModels(): Models;
103
103
  /** Earlier default for this slot, saved into a profile by the wizard's prefilled inputs. */
104
104
  export declare function isRetiredDefaultModel(slot: string, model: string): boolean;
105
+ /** Every earlier default of any slot (older vibecli versions wrote these into tool settings). */
106
+ export declare function getRetiredDefaultModelIds(): string[];
105
107
  /** The model non-Claude tools use unless the user configured something else. */
106
108
  export declare function getDefaultToolModel(): string;
107
109
  /**
@@ -1 +1 @@
1
- import{dirname as e,join as o}from"path";import{fileURLToPath as t}from"url";import{existsSync as l,readFileSync as n}from"fs";import{currentClientConfig as r,usableClientSection as s}from"./client-config.js";import{brand as a}from"./brand.js";const i=e(t(import.meta.url)),d=(e=[],o=[])=>[...new Set([...e,...o])];export function overlayClientSection(e,o){if(!o)return e;const t={...e.retiredDefaultModels??{}};for(const[e,l]of Object.entries(o.retiredDefaultModels??{}))t[e]=d(t[e],l);return{...e,defaultModels:{...e.defaultModels,...o.defaultModels??{}},retiredDefaultModels:t,toolDefaults:{...e.toolDefaults??{},...o.toolDefaults??{}},claudeCode:o.tierChains?{...e.claudeCode??{},tierChains:{...e.claudeCode?.tierChains??{},...o.tierChains}}:e.claudeCode,claudeDesktop:o.oneMillionFallback?{...e.claudeDesktop??{},oneMillionFallback:[...o.oneMillionFallback]}:e.claudeDesktop,gatewayModels:o.retiredModels?{...e.gatewayModels??{},retired:d(e.gatewayModels?.retired,o.retiredModels)}:e.gatewayModels,toolMinVersions:{...e.toolMinVersions??{},...o.toolMinVersions??{}},agy:o.agyModels?{...e.agy??{},gatewayModels:[...o.agyModels]}:e.agy}}let u=null;function c(){return u||(u=overlayClientSection(function(){const e=[o(i,"..","..","models.json"),o(i,"..","models.json"),o(i,"models.json")];for(const o of e)if(l(o))return JSON.parse(n(o,"utf-8"));throw new Error(`models.json not found, searched: ${e.join(", ")}`)}(),s(r()?.config))),u}export function getDefaultModels(){return{...c().defaultModels}}export function isRetiredDefaultModel(e,o){return c().retiredDefaultModels?.[e]?.includes(o)??!1}export function getDefaultToolModel(){return c().defaultToolModel?.trim()||"gpt-5.5"}export function getToolDefaultModel(e){const o=c().toolDefaults;return o&&Object.prototype.hasOwnProperty.call(o,e)?(o[e]??"").trim():getDefaultToolModel()}export function getPresets(){return[...c().presets]}export function resolvePreset(e){return e.models?{...e.models}:e.model?{haiku:e.model,sonnet:e.model,opus:e.model,reasoning:e.model}:getDefaultModels()}export function getClaudeCodeTierChains(){const e=c().claudeCode?.tierChains??{};return Object.fromEntries(Object.entries(e).map(([e,o])=>[e,[...o]]))}export function getClaudeDesktopRules(){const e=c().claudeDesktop??{};return{oneMillionFallback:[...e.oneMillionFallback??[]],oneMillionExclusions:(e.oneMillionExclusions??[]).map(e=>({...e,models:[...e.models]}))}}export function getGatewayModelRules(){const e=c().gatewayModels??{};return{autoCompactRatio:e.autoCompactRatio??.8,models:(e.models??[]).map(e=>({...e})),retired:[...e.retired??[]]}}export function getBuiltinGatewayAddresses(){return a().gatewayAddresses.map(e=>({...e}))}export function getCodexRules(){return{standardContextWindow:c().codex?.standardContextWindow??272e3}}export function getAgyRules(){return{gatewayModels:[...c().agy?.gatewayModels??[]]}}export function compareVersions(e,o){const t=e.split(".").map(e=>parseInt(e,10)||0),l=o.split(".").map(e=>parseInt(e,10)||0);for(let e=0;e<Math.max(t.length,l.length);e++){const o=(t[e]??0)-(l[e]??0);if(0!==o)return o}return 0}export function getToolMinVersion(e){return c().toolMinVersions?.[e]?.trim()||null}export function reloadRegistry(){u=null}
1
+ import{dirname as e,join as t}from"path";import{fileURLToPath as o}from"url";import{existsSync as l,readFileSync as n}from"fs";import{currentClientConfig as r,usableClientSection as s}from"./client-config.js";import{brand as a}from"./brand.js";const i=e(o(import.meta.url)),d=(e=[],t=[])=>[...new Set([...e,...t])];export function overlayClientSection(e,t){if(!t)return e;const o={...e.retiredDefaultModels??{}};for(const[e,l]of Object.entries(t.retiredDefaultModels??{}))o[e]=d(o[e],l);return{...e,defaultModels:{...e.defaultModels,...t.defaultModels??{}},retiredDefaultModels:o,toolDefaults:{...e.toolDefaults??{},...t.toolDefaults??{}},claudeCode:t.tierChains?{...e.claudeCode??{},tierChains:{...e.claudeCode?.tierChains??{},...t.tierChains}}:e.claudeCode,claudeDesktop:t.oneMillionFallback?{...e.claudeDesktop??{},oneMillionFallback:[...t.oneMillionFallback]}:e.claudeDesktop,gatewayModels:t.retiredModels?{...e.gatewayModels??{},retired:d(e.gatewayModels?.retired,t.retiredModels)}:e.gatewayModels,toolMinVersions:{...e.toolMinVersions??{},...t.toolMinVersions??{}},agy:t.agyModels?{...e.agy??{},gatewayModels:[...t.agyModels]}:e.agy}}let u=null;function c(){return u||(u=overlayClientSection(function(){const e=[t(i,"..","..","models.json"),t(i,"..","models.json"),t(i,"models.json")];for(const t of e)if(l(t))return JSON.parse(n(t,"utf-8"));throw new Error(`models.json not found, searched: ${e.join(", ")}`)}(),s(r()?.config))),u}export function getDefaultModels(){return{...c().defaultModels}}export function isRetiredDefaultModel(e,t){return c().retiredDefaultModels?.[e]?.includes(t)??!1}export function getRetiredDefaultModelIds(){return[...new Set(Object.values(c().retiredDefaultModels??{}).flat())]}export function getDefaultToolModel(){return c().defaultToolModel?.trim()||"gpt-5.5"}export function getToolDefaultModel(e){const t=c().toolDefaults;return t&&Object.prototype.hasOwnProperty.call(t,e)?(t[e]??"").trim():getDefaultToolModel()}export function getPresets(){return[...c().presets]}export function resolvePreset(e){return e.models?{...e.models}:e.model?{haiku:e.model,sonnet:e.model,opus:e.model,reasoning:e.model}:getDefaultModels()}export function getClaudeCodeTierChains(){const e=c().claudeCode?.tierChains??{};return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,[...t]]))}export function getClaudeDesktopRules(){const e=c().claudeDesktop??{};return{oneMillionFallback:[...e.oneMillionFallback??[]],oneMillionExclusions:(e.oneMillionExclusions??[]).map(e=>({...e,models:[...e.models]}))}}export function getGatewayModelRules(){const e=c().gatewayModels??{};return{autoCompactRatio:e.autoCompactRatio??.8,models:(e.models??[]).map(e=>({...e})),retired:[...e.retired??[]]}}export function getBuiltinGatewayAddresses(){return a().gatewayAddresses.map(e=>({...e}))}export function getCodexRules(){return{standardContextWindow:c().codex?.standardContextWindow??272e3}}export function getAgyRules(){return{gatewayModels:[...c().agy?.gatewayModels??[]]}}export function compareVersions(e,t){const o=e.split(".").map(e=>parseInt(e,10)||0),l=t.split(".").map(e=>parseInt(e,10)||0);for(let e=0;e<Math.max(o.length,l.length);e++){const t=(o[e]??0)-(l[e]??0);if(0!==t)return t}return 0}export function getToolMinVersion(e){return c().toolMinVersions?.[e]?.trim()||null}export function reloadRegistry(){u=null}
@@ -3,6 +3,11 @@
3
3
  * UAC prompt each, asked in interactive terminals; `--yes` runs them without asking.
4
4
  */
5
5
  export declare function runPendingElevations(tools: string[]): Promise<void>;
6
+ /**
7
+ * The adapters' `followUp()` offers (Codex sessions, another service's ANTHROPIC_* variables): asked in a
8
+ * terminal with default yes, done under `--yes`, otherwise only the hint is printed. Also after `config <tool>`.
9
+ */
10
+ export declare function runFollowUps(tools: string[]): Promise<void>;
6
11
  /**
7
12
  * What setup and the wizard ask right after writing configs: UAC changes and
8
13
  * adapter follow-ups (non-interactive: only their hint), then upgrade tools too
@@ -1 +1 @@
1
- import o from"chalk";import t from"inquirer";import{i18n as n}from"./i18n.js";import{canPrompt as e,hasExplicitYes as r,shouldAutoConfirm as i}from"./runtime-options.js";import{toolManager as s}from"./tool-manager.js";import{getAdapter as a}from"./tools/registry.js";import{upgradeTool as l}from"./tool-upgrade.js";import{appsForTools as p,upgradeApp as f}from"./app-update.js";import{logger as c}from"../utils/logger.js";async function u(o){const{ok:n}=await t.prompt([{type:"confirm",name:"ok",message:o,default:!0}]);return n}export async function runPendingElevations(t){const r=e();for(const e of t){const t=a(e)?.pendingElevation?.();if(!t)continue;if(!(i()||r&&await u(t.prompt)))continue;const s=a(e)?.displayName??e;console.log(o.gray(" "+n.t("setup.elevation_running"))),console.log(t.run()?o.green(" √ "+n.t("setup.elevation_done",{tool:s})):o.yellow(" ! "+n.t("setup.elevation_failed",{tool:s})))}}export async function postApplyPrompts(t,i={}){const m=new Set;for(const o of i.apps?p(t):[])try{const t=await f(o,{install:i.apps.install,quiet:!0,askBeforeUpgrade:!0});t.upgraded&&t.running&&m.add(o)}catch(t){c.logError(`postApplyPrompts.upgradeApp(${o})`,t)}for(const n of t){const t=await(a(n)?.prepareRuntime?.())??[];for(const n of t)console.log("action"===n.kind?o.yellow(" ! "+n.text):o.green(" √ "+n.text))}await runPendingElevations(t);const g=e();for(const n of t){let t;try{t=await(a(n)?.followUp?.())}catch(o){c.logError(`postApplyPrompts.followUp(${n})`,o);continue}if(t)if("run"in t&&(r()||g))if(r()||await u(t.prompt))for(const n of await t.run())console.log("action"===n.kind?o.yellow(" ! "+n.text):o.green(" √ "+n.text));else t.decline();else console.log(o.yellow(" ! "+t.hint))}const d=r(),y=g||d?t.filter(o=>a(o)?.installSpec&&s.outdatedVersion(o)):[];if(y.length>0){const o=y.map(o=>a(o)?.displayName??o).join("、");if(d||await u(n.t("setup.offer_upgrade",{tools:o})))for(const o of y)await l(o)}for(const e of t){const t=a(e);if(m.has(e)||!t?.runningApp?.isRunning())continue;if(d||!g){console.log(o.yellow(" ! "+n.t("setup.reopen_hint",{tool:t.displayName})));continue}if(!await u(n.t("setup.offer_restart",{tool:t.displayName})))continue;const r=t.runningApp.restart();console.log(r?o.green(" √ "+n.t("setup.restarted",{tool:t.displayName})):o.yellow(" ! "+n.t("setup.restart_failed",{tool:t.displayName})))}}
1
+ import o from"chalk";import t from"inquirer";import{i18n as n}from"./i18n.js";import{canPrompt as e,hasExplicitYes as r,shouldAutoConfirm as i}from"./runtime-options.js";import{toolManager as s}from"./tool-manager.js";import{getAdapter as a}from"./tools/registry.js";import{upgradeTool as l}from"./tool-upgrade.js";import{appsForTools as p,upgradeApp as c}from"./app-update.js";import{logger as f}from"../utils/logger.js";async function u(o){const{ok:n}=await t.prompt([{type:"confirm",name:"ok",message:o,default:!0}]);return n}export async function runPendingElevations(t){const r=e();for(const e of t){const t=a(e)?.pendingElevation?.();if(!t)continue;if(!(i()||r&&await u(t.prompt)))continue;const s=a(e)?.displayName??e;console.log(o.gray(" "+n.t("setup.elevation_running"))),console.log(t.run()?o.green(" √ "+n.t("setup.elevation_done",{tool:s})):o.yellow(" ! "+n.t("setup.elevation_failed",{tool:s})))}}export async function runFollowUps(t){const n=e();for(const e of t){let t;try{t=await(a(e)?.followUp?.())}catch(o){f.logError(`postApplyPrompts.followUp(${e})`,o);continue}if(t)if("run"in t&&(r()||n))if(r()||await u(t.prompt))for(const n of await t.run())console.log("action"===n.kind?o.yellow(" ! "+n.text):o.green(" √ "+n.text));else t.decline();else console.log(o.yellow(" ! "+t.hint))}}export async function postApplyPrompts(t,i={}){const m=new Set;for(const o of i.apps?p(t):[])try{const t=await c(o,{install:i.apps.install,quiet:!0,askBeforeUpgrade:!0});t.upgraded&&t.running&&m.add(o)}catch(t){f.logError(`postApplyPrompts.upgradeApp(${o})`,t)}for(const n of t){const t=await(a(n)?.prepareRuntime?.())??[];for(const n of t)console.log("action"===n.kind?o.yellow(" ! "+n.text):o.green(" √ "+n.text))}await runPendingElevations(t),await runFollowUps(t);const g=e(),d=r(),y=g||d?t.filter(o=>a(o)?.installSpec&&s.outdatedVersion(o)):[];if(y.length>0){const o=y.map(o=>a(o)?.displayName??o).join("、");if(d||await u(n.t("setup.offer_upgrade",{tools:o})))for(const o of y)await l(o)}for(const e of t){const t=a(e);if(m.has(e)||!t?.runningApp?.isRunning())continue;if(d||!g){console.log(o.yellow(" ! "+n.t("setup.reopen_hint",{tool:t.displayName})));continue}if(!await u(n.t("setup.offer_restart",{tool:t.displayName})))continue;const r=t.runningApp.restart();console.log(r?o.green(" √ "+n.t("setup.restarted",{tool:t.displayName})):o.yellow(" ! "+n.t("setup.restart_failed",{tool:t.displayName})))}}
@@ -22,6 +22,7 @@ export interface ToolInfo {
22
22
  /** GUI app (no terminal command to type, e.g. Claude Desktop). */
23
23
  gui?: boolean;
24
24
  }
25
+ /** Every key saved in any profile (default and tool-specific), trimmed. */
25
26
  /**
26
27
  * Tool metadata keyed by id. Derived from the adapter registry so the list of
27
28
  * supported tools lives in exactly one place (`lib/tools/registry.ts`).
@@ -62,6 +63,7 @@ export declare class ToolManager {
62
63
  forceResetConfig(toolName: string): string[];
63
64
  loadPrivateConfig(toolName: string, apiKey: string, models: VibecliModels, catalog?: ModelCatalog, options?: {
64
65
  force?: boolean;
66
+ takeOver?: boolean;
65
67
  }): void;
66
68
  /**
67
69
  * `loadPrivateConfig` plus the network lookup adapters with
@@ -70,6 +72,7 @@ export declare class ToolManager {
70
72
  */
71
73
  applyPrivateConfig(toolName: string, apiKey: string, models: VibecliModels, options?: {
72
74
  force?: boolean;
75
+ takeOver?: boolean;
73
76
  }): Promise<void>;
74
77
  private applyPrivateConfigNow;
75
78
  /** Post-apply follow-ups the adapter wants shown to the user (may be empty). */
@@ -1 +1 @@
1
- import{execSync as o,spawnSync as t}from"child_process";import{i18n as n}from"./i18n.js";import e from"inquirer";import r from"chalk";import{canPrompt as i,shouldAutoConfirm as l}from"./runtime-options.js";import{logger as s}from"../utils/logger.js";import{configManager as a}from"./config.js";import{getAdapter as c,listAdapters as d,TOOL_ADAPTERS as p}from"./tools/registry.js";import{backupBeforeWrite as u,listBackups as m,restoreBackup as f}from"./tools/backup.js";import{existsSync as g,rmSync as h}from"fs";import{dirname as w,join as y}from"path";import{toolHome as P}from"./tools/types.js";import{stringWidth as $}from"../utils/string-width.js";import{resolveModelCatalog as T}from"./model-catalog.js";import{compareVersions as v,getToolMinVersion as C}from"./model-registry.js";import{findInstalls as k,forgetInstalls as E,installLabel as O,mirrorInstallCommand as _,npmMirrorInstallCommand as S,npmMirrorVersion as N}from"./tools/tool-installs.js";import{mirrorInstall as j}from"./tool-upgrade.js";import{upgradeApp as M}from"./app-update.js";import{CLI_NAME as U}from"./brand.js";import{track as b,trackStep as x}from"./telemetry.js";import{addUserPathDir as I,broadcastEnvChange as R}from"./windows-env.js";export{v as compareVersions};function F(o){const t=p[o];return{name:t.name,command:t.command,installCommand:t.installCommand,configPath:t.configPath,displayName:t.displayName,...t.hidden?{hidden:!0}:{},...t.isInstalled?{gui:!0}:{}}}function L(){const o=new Set;for(const t of a.listProfiles()){const n=a.getProfile(t);for(const t of[n.api_key,...Object.values(n.tool_api_keys??{})])t?.trim()&&o.add(t.trim())}return[...o]}export const SUPPORTED_TOOLS=Object.fromEntries(Object.keys(p).map(o=>[o,F(o)]));export class ToolManager{static instance;constructor(){}static getInstance(){return ToolManager.instance||(ToolManager.instance=new ToolManager),ToolManager.instance}isToolInstalled(o){if(!SUPPORTED_TOOLS[o])return!1;const t=c(o);if(t?.isInstalled)try{return t.isInstalled()}catch{return!1}return this.isOnPath(o)||null!==this.nativeLauncher(o)}isOnPath(t){const n=SUPPORTED_TOOLS[t];if(!n)return!1;try{const t="win32"===process.platform?`where ${n.command}`:`which ${n.command}`;return o(t,{stdio:"pipe"}),!0}catch{return!1}}nativeLauncher(o){const t=c(o),n=t?.installSpec?.native?.binDir;if(!t||!n)return null;const e="win32"===process.platform?`${t.command}.exe`:t.command,r=y(P(),...n,e);return g(r)?r:null}ensureNativeOnPath(o){if("win32"!==process.platform||this.isOnPath(o))return null;const t=this.nativeLauncher(o);if(!t)return null;const n=w(t);try{if(!I(n))return null}catch(t){return s.logError(`ensureNativeOnPath: ${o}`,t),null}return R(),process.env.Path=`${process.env.Path??""};${n}`,n}async installTool(o){return x(`install:${o}`,()=>this.installToolNow(o))}async installToolNow(t){const s=SUPPORTED_TOOLS[t];if(!s)throw new Error(`Unknown tool: ${t}`);const a=c(t)?.appInstaller;if(a&&!a.blocker()){const o=await M(t,{install:!0});if("failed"===o.result||"unavailable"===o.result)throw new Error(`Failed to install ${s.displayName}`);return}const d=c(t)?.installSpec;if(d&&(d.mirrorScript||d.npmPackage)){const o=_(d);if(await j(d)&&(E(),this.isToolInstalled(t)))return void console.log(r.green("√ "+n.t("wizard.tool_installed")));throw console.log(r.red("× "+n.t("wizard.install_failed"))),console.log(r.yellow(" ! "+n.t("install.manual_command",{tool:s.displayName,command:o}))),d.mirrorScript&&d.npmPackage&&console.log(r.yellow(" ! "+n.t("install.manual_npm",{command:S(d,await N(d))}))),new Error(`Failed to install ${s.displayName}`)}const p=s.installCommand;console.log(r.gray("$ ")+r.white(p));try{return o(p,{stdio:"inherit"}),E(),void console.log(r.green("√ "+n.t("wizard.tool_installed")))}catch(o){if(console.log(r.red("× "+n.t("wizard.install_failed"))),!/EACCES|EPERM|permission denied/i.test(`${o?.message??""}${o?.stderr??""}`)&&243!==o?.status&&!p.startsWith("npm "))throw new Error(`Failed to install ${s.displayName}: ${o}`);console.log(r.yellow(" ! "+("win32"===process.platform?n.t("install.permission_windows",{command:p}):n.t("install.permission_unix",{command:p}))))}const{action:u}=!i()||l()?{action:"continue"}:await e.prompt([{type:"list",name:"action",message:n.t("install.what_next"),choices:[{name:n.t("install.installed_continue"),value:"continue"},{name:n.t("install.cancel_install"),value:"cancel"}]}]);if("cancel"===u)throw new Error(n.t("install.user_cancelled"));if(E(),!this.isToolInstalled(t))throw console.log(r.red("× "+n.t("install.still_not_installed",{tool:s.displayName}))),new Error(`${s.displayName} is not installed`);console.log(r.green("√ "+n.t("install.verified_success",{tool:s.displayName})))}getToolConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);try{return t.getConfig()}catch(t){return s.warn(`Failed to read config for ${o}:`,t),s.logError(`ToolManager.getToolConfig(${o})`,t),null}}updateToolConfig(o,t){const n=c(o);if(!n)throw new Error(`Unknown tool: ${o}`);if(!n.updateConfig)throw new Error(`Tool ${o} does not support raw config updates`);n.updateConfig(t)}forceResetConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);const n=t.forceResetPaths?t.forceResetPaths():this.backupPathsFor(t),e=[];for(const o of n)g(o)&&(u(o),h(o,{force:!0}),e.push(o));return e}loadPrivateConfig(o,t,n,e,r={}){const i=c(o);if(!i)throw new Error(`Unknown tool: ${o}`);r.force&&this.forceResetConfig(o),i.loadPrivateConfig({apiKey:t,baseUrl:a.getBaseUrl(),models:n,settings:a.getToolSettings(o),...e?{catalog:e}:{}})}async applyPrivateConfig(o,t,n,e={}){const r=this.installedVersion(o);return x(`apply:${o}`,()=>this.applyPrivateConfigNow(o,t,n,e),{...r?{tool_version:r}:{},...e.force?{force:!0}:{}})}async applyPrivateConfigNow(o,t,n,e){const r=c(o);if(!r)throw new Error(`Unknown tool: ${o}`);const i=r.wantsModelCatalog?await T(t):null;e.force?this.loadPrivateConfig(o,t,n,i??void 0,{force:!0}):i?this.loadPrivateConfig(o,t,n,i):this.loadPrivateConfig(o,t,n)}applyNotes(o){const t=c(o);if(!t)return[];const e=[];try{t.applyNotes&&e.push(...t.applyNotes())}catch(t){s.logError(`ToolManager.applyNotes(${o})`,t)}const r=this.outdatedVersion(o);if(r){e.push({kind:"action",text:n.t("tools.version_outdated",{current:r.current,min:r.min,upgrade:t.installSpec?`${U} upgrade ${o}`:t.upgradeCommand||t.installCommand})});for(const o of t.upgradeHints?.(r.min)??[])e.push({kind:"action",text:o})}const i=t.installSpec?k(t.installSpec):[];return i.length>1&&e.push({kind:"action",text:n.t("upgrade.duplicates_note",{count:String(i.length),active:O(i[0]),others:i.slice(1).map(O).join("、"),tool:o})}),e}printApplied(o,t=16){const n=SUPPORTED_TOOLS[o]?.displayName??o,e=this.applyNotes(o);for(const o of e.filter(o=>"detail"===o.kind))s.record(`${n}: ${o.text}`);const i=e.filter(o=>"summary"===o.kind).map(o=>o.text).join(";"),l=" ".repeat(Math.max(1,t-$(n)));console.log(r.green("√ "+n)+(i?l+i:""));for(const o of e.filter(o=>"action"===o.kind))console.log(r.yellow(" ! "+o.text))}installedVersion(o){const n=c(o);if(!n)return null;if(n.installSpec)return k(n.installSpec)[0]?.version??null;if(n.installedVersion)try{return n.installedVersion()}catch(t){return s.logError(`ToolManager.installedVersion(${o})`,t),null}if(n.isInstalled)return null;try{const o={encoding:"utf-8",timeout:1e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]},e=`${("win32"===process.platform?t(`${n.command} --version`,{...o,shell:!0}):t(n.command,["--version"],o)).stdout??""}`.match(/(\d+)\.(\d+)\.(\d+)/);return e?e[0]:null}catch{return null}}outdatedVersion(o){const t=C(o);if(!t)return null;const n=this.installedVersion(o);return n&&v(n,t)<0?{current:n,min:t}:null}unloadPrivateConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);try{t.unloadPrivateConfig({savedKeys:L()}),b(`remove:${o}`,"ok")}catch(t){throw b(`remove:${o}`,"fail",{error:t}),t}let e=[];try{e=t.unloadNotes?.()??[]}catch(t){s.logError(`ToolManager.unloadNotes(${o})`,t)}return e.length>0?e:[{kind:"action",text:n.t("config.reopen_hint",{tool:t.displayName})}]}async clearPinnedModels(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);if(a.setToolModel(o,null),!t.clearPinnedModels)return[];const n=a.getApiKeyForTool(o),e=t.wantsModelCatalog&&n?await T(n):null;return t.clearPinnedModels(e??void 0)}supportsClearPinnedModels(o){return Boolean(c(o)?.clearPinnedModels)}holdsOurConfig(o){const t=c(o);if(!t)return!1;const n=L();return t.holdsOurConfig?t.holdsOurConfig(n):Boolean(t.detectCurrentConfig().apiKey)}detectCurrentConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);return t.detectCurrentConfig()}backupPathsFor(o){return o.backupPaths?o.backupPaths():[o.configPath]}listToolBackups(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,backups:m(o)}))}restorePrivateConfig(o){const t=c(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,result:f(o)}))}getInstalledTools(){return Object.keys(SUPPORTED_TOOLS).filter(o=>this.isToolInstalled(o))}getSupportedTools(){return d().filter(o=>!o.hidden).map(o=>F(o.name))}isGitInstalled(){try{const t="win32"===process.platform?"where git":"which git";return o(t,{stdio:"pipe"}),!0}catch{return!1}}}export const toolManager=ToolManager.getInstance();
1
+ import{execSync as o,spawnSync as t}from"child_process";import{i18n as n}from"./i18n.js";import e from"inquirer";import r from"chalk";import{canPrompt as i,shouldAutoConfirm as l}from"./runtime-options.js";import{logger as a}from"../utils/logger.js";import{configManager as s,savedApiKeys as c}from"./config.js";import{getAdapter as d,listAdapters as p,TOOL_ADAPTERS as u}from"./tools/registry.js";import{backupBeforeWrite as m,listBackups as f,restoreBackup as g}from"./tools/backup.js";import{existsSync as h,rmSync as w}from"fs";import{dirname as y,join as P}from"path";import{toolHome as v}from"./tools/types.js";import{stringWidth as $}from"../utils/string-width.js";import{resolveModelCatalog as T}from"./model-catalog.js";import{compareVersions as k,getToolMinVersion as C}from"./model-registry.js";import{findInstalls as E,forgetInstalls as O,installLabel as _,mirrorInstallCommand as S,npmMirrorInstallCommand as N,npmMirrorVersion as j}from"./tools/tool-installs.js";import{mirrorInstall as M}from"./tool-upgrade.js";import{upgradeApp as U}from"./app-update.js";import{CLI_NAME as b}from"./brand.js";import{track as x,trackStep as I}from"./telemetry.js";import{addUserPathDir as R,broadcastEnvChange as F}from"./windows-env.js";export{k as compareVersions};function L(o){const t=u[o];return{name:t.name,command:t.command,installCommand:t.installCommand,configPath:t.configPath,displayName:t.displayName,...t.hidden?{hidden:!0}:{},...t.isInstalled?{gui:!0}:{}}}export const SUPPORTED_TOOLS=Object.fromEntries(Object.keys(u).map(o=>[o,L(o)]));export class ToolManager{static instance;constructor(){}static getInstance(){return ToolManager.instance||(ToolManager.instance=new ToolManager),ToolManager.instance}isToolInstalled(o){if(!SUPPORTED_TOOLS[o])return!1;const t=d(o);if(t?.isInstalled)try{return t.isInstalled()}catch{return!1}return this.isOnPath(o)||null!==this.nativeLauncher(o)}isOnPath(t){const n=SUPPORTED_TOOLS[t];if(!n)return!1;try{const t="win32"===process.platform?`where ${n.command}`:`which ${n.command}`;return o(t,{stdio:"pipe"}),!0}catch{return!1}}nativeLauncher(o){const t=d(o),n=t?.installSpec?.native?.binDir;if(!t||!n)return null;const e="win32"===process.platform?`${t.command}.exe`:t.command,r=P(v(),...n,e);return h(r)?r:null}ensureNativeOnPath(o){if("win32"!==process.platform||this.isOnPath(o))return null;const t=this.nativeLauncher(o);if(!t)return null;const n=y(t);try{if(!R(n))return null}catch(t){return a.logError(`ensureNativeOnPath: ${o}`,t),null}return F(),process.env.Path=`${process.env.Path??""};${n}`,n}async installTool(o){return I(`install:${o}`,()=>this.installToolNow(o))}async installToolNow(t){const a=SUPPORTED_TOOLS[t];if(!a)throw new Error(`Unknown tool: ${t}`);const s=d(t)?.appInstaller;if(s&&!s.blocker()){const o=await U(t,{install:!0});if("failed"===o.result||"unavailable"===o.result)throw new Error(`Failed to install ${a.displayName}`);return}const c=d(t)?.installSpec;if(c&&(c.mirrorScript||c.npmPackage)){const o=S(c);if(await M(c)&&(O(),this.isToolInstalled(t)))return void console.log(r.green("√ "+n.t("wizard.tool_installed")));throw console.log(r.red("× "+n.t("wizard.install_failed"))),console.log(r.yellow(" ! "+n.t("install.manual_command",{tool:a.displayName,command:o}))),c.mirrorScript&&c.npmPackage&&console.log(r.yellow(" ! "+n.t("install.manual_npm",{command:N(c,await j(c))}))),new Error(`Failed to install ${a.displayName}`)}const p=a.installCommand;console.log(r.gray("$ ")+r.white(p));try{return o(p,{stdio:"inherit"}),O(),void console.log(r.green("√ "+n.t("wizard.tool_installed")))}catch(o){if(console.log(r.red("× "+n.t("wizard.install_failed"))),!/EACCES|EPERM|permission denied/i.test(`${o?.message??""}${o?.stderr??""}`)&&243!==o?.status&&!p.startsWith("npm "))throw new Error(`Failed to install ${a.displayName}: ${o}`);console.log(r.yellow(" ! "+("win32"===process.platform?n.t("install.permission_windows",{command:p}):n.t("install.permission_unix",{command:p}))))}const{action:u}=!i()||l()?{action:"continue"}:await e.prompt([{type:"list",name:"action",message:n.t("install.what_next"),choices:[{name:n.t("install.installed_continue"),value:"continue"},{name:n.t("install.cancel_install"),value:"cancel"}]}]);if("cancel"===u)throw new Error(n.t("install.user_cancelled"));if(O(),!this.isToolInstalled(t))throw console.log(r.red("× "+n.t("install.still_not_installed",{tool:a.displayName}))),new Error(`${a.displayName} is not installed`);console.log(r.green("√ "+n.t("install.verified_success",{tool:a.displayName})))}getToolConfig(o){const t=d(o);if(!t)throw new Error(`Unknown tool: ${o}`);try{return t.getConfig()}catch(t){return a.warn(`Failed to read config for ${o}:`,t),a.logError(`ToolManager.getToolConfig(${o})`,t),null}}updateToolConfig(o,t){const n=d(o);if(!n)throw new Error(`Unknown tool: ${o}`);if(!n.updateConfig)throw new Error(`Tool ${o} does not support raw config updates`);n.updateConfig(t)}forceResetConfig(o){const t=d(o);if(!t)throw new Error(`Unknown tool: ${o}`);const n=t.forceResetPaths?t.forceResetPaths():this.backupPathsFor(t),e=[];for(const o of n)h(o)&&(m(o),w(o,{force:!0}),e.push(o));return e}loadPrivateConfig(o,t,n,e,r={}){const i=d(o);if(!i)throw new Error(`Unknown tool: ${o}`);r.force&&this.forceResetConfig(o),i.loadPrivateConfig({apiKey:t,baseUrl:s.getBaseUrl(),models:n,settings:s.getToolSettings(o),...e?{catalog:e}:{},...r.takeOver?{takeOver:!0}:{}})}async applyPrivateConfig(o,t,n,e={}){const r=this.installedVersion(o);return I(`apply:${o}`,()=>this.applyPrivateConfigNow(o,t,n,e),{...r?{tool_version:r}:{},...e.force?{force:!0}:{}})}async applyPrivateConfigNow(o,t,n,e){const r=d(o);if(!r)throw new Error(`Unknown tool: ${o}`);const i=r.wantsModelCatalog?await T(t):null,{force:l,takeOver:a}=e;l||a?this.loadPrivateConfig(o,t,n,i??void 0,{force:l,takeOver:a}):i?this.loadPrivateConfig(o,t,n,i):this.loadPrivateConfig(o,t,n)}applyNotes(o){const t=d(o);if(!t)return[];const e=[];try{t.applyNotes&&e.push(...t.applyNotes())}catch(t){a.logError(`ToolManager.applyNotes(${o})`,t)}const r=this.outdatedVersion(o);if(r){e.push({kind:"action",text:n.t("tools.version_outdated",{current:r.current,min:r.min,upgrade:t.installSpec?`${b} upgrade ${o}`:t.upgradeCommand||t.installCommand})});for(const o of t.upgradeHints?.(r.min)??[])e.push({kind:"action",text:o})}const i=t.installSpec?E(t.installSpec):[];return i.length>1&&e.push({kind:"action",text:n.t("upgrade.duplicates_note",{count:String(i.length),active:_(i[0]),others:i.slice(1).map(_).join("、"),tool:o})}),e}printApplied(o,t=16){const n=SUPPORTED_TOOLS[o]?.displayName??o,e=this.applyNotes(o);for(const o of e.filter(o=>"detail"===o.kind))a.record(`${n}: ${o.text}`);const i=e.filter(o=>"summary"===o.kind).map(o=>o.text).join(";"),l=" ".repeat(Math.max(1,t-$(n)));console.log(r.green("√ "+n)+(i?l+i:""));for(const o of e.filter(o=>"action"===o.kind))console.log(r.yellow(" ! "+o.text))}installedVersion(o){const n=d(o);if(!n)return null;if(n.installSpec)return E(n.installSpec)[0]?.version??null;if(n.installedVersion)try{return n.installedVersion()}catch(t){return a.logError(`ToolManager.installedVersion(${o})`,t),null}if(n.isInstalled)return null;try{const o={encoding:"utf-8",timeout:1e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]},e=`${("win32"===process.platform?t(`${n.command} --version`,{...o,shell:!0}):t(n.command,["--version"],o)).stdout??""}`.match(/(\d+)\.(\d+)\.(\d+)/);return e?e[0]:null}catch{return null}}outdatedVersion(o){const t=C(o);if(!t)return null;const n=this.installedVersion(o);return n&&k(n,t)<0?{current:n,min:t}:null}unloadPrivateConfig(o){const t=d(o);if(!t)throw new Error(`Unknown tool: ${o}`);try{t.unloadPrivateConfig({savedKeys:c()}),x(`remove:${o}`,"ok")}catch(t){throw x(`remove:${o}`,"fail",{error:t}),t}let e=[];try{e=t.unloadNotes?.()??[]}catch(t){a.logError(`ToolManager.unloadNotes(${o})`,t)}return e.length>0?e:[{kind:"action",text:n.t("config.reopen_hint",{tool:t.displayName})}]}async clearPinnedModels(o){const t=d(o);if(!t)throw new Error(`Unknown tool: ${o}`);if(s.setToolModel(o,null),!t.clearPinnedModels)return[];const n=s.getApiKeyForTool(o),e=t.wantsModelCatalog&&n?await T(n):null;return t.clearPinnedModels(e??void 0)}supportsClearPinnedModels(o){return Boolean(d(o)?.clearPinnedModels)}holdsOurConfig(o){const t=d(o);if(!t)return!1;const n=c();return t.holdsOurConfig?t.holdsOurConfig(n):Boolean(t.detectCurrentConfig().apiKey)}detectCurrentConfig(o){const t=d(o);if(!t)throw new Error(`Unknown tool: ${o}`);return t.detectCurrentConfig()}backupPathsFor(o){return o.backupPaths?o.backupPaths():[o.configPath]}listToolBackups(o){const t=d(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,backups:f(o)}))}restorePrivateConfig(o){const t=d(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,result:g(o)}))}getInstalledTools(){return Object.keys(SUPPORTED_TOOLS).filter(o=>this.isToolInstalled(o))}getSupportedTools(){return p().filter(o=>!o.hidden).map(o=>L(o.name))}isGitInstalled(){try{const t="win32"===process.platform?"where git":"which git";return o(t,{stdio:"pipe"}),!0}catch{return!1}}}export const toolManager=ToolManager.getInstance();
@@ -1 +1 @@
1
- import{join as e}from"path";import{applyGatewayModels as t,claudeCodeManager as o}from"../claude-code-manager.js";import{backupBeforeWrite as s}from"./backup.js";import{i18n as n}from"../i18n.js";import{baseModelId as a}from"../model-catalog.js";import{gatewayModelSpecs as i,prettyModelName as r,vendorNames as l}from"../gateway-models.js";import{toolHome as d}from"./types.js";import{gatewayAddresses as c,normalizeBaseUrl as u}from"../gateway-addresses.js";import{configManager as m}from"../config.js";import{spawnSync as p}from"child_process";import{existsSync as g,readFileSync as f}from"fs";import{detectManagedOverrides as _}from"./claude-managed.js";import{installOfficialPlugins as C}from"./claude-plugins.js";import{findInstalls as h,mirrorInstallCommand as A,brandInstallScripts as j}from"./tool-installs.js";import{updateNativeFromMirror as y}from"./claude-native-mirror.js";import{brandEnv as P}from"../brand.js";import{claudeFormat as S,claudeProjectFiles as k}from"../sessions/formats.js";const v=e(d(),".claude","settings.json"),O=e(d(),".claude.json");let T,N=null,x=()=>0===p("security",["find-generic-password","-s","Claude Code-credentials"],{stdio:"ignore"}).status;export function setClaudeKeychainProbeForTests(e){x=e}export function claudeAccountLoginPresent(){const t=process.env.CLAUDE_CONFIG_DIR?.trim()||e(d(),".claude");if(g(e(t,".credentials.json")))return!0;if("darwin"!==process.platform||P("TEST_HOME"))return!1;try{return x()}catch{return!1}}function H(){try{const t=JSON.parse(f(e(d(),".claude","settings.json"),"utf-8"));return"string"==typeof t.autoUpdatesChannel?t.autoUpdatesChannel:"latest"}catch{return"latest"}}function b(e){if(!e)return;const t=new Set(e.models);return i("claude-code",e.clientModels).filter(e=>t.has(e.id))}const w={command:"claude",npmPackage:"@anthropic-ai/claude-code",native:{binDir:[".local","bin"],updateArgs:["update"],dataDirs:[[".local","share","claude"]],mirrorUpdate:()=>y(H())},mirrorScript:j("claude-code"),brew:"claude-code"};export const claudeCodeAdapter={name:"claude-code",displayName:"Claude Code",command:"claude",installCommand:A(w),upgradeCommand:"claude update",installSpec:w,upgradeHints:e=>"stable"===H()?[n.t("tools.claude_code.stable_channel",{min:e})]:[],configPath:v,sessions:{format:S,files:()=>k(e(process.env.CLAUDE_CONFIG_DIR?.trim()||e(d(),".claude"),"projects")),resumeCommand:e=>({command:"claude",args:["--resume",e]})},wantsModelCatalog:!0,loadPrivateConfig(t){s(v),s(O),T=b(t.catalog),o.loadPrivateConfig(t.apiKey,t.models,t.catalog?.models,T);const n=e(d(),".local","bin","win32"===process.platform?"claude.exe":"claude"),a=h(claudeCodeAdapter.installSpec)[0]?.path??(g(n)?n:null);N=a?C(a):null},holdsOurConfig(e){const t=o.getSettings().env??{},s="string"==typeof t.ANTHROPIC_AUTH_TOKEN?t.ANTHROPIC_AUTH_TOKEN.trim():"",n="string"==typeof t.ANTHROPIC_BASE_URL?u(t.ANTHROPIC_BASE_URL):null;return!(!s||!e.includes(s))||null!==n&&(c().some(e=>e.url===n)||n===u(m.getBaseUrl()))},unloadPrivateConfig(e){const t=o.getSettings().env??{};Boolean(t.ANTHROPIC_AUTH_TOKEN||t.ANTHROPIC_BASE_URL)&&!claudeCodeAdapter.holdsOurConfig(e?.savedKeys??[])||(s(v),o.unloadPrivateConfig())},detectCurrentConfig:()=>o.detectCurrentConfig(),getConfig:()=>({settings:o.getSettings(),mcp:o.getMCPConfig()}),updateConfig(e){const t=e||{};t.settings&&o.saveSettings(t.settings),t.mcp&&o.saveMCPConfig(t.mcp)},clearPinnedModels:e=>(s(v),o.clearPinnedModels(e?.models)),listedModels(){const e=o.getSettings().modelPicker;return Array.isArray(e?.options)?e.options.map(e=>a(String(e.model))):null},refreshModelMenu(e){const n=o.getSettings(),a=t(n,b(e.catalog));JSON.stringify(a)!==JSON.stringify(n)&&(s(v),o.saveSettings(a))},applyNotes(){const e=[];N?.installed.length&&(e.push({kind:"summary",text:n.t("tools.claude_code.plugins_installed",{count:String(N.installed.length)})}),e.push({kind:"detail",text:N.installed.join(", ")})),"git"===N?.skipped?e.push({kind:"action",text:n.t("tools.claude_code.plugins_need_git")}):("marketplace"===N?.skipped||N?.failed.length)&&e.push({kind:"action",text:n.t("tools.claude_code.plugins_failed")}),T&&T.length>0&&(e.push({kind:"summary",text:n.t("tools.claude_code.gateway_models",{count:String(T.length),vendors:l(T.map(e=>e.id)).join(" / ")})}),e.push({kind:"detail",text:T.map(e=>e.name||r(e.id)).join(", ")})),"win32"!==process.platform||process.env.CLAUDE_CODE_GIT_BASH_PATH||0===p("where",["git"],{windowsHide:!0,stdio:"ignore"}).status||e.push({kind:"action",text:n.t("tools.claude_code.no_git_bash")}),claudeAccountLoginPresent()&&e.push({kind:"detail",text:n.t("tools.claude_code.account_login_overridden")});for(const t of _())e.push({kind:"action",text:n.t("tools.claude_code.managed_override",{source:t.source,keys:t.keys.join(", ")})});for(const t of o.getLastTierFallbacks())e.push({kind:"detail",text:n.t("tools.claude_code.tier_fallback",{tier:t.tier,from:t.from,to:t.to})});return e},backupPaths:()=>[v,O],forceResetPaths:()=>[v]};
1
+ import{join as e}from"path";import{applyGatewayModels as t,claudeCodeManager as o}from"../claude-code-manager.js";import{backupBeforeWrite as n}from"./backup.js";import{i18n as s}from"../i18n.js";import{baseModelId as a}from"../model-catalog.js";import{gatewayModelSpecs as r,prettyModelName as i,vendorNames as l}from"../gateway-models.js";import{toolHome as c}from"./types.js";import{gatewayAddresses as d,normalizeBaseUrl as u}from"../gateway-addresses.js";import{configManager as m,savedApiKeys as p}from"../config.js";import{envCleanupPlan as f,lastEnvCleanup as g,removeEnvSources as _}from"../env-cleanup.js";import{canPrompt as h,hasExplicitYes as v}from"../runtime-options.js";import{maskHome as C}from"../telemetry.js";import{spawnSync as j}from"child_process";import{existsSync as y,readFileSync as k}from"fs";import{detectManagedOverrides as A}from"./claude-managed.js";import{installOfficialPlugins as O}from"./claude-plugins.js";import{findInstalls as S,mirrorInstallCommand as P,brandInstallScripts as x}from"./tool-installs.js";import{updateNativeFromMirror as b}from"./claude-native-mirror.js";import{brandEnv as T}from"../brand.js";import{claudeFormat as N,claudeProjectFiles as w}from"../sessions/formats.js";const H=e(c(),".claude","settings.json"),L=e(c(),".claude.json");let U,R=null,E=()=>0===j("security",["find-generic-password","-s","Claude Code-credentials"],{stdio:"ignore"}).status;export function setClaudeKeychainProbeForTests(e){E=e}export function claudeAccountLoginPresent(){const t=process.env.CLAUDE_CONFIG_DIR?.trim()||e(c(),".claude");if(y(e(t,".credentials.json")))return!0;if("darwin"!==process.platform||T("TEST_HOME"))return!1;try{return E()}catch{return!1}}function I(){try{const t=JSON.parse(k(e(c(),".claude","settings.json"),"utf-8"));return"string"==typeof t.autoUpdatesChannel?t.autoUpdatesChannel:"latest"}catch{return"latest"}}function M(e){if(!e)return;const t=new Set(e.models);return r("claude-code",e.clientModels).filter(e=>t.has(e.id))}function D(){const e=o.getSettings().env?.ANTHROPIC_BASE_URL;return"string"==typeof e&&e.trim()?claudeCodeAdapter.holdsOurConfig(p())?null:e.trim():null}let B=null;const K={command:"claude",npmPackage:"@anthropic-ai/claude-code",native:{binDir:[".local","bin"],updateArgs:["update"],dataDirs:[[".local","share","claude"]],mirrorUpdate:()=>b(I())},mirrorScript:x("claude-code"),brew:"claude-code"};function F(){return h()&&!v()}export const claudeCodeAdapter={name:"claude-code",displayName:"Claude Code",command:"claude",installCommand:P(K),upgradeCommand:"claude update",installSpec:K,upgradeHints:e=>"stable"===I()?[s.t("tools.claude_code.stable_channel",{min:e})]:[],configPath:H,sessions:{format:N,files:()=>w(e(process.env.CLAUDE_CONFIG_DIR?.trim()||e(c(),".claude"),"projects")),resumeCommand:e=>({command:"claude",args:["--resume",e]})},wantsModelCatalog:!0,loadPrivateConfig(t){B=D(),n(H),n(L),U=M(t.catalog),o.loadPrivateConfig(t.apiKey,t.models,t.catalog?.models,U);const s=e(c(),".local","bin","win32"===process.platform?"claude.exe":"claude"),a=S(claudeCodeAdapter.installSpec)[0]?.path??(y(s)?s:null);R=a?O(a):null},holdsOurConfig(e){const t=o.getSettings().env??{},n="string"==typeof t.ANTHROPIC_AUTH_TOKEN?t.ANTHROPIC_AUTH_TOKEN.trim():"",s="string"==typeof t.ANTHROPIC_BASE_URL?u(t.ANTHROPIC_BASE_URL):null;return!(!n||!e.includes(n))||null!==s&&(d().some(e=>e.url===s)||s===u(m.getBaseUrl()))},planNotes(){const e=[],t=D();t&&e.push(s.t("tools.claude_code.plan_replace_provider",{url:t}));for(const t of f())e.push(s.t("tools.claude_code.plan_env_remove",{location:C(t.location),vars:Object.keys(t.vars).join(", ")}));return e},unloadPrivateConfig(e){const t=o.getSettings().env??{};Boolean(t.ANTHROPIC_AUTH_TOKEN||t.ANTHROPIC_BASE_URL)&&!claudeCodeAdapter.holdsOurConfig(e?.savedKeys??[])||(n(H),o.unloadPrivateConfig())},detectCurrentConfig:()=>o.detectCurrentConfig(),getConfig:()=>({settings:o.getSettings(),mcp:o.getMCPConfig()}),updateConfig(e){const t=e||{};t.settings&&o.saveSettings(t.settings),t.mcp&&o.saveMCPConfig(t.mcp)},clearPinnedModels:e=>(n(H),o.clearPinnedModels(e?.models)),listedModels(){const e=o.getSettings().modelPicker;return Array.isArray(e?.options)?e.options.map(e=>a(String(e.model))):null},refreshModelMenu(e){const s=o.getSettings(),a=t(s,M(e.catalog));JSON.stringify(a)!==JSON.stringify(s)&&(n(H),o.saveSettings(a))},async followUp(){const e=g().foreign;if(0===e.length||!F())return null;const t=e.map(e=>`${C(e.location)}(${Object.keys(e.vars).join(", ")})`).join("、");return{prompt:s.t("tools.claude_code.env_foreign_offer",{where:t}),hint:s.t("tools.claude_code.env_foreign",{location:e.map(e=>C(e.location)).join("、"),vars:[...new Set(e.flatMap(e=>Object.keys(e.vars)))].join(", ")}),async run(){const t=_(e),o=t.removed.map(e=>({kind:"summary",text:s.t("tools.claude_code.env_removed_foreign",{location:C(e.location),vars:Object.keys(e.vars).join(", ")})}));return t.machineLeft.length>0&&o.push({kind:"action",text:s.t("messages.env_vars_machine_left",{vars:t.machineLeft.join(", ")})}),o},decline(){}}},applyNotes(){const e=[];R?.installed.length&&(e.push({kind:"summary",text:s.t("tools.claude_code.plugins_installed",{count:String(R.installed.length)})}),e.push({kind:"detail",text:R.installed.join(", ")})),"git"===R?.skipped?e.push({kind:"action",text:s.t("tools.claude_code.plugins_need_git")}):("marketplace"===R?.skipped||R?.failed.length)&&e.push({kind:"action",text:s.t("tools.claude_code.plugins_failed")}),U&&U.length>0&&(e.push({kind:"summary",text:s.t("tools.claude_code.gateway_models",{count:String(U.length),vendors:l(U.map(e=>e.id)).join(" / ")})}),e.push({kind:"detail",text:U.map(e=>e.name||i(e.id)).join(", ")})),B&&e.push({kind:"summary",text:s.t("tools.claude_code.provider_replaced",{url:B})});const t=g();for(const o of t.removed)e.push({kind:"summary",text:s.t("tools.claude_code.env_removed",{location:C(o.location),vars:Object.keys(o.vars).join(", ")})});for(const o of t.foreign){const t={location:C(o.location),vars:Object.keys(o.vars).join(", ")};e.push(F()?{kind:"detail",text:s.t("tools.claude_code.env_foreign_found",t)}:{kind:"action",text:s.t("tools.claude_code.env_foreign",t)})}t.machineLeft.length>0&&e.push({kind:"action",text:s.t("messages.env_vars_machine_left",{vars:t.machineLeft.join(", ")})});const n=o.getLastKept();n.length>0&&e.push({kind:"summary",text:s.t("tools.claude_code.kept_user_models",{values:n.join(", ")})}),"win32"!==process.platform||process.env.CLAUDE_CODE_GIT_BASH_PATH||0===j("where",["git"],{windowsHide:!0,stdio:"ignore"}).status||e.push({kind:"action",text:s.t("tools.claude_code.no_git_bash")}),claudeAccountLoginPresent()&&e.push({kind:"detail",text:s.t("tools.claude_code.account_login_overridden")});for(const t of A())e.push({kind:"action",text:s.t("tools.claude_code.managed_override",{source:t.source,keys:t.keys.join(", ")})});for(const t of o.getLastTierFallbacks())e.push({kind:"detail",text:s.t("tools.claude_code.tier_fallback",{tier:t.tier,from:t.from,to:t.to})});return e},backupPaths:()=>[H,L],forceResetPaths:()=>[H]};
@@ -1,5 +1,5 @@
1
1
  import { type ToolAdapter } from './types.js';
2
- import type { VibecliModels } from '../config.js';
2
+ import { type VibecliModels } from '../config.js';
3
3
  import { type ModelCatalog } from '../model-catalog.js';
4
4
  /**
5
5
  * Tool setting (config.yaml `tool_settings['claude-desktop'].hide_official_login`).
@@ -1 +1 @@
1
- import{chmodSync as e,existsSync as t,mkdirSync as o,readdirSync as n,readFileSync as r,rmSync as s}from"fs";import{dirname as i}from"path";import{join as l}from"path";import{randomUUID as a}from"crypto";import{execFileSync as c}from"child_process";import{userInfo as d}from"os";import p from"chalk";import{logger as u}from"../../utils/logger.js";import{track as f}from"../telemetry.js";import{ensureDesktopCli as m,installedDesktopAsarPath as g}from"./claude-desktop-cli.js";import{i18n as y}from"../i18n.js";import{BRAND_NAME as h,brand as k,brandEnv as _,CLI_NAME as b}from"../brand.js";import{backupBeforeWrite as D,atomicWriteFile as w}from"./backup.js";import{toolHome as A}from"./types.js";import{canRestartDesktop as C,desktopQuitRefused as E,isDesktopRunning as v,launchDesktop as M,quitDesktop as O,restartDesktop as S,WINDOWS_PACKAGE_FAMILIES as x}from"./desktop-process.js";import{desktopInstallBlocker as P,fetchLatestDesktopVersion as j,installedMacApp as I,installLatestDesktop as L}from"./claude-desktop-app.js";import{setUserRegistryElevated as T}from"./elevated-reg.js";import{UserActionNeeded as $}from"./types.js";import{baseModelId as N,isClaudeModel as R}from"../model-catalog.js";import{getDefaultModels as G}from"../model-registry.js";import{claudeFormat as K,nestedClaudeProjectFiles as U}from"../sessions/formats.js";import{powerShellEnv as F}from"../powershell-env.js";const H=h;export const CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING="hide_official_login";export const CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING="force_registry";const J=/^[a-f0-9-]{36}$/;function V(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}export function claudeDesktopUserDataDir(){const e=process.env.CLAUDE_USER_DATA_DIR?.trim();if(e)return e;const o=A(),n=Boolean(_("TEST_HOME")?.trim());switch(process.platform){case"darwin":return l(o,"Library","Application Support","Claude-3p");case"win32":{const e=!n&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:l(o,"AppData","Local");return x.map(t=>l(e,"Packages",t,"LocalCache","Local","Claude-3p")).find(e=>t(e))??l(e,"Claude-3p")}default:{const e=!n&&process.env.XDG_CONFIG_HOME?process.env.XDG_CONFIG_HOME:l(o,".config");return l(e,"Claude-3p")}}}const B=()=>l(claudeDesktopUserDataDir(),"configLibrary"),W=()=>l(B(),"_meta.json"),z=e=>l(B(),`${e}.json`),q=()=>l(claudeDesktopUserDataDir(),"claude_desktop_config.json");function X(e){if(!t(e))return null;const o=r(e,"utf-8");if(!o.trim())return null;try{const e=JSON.parse(o);return V(e)?e:null}catch(t){throw new Error(`Existing ${e} cannot be parsed; back it up and fix it first: ${t instanceof Error?t.message:String(t)}`)}}function Z(n,r){const s=i(n);t(s)||o(s,{recursive:!0,mode:448}),D(n),w(n,JSON.stringify(r,null,2)+"\n");try{e(n,384)}catch(e){u.logError("claude-desktop.writeJson.chmod",e)}}function Y(){const e=X(W());if(!e)return null;const t=Array.isArray(e.entries)?e.entries.filter(e=>V(e)&&"string"==typeof e.id&&"string"==typeof e.name):[];return{...e,appliedId:"string"==typeof e.appliedId?e.appliedId:"",entries:t}}function Q(e){return e?.entries.find(e=>e.name===H&&J.test(e.id))}const ee={opus:0,fable:1,sonnet:2,haiku:3};function te(e){let t=/^claude-(opus|sonnet|haiku|fable)-(\d+(?:-\d+)*)/i.exec(e);return t?{family:t[1].toLowerCase(),version:t[2].split("-").map(Number)}:(t=/^claude-(\d+(?:-\d+)*)-(opus|sonnet|haiku)/i.exec(e),t?{family:t[2].toLowerCase(),version:t[1].split("-").map(Number)}:null)}export function humanizeModelId(e){const t=te(e);return t?`${t.family[0].toUpperCase()+t.family.slice(1)} ${t.version.filter(e=>e<1e7).slice(0,2).join(".")}`:e}function oe(e){return te(e)?.family}export function buildInferenceModels(e,t){const{primary:o,bySlot:n}=function(e){const t=["opus","sonnet","haiku","reasoning"].map(t=>N(e[t]||"")).filter(Boolean);return{primary:t[0]??"",bySlot:t}}(e),r=new Set,s=t?.labels??{};let i;if(t&&t.models.some(R)){i=[...new Set(t.models.filter(R).map(N))];for(const e of t.oneMillion)r.add(e)}else{i=[];for(const t of["opus","sonnet","haiku","reasoning"]){const o=(e[t]||"").trim(),n=N(o);n&&(i.includes(n)||i.push(n),/\[1m\]/i.test(o)&&r.add(n))}}const l=e=>ee[oe(e)??""]??9;i.sort((e,t)=>{if(e===o)return-1;if(t===o)return 1;const n=l(e)-l(t);if(0!==n)return n;const r=te(e),s=te(t);return r&&s?function(e,t){const o=Math.max(e.length,t.length);for(let n=0;n<o;n++){const o=(t[n]??0)-(e[n]??0);if(0!==o)return o}return 0}(r.version,s.version):e.localeCompare(t)});const a=new Set,c=new Map,d=new Set(Object.values(G()).map(e=>N(e||"")));for(const e of n){const t=oe(e);t&&i.includes(e)&&!d.has(e)&&!c.has(t)&&c.set(t,e)}return i.map(e=>{const t=oe(e),o={name:e,labelOverride:s[e]||humanizeModelId(e)};if(r.has(e)&&(o.supports1m=!0,o.prefer1m=!0),t){o.anthropicFamilyTier=t;const n=c.get(t);n&&n!==e||a.has(t)||(o.isFamilyDefault=!0,a.add(t))}return o})}let ne=null,re=null,se=null,ie=null,le=null;function ae(e){return{inferenceProvider:"gateway",inferenceCredentialKind:"static",inferenceGatewayBaseUrl:(e.baseUrl||"").trim().replace(/\/+$/,""),inferenceGatewayApiKey:e.apiKey,inferenceModels:buildInferenceModels(e.models,e.catalog),disableDeploymentModeChooser:!1!==e.settings?.hide_official_login,chatTabEnabled:!0,chatAdvancedFileAnalysisEnabled:!0,autoModeEnabled:!0,coworkEgressAllowedHosts:["*"],disableEssentialTelemetry:!0,disableNonessentialTelemetry:!0,disableNonessentialServices:!1}}const ce={defaultModelEffort:"medium",modelPrefer1mContext:!0,skipWebFetchPreflight:!0,toolSearchEnabled:!0,builtinBrowserEnabled:!0,isDesktopExtensionEnabled:!0,sshHostAllowlist:["*"],claudeAiImport:{enabled:!0,automatic3pImport:!0,exportEnabled:!0},coworkVmIpv6Enabled:!0,mcpToolTimeoutSec:3600,updateViaUpdatesHost:!0,banner:{enabled:!1}},de=()=>{if(_("TEST_HOME")?.trim())return null;const e=g();return e?r(e):null};let pe=de,ue=null;export function setDesktopAsarForTests(e){pe=void 0===e?de:()=>e,ue=null}function fe(){if(ue)return ue;let e=null;try{e=pe()}catch(e){u.logError("claude-desktop.unsupportedDefaults",e)}return ue=new Set(e?Object.keys(ce).filter(t=>!e.includes(t)):[]),ue}function me(e){const t=fe();return Object.fromEntries(Object.entries(ce).filter(([o])=>!e(o)&&!t.has(o)))}function ge(e){const t={...me(t=>t in e),...e};for(const e of fe())e in t&&JSON.stringify(t[e])===JSON.stringify(ce[e])&&delete t[e];return t}const ye="SOFTWARE\\Policies\\Claude",he=`HKCU\\${ye}`,ke="HKLM\\SOFTWARE\\Policies\\Claude",_e=`${b}-claude-policy.reg`,be=e=>c("reg",e,{stdio:["ignore","pipe","pipe"]}).toString();let De=be;export function setRegRunnerForTests(e){De=e??be}function we(){return"win32"===process.platform}function Ae(e){let t;try{t=De(["query",e])}catch{return null}const o=new Map;for(const e of t.split(/\r?\n/)){const t=/^\s{2,}(\S+)\s+(REG_[A-Z_]+)\s*(.*)$/.exec(e);t&&o.set(t[1],t[3])}return o}function Ce(){if(null===Ae(he))return;const e=l(claudeDesktopUserDataDir(),_e);try{t(i(e))||o(i(e),{recursive:!0,mode:448}),D(e),De(["export",he,e,"/y"])}catch(e){u.logError("claude-desktop.snapshotPolicy",e)}}function Ee(e){Ce();for(const[t,o]of Object.entries(e)){const[e,n]="boolean"==typeof o?["REG_DWORD",o?"1":"0"]:"number"==typeof o?["REG_DWORD",String(o)]:"string"==typeof o?["REG_SZ",o]:["REG_SZ",JSON.stringify(o)];De(["add",he,"/v",t,"/t",e,"/d",n,"/f"])}}function ve(e){const t=Ae(he);if(!t)return;Ce();let o=t.size;for(const n of e)t.has(n)&&(De(["delete",he,"/v",n,"/f"]),o-=1);o<=0&&De(["delete",he,"/f"])}function Me(){const e=!Boolean(_("TEST_HOME")?.trim())&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:l(A(),"AppData","Local");return!!t(l(e,"AnthropicClaude"))||x.some(o=>t(l(e,"Packages",o,"LocalCache","Local","Claude-3p")))}const Oe=[...Object.keys(ae({apiKey:"",baseUrl:"",models:{haiku:"",sonnet:"",opus:"",reasoning:""}})),...Object.keys(ce)];export function detectManagedConfig(){try{if("darwin"===process.platform){let e="";try{e=d().username}catch{}return[e?`/Library/Managed Preferences/${e}/com.anthropic.claudefordesktop.plist`:"","/Library/Managed Preferences/com.anthropic.claudefordesktop.plist"].filter(Boolean).find(e=>t(e))??null}if("win32"===process.platform)return Ae(ke)?ke:null;const e="/etc/claude-desktop/managed-settings.json";return t(e)?e:null}catch(e){return u.logError("claude-desktop.detectManagedConfig",e),null}}function Se(){const e=A();let o;switch(process.platform){case"darwin":o=["/Applications/Claude.app",l(e,"Applications","Claude.app")];break;case"win32":{const t=process.env.LOCALAPPDATA||l(e,"AppData","Local");o=[l(t,"AnthropicClaude"),l(t,"Programs","Claude"),...x.map(e=>l(t,"Packages",e))];break}default:o=["/usr/lib/claude-desktop","/opt/Claude","/usr/bin/claude-desktop",l(e,".local","bin","claude-desktop")]}return o.push(claudeDesktopUserDataDir(),l(claudeDesktopUserDataDir(),"..","Claude")),o.some(e=>t(e))}const xe=/\d+\.\d+\.\d+/;function Pe(e){const t=e=>e.split(".").map(Number);return e.sort((e,o)=>{const[n,r]=[t(e),t(o)];for(let e=0;e<3;e++)if(n[e]!==r[e])return r[e]-n[e];return 0})[0]??null}function je(){if("darwin"===process.platform){for(const e of["/Applications/Claude.app",l(A(),"Applications","Claude.app")]){const o=l(e,"Contents","Info.plist");if(!t(o))continue;const n=/<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/.exec(r(o,"utf-8")),s=n?xe.exec(n[1])?.[0]:void 0;if(s)return s}return null}if("win32"===process.platform){const e=l(process.env.LOCALAPPDATA||l(A(),"AppData","Local"),"AnthropicClaude");if(t(e)){const t=n(e).map(e=>/^app-(\d+\.\d+\.\d+)$/.exec(e)?.[1]).filter(e=>!!e);if(t.length>0)return Pe(t)}const o=x.map(e=>`'${e}'`).join(",");return Pe(c("powershell.exe",["-NoProfile","-Command",`Get-AppxPackage | Where-Object { @(${o}) -contains $_.PackageFamilyName } | ForEach-Object { $_.Version.ToString() }`],{encoding:"utf-8",timeout:15e3,windowsHide:!0,stdio:["ignore","pipe","ignore"],env:F()}).split(/\r?\n/).flatMap(e=>xe.exec(e)?.[0]??[]))}if("linux"===process.platform)try{const e=c("dpkg-query",["-W","-f=${Version}","claude-desktop"],{encoding:"utf-8",timeout:5e3,stdio:["ignore","pipe","ignore"]});return xe.exec(e)?.[0]??null}catch{return null}return null}const Ie="darwin"===process.platform?"open -a Claude":"win32"===process.platform?"Claude":"claude-desktop",Le="darwin"!==process.platform&&"win32"!==process.platform||!k().installMirror?.claudeDesktop?"https://claude.ai/download":k().installMirror.claudeDesktop,Te="darwin"===process.platform?`open ${Le}`:"win32"===process.platform?`start ${Le}`:`xdg-open ${Le}`;export const claudeDesktopAdapter={name:"claude-desktop",displayName:"Claude Desktop",command:Ie,installCommand:Te,configPath:W(),sessions:{format:K,files:()=>U(l(claudeDesktopUserDataDir(),"local-agent-mode-sessions"))},isInstalled:Se,installedVersion:je,prepareRuntime:async function(){if(!["win32","darwin","linux"].includes(process.platform)||!Se())return[];const e=Date.now();try{const t=await m({userDataDir:claudeDesktopUserDataDir(),onDownload:e=>console.log(p.gray(" "+y.t("tools.claude_desktop.code_cli_downloading",{version:e}))),desktopVersion:"darwin"===process.platform?je():null,mirrorRepo:k().installMirror?.claudeDesktop?.replace(/\/-\/releases\/latest\/?$/,"")??null});return f("desktop-code-cli","skipped"===t.status?"skip":"ok",{duration_ms:Date.now()-e,detail:{...t}}),"installed"!==t.status?[]:[{kind:"summary",text:y.t("tools.claude_desktop.code_cli_installed",{version:t.version})}]}catch(t){return u.logError("claude-desktop.prepareCodeTabCli",t),f("desktop-code-cli","fail",{duration_ms:Date.now()-e,error:t}),[{kind:"action",text:y.t("tools.claude_desktop.code_cli_failed",{reason:t instanceof Error?t.message:String(t)})}]}},runningApp:C()?{isRunning:v,restart:S,quit:O,quitRefused:E,launch:M}:void 0,appInstaller:{vendor:"Anthropic",sizeMb:()=>300,downloadPage:"https://claude.ai/download",blocker:P,latestVersion:()=>j(),installedPath(){if("darwin"===process.platform)return I();if("win32"!==process.platform)return null;try{return je()?"MSIX":null}catch(e){return u.logError("claude-desktop.installedPath",e),null}},install:e=>L(e)},wantsModelCatalog:!0,loadPrivateConfig(e){const t=Y()??{appliedId:"",entries:[]};let o=Q(t);o||(o={id:a(),name:H},t.entries.push(o));const n=ae(e);re=!0===n.disableDeploymentModeChooser,ne={models:n.inferenceModels,source:e.catalog?e.catalog.oneMillionSource:"slots",groups:e.catalog?.matchedGroups??[]};const r=X(z(o.id))??{};Z(z(o.id),{...ge(r),...n}),t.appliedId=o.id,Z(W(),t);const s=X(q())??{};if("3p"!==s.deploymentMode&&Z(q(),{...s,deploymentMode:"3p"}),ie=null,le=null,se=null,we()){const t=Ae(he),o=Oe.filter(e=>t?.has(e)),r={...me(e=>t?.has(e)??!1),...n},s=!0===e.settings?.force_registry,i=!s&&Me();try{i?ve(Oe):Ee(r),se=i?"removed":"written"}catch(e){u.logError("claude-desktop.policy",e),ie=e instanceof Error?e.message.trim():String(e),(o.length>0||s)&&(le=i?{action:"remove",values:Object.fromEntries(o.map(e=>[e,null])),deleteKey:o.length===t.size}:{action:"write",values:r,deleteKey:!1})}}},pendingElevation(){const e=le;return e?{prompt:y.t(`tools.claude_desktop.elevate_${e.action}`),run:()=>{if(!T(ye,e.values,e.deleteKey))return!1;const t=Ae(he),o="remove"===e.action?Object.keys(e.values).every(e=>!t?.has(e)):Object.keys(e.values).every(e=>t?.has(e));return o&&(le=null,ie=null),o}}:null},unloadPrivateConfig(){if(we())try{ve(Oe)}catch(e){u.logError("claude-desktop.removePolicy",e)}const e=Y(),t=Q(e);if(!e||!t)return;D(z(t.id)),s(z(t.id),{force:!0});const o=e.entries.filter(e=>e.id!==t.id);0===o.length?(D(W()),s(W(),{force:!0})):Z(W(),{...e,entries:o,appliedId:e.appliedId===t.id?o[0].id:e.appliedId})},listedModels(){const e=Y(),t=Q(e);if(!t||e?.appliedId!==t.id)return null;const o=X(z(t.id))?.inferenceModels;return Array.isArray(o)?o.map(e=>String(e.name)):null},refreshModelMenu(e){const t=Y(),o=Q(t);if(!o||t?.appliedId!==o.id)return;const n=X(z(o.id));if(!n)return;const r=buildInferenceModels(e.models,e.catalog),s=JSON.stringify(n.inferenceModels)!==JSON.stringify(r),i={...ge(n),inferenceModels:r},l=JSON.stringify(i)!==JSON.stringify(n);le=null;const a=we()?Ae(he):null;if(!a?.has("inferenceModels"))return void(l&&Z(z(o.id),i));const c=Oe.filter(e=>a.has(e)),d=!0!==e.settings?.force_registry&&Me();if(l&&Z(z(o.id),i),d||s)try{d?ve(Oe):Ee({inferenceModels:r})}catch(e){throw u.logError("claude-desktop.refreshModelMenu registry",e),le=d?{action:"remove",values:Object.fromEntries(c.map(e=>[e,null])),deleteKey:c.length===a.size}:{action:"write",values:{inferenceModels:r},deleteKey:!1},new $(y.t("tools.claude_desktop.refresh_needs_admin"))}},detectCurrentConfig(){try{if(we()){const e=Ae(he)?.get("inferenceGatewayApiKey");if(e)return{apiKey:e}}const e=Q(Y());if(!e)return{apiKey:null};const t=X(z(e.id)),o=t?.inferenceGatewayApiKey;return{apiKey:"string"==typeof o&&o?o:null}}catch(e){return u.logError("claude-desktop.detectCurrentConfig",e),{apiKey:null}}},getConfig(){try{const e=Y(),t=Q(e);return{meta:e,applied:t?X(z(t.id)):null,desktop:X(q()),...we()?{policy:Object.fromEntries(Ae(he)??[])}:{}}}catch(e){return u.logError("claude-desktop.getConfig",e),null}},clearPinnedModels(){let e=!1;we()&&Ae(he)?.has("inferenceModels")&&(Ce(),De(["delete",he,"/v","inferenceModels","/f"]),e=!0);const t=Q(Y()),o=t?X(z(t.id)):null;if(t&&o&&void 0!==o.inferenceModels){const{inferenceModels:n,...r}=o;Z(z(t.id),r),e=!0}return e?["inferenceModels"]:[]},applyNotes(){const e=[];if(ne&&ne.models.length>0){const{models:t,source:o,groups:n}=ne;e.push({kind:"summary",text:y.t("tools.claude_desktop.models_summary",{count:String(t.length),default:t[0].labelOverride??t[0].name})}),e.push({kind:"detail",text:y.t(`tools.claude_desktop.models_written_${o}`,{count:String(t.length),list:t.map(e=>`${e.labelOverride}${e.supports1m?" (1M)":""}`).join(", "),groups:n.join(" / ")})})}null!==re&&e.push({kind:"detail",text:y.t(re?"tools.claude_desktop.official_login_hidden":"tools.claude_desktop.official_login_shown")}),C()&&!v()||e.push({kind:"action",text:y.t("tools.claude_desktop.restart_hint")}),le?(e.push({kind:"action",text:y.t(`tools.claude_desktop.policy_stale_${le.action}`)}),e.push({kind:"detail",text:ie??""})):ie?(e.push({kind:"detail",text:y.t("tools.claude_desktop.registry_denied")}),e.push({kind:"detail",text:ie})):we()&&se&&e.push({kind:"detail",text:y.t(`tools.claude_desktop.registry_${se}`,{key:he})});const t=detectManagedConfig();return t&&e.push({kind:"action",text:y.t("tools.claude_desktop.managed_conflict",{path:t})}),e},forceResetPaths(){const e=[W(),q()];try{const t=Q(Y());t&&e.push(z(t.id))}catch{}return e},backupPaths(){const e=[W(),q()];we()&&e.push(l(claudeDesktopUserDataDir(),_e));try{const t=Q(Y());t&&e.push(z(t.id))}catch{}return e}};
1
+ import{chmodSync as e,existsSync as t,mkdirSync as o,readdirSync as n,readFileSync as r,rmSync as s}from"fs";import{dirname as i}from"path";import{join as l}from"path";import{randomUUID as a}from"crypto";import{execFileSync as c}from"child_process";import{userInfo as d}from"os";import u from"chalk";import{logger as p}from"../../utils/logger.js";import{track as f}from"../telemetry.js";import{ensureDesktopCli as m,installedDesktopAsarPath as g}from"./claude-desktop-cli.js";import{i18n as y}from"../i18n.js";import{BRAND_NAME as h,brand as k,brandEnv as _,CLI_NAME as w}from"../brand.js";import{backupBeforeWrite as b,atomicWriteFile as D}from"./backup.js";import{toolHome as A}from"./types.js";import{canRestartDesktop as C,desktopQuitRefused as v,isDesktopRunning as E,launchDesktop as M,quitDesktop as O,restartDesktop as S,WINDOWS_PACKAGE_FAMILIES as x}from"./desktop-process.js";import{desktopInstallBlocker as j,fetchLatestDesktopVersion as P,installedMacApp as I,installLatestDesktop as L}from"./claude-desktop-app.js";import{setUserRegistryElevated as T}from"./elevated-reg.js";import{UserActionNeeded as $}from"./types.js";import{savedApiKeys as G}from"../config.js";import{isOurGatewayUrl as N,noteWrittenGatewayUrl as U}from"../gateway-addresses.js";import{baseModelId as R,isClaudeModel as K}from"../model-catalog.js";import{getDefaultModels as F}from"../model-registry.js";import{claudeFormat as B,nestedClaudeProjectFiles as H}from"../sessions/formats.js";import{powerShellEnv as J}from"../powershell-env.js";const V=h;export const CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING="hide_official_login";export const CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING="force_registry";const W=/^[a-f0-9-]{36}$/;function z(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}export function claudeDesktopUserDataDir(){const e=process.env.CLAUDE_USER_DATA_DIR?.trim();if(e)return e;const o=A(),n=Boolean(_("TEST_HOME")?.trim());switch(process.platform){case"darwin":return l(o,"Library","Application Support","Claude-3p");case"win32":{const e=!n&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:l(o,"AppData","Local");return x.map(t=>l(e,"Packages",t,"LocalCache","Local","Claude-3p")).find(e=>t(e))??l(e,"Claude-3p")}default:{const e=!n&&process.env.XDG_CONFIG_HOME?process.env.XDG_CONFIG_HOME:l(o,".config");return l(e,"Claude-3p")}}}const q=()=>l(claudeDesktopUserDataDir(),"configLibrary"),X=()=>l(q(),"_meta.json"),Z=e=>l(q(),`${e}.json`),Y=()=>l(claudeDesktopUserDataDir(),"claude_desktop_config.json");function Q(e){if(!t(e))return null;const o=r(e,"utf-8");if(!o.trim())return null;try{const e=JSON.parse(o);return z(e)?e:null}catch(t){throw new Error(`Existing ${e} cannot be parsed; back it up and fix it first: ${t instanceof Error?t.message:String(t)}`)}}function ee(n,r){const s=i(n);t(s)||o(s,{recursive:!0,mode:448}),b(n),D(n,JSON.stringify(r,null,2)+"\n");try{e(n,384)}catch(e){p.logError("claude-desktop.writeJson.chmod",e)}}function te(){const e=Q(X());if(!e)return null;const t=Array.isArray(e.entries)?e.entries.filter(e=>z(e)&&"string"==typeof e.id&&"string"==typeof e.name):[];return{...e,appliedId:"string"==typeof e.appliedId?e.appliedId:"",entries:t}}function oe(e){return e?.entries.find(e=>e.name===V&&W.test(e.id))}const ne={opus:0,fable:1,sonnet:2,haiku:3};function re(e){let t=/^claude-(opus|sonnet|haiku|fable)-(\d+(?:-\d+)*)/i.exec(e);return t?{family:t[1].toLowerCase(),version:t[2].split("-").map(Number)}:(t=/^claude-(\d+(?:-\d+)*)-(opus|sonnet|haiku)/i.exec(e),t?{family:t[2].toLowerCase(),version:t[1].split("-").map(Number)}:null)}export function humanizeModelId(e){const t=re(e);return t?`${t.family[0].toUpperCase()+t.family.slice(1)} ${t.version.filter(e=>e<1e7).slice(0,2).join(".")}`:e}function se(e){return re(e)?.family}export function buildInferenceModels(e,t){const{primary:o,bySlot:n}=function(e){const t=["opus","sonnet","haiku","reasoning"].map(t=>R(e[t]||"")).filter(Boolean);return{primary:t[0]??"",bySlot:t}}(e),r=new Set,s=t?.labels??{};let i;if(t&&t.models.some(K)){i=[...new Set(t.models.filter(K).map(R))];for(const e of t.oneMillion)r.add(e)}else{i=[];for(const t of["opus","sonnet","haiku","reasoning"]){const o=(e[t]||"").trim(),n=R(o);n&&(i.includes(n)||i.push(n),/\[1m\]/i.test(o)&&r.add(n))}}const l=e=>ne[se(e)??""]??9;i.sort((e,t)=>{if(e===o)return-1;if(t===o)return 1;const n=l(e)-l(t);if(0!==n)return n;const r=re(e),s=re(t);return r&&s?function(e,t){const o=Math.max(e.length,t.length);for(let n=0;n<o;n++){const o=(t[n]??0)-(e[n]??0);if(0!==o)return o}return 0}(r.version,s.version):e.localeCompare(t)});const a=new Set,c=new Map,d=new Set(Object.values(F()).map(e=>R(e||"")));for(const e of n){const t=se(e);t&&i.includes(e)&&!d.has(e)&&!c.has(t)&&c.set(t,e)}return i.map(e=>{const t=se(e),o={name:e,labelOverride:s[e]||humanizeModelId(e)};if(r.has(e)&&(o.supports1m=!0,o.prefer1m=!0),t){o.anthropicFamilyTier=t;const n=c.get(t);n&&n!==e||a.has(t)||(o.isFamilyDefault=!0,a.add(t))}return o})}let ie=null,le=null,ae=null,ce=null,de=null;function ue(e){return{inferenceProvider:"gateway",inferenceCredentialKind:"static",inferenceGatewayBaseUrl:(e.baseUrl||"").trim().replace(/\/+$/,""),inferenceGatewayApiKey:e.apiKey,inferenceModels:buildInferenceModels(e.models,e.catalog),disableDeploymentModeChooser:!1!==e.settings?.hide_official_login,chatTabEnabled:!0,chatAdvancedFileAnalysisEnabled:!0,autoModeEnabled:!0,coworkEgressAllowedHosts:["*"],disableEssentialTelemetry:!0,disableNonessentialTelemetry:!0,disableNonessentialServices:!1}}const pe={defaultModelEffort:"medium",modelPrefer1mContext:!0,skipWebFetchPreflight:!0,toolSearchEnabled:!0,builtinBrowserEnabled:!0,isDesktopExtensionEnabled:!0,sshHostAllowlist:["*"],claudeAiImport:{enabled:!0,automatic3pImport:!0,exportEnabled:!0},coworkVmIpv6Enabled:!0,mcpToolTimeoutSec:3600,updateViaUpdatesHost:!0,banner:{enabled:!1}},fe=()=>{if(_("TEST_HOME")?.trim())return null;const e=g();return e?r(e):null};let me=fe,ge=null;export function setDesktopAsarForTests(e){me=void 0===e?fe:()=>e,ge=null}function ye(){if(ge)return ge;let e=null;try{e=me()}catch(e){p.logError("claude-desktop.unsupportedDefaults",e)}return ge=new Set(e?Object.keys(pe).filter(t=>!e.includes(t)):[]),ge}function he(e){const t=ye();return Object.fromEntries(Object.entries(pe).filter(([o])=>!e(o)&&!t.has(o)))}function ke(e){const t={...he(t=>t in e),...e};for(const e of ye())e in t&&JSON.stringify(t[e])===JSON.stringify(pe[e])&&delete t[e];return t}const _e="SOFTWARE\\Policies\\Claude",we=`HKCU\\${_e}`,be="HKLM\\SOFTWARE\\Policies\\Claude",De=`${w}-claude-policy.reg`,Ae=e=>c("reg",e,{stdio:["ignore","pipe","pipe"]}).toString();let Ce=Ae;export function setRegRunnerForTests(e){Ce=e??Ae}function ve(){return"win32"===process.platform}function Ee(e){let t;try{t=Ce(["query",e])}catch{return null}const o=new Map;for(const e of t.split(/\r?\n/)){const t=/^\s{2,}(\S+)\s+(REG_[A-Z_]+)\s*(.*)$/.exec(e);t&&o.set(t[1],t[3])}return o}function Me(){if(null===Ee(we))return;const e=l(claudeDesktopUserDataDir(),De);try{t(i(e))||o(i(e),{recursive:!0,mode:448}),b(e),Ce(["export",we,e,"/y"])}catch(e){p.logError("claude-desktop.snapshotPolicy",e)}}function Oe(e){Me();for(const[t,o]of Object.entries(e)){const[e,n]="boolean"==typeof o?["REG_DWORD",o?"1":"0"]:"number"==typeof o?["REG_DWORD",String(o)]:"string"==typeof o?["REG_SZ",o]:["REG_SZ",JSON.stringify(o)];Ce(["add",we,"/v",t,"/t",e,"/d",n,"/f"])}}function Se(e){const t=Ee(we);if(!t)return;Me();let o=t.size;for(const n of e)t.has(n)&&(Ce(["delete",we,"/v",n,"/f"]),o-=1);o<=0&&Ce(["delete",we,"/f"])}function xe(){const e=!Boolean(_("TEST_HOME")?.trim())&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:l(A(),"AppData","Local");return!!t(l(e,"AnthropicClaude"))||x.some(o=>t(l(e,"Packages",o,"LocalCache","Local","Claude-3p")))}const je=[...Object.keys(ue({apiKey:"",baseUrl:"",models:{haiku:"",sonnet:"",opus:"",reasoning:""}})),...Object.keys(pe)];function Pe(e){if(!e||!je.some(t=>e.has(t)))return"none";const t=e.get("inferenceGatewayApiKey")?.trim();return N(e.get("inferenceGatewayBaseUrl"))||t&&G().includes(t)?"ours":"foreign"}function Ie(){const e=Q(Y())?.deploymentMode;if(void 0!==e&&"3p"!==e)return{kind:"mode"};const t=te(),o=t?.entries.find(e=>e.id===t.appliedId);if(!o||o.id===oe(t)?.id)return null;const n=Q(Z(o.id));return n&&(n.inferenceProvider||n.inferenceGatewayBaseUrl)?{kind:"entry",name:o.name}:null}function Le(e){return"mode"===e.kind?y.t("tools.claude_desktop.current_official"):y.t("tools.claude_desktop.current_entry",{name:e.name})}let Te=null,$e=null;export function detectManagedConfig(){try{if("darwin"===process.platform){let e="";try{e=d().username}catch{}return[e?`/Library/Managed Preferences/${e}/com.anthropic.claudefordesktop.plist`:"","/Library/Managed Preferences/com.anthropic.claudefordesktop.plist"].filter(Boolean).find(e=>t(e))??null}if("win32"===process.platform)return Ee(be)?be:null;const e="/etc/claude-desktop/managed-settings.json";return t(e)?e:null}catch(e){return p.logError("claude-desktop.detectManagedConfig",e),null}}function Ge(){const e=A();let o;switch(process.platform){case"darwin":o=["/Applications/Claude.app",l(e,"Applications","Claude.app")];break;case"win32":{const t=process.env.LOCALAPPDATA||l(e,"AppData","Local");o=[l(t,"AnthropicClaude"),l(t,"Programs","Claude"),...x.map(e=>l(t,"Packages",e))];break}default:o=["/usr/lib/claude-desktop","/opt/Claude","/usr/bin/claude-desktop",l(e,".local","bin","claude-desktop")]}return o.push(claudeDesktopUserDataDir(),l(claudeDesktopUserDataDir(),"..","Claude")),o.some(e=>t(e))}const Ne=/\d+\.\d+\.\d+/;function Ue(e){const t=e=>e.split(".").map(Number);return e.sort((e,o)=>{const[n,r]=[t(e),t(o)];for(let e=0;e<3;e++)if(n[e]!==r[e])return r[e]-n[e];return 0})[0]??null}function Re(){if("darwin"===process.platform){for(const e of["/Applications/Claude.app",l(A(),"Applications","Claude.app")]){const o=l(e,"Contents","Info.plist");if(!t(o))continue;const n=/<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/.exec(r(o,"utf-8")),s=n?Ne.exec(n[1])?.[0]:void 0;if(s)return s}return null}if("win32"===process.platform){const e=l(process.env.LOCALAPPDATA||l(A(),"AppData","Local"),"AnthropicClaude");if(t(e)){const t=n(e).map(e=>/^app-(\d+\.\d+\.\d+)$/.exec(e)?.[1]).filter(e=>!!e);if(t.length>0)return Ue(t)}const o=x.map(e=>`'${e}'`).join(",");return Ue(c("powershell.exe",["-NoProfile","-Command",`Get-AppxPackage | Where-Object { @(${o}) -contains $_.PackageFamilyName } | ForEach-Object { $_.Version.ToString() }`],{encoding:"utf-8",timeout:15e3,windowsHide:!0,stdio:["ignore","pipe","ignore"],env:J()}).split(/\r?\n/).flatMap(e=>Ne.exec(e)?.[0]??[]))}if("linux"===process.platform)try{const e=c("dpkg-query",["-W","-f=${Version}","claude-desktop"],{encoding:"utf-8",timeout:5e3,stdio:["ignore","pipe","ignore"]});return Ne.exec(e)?.[0]??null}catch{return null}return null}const Ke="darwin"===process.platform?"open -a Claude":"win32"===process.platform?"Claude":"claude-desktop",Fe="darwin"!==process.platform&&"win32"!==process.platform||!k().installMirror?.claudeDesktop?"https://claude.ai/download":k().installMirror.claudeDesktop,Be="darwin"===process.platform?`open ${Fe}`:"win32"===process.platform?`start ${Fe}`:`xdg-open ${Fe}`;export const claudeDesktopAdapter={name:"claude-desktop",displayName:"Claude Desktop",command:Ke,installCommand:Be,configPath:X(),sessions:{format:B,files:()=>H(l(claudeDesktopUserDataDir(),"local-agent-mode-sessions"))},isInstalled:Ge,installedVersion:Re,prepareRuntime:async function(){if(!["win32","darwin","linux"].includes(process.platform)||!Ge())return[];const e=Date.now();try{const t=await m({userDataDir:claudeDesktopUserDataDir(),onDownload:e=>console.log(u.gray(" "+y.t("tools.claude_desktop.code_cli_downloading",{version:e}))),desktopVersion:"darwin"===process.platform?Re():null,mirrorRepo:k().installMirror?.claudeDesktop?.replace(/\/-\/releases\/latest\/?$/,"")??null});return f("desktop-code-cli","skipped"===t.status?"skip":"ok",{duration_ms:Date.now()-e,detail:{...t}}),"installed"!==t.status?[]:[{kind:"summary",text:y.t("tools.claude_desktop.code_cli_installed",{version:t.version})}]}catch(t){return p.logError("claude-desktop.prepareCodeTabCli",t),f("desktop-code-cli","fail",{duration_ms:Date.now()-e,error:t}),[{kind:"action",text:y.t("tools.claude_desktop.code_cli_failed",{reason:t instanceof Error?t.message:String(t)})}]}},runningApp:C()?{isRunning:E,restart:S,quit:O,quitRefused:v,launch:M}:void 0,appInstaller:{vendor:"Anthropic",sizeMb:()=>300,downloadPage:"https://claude.ai/download",blocker:j,latestVersion:()=>P(),installedPath(){if("darwin"===process.platform)return I();if("win32"!==process.platform)return null;try{return Re()?"MSIX":null}catch(e){return p.logError("claude-desktop.installedPath",e),null}},install:e=>L(e)},wantsModelCatalog:!0,loadPrivateConfig(e){const t=te()??{appliedId:"",entries:[]};let o=oe(t);o||(o={id:a(),name:V},t.entries.push(o));const n=ue(e);U(String(n.inferenceGatewayBaseUrl)),le=!0===n.disableDeploymentModeChooser,ie={models:n.inferenceModels,source:e.catalog?e.catalog.oneMillionSource:"slots",groups:e.catalog?.matchedGroups??[]};const r=Q(Z(o.id))??{};ee(Z(o.id),{...ke(r),...n});const s=Ie();Te=s&&!e.takeOver?Le(s):null,Te||(t.appliedId=o.id),ee(X(),t);const i=Q(Y())??{};Te||"3p"===i.deploymentMode||ee(Y(),{...i,deploymentMode:"3p"}),ce=null,de=null,ae=null,$e=null;const l=!0===e.settings?.force_registry,c=ve()?Ee(we):null;if(ve()&&"foreign"===Pe(c)&&!l)$e=c?.get("inferenceGatewayBaseUrl")||we;else if(ve()){const t=Ee(we),o=je.filter(e=>t?.has(e)),r={...he(e=>t?.has(e)??!1),...n},s=!0===e.settings?.force_registry,i=!s&&xe();try{i?Se(je):Oe(r),ae=i?"removed":"written"}catch(e){p.logError("claude-desktop.policy",e),ce=e instanceof Error?e.message.trim():String(e),(o.length>0||s)&&(de=i?{action:"remove",values:Object.fromEntries(o.map(e=>[e,null])),deleteKey:o.length===t.size}:{action:"write",values:r,deleteKey:!1})}}},pendingElevation(){const e=de;return e?{prompt:y.t(`tools.claude_desktop.elevate_${e.action}`),run:()=>{if(!T(_e,e.values,e.deleteKey))return!1;const t=Ee(we),o="remove"===e.action?Object.keys(e.values).every(e=>!t?.has(e)):Object.keys(e.values).every(e=>t?.has(e));return o&&(de=null,ce=null),o}}:null},unloadPrivateConfig(){if(ve()&&"ours"===Pe(Ee(we)))try{Se(je)}catch(e){p.logError("claude-desktop.removePolicy",e)}const e=te(),t=oe(e);if(!e||!t)return;b(Z(t.id)),s(Z(t.id),{force:!0});const o=e.entries.filter(e=>e.id!==t.id);0===o.length?(b(X()),s(X(),{force:!0})):ee(X(),{...e,entries:o,appliedId:e.appliedId===t.id?o[0].id:e.appliedId})},listedModels(){const e=te(),t=oe(e);if(!t||e?.appliedId!==t.id)return null;const o=Q(Z(t.id))?.inferenceModels;return Array.isArray(o)?o.map(e=>String(e.name)):null},refreshModelMenu(e){const t=te(),o=oe(t);if(!o||t?.appliedId!==o.id)return;const n=Q(Z(o.id));if(!n)return;const r=buildInferenceModels(e.models,e.catalog),s=JSON.stringify(n.inferenceModels)!==JSON.stringify(r),i={...ke(n),inferenceModels:r},l=JSON.stringify(i)!==JSON.stringify(n);de=null;const a=ve()?Ee(we):null,c="foreign"===Pe(a)&&!0!==e.settings?.force_registry;if(!a?.has("inferenceModels")||c)return void(l&&ee(Z(o.id),i));const d=je.filter(e=>a.has(e)),u=!0!==e.settings?.force_registry&&xe();if(l&&ee(Z(o.id),i),u||s)try{u?Se(je):Oe({inferenceModels:r})}catch(e){throw p.logError("claude-desktop.refreshModelMenu registry",e),de=u?{action:"remove",values:Object.fromEntries(d.map(e=>[e,null])),deleteKey:d.length===a.size}:{action:"write",values:{inferenceModels:r},deleteKey:!1},new $(y.t("tools.claude_desktop.refresh_needs_admin"))}},detectCurrentConfig(){try{if(ve()){const e=Ee(we)?.get("inferenceGatewayApiKey");if(e)return{apiKey:e}}const e=oe(te());if(!e)return{apiKey:null};const t=Q(Z(e.id)),o=t?.inferenceGatewayApiKey;return{apiKey:"string"==typeof o&&o?o:null}}catch(e){return p.logError("claude-desktop.detectCurrentConfig",e),{apiKey:null}}},getConfig(){try{const e=te(),t=oe(e);return{meta:e,applied:t?Q(Z(t.id)):null,desktop:Q(Y()),...ve()?{policy:Object.fromEntries(Ee(we)??[])}:{}}}catch(e){return p.logError("claude-desktop.getConfig",e),null}},clearPinnedModels(){let e=!1;ve()&&Ee(we)?.has("inferenceModels")&&(Me(),Ce(["delete",we,"/v","inferenceModels","/f"]),e=!0);const t=oe(te()),o=t?Q(Z(t.id)):null;if(t&&o&&void 0!==o.inferenceModels){const{inferenceModels:n,...r}=o;ee(Z(t.id),r),e=!0}return e?["inferenceModels"]:[]},applyNotes(){const e=[];if(ie&&ie.models.length>0){const{models:t,source:o,groups:n}=ie;e.push({kind:"summary",text:y.t("tools.claude_desktop.models_summary",{count:String(t.length),default:t[0].labelOverride??t[0].name})}),e.push({kind:"detail",text:y.t(`tools.claude_desktop.models_written_${o}`,{count:String(t.length),list:t.map(e=>`${e.labelOverride}${e.supports1m?" (1M)":""}`).join(", "),groups:n.join(" / ")})})}null!==le&&e.push({kind:"detail",text:y.t(le?"tools.claude_desktop.official_login_hidden":"tools.claude_desktop.official_login_shown")}),C()&&!E()||e.push({kind:"action",text:y.t("tools.claude_desktop.restart_hint")}),de?(e.push({kind:"action",text:y.t(`tools.claude_desktop.policy_stale_${de.action}`)}),e.push({kind:"detail",text:ce??""})):ce?(e.push({kind:"detail",text:y.t("tools.claude_desktop.registry_denied")}),e.push({kind:"detail",text:ce})):ve()&&ae&&e.push({kind:"detail",text:y.t(`tools.claude_desktop.registry_${ae}`,{key:we})}),Te&&e.push({kind:"action",text:y.t("tools.claude_desktop.not_switched",{current:Te})}),$e&&e.push({kind:"action",text:y.t("tools.claude_desktop.foreign_policy",{key:we,url:$e})});const t=detectManagedConfig();return t&&e.push({kind:"action",text:y.t("tools.claude_desktop.managed_conflict",{path:t})}),e},planNotes(){const e=[],t=Ie();if(t&&e.push(y.t("tools.claude_desktop.plan_switch",{current:Le(t)})),ve()){const t=Ee(we);"foreign"===Pe(t)&&e.push(y.t("tools.claude_desktop.plan_foreign_policy",{key:we,url:t?.get("inferenceGatewayBaseUrl")||"-"}))}return e},forceResetPaths(){const e=[X(),Y()];try{const t=oe(te());t&&e.push(Z(t.id))}catch{}return e},backupPaths(){const e=[X(),Y()];ve()&&e.push(l(claudeDesktopUserDataDir(),De));try{const t=oe(te());t&&e.push(Z(t.id))}catch{}return e}};
@@ -1 +1 @@
1
- import{createHash as e}from"crypto";import{existsSync as t,mkdirSync as o,readdirSync as n,readFileSync as r,rmSync as i,statSync as s,writeFileSync as a}from"fs";import{join as l}from"path";import*as c from"@iarna/toml";import{logger as d}from"../../utils/logger.js";import{i18n as u}from"../i18n.js";import{backupBeforeWrite as m,atomicWriteFile as p}from"./backup.js";import{codexHome as f,pickModel as _,toolHome as g,withV1 as x}from"./types.js";import{moveSessionsToProvider as h,NO_STATE_DB as y,runningCodexPids as k}from"../codex-sessions.js";import{codexFormat as b,codexRolloutFiles as v}from"../sessions/formats.js";import{getToolDefaultModel as w}from"../model-registry.js";import{configManager as j}from"../config.js";import{maskHome as C,track as O}from"../telemetry.js";import{buildCodexCatalog as S,catalogRejections as M,codexCatalogPath as A,fillFromOlderEntries as E,installedCodexBinaries as N,loadBundledCodexModels as P,loadPreviousCodexModels as T,previousGatewayModelIds as D}from"./codex-catalog.js";import{gatewayModelSpecs as I,modelFamily as L}from"../gateway-models.js";import{findInstalls as $,mirrorInstallCommand as J,brandInstallScripts as G}from"./tool-installs.js";import{chatgptDesktopApp as R}from"./chatgpt-desktop.js";const K=()=>f(),X=()=>l(K(),"config.toml"),B="sessions_move_declined",U=["browser_use","browser_use_external","computer_use"];function W(e){const t=e.features;if(!V(t)||!U.every(e=>!1===t[e]))return!1;for(const e of U)delete t[e];return!0}export function codexWorkModeOn(){try{const e=ee();return e.model_provider===F&&V(e.desktop)&&"STEPS_PROSE"===e.desktop.conversationDetailMode}catch{return!1}}function q(){try{if(V(ee().desktop))return!0}catch{}if("darwin"===process.platform)return["/Applications",l(g(),"Applications")].some(e=>["ChatGPT.app","Codex.app"].some(o=>t(l(e,o))));if("win32"===process.platform){const e=l(process.env.LOCALAPPDATA||l(g(),"AppData","Local"),"Packages");try{return n(e).some(e=>/^OpenAI\.(Codex|ChatGPT)/i.test(e))}catch{return!1}}return t("/usr/lib/chatgpt/ChatGPT")}export function codexConfigPath(){return X()}const z=()=>l(K(),"auth.json"),Y="OPENAI_API_KEY",F="custom",H=1e6,Q=9e5;export const CODEX_ONE_MILLION_CONTEXT_SETTING="one_million_context";function V(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function Z(e,t){return V(e[t])||(e[t]={}),e[t]}function ee(){if(!t(X()))return{};const e=r(X(),"utf-8");if(!e.trim())return{};try{const t=c.parse(e);if(!V(t))throw new Error("config.toml root must be a TOML table");return t}catch(e){throw new Error(`Existing ~/.codex/config.toml cannot be parsed; back it up and fix it first: ${e instanceof Error?e.message:String(e)}`)}}function te(){if(!t(z()))return{};try{const e=JSON.parse(r(z(),"utf-8"));return V(e)?e:{}}catch{return{}}}let oe=null;function ne(e){const t=e.profiles;if(V(t)){for(const[e,o]of Object.entries(t))V(o)&&2===Object.keys(o).length&&o.model_provider===F&&o.model===e&&delete t[e];0===Object.keys(t).length&&delete e.profiles}}let re=null;const ie=()=>l(j.getConfigDir(),"codex-catalog-check.json");function se(e){const o=A();t(o)&&r(o,"utf-8")===e||(m(o),p(o,e))}function ae(t,n){if(0===n.length)return[];const i=function(t,o){const n=e("sha256").update(t);for(const e of o)try{const t=s(e);n.update(`\0${e}\0${t.size}\0${t.mtimeMs}`)}catch{n.update(`\0${e}`)}return n.digest("hex")}(t,n);if(function(e){try{return JSON.parse(r(ie(),"utf-8")).signature===e}catch{return!1}}(i))return[];const l=M(A(),n);return 0===l.length&&function(e){try{o(j.getConfigDir(),{recursive:!0}),a(ie(),JSON.stringify({signature:e})+"\n")}catch(e){d.logError("codexAdapter.rememberAccepted",e)}}(i),l}function le(e,t,o){const n=!1!==t.settings?.one_million_context;!function(e){e.model_context_window===H&&delete e.model_context_window,e.model_auto_compact_token_limit===Q&&delete e.model_auto_compact_token_limit}(e);const r=()=>{e.model_catalog_json===A()&&delete e.model_catalog_json,n&&(e.model_context_window=H,e.model_auto_compact_token_limit=Q)},s=P()??T();if(!s)return d.logError("codexAdapter.writeModelCatalog",new Error("no Codex binary found; model catalog skipped")),re="skipped",void r();const a=t.catalog,l=e=>S({bundled:e,specs:I("codex",a?.clientModels),...a?{keyModels:a.models}:{},gatewayAvailable:a?.models??D(),oneMillion:n,selectedModel:o,..."gateway"===a?.oneMillionSource?{claudeOneMillion:a.oneMillion}:{}}),c=e=>JSON.stringify(e,null,2)+"\n";let u=l(s);se(c(u));const m=N(),p=ae(c(u),m);if(p.length>0){const e=Date.now();let t=!1;for(const e of p){const o=P(e.bin);if(o){for(const e of[{models:E(u.models,o)},{models:E(l(o).models,o)}])if(se(c(e)),0===ae(c(e),m).length){u=e,t=!0;break}if(t)break}}if(O("codex-catalog",t?"fallback":"fail",{duration_ms:Date.now()-e,error:p[0].error,detail:{rejected_by:p.map(e=>({version:e.version,path:C(e.bin)}))}}),!t)return re={rejectedBy:p[0]},i(A(),{force:!0}),void r()}re={listed:u.models.filter(e=>"list"===e.visibility).map(e=>({id:String(e.slug),name:String(e.display_name??e.slug)}))},e.model_catalog_json=A()}export function codexCatalogRejection(){let e;try{e=ee()}catch{return null}return e.model_catalog_json===A()&&t(A())?M(A())[0]??null:null}export function setCodexOneMillionContext(e,t){const o=ee(),n=c.stringify(o),r="string"==typeof o.model?o.model:w("codex");le(o,{settings:{[CODEX_ONE_MILLION_CONTEXT_SETTING]:e},catalog:t},r);const i=c.stringify(o);i!==n&&(m(X()),p(X(),i))}const ce={command:"codex",npmPackage:"@openai/codex",native:{binDir:"win32"===process.platform?["AppData","Local","Programs","OpenAI","Codex","bin"]:[".local","bin"],updateArgs:["update"],updateTimeoutMs:12e4,dataDirs:[[".codex","packages","standalone"]]},mirrorScript:G("codex"),brew:"codex"};export const codexAdapter={name:"codex",companionApps:[R],displayName:"Codex",command:"codex",installCommand:J(ce),installSpec:ce,configPath:X(),sessions:{format:b,files:()=>[...v(l(f(),"sessions")),...v(l(f(),"archived_sessions"))],resumeCommand:e=>({command:"codex",args:["resume",e]})},wantsModelCatalog:!0,listedModels(){if(ee().model_catalog_json!==A())return null;try{return(JSON.parse(r(A(),"utf-8")).models??[]).filter(e=>"list"===e.visibility).map(e=>String(e.slug))}catch{return null}},refreshModelMenu(e){if(ee().model_catalog_json!==A())return;setCodexOneMillionContext(!1!==e.settings?.one_million_context,e.catalog);const t=ee(),o=function(e,t){const o=V(e.model_providers)?e.model_providers[F]:void 0;return!(!V(o)||o.base_url!==t||!0===o.supports_standalone_web_search||(o.supports_standalone_web_search=!0,0))}(t,x(e.baseUrl));(W(t)||o)&&(m(X()),p(X(),c.stringify(t)))},async followUp(){if(ee().model_provider!==F)return null;const e=await h(F,{dryRun:!0}),t=Math.max(e.moved.length,e.dbRows);if(0===t)return null;const o=j.getToolSettings("codex")[B];if("number"==typeof o&&t<=o)return null;const n={count:String(t)};return k().length>0?{hint:u.t("tools.codex.sessions_hidden_running",n)}:{prompt:u.t("tools.codex.sessions_offer",n),hint:u.t("tools.codex.sessions_hidden",n),async run(){const e=await h(F),t=[...new Set(e.moved.map(e=>e.from))].join("、")||"-",o=String(Math.max(e.moved.length,e.dbRows)),n=[{kind:"summary",text:u.t("codex_sessions.moved",{count:o,from:t,target:F})},{kind:"summary",text:u.t("codex_sessions.backup",{dir:e.backupDir??""})}];return e.dbSkipped&&e.dbSkipped!==y&&n.push({kind:"action",text:u.t("codex_sessions.db_skipped",{reason:e.dbSkipped})}),n},decline(){j.setToolSetting("codex",B,t)}}},applyNotes(){if("skipped"===re)return 0===$(ce).length?[]:[{kind:"action",text:u.t("tools.codex.catalog_skipped")}];if(!re)return[];if("rejectedBy"in re){const{bin:e,version:t}=re.rejectedBy;return[{kind:"action",text:u.t("tools.codex.catalog_rejected",{path:e,version:t??"?"})}]}const e=new Map;for(const t of re.listed)e.set(L(t.id),(e.get(L(t.id))??0)+1);const t=["gpt","claude","gemini","other","grok"].filter(t=>e.has(t)).map(t=>`${u.t(`tools.model_family.${t}`)} ${e.get(t)}`).join(" · ");return[{kind:"summary",text:u.t("tools.codex.catalog_written",{count:String(re.listed.length),breakdown:t})},{kind:"detail",text:re.listed.map(e=>e.name).join(", ")},...codexWorkModeOn()||q()?[{kind:"action",text:u.t(codexWorkModeOn()?"tools.codex.work_mode_on":"tools.codex.work_mode_hint")}]:[]]},loadPrivateConfig(e){const t=w("codex"),o=_(e.models,t),n=function(e){return/(?:^|\/)claude(?:-|$)/i.test(e)}(o)?t:o,r=x(e.baseUrl),i=ee();i.model=n,i.model_provider=F,i.model_reasoning_effort="high",le(i,e,n);const s=Z(i,"model_providers"),a=V(s[F])?{...s[F]}:{};delete a.env_key;const{experimental_bearer_token:l,...d}=a;s[F]={...d,name:"custom",wire_api:"responses",requires_openai_auth:!0,supports_standalone_web_search:!0,base_url:r},ne(i),Z(Z(i,"tui"),"model_availability_nux")[n]=4;const u=Z(i,"features");u.goals=!0,u.js_repl=!1,W(i),m(X()),p(X(),c.stringify(i)),function(e){const t=e.trim();if(!t)return;const o={...te(),auth_mode:"apikey",[Y]:t};m(z()),p(z(),JSON.stringify(o,null,2)+"\n",384)}(e.apiKey)},holdsOurConfig(e){const t=te()[Y];return"string"==typeof t&&e.includes(t.trim())},unloadPrivateConfig(e){if(oe=function(e){const t=te(),o="string"==typeof t[Y]?t[Y].trim():"";if(!o)return V(t.tokens)?"chatgpt":null;if(!e.includes(o))return"other_key";const{[Y]:n,auth_mode:r,...s}=t;return m(z()),V(s.tokens)?(p(z(),JSON.stringify({...s,auth_mode:"chatgpt"},null,2)+"\n",384),"chatgpt"):(i(z(),{force:!0}),"signed_out")}(e?.savedKeys??[]),!t(X()))return;let o;try{o=ee()}catch(e){return void d.logError("codexAdapter.unloadPrivateConfig",e)}const n=o.model_providers;V(n)&&(delete n[F],0===Object.keys(n).length&&delete o.model_providers),o.model_provider===F&&delete o.model_provider,o.model_catalog_json===A()&&delete o.model_catalog_json,W(o),ne(o),m(X()),p(X(),c.stringify(o))},unloadNotes(){switch(oe){case"chatgpt":return[{kind:"action",text:u.t("tools.codex.unload_chatgpt_restored")}];case"other_key":return[{kind:"action",text:u.t("tools.codex.unload_other_key")}];default:return[{kind:"action",text:u.t("tools.codex.unload_sign_in")}]}},detectCurrentConfig(){const e=te()[Y];return{apiKey:"string"==typeof e&&e.trim()?e.trim():null}},getConfig(){try{return ee()}catch(e){return d.logError("codexAdapter.getConfig",e),null}},backupPaths:()=>[X(),z(),A()]};export function codexAuthProblem(){try{const e=ee(),t=e.model_providers?.[F];if(e.model_provider!==F||!t)return null;if("string"==typeof t.experimental_bearer_token&&t.experimental_bearer_token)return"stale_bearer";const o=te();return!0===t.requires_openai_auth&&"chatgpt"===o.auth_mode?"chatgpt_login":null}catch{return null}}
1
+ import{createHash as e}from"crypto";import{existsSync as t,mkdirSync as o,readdirSync as r,readFileSync as n,rmSync as s,statSync as i,writeFileSync as l}from"fs";import{join as a}from"path";import*as c from"@iarna/toml";import{logger as d}from"../../utils/logger.js";import{i18n as u}from"../i18n.js";import{backupBeforeWrite as m,atomicWriteFile as p}from"./backup.js";import{codexHome as f,pickModel as _,toolHome as g,withV1 as x}from"./types.js";import{moveSessionsToProvider as h,NO_STATE_DB as y,runningCodexPids as k}from"../codex-sessions.js";import{codexFormat as b,codexRolloutFiles as v}from"../sessions/formats.js";import{getGatewayModelRules as w,getToolDefaultModel as j}from"../model-registry.js";import{claimField as S}from"../written-values.js";import{configManager as C}from"../config.js";import{maskHome as O,track as M}from"../telemetry.js";import{buildCodexCatalog as A,catalogRejections as E,codexCatalogPath as N,fillFromOlderEntries as P,installedCodexBinaries as T,loadBundledCodexModels as D,loadPreviousCodexModels as $,previousGatewayModelIds as I}from"./codex-catalog.js";import{gatewayModelSpecs as L,modelFamily as J}from"../gateway-models.js";import{isOurGatewayUrl as G,noteWrittenGatewayUrl as R}from"../gateway-addresses.js";import{findInstalls as K,mirrorInstallCommand as X,brandInstallScripts as B}from"./tool-installs.js";import{chatgptDesktopApp as U}from"./chatgpt-desktop.js";const W=()=>f(),q=()=>a(W(),"config.toml"),z="sessions_move_declined",Y=["browser_use","browser_use_external","computer_use"],F="desktop_features_restored";function H(e){if(!0===C.getToolSetting("codex",F))return!1;const t=e.features,o=ae(t)&&Y.every(e=>!1===t[e]);if(C.setToolSetting("codex",F,!0),!o)return!1;for(const e of Y)delete t[e];return!0}export function codexWorkModeOn(){try{const e=de();return e.model_provider===ee&&ae(e.desktop)&&"STEPS_PROSE"===e.desktop.conversationDetailMode}catch{return!1}}function Q(){try{if(ae(de().desktop))return!0}catch{}if("darwin"===process.platform)return["/Applications",a(g(),"Applications")].some(e=>["ChatGPT.app","Codex.app"].some(o=>t(a(e,o))));if("win32"===process.platform){const e=a(process.env.LOCALAPPDATA||a(g(),"AppData","Local"),"Packages");try{return r(e).some(e=>/^OpenAI\.(Codex|ChatGPT)/i.test(e))}catch{return!1}}return t("/usr/lib/chatgpt/ChatGPT")}export function codexConfigPath(){return q()}const V=()=>a(W(),"auth.json"),Z="OPENAI_API_KEY",ee="custom",te="high",oe=["gpt-5.5","gpt-5.6-sol","gpt-6-astra"],re=["high","xhigh"],ne={goals:!0,js_repl:!1};let se=[];const ie=1e6,le=9e5;export const CODEX_ONE_MILLION_CONTEXT_SETTING="one_million_context";function ae(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function ce(e,t){return ae(e[t])||(e[t]={}),e[t]}function de(){if(!t(q()))return{};const e=n(q(),"utf-8");if(!e.trim())return{};try{const t=c.parse(e);if(!ae(t))throw new Error("config.toml root must be a TOML table");return t}catch(e){throw new Error(`Existing ~/.codex/config.toml cannot be parsed; back it up and fix it first: ${e instanceof Error?e.message:String(e)}`)}}function ue(){if(!t(V()))return{};try{const e=JSON.parse(n(V(),"utf-8"));return ae(e)?e:{}}catch{return{}}}let me=null;function pe(e){const t=e.profiles;if(ae(t)){for(const[e,o]of Object.entries(t))ae(o)&&2===Object.keys(o).length&&o.model_provider===ee&&o.model===e&&delete t[e];0===Object.keys(t).length&&delete e.profiles}}let fe=null;const _e=()=>a(C.getConfigDir(),"codex-catalog-check.json");function ge(e){const o=N();t(o)&&n(o,"utf-8")===e||(m(o),p(o,e))}function xe(t,r){if(0===r.length)return[];const s=function(t,o){const r=e("sha256").update(t);for(const e of o)try{const t=i(e);r.update(`\0${e}\0${t.size}\0${t.mtimeMs}`)}catch{r.update(`\0${e}`)}return r.digest("hex")}(t,r);if(function(e){try{return JSON.parse(n(_e(),"utf-8")).signature===e}catch{return!1}}(s))return[];const a=E(N(),r);return 0===a.length&&function(e){try{o(C.getConfigDir(),{recursive:!0}),l(_e(),JSON.stringify({signature:e})+"\n")}catch(e){d.logError("codexAdapter.rememberAccepted",e)}}(s),a}function he(e,t,o){const r=!1!==t.settings?.one_million_context;!function(e){e.model_context_window===ie&&delete e.model_context_window,e.model_auto_compact_token_limit===le&&delete e.model_auto_compact_token_limit}(e);const n=()=>{e.model_catalog_json===N()&&delete e.model_catalog_json,r&&(e.model_context_window=ie,e.model_auto_compact_token_limit=le)},i=D()??$();if(!i)return d.logError("codexAdapter.writeModelCatalog",new Error("no Codex binary found; model catalog skipped")),fe="skipped",void n();const l=t.catalog,a=e=>A({bundled:e,specs:L("codex",l?.clientModels),...l?{keyModels:l.models}:{},gatewayAvailable:l?.models??I(),oneMillion:r,selectedModel:o,..."gateway"===l?.oneMillionSource?{claudeOneMillion:l.oneMillion}:{}}),c=e=>JSON.stringify(e,null,2)+"\n";let u=a(i);ge(c(u));const m=T(),p=xe(c(u),m);if(p.length>0){const e=Date.now();let t=!1;for(const e of p){const o=D(e.bin);if(o){for(const e of[{models:P(u.models,o)},{models:P(a(o).models,o)}])if(ge(c(e)),0===xe(c(e),m).length){u=e,t=!0;break}if(t)break}}if(M("codex-catalog",t?"fallback":"fail",{duration_ms:Date.now()-e,error:p[0].error,detail:{rejected_by:p.map(e=>({version:e.version,path:O(e.bin)}))}}),!t)return fe={rejectedBy:p[0]},s(N(),{force:!0}),void n()}fe={listed:u.models.filter(e=>"list"===e.visibility).map(e=>({id:String(e.slug),name:String(e.display_name??e.slug)}))},e.model_catalog_json=N()}export function codexCatalogRejection(){let e;try{e=de()}catch{return null}return e.model_catalog_json===N()&&t(N())?E(N())[0]??null:null}export function setCodexOneMillionContext(e,t){const o=de(),r=c.stringify(o),n="string"==typeof o.model?o.model:j("codex");he(o,{settings:{[CODEX_ONE_MILLION_CONTEXT_SETTING]:e},catalog:t},n);const s=c.stringify(o);s!==r&&(m(q()),p(q(),s))}const ye={command:"codex",npmPackage:"@openai/codex",native:{binDir:"win32"===process.platform?["AppData","Local","Programs","OpenAI","Codex","bin"]:[".local","bin"],updateArgs:["update"],updateTimeoutMs:12e4,dataDirs:[[".codex","packages","standalone"]]},mirrorScript:B("codex"),brew:"codex"};function ke(e){const t=ae(e.model_providers)?e.model_providers[ee]:void 0;if(!ae(t))return null;const o="string"==typeof t.base_url?t.base_url.trim():"";return o&&!G(o)?o:null}let be=null;function ve(){if("skipped"===fe)return 0===K(ye).length?[]:[{kind:"action",text:u.t("tools.codex.catalog_skipped")}];if(!fe)return[];if("rejectedBy"in fe){const{bin:e,version:t}=fe.rejectedBy;return[{kind:"action",text:u.t("tools.codex.catalog_rejected",{path:e,version:t??"?"})}]}const e=new Map;for(const t of fe.listed)e.set(J(t.id),(e.get(J(t.id))??0)+1);const t=["gpt","claude","gemini","other","grok"].filter(t=>e.has(t)).map(t=>`${u.t(`tools.model_family.${t}`)} ${e.get(t)}`).join(" · ");return[{kind:"summary",text:u.t("tools.codex.catalog_written",{count:String(fe.listed.length),breakdown:t})},{kind:"detail",text:fe.listed.map(e=>e.name).join(", ")},...codexWorkModeOn()||Q()?[{kind:"action",text:u.t(codexWorkModeOn()?"tools.codex.work_mode_on":"tools.codex.work_mode_hint")}]:[]]}export const codexAdapter={name:"codex",companionApps:[U],displayName:"Codex",command:"codex",installCommand:X(ye),installSpec:ye,configPath:q(),sessions:{format:b,files:()=>[...v(a(f(),"sessions")),...v(a(f(),"archived_sessions"))],resumeCommand:e=>({command:"codex",args:["resume",e]})},wantsModelCatalog:!0,listedModels(){if(de().model_catalog_json!==N())return null;try{return(JSON.parse(n(N(),"utf-8")).models??[]).filter(e=>"list"===e.visibility).map(e=>String(e.slug))}catch{return null}},refreshModelMenu(e){if(de().model_catalog_json!==N())return;setCodexOneMillionContext(!1!==e.settings?.one_million_context,e.catalog);const t=de(),o=function(e,t){const o=ae(e.model_providers)?e.model_providers[ee]:void 0;return!(!ae(o)||o.base_url!==t||!0===o.supports_standalone_web_search||(o.supports_standalone_web_search=!0,0))}(t,x(e.baseUrl));(H(t)||o)&&(m(q()),p(q(),c.stringify(t)))},async followUp(){if(de().model_provider!==ee)return null;const e=await h(ee,{dryRun:!0}),t=Math.max(e.moved.length,e.dbRows);if(0===t)return null;const o=C.getToolSettings("codex")[z];if("number"==typeof o&&t<=o)return null;const r={count:String(t)};return k().length>0?{hint:u.t("tools.codex.sessions_hidden_running",r)}:{prompt:u.t("tools.codex.sessions_offer",r),hint:u.t("tools.codex.sessions_hidden",r),async run(){const e=await h(ee),t=[...new Set(e.moved.map(e=>e.from))].join("、")||"-",o=String(Math.max(e.moved.length,e.dbRows)),r=[{kind:"summary",text:u.t("codex_sessions.moved",{count:o,from:t,target:ee})},{kind:"summary",text:u.t("codex_sessions.backup",{dir:e.backupDir??""})}];return e.dbSkipped&&e.dbSkipped!==y&&r.push({kind:"action",text:u.t("codex_sessions.db_skipped",{reason:e.dbSkipped})}),r},decline(){C.setToolSetting("codex",z,t)}}},applyNotes(){const e=[];return be&&e.push({kind:"summary",text:u.t("tools.codex.provider_replaced",{url:be})}),se.length>0&&e.push({kind:"summary",text:u.t("tools.codex.kept_user_settings",{values:se.join(", ")})}),[...e,...ve()]},planNotes(){let e;try{e=de()}catch{return[]}const t=[],o=ke(e);return o?t.push(u.t("tools.codex.plan_replace_provider",{url:o})):"string"==typeof e.model_provider&&e.model_provider!==ee&&t.push(u.t("tools.codex.plan_switch_provider",{provider:e.model_provider})),t},loadPrivateConfig(e){const t=j("codex"),o=_(e.models,t),r=function(e){return/(?:^|\/)claude(?:-|$)/i.test(e)}(o)?t:o,n=x(e.baseUrl),s=de();se=[];const i=w().retired,l="string"==typeof s.model&&i.includes(s.model)?void 0:s.model;S("codex.model",l,r,{explicit:r!==t,legacy:oe})?s.model=r:se.push(`model = ${String(s.model)}`),s.model_provider=ee,S("codex.model_reasoning_effort",s.model_reasoning_effort,te,{legacy:re})?s.model_reasoning_effort=te:se.push(`model_reasoning_effort = ${String(s.model_reasoning_effort)}`);const a="string"==typeof s.model?s.model:r;he(s,e,a);const d=ce(s,"model_providers");be=ke(s),R(n);const u=ae(d[ee])?{...d[ee]}:{};delete u.env_key;const{experimental_bearer_token:f,...g}=u;d[ee]={...g,name:"custom",wire_api:"responses",requires_openai_auth:!0,supports_standalone_web_search:!0,base_url:n},pe(s),ce(ce(s,"tui"),"model_availability_nux")[a]=4;const h=ce(s,"features");for(const[e,t]of Object.entries(ne))(S(`codex.features.${e}`,h[e],String(t),{legacy:[String(t)]})||h[e]===t)&&(h[e]=t);H(s),m(q()),p(q(),c.stringify(s)),function(e){const t=e.trim();if(!t)return;const o={...ue(),auth_mode:"apikey",[Z]:t};m(V()),p(V(),JSON.stringify(o,null,2)+"\n",384)}(e.apiKey)},holdsOurConfig(e){const t=ue()[Z];return"string"==typeof t&&e.includes(t.trim())},unloadPrivateConfig(e){if(me=function(e){const t=ue(),o="string"==typeof t[Z]?t[Z].trim():"";if(!o)return ae(t.tokens)?"chatgpt":null;if(!e.includes(o))return"other_key";const{[Z]:r,auth_mode:n,...i}=t;return m(V()),ae(i.tokens)?(p(V(),JSON.stringify({...i,auth_mode:"chatgpt"},null,2)+"\n",384),"chatgpt"):(s(V(),{force:!0}),"signed_out")}(e?.savedKeys??[]),!t(q()))return;let o;try{o=de()}catch(e){return void d.logError("codexAdapter.unloadPrivateConfig",e)}const r=o.model_providers;ae(r)&&ae(r[ee])&&G(r[ee].base_url)&&ae(r)&&(delete r[ee],0===Object.keys(r).length&&delete o.model_providers,o.model_provider===ee&&delete o.model_provider),o.model_catalog_json===N()&&delete o.model_catalog_json,H(o),pe(o),m(q()),p(q(),c.stringify(o))},unloadNotes(){switch(me){case"chatgpt":return[{kind:"action",text:u.t("tools.codex.unload_chatgpt_restored")}];case"other_key":return[{kind:"action",text:u.t("tools.codex.unload_other_key")}];default:return[{kind:"action",text:u.t("tools.codex.unload_sign_in")}]}},detectCurrentConfig(){const e=ue()[Z];return{apiKey:"string"==typeof e&&e.trim()?e.trim():null}},getConfig(){try{return de()}catch(e){return d.logError("codexAdapter.getConfig",e),null}},backupPaths:()=>[q(),V(),N()]};export function codexAuthProblem(){try{const e=de(),t=e.model_providers?.[ee];if(e.model_provider!==ee||!t)return null;if("string"==typeof t.experimental_bearer_token&&t.experimental_bearer_token)return"stale_bearer";const o=ue();return!0===t.requires_openai_auth&&"chatgpt"===o.auth_mode?"chatgpt_login":null}catch{return null}}
@@ -13,7 +13,9 @@
13
13
  * - macOS: the .dmg is attached read-only, the app copied with `ditto` next to the target and swapped in with
14
14
  * two renames (the old bundle stays until the new one is in place). A new install goes to /Applications, or
15
15
  * ~/Applications when /Applications isn't writable for this user. Write access is checked before downloading.
16
- * - Windows: `Add-AppxPackage` (per user, no administrator).
16
+ * - Windows: `Add-AppxPackage` (per user). Windows refuses some first installs without an administrator
17
+ * (0x80073D28, 11-03 a customer's fresh Claude Desktop install; upgrades of the same package worked without):
18
+ * then, if `progress.elevate()` agrees, the downloaded package is installed once more through one UAC prompt.
17
19
  * - Not as root (sudo) on macOS, not as SYSTEM on Windows: the app would belong to the wrong account. Not over
18
20
  * SSH on Windows: a network logon can't deploy MSIX packages.
19
21
  */
@@ -83,6 +85,8 @@ export interface DesktopInstallProgress {
83
85
  percent?(percent: number): void;
84
86
  verifying?(): void;
85
87
  installing?(): void;
88
+ /** Windows asked for an administrator: true = install through a UAC prompt (asked / announced by the caller). */
89
+ elevate?(): Promise<boolean>;
86
90
  }
87
91
  export interface DesktopAppInstaller {
88
92
  mirrorRepo(): string | null;
@@ -1 +1 @@
1
- import{spawnSync as t}from"child_process";import{createHash as e}from"crypto";import{accessSync as r,constants as o,createReadStream as n,createWriteStream as s,existsSync as a,mkdirSync as i,mkdtempSync as c,readFileSync as l,renameSync as p,rmSync as u}from"fs";import{cpus as d,tmpdir as f}from"os";import{basename as m,dirname as g,join as w}from"path";import{Readable as h,Transform as $}from"stream";import{pipeline as S}from"stream/promises";import{logger as A}from"../../utils/logger.js";import{i18n as x}from"../i18n.js";import{powerShellEnv as y}from"../powershell-env.js";import{toolHome as E}from"./types.js";const v=(e,r,o={})=>{const n=t(e,r,{encoding:"utf-8",timeout:o.timeout??12e4,windowsHide:!0,input:o.input,stdio:[void 0===o.input?"ignore":"pipe","pipe","pipe"],maxBuffer:16777216,env:y()});return n.error&&A.logError(`desktop-app: ${e}`,n.error),{status:n.status,stdout:`${n.stdout??""}`,stderr:`${n.stderr??""}`}};let _=v,I=(...t)=>fetch(...t),k=null,P=null,b=null,C=null;export function setDesktopAppDepsForTests(t){void 0!==t.run&&(_=t.run??v),void 0!==t.fetch&&(I=t.fetch??((...t)=>fetch(...t))),void 0!==t.platform&&(k=t.platform),void 0!==t.arm64&&(P=t.arm64),void 0!==t.privileged&&(b=t.privileged),void 0!==t.remote&&(C=t.remote)}export function appPlatform(){return k??process.platform}export function isArm64Machine(){return null!==P?P:"arm64"===process.arch||("win32"===appPlatform()?"ARM64"===process.env.PROCESSOR_ARCHITECTURE||"ARM64"===process.env.PROCESSOR_ARCHITEW6432:"darwin"===appPlatform()&&/\bApple\b/.test(d()[0]?.model??""))}export class DesktopInstallError extends Error{constructor(t){super(t),this.name="DesktopInstallError"}}export const fail=(t,e={})=>{const r={};for(const[t,o]of Object.entries(e))r[t]=o.trim()||x.t("app_update.reason_unknown");throw new DesktopInstallError(x.t(`app_update.error_${t}`,r))};export function parseSha256Sums(t){const e=new Map;for(const r of t.split(/\r?\n/)){const t=/^([0-9a-f]{64})\s+\*?(\S.*)$/i.exec(r.trim());t&&e.set(t[2].trim(),t[1].toLowerCase())}return e}async function T(t,e){const r=await I(t,{signal:AbortSignal.timeout(e)});if(!r.ok)throw new Error(`${t}: HTTP ${r.status}`);return(await r.text()).trim()}function M(t,e){try{const r=l(w(t,"Contents","Info.plist"),"utf-8");return new RegExp(`<key>${e}</key>\\s*<string>([^<]*)</string>`).exec(r)?.[1]??null}catch{return null}}export function macBundleId(t){return M(t,"CFBundleIdentifier")}export function macAppVersion(t){return/^\d+\.\d+\.\d+/.exec(M(t,"CFBundleShortVersionString")??"")?.[0]??null}function R(t){try{return r(t,o.W_OK),!0}catch{return!1}}const O=t=>`'${t.replace(/'/g,"''")}'`;function j(t,e=12e4){return _("powershell.exe",["-NoProfile","-NonInteractive","-ExecutionPolicy","Bypass","-Command","[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; "+t],{timeout:e})}export function powerShellError(t){return t.replace(/#< CLIXML/g,"").replace(/_x000D__x000A_/g,"\n").replace(/<\/S>/g,"\n").replace(/<[^>]+>/g,"").replace(/_x[0-9A-F]{4}_/g,"").replace(/&apos;/g,"'").replace(/&quot;/g,'"').replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&").split(/\r?\n/).map(t=>t.trim()).find(t=>t&&!/^(At line|At char|所在位置|\+|~|CategoryInfo|FullyQualifiedErrorId)/i.test(t))??""}export function createDesktopAppInstaller(t){const r=()=>t.mirror()?.replace(/\/-\/releases\/latest\/?$/,"")??null,o=()=>t.asset(appPlatform(),isArm64Machine()),l=()=>{const e=appPlatform();return"darwin"!==e&&"win32"!==e?"unsupported_platform":o()?r()?"darwin"===e&&(b??0===process.getuid?.())?"root":"win32"===e&&(null!==b?b:/\\system32\\config\\systemprofile/i.test(process.env.USERPROFILE??"")||!0===process.env.USERNAME?.endsWith("$"))?"system_account":"win32"===e&&(null!==C?C:Boolean(process.env.SSH_CONNECTION||process.env.SSH_CLIENT))?"remote_session":t.extraBlocker?.(e)??null:"no_mirror":"darwin"===e?"unsupported_arch":"unsupported_platform"},d=async(e=8e3)=>{const o=r();if(!o)throw new Error("no mirror");const n=t.versionFile(appPlatform(),isArm64Machine()),s=await T(`${o}/-/releases/latest/download/${n}`,e),a=/^(\d+\.\d+\.\d+)(\.\d+)?$/.exec(s)?.[1];if(!a)throw new Error(`unexpected ${n}: ${s.slice(0,40)}`);return a},y=()=>{for(const e of["/Applications",w(E(),"Applications")])for(const r of t.macApp.installedNames){const o=w(e,r);if(!a(w(o,"Contents","Info.plist")))continue;const n=macBundleId(o);if(null===n||n===t.macApp.bundleId)return o}return null},v=e=>{const r=_("codesign",["--verify","--deep","--strict",e],{timeout:6e5});0!==r.status&&fail("signature",{reason:(r.stderr||r.stdout).trim().split("\n")[0]||`codesign ${r.status}`});const o=_("codesign",["-dv",e]),n=`${o.stdout}\n${o.stderr}`,s=/^TeamIdentifier=(\S+)/m.exec(n)?.[1],a=/^Identifier=(\S+)/m.exec(n)?.[1];s===t.macApp.teamId&&a===t.macApp.bundleId||fail("signature",{reason:`TeamIdentifier=${s??"?"} Identifier=${a??"?"}`});const i=_("spctl",["-a","-t","exec","-vv",e],{timeout:3e5});0!==i.status&&fail("signature",{reason:(i.stderr||i.stdout).trim().split("\n")[0]||`spctl ${i.status}`})},k=()=>{const e=y();let r=e;if(!r){const e=R("/Applications")?"/Applications":w(E(),"Applications");r=w(e,t.macApp.installedNames[0])}const o=g(r);return(a(o)&&!R(o)||e&&!R(e))&&fail("no_permission",{path:r}),{target:r,existing:e}},P=e=>{const r=j(`$s = Get-AuthenticodeSignature -LiteralPath ${O(e)}; [pscustomobject]@{ status = [string]$s.Status; subject = [string]$s.SignerCertificate.Subject } | ConvertTo-Json -Compress`);let o={};try{o=JSON.parse(r.stdout.trim()||"{}")}catch{}if("Valid"!==o.status||!t.windows.signer.test(o.subject??"")){const t=o.status?`${o.status} ${o.subject??""}`:powerShellError(r.stderr)||powerShellError(r.stdout.trim().startsWith("{")?"":r.stdout)||`exit ${r.status}`;fail("signature",{reason:t.trim()})}},M=()=>{const e=j(`Get-AppxPackage | Where-Object { ${t.windows.packageFilter} } | ForEach-Object { $_.Version.ToString() }`,3e4);return/\d+\.\d+\.\d+/.exec(e.stdout)?.[0]??null};return{mirrorRepo:r,assetName:o,blocker:l,latestVersion:d,installedMacApp:y,windowsPackageVersion:M,verifyMacApp:v,verifyWindowsPackage:P,install:async(y={})=>{const E=l();E&&fail("blocked",{reason:x.t(`app_update.reason_${E}`)});const b=r(),C=o();let R;try{R=await d(15e3)}catch(t){fail("download",{reason:t instanceof Error?t.message:String(t)})}const N=t.releaseTag?`${b}/-/releases/download/${t.releaseTag(R)}`:`${b}/-/releases/latest/download`;let F;try{F=parseSha256Sums(await T(`${N}/SHA256SUMS`,15e3)).get(C)}catch(e){A.logError(`${t.id}: SHA256SUMS`,e)}F||fail("no_checksum",{file:C}),"darwin"===appPlatform()&&k();const H=c(w(f(),`${t.id}-`));try{const r=w(H,C);y.downloading?.(R),await async function(t,e,r){let o;try{o=await I(t,{signal:AbortSignal.timeout(18e5)})}catch(t){fail("download",{reason:t instanceof Error?t.message:String(t)})}o.ok&&o.body||fail("download",{reason:`HTTP ${o.status}`});const n=Number(o.headers.get("content-length"))||0;let a=0,i=-1;const c=new $({transform(t,e,o){a+=t.length;const s=n?Math.floor(100*a/n):-1;s>=0&&s!==i&&(i=s,r?.(s)),o(null,t)}});try{await S(h.fromWeb(o.body),c,s(e))}catch(t){u(e,{force:!0}),fail("download",{reason:t instanceof Error?t.message:String(t)})}}(`${N}/${C}`,r,y.percent),y.verifying?.();const o=await async function(t){const r=e("sha256");for await(const e of n(t))r.update(e);return r.digest("hex")}(r);return o!==F&&fail("checksum",{file:C,expected:F.slice(0,12),actual:o.slice(0,12)}),y.installing?.(),"darwin"===appPlatform()?await(async(e,r)=>{const o=w(r,"mnt");i(o,{recursive:!0});const n=_("hdiutil",["attach","-nobrowse","-readonly","-noautoopen","-mountpoint",o,e],{timeout:3e5,input:"Y\n"});0!==n.status&&fail("mount",{reason:(n.stderr||n.stdout).trim().split("\n").pop()??""});let s=null;try{const e=w(o,t.macApp.source);a(e)||fail("bad_package",{reason:t.macApp.source});const{target:r,existing:n}=k(),c=g(r),l=m(r);i(c,{recursive:!0}),s=w(c,`.${l}.${process.pid}.new`),u(s,{recursive:!0,force:!0});const d=_("ditto",[e,s],{timeout:9e5});0!==d.status&&fail("copy",{reason:(d.stderr||d.stdout).trim().split("\n")[0]??""}),v(s);const f=macAppVersion(s);f||fail("bad_package",{reason:"Info.plist"});const h=w(c,`.${l}.${process.pid}.old`);try{n&&p(n,h)}catch(t){throw["EPERM","EACCES"].includes(t.code??"")&&fail("app_management",{path:n}),t}try{p(s,r)}catch(t){throw n&&p(h,n),t}return s=null,u(h,{recursive:!0,force:!0}),{version:f,location:r}}finally{s&&u(s,{recursive:!0,force:!0}),_("hdiutil",["detach",o,"-force"],{timeout:6e4})}})(r,H):(t=>{P(t);const e=j(`$ErrorActionPreference = 'Stop'; Add-AppxPackage -Path ${O(t)} -ForceApplicationShutdown`,9e5);0!==e.status&&fail("install",{reason:powerShellError(e.stderr)||powerShellError(e.stdout)||`Add-AppxPackage ${e.status}`});const r=M();return r||fail("install",{reason:"Get-AppxPackage"}),{version:r,location:"MSIX"}})(r)}finally{u(H,{recursive:!0,force:!0})}}}}
1
+ import{spawnSync as t}from"child_process";import{createHash as e}from"crypto";import{accessSync as r,constants as o,createReadStream as n,createWriteStream as s,existsSync as a,mkdirSync as i,mkdtempSync as c,readFileSync as l,renameSync as p,rmSync as u}from"fs";import{cpus as d,tmpdir as f}from"os";import{basename as m,dirname as g,join as h}from"path";import{Readable as w,Transform as $}from"stream";import{pipeline as S}from"stream/promises";import{logger as A}from"../../utils/logger.js";import{i18n as x}from"../i18n.js";import{powerShellEnv as E}from"../powershell-env.js";import{toolHome as y}from"./types.js";const v=(e,r,o={})=>{const n=t(e,r,{encoding:"utf-8",timeout:o.timeout??12e4,windowsHide:!0,input:o.input,stdio:[void 0===o.input?"ignore":"pipe","pipe","pipe"],maxBuffer:16777216,env:E()});return n.error&&A.logError(`desktop-app: ${e}`,n.error),{status:n.status,stdout:`${n.stdout??""}`,stderr:`${n.stderr??""}`}};let P=v,_=(...t)=>fetch(...t),I=null,k=null,b=null,C=null;export function setDesktopAppDepsForTests(t){void 0!==t.run&&(P=t.run??v),void 0!==t.fetch&&(_=t.fetch??((...t)=>fetch(...t))),void 0!==t.platform&&(I=t.platform),void 0!==t.arm64&&(k=t.arm64),void 0!==t.privileged&&(b=t.privileged),void 0!==t.remote&&(C=t.remote)}export function appPlatform(){return I??process.platform}export function isArm64Machine(){return null!==k?k:"arm64"===process.arch||("win32"===appPlatform()?"ARM64"===process.env.PROCESSOR_ARCHITECTURE||"ARM64"===process.env.PROCESSOR_ARCHITEW6432:"darwin"===appPlatform()&&/\bApple\b/.test(d()[0]?.model??""))}export class DesktopInstallError extends Error{constructor(t){super(t),this.name="DesktopInstallError"}}export const fail=(t,e={})=>{const r={};for(const[t,o]of Object.entries(e))r[t]=o.trim()||x.t("app_update.reason_unknown");throw new DesktopInstallError(x.t(`app_update.error_${t}`,r))};export function parseSha256Sums(t){const e=new Map;for(const r of t.split(/\r?\n/)){const t=/^([0-9a-f]{64})\s+\*?(\S.*)$/i.exec(r.trim());t&&e.set(t[2].trim(),t[1].toLowerCase())}return e}async function T(t,e){const r=await _(t,{signal:AbortSignal.timeout(e)});if(!r.ok)throw new Error(`${t}: HTTP ${r.status}`);return(await r.text()).trim()}function M(t,e){try{const r=l(h(t,"Contents","Info.plist"),"utf-8");return new RegExp(`<key>${e}</key>\\s*<string>([^<]*)</string>`).exec(r)?.[1]??null}catch{return null}}export function macBundleId(t){return M(t,"CFBundleIdentifier")}export function macAppVersion(t){return/^\d+\.\d+\.\d+/.exec(M(t,"CFBundleShortVersionString")??"")?.[0]??null}function R(t){try{return r(t,o.W_OK),!0}catch{return!1}}const F=t=>`'${t.replace(/'/g,"''")}'`;function O(t,e=12e4){return P("powershell.exe",["-NoProfile","-NonInteractive","-ExecutionPolicy","Bypass","-Command","[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; "+t],{timeout:e})}export function powerShellError(t){return t.replace(/#< CLIXML/g,"").replace(/_x000D__x000A_/g,"\n").replace(/<\/S>/g,"\n").replace(/<[^>]+>/g,"").replace(/_x[0-9A-F]{4}_/g,"").replace(/&apos;/g,"'").replace(/&quot;/g,'"').replace(/&lt;/g,"<").replace(/&gt;/g,">").replace(/&amp;/g,"&").split(/\r?\n/).map(t=>t.trim()).find(t=>t&&!/^(At line|At char|所在位置|\+|~|CategoryInfo|FullyQualifiedErrorId)/i.test(t))??""}export function createDesktopAppInstaller(t){const r=()=>t.mirror()?.replace(/\/-\/releases\/latest\/?$/,"")??null,o=()=>t.asset(appPlatform(),isArm64Machine()),d=()=>{const e=appPlatform();return"darwin"!==e&&"win32"!==e?"unsupported_platform":o()?r()?"darwin"===e&&(b??0===process.getuid?.())?"root":"win32"===e&&(null!==b?b:/\\system32\\config\\systemprofile/i.test(process.env.USERPROFILE??"")||!0===process.env.USERNAME?.endsWith("$"))?"system_account":"win32"===e&&(null!==C?C:Boolean(process.env.SSH_CONNECTION||process.env.SSH_CLIENT))?"remote_session":t.extraBlocker?.(e)??null:"no_mirror":"darwin"===e?"unsupported_arch":"unsupported_platform"},E=async(e=8e3)=>{const o=r();if(!o)throw new Error("no mirror");const n=t.versionFile(appPlatform(),isArm64Machine()),s=await T(`${o}/-/releases/latest/download/${n}`,e),a=/^(\d+\.\d+\.\d+)(\.\d+)?$/.exec(s)?.[1];if(!a)throw new Error(`unexpected ${n}: ${s.slice(0,40)}`);return a},v=()=>{for(const e of["/Applications",h(y(),"Applications")])for(const r of t.macApp.installedNames){const o=h(e,r);if(!a(h(o,"Contents","Info.plist")))continue;const n=macBundleId(o);if(null===n||n===t.macApp.bundleId)return o}return null},I=e=>{const r=P("codesign",["--verify","--deep","--strict",e],{timeout:6e5});0!==r.status&&fail("signature",{reason:(r.stderr||r.stdout).trim().split("\n")[0]||`codesign ${r.status}`});const o=P("codesign",["-dv",e]),n=`${o.stdout}\n${o.stderr}`,s=/^TeamIdentifier=(\S+)/m.exec(n)?.[1],a=/^Identifier=(\S+)/m.exec(n)?.[1];s===t.macApp.teamId&&a===t.macApp.bundleId||fail("signature",{reason:`TeamIdentifier=${s??"?"} Identifier=${a??"?"}`});const i=P("spctl",["-a","-t","exec","-vv",e],{timeout:3e5});0!==i.status&&fail("signature",{reason:(i.stderr||i.stdout).trim().split("\n")[0]||`spctl ${i.status}`})},k=()=>{const e=v();let r=e;if(!r){const e=R("/Applications")?"/Applications":h(y(),"Applications");r=h(e,t.macApp.installedNames[0])}const o=g(r);return(a(o)&&!R(o)||e&&!R(e))&&fail("no_permission",{path:r}),{target:r,existing:e}},M=e=>{const r=O(`$s = Get-AuthenticodeSignature -LiteralPath ${F(e)}; [pscustomobject]@{ status = [string]$s.Status; subject = [string]$s.SignerCertificate.Subject } | ConvertTo-Json -Compress`);let o={};try{o=JSON.parse(r.stdout.trim()||"{}")}catch{}if("Valid"!==o.status||!t.windows.signer.test(o.subject??"")){const t=o.status?`${o.status} ${o.subject??""}`:powerShellError(r.stderr)||powerShellError(r.stdout.trim().startsWith("{")?"":r.stdout)||`exit ${r.status}`;fail("signature",{reason:t.trim()})}},N=()=>{const e=O(`Get-AppxPackage | Where-Object { ${t.windows.packageFilter} } | ForEach-Object { $_.Version.ToString() }`,3e4);return/\d+\.\d+\.\d+/.exec(e.stdout)?.[0]??null};return{mirrorRepo:r,assetName:o,blocker:d,latestVersion:E,installedMacApp:v,windowsPackageVersion:N,verifyMacApp:I,verifyWindowsPackage:M,install:async(y={})=>{const v=d();v&&fail("blocked",{reason:x.t(`app_update.reason_${v}`)});const b=r(),C=o();let R;try{R=await E(15e3)}catch(t){fail("download",{reason:t instanceof Error?t.message:String(t)})}const j=t.releaseTag?`${b}/-/releases/download/${t.releaseTag(R)}`:`${b}/-/releases/latest/download`;let B;try{B=parseSha256Sums(await T(`${j}/SHA256SUMS`,15e3)).get(C)}catch(e){A.logError(`${t.id}: SHA256SUMS`,e)}B||fail("no_checksum",{file:C}),"darwin"===appPlatform()&&k();const H=c(h(f(),`${t.id}-`));try{const r=h(H,C);y.downloading?.(R),await async function(t,e,r){let o;try{o=await _(t,{signal:AbortSignal.timeout(18e5)})}catch(t){fail("download",{reason:t instanceof Error?t.message:String(t)})}o.ok&&o.body||fail("download",{reason:`HTTP ${o.status}`});const n=Number(o.headers.get("content-length"))||0;let a=0,i=-1;const c=new $({transform(t,e,o){a+=t.length;const s=n?Math.floor(100*a/n):-1;s>=0&&s!==i&&(i=s,r?.(s)),o(null,t)}});try{await S(w.fromWeb(o.body),c,s(e))}catch(t){u(e,{force:!0}),fail("download",{reason:t instanceof Error?t.message:String(t)})}}(`${j}/${C}`,r,y.percent),y.verifying?.();const o=await async function(t){const r=e("sha256");for await(const e of n(t))r.update(e);return r.digest("hex")}(r);return o!==B&&fail("checksum",{file:C,expected:B.slice(0,12),actual:o.slice(0,12)}),y.installing?.(),"darwin"===appPlatform()?await(async(e,r)=>{const o=h(r,"mnt");i(o,{recursive:!0});const n=P("hdiutil",["attach","-nobrowse","-readonly","-noautoopen","-mountpoint",o,e],{timeout:3e5,input:"Y\n"});0!==n.status&&fail("mount",{reason:(n.stderr||n.stdout).trim().split("\n").pop()??""});let s=null;try{const e=h(o,t.macApp.source);a(e)||fail("bad_package",{reason:t.macApp.source});const{target:r,existing:n}=k(),c=g(r),l=m(r);i(c,{recursive:!0}),s=h(c,`.${l}.${process.pid}.new`),u(s,{recursive:!0,force:!0});const d=P("ditto",[e,s],{timeout:9e5});0!==d.status&&fail("copy",{reason:(d.stderr||d.stdout).trim().split("\n")[0]??""}),I(s);const f=macAppVersion(s);f||fail("bad_package",{reason:"Info.plist"});const w=h(c,`.${l}.${process.pid}.old`);try{n&&p(n,w)}catch(t){throw["EPERM","EACCES"].includes(t.code??"")&&fail("app_management",{path:n}),t}try{p(s,r)}catch(t){throw n&&p(w,n),t}return s=null,u(w,{recursive:!0,force:!0}),{version:f,location:r}}finally{s&&u(s,{recursive:!0,force:!0}),P("hdiutil",["detach",o,"-force"],{timeout:6e4})}})(r,H):await(async(t,e)=>{M(t);const r=O(`$ErrorActionPreference = 'Stop'; Add-AppxPackage -Path ${F(t)} -ForceApplicationShutdown`,9e5);if(0!==r.status){const o=powerShellError(r.stderr)||powerShellError(r.stdout)||`Add-AppxPackage ${r.status}`;/0x80073D28/i.test(`${r.stderr}\n${r.stdout}`)||fail("install",{reason:o}),await(e.elevate?.())||fail("needs_admin");const n=(t=>{const e=h(g(t),"elevated-install.log"),r=`$ErrorActionPreference = 'Stop'; try { Add-AppxPackage -Path ${F(t)} -ForceApplicationShutdown; exit 0 } catch { [IO.File]::WriteAllText(${F(e)}, $_.Exception.Message, [Text.Encoding]::UTF8); exit 1 }`,o=O(`$ErrorActionPreference = 'Stop'; $p = Start-Process -FilePath 'powershell.exe' -ArgumentList @('-NoProfile', '-ExecutionPolicy', 'Bypass', '-EncodedCommand', '${Buffer.from(r,"utf16le").toString("base64")}') -Verb RunAs -Wait -PassThru -WindowStyle Hidden; exit $p.ExitCode`,12e5);if(0===o.status)return null;let n="";try{n=l(e,"utf-8").trim()}catch{}return n||powerShellError(o.stderr)||powerShellError(o.stdout)||`exit ${o.status}`})(t);n&&fail("install",{reason:n}),N()||fail("other_account")}const o=N();return o||fail("install",{reason:"Get-AppxPackage"}),{version:o,location:"MSIX"}})(r,y)}finally{u(H,{recursive:!0,force:!0})}}}}
@@ -36,6 +36,13 @@ export interface ToolApplyContext {
36
36
  * Only resolved for adapters that set `wantsModelCatalog`; absent offline.
37
37
  */
38
38
  catalog?: ModelCatalog;
39
+ /**
40
+ * The user asked for this tool by name (a tool-specific key, `config <tool>`, the wizard) or
41
+ * confirmed a write plan listing what gets replaced (`planNotes`): the adapter may switch the
42
+ * tool over from settings someone else made (Claude Desktop's deployment mode and active
43
+ * entry). Otherwise it writes its own entry and leaves the switch to the user (new-api#174).
44
+ */
45
+ takeOver?: boolean;
39
46
  }
40
47
  /**
41
48
  * One self-contained integration for a downstream coding tool.
@@ -93,6 +100,8 @@ export interface AppInstaller {
93
100
  percent(percent: number): void;
94
101
  verifying(): void;
95
102
  installing(): void;
103
+ /** Windows wants an administrator for this install: true = go ahead with a UAC prompt. */
104
+ elevate?(): Promise<boolean>;
96
105
  }): Promise<{
97
106
  version: string;
98
107
  location: string;
@@ -217,6 +226,12 @@ export interface ToolAdapter {
217
226
  * provider slot other software also writes (Codex auth.json, Claude Code env) check it.
218
227
  */
219
228
  holdsOurConfig?(savedKeys: string[]): boolean;
229
+ /**
230
+ * Settings outside its own entry this write would remove or replace (another service's
231
+ * provider, shell variables, the app's active configuration): listed in the write plan and
232
+ * `--dry-run`, so the user sees them before saying yes.
233
+ */
234
+ planNotes?(): string[];
220
235
  /** Localized next steps after the last `unloadPrivateConfig` (e.g. how to sign in with the vendor's own account). */
221
236
  unloadNotes?(): ApplyNote[];
222
237
  /** Read back the api key currently configured for this tool, if any. */