@vibeapi/cli 0.0.155 → 0.0.157

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/brand.json CHANGED
@@ -43,7 +43,8 @@
43
43
  "scripts": "https://cnb.cool/vibeapi/install/-/git/raw/main",
44
44
  "agy": "https://cnb.cool/lib/mirrors/-/releases/download/agy",
45
45
  "claudeDesktop": "https://cnb.cool/lib/mirrors/-/releases/download/claude-desktop",
46
- "chatgptDesktop": "https://cnb.cool/lib/mirrors/-/releases/download/chatgpt-desktop"
46
+ "chatgptDesktop": "https://cnb.cool/lib/mirrors/-/releases/download/chatgpt-desktop",
47
+ "downloadCounter": "https://dl.vibecli.cn"
47
48
  },
48
49
  "pluginMarketplaces": [
49
50
  {
@@ -52,6 +52,11 @@ export interface Brand {
52
52
  claudeDesktop?: string;
53
53
  /** ChatGPT desktop app (contains Codex) download mirror for macOS / Windows (see mirror-url.ts). */
54
54
  chatgptDesktop?: string;
55
+ /**
56
+ * Download counter in front of cnb.cool (logs the download, then 302s to the same path): desktop app downloads
57
+ * try `<counter><path>` first and fall back to cnb.cool (see mirror-url.ts `downloadUrls`). Omitted = direct.
58
+ */
59
+ downloadCounter?: string;
55
60
  };
56
61
  /** Claude Code plugin marketplaces tried before Anthropic's GitHub repo. */
57
62
  pluginMarketplaces: BrandPluginMarketplace[];
@@ -65,7 +65,7 @@ export declare class ClaudeCodeManager {
65
65
  private mcpConfigPath;
66
66
  private lastTierFallbacks;
67
67
  /** `NAME=value` of model settings the user chose that the last loadPrivateConfig left alone. */
68
- private lastKept;
68
+ private lastReplaced;
69
69
  private constructor();
70
70
  static getInstance(): ClaudeCodeManager;
71
71
  /**
@@ -112,8 +112,8 @@ export declare class ClaudeCodeManager {
112
112
  * @returns 实际被清除的键名(未改动时为空数组)
113
113
  */
114
114
  clearPinnedModels(availableModels?: string[]): string[];
115
- /** 最近一次 loadPrivateConfig 保留下来的用户自己的模型设置(`名字=值`)。 */
116
- getLastKept(): string[];
115
+ /** 最近一次 loadPrivateConfig 换掉的、不是 vibecli 写的模型设置(`名字=值`)。 */
116
+ getLastReplaced(): string[];
117
117
  /** 最近一次 loadPrivateConfig 实际写入的档位回退(用于应用后的提示)。 */
118
118
  getLastTierFallbacks(): TierFallback[];
119
119
  /**
@@ -1 +1 @@
1
- import{existsSync as e,mkdirSync as t,readFileSync as n,writeFileSync as o,renameSync as s,unlinkSync as i}from"fs";import{join as r,dirname as a}from"path";import{toolHome as l}from"./tools/types.js";import{logger as c}from"../utils/logger.js";import{configManager as d,DEFAULT_MODELS as g}from"./config.js";import{loadSettingsTemplate as u}from"./settings-template.js";import{cleanupAnthropicEnvVars as f}from"./env-cleanup.js";import{getClaudeCodeTierChains as m,getGatewayModelRules as O,getRetiredDefaultModelIds as C}from"./model-registry.js";import{claimField as h,forgetField as p,ownsValue as _}from"./written-values.js";import{noteWrittenGatewayUrl as E}from"./gateway-addresses.js";import{autoCompactTokens as A,modelBlurb as T,prettyModelName as v}from"./gateway-models.js";import{baseModelId as P}from"./model-catalog.js";export const MODEL_ENV_VARS=["ANTHROPIC_DEFAULT_HAIKU_MODEL","ANTHROPIC_DEFAULT_SONNET_MODEL","ANTHROPIC_DEFAULT_OPUS_MODEL","ANTHROPIC_DEFAULT_FABLE_MODEL","ANTHROPIC_MODEL","ANTHROPIC_REASONING_MODEL"];const N="claude-code.model",S=e=>`claude-code.env.${e}`;function M(e){const t=Object.values(m()).flat(),n=[...Object.values(g),...Object.values(e)].filter(e=>"string"==typeof e&&""!==e);return[...new Set(["opus[1m]",...n,...C(),...t])]}const D={opus:"ANTHROPIC_DEFAULT_OPUS_MODEL",sonnet:"ANTHROPIC_DEFAULT_SONNET_MODEL",haiku:"ANTHROPIC_DEFAULT_HAIKU_MODEL",fable:"ANTHROPIC_DEFAULT_FABLE_MODEL"},L="CLAUDE_CODE_MAX_CONTEXT_TOKENS";function y(){return r(d.getConfigDir(),"claude-code-picker.json")}function I(){try{const e=JSON.parse(n(y(),"utf-8")).ids;return Array.isArray(e)?e.map(String):[]}catch{return[]}}function R(e,t=[]){if(!e||"object"!=typeof e)return!1;const{options:n,replaceBuiltInOptions:o}=e;if(!Array.isArray(n)||o)return!1;const s=O(),i=new Set([...s.models.map(e=>e.id),...s.retired,...I(),...t]);return n.every(e=>e&&"object"==typeof e&&i.has(P(String(e.model))))}export function applyGatewayModels(e,n){if(void 0===n)return e;const s={...e};if(void 0!==s.modelPicker&&!R(s.modelPicker,n.map(e=>e.id)))return s;const i=R(s.modelPicker)?s.modelPicker.options.map(e=>P(e.model)):[],r={...s.env||{}},a={...s.modelSettings||{}};for(const e of i){if(!a[e])continue;const{autoCompactWindow:t,...n}=a[e];Object.keys(n).length>0?a[e]=n:delete a[e]}const l=e=>(e.contextWindow??0)>=1e6,g=n.filter(e=>!l(e)).map(e=>e.contextWindow).filter(e=>"number"==typeof e&&e>0);!function(e){try{t(d.getConfigDir(),{recursive:!0}),o(y(),JSON.stringify({ids:e})+"\n")}catch(e){c.logError("claudeCode.recordWrittenPickerIds",e)}}(n.map(e=>e.id));const u=e=>T(e.description,{millionContext:l(e)});if(0===n.length)delete s.modelPicker,delete r[L];else{s.modelPicker={options:n.map(e=>({model:l(e)?`${e.id}[1m]`:e.id,label:e.name||v(e.id),...u(e)?{description:u(e)}:{}}))},g.length>0?r[L]=String(Math.min(...g)):delete r[L];for(const e of n){if(!e.contextWindow)continue;const t=A(e.contextWindow,e.autoCompactTokens);a[e.id]={...a[e.id],autoCompactWindow:Math.min(Math.max(t,1e5),1e6)}}}return Object.keys(a).length>0?s.modelSettings=a:delete s.modelSettings,Object.keys(r).length>0?s.env=r:delete s.env,s}export function resolveTierFallbacks(e){if(!e||0===e.length)return[];const t=new Set(e.map(P)),n=[];for(const[e,o]of Object.entries(m())){const s=D[e],[i,...r]=o;if(!s||!i||t.has(i))continue;const a=r.find(e=>t.has(e));a&&n.push({tier:e,envVar:s,from:i,to:a})}return n}export class ClaudeCodeManager{static instance;settingsPath;mcpConfigPath;lastTierFallbacks=[];lastKept=[];constructor(){this.settingsPath=r(l(),".claude","settings.json"),this.mcpConfigPath=r(l(),".claude.json")}static getInstance(){return ClaudeCodeManager.instance||(ClaudeCodeManager.instance=new ClaudeCodeManager),ClaudeCodeManager.instance}ensureConfigDir(n){const o=a(n);e(o)||t(o,{recursive:!0})}atomicWrite(t,n){const r=`${t}.tmp`;try{o(r,n,"utf-8"),s(r,t)}catch(t){if(e(r))try{i(r)}catch{}throw t}}getSettings(){try{if(e(this.settingsPath)){const e=n(this.settingsPath,"utf-8");return JSON.parse(e)}}catch(e){c.warn("Failed to read Claude Code settings:",e),c.logError("ClaudeCodeManager.getSettings",e)}return{}}saveSettings(e){try{this.ensureConfigDir(this.settingsPath),this.atomicWrite(this.settingsPath,JSON.stringify(e,null,2))}catch(e){throw new Error(`Failed to save Claude Code settings: ${e}`)}}getMCPConfig(){try{if(e(this.mcpConfigPath)){const e=n(this.mcpConfigPath,"utf-8");return JSON.parse(e)}}catch(e){c.warn("Failed to read Claude Code MCP config:",e),c.logError("ClaudeCodeManager.getMCPConfig",e)}return{}}saveMCPConfig(e){try{this.ensureConfigDir(this.mcpConfigPath),this.atomicWrite(this.mcpConfigPath,JSON.stringify(e,null,2))}catch(e){throw new Error(`Failed to save Claude Code MCP config: ${e}`)}}loadPrivateConfig(e,t,n,o){this.ensureOnboardingCompleted(),f();const s=u(),i=s.env||{},{env:r,...a}=s,l=this.getSettings(),{ANTHROPIC_API_KEY:c,...m}=l.env||{},O={...m},C={},A=e=>{const n=(t[e]||"").trim();return n&&n!==g[e]?n:null},T=A("haiku"),v=A("sonnet"),P=A("opus"),D=new Set([T&&"haiku",v&&"sonnet",P&&"opus"].filter(Boolean)),L=resolveTierFallbacks(n).filter(e=>!D.has(e.tier));for(const e of L)C[e.envVar]=e.to;const y=new Set;T&&(C.ANTHROPIC_DEFAULT_HAIKU_MODEL=T),v&&(C.ANTHROPIC_DEFAULT_SONNET_MODEL=v),P&&(C.ANTHROPIC_DEFAULT_OPUS_MODEL=P,C.ANTHROPIC_MODEL=P),T&&y.add("ANTHROPIC_DEFAULT_HAIKU_MODEL"),v&&y.add("ANTHROPIC_DEFAULT_SONNET_MODEL"),P&&["ANTHROPIC_DEFAULT_OPUS_MODEL","ANTHROPIC_MODEL"].forEach(e=>y.add(e));const I=M(t);this.lastKept=[];for(const e of MODEL_ENV_VARS){const t=O[e],n=C[e];if(void 0!==n)h(S(e),t,n,{explicit:y.has(e),legacy:I})?O[e]=n:this.lastKept.push(`${e}=${t}`);else{if(void 0===t)continue;_(S(e),t,I)?(delete O[e],p(S(e))):this.lastKept.push(`${e}=${t}`)}}this.lastTierFallbacks=L.filter(e=>O[e.envVar]===e.to);const R={...l};for(const[e,t]of Object.entries(a))"model"!==e&&(e in R||(R[e]=t));R.showThinkingSummaries=!0;const U={...R,env:{...O,...Object.fromEntries(Object.entries(i).filter(([e])=>!(e in O))),ANTHROPIC_AUTH_TOKEN:e,ANTHROPIC_BASE_URL:d.getBaseUrl()}};E(d.getBaseUrl());const H=P??("string"==typeof a.model?a.model:void 0),F=l.model;void 0===H?void 0!==F&&_(N,F,I)&&(delete U.model,p(N)):h(N,F,H,{explicit:Boolean(P),legacy:I})?U.model=H:this.lastKept.push(`model=${String(F)}`),this.saveSettings(applyGatewayModels(U,o))}ensureOnboardingCompleted(){try{const e=this.getMCPConfig();e.hasCompletedOnboarding||this.saveMCPConfig({...e,hasCompletedOnboarding:!0})}catch(e){c.warn("Failed to ensure onboarding completed:",e),c.logError("ClaudeCodeManager.ensureOnboardingCompleted",e)}}unloadPrivateConfig(){const e=this.getSettings(),t=M(d.getModelsForTool("claude-code")),n=void 0!==e.model&&_(N,e.model,t);if(p(N),!e.env){if(n){const{model:t,...n}=e;this.saveSettings(n)}return}const{ANTHROPIC_AUTH_TOKEN:o,ANTHROPIC_BASE_URL:s,API_TIMEOUT_MS:i,CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:r,CLAUDE_CODE_AUTO_MODE_SERVER:a,...l}=e.env,c={...l};for(const e of MODEL_ENV_VARS)e in c&&_(S(e),c[e],t)&&delete c[e],p(S(e));const g={...applyGatewayModels({...e,env:c},[])};g.env=g.env||{},n&&delete g.model,g.env&&0===Object.keys(g.env).length&&delete g.env,this.saveSettings(g)}clearPinnedModels(e){const t=this.getSettings(),n=t.env,o=n?.ANTHROPIC_AUTH_TOKEN?Object.fromEntries(resolveTierFallbacks(e).map(e=>[e.envVar,e.to])):{},s=[];for(const e of MODEL_ENV_VARS)n&&e in n&&n[e]!==o[e]&&s.push(e);void 0!==t.model&&s.push("model");const i=Object.entries(o).some(([e,t])=>n?.[e]!==t);if(0===s.length&&!i)return[];const r={...t};if(delete r.model,n){const e={...n};for(const t of MODEL_ENV_VARS)delete e[t];Object.assign(e,o),0===Object.keys(e).length?delete r.env:r.env=e}this.saveSettings(r),p(N);for(const e of MODEL_ENV_VARS)o[e]?h(S(e),o[e],o[e]):p(S(e));return s}getLastKept(){return[...this.lastKept]}getLastTierFallbacks(){return[...this.lastTierFallbacks]}detectCurrentConfig(){try{const e=this.getSettings();return e.env&&e.env.ANTHROPIC_AUTH_TOKEN?{apiKey:e.env.ANTHROPIC_AUTH_TOKEN}:{apiKey:null}}catch{return{apiKey:null}}}getExperimentalFeature(e){const t=this.getSettings();return t.env?.[e]}setExperimentalFeature(e,t){const n=this.getSettings(),o=n.env||{},s={...n,env:{...o,[e]:t}};this.saveSettings(s)}removeExperimentalFeature(e){const t=this.getSettings();if(!t.env)return;const{[e]:n,...o}=t.env,s={...t,env:o};this.saveSettings(s)}}export const claudeCodeManager=ClaudeCodeManager.getInstance();
1
+ import{existsSync as e,mkdirSync as t,readFileSync as n,writeFileSync as o,renameSync as s,unlinkSync as i}from"fs";import{join as r,dirname as a}from"path";import{toolHome as l}from"./tools/types.js";import{logger as c}from"../utils/logger.js";import{configManager as d,DEFAULT_MODELS as g}from"./config.js";import{loadSettingsTemplate as u}from"./settings-template.js";import{cleanupAnthropicEnvVars as f}from"./env-cleanup.js";import{getClaudeCodeTierChains as m,getGatewayModelRules as O,getRetiredDefaultModelIds as C}from"./model-registry.js";import{claimField as h,forgetField as p,ownsValue as _,takeField as E}from"./written-values.js";import{noteWrittenGatewayUrl as A}from"./gateway-addresses.js";import{autoCompactTokens as T,modelBlurb as v,prettyModelName as P}from"./gateway-models.js";import{baseModelId as N}from"./model-catalog.js";export const MODEL_ENV_VARS=["ANTHROPIC_DEFAULT_HAIKU_MODEL","ANTHROPIC_DEFAULT_SONNET_MODEL","ANTHROPIC_DEFAULT_OPUS_MODEL","ANTHROPIC_DEFAULT_FABLE_MODEL","ANTHROPIC_MODEL","ANTHROPIC_REASONING_MODEL"];const S="claude-code.model",M=e=>`claude-code.env.${e}`;function D(e){const t=Object.values(m()).flat(),n=[...Object.values(g),...Object.values(e)].filter(e=>"string"==typeof e&&""!==e);return[...new Set(["opus[1m]",...n,...C(),...t])]}const L={opus:"ANTHROPIC_DEFAULT_OPUS_MODEL",sonnet:"ANTHROPIC_DEFAULT_SONNET_MODEL",haiku:"ANTHROPIC_DEFAULT_HAIKU_MODEL",fable:"ANTHROPIC_DEFAULT_FABLE_MODEL"},R="CLAUDE_CODE_MAX_CONTEXT_TOKENS";function y(){return r(d.getConfigDir(),"claude-code-picker.json")}function I(){try{const e=JSON.parse(n(y(),"utf-8")).ids;return Array.isArray(e)?e.map(String):[]}catch{return[]}}function U(e,t=[]){if(!e||"object"!=typeof e)return!1;const{options:n,replaceBuiltInOptions:o}=e;if(!Array.isArray(n)||o)return!1;const s=O(),i=new Set([...s.models.map(e=>e.id),...s.retired,...I(),...t]);return n.every(e=>e&&"object"==typeof e&&i.has(N(String(e.model))))}export function applyGatewayModels(e,n){if(void 0===n)return e;const s={...e};if(void 0!==s.modelPicker&&!U(s.modelPicker,n.map(e=>e.id)))return s;const i=U(s.modelPicker)?s.modelPicker.options.map(e=>N(e.model)):[],r={...s.env||{}},a={...s.modelSettings||{}};for(const e of i){if(!a[e])continue;const{autoCompactWindow:t,...n}=a[e];Object.keys(n).length>0?a[e]=n:delete a[e]}const l=e=>(e.contextWindow??0)>=1e6,g=n.filter(e=>!l(e)).map(e=>e.contextWindow).filter(e=>"number"==typeof e&&e>0);!function(e){try{t(d.getConfigDir(),{recursive:!0}),o(y(),JSON.stringify({ids:e})+"\n")}catch(e){c.logError("claudeCode.recordWrittenPickerIds",e)}}(n.map(e=>e.id));const u=e=>v(e.description,{millionContext:l(e)});if(0===n.length)delete s.modelPicker,delete r[R];else{s.modelPicker={options:n.map(e=>({model:l(e)?`${e.id}[1m]`:e.id,label:e.name||P(e.id),...u(e)?{description:u(e)}:{}}))},g.length>0?r[R]=String(Math.min(...g)):delete r[R];for(const e of n){if(!e.contextWindow)continue;const t=T(e.contextWindow,e.autoCompactTokens);a[e.id]={...a[e.id],autoCompactWindow:Math.min(Math.max(t,1e5),1e6)}}}return Object.keys(a).length>0?s.modelSettings=a:delete s.modelSettings,Object.keys(r).length>0?s.env=r:delete s.env,s}export function resolveTierFallbacks(e){if(!e||0===e.length)return[];const t=new Set(e.map(N)),n=[];for(const[e,o]of Object.entries(m())){const s=L[e],[i,...r]=o;if(!s||!i||t.has(i))continue;const a=r.find(e=>t.has(e));a&&n.push({tier:e,envVar:s,from:i,to:a})}return n}export class ClaudeCodeManager{static instance;settingsPath;mcpConfigPath;lastTierFallbacks=[];lastReplaced=[];constructor(){this.settingsPath=r(l(),".claude","settings.json"),this.mcpConfigPath=r(l(),".claude.json")}static getInstance(){return ClaudeCodeManager.instance||(ClaudeCodeManager.instance=new ClaudeCodeManager),ClaudeCodeManager.instance}ensureConfigDir(n){const o=a(n);e(o)||t(o,{recursive:!0})}atomicWrite(t,n){const r=`${t}.tmp`;try{o(r,n,"utf-8"),s(r,t)}catch(t){if(e(r))try{i(r)}catch{}throw t}}getSettings(){try{if(e(this.settingsPath)){const e=n(this.settingsPath,"utf-8");return JSON.parse(e)}}catch(e){c.warn("Failed to read Claude Code settings:",e),c.logError("ClaudeCodeManager.getSettings",e)}return{}}saveSettings(e){try{this.ensureConfigDir(this.settingsPath),this.atomicWrite(this.settingsPath,JSON.stringify(e,null,2))}catch(e){throw new Error(`Failed to save Claude Code settings: ${e}`)}}getMCPConfig(){try{if(e(this.mcpConfigPath)){const e=n(this.mcpConfigPath,"utf-8");return JSON.parse(e)}}catch(e){c.warn("Failed to read Claude Code MCP config:",e),c.logError("ClaudeCodeManager.getMCPConfig",e)}return{}}saveMCPConfig(e){try{this.ensureConfigDir(this.mcpConfigPath),this.atomicWrite(this.mcpConfigPath,JSON.stringify(e,null,2))}catch(e){throw new Error(`Failed to save Claude Code MCP config: ${e}`)}}loadPrivateConfig(e,t,n,o){this.ensureOnboardingCompleted(),f();const s=u(),i=s.env||{},{env:r,...a}=s,l=this.getSettings(),{ANTHROPIC_API_KEY:c,...m}=l.env||{},O={...m},C={},h=e=>{const n=(t[e]||"").trim();return n&&n!==g[e]?n:null},T=h("haiku"),v=h("sonnet"),P=h("opus"),N=new Set([T&&"haiku",v&&"sonnet",P&&"opus"].filter(Boolean)),L=resolveTierFallbacks(n).filter(e=>!N.has(e.tier));for(const e of L)C[e.envVar]=e.to;const R=new Set;T&&(C.ANTHROPIC_DEFAULT_HAIKU_MODEL=T),v&&(C.ANTHROPIC_DEFAULT_SONNET_MODEL=v),P&&(C.ANTHROPIC_DEFAULT_OPUS_MODEL=P,C.ANTHROPIC_MODEL=P),T&&R.add("ANTHROPIC_DEFAULT_HAIKU_MODEL"),v&&R.add("ANTHROPIC_DEFAULT_SONNET_MODEL"),P&&["ANTHROPIC_DEFAULT_OPUS_MODEL","ANTHROPIC_MODEL"].forEach(e=>R.add(e));const y=D(t);this.lastReplaced=[];for(const e of MODEL_ENV_VARS){const t=O[e],n=C[e];if(void 0!==n)void 0===t||t===n||_(M(e),t,y)||this.lastReplaced.push(`${e}=${t}`),O[e]=n,E(M(e),n);else{if(void 0===t)continue;_(M(e),t,y)||this.lastReplaced.push(`${e}=${t}`),delete O[e],p(M(e))}}this.lastTierFallbacks=L.filter(e=>O[e.envVar]===e.to);const I={...l};for(const[e,t]of Object.entries(a))"model"!==e&&(e in I||(I[e]=t));I.showThinkingSummaries=!0;const U={...I,env:{...O,...Object.fromEntries(Object.entries(i).filter(([e])=>!(e in O))),ANTHROPIC_AUTH_TOKEN:e,ANTHROPIC_BASE_URL:d.getBaseUrl()}};A(d.getBaseUrl());const H=P??("string"==typeof a.model?a.model:void 0),F=l.model,b=void 0!==F&&F!==H&&!_(S,F,y);void 0===H?(delete U.model,p(S)):(U.model=H,E(S,H)),b&&this.lastReplaced.push(`model=${String(F)}`),this.saveSettings(applyGatewayModels(U,o))}ensureOnboardingCompleted(){try{const e=this.getMCPConfig();e.hasCompletedOnboarding||this.saveMCPConfig({...e,hasCompletedOnboarding:!0})}catch(e){c.warn("Failed to ensure onboarding completed:",e),c.logError("ClaudeCodeManager.ensureOnboardingCompleted",e)}}unloadPrivateConfig(){const e=this.getSettings(),t=D(d.getModelsForTool("claude-code")),n=void 0!==e.model&&_(S,e.model,t);if(p(S),!e.env){if(n){const{model:t,...n}=e;this.saveSettings(n)}return}const{ANTHROPIC_AUTH_TOKEN:o,ANTHROPIC_BASE_URL:s,API_TIMEOUT_MS:i,CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC:r,CLAUDE_CODE_AUTO_MODE_SERVER:a,...l}=e.env,c={...l};for(const e of MODEL_ENV_VARS)e in c&&_(M(e),c[e],t)&&delete c[e],p(M(e));const g={...applyGatewayModels({...e,env:c},[])};g.env=g.env||{},n&&delete g.model,g.env&&0===Object.keys(g.env).length&&delete g.env,this.saveSettings(g)}clearPinnedModels(e){const t=this.getSettings(),n=t.env,o=n?.ANTHROPIC_AUTH_TOKEN?Object.fromEntries(resolveTierFallbacks(e).map(e=>[e.envVar,e.to])):{},s=[];for(const e of MODEL_ENV_VARS)n&&e in n&&n[e]!==o[e]&&s.push(e);void 0!==t.model&&s.push("model");const i=Object.entries(o).some(([e,t])=>n?.[e]!==t);if(0===s.length&&!i)return[];const r={...t};if(delete r.model,n){const e={...n};for(const t of MODEL_ENV_VARS)delete e[t];Object.assign(e,o),0===Object.keys(e).length?delete r.env:r.env=e}this.saveSettings(r),p(S);for(const e of MODEL_ENV_VARS)o[e]?h(M(e),o[e],o[e]):p(M(e));return s}getLastReplaced(){return[...this.lastReplaced]}getLastTierFallbacks(){return[...this.lastTierFallbacks]}detectCurrentConfig(){try{const e=this.getSettings();return e.env&&e.env.ANTHROPIC_AUTH_TOKEN?{apiKey:e.env.ANTHROPIC_AUTH_TOKEN}:{apiKey:null}}catch{return{apiKey:null}}}getExperimentalFeature(e){const t=this.getSettings();return t.env?.[e]}setExperimentalFeature(e,t){const n=this.getSettings(),o=n.env||{},s={...n,env:{...o,[e]:t}};this.saveSettings(s)}removeExperimentalFeature(e){const t=this.getSettings();if(!t.env)return;const{[e]:n,...o}=t.env,s={...t,env:o};this.saveSettings(s)}}export const claudeCodeManager=ClaudeCodeManager.getInstance();
@@ -5,3 +5,14 @@
5
5
  export declare function mirrorFileUrl(mirror: string, file: string, oldReleaseTag?: string): string;
6
6
  /** A page people can open in a browser for the mirror: the release page of its tag. */
7
7
  export declare function mirrorPageUrl(mirror: string): string;
8
+ /**
9
+ * Where to fetch a mirror file from, in order. With a download counter (`installMirror.downloadCounter`: it logs the
10
+ * download, then redirects to the same path on cnb.cool) a cnb.cool release file is tried through it first, then
11
+ * directly; anything else (no counter, another host, git raw files) is fetched directly.
12
+ */
13
+ export declare function downloadUrls(url: string, counter: string | undefined): string[];
14
+ /**
15
+ * Runs `fetchOne` on each of `downloadUrls(url, counter)` until one succeeds; a failure of the counter (unreachable,
16
+ * an error status, a broken transfer) falls back to the direct URL. Throws the direct URL's error.
17
+ */
18
+ export declare function withDownloadFallback<T>(url: string, counter: string | undefined, fetchOne: (url: string) => Promise<T>): Promise<T>;
@@ -1 +1 @@
1
- const e=/\/-\/releases\/latest$/;export function mirrorFileUrl(r,t,l){const s=r.replace(/\/+$/,"");if(e.test(s)){const r=s.replace(e,"");return l?`${r}/-/releases/download/${l}/${t}`:`${r}/-/releases/latest/download/${t}`}return`${s}/${t}`}export function mirrorPageUrl(e){const r=e.replace(/\/+$/,""),t=/^(.*\/-\/releases)\/download\/([^/]+)$/.exec(r);return t?`${t[1]}/tag/${t[2]}`:r.replace(/\/-\/releases\/latest\/download$/,"/-/releases/latest")}
1
+ const e=/\/-\/releases\/latest$/;export function mirrorFileUrl(t,r,o){const l=t.replace(/\/+$/,"");if(e.test(l)){const t=l.replace(e,"");return o?`${t}/-/releases/download/${o}/${r}`:`${t}/-/releases/latest/download/${r}`}return`${l}/${r}`}export function mirrorPageUrl(e){const t=e.replace(/\/+$/,""),r=/^(.*\/-\/releases)\/download\/([^/]+)$/.exec(t);return r?`${r[1]}/tag/${r[2]}`:t.replace(/\/-\/releases\/latest\/download$/,"/-/releases/latest")}const t=/^\/[^?#]+\/-\/releases\/(?:latest\/download|download\/[^/]+)\/[^/]+$/;export function downloadUrls(e,r){if(!r||!e.startsWith("https://cnb.cool/"))return[e];const o=e.slice(16);return t.test(o)?[`${r.replace(/\/+$/,"")}${o}`,e]:[e]}export async function withDownloadFallback(e,t,r){const o=downloadUrls(e,t);for(const e of o.slice(0,-1))try{return await r(e)}catch{}return r(o[o.length-1])}
@@ -1 +1 @@
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
+ 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 R,U=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),R=M(t.catalog),o.loadPrivateConfig(t.apiKey,t.models,t.catalog?.models,R);const s=e(c(),".local","bin","win32"===process.platform?"claude.exe":"claude"),a=S(claudeCodeAdapter.installSpec)[0]?.path??(y(s)?s:null);U=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=[];U?.installed.length&&(e.push({kind:"summary",text:s.t("tools.claude_code.plugins_installed",{count:String(U.installed.length)})}),e.push({kind:"detail",text:U.installed.join(", ")})),"git"===U?.skipped?e.push({kind:"action",text:s.t("tools.claude_code.plugins_need_git")}):("marketplace"===U?.skipped||U?.failed.length)&&e.push({kind:"action",text:s.t("tools.claude_code.plugins_failed")}),R&&R.length>0&&(e.push({kind:"summary",text:s.t("tools.claude_code.gateway_models",{count:String(R.length),vendors:l(R.map(e=>e.id)).join(" / ")})}),e.push({kind:"detail",text:R.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.getLastReplaced();n.length>0&&e.push({kind:"summary",text:s.t("tools.claude_code.replaced_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 +1 @@
1
- import{execFileSync as e}from"child_process";import{createHash as r}from"crypto";import{createReadStream as t,createWriteStream as s,existsSync as o,readdirSync as i,readFileSync as n}from"fs";import{copyFile as a,mkdir as l,readFile as c,rename as u,rm as f,writeFile as p}from"fs/promises";import{isAbsolute as d,join as m,normalize as h,sep as w}from"path";import{Readable as g,Writable as b}from"stream";import{pipeline as D}from"stream/promises";import*as v from"zlib";import{logger as y}from"../../utils/logger.js";import{brandEnv as k}from"../brand.js";import{downloadNativeBinary as $,nativeLayout as C,nativePlatformKey as x}from"./claude-native-mirror.js";import{WINDOWS_PACKAGE_FAMILIES as N}from"./desktop-process.js";import{toolHome as A}from"./types.js";import{mirrorFileUrl as P}from"../mirror-url.js";import{powerShellEnv as L}from"../powershell-env.js";export function readDesktopCliPin(e,r,t=!1){const s=e.indexOf('claude-code-releases","sdkWrapperVersion"');if(s<0)return null;const o=e.lastIndexOf("JSON.parse('",s),i=e.indexOf("')",s);if(o<0||i<0)return null;try{const s=JSON.parse(e.subarray(o+12,i).toString("utf-8")),n="string"==typeof s.version?s.version:"",a=s.manifest?.platforms?.[r],l=t?a?.bundle?.checksum:a?.checksum;return/^\d+\.\d+\.\d+$/.test(n)&&"string"==typeof l&&/^[0-9a-f]{64}$/.test(l)?{version:n,checksum:l}:null}catch{return null}}function O(){const r=m(process.env.LOCALAPPDATA||"","AnthropicClaude");if(process.env.LOCALAPPDATA&&o(r)){const e=i(r).filter(e=>/^app-\d+\.\d+\.\d+$/.test(e)).sort((e,r)=>r.localeCompare(e,void 0,{numeric:!0}));for(const t of e){const e=m(r,t,"resources","app.asar");if(o(e))return e}}try{const r=e("powershell.exe",["-NoProfile","-Command",`Get-AppxPackage | Where-Object { @(${N.map(e=>`'${e}'`).join(",")}) -contains $_.PackageFamilyName } | ForEach-Object { $_.InstallLocation }`],{encoding:"utf-8",timeout:15e3,windowsHide:!0,stdio:["ignore","pipe","ignore"],env:L()});for(const e of r.split(/\r?\n/).map(e=>e.trim()).filter(Boolean)){const r=m(e,"app","resources","app.asar");if(o(r))return r}}catch(e){y.logError("claude-desktop-cli.windowsAsarPath",e)}return null}function E(){if(k("TEST_HOME")?.trim())return null;for(const e of["/usr/lib/claude-desktop","/opt/Claude"]){const r=m(e,"resources","app.asar");if(o(r))return r}return null}function j(){for(const e of["/Applications/Claude.app",m(A(),"Applications","Claude.app")]){const r=m(e,"Contents","Resources","app.asar");if(o(r))return r}return null}export function installedDesktopAsarPath(){return"win32"===process.platform?O():"darwin"===process.platform?j():"linux"===process.platform?E():null}class S extends b{dest;buffer=Buffer.alloc(0);remaining=0;padding=0;file=null;longName=null;collectingLongName=null;constructor(e){super(),this.dest=e}_write(e,r,t){this.buffer=this.buffer.length?Buffer.concat([this.buffer,e]):e,this.drain().then(()=>t()).catch(t)}_final(e){this.remaining>0?e(new Error("archive ends inside an entry")):e()}target(e){const r=h(e);if(!r||d(r)||".."===r||r.startsWith(`..${w}`))throw new Error(`unsafe path in archive: ${e}`);return m(this.dest,r)}async closeFile(){const e=this.file;this.file=null,e&&await new Promise((r,t)=>e.end(e=>e?t(e):r()))}async drain(){for(;;){if(this.remaining>0){if(0===this.buffer.length)return;const e=this.buffer.subarray(0,Math.min(this.remaining,this.buffer.length));this.buffer=this.buffer.subarray(e.length),this.remaining-=e.length,this.collectingLongName?this.collectingLongName.push(e):this.file&&!this.file.write(e)&&await new Promise(e=>this.file.once("drain",()=>e())),0===this.remaining&&(this.collectingLongName&&(this.longName=Buffer.concat(this.collectingLongName).toString("utf-8").replace(/\0.*$/s,""),this.collectingLongName=null),await this.closeFile());continue}if(this.padding>0){if(this.buffer.length<this.padding)return;this.buffer=this.buffer.subarray(this.padding),this.padding=0}if(this.buffer.length<512)return;const e=this.buffer.subarray(0,512);if(this.buffer=this.buffer.subarray(512),e.every(e=>0===e))continue;const r=(r,t)=>e.subarray(r,r+t).toString("utf-8").replace(/\0.*$/s,""),t=r(345,155);let o=t?`${t}/${r(0,100)}`:r(0,100);null!==this.longName&&(o=this.longName,this.longName=null);const i=parseInt(r(124,12).trim()||"0",8),n=511&parseInt(r(100,8).trim()||"644",8),a=r(156,1)||"0";if(this.remaining=i,this.padding=(512-i%512)%512,"L"===a)this.collectingLongName=[];else if("x"===a||"g"===a);else if("5"===a)await l(this.target(o),{recursive:!0});else{if("0"!==a)throw new Error(`unexpected entry type ${a} in archive: ${o}`);{const e=this.target(o);await l(m(e,".."),{recursive:!0}),this.file=s(e,{mode:n||420}),0===i&&await this.closeFile()}}}}}export async function installDesktopCli(e){const s=readDesktopCliPin(e.asar,e.platformKey,e.bundle);if(!s)return{status:"skipped",reason:"unknown app layout"};if(e.bundle&&!e.download)return{status:"skipped",reason:"no bundle mirror"};const i=e.platformKey.startsWith("win32")?"claude.exe":"claude",n=m(e.userDataDir,"claude-code",s.version),d=m(n,s.checksum.slice(0,12)),h=e.bundle?m(d,"claude.app","Contents","MacOS","claude"):m(d,i),w=m(d,".verified");try{if(o(h)&&(await c(w,"utf-8")).trim()===s.checksum)return{status:"present",version:s.version}}catch{}await l(n,{recursive:!0});const g=m(n,`.partial-${s.checksum.slice(0,12)}`),y=`${g}.download`;try{await f(w,{force:!0}),await f(g,{recursive:!0,force:!0});let i="mirror";if(e.bundle){if(e.onDownload?.(s.version),await e.download(s.version,y),await async function(e,s,o){const i=r("sha256");if(await D(t(e),new b({write(e,r,t){i.update(e),t()}})),i.digest("hex")!==s)throw new Error("downloaded bundle does not match the app's checksum");const n=v.createZstdDecompress;if(!n)throw new Error(`Node ${process.version} cannot decompress zstd (needs 22.15 or newer)`);await D(t(e),n(),new S(o))}(y,s.checksum,g),!o(m(g,"claude.app","Contents","MacOS","claude")))throw new Error("bundle has no claude.app");await f(d,{recursive:!0,force:!0}),await u(g,d)}else{const r=e.localVersionsDir?m(e.localVersionsDir,s.version):null;if(r&&o(r))await a(r,g),i="local";else{e.onDownload?.(s.version);const r=e.download??((r,t)=>$(e.platformKey,r,t));await r(s.version,g)}await l(d,{recursive:!0}),await u(g,h)}return await p(w,s.checksum),{status:"installed",version:s.version,source:i}}finally{await f(g,{recursive:!0,force:!0}),await f(y,{force:!0}),await f(`${g}.download`,{force:!0})}}let F=(...e)=>fetch(...e);export function setDesktopCliFetchForTests(e){F=e}export async function ensureDesktopCli(e){const r=x();if(!r)return{status:"skipped",reason:"unsupported architecture"};if("win32"===process.platform){const t=O();return t?installDesktopCli({userDataDir:e.userDataDir,asar:n(t),platformKey:r,localVersionsDir:C().versionsDir,onDownload:e.onDownload}):{status:"skipped",reason:"app.asar not found"}}if("darwin"===process.platform){const t=j();if(!t)return{status:"skipped",reason:"app.asar not found"};const{mirror:o,desktopVersion:i}=e;return installDesktopCli({userDataDir:e.userDataDir,asar:n(t),platformKey:r,bundle:!0,onDownload:e.onDownload,download:o&&i?(e,t)=>async function(e,r){const t=await F(e,{signal:AbortSignal.timeout(9e5)});if(!t.ok||!t.body)throw new Error(`${e}: HTTP ${t.status}`);await D(g.fromWeb(t.body),s(r))}(P(o,`claude-code-${e}-${r}.app.tar.zst`,`v${i}`),t):void 0})}if("linux"===process.platform){const t=E();return t?installDesktopCli({userDataDir:e.userDataDir,asar:n(t),platformKey:r.replace(/-musl$/,""),localVersionsDir:r.endsWith("-musl")?void 0:C().versionsDir,onDownload:e.onDownload}):{status:"skipped",reason:"app.asar not found"}}return{status:"skipped",reason:"unsupported platform"}}
1
+ import{execFileSync as e}from"child_process";import{createHash as r}from"crypto";import{createReadStream as t,createWriteStream as s,existsSync as o,readdirSync as n,readFileSync as i}from"fs";import{copyFile as a,mkdir as l,readFile as c,rename as u,rm as f,writeFile as p}from"fs/promises";import{isAbsolute as d,join as m,normalize as h,sep as w}from"path";import{Readable as g,Writable as b}from"stream";import{pipeline as D}from"stream/promises";import*as v from"zlib";import{logger as y}from"../../utils/logger.js";import{brand as k,brandEnv as $}from"../brand.js";import{downloadNativeBinary as C,nativeLayout as x,nativePlatformKey as N}from"./claude-native-mirror.js";import{WINDOWS_PACKAGE_FAMILIES as A}from"./desktop-process.js";import{toolHome as P}from"./types.js";import{mirrorFileUrl as L,withDownloadFallback as O}from"../mirror-url.js";import{powerShellEnv as E}from"../powershell-env.js";export function readDesktopCliPin(e,r,t=!1){const s=e.indexOf('claude-code-releases","sdkWrapperVersion"');if(s<0)return null;const o=e.lastIndexOf("JSON.parse('",s),n=e.indexOf("')",s);if(o<0||n<0)return null;try{const s=JSON.parse(e.subarray(o+12,n).toString("utf-8")),i="string"==typeof s.version?s.version:"",a=s.manifest?.platforms?.[r],l=t?a?.bundle?.checksum:a?.checksum;return/^\d+\.\d+\.\d+$/.test(i)&&"string"==typeof l&&/^[0-9a-f]{64}$/.test(l)?{version:i,checksum:l}:null}catch{return null}}function j(){const r=m(process.env.LOCALAPPDATA||"","AnthropicClaude");if(process.env.LOCALAPPDATA&&o(r)){const e=n(r).filter(e=>/^app-\d+\.\d+\.\d+$/.test(e)).sort((e,r)=>r.localeCompare(e,void 0,{numeric:!0}));for(const t of e){const e=m(r,t,"resources","app.asar");if(o(e))return e}}try{const r=e("powershell.exe",["-NoProfile","-Command",`Get-AppxPackage | Where-Object { @(${A.map(e=>`'${e}'`).join(",")}) -contains $_.PackageFamilyName } | ForEach-Object { $_.InstallLocation }`],{encoding:"utf-8",timeout:15e3,windowsHide:!0,stdio:["ignore","pipe","ignore"],env:E()});for(const e of r.split(/\r?\n/).map(e=>e.trim()).filter(Boolean)){const r=m(e,"app","resources","app.asar");if(o(r))return r}}catch(e){y.logError("claude-desktop-cli.windowsAsarPath",e)}return null}function S(){if($("TEST_HOME")?.trim())return null;for(const e of["/usr/lib/claude-desktop","/opt/Claude"]){const r=m(e,"resources","app.asar");if(o(r))return r}return null}function F(){for(const e of["/Applications/Claude.app",m(P(),"Applications","Claude.app")]){const r=m(e,"Contents","Resources","app.asar");if(o(r))return r}return null}export function installedDesktopAsarPath(){return"win32"===process.platform?j():"darwin"===process.platform?F():"linux"===process.platform?S():null}class T extends b{dest;buffer=Buffer.alloc(0);remaining=0;padding=0;file=null;longName=null;collectingLongName=null;constructor(e){super(),this.dest=e}_write(e,r,t){this.buffer=this.buffer.length?Buffer.concat([this.buffer,e]):e,this.drain().then(()=>t()).catch(t)}_final(e){this.remaining>0?e(new Error("archive ends inside an entry")):e()}target(e){const r=h(e);if(!r||d(r)||".."===r||r.startsWith(`..${w}`))throw new Error(`unsafe path in archive: ${e}`);return m(this.dest,r)}async closeFile(){const e=this.file;this.file=null,e&&await new Promise((r,t)=>e.end(e=>e?t(e):r()))}async drain(){for(;;){if(this.remaining>0){if(0===this.buffer.length)return;const e=this.buffer.subarray(0,Math.min(this.remaining,this.buffer.length));this.buffer=this.buffer.subarray(e.length),this.remaining-=e.length,this.collectingLongName?this.collectingLongName.push(e):this.file&&!this.file.write(e)&&await new Promise(e=>this.file.once("drain",()=>e())),0===this.remaining&&(this.collectingLongName&&(this.longName=Buffer.concat(this.collectingLongName).toString("utf-8").replace(/\0.*$/s,""),this.collectingLongName=null),await this.closeFile());continue}if(this.padding>0){if(this.buffer.length<this.padding)return;this.buffer=this.buffer.subarray(this.padding),this.padding=0}if(this.buffer.length<512)return;const e=this.buffer.subarray(0,512);if(this.buffer=this.buffer.subarray(512),e.every(e=>0===e))continue;const r=(r,t)=>e.subarray(r,r+t).toString("utf-8").replace(/\0.*$/s,""),t=r(345,155);let o=t?`${t}/${r(0,100)}`:r(0,100);null!==this.longName&&(o=this.longName,this.longName=null);const n=parseInt(r(124,12).trim()||"0",8),i=511&parseInt(r(100,8).trim()||"644",8),a=r(156,1)||"0";if(this.remaining=n,this.padding=(512-n%512)%512,"L"===a)this.collectingLongName=[];else if("x"===a||"g"===a);else if("5"===a)await l(this.target(o),{recursive:!0});else{if("0"!==a)throw new Error(`unexpected entry type ${a} in archive: ${o}`);{const e=this.target(o);await l(m(e,".."),{recursive:!0}),this.file=s(e,{mode:i||420}),0===n&&await this.closeFile()}}}}}export async function installDesktopCli(e){const s=readDesktopCliPin(e.asar,e.platformKey,e.bundle);if(!s)return{status:"skipped",reason:"unknown app layout"};if(e.bundle&&!e.download)return{status:"skipped",reason:"no bundle mirror"};const n=e.platformKey.startsWith("win32")?"claude.exe":"claude",i=m(e.userDataDir,"claude-code",s.version),d=m(i,s.checksum.slice(0,12)),h=e.bundle?m(d,"claude.app","Contents","MacOS","claude"):m(d,n),w=m(d,".verified");try{if(o(h)&&(await c(w,"utf-8")).trim()===s.checksum)return{status:"present",version:s.version}}catch{}await l(i,{recursive:!0});const g=m(i,`.partial-${s.checksum.slice(0,12)}`),y=`${g}.download`;try{await f(w,{force:!0}),await f(g,{recursive:!0,force:!0});let n="mirror";if(e.bundle){if(e.onDownload?.(s.version),await e.download(s.version,y),await async function(e,s,o){const n=r("sha256");if(await D(t(e),new b({write(e,r,t){n.update(e),t()}})),n.digest("hex")!==s)throw new Error("downloaded bundle does not match the app's checksum");const i=v.createZstdDecompress;if(!i)throw new Error(`Node ${process.version} cannot decompress zstd (needs 22.15 or newer)`);await D(t(e),i(),new T(o))}(y,s.checksum,g),!o(m(g,"claude.app","Contents","MacOS","claude")))throw new Error("bundle has no claude.app");await f(d,{recursive:!0,force:!0}),await u(g,d)}else{const r=e.localVersionsDir?m(e.localVersionsDir,s.version):null;if(r&&o(r))await a(r,g),n="local";else{e.onDownload?.(s.version);const r=e.download??((r,t)=>C(e.platformKey,r,t));await r(s.version,g)}await l(d,{recursive:!0}),await u(g,h)}return await p(w,s.checksum),{status:"installed",version:s.version,source:n}}finally{await f(g,{recursive:!0,force:!0}),await f(y,{force:!0}),await f(`${g}.download`,{force:!0})}}let K=(...e)=>fetch(...e);export function setDesktopCliFetchForTests(e){K=e}export async function ensureDesktopCli(e){const r=N();if(!r)return{status:"skipped",reason:"unsupported architecture"};if("win32"===process.platform){const t=j();return t?installDesktopCli({userDataDir:e.userDataDir,asar:i(t),platformKey:r,localVersionsDir:x().versionsDir,onDownload:e.onDownload}):{status:"skipped",reason:"app.asar not found"}}if("darwin"===process.platform){const t=F();if(!t)return{status:"skipped",reason:"app.asar not found"};const{mirror:o,desktopVersion:n}=e;return installDesktopCli({userDataDir:e.userDataDir,asar:i(t),platformKey:r,bundle:!0,onDownload:e.onDownload,download:o&&n?(e,t)=>O(L(o,`claude-code-${e}-${r}.app.tar.zst`,`v${n}`),k().installMirror?.downloadCounter,e=>async function(e,r){const t=await K(e,{signal:AbortSignal.timeout(9e5)});if(!t.ok||!t.body)throw new Error(`${e}: HTTP ${t.status}`);await D(g.fromWeb(t.body),s(r))}(e,t)):void 0})}if("linux"===process.platform){const t=S();return t?installDesktopCli({userDataDir:e.userDataDir,asar:i(t),platformKey:r.replace(/-musl$/,""),localVersionsDir:r.endsWith("-musl")?void 0:x().versionsDir,onDownload:e.onDownload}):{status:"skipped",reason:"app.asar not found"}}return{status:"skipped",reason:"unsupported platform"}}
@@ -1 +1 @@
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}}
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 d from"@iarna/toml";import{logger as c}from"../../utils/logger.js";import{i18n as u}from"../i18n.js";import{backupBeforeWrite as p,atomicWriteFile as m}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{ownsValue as S,takeField as C}from"../written-values.js";import{configManager as O}from"../config.js";import{maskHome as M,track as A}from"../telemetry.js";import{buildCodexCatalog as E,catalogRejections as N,codexCatalogPath as P,fillFromOlderEntries as T,installedCodexBinaries as D,loadBundledCodexModels as $,loadPreviousCodexModels as I,previousGatewayModelIds as L}from"./codex-catalog.js";import{gatewayModelSpecs as J,modelFamily as G}from"../gateway-models.js";import{isOurGatewayUrl as R,noteWrittenGatewayUrl as K}from"../gateway-addresses.js";import{findInstalls as X,mirrorInstallCommand as B,brandInstallScripts as U}from"./tool-installs.js";import{chatgptDesktopApp as W}from"./chatgpt-desktop.js";const q=()=>f(),z=()=>a(q(),"config.toml"),Y="sessions_move_declined",F=["browser_use","browser_use_external","computer_use"],H="desktop_features_restored";function Q(e){if(!0===O.getToolSetting("codex",H))return!1;const t=e.features,o=de(t)&&F.every(e=>!1===t[e]);if(O.setToolSetting("codex",H,!0),!o)return!1;for(const e of F)delete t[e];return!0}export function codexWorkModeOn(){try{const e=ue();return e.model_provider===te&&de(e.desktop)&&"STEPS_PROSE"===e.desktop.conversationDetailMode}catch{return!1}}function V(){try{if(de(ue().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 z()}const Z=()=>a(q(),"auth.json"),ee="OPENAI_API_KEY",te="custom",oe="high",re=["gpt-5.5","gpt-5.6-sol","gpt-6-astra"],ne=["high","xhigh"],se={goals:!0,js_repl:!1};let ie=[];const le=1e6,ae=9e5;export const CODEX_ONE_MILLION_CONTEXT_SETTING="one_million_context";function de(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function ce(e,t){return de(e[t])||(e[t]={}),e[t]}function ue(){if(!t(z()))return{};const e=n(z(),"utf-8");if(!e.trim())return{};try{const t=d.parse(e);if(!de(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 pe(){if(!t(Z()))return{};try{const e=JSON.parse(n(Z(),"utf-8"));return de(e)?e:{}}catch{return{}}}let me=null;function fe(e){const t=e.profiles;if(de(t)){for(const[e,o]of Object.entries(t))de(o)&&2===Object.keys(o).length&&o.model_provider===te&&o.model===e&&delete t[e];0===Object.keys(t).length&&delete e.profiles}}let _e=null;const ge=()=>a(O.getConfigDir(),"codex-catalog-check.json");function xe(e){const o=P();t(o)&&n(o,"utf-8")===e||(p(o),m(o,e))}function he(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(ge(),"utf-8")).signature===e}catch{return!1}}(s))return[];const a=N(P(),r);return 0===a.length&&function(e){try{o(O.getConfigDir(),{recursive:!0}),l(ge(),JSON.stringify({signature:e})+"\n")}catch(e){c.logError("codexAdapter.rememberAccepted",e)}}(s),a}function ye(e,t,o){const r=!1!==t.settings?.one_million_context;!function(e){e.model_context_window===le&&delete e.model_context_window,e.model_auto_compact_token_limit===ae&&delete e.model_auto_compact_token_limit}(e);const n=()=>{e.model_catalog_json===P()&&delete e.model_catalog_json,r&&(e.model_context_window=le,e.model_auto_compact_token_limit=ae)},i=$()??I();if(!i)return c.logError("codexAdapter.writeModelCatalog",new Error("no Codex binary found; model catalog skipped")),_e="skipped",void n();const l=t.catalog,a=e=>E({bundled:e,specs:J("codex",l?.clientModels),...l?{keyModels:l.models}:{},gatewayAvailable:l?.models??L(),oneMillion:r,selectedModel:o,..."gateway"===l?.oneMillionSource?{claudeOneMillion:l.oneMillion}:{}}),d=e=>JSON.stringify(e,null,2)+"\n";let u=a(i);xe(d(u));const p=D(),m=he(d(u),p);if(m.length>0){const e=Date.now();let t=!1;for(const e of m){const o=$(e.bin);if(o){for(const e of[{models:T(u.models,o)},{models:T(a(o).models,o)}])if(xe(d(e)),0===he(d(e),p).length){u=e,t=!0;break}if(t)break}}if(A("codex-catalog",t?"fallback":"fail",{duration_ms:Date.now()-e,error:m[0].error,detail:{rejected_by:m.map(e=>({version:e.version,path:M(e.bin)}))}}),!t)return _e={rejectedBy:m[0]},s(P(),{force:!0}),void n()}_e={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=P()}export function codexCatalogRejection(){let e;try{e=ue()}catch{return null}return e.model_catalog_json===P()&&t(P())?N(P())[0]??null:null}export function setCodexOneMillionContext(e,t){const o=ue(),r=d.stringify(o),n="string"==typeof o.model?o.model:j("codex");ye(o,{settings:{[CODEX_ONE_MILLION_CONTEXT_SETTING]:e},catalog:t},n);const s=d.stringify(o);s!==r&&(p(z()),m(z(),s))}const ke={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:U("codex"),brew:"codex"};function be(e){const t=de(e.model_providers)?e.model_providers[te]:void 0;if(!de(t))return null;const o="string"==typeof t.base_url?t.base_url.trim():"";return o&&!R(o)?o:null}let ve=null;function we(){if("skipped"===_e)return 0===X(ke).length?[]:[{kind:"action",text:u.t("tools.codex.catalog_skipped")}];if(!_e)return[];if("rejectedBy"in _e){const{bin:e,version:t}=_e.rejectedBy;return[{kind:"action",text:u.t("tools.codex.catalog_rejected",{path:e,version:t??"?"})}]}const e=new Map;for(const t of _e.listed)e.set(G(t.id),(e.get(G(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(_e.listed.length),breakdown:t})},{kind:"detail",text:_e.listed.map(e=>e.name).join(", ")},...codexWorkModeOn()||V()?[{kind:"action",text:u.t(codexWorkModeOn()?"tools.codex.work_mode_on":"tools.codex.work_mode_hint")}]:[]]}export const codexAdapter={name:"codex",companionApps:[W],displayName:"Codex",command:"codex",installCommand:B(ke),installSpec:ke,configPath:z(),sessions:{format:b,files:()=>[...v(a(f(),"sessions")),...v(a(f(),"archived_sessions"))],resumeCommand:e=>({command:"codex",args:["resume",e]})},wantsModelCatalog:!0,listedModels(){if(ue().model_catalog_json!==P())return null;try{return(JSON.parse(n(P(),"utf-8")).models??[]).filter(e=>"list"===e.visibility).map(e=>String(e.slug))}catch{return null}},refreshModelMenu(e){if(ue().model_catalog_json!==P())return;setCodexOneMillionContext(!1!==e.settings?.one_million_context,e.catalog);const t=ue(),o=function(e,t){const o=de(e.model_providers)?e.model_providers[te]:void 0;return!(!de(o)||o.base_url!==t||!0===o.supports_standalone_web_search||(o.supports_standalone_web_search=!0,0))}(t,x(e.baseUrl));(Q(t)||o)&&(p(z()),m(z(),d.stringify(t)))},async followUp(){if(ue().model_provider!==te)return null;const e=await h(te,{dryRun:!0}),t=Math.max(e.moved.length,e.dbRows);if(0===t)return null;const o=O.getToolSettings("codex")[Y];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(te),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:te})},{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(){O.setToolSetting("codex",Y,t)}}},applyNotes(){const e=[];return ve&&e.push({kind:"summary",text:u.t("tools.codex.provider_replaced",{url:ve})}),ie.length>0&&e.push({kind:"summary",text:u.t("tools.codex.replaced_user_settings",{values:ie.join(", ")})}),[...e,...we()]},planNotes(){let e;try{e=ue()}catch{return[]}const t=[],o=be(e);return o?t.push(u.t("tools.codex.plan_replace_provider",{url:o})):"string"==typeof e.model_provider&&e.model_provider!==te&&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=ue();ie=[];const i=w().retired,l=(e,t,o,r,n)=>{void 0===t||t===o||"string"==typeof t&&i.includes(t)||S(e,t,r)||ie.push(`${n} = ${String(t)}`),C(e,o)};l("codex.model",s.model,r,re,"model"),s.model=r,s.model_provider=te,l("codex.model_reasoning_effort",s.model_reasoning_effort,oe,ne,"model_reasoning_effort"),s.model_reasoning_effort=oe;const a="string"==typeof s.model?s.model:r;ye(s,e,a);const c=ce(s,"model_providers");ve=be(s),K(n);const u=de(c[te])?{...c[te]}:{};delete u.env_key;const{experimental_bearer_token:f,...g}=u;c[te]={...g,name:"custom",wire_api:"responses",requires_openai_auth:!0,supports_standalone_web_search:!0,base_url:n},fe(s),ce(ce(s,"tui"),"model_availability_nux")[a]=4;const h=ce(s,"features");for(const[e,t]of Object.entries(se))l(`codex.features.${e}`,void 0===h[e]?void 0:String(h[e]),String(t),[String(t)],`features.${e}`),h[e]=t;Q(s),p(z()),m(z(),d.stringify(s)),function(e){const t=e.trim();if(!t)return;const o={...pe(),auth_mode:"apikey",[ee]:t};p(Z()),m(Z(),JSON.stringify(o,null,2)+"\n",384)}(e.apiKey)},holdsOurConfig(e){const t=pe()[ee];return"string"==typeof t&&e.includes(t.trim())},unloadPrivateConfig(e){if(me=function(e){const t=pe(),o="string"==typeof t[ee]?t[ee].trim():"";if(!o)return de(t.tokens)?"chatgpt":null;if(!e.includes(o))return"other_key";const{[ee]:r,auth_mode:n,...i}=t;return p(Z()),de(i.tokens)?(m(Z(),JSON.stringify({...i,auth_mode:"chatgpt"},null,2)+"\n",384),"chatgpt"):(s(Z(),{force:!0}),"signed_out")}(e?.savedKeys??[]),!t(z()))return;let o;try{o=ue()}catch(e){return void c.logError("codexAdapter.unloadPrivateConfig",e)}const r=o.model_providers;de(r)&&de(r[te])&&R(r[te].base_url)&&de(r)&&(delete r[te],0===Object.keys(r).length&&delete o.model_providers,o.model_provider===te&&delete o.model_provider),o.model_catalog_json===P()&&delete o.model_catalog_json,Q(o),fe(o),p(z()),m(z(),d.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=pe()[ee];return{apiKey:"string"==typeof e&&e.trim()?e.trim():null}},getConfig(){try{return ue()}catch(e){return c.logError("codexAdapter.getConfig",e),null}},backupPaths:()=>[z(),Z(),P()]};export function codexAuthProblem(){try{const e=ue(),t=e.model_providers?.[te];if(e.model_provider!==te||!t)return null;if("string"==typeof t.experimental_bearer_token&&t.experimental_bearer_token)return"stale_bearer";const o=pe();return!0===t.requires_openai_auth&&"chatgpt"===o.auth_mode?"chatgpt_login":null}catch{return null}}
@@ -1 +1 @@
1
- import{spawnSync as t}from"child_process";import{createHash as e}from"crypto";import{accessSync as r,constants as o,copyFileSync as n,createReadStream as s,createWriteStream as i,existsSync as a,mkdirSync as c,mkdtempSync as l,readFileSync as p,renameSync as u,rmSync as d}from"fs";import{cpus as f,tmpdir as m}from"os";import{basename as g,dirname as h,join as w}from"path";import{Readable as S,Transform as A}from"stream";import{pipeline as x}from"stream/promises";import{logger as y}from"../../utils/logger.js";import{i18n as E}from"../i18n.js";import{powerShellEnv as $}from"../powershell-env.js";import{toolHome as v}from"./types.js";import{configManager as k}from"../config.js";import{mirrorFileUrl as _}from"../mirror-url.js";const P=(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:$()});return n.error&&y.logError(`desktop-app: ${e}`,n.error),{status:n.status,stdout:`${n.stdout??""}`,stderr:`${n.stderr??""}`}};let I=P,b=(...t)=>fetch(...t),C=null,T=null,M=null,F=null;export function setDesktopAppDepsForTests(t){void 0!==t.run&&(I=t.run??P),void 0!==t.fetch&&(b=t.fetch??((...t)=>fetch(...t))),void 0!==t.platform&&(C=t.platform),void 0!==t.arm64&&(T=t.arm64),void 0!==t.privileged&&(M=t.privileged),void 0!==t.remote&&(F=t.remote)}export function appPlatform(){return C??process.platform}export function isArm64Machine(){return null!==T?T:"arm64"===process.arch||("win32"===appPlatform()?"ARM64"===process.env.PROCESSOR_ARCHITECTURE||"ARM64"===process.env.PROCESSOR_ARCHITEW6432:"darwin"===appPlatform()&&/\bApple\b/.test(f()[0]?.model??""))}export class DesktopInstallError extends Error{key;constructor(t,e){super(t),this.name="DesktopInstallError",this.key=e}}export const fail=(t,e={})=>{const r={};for(const[t,o]of Object.entries(e))r[t]=o.trim()||E.t("app_update.reason_unknown");throw new DesktopInstallError(E.t(`app_update.error_${t}`,r),t)};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 R(t){const r=e("sha256");for await(const e of s(t))r.update(e);return r.digest("hex")}async function j(t,e){const r=await b(t,{signal:AbortSignal.timeout(e)});if(!r.ok)throw new Error(`${t}: HTTP ${r.status}`);return(await r.text()).trim()}function O(t,e){try{const r=p(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 O(t,"CFBundleIdentifier")}export function macAppVersion(t){return/^\d+\.\d+\.\d+/.exec(O(t,"CFBundleShortVersionString")??"")?.[0]??null}function N(t){try{return r(t,o.W_OK),!0}catch{return!1}}const B=t=>`'${t.replace(/'/g,"''")}'`;function D(t,e=12e4){return I("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 e=()=>t.mirror()||null,r=()=>t.asset(appPlatform(),isArm64Machine()),o=()=>{const o=appPlatform();return"darwin"!==o&&"win32"!==o?"unsupported_platform":r()?e()?"darwin"===o&&(M??0===process.getuid?.())?"root":"win32"===o&&(null!==M?M:/\\system32\\config\\systemprofile/i.test(process.env.USERPROFILE??"")||!0===process.env.USERNAME?.endsWith("$"))?"system_account":"win32"===o&&(null!==F?F:Boolean(process.env.SSH_CONNECTION||process.env.SSH_CLIENT))?"remote_session":t.extraBlocker?.(o)??null:"no_mirror":"darwin"===o?"unsupported_arch":"unsupported_platform"},s=async(r=8e3)=>{const o=e();if(!o)throw new Error("no mirror");const n=t.versionFile(appPlatform(),isArm64Machine()),s=await j(_(o,n),r),i=/^(\d+\.\d+\.\d+)(\.\d+)?$/.exec(s)?.[1];if(!i)throw new Error(`unexpected ${n}: ${s.slice(0,40)}`);return i},f=()=>{for(const e of["/Applications",w(v(),"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},$=e=>{const r=I("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=I("codesign",["-dv",e]),n=`${o.stdout}\n${o.stderr}`,s=/^TeamIdentifier=(\S+)/m.exec(n)?.[1],i=/^Identifier=(\S+)/m.exec(n)?.[1];s===t.macApp.teamId&&i===t.macApp.bundleId||fail("signature",{reason:`TeamIdentifier=${s??"?"} Identifier=${i??"?"}`});const a=I("spctl",["-a","-t","exec","-vv",e],{timeout:3e5});0!==a.status&&fail("signature",{reason:(a.stderr||a.stdout).trim().split("\n")[0]||`spctl ${a.status}`})},P=()=>{const e=f();let r=e;if(!r){const e=N("/Applications")?"/Applications":w(v(),"Applications");r=w(e,t.macApp.installedNames[0])}const o=h(r);return(a(o)&&!N(o)||e&&!N(e))&&fail("no_permission",{path:r}),{target:r,existing:e}},C=e=>{const r=D(`$s = Get-AuthenticodeSignature -LiteralPath ${B(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()})}},T=()=>{const e=D(`Get-AppxPackage | Where-Object { ${t.windows.packageFilter} } | ForEach-Object { $_.Version.ToString() }`,3e4);return/\d+\.\d+\.\d+/.exec(e.stdout)?.[0]??null};return{assetName:r,blocker:o,latestVersion:s,installedMacApp:f,windowsPackageVersion:T,verifyMacApp:$,verifyWindowsPackage:C,install:async(f={})=>{const v=o();v&&fail("blocked",{reason:E.t(`app_update.reason_${v}`)});const M=e(),F=r();let O;try{O=await s(15e3)}catch(t){fail("download",{reason:t instanceof Error?t.message:String(t)})}const N=e=>_(M,e,t.releaseTag?.(O));let H;try{H=parseSha256Sums(await j(N("SHA256SUMS"),15e3)).get(F)}catch(e){y.logError(`${t.id}: SHA256SUMS`,e)}H||fail("no_checksum",{file:F}),"darwin"===appPlatform()&&P();const W=w(k.getConfigDir(),"downloads",t.id),V=w(W,F),L=l(w(m(),`${t.id}-`));let U=w(L,F),G=!1;try{a(V)&&await R(V)===H?(U=V,f.reusing?.(O)):(f.downloading?.(O),await async function(t,e,r){let o;try{o=await b(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 s=0,a=-1;const c=new A({transform(t,e,o){s+=t.length;const i=n?Math.floor(100*s/n):-1;i>=0&&i!==a&&(a=i,r?.(i)),o(null,t)}});try{await x(S.fromWeb(o.body),c,i(e))}catch(t){d(e,{force:!0}),fail("download",{reason:t instanceof Error?t.message:String(t)})}}(N(F),U,f.percent)),f.verifying?.();const e=await R(U);e!==H&&fail("checksum",{file:F,expected:H.slice(0,12),actual:e.slice(0,12)}),f.installing?.();const r="darwin"===appPlatform()?await(async(e,r)=>{const o=w(r,"mnt");c(o,{recursive:!0});const n=I("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}=P(),i=h(r),l=g(r);c(i,{recursive:!0}),s=w(i,`.${l}.${process.pid}.new`),d(s,{recursive:!0,force:!0});const p=I("ditto",[e,s],{timeout:9e5});0!==p.status&&fail("copy",{reason:(p.stderr||p.stdout).trim().split("\n")[0]??""}),$(s);const f=macAppVersion(s);f||fail("bad_package",{reason:"Info.plist"});const m=w(i,`.${l}.${process.pid}.old`);try{n&&u(n,m)}catch(t){throw["EPERM","EACCES"].includes(t.code??"")&&fail("app_management",{path:n}),t}try{u(s,r)}catch(t){throw n&&u(m,n),t}return s=null,d(m,{recursive:!0,force:!0}),{version:f,location:r}}finally{s&&d(s,{recursive:!0,force:!0}),I("hdiutil",["detach",o,"-force"],{timeout:6e4})}})(U,L):await(async(t,e)=>{C(t);const r=D(`$ErrorActionPreference = 'Stop'; Add-AppxPackage -Path ${B(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=w(h(t),"elevated-install.log"),r=`$ErrorActionPreference = 'Stop'; try { Add-AppxPackage -Path ${B(t)} -ForceApplicationShutdown; exit 0 } catch { [IO.File]::WriteAllText(${B(e)}, $_.Exception.Message, [Text.Encoding]::UTF8); exit 1 }`,o=D(`$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=p(e,"utf-8").trim()}catch{}return n||powerShellError(o.stderr)||powerShellError(o.stdout)||`exit ${o.status}`})(t);n&&fail("install",{reason:n}),T()||fail("other_account")}const o=T();return o||fail("install",{reason:"Get-AppxPackage"}),{version:o,location:"MSIX"}})(U,f);return G=!0,r}catch(t){const e=t instanceof DesktopInstallError?t.key:void 0;throw U!==V&&a(U)&&!["checksum","signature","bad_package","mount"].includes(e??"")&&function(t,e,r){try{d(e,{recursive:!0,force:!0}),c(e,{recursive:!0});try{u(t,r)}catch{n(t,r)}}catch(t){y.logError("desktop-app: keep package",t),d(e,{recursive:!0,force:!0})}}(U,W,V),U===V&&["signature","bad_package","mount"].includes(e??"")&&d(W,{recursive:!0,force:!0}),t}finally{G&&d(W,{recursive:!0,force:!0}),d(L,{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,copyFileSync as n,createReadStream as s,createWriteStream as i,existsSync as a,mkdirSync as c,mkdtempSync as l,readFileSync as p,renameSync as u,rmSync as d}from"fs";import{cpus as f,tmpdir as m}from"os";import{basename as g,dirname as h,join as w}from"path";import{Readable as S,Transform as A}from"stream";import{pipeline as x}from"stream/promises";import{logger as y}from"../../utils/logger.js";import{i18n as E}from"../i18n.js";import{powerShellEnv as $}from"../powershell-env.js";import{toolHome as v}from"./types.js";import{configManager as k}from"../config.js";import{brand as _}from"../brand.js";import{mirrorFileUrl as P,withDownloadFallback as I}from"../mirror-url.js";const b=(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:$()});return n.error&&y.logError(`desktop-app: ${e}`,n.error),{status:n.status,stdout:`${n.stdout??""}`,stderr:`${n.stderr??""}`}};let C=b,T=(...t)=>fetch(...t),M=null,j=null,F=null,R=null;export function setDesktopAppDepsForTests(t){void 0!==t.run&&(C=t.run??b),void 0!==t.fetch&&(T=t.fetch??((...t)=>fetch(...t))),void 0!==t.platform&&(M=t.platform),void 0!==t.arm64&&(j=t.arm64),void 0!==t.privileged&&(F=t.privileged),void 0!==t.remote&&(R=t.remote)}export function appPlatform(){return M??process.platform}export function isArm64Machine(){return null!==j?j:"arm64"===process.arch||("win32"===appPlatform()?"ARM64"===process.env.PROCESSOR_ARCHITECTURE||"ARM64"===process.env.PROCESSOR_ARCHITEW6432:"darwin"===appPlatform()&&/\bApple\b/.test(f()[0]?.model??""))}export class DesktopInstallError extends Error{key;constructor(t,e){super(t),this.name="DesktopInstallError",this.key=e}}export const fail=(t,e={})=>{const r={};for(const[t,o]of Object.entries(e))r[t]=o.trim()||E.t("app_update.reason_unknown");throw new DesktopInstallError(E.t(`app_update.error_${t}`,r),t)};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 O(t){const r=e("sha256");for await(const e of s(t))r.update(e);return r.digest("hex")}async function N(t,e){const r=await T(t,{signal:AbortSignal.timeout(e)});if(!r.ok)throw new Error(`${t}: HTTP ${r.status}`);return(await r.text()).trim()}function B(t,e){try{const r=p(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 B(t,"CFBundleIdentifier")}export function macAppVersion(t){return/^\d+\.\d+\.\d+/.exec(B(t,"CFBundleShortVersionString")??"")?.[0]??null}function D(t){try{return r(t,o.W_OK),!0}catch{return!1}}const H=t=>`'${t.replace(/'/g,"''")}'`;function W(t,e=12e4){return C("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 e=()=>t.mirror()||null,r=()=>t.asset(appPlatform(),isArm64Machine()),o=()=>{const o=appPlatform();return"darwin"!==o&&"win32"!==o?"unsupported_platform":r()?e()?"darwin"===o&&(F??0===process.getuid?.())?"root":"win32"===o&&(null!==F?F:/\\system32\\config\\systemprofile/i.test(process.env.USERPROFILE??"")||!0===process.env.USERNAME?.endsWith("$"))?"system_account":"win32"===o&&(null!==R?R:Boolean(process.env.SSH_CONNECTION||process.env.SSH_CLIENT))?"remote_session":t.extraBlocker?.(o)??null:"no_mirror":"darwin"===o?"unsupported_arch":"unsupported_platform"},s=async(r=8e3)=>{const o=e();if(!o)throw new Error("no mirror");const n=t.versionFile(appPlatform(),isArm64Machine()),s=await N(P(o,n),r),i=/^(\d+\.\d+\.\d+)(\.\d+)?$/.exec(s)?.[1];if(!i)throw new Error(`unexpected ${n}: ${s.slice(0,40)}`);return i},f=()=>{for(const e of["/Applications",w(v(),"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},$=e=>{const r=C("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=C("codesign",["-dv",e]),n=`${o.stdout}\n${o.stderr}`,s=/^TeamIdentifier=(\S+)/m.exec(n)?.[1],i=/^Identifier=(\S+)/m.exec(n)?.[1];s===t.macApp.teamId&&i===t.macApp.bundleId||fail("signature",{reason:`TeamIdentifier=${s??"?"} Identifier=${i??"?"}`});const a=C("spctl",["-a","-t","exec","-vv",e],{timeout:3e5});0!==a.status&&fail("signature",{reason:(a.stderr||a.stdout).trim().split("\n")[0]||`spctl ${a.status}`})},b=()=>{const e=f();let r=e;if(!r){const e=D("/Applications")?"/Applications":w(v(),"Applications");r=w(e,t.macApp.installedNames[0])}const o=h(r);return(a(o)&&!D(o)||e&&!D(e))&&fail("no_permission",{path:r}),{target:r,existing:e}},M=e=>{const r=W(`$s = Get-AuthenticodeSignature -LiteralPath ${H(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()})}},j=()=>{const e=W(`Get-AppxPackage | Where-Object { ${t.windows.packageFilter} } | ForEach-Object { $_.Version.ToString() }`,3e4);return/\d+\.\d+\.\d+/.exec(e.stdout)?.[0]??null};return{assetName:r,blocker:o,latestVersion:s,installedMacApp:f,windowsPackageVersion:j,verifyMacApp:$,verifyWindowsPackage:M,install:async(f={})=>{const v=o();v&&fail("blocked",{reason:E.t(`app_update.reason_${v}`)});const F=e(),R=r();let B;try{B=await s(15e3)}catch(t){fail("download",{reason:t instanceof Error?t.message:String(t)})}const D=e=>P(F,e,t.releaseTag?.(B)),V=_().installMirror?.downloadCounter;let L;try{L=parseSha256Sums(await I(D("SHA256SUMS"),V,t=>N(t,15e3))).get(R)}catch(e){y.logError(`${t.id}: SHA256SUMS`,e)}L||fail("no_checksum",{file:R}),"darwin"===appPlatform()&&b();const U=w(k.getConfigDir(),"downloads",t.id),G=w(U,R),J=l(w(m(),`${t.id}-`));let X=w(J,R),q=!1;try{a(G)&&await O(G)===L?(X=G,f.reusing?.(B)):(f.downloading?.(B),await I(D(R),V,t=>async function(t,e,r){let o;try{o=await T(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 s=0,a=-1;const c=new A({transform(t,e,o){s+=t.length;const i=n?Math.floor(100*s/n):-1;i>=0&&i!==a&&(a=i,r?.(i)),o(null,t)}});try{await x(S.fromWeb(o.body),c,i(e))}catch(t){d(e,{force:!0}),fail("download",{reason:t instanceof Error?t.message:String(t)})}}(t,X,f.percent))),f.verifying?.();const e=await O(X);e!==L&&fail("checksum",{file:R,expected:L.slice(0,12),actual:e.slice(0,12)}),f.installing?.();const r="darwin"===appPlatform()?await(async(e,r)=>{const o=w(r,"mnt");c(o,{recursive:!0});const n=C("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}=b(),i=h(r),l=g(r);c(i,{recursive:!0}),s=w(i,`.${l}.${process.pid}.new`),d(s,{recursive:!0,force:!0});const p=C("ditto",[e,s],{timeout:9e5});0!==p.status&&fail("copy",{reason:(p.stderr||p.stdout).trim().split("\n")[0]??""}),$(s);const f=macAppVersion(s);f||fail("bad_package",{reason:"Info.plist"});const m=w(i,`.${l}.${process.pid}.old`);try{n&&u(n,m)}catch(t){throw["EPERM","EACCES"].includes(t.code??"")&&fail("app_management",{path:n}),t}try{u(s,r)}catch(t){throw n&&u(m,n),t}return s=null,d(m,{recursive:!0,force:!0}),{version:f,location:r}}finally{s&&d(s,{recursive:!0,force:!0}),C("hdiutil",["detach",o,"-force"],{timeout:6e4})}})(X,J):await(async(t,e)=>{M(t);const r=W(`$ErrorActionPreference = 'Stop'; Add-AppxPackage -Path ${H(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=w(h(t),"elevated-install.log"),r=`$ErrorActionPreference = 'Stop'; try { Add-AppxPackage -Path ${H(t)} -ForceApplicationShutdown; exit 0 } catch { [IO.File]::WriteAllText(${H(e)}, $_.Exception.Message, [Text.Encoding]::UTF8); exit 1 }`,o=W(`$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=p(e,"utf-8").trim()}catch{}return n||powerShellError(o.stderr)||powerShellError(o.stdout)||`exit ${o.status}`})(t);n&&fail("install",{reason:n}),j()||fail("other_account")}const o=j();return o||fail("install",{reason:"Get-AppxPackage"}),{version:o,location:"MSIX"}})(X,f);return q=!0,r}catch(t){const e=t instanceof DesktopInstallError?t.key:void 0;throw X!==G&&a(X)&&!["checksum","signature","bad_package","mount"].includes(e??"")&&function(t,e,r){try{d(e,{recursive:!0,force:!0}),c(e,{recursive:!0});try{u(t,r)}catch{n(t,r)}}catch(t){y.logError("desktop-app: keep package",t),d(e,{recursive:!0,force:!0})}}(X,U,G),X===G&&["signature","bad_package","mount"].includes(e??"")&&d(U,{recursive:!0,force:!0}),t}finally{q&&d(U,{recursive:!0,force:!0}),d(J,{recursive:!0,force:!0})}}}}
@@ -11,6 +11,12 @@ export declare function ownsValue(key: string, current: unknown, legacy?: readon
11
11
  * true → the caller writes `desired` (recorded as ours); false → the user's value stays.
12
12
  */
13
13
  export declare function claimField(key: string, current: unknown, desired: string, options?: ClaimOptions): boolean;
14
+ /**
15
+ * vibecli writes `value` into the field whatever it held (setup / config: the user runs them to get
16
+ * a working setup in one go, user 2026-11-03; the file was backed up first). Recorded as ours so
17
+ * uninstall still takes out only what vibecli wrote.
18
+ */
19
+ export declare function takeField(key: string, value: string): void;
14
20
  /** vibecli removed its value from the field (or the user cleared it through vibecli). */
15
21
  export declare function forgetField(key: string): void;
16
22
  /**
@@ -1 +1 @@
1
- import{mkdirSync as e,readFileSync as t,writeFileSync as n}from"fs";import{join as r}from"path";import{configManager as i}from"./config.js";import{logger as o}from"../utils/logger.js";function s(){return r(i.getConfigDir(),"written-values.json")}function l(){try{const e=JSON.parse(t(s(),"utf-8"));return e.values&&"object"==typeof e.values?e.values:{}}catch{return{}}}function u(t){try{e(i.getConfigDir(),{recursive:!0}),n(s(),JSON.stringify({version:1,values:t},null,2)+"\n",{mode:384})}catch(e){o.logError("writtenValues.save",e)}}export function ownsValue(e,t,n=[]){if("string"!=typeof t)return!1;const r=l()[e];return r?r.written===t:n.includes(t)}export function claimField(e,t,n,r={}){const i=l(),o=i[e];let s;return s=null==t||""===t||t===n||"string"==typeof t&&(o?o.written===t||Boolean(r.explicit)&&o.desired!==n:Boolean(r.explicit)||(r.legacy??[]).includes(t)),i[e]=s?{written:n,desired:n}:{desired:n},u(i),s}export function forgetField(e){const t=l();e in t&&(delete t[e],u(t))}const c="gateway_urls";export function noteGatewayUrl(e){const t=l(),n=(t[c]?.desired??"").split("\n").filter(Boolean);n.includes(e)||(t[c]={desired:[...n,e].join("\n")},u(t))}export function wroteGatewayUrl(e){return(l()[c]?.desired??"").split("\n").includes(e)}
1
+ import{mkdirSync as e,readFileSync as t,writeFileSync as n}from"fs";import{join as r}from"path";import{configManager as i}from"./config.js";import{logger as o}from"../utils/logger.js";function s(){return r(i.getConfigDir(),"written-values.json")}function l(){try{const e=JSON.parse(t(s(),"utf-8"));return e.values&&"object"==typeof e.values?e.values:{}}catch{return{}}}function u(t){try{e(i.getConfigDir(),{recursive:!0}),n(s(),JSON.stringify({version:1,values:t},null,2)+"\n",{mode:384})}catch(e){o.logError("writtenValues.save",e)}}export function ownsValue(e,t,n=[]){if("string"!=typeof t)return!1;const r=l()[e];return r?r.written===t:n.includes(t)}export function claimField(e,t,n,r={}){const i=l(),o=i[e];let s;return s=null==t||""===t||t===n||"string"==typeof t&&(o?o.written===t||Boolean(r.explicit)&&o.desired!==n:Boolean(r.explicit)||(r.legacy??[]).includes(t)),i[e]=s?{written:n,desired:n}:{desired:n},u(i),s}export function takeField(e,t){const n=l();n[e]={written:t,desired:t},u(n)}export function forgetField(e){const t=l();e in t&&(delete t[e],u(t))}const c="gateway_urls";export function noteGatewayUrl(e){const t=l(),n=(t[c]?.desired??"").split("\n").filter(Boolean);n.includes(e)||(t[c]={desired:[...n,e].join("\n")},u(t))}export function wroteGatewayUrl(e){return(l()[c]?.desired??"").split("\n").includes(e)}
@@ -381,7 +381,7 @@
381
381
  "list_separator": ", "
382
382
  },
383
383
  "codex": {
384
- "kept_user_settings": "Kept what you set yourself: {{values}}",
384
+ "replaced_user_settings": "Replaced the earlier settings: {{values}} (backed up; to restore run {{cli}} config codex restore)",
385
385
  "plan_replace_provider": "Replace model_providers.custom (now pointing at {{url}}, not written by {{product}})",
386
386
  "plan_switch_provider": "Codex now uses {{provider}}; it will switch to {{brand}}",
387
387
  "provider_replaced": "Replaced the previous custom provider {{url}}; the old file is backed up",
@@ -434,7 +434,7 @@
434
434
  "plan_replace_provider": "Replace Claude Code's current endpoint {{url}} (not written by {{product}})",
435
435
  "provider_replaced": "Replaced the previous endpoint {{url}}; the old file is backed up",
436
436
  "gateway_models": "{{count}} more models added to /model ({{vendors}})",
437
- "kept_user_models": "Kept the models you set yourself: {{values}}",
437
+ "replaced_user_models": "Replaced the earlier model settings: {{values}} (backed up; to restore run {{cli}} config claude-code restore)",
438
438
  "tier_fallback": "This API key can't use Claude Code's default {{from}}; the {{tier}} alias now uses {{to}}",
439
439
  "stable_channel": "Your update channel in settings.json is stable, which may not have reached {{min}} yet; set autoUpdatesChannel to latest, then upgrade",
440
440
  "managed_override": "Claude Code managed settings found ({{source}}); {{keys}} there override what {{product}} writes, so this config won't take effect. Managed settings usually come from your company's IT; ask your administrator",
@@ -381,7 +381,7 @@
381
381
  "list_separator": "、"
382
382
  },
383
383
  "codex": {
384
- "kept_user_settings": "已保留你自己设的:{{values}}",
384
+ "replaced_user_settings": "已替换原来的设置:{{values}}(已备份,恢复运行 {{cli}} config codex restore)",
385
385
  "plan_replace_provider": "替换 model_providers.custom(现在指向 {{url}},不是 {{product}} 写的)",
386
386
  "plan_switch_provider": "Codex 现在用的是 {{provider}},将改用 {{brand}}",
387
387
  "provider_replaced": "已替换原来的 custom 提供方 {{url}},修改前的文件已备份",
@@ -434,7 +434,7 @@
434
434
  "plan_replace_provider": "替换 Claude Code 现在的接入地址 {{url}}(不是 {{product}} 写的)",
435
435
  "provider_replaced": "已替换原来的接入地址 {{url}},修改前的文件已备份",
436
436
  "gateway_models": "/model 菜单新增 {{count}} 个其他模型({{vendors}})",
437
- "kept_user_models": "已保留你自己设的模型:{{values}}",
437
+ "replaced_user_models": "已替换原来的模型设置:{{values}}(已备份,恢复运行 {{cli}} config claude-code restore)",
438
438
  "tier_fallback": "当前令牌无法使用 Claude Code 默认的 {{from}},{{tier}} 档已改用 {{to}}",
439
439
  "stable_channel": "settings.json 里的更新渠道是 stable,这个渠道可能还没有更新到 {{min}}。请把 autoUpdatesChannel 改成 latest 后再升级",
440
440
  "managed_override": "发现 Claude Code 的托管配置({{source}}),其中 {{keys}} 优先于 {{product}} 写入的设置,这里的配置不会生效。托管配置通常由公司电脑统一下发,请联系公司 IT 管理员",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeapi/cli",
3
- "version": "0.0.155",
3
+ "version": "0.0.157",
4
4
  "description": "CLI tool for managing AI coding assistants (Claude Code, Codex, OpenClaw, Hermes, AtomCode, Grok Build) with one unified config",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",