@vibeapi/cli 0.0.149 → 0.0.150
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -17
- package/dist/commands/config.js +1 -1
- package/dist/commands/setup.js +1 -1
- package/dist/lib/claude-code-manager.d.ts +4 -0
- package/dist/lib/claude-code-manager.js +1 -1
- package/dist/lib/command.d.ts +0 -5
- package/dist/lib/command.js +1 -1
- package/dist/lib/config.d.ts +2 -0
- package/dist/lib/config.js +1 -1
- package/dist/lib/env-cleanup.d.ts +32 -28
- package/dist/lib/env-cleanup.js +1 -1
- package/dist/lib/gateway-addresses.d.ts +4 -0
- package/dist/lib/gateway-addresses.js +1 -1
- package/dist/lib/model-registry.d.ts +2 -0
- package/dist/lib/model-registry.js +1 -1
- package/dist/lib/tool-manager.d.ts +3 -0
- package/dist/lib/tool-manager.js +1 -1
- package/dist/lib/tools/claude-code.js +1 -1
- package/dist/lib/tools/claude-desktop.d.ts +1 -1
- package/dist/lib/tools/claude-desktop.js +1 -1
- package/dist/lib/tools/codex.js +1 -1
- package/dist/lib/tools/types.d.ts +13 -0
- package/dist/lib/wizard.js +1 -1
- package/dist/lib/write-plan.d.ts +2 -0
- package/dist/lib/write-plan.js +1 -1
- package/dist/lib/written-values.d.ts +21 -0
- package/dist/lib/written-values.js +1 -0
- package/dist/locales/en_US.json +16 -0
- package/dist/locales/zh_CN.json +16 -0
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
import{dirname as e,join as
|
|
1
|
+
import{dirname as e,join as t}from"path";import{fileURLToPath as o}from"url";import{existsSync as l,readFileSync as n}from"fs";import{currentClientConfig as r,usableClientSection as s}from"./client-config.js";import{brand as a}from"./brand.js";const i=e(o(import.meta.url)),d=(e=[],t=[])=>[...new Set([...e,...t])];export function overlayClientSection(e,t){if(!t)return e;const o={...e.retiredDefaultModels??{}};for(const[e,l]of Object.entries(t.retiredDefaultModels??{}))o[e]=d(o[e],l);return{...e,defaultModels:{...e.defaultModels,...t.defaultModels??{}},retiredDefaultModels:o,toolDefaults:{...e.toolDefaults??{},...t.toolDefaults??{}},claudeCode:t.tierChains?{...e.claudeCode??{},tierChains:{...e.claudeCode?.tierChains??{},...t.tierChains}}:e.claudeCode,claudeDesktop:t.oneMillionFallback?{...e.claudeDesktop??{},oneMillionFallback:[...t.oneMillionFallback]}:e.claudeDesktop,gatewayModels:t.retiredModels?{...e.gatewayModels??{},retired:d(e.gatewayModels?.retired,t.retiredModels)}:e.gatewayModels,toolMinVersions:{...e.toolMinVersions??{},...t.toolMinVersions??{}},agy:t.agyModels?{...e.agy??{},gatewayModels:[...t.agyModels]}:e.agy}}let u=null;function c(){return u||(u=overlayClientSection(function(){const e=[t(i,"..","..","models.json"),t(i,"..","models.json"),t(i,"models.json")];for(const t of e)if(l(t))return JSON.parse(n(t,"utf-8"));throw new Error(`models.json not found, searched: ${e.join(", ")}`)}(),s(r()?.config))),u}export function getDefaultModels(){return{...c().defaultModels}}export function isRetiredDefaultModel(e,t){return c().retiredDefaultModels?.[e]?.includes(t)??!1}export function getRetiredDefaultModelIds(){return[...new Set(Object.values(c().retiredDefaultModels??{}).flat())]}export function getDefaultToolModel(){return c().defaultToolModel?.trim()||"gpt-5.5"}export function getToolDefaultModel(e){const t=c().toolDefaults;return t&&Object.prototype.hasOwnProperty.call(t,e)?(t[e]??"").trim():getDefaultToolModel()}export function getPresets(){return[...c().presets]}export function resolvePreset(e){return e.models?{...e.models}:e.model?{haiku:e.model,sonnet:e.model,opus:e.model,reasoning:e.model}:getDefaultModels()}export function getClaudeCodeTierChains(){const e=c().claudeCode?.tierChains??{};return Object.fromEntries(Object.entries(e).map(([e,t])=>[e,[...t]]))}export function getClaudeDesktopRules(){const e=c().claudeDesktop??{};return{oneMillionFallback:[...e.oneMillionFallback??[]],oneMillionExclusions:(e.oneMillionExclusions??[]).map(e=>({...e,models:[...e.models]}))}}export function getGatewayModelRules(){const e=c().gatewayModels??{};return{autoCompactRatio:e.autoCompactRatio??.8,models:(e.models??[]).map(e=>({...e})),retired:[...e.retired??[]]}}export function getBuiltinGatewayAddresses(){return a().gatewayAddresses.map(e=>({...e}))}export function getCodexRules(){return{standardContextWindow:c().codex?.standardContextWindow??272e3}}export function getAgyRules(){return{gatewayModels:[...c().agy?.gatewayModels??[]]}}export function compareVersions(e,t){const o=e.split(".").map(e=>parseInt(e,10)||0),l=t.split(".").map(e=>parseInt(e,10)||0);for(let e=0;e<Math.max(o.length,l.length);e++){const t=(o[e]??0)-(l[e]??0);if(0!==t)return t}return 0}export function getToolMinVersion(e){return c().toolMinVersions?.[e]?.trim()||null}export function reloadRegistry(){u=null}
|
|
@@ -22,6 +22,7 @@ export interface ToolInfo {
|
|
|
22
22
|
/** GUI app (no terminal command to type, e.g. Claude Desktop). */
|
|
23
23
|
gui?: boolean;
|
|
24
24
|
}
|
|
25
|
+
/** Every key saved in any profile (default and tool-specific), trimmed. */
|
|
25
26
|
/**
|
|
26
27
|
* Tool metadata keyed by id. Derived from the adapter registry so the list of
|
|
27
28
|
* supported tools lives in exactly one place (`lib/tools/registry.ts`).
|
|
@@ -62,6 +63,7 @@ export declare class ToolManager {
|
|
|
62
63
|
forceResetConfig(toolName: string): string[];
|
|
63
64
|
loadPrivateConfig(toolName: string, apiKey: string, models: VibecliModels, catalog?: ModelCatalog, options?: {
|
|
64
65
|
force?: boolean;
|
|
66
|
+
takeOver?: boolean;
|
|
65
67
|
}): void;
|
|
66
68
|
/**
|
|
67
69
|
* `loadPrivateConfig` plus the network lookup adapters with
|
|
@@ -70,6 +72,7 @@ export declare class ToolManager {
|
|
|
70
72
|
*/
|
|
71
73
|
applyPrivateConfig(toolName: string, apiKey: string, models: VibecliModels, options?: {
|
|
72
74
|
force?: boolean;
|
|
75
|
+
takeOver?: boolean;
|
|
73
76
|
}): Promise<void>;
|
|
74
77
|
private applyPrivateConfigNow;
|
|
75
78
|
/** Post-apply follow-ups the adapter wants shown to the user (may be empty). */
|
package/dist/lib/tool-manager.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{execSync as o,spawnSync as t}from"child_process";import{i18n as n}from"./i18n.js";import e from"inquirer";import r from"chalk";import{canPrompt as i,shouldAutoConfirm as l}from"./runtime-options.js";import{logger as
|
|
1
|
+
import{execSync as o,spawnSync as t}from"child_process";import{i18n as n}from"./i18n.js";import e from"inquirer";import r from"chalk";import{canPrompt as i,shouldAutoConfirm as l}from"./runtime-options.js";import{logger as a}from"../utils/logger.js";import{configManager as s,savedApiKeys as c}from"./config.js";import{getAdapter as d,listAdapters as p,TOOL_ADAPTERS as u}from"./tools/registry.js";import{backupBeforeWrite as m,listBackups as f,restoreBackup as g}from"./tools/backup.js";import{existsSync as h,rmSync as w}from"fs";import{dirname as y,join as P}from"path";import{toolHome as v}from"./tools/types.js";import{stringWidth as $}from"../utils/string-width.js";import{resolveModelCatalog as T}from"./model-catalog.js";import{compareVersions as k,getToolMinVersion as C}from"./model-registry.js";import{findInstalls as E,forgetInstalls as O,installLabel as _,mirrorInstallCommand as S,npmMirrorInstallCommand as N,npmMirrorVersion as j}from"./tools/tool-installs.js";import{mirrorInstall as M}from"./tool-upgrade.js";import{upgradeApp as U}from"./app-update.js";import{CLI_NAME as b}from"./brand.js";import{track as x,trackStep as I}from"./telemetry.js";import{addUserPathDir as R,broadcastEnvChange as F}from"./windows-env.js";export{k as compareVersions};function L(o){const t=u[o];return{name:t.name,command:t.command,installCommand:t.installCommand,configPath:t.configPath,displayName:t.displayName,...t.hidden?{hidden:!0}:{},...t.isInstalled?{gui:!0}:{}}}export const SUPPORTED_TOOLS=Object.fromEntries(Object.keys(u).map(o=>[o,L(o)]));export class ToolManager{static instance;constructor(){}static getInstance(){return ToolManager.instance||(ToolManager.instance=new ToolManager),ToolManager.instance}isToolInstalled(o){if(!SUPPORTED_TOOLS[o])return!1;const t=d(o);if(t?.isInstalled)try{return t.isInstalled()}catch{return!1}return this.isOnPath(o)||null!==this.nativeLauncher(o)}isOnPath(t){const n=SUPPORTED_TOOLS[t];if(!n)return!1;try{const t="win32"===process.platform?`where ${n.command}`:`which ${n.command}`;return o(t,{stdio:"pipe"}),!0}catch{return!1}}nativeLauncher(o){const t=d(o),n=t?.installSpec?.native?.binDir;if(!t||!n)return null;const e="win32"===process.platform?`${t.command}.exe`:t.command,r=P(v(),...n,e);return h(r)?r:null}ensureNativeOnPath(o){if("win32"!==process.platform||this.isOnPath(o))return null;const t=this.nativeLauncher(o);if(!t)return null;const n=y(t);try{if(!R(n))return null}catch(t){return a.logError(`ensureNativeOnPath: ${o}`,t),null}return F(),process.env.Path=`${process.env.Path??""};${n}`,n}async installTool(o){return I(`install:${o}`,()=>this.installToolNow(o))}async installToolNow(t){const a=SUPPORTED_TOOLS[t];if(!a)throw new Error(`Unknown tool: ${t}`);const s=d(t)?.appInstaller;if(s&&!s.blocker()){const o=await U(t,{install:!0});if("failed"===o.result||"unavailable"===o.result)throw new Error(`Failed to install ${a.displayName}`);return}const c=d(t)?.installSpec;if(c&&(c.mirrorScript||c.npmPackage)){const o=S(c);if(await M(c)&&(O(),this.isToolInstalled(t)))return void console.log(r.green("√ "+n.t("wizard.tool_installed")));throw console.log(r.red("× "+n.t("wizard.install_failed"))),console.log(r.yellow(" ! "+n.t("install.manual_command",{tool:a.displayName,command:o}))),c.mirrorScript&&c.npmPackage&&console.log(r.yellow(" ! "+n.t("install.manual_npm",{command:N(c,await j(c))}))),new Error(`Failed to install ${a.displayName}`)}const p=a.installCommand;console.log(r.gray("$ ")+r.white(p));try{return o(p,{stdio:"inherit"}),O(),void console.log(r.green("√ "+n.t("wizard.tool_installed")))}catch(o){if(console.log(r.red("× "+n.t("wizard.install_failed"))),!/EACCES|EPERM|permission denied/i.test(`${o?.message??""}${o?.stderr??""}`)&&243!==o?.status&&!p.startsWith("npm "))throw new Error(`Failed to install ${a.displayName}: ${o}`);console.log(r.yellow(" ! "+("win32"===process.platform?n.t("install.permission_windows",{command:p}):n.t("install.permission_unix",{command:p}))))}const{action:u}=!i()||l()?{action:"continue"}:await e.prompt([{type:"list",name:"action",message:n.t("install.what_next"),choices:[{name:n.t("install.installed_continue"),value:"continue"},{name:n.t("install.cancel_install"),value:"cancel"}]}]);if("cancel"===u)throw new Error(n.t("install.user_cancelled"));if(O(),!this.isToolInstalled(t))throw console.log(r.red("× "+n.t("install.still_not_installed",{tool:a.displayName}))),new Error(`${a.displayName} is not installed`);console.log(r.green("√ "+n.t("install.verified_success",{tool:a.displayName})))}getToolConfig(o){const t=d(o);if(!t)throw new Error(`Unknown tool: ${o}`);try{return t.getConfig()}catch(t){return a.warn(`Failed to read config for ${o}:`,t),a.logError(`ToolManager.getToolConfig(${o})`,t),null}}updateToolConfig(o,t){const n=d(o);if(!n)throw new Error(`Unknown tool: ${o}`);if(!n.updateConfig)throw new Error(`Tool ${o} does not support raw config updates`);n.updateConfig(t)}forceResetConfig(o){const t=d(o);if(!t)throw new Error(`Unknown tool: ${o}`);const n=t.forceResetPaths?t.forceResetPaths():this.backupPathsFor(t),e=[];for(const o of n)h(o)&&(m(o),w(o,{force:!0}),e.push(o));return e}loadPrivateConfig(o,t,n,e,r={}){const i=d(o);if(!i)throw new Error(`Unknown tool: ${o}`);r.force&&this.forceResetConfig(o),i.loadPrivateConfig({apiKey:t,baseUrl:s.getBaseUrl(),models:n,settings:s.getToolSettings(o),...e?{catalog:e}:{},...r.takeOver?{takeOver:!0}:{}})}async applyPrivateConfig(o,t,n,e={}){const r=this.installedVersion(o);return I(`apply:${o}`,()=>this.applyPrivateConfigNow(o,t,n,e),{...r?{tool_version:r}:{},...e.force?{force:!0}:{}})}async applyPrivateConfigNow(o,t,n,e){const r=d(o);if(!r)throw new Error(`Unknown tool: ${o}`);const i=r.wantsModelCatalog?await T(t):null,{force:l,takeOver:a}=e;l||a?this.loadPrivateConfig(o,t,n,i??void 0,{force:l,takeOver:a}):i?this.loadPrivateConfig(o,t,n,i):this.loadPrivateConfig(o,t,n)}applyNotes(o){const t=d(o);if(!t)return[];const e=[];try{t.applyNotes&&e.push(...t.applyNotes())}catch(t){a.logError(`ToolManager.applyNotes(${o})`,t)}const r=this.outdatedVersion(o);if(r){e.push({kind:"action",text:n.t("tools.version_outdated",{current:r.current,min:r.min,upgrade:t.installSpec?`${b} upgrade ${o}`:t.upgradeCommand||t.installCommand})});for(const o of t.upgradeHints?.(r.min)??[])e.push({kind:"action",text:o})}const i=t.installSpec?E(t.installSpec):[];return i.length>1&&e.push({kind:"action",text:n.t("upgrade.duplicates_note",{count:String(i.length),active:_(i[0]),others:i.slice(1).map(_).join("、"),tool:o})}),e}printApplied(o,t=16){const n=SUPPORTED_TOOLS[o]?.displayName??o,e=this.applyNotes(o);for(const o of e.filter(o=>"detail"===o.kind))a.record(`${n}: ${o.text}`);const i=e.filter(o=>"summary"===o.kind).map(o=>o.text).join(";"),l=" ".repeat(Math.max(1,t-$(n)));console.log(r.green("√ "+n)+(i?l+i:""));for(const o of e.filter(o=>"action"===o.kind))console.log(r.yellow(" ! "+o.text))}installedVersion(o){const n=d(o);if(!n)return null;if(n.installSpec)return E(n.installSpec)[0]?.version??null;if(n.installedVersion)try{return n.installedVersion()}catch(t){return a.logError(`ToolManager.installedVersion(${o})`,t),null}if(n.isInstalled)return null;try{const o={encoding:"utf-8",timeout:1e4,windowsHide:!0,stdio:["ignore","pipe","pipe"]},e=`${("win32"===process.platform?t(`${n.command} --version`,{...o,shell:!0}):t(n.command,["--version"],o)).stdout??""}`.match(/(\d+)\.(\d+)\.(\d+)/);return e?e[0]:null}catch{return null}}outdatedVersion(o){const t=C(o);if(!t)return null;const n=this.installedVersion(o);return n&&k(n,t)<0?{current:n,min:t}:null}unloadPrivateConfig(o){const t=d(o);if(!t)throw new Error(`Unknown tool: ${o}`);try{t.unloadPrivateConfig({savedKeys:c()}),x(`remove:${o}`,"ok")}catch(t){throw x(`remove:${o}`,"fail",{error:t}),t}let e=[];try{e=t.unloadNotes?.()??[]}catch(t){a.logError(`ToolManager.unloadNotes(${o})`,t)}return e.length>0?e:[{kind:"action",text:n.t("config.reopen_hint",{tool:t.displayName})}]}async clearPinnedModels(o){const t=d(o);if(!t)throw new Error(`Unknown tool: ${o}`);if(s.setToolModel(o,null),!t.clearPinnedModels)return[];const n=s.getApiKeyForTool(o),e=t.wantsModelCatalog&&n?await T(n):null;return t.clearPinnedModels(e??void 0)}supportsClearPinnedModels(o){return Boolean(d(o)?.clearPinnedModels)}holdsOurConfig(o){const t=d(o);if(!t)return!1;const n=c();return t.holdsOurConfig?t.holdsOurConfig(n):Boolean(t.detectCurrentConfig().apiKey)}detectCurrentConfig(o){const t=d(o);if(!t)throw new Error(`Unknown tool: ${o}`);return t.detectCurrentConfig()}backupPathsFor(o){return o.backupPaths?o.backupPaths():[o.configPath]}listToolBackups(o){const t=d(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,backups:f(o)}))}restorePrivateConfig(o){const t=d(o);if(!t)throw new Error(`Unknown tool: ${o}`);return this.backupPathsFor(t).map(o=>({file:o,result:g(o)}))}getInstalledTools(){return Object.keys(SUPPORTED_TOOLS).filter(o=>this.isToolInstalled(o))}getSupportedTools(){return p().filter(o=>!o.hidden).map(o=>L(o.name))}isGitInstalled(){try{const t="win32"===process.platform?"where git":"which git";return o(t,{stdio:"pipe"}),!0}catch{return!1}}}export const toolManager=ToolManager.getInstance();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{join as e}from"path";import{applyGatewayModels as t,claudeCodeManager as o}from"../claude-code-manager.js";import{backupBeforeWrite as
|
|
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 d}from"./types.js";import{gatewayAddresses as c,normalizeBaseUrl as u}from"../gateway-addresses.js";import{configManager as m,savedApiKeys as p}from"../config.js";import{envCleanupPlan as g,lastEnvCleanup as f}from"../env-cleanup.js";import{maskHome as _}from"../telemetry.js";import{spawnSync as h}from"child_process";import{existsSync as C,readFileSync as v}from"fs";import{detectManagedOverrides as j}from"./claude-managed.js";import{installOfficialPlugins as y}from"./claude-plugins.js";import{findInstalls as k,mirrorInstallCommand as A,brandInstallScripts as P}from"./tool-installs.js";import{updateNativeFromMirror as S}from"./claude-native-mirror.js";import{brandEnv as O}from"../brand.js";import{claudeFormat as x,claudeProjectFiles as T}from"../sessions/formats.js";const N=e(d(),".claude","settings.json"),b=e(d(),".claude.json");let H,R=null,U=()=>0===h("security",["find-generic-password","-s","Claude Code-credentials"],{stdio:"ignore"}).status;export function setClaudeKeychainProbeForTests(e){U=e}export function claudeAccountLoginPresent(){const t=process.env.CLAUDE_CONFIG_DIR?.trim()||e(d(),".claude");if(C(e(t,".credentials.json")))return!0;if("darwin"!==process.platform||O("TEST_HOME"))return!1;try{return U()}catch{return!1}}function w(){try{const t=JSON.parse(v(e(d(),".claude","settings.json"),"utf-8"));return"string"==typeof t.autoUpdatesChannel?t.autoUpdatesChannel:"latest"}catch{return"latest"}}function E(e){if(!e)return;const t=new Set(e.models);return r("claude-code",e.clientModels).filter(e=>t.has(e.id))}function L(){const e=o.getSettings().env?.ANTHROPIC_BASE_URL;return"string"==typeof e&&e.trim()?claudeCodeAdapter.holdsOurConfig(p())?null:e.trim():null}let I=null;const M={command:"claude",npmPackage:"@anthropic-ai/claude-code",native:{binDir:[".local","bin"],updateArgs:["update"],dataDirs:[[".local","share","claude"]],mirrorUpdate:()=>S(w())},mirrorScript:P("claude-code"),brew:"claude-code"};export const claudeCodeAdapter={name:"claude-code",displayName:"Claude Code",command:"claude",installCommand:A(M),upgradeCommand:"claude update",installSpec:M,upgradeHints:e=>"stable"===w()?[s.t("tools.claude_code.stable_channel",{min:e})]:[],configPath:N,sessions:{format:x,files:()=>T(e(process.env.CLAUDE_CONFIG_DIR?.trim()||e(d(),".claude"),"projects")),resumeCommand:e=>({command:"claude",args:["--resume",e]})},wantsModelCatalog:!0,loadPrivateConfig(t){I=L(),n(N),n(b),H=E(t.catalog),o.loadPrivateConfig(t.apiKey,t.models,t.catalog?.models,H);const s=e(d(),".local","bin","win32"===process.platform?"claude.exe":"claude"),a=k(claudeCodeAdapter.installSpec)[0]?.path??(C(s)?s:null);R=a?y(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&&(c().some(e=>e.url===s)||s===u(m.getBaseUrl()))},planNotes(){const e=[],t=L();t&&e.push(s.t("tools.claude_code.plan_replace_provider",{url:t}));for(const t of g())e.push(s.t("tools.claude_code.plan_env_remove",{location:_(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(N),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(N),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,E(e.catalog));JSON.stringify(a)!==JSON.stringify(s)&&(n(N),o.saveSettings(a))},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")}),H&&H.length>0&&(e.push({kind:"summary",text:s.t("tools.claude_code.gateway_models",{count:String(H.length),vendors:l(H.map(e=>e.id)).join(" / ")})}),e.push({kind:"detail",text:H.map(e=>e.name||i(e.id)).join(", ")})),I&&e.push({kind:"summary",text:s.t("tools.claude_code.provider_replaced",{url:I})});const t=f();for(const o of t.removed)e.push({kind:"summary",text:s.t("tools.claude_code.env_removed",{location:_(o.location),vars:Object.keys(o.vars).join(", ")})});for(const o of t.foreign)e.push({kind:"action",text:s.t("tools.claude_code.env_foreign",{location:_(o.location),vars:Object.keys(o.vars).join(", ")})});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===h("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 j())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:()=>[N,b],forceResetPaths:()=>[N]};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ToolAdapter } from './types.js';
|
|
2
|
-
import type
|
|
2
|
+
import { type VibecliModels } from '../config.js';
|
|
3
3
|
import { type ModelCatalog } from '../model-catalog.js';
|
|
4
4
|
/**
|
|
5
5
|
* Tool setting (config.yaml `tool_settings['claude-desktop'].hide_official_login`).
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{chmodSync as e,existsSync as t,mkdirSync as o,readdirSync as n,readFileSync as r,rmSync as s}from"fs";import{dirname as i}from"path";import{join as l}from"path";import{randomUUID as a}from"crypto";import{execFileSync as c}from"child_process";import{userInfo as d}from"os";import p from"chalk";import{logger as u}from"../../utils/logger.js";import{track as f}from"../telemetry.js";import{ensureDesktopCli as m,installedDesktopAsarPath as g}from"./claude-desktop-cli.js";import{i18n as y}from"../i18n.js";import{BRAND_NAME as h,brand as k,brandEnv as _,CLI_NAME as b}from"../brand.js";import{backupBeforeWrite as D,atomicWriteFile as w}from"./backup.js";import{toolHome as A}from"./types.js";import{canRestartDesktop as C,desktopQuitRefused as E,isDesktopRunning as v,launchDesktop as M,quitDesktop as O,restartDesktop as S,WINDOWS_PACKAGE_FAMILIES as x}from"./desktop-process.js";import{desktopInstallBlocker as P,fetchLatestDesktopVersion as j,installedMacApp as I,installLatestDesktop as L}from"./claude-desktop-app.js";import{setUserRegistryElevated as T}from"./elevated-reg.js";import{UserActionNeeded as $}from"./types.js";import{baseModelId as N,isClaudeModel as R}from"../model-catalog.js";import{getDefaultModels as G}from"../model-registry.js";import{claudeFormat as K,nestedClaudeProjectFiles as U}from"../sessions/formats.js";import{powerShellEnv as F}from"../powershell-env.js";const H=h;export const CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING="hide_official_login";export const CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING="force_registry";const J=/^[a-f0-9-]{36}$/;function V(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}export function claudeDesktopUserDataDir(){const e=process.env.CLAUDE_USER_DATA_DIR?.trim();if(e)return e;const o=A(),n=Boolean(_("TEST_HOME")?.trim());switch(process.platform){case"darwin":return l(o,"Library","Application Support","Claude-3p");case"win32":{const e=!n&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:l(o,"AppData","Local");return x.map(t=>l(e,"Packages",t,"LocalCache","Local","Claude-3p")).find(e=>t(e))??l(e,"Claude-3p")}default:{const e=!n&&process.env.XDG_CONFIG_HOME?process.env.XDG_CONFIG_HOME:l(o,".config");return l(e,"Claude-3p")}}}const B=()=>l(claudeDesktopUserDataDir(),"configLibrary"),W=()=>l(B(),"_meta.json"),z=e=>l(B(),`${e}.json`),q=()=>l(claudeDesktopUserDataDir(),"claude_desktop_config.json");function X(e){if(!t(e))return null;const o=r(e,"utf-8");if(!o.trim())return null;try{const e=JSON.parse(o);return V(e)?e:null}catch(t){throw new Error(`Existing ${e} cannot be parsed; back it up and fix it first: ${t instanceof Error?t.message:String(t)}`)}}function Z(n,r){const s=i(n);t(s)||o(s,{recursive:!0,mode:448}),D(n),w(n,JSON.stringify(r,null,2)+"\n");try{e(n,384)}catch(e){u.logError("claude-desktop.writeJson.chmod",e)}}function Y(){const e=X(W());if(!e)return null;const t=Array.isArray(e.entries)?e.entries.filter(e=>V(e)&&"string"==typeof e.id&&"string"==typeof e.name):[];return{...e,appliedId:"string"==typeof e.appliedId?e.appliedId:"",entries:t}}function Q(e){return e?.entries.find(e=>e.name===H&&J.test(e.id))}const ee={opus:0,fable:1,sonnet:2,haiku:3};function te(e){let t=/^claude-(opus|sonnet|haiku|fable)-(\d+(?:-\d+)*)/i.exec(e);return t?{family:t[1].toLowerCase(),version:t[2].split("-").map(Number)}:(t=/^claude-(\d+(?:-\d+)*)-(opus|sonnet|haiku)/i.exec(e),t?{family:t[2].toLowerCase(),version:t[1].split("-").map(Number)}:null)}export function humanizeModelId(e){const t=te(e);return t?`${t.family[0].toUpperCase()+t.family.slice(1)} ${t.version.filter(e=>e<1e7).slice(0,2).join(".")}`:e}function oe(e){return te(e)?.family}export function buildInferenceModels(e,t){const{primary:o,bySlot:n}=function(e){const t=["opus","sonnet","haiku","reasoning"].map(t=>N(e[t]||"")).filter(Boolean);return{primary:t[0]??"",bySlot:t}}(e),r=new Set,s=t?.labels??{};let i;if(t&&t.models.some(R)){i=[...new Set(t.models.filter(R).map(N))];for(const e of t.oneMillion)r.add(e)}else{i=[];for(const t of["opus","sonnet","haiku","reasoning"]){const o=(e[t]||"").trim(),n=N(o);n&&(i.includes(n)||i.push(n),/\[1m\]/i.test(o)&&r.add(n))}}const l=e=>ee[oe(e)??""]??9;i.sort((e,t)=>{if(e===o)return-1;if(t===o)return 1;const n=l(e)-l(t);if(0!==n)return n;const r=te(e),s=te(t);return r&&s?function(e,t){const o=Math.max(e.length,t.length);for(let n=0;n<o;n++){const o=(t[n]??0)-(e[n]??0);if(0!==o)return o}return 0}(r.version,s.version):e.localeCompare(t)});const a=new Set,c=new Map,d=new Set(Object.values(G()).map(e=>N(e||"")));for(const e of n){const t=oe(e);t&&i.includes(e)&&!d.has(e)&&!c.has(t)&&c.set(t,e)}return i.map(e=>{const t=oe(e),o={name:e,labelOverride:s[e]||humanizeModelId(e)};if(r.has(e)&&(o.supports1m=!0,o.prefer1m=!0),t){o.anthropicFamilyTier=t;const n=c.get(t);n&&n!==e||a.has(t)||(o.isFamilyDefault=!0,a.add(t))}return o})}let ne=null,re=null,se=null,ie=null,le=null;function ae(e){return{inferenceProvider:"gateway",inferenceCredentialKind:"static",inferenceGatewayBaseUrl:(e.baseUrl||"").trim().replace(/\/+$/,""),inferenceGatewayApiKey:e.apiKey,inferenceModels:buildInferenceModels(e.models,e.catalog),disableDeploymentModeChooser:!1!==e.settings?.hide_official_login,chatTabEnabled:!0,chatAdvancedFileAnalysisEnabled:!0,autoModeEnabled:!0,coworkEgressAllowedHosts:["*"],disableEssentialTelemetry:!0,disableNonessentialTelemetry:!0,disableNonessentialServices:!1}}const ce={defaultModelEffort:"medium",modelPrefer1mContext:!0,skipWebFetchPreflight:!0,toolSearchEnabled:!0,builtinBrowserEnabled:!0,isDesktopExtensionEnabled:!0,sshHostAllowlist:["*"],claudeAiImport:{enabled:!0,automatic3pImport:!0,exportEnabled:!0},coworkVmIpv6Enabled:!0,mcpToolTimeoutSec:3600,updateViaUpdatesHost:!0,banner:{enabled:!1}},de=()=>{if(_("TEST_HOME")?.trim())return null;const e=g();return e?r(e):null};let pe=de,ue=null;export function setDesktopAsarForTests(e){pe=void 0===e?de:()=>e,ue=null}function fe(){if(ue)return ue;let e=null;try{e=pe()}catch(e){u.logError("claude-desktop.unsupportedDefaults",e)}return ue=new Set(e?Object.keys(ce).filter(t=>!e.includes(t)):[]),ue}function me(e){const t=fe();return Object.fromEntries(Object.entries(ce).filter(([o])=>!e(o)&&!t.has(o)))}function ge(e){const t={...me(t=>t in e),...e};for(const e of fe())e in t&&JSON.stringify(t[e])===JSON.stringify(ce[e])&&delete t[e];return t}const ye="SOFTWARE\\Policies\\Claude",he=`HKCU\\${ye}`,ke="HKLM\\SOFTWARE\\Policies\\Claude",_e=`${b}-claude-policy.reg`,be=e=>c("reg",e,{stdio:["ignore","pipe","pipe"]}).toString();let De=be;export function setRegRunnerForTests(e){De=e??be}function we(){return"win32"===process.platform}function Ae(e){let t;try{t=De(["query",e])}catch{return null}const o=new Map;for(const e of t.split(/\r?\n/)){const t=/^\s{2,}(\S+)\s+(REG_[A-Z_]+)\s*(.*)$/.exec(e);t&&o.set(t[1],t[3])}return o}function Ce(){if(null===Ae(he))return;const e=l(claudeDesktopUserDataDir(),_e);try{t(i(e))||o(i(e),{recursive:!0,mode:448}),D(e),De(["export",he,e,"/y"])}catch(e){u.logError("claude-desktop.snapshotPolicy",e)}}function Ee(e){Ce();for(const[t,o]of Object.entries(e)){const[e,n]="boolean"==typeof o?["REG_DWORD",o?"1":"0"]:"number"==typeof o?["REG_DWORD",String(o)]:"string"==typeof o?["REG_SZ",o]:["REG_SZ",JSON.stringify(o)];De(["add",he,"/v",t,"/t",e,"/d",n,"/f"])}}function ve(e){const t=Ae(he);if(!t)return;Ce();let o=t.size;for(const n of e)t.has(n)&&(De(["delete",he,"/v",n,"/f"]),o-=1);o<=0&&De(["delete",he,"/f"])}function Me(){const e=!Boolean(_("TEST_HOME")?.trim())&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:l(A(),"AppData","Local");return!!t(l(e,"AnthropicClaude"))||x.some(o=>t(l(e,"Packages",o,"LocalCache","Local","Claude-3p")))}const Oe=[...Object.keys(ae({apiKey:"",baseUrl:"",models:{haiku:"",sonnet:"",opus:"",reasoning:""}})),...Object.keys(ce)];export function detectManagedConfig(){try{if("darwin"===process.platform){let e="";try{e=d().username}catch{}return[e?`/Library/Managed Preferences/${e}/com.anthropic.claudefordesktop.plist`:"","/Library/Managed Preferences/com.anthropic.claudefordesktop.plist"].filter(Boolean).find(e=>t(e))??null}if("win32"===process.platform)return Ae(ke)?ke:null;const e="/etc/claude-desktop/managed-settings.json";return t(e)?e:null}catch(e){return u.logError("claude-desktop.detectManagedConfig",e),null}}function Se(){const e=A();let o;switch(process.platform){case"darwin":o=["/Applications/Claude.app",l(e,"Applications","Claude.app")];break;case"win32":{const t=process.env.LOCALAPPDATA||l(e,"AppData","Local");o=[l(t,"AnthropicClaude"),l(t,"Programs","Claude"),...x.map(e=>l(t,"Packages",e))];break}default:o=["/usr/lib/claude-desktop","/opt/Claude","/usr/bin/claude-desktop",l(e,".local","bin","claude-desktop")]}return o.push(claudeDesktopUserDataDir(),l(claudeDesktopUserDataDir(),"..","Claude")),o.some(e=>t(e))}const xe=/\d+\.\d+\.\d+/;function Pe(e){const t=e=>e.split(".").map(Number);return e.sort((e,o)=>{const[n,r]=[t(e),t(o)];for(let e=0;e<3;e++)if(n[e]!==r[e])return r[e]-n[e];return 0})[0]??null}function je(){if("darwin"===process.platform){for(const e of["/Applications/Claude.app",l(A(),"Applications","Claude.app")]){const o=l(e,"Contents","Info.plist");if(!t(o))continue;const n=/<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/.exec(r(o,"utf-8")),s=n?xe.exec(n[1])?.[0]:void 0;if(s)return s}return null}if("win32"===process.platform){const e=l(process.env.LOCALAPPDATA||l(A(),"AppData","Local"),"AnthropicClaude");if(t(e)){const t=n(e).map(e=>/^app-(\d+\.\d+\.\d+)$/.exec(e)?.[1]).filter(e=>!!e);if(t.length>0)return Pe(t)}const o=x.map(e=>`'${e}'`).join(",");return Pe(c("powershell.exe",["-NoProfile","-Command",`Get-AppxPackage | Where-Object { @(${o}) -contains $_.PackageFamilyName } | ForEach-Object { $_.Version.ToString() }`],{encoding:"utf-8",timeout:15e3,windowsHide:!0,stdio:["ignore","pipe","ignore"],env:F()}).split(/\r?\n/).flatMap(e=>xe.exec(e)?.[0]??[]))}if("linux"===process.platform)try{const e=c("dpkg-query",["-W","-f=${Version}","claude-desktop"],{encoding:"utf-8",timeout:5e3,stdio:["ignore","pipe","ignore"]});return xe.exec(e)?.[0]??null}catch{return null}return null}const Ie="darwin"===process.platform?"open -a Claude":"win32"===process.platform?"Claude":"claude-desktop",Le="darwin"!==process.platform&&"win32"!==process.platform||!k().installMirror?.claudeDesktop?"https://claude.ai/download":k().installMirror.claudeDesktop,Te="darwin"===process.platform?`open ${Le}`:"win32"===process.platform?`start ${Le}`:`xdg-open ${Le}`;export const claudeDesktopAdapter={name:"claude-desktop",displayName:"Claude Desktop",command:Ie,installCommand:Te,configPath:W(),sessions:{format:K,files:()=>U(l(claudeDesktopUserDataDir(),"local-agent-mode-sessions"))},isInstalled:Se,installedVersion:je,prepareRuntime:async function(){if(!["win32","darwin","linux"].includes(process.platform)||!Se())return[];const e=Date.now();try{const t=await m({userDataDir:claudeDesktopUserDataDir(),onDownload:e=>console.log(p.gray(" "+y.t("tools.claude_desktop.code_cli_downloading",{version:e}))),desktopVersion:"darwin"===process.platform?je():null,mirrorRepo:k().installMirror?.claudeDesktop?.replace(/\/-\/releases\/latest\/?$/,"")??null});return f("desktop-code-cli","skipped"===t.status?"skip":"ok",{duration_ms:Date.now()-e,detail:{...t}}),"installed"!==t.status?[]:[{kind:"summary",text:y.t("tools.claude_desktop.code_cli_installed",{version:t.version})}]}catch(t){return u.logError("claude-desktop.prepareCodeTabCli",t),f("desktop-code-cli","fail",{duration_ms:Date.now()-e,error:t}),[{kind:"action",text:y.t("tools.claude_desktop.code_cli_failed",{reason:t instanceof Error?t.message:String(t)})}]}},runningApp:C()?{isRunning:v,restart:S,quit:O,quitRefused:E,launch:M}:void 0,appInstaller:{vendor:"Anthropic",sizeMb:()=>300,downloadPage:"https://claude.ai/download",blocker:P,latestVersion:()=>j(),installedPath(){if("darwin"===process.platform)return I();if("win32"!==process.platform)return null;try{return je()?"MSIX":null}catch(e){return u.logError("claude-desktop.installedPath",e),null}},install:e=>L(e)},wantsModelCatalog:!0,loadPrivateConfig(e){const t=Y()??{appliedId:"",entries:[]};let o=Q(t);o||(o={id:a(),name:H},t.entries.push(o));const n=ae(e);re=!0===n.disableDeploymentModeChooser,ne={models:n.inferenceModels,source:e.catalog?e.catalog.oneMillionSource:"slots",groups:e.catalog?.matchedGroups??[]};const r=X(z(o.id))??{};Z(z(o.id),{...ge(r),...n}),t.appliedId=o.id,Z(W(),t);const s=X(q())??{};if("3p"!==s.deploymentMode&&Z(q(),{...s,deploymentMode:"3p"}),ie=null,le=null,se=null,we()){const t=Ae(he),o=Oe.filter(e=>t?.has(e)),r={...me(e=>t?.has(e)??!1),...n},s=!0===e.settings?.force_registry,i=!s&&Me();try{i?ve(Oe):Ee(r),se=i?"removed":"written"}catch(e){u.logError("claude-desktop.policy",e),ie=e instanceof Error?e.message.trim():String(e),(o.length>0||s)&&(le=i?{action:"remove",values:Object.fromEntries(o.map(e=>[e,null])),deleteKey:o.length===t.size}:{action:"write",values:r,deleteKey:!1})}}},pendingElevation(){const e=le;return e?{prompt:y.t(`tools.claude_desktop.elevate_${e.action}`),run:()=>{if(!T(ye,e.values,e.deleteKey))return!1;const t=Ae(he),o="remove"===e.action?Object.keys(e.values).every(e=>!t?.has(e)):Object.keys(e.values).every(e=>t?.has(e));return o&&(le=null,ie=null),o}}:null},unloadPrivateConfig(){if(we())try{ve(Oe)}catch(e){u.logError("claude-desktop.removePolicy",e)}const e=Y(),t=Q(e);if(!e||!t)return;D(z(t.id)),s(z(t.id),{force:!0});const o=e.entries.filter(e=>e.id!==t.id);0===o.length?(D(W()),s(W(),{force:!0})):Z(W(),{...e,entries:o,appliedId:e.appliedId===t.id?o[0].id:e.appliedId})},listedModels(){const e=Y(),t=Q(e);if(!t||e?.appliedId!==t.id)return null;const o=X(z(t.id))?.inferenceModels;return Array.isArray(o)?o.map(e=>String(e.name)):null},refreshModelMenu(e){const t=Y(),o=Q(t);if(!o||t?.appliedId!==o.id)return;const n=X(z(o.id));if(!n)return;const r=buildInferenceModels(e.models,e.catalog),s=JSON.stringify(n.inferenceModels)!==JSON.stringify(r),i={...ge(n),inferenceModels:r},l=JSON.stringify(i)!==JSON.stringify(n);le=null;const a=we()?Ae(he):null;if(!a?.has("inferenceModels"))return void(l&&Z(z(o.id),i));const c=Oe.filter(e=>a.has(e)),d=!0!==e.settings?.force_registry&&Me();if(l&&Z(z(o.id),i),d||s)try{d?ve(Oe):Ee({inferenceModels:r})}catch(e){throw u.logError("claude-desktop.refreshModelMenu registry",e),le=d?{action:"remove",values:Object.fromEntries(c.map(e=>[e,null])),deleteKey:c.length===a.size}:{action:"write",values:{inferenceModels:r},deleteKey:!1},new $(y.t("tools.claude_desktop.refresh_needs_admin"))}},detectCurrentConfig(){try{if(we()){const e=Ae(he)?.get("inferenceGatewayApiKey");if(e)return{apiKey:e}}const e=Q(Y());if(!e)return{apiKey:null};const t=X(z(e.id)),o=t?.inferenceGatewayApiKey;return{apiKey:"string"==typeof o&&o?o:null}}catch(e){return u.logError("claude-desktop.detectCurrentConfig",e),{apiKey:null}}},getConfig(){try{const e=Y(),t=Q(e);return{meta:e,applied:t?X(z(t.id)):null,desktop:X(q()),...we()?{policy:Object.fromEntries(Ae(he)??[])}:{}}}catch(e){return u.logError("claude-desktop.getConfig",e),null}},clearPinnedModels(){let e=!1;we()&&Ae(he)?.has("inferenceModels")&&(Ce(),De(["delete",he,"/v","inferenceModels","/f"]),e=!0);const t=Q(Y()),o=t?X(z(t.id)):null;if(t&&o&&void 0!==o.inferenceModels){const{inferenceModels:n,...r}=o;Z(z(t.id),r),e=!0}return e?["inferenceModels"]:[]},applyNotes(){const e=[];if(ne&&ne.models.length>0){const{models:t,source:o,groups:n}=ne;e.push({kind:"summary",text:y.t("tools.claude_desktop.models_summary",{count:String(t.length),default:t[0].labelOverride??t[0].name})}),e.push({kind:"detail",text:y.t(`tools.claude_desktop.models_written_${o}`,{count:String(t.length),list:t.map(e=>`${e.labelOverride}${e.supports1m?" (1M)":""}`).join(", "),groups:n.join(" / ")})})}null!==re&&e.push({kind:"detail",text:y.t(re?"tools.claude_desktop.official_login_hidden":"tools.claude_desktop.official_login_shown")}),C()&&!v()||e.push({kind:"action",text:y.t("tools.claude_desktop.restart_hint")}),le?(e.push({kind:"action",text:y.t(`tools.claude_desktop.policy_stale_${le.action}`)}),e.push({kind:"detail",text:ie??""})):ie?(e.push({kind:"detail",text:y.t("tools.claude_desktop.registry_denied")}),e.push({kind:"detail",text:ie})):we()&&se&&e.push({kind:"detail",text:y.t(`tools.claude_desktop.registry_${se}`,{key:he})});const t=detectManagedConfig();return t&&e.push({kind:"action",text:y.t("tools.claude_desktop.managed_conflict",{path:t})}),e},forceResetPaths(){const e=[W(),q()];try{const t=Q(Y());t&&e.push(z(t.id))}catch{}return e},backupPaths(){const e=[W(),q()];we()&&e.push(l(claudeDesktopUserDataDir(),_e));try{const t=Q(Y());t&&e.push(z(t.id))}catch{}return e}};
|
|
1
|
+
import{chmodSync as e,existsSync as t,mkdirSync as o,readdirSync as n,readFileSync as r,rmSync as s}from"fs";import{dirname as i}from"path";import{join as l}from"path";import{randomUUID as a}from"crypto";import{execFileSync as c}from"child_process";import{userInfo as d}from"os";import u from"chalk";import{logger as p}from"../../utils/logger.js";import{track as f}from"../telemetry.js";import{ensureDesktopCli as m,installedDesktopAsarPath as g}from"./claude-desktop-cli.js";import{i18n as y}from"../i18n.js";import{BRAND_NAME as h,brand as k,brandEnv as _,CLI_NAME as w}from"../brand.js";import{backupBeforeWrite as b,atomicWriteFile as D}from"./backup.js";import{toolHome as A}from"./types.js";import{canRestartDesktop as C,desktopQuitRefused as v,isDesktopRunning as E,launchDesktop as M,quitDesktop as O,restartDesktop as S,WINDOWS_PACKAGE_FAMILIES as x}from"./desktop-process.js";import{desktopInstallBlocker as j,fetchLatestDesktopVersion as P,installedMacApp as I,installLatestDesktop as L}from"./claude-desktop-app.js";import{setUserRegistryElevated as T}from"./elevated-reg.js";import{UserActionNeeded as $}from"./types.js";import{savedApiKeys as G}from"../config.js";import{isOurGatewayUrl as N,noteWrittenGatewayUrl as U}from"../gateway-addresses.js";import{baseModelId as R,isClaudeModel as K}from"../model-catalog.js";import{getDefaultModels as F}from"../model-registry.js";import{claudeFormat as B,nestedClaudeProjectFiles as H}from"../sessions/formats.js";import{powerShellEnv as J}from"../powershell-env.js";const V=h;export const CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING="hide_official_login";export const CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING="force_registry";const W=/^[a-f0-9-]{36}$/;function z(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}export function claudeDesktopUserDataDir(){const e=process.env.CLAUDE_USER_DATA_DIR?.trim();if(e)return e;const o=A(),n=Boolean(_("TEST_HOME")?.trim());switch(process.platform){case"darwin":return l(o,"Library","Application Support","Claude-3p");case"win32":{const e=!n&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:l(o,"AppData","Local");return x.map(t=>l(e,"Packages",t,"LocalCache","Local","Claude-3p")).find(e=>t(e))??l(e,"Claude-3p")}default:{const e=!n&&process.env.XDG_CONFIG_HOME?process.env.XDG_CONFIG_HOME:l(o,".config");return l(e,"Claude-3p")}}}const q=()=>l(claudeDesktopUserDataDir(),"configLibrary"),X=()=>l(q(),"_meta.json"),Z=e=>l(q(),`${e}.json`),Y=()=>l(claudeDesktopUserDataDir(),"claude_desktop_config.json");function Q(e){if(!t(e))return null;const o=r(e,"utf-8");if(!o.trim())return null;try{const e=JSON.parse(o);return z(e)?e:null}catch(t){throw new Error(`Existing ${e} cannot be parsed; back it up and fix it first: ${t instanceof Error?t.message:String(t)}`)}}function ee(n,r){const s=i(n);t(s)||o(s,{recursive:!0,mode:448}),b(n),D(n,JSON.stringify(r,null,2)+"\n");try{e(n,384)}catch(e){p.logError("claude-desktop.writeJson.chmod",e)}}function te(){const e=Q(X());if(!e)return null;const t=Array.isArray(e.entries)?e.entries.filter(e=>z(e)&&"string"==typeof e.id&&"string"==typeof e.name):[];return{...e,appliedId:"string"==typeof e.appliedId?e.appliedId:"",entries:t}}function oe(e){return e?.entries.find(e=>e.name===V&&W.test(e.id))}const ne={opus:0,fable:1,sonnet:2,haiku:3};function re(e){let t=/^claude-(opus|sonnet|haiku|fable)-(\d+(?:-\d+)*)/i.exec(e);return t?{family:t[1].toLowerCase(),version:t[2].split("-").map(Number)}:(t=/^claude-(\d+(?:-\d+)*)-(opus|sonnet|haiku)/i.exec(e),t?{family:t[2].toLowerCase(),version:t[1].split("-").map(Number)}:null)}export function humanizeModelId(e){const t=re(e);return t?`${t.family[0].toUpperCase()+t.family.slice(1)} ${t.version.filter(e=>e<1e7).slice(0,2).join(".")}`:e}function se(e){return re(e)?.family}export function buildInferenceModels(e,t){const{primary:o,bySlot:n}=function(e){const t=["opus","sonnet","haiku","reasoning"].map(t=>R(e[t]||"")).filter(Boolean);return{primary:t[0]??"",bySlot:t}}(e),r=new Set,s=t?.labels??{};let i;if(t&&t.models.some(K)){i=[...new Set(t.models.filter(K).map(R))];for(const e of t.oneMillion)r.add(e)}else{i=[];for(const t of["opus","sonnet","haiku","reasoning"]){const o=(e[t]||"").trim(),n=R(o);n&&(i.includes(n)||i.push(n),/\[1m\]/i.test(o)&&r.add(n))}}const l=e=>ne[se(e)??""]??9;i.sort((e,t)=>{if(e===o)return-1;if(t===o)return 1;const n=l(e)-l(t);if(0!==n)return n;const r=re(e),s=re(t);return r&&s?function(e,t){const o=Math.max(e.length,t.length);for(let n=0;n<o;n++){const o=(t[n]??0)-(e[n]??0);if(0!==o)return o}return 0}(r.version,s.version):e.localeCompare(t)});const a=new Set,c=new Map,d=new Set(Object.values(F()).map(e=>R(e||"")));for(const e of n){const t=se(e);t&&i.includes(e)&&!d.has(e)&&!c.has(t)&&c.set(t,e)}return i.map(e=>{const t=se(e),o={name:e,labelOverride:s[e]||humanizeModelId(e)};if(r.has(e)&&(o.supports1m=!0,o.prefer1m=!0),t){o.anthropicFamilyTier=t;const n=c.get(t);n&&n!==e||a.has(t)||(o.isFamilyDefault=!0,a.add(t))}return o})}let ie=null,le=null,ae=null,ce=null,de=null;function ue(e){return{inferenceProvider:"gateway",inferenceCredentialKind:"static",inferenceGatewayBaseUrl:(e.baseUrl||"").trim().replace(/\/+$/,""),inferenceGatewayApiKey:e.apiKey,inferenceModels:buildInferenceModels(e.models,e.catalog),disableDeploymentModeChooser:!1!==e.settings?.hide_official_login,chatTabEnabled:!0,chatAdvancedFileAnalysisEnabled:!0,autoModeEnabled:!0,coworkEgressAllowedHosts:["*"],disableEssentialTelemetry:!0,disableNonessentialTelemetry:!0,disableNonessentialServices:!1}}const pe={defaultModelEffort:"medium",modelPrefer1mContext:!0,skipWebFetchPreflight:!0,toolSearchEnabled:!0,builtinBrowserEnabled:!0,isDesktopExtensionEnabled:!0,sshHostAllowlist:["*"],claudeAiImport:{enabled:!0,automatic3pImport:!0,exportEnabled:!0},coworkVmIpv6Enabled:!0,mcpToolTimeoutSec:3600,updateViaUpdatesHost:!0,banner:{enabled:!1}},fe=()=>{if(_("TEST_HOME")?.trim())return null;const e=g();return e?r(e):null};let me=fe,ge=null;export function setDesktopAsarForTests(e){me=void 0===e?fe:()=>e,ge=null}function ye(){if(ge)return ge;let e=null;try{e=me()}catch(e){p.logError("claude-desktop.unsupportedDefaults",e)}return ge=new Set(e?Object.keys(pe).filter(t=>!e.includes(t)):[]),ge}function he(e){const t=ye();return Object.fromEntries(Object.entries(pe).filter(([o])=>!e(o)&&!t.has(o)))}function ke(e){const t={...he(t=>t in e),...e};for(const e of ye())e in t&&JSON.stringify(t[e])===JSON.stringify(pe[e])&&delete t[e];return t}const _e="SOFTWARE\\Policies\\Claude",we=`HKCU\\${_e}`,be="HKLM\\SOFTWARE\\Policies\\Claude",De=`${w}-claude-policy.reg`,Ae=e=>c("reg",e,{stdio:["ignore","pipe","pipe"]}).toString();let Ce=Ae;export function setRegRunnerForTests(e){Ce=e??Ae}function ve(){return"win32"===process.platform}function Ee(e){let t;try{t=Ce(["query",e])}catch{return null}const o=new Map;for(const e of t.split(/\r?\n/)){const t=/^\s{2,}(\S+)\s+(REG_[A-Z_]+)\s*(.*)$/.exec(e);t&&o.set(t[1],t[3])}return o}function Me(){if(null===Ee(we))return;const e=l(claudeDesktopUserDataDir(),De);try{t(i(e))||o(i(e),{recursive:!0,mode:448}),b(e),Ce(["export",we,e,"/y"])}catch(e){p.logError("claude-desktop.snapshotPolicy",e)}}function Oe(e){Me();for(const[t,o]of Object.entries(e)){const[e,n]="boolean"==typeof o?["REG_DWORD",o?"1":"0"]:"number"==typeof o?["REG_DWORD",String(o)]:"string"==typeof o?["REG_SZ",o]:["REG_SZ",JSON.stringify(o)];Ce(["add",we,"/v",t,"/t",e,"/d",n,"/f"])}}function Se(e){const t=Ee(we);if(!t)return;Me();let o=t.size;for(const n of e)t.has(n)&&(Ce(["delete",we,"/v",n,"/f"]),o-=1);o<=0&&Ce(["delete",we,"/f"])}function xe(){const e=!Boolean(_("TEST_HOME")?.trim())&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:l(A(),"AppData","Local");return!!t(l(e,"AnthropicClaude"))||x.some(o=>t(l(e,"Packages",o,"LocalCache","Local","Claude-3p")))}const je=[...Object.keys(ue({apiKey:"",baseUrl:"",models:{haiku:"",sonnet:"",opus:"",reasoning:""}})),...Object.keys(pe)];function Pe(e){if(!e||!je.some(t=>e.has(t)))return"none";const t=e.get("inferenceGatewayApiKey")?.trim();return N(e.get("inferenceGatewayBaseUrl"))||t&&G().includes(t)?"ours":"foreign"}function Ie(){const e=Q(Y())?.deploymentMode;if(void 0!==e&&"3p"!==e)return{kind:"mode"};const t=te(),o=t?.entries.find(e=>e.id===t.appliedId);if(!o||o.id===oe(t)?.id)return null;const n=Q(Z(o.id));return n&&(n.inferenceProvider||n.inferenceGatewayBaseUrl)?{kind:"entry",name:o.name}:null}function Le(e){return"mode"===e.kind?y.t("tools.claude_desktop.current_official"):y.t("tools.claude_desktop.current_entry",{name:e.name})}let Te=null,$e=null;export function detectManagedConfig(){try{if("darwin"===process.platform){let e="";try{e=d().username}catch{}return[e?`/Library/Managed Preferences/${e}/com.anthropic.claudefordesktop.plist`:"","/Library/Managed Preferences/com.anthropic.claudefordesktop.plist"].filter(Boolean).find(e=>t(e))??null}if("win32"===process.platform)return Ee(be)?be:null;const e="/etc/claude-desktop/managed-settings.json";return t(e)?e:null}catch(e){return p.logError("claude-desktop.detectManagedConfig",e),null}}function Ge(){const e=A();let o;switch(process.platform){case"darwin":o=["/Applications/Claude.app",l(e,"Applications","Claude.app")];break;case"win32":{const t=process.env.LOCALAPPDATA||l(e,"AppData","Local");o=[l(t,"AnthropicClaude"),l(t,"Programs","Claude"),...x.map(e=>l(t,"Packages",e))];break}default:o=["/usr/lib/claude-desktop","/opt/Claude","/usr/bin/claude-desktop",l(e,".local","bin","claude-desktop")]}return o.push(claudeDesktopUserDataDir(),l(claudeDesktopUserDataDir(),"..","Claude")),o.some(e=>t(e))}const Ne=/\d+\.\d+\.\d+/;function Ue(e){const t=e=>e.split(".").map(Number);return e.sort((e,o)=>{const[n,r]=[t(e),t(o)];for(let e=0;e<3;e++)if(n[e]!==r[e])return r[e]-n[e];return 0})[0]??null}function Re(){if("darwin"===process.platform){for(const e of["/Applications/Claude.app",l(A(),"Applications","Claude.app")]){const o=l(e,"Contents","Info.plist");if(!t(o))continue;const n=/<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/.exec(r(o,"utf-8")),s=n?Ne.exec(n[1])?.[0]:void 0;if(s)return s}return null}if("win32"===process.platform){const e=l(process.env.LOCALAPPDATA||l(A(),"AppData","Local"),"AnthropicClaude");if(t(e)){const t=n(e).map(e=>/^app-(\d+\.\d+\.\d+)$/.exec(e)?.[1]).filter(e=>!!e);if(t.length>0)return Ue(t)}const o=x.map(e=>`'${e}'`).join(",");return Ue(c("powershell.exe",["-NoProfile","-Command",`Get-AppxPackage | Where-Object { @(${o}) -contains $_.PackageFamilyName } | ForEach-Object { $_.Version.ToString() }`],{encoding:"utf-8",timeout:15e3,windowsHide:!0,stdio:["ignore","pipe","ignore"],env:J()}).split(/\r?\n/).flatMap(e=>Ne.exec(e)?.[0]??[]))}if("linux"===process.platform)try{const e=c("dpkg-query",["-W","-f=${Version}","claude-desktop"],{encoding:"utf-8",timeout:5e3,stdio:["ignore","pipe","ignore"]});return Ne.exec(e)?.[0]??null}catch{return null}return null}const Ke="darwin"===process.platform?"open -a Claude":"win32"===process.platform?"Claude":"claude-desktop",Fe="darwin"!==process.platform&&"win32"!==process.platform||!k().installMirror?.claudeDesktop?"https://claude.ai/download":k().installMirror.claudeDesktop,Be="darwin"===process.platform?`open ${Fe}`:"win32"===process.platform?`start ${Fe}`:`xdg-open ${Fe}`;export const claudeDesktopAdapter={name:"claude-desktop",displayName:"Claude Desktop",command:Ke,installCommand:Be,configPath:X(),sessions:{format:B,files:()=>H(l(claudeDesktopUserDataDir(),"local-agent-mode-sessions"))},isInstalled:Ge,installedVersion:Re,prepareRuntime:async function(){if(!["win32","darwin","linux"].includes(process.platform)||!Ge())return[];const e=Date.now();try{const t=await m({userDataDir:claudeDesktopUserDataDir(),onDownload:e=>console.log(u.gray(" "+y.t("tools.claude_desktop.code_cli_downloading",{version:e}))),desktopVersion:"darwin"===process.platform?Re():null,mirrorRepo:k().installMirror?.claudeDesktop?.replace(/\/-\/releases\/latest\/?$/,"")??null});return f("desktop-code-cli","skipped"===t.status?"skip":"ok",{duration_ms:Date.now()-e,detail:{...t}}),"installed"!==t.status?[]:[{kind:"summary",text:y.t("tools.claude_desktop.code_cli_installed",{version:t.version})}]}catch(t){return p.logError("claude-desktop.prepareCodeTabCli",t),f("desktop-code-cli","fail",{duration_ms:Date.now()-e,error:t}),[{kind:"action",text:y.t("tools.claude_desktop.code_cli_failed",{reason:t instanceof Error?t.message:String(t)})}]}},runningApp:C()?{isRunning:E,restart:S,quit:O,quitRefused:v,launch:M}:void 0,appInstaller:{vendor:"Anthropic",sizeMb:()=>300,downloadPage:"https://claude.ai/download",blocker:j,latestVersion:()=>P(),installedPath(){if("darwin"===process.platform)return I();if("win32"!==process.platform)return null;try{return Re()?"MSIX":null}catch(e){return p.logError("claude-desktop.installedPath",e),null}},install:e=>L(e)},wantsModelCatalog:!0,loadPrivateConfig(e){const t=te()??{appliedId:"",entries:[]};let o=oe(t);o||(o={id:a(),name:V},t.entries.push(o));const n=ue(e);U(String(n.inferenceGatewayBaseUrl)),le=!0===n.disableDeploymentModeChooser,ie={models:n.inferenceModels,source:e.catalog?e.catalog.oneMillionSource:"slots",groups:e.catalog?.matchedGroups??[]};const r=Q(Z(o.id))??{};ee(Z(o.id),{...ke(r),...n});const s=Ie();Te=s&&!e.takeOver?Le(s):null,Te||(t.appliedId=o.id),ee(X(),t);const i=Q(Y())??{};Te||"3p"===i.deploymentMode||ee(Y(),{...i,deploymentMode:"3p"}),ce=null,de=null,ae=null,$e=null;const l=!0===e.settings?.force_registry,c=ve()?Ee(we):null;if(ve()&&"foreign"===Pe(c)&&!l)$e=c?.get("inferenceGatewayBaseUrl")||we;else if(ve()){const t=Ee(we),o=je.filter(e=>t?.has(e)),r={...he(e=>t?.has(e)??!1),...n},s=!0===e.settings?.force_registry,i=!s&&xe();try{i?Se(je):Oe(r),ae=i?"removed":"written"}catch(e){p.logError("claude-desktop.policy",e),ce=e instanceof Error?e.message.trim():String(e),(o.length>0||s)&&(de=i?{action:"remove",values:Object.fromEntries(o.map(e=>[e,null])),deleteKey:o.length===t.size}:{action:"write",values:r,deleteKey:!1})}}},pendingElevation(){const e=de;return e?{prompt:y.t(`tools.claude_desktop.elevate_${e.action}`),run:()=>{if(!T(_e,e.values,e.deleteKey))return!1;const t=Ee(we),o="remove"===e.action?Object.keys(e.values).every(e=>!t?.has(e)):Object.keys(e.values).every(e=>t?.has(e));return o&&(de=null,ce=null),o}}:null},unloadPrivateConfig(){if(ve()&&"ours"===Pe(Ee(we)))try{Se(je)}catch(e){p.logError("claude-desktop.removePolicy",e)}const e=te(),t=oe(e);if(!e||!t)return;b(Z(t.id)),s(Z(t.id),{force:!0});const o=e.entries.filter(e=>e.id!==t.id);0===o.length?(b(X()),s(X(),{force:!0})):ee(X(),{...e,entries:o,appliedId:e.appliedId===t.id?o[0].id:e.appliedId})},listedModels(){const e=te(),t=oe(e);if(!t||e?.appliedId!==t.id)return null;const o=Q(Z(t.id))?.inferenceModels;return Array.isArray(o)?o.map(e=>String(e.name)):null},refreshModelMenu(e){const t=te(),o=oe(t);if(!o||t?.appliedId!==o.id)return;const n=Q(Z(o.id));if(!n)return;const r=buildInferenceModels(e.models,e.catalog),s=JSON.stringify(n.inferenceModels)!==JSON.stringify(r),i={...ke(n),inferenceModels:r},l=JSON.stringify(i)!==JSON.stringify(n);de=null;const a=ve()?Ee(we):null,c="foreign"===Pe(a)&&!0!==e.settings?.force_registry;if(!a?.has("inferenceModels")||c)return void(l&&ee(Z(o.id),i));const d=je.filter(e=>a.has(e)),u=!0!==e.settings?.force_registry&&xe();if(l&&ee(Z(o.id),i),u||s)try{u?Se(je):Oe({inferenceModels:r})}catch(e){throw p.logError("claude-desktop.refreshModelMenu registry",e),de=u?{action:"remove",values:Object.fromEntries(d.map(e=>[e,null])),deleteKey:d.length===a.size}:{action:"write",values:{inferenceModels:r},deleteKey:!1},new $(y.t("tools.claude_desktop.refresh_needs_admin"))}},detectCurrentConfig(){try{if(ve()){const e=Ee(we)?.get("inferenceGatewayApiKey");if(e)return{apiKey:e}}const e=oe(te());if(!e)return{apiKey:null};const t=Q(Z(e.id)),o=t?.inferenceGatewayApiKey;return{apiKey:"string"==typeof o&&o?o:null}}catch(e){return p.logError("claude-desktop.detectCurrentConfig",e),{apiKey:null}}},getConfig(){try{const e=te(),t=oe(e);return{meta:e,applied:t?Q(Z(t.id)):null,desktop:Q(Y()),...ve()?{policy:Object.fromEntries(Ee(we)??[])}:{}}}catch(e){return p.logError("claude-desktop.getConfig",e),null}},clearPinnedModels(){let e=!1;ve()&&Ee(we)?.has("inferenceModels")&&(Me(),Ce(["delete",we,"/v","inferenceModels","/f"]),e=!0);const t=oe(te()),o=t?Q(Z(t.id)):null;if(t&&o&&void 0!==o.inferenceModels){const{inferenceModels:n,...r}=o;ee(Z(t.id),r),e=!0}return e?["inferenceModels"]:[]},applyNotes(){const e=[];if(ie&&ie.models.length>0){const{models:t,source:o,groups:n}=ie;e.push({kind:"summary",text:y.t("tools.claude_desktop.models_summary",{count:String(t.length),default:t[0].labelOverride??t[0].name})}),e.push({kind:"detail",text:y.t(`tools.claude_desktop.models_written_${o}`,{count:String(t.length),list:t.map(e=>`${e.labelOverride}${e.supports1m?" (1M)":""}`).join(", "),groups:n.join(" / ")})})}null!==le&&e.push({kind:"detail",text:y.t(le?"tools.claude_desktop.official_login_hidden":"tools.claude_desktop.official_login_shown")}),C()&&!E()||e.push({kind:"action",text:y.t("tools.claude_desktop.restart_hint")}),de?(e.push({kind:"action",text:y.t(`tools.claude_desktop.policy_stale_${de.action}`)}),e.push({kind:"detail",text:ce??""})):ce?(e.push({kind:"detail",text:y.t("tools.claude_desktop.registry_denied")}),e.push({kind:"detail",text:ce})):ve()&&ae&&e.push({kind:"detail",text:y.t(`tools.claude_desktop.registry_${ae}`,{key:we})}),Te&&e.push({kind:"action",text:y.t("tools.claude_desktop.not_switched",{current:Te})}),$e&&e.push({kind:"action",text:y.t("tools.claude_desktop.foreign_policy",{key:we,url:$e})});const t=detectManagedConfig();return t&&e.push({kind:"action",text:y.t("tools.claude_desktop.managed_conflict",{path:t})}),e},planNotes(){const e=[],t=Ie();if(t&&e.push(y.t("tools.claude_desktop.plan_switch",{current:Le(t)})),ve()){const t=Ee(we);"foreign"===Pe(t)&&e.push(y.t("tools.claude_desktop.plan_foreign_policy",{key:we,url:t?.get("inferenceGatewayBaseUrl")||"-"}))}return e},forceResetPaths(){const e=[X(),Y()];try{const t=oe(te());t&&e.push(Z(t.id))}catch{}return e},backupPaths(){const e=[X(),Y()];ve()&&e.push(l(claudeDesktopUserDataDir(),De));try{const t=oe(te());t&&e.push(Z(t.id))}catch{}return e}};
|
package/dist/lib/tools/codex.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createHash as e}from"crypto";import{existsSync as t,mkdirSync as o,readdirSync as n,readFileSync as r,rmSync as i,statSync as s,writeFileSync as a}from"fs";import{join as l}from"path";import*as c from"@iarna/toml";import{logger as d}from"../../utils/logger.js";import{i18n as u}from"../i18n.js";import{backupBeforeWrite as m,atomicWriteFile as p}from"./backup.js";import{codexHome as f,pickModel as _,toolHome as g,withV1 as x}from"./types.js";import{moveSessionsToProvider as h,NO_STATE_DB as y,runningCodexPids as k}from"../codex-sessions.js";import{codexFormat as b,codexRolloutFiles as v}from"../sessions/formats.js";import{getToolDefaultModel as w}from"../model-registry.js";import{configManager as j}from"../config.js";import{maskHome as C,track as O}from"../telemetry.js";import{buildCodexCatalog as S,catalogRejections as M,codexCatalogPath as A,fillFromOlderEntries as E,installedCodexBinaries as N,loadBundledCodexModels as P,loadPreviousCodexModels as T,previousGatewayModelIds as D}from"./codex-catalog.js";import{gatewayModelSpecs as I,modelFamily as L}from"../gateway-models.js";import{findInstalls as $,mirrorInstallCommand as J,brandInstallScripts as G}from"./tool-installs.js";import{chatgptDesktopApp as R}from"./chatgpt-desktop.js";const K=()=>f(),X=()=>l(K(),"config.toml"),B="sessions_move_declined",U=["browser_use","browser_use_external","computer_use"];function W(e){const t=e.features;if(!V(t)||!U.every(e=>!1===t[e]))return!1;for(const e of U)delete t[e];return!0}export function codexWorkModeOn(){try{const e=ee();return e.model_provider===F&&V(e.desktop)&&"STEPS_PROSE"===e.desktop.conversationDetailMode}catch{return!1}}function q(){try{if(V(ee().desktop))return!0}catch{}if("darwin"===process.platform)return["/Applications",l(g(),"Applications")].some(e=>["ChatGPT.app","Codex.app"].some(o=>t(l(e,o))));if("win32"===process.platform){const e=l(process.env.LOCALAPPDATA||l(g(),"AppData","Local"),"Packages");try{return n(e).some(e=>/^OpenAI\.(Codex|ChatGPT)/i.test(e))}catch{return!1}}return t("/usr/lib/chatgpt/ChatGPT")}export function codexConfigPath(){return X()}const z=()=>l(K(),"auth.json"),Y="OPENAI_API_KEY",F="custom",H=1e6,Q=9e5;export const CODEX_ONE_MILLION_CONTEXT_SETTING="one_million_context";function V(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function Z(e,t){return V(e[t])||(e[t]={}),e[t]}function ee(){if(!t(X()))return{};const e=r(X(),"utf-8");if(!e.trim())return{};try{const t=c.parse(e);if(!V(t))throw new Error("config.toml root must be a TOML table");return t}catch(e){throw new Error(`Existing ~/.codex/config.toml cannot be parsed; back it up and fix it first: ${e instanceof Error?e.message:String(e)}`)}}function te(){if(!t(z()))return{};try{const e=JSON.parse(r(z(),"utf-8"));return V(e)?e:{}}catch{return{}}}let oe=null;function ne(e){const t=e.profiles;if(V(t)){for(const[e,o]of Object.entries(t))V(o)&&2===Object.keys(o).length&&o.model_provider===F&&o.model===e&&delete t[e];0===Object.keys(t).length&&delete e.profiles}}let re=null;const ie=()=>l(j.getConfigDir(),"codex-catalog-check.json");function se(e){const o=A();t(o)&&r(o,"utf-8")===e||(m(o),p(o,e))}function ae(t,n){if(0===n.length)return[];const i=function(t,o){const n=e("sha256").update(t);for(const e of o)try{const t=s(e);n.update(`\0${e}\0${t.size}\0${t.mtimeMs}`)}catch{n.update(`\0${e}`)}return n.digest("hex")}(t,n);if(function(e){try{return JSON.parse(r(ie(),"utf-8")).signature===e}catch{return!1}}(i))return[];const l=M(A(),n);return 0===l.length&&function(e){try{o(j.getConfigDir(),{recursive:!0}),a(ie(),JSON.stringify({signature:e})+"\n")}catch(e){d.logError("codexAdapter.rememberAccepted",e)}}(i),l}function le(e,t,o){const n=!1!==t.settings?.one_million_context;!function(e){e.model_context_window===H&&delete e.model_context_window,e.model_auto_compact_token_limit===Q&&delete e.model_auto_compact_token_limit}(e);const r=()=>{e.model_catalog_json===A()&&delete e.model_catalog_json,n&&(e.model_context_window=H,e.model_auto_compact_token_limit=Q)},s=P()??T();if(!s)return d.logError("codexAdapter.writeModelCatalog",new Error("no Codex binary found; model catalog skipped")),re="skipped",void r();const a=t.catalog,l=e=>S({bundled:e,specs:I("codex",a?.clientModels),...a?{keyModels:a.models}:{},gatewayAvailable:a?.models??D(),oneMillion:n,selectedModel:o,..."gateway"===a?.oneMillionSource?{claudeOneMillion:a.oneMillion}:{}}),c=e=>JSON.stringify(e,null,2)+"\n";let u=l(s);se(c(u));const m=N(),p=ae(c(u),m);if(p.length>0){const e=Date.now();let t=!1;for(const e of p){const o=P(e.bin);if(o){for(const e of[{models:E(u.models,o)},{models:E(l(o).models,o)}])if(se(c(e)),0===ae(c(e),m).length){u=e,t=!0;break}if(t)break}}if(O("codex-catalog",t?"fallback":"fail",{duration_ms:Date.now()-e,error:p[0].error,detail:{rejected_by:p.map(e=>({version:e.version,path:C(e.bin)}))}}),!t)return re={rejectedBy:p[0]},i(A(),{force:!0}),void r()}re={listed:u.models.filter(e=>"list"===e.visibility).map(e=>({id:String(e.slug),name:String(e.display_name??e.slug)}))},e.model_catalog_json=A()}export function codexCatalogRejection(){let e;try{e=ee()}catch{return null}return e.model_catalog_json===A()&&t(A())?M(A())[0]??null:null}export function setCodexOneMillionContext(e,t){const o=ee(),n=c.stringify(o),r="string"==typeof o.model?o.model:w("codex");le(o,{settings:{[CODEX_ONE_MILLION_CONTEXT_SETTING]:e},catalog:t},r);const i=c.stringify(o);i!==n&&(m(X()),p(X(),i))}const ce={command:"codex",npmPackage:"@openai/codex",native:{binDir:"win32"===process.platform?["AppData","Local","Programs","OpenAI","Codex","bin"]:[".local","bin"],updateArgs:["update"],updateTimeoutMs:12e4,dataDirs:[[".codex","packages","standalone"]]},mirrorScript:G("codex"),brew:"codex"};export const codexAdapter={name:"codex",companionApps:[R],displayName:"Codex",command:"codex",installCommand:J(ce),installSpec:ce,configPath:X(),sessions:{format:b,files:()=>[...v(l(f(),"sessions")),...v(l(f(),"archived_sessions"))],resumeCommand:e=>({command:"codex",args:["resume",e]})},wantsModelCatalog:!0,listedModels(){if(ee().model_catalog_json!==A())return null;try{return(JSON.parse(r(A(),"utf-8")).models??[]).filter(e=>"list"===e.visibility).map(e=>String(e.slug))}catch{return null}},refreshModelMenu(e){if(ee().model_catalog_json!==A())return;setCodexOneMillionContext(!1!==e.settings?.one_million_context,e.catalog);const t=ee(),o=function(e,t){const o=V(e.model_providers)?e.model_providers[F]:void 0;return!(!V(o)||o.base_url!==t||!0===o.supports_standalone_web_search||(o.supports_standalone_web_search=!0,0))}(t,x(e.baseUrl));(W(t)||o)&&(m(X()),p(X(),c.stringify(t)))},async followUp(){if(ee().model_provider!==F)return null;const e=await h(F,{dryRun:!0}),t=Math.max(e.moved.length,e.dbRows);if(0===t)return null;const o=j.getToolSettings("codex")[B];if("number"==typeof o&&t<=o)return null;const n={count:String(t)};return k().length>0?{hint:u.t("tools.codex.sessions_hidden_running",n)}:{prompt:u.t("tools.codex.sessions_offer",n),hint:u.t("tools.codex.sessions_hidden",n),async run(){const e=await h(F),t=[...new Set(e.moved.map(e=>e.from))].join("、")||"-",o=String(Math.max(e.moved.length,e.dbRows)),n=[{kind:"summary",text:u.t("codex_sessions.moved",{count:o,from:t,target:F})},{kind:"summary",text:u.t("codex_sessions.backup",{dir:e.backupDir??""})}];return e.dbSkipped&&e.dbSkipped!==y&&n.push({kind:"action",text:u.t("codex_sessions.db_skipped",{reason:e.dbSkipped})}),n},decline(){j.setToolSetting("codex",B,t)}}},applyNotes(){if("skipped"===re)return 0===$(ce).length?[]:[{kind:"action",text:u.t("tools.codex.catalog_skipped")}];if(!re)return[];if("rejectedBy"in re){const{bin:e,version:t}=re.rejectedBy;return[{kind:"action",text:u.t("tools.codex.catalog_rejected",{path:e,version:t??"?"})}]}const e=new Map;for(const t of re.listed)e.set(L(t.id),(e.get(L(t.id))??0)+1);const t=["gpt","claude","gemini","other","grok"].filter(t=>e.has(t)).map(t=>`${u.t(`tools.model_family.${t}`)} ${e.get(t)}`).join(" · ");return[{kind:"summary",text:u.t("tools.codex.catalog_written",{count:String(re.listed.length),breakdown:t})},{kind:"detail",text:re.listed.map(e=>e.name).join(", ")},...codexWorkModeOn()||q()?[{kind:"action",text:u.t(codexWorkModeOn()?"tools.codex.work_mode_on":"tools.codex.work_mode_hint")}]:[]]},loadPrivateConfig(e){const t=w("codex"),o=_(e.models,t),n=function(e){return/(?:^|\/)claude(?:-|$)/i.test(e)}(o)?t:o,r=x(e.baseUrl),i=ee();i.model=n,i.model_provider=F,i.model_reasoning_effort="high",le(i,e,n);const s=Z(i,"model_providers"),a=V(s[F])?{...s[F]}:{};delete a.env_key;const{experimental_bearer_token:l,...d}=a;s[F]={...d,name:"custom",wire_api:"responses",requires_openai_auth:!0,supports_standalone_web_search:!0,base_url:r},ne(i),Z(Z(i,"tui"),"model_availability_nux")[n]=4;const u=Z(i,"features");u.goals=!0,u.js_repl=!1,W(i),m(X()),p(X(),c.stringify(i)),function(e){const t=e.trim();if(!t)return;const o={...te(),auth_mode:"apikey",[Y]:t};m(z()),p(z(),JSON.stringify(o,null,2)+"\n",384)}(e.apiKey)},holdsOurConfig(e){const t=te()[Y];return"string"==typeof t&&e.includes(t.trim())},unloadPrivateConfig(e){if(oe=function(e){const t=te(),o="string"==typeof t[Y]?t[Y].trim():"";if(!o)return V(t.tokens)?"chatgpt":null;if(!e.includes(o))return"other_key";const{[Y]:n,auth_mode:r,...s}=t;return m(z()),V(s.tokens)?(p(z(),JSON.stringify({...s,auth_mode:"chatgpt"},null,2)+"\n",384),"chatgpt"):(i(z(),{force:!0}),"signed_out")}(e?.savedKeys??[]),!t(X()))return;let o;try{o=ee()}catch(e){return void d.logError("codexAdapter.unloadPrivateConfig",e)}const n=o.model_providers;V(n)&&(delete n[F],0===Object.keys(n).length&&delete o.model_providers),o.model_provider===F&&delete o.model_provider,o.model_catalog_json===A()&&delete o.model_catalog_json,W(o),ne(o),m(X()),p(X(),c.stringify(o))},unloadNotes(){switch(oe){case"chatgpt":return[{kind:"action",text:u.t("tools.codex.unload_chatgpt_restored")}];case"other_key":return[{kind:"action",text:u.t("tools.codex.unload_other_key")}];default:return[{kind:"action",text:u.t("tools.codex.unload_sign_in")}]}},detectCurrentConfig(){const e=te()[Y];return{apiKey:"string"==typeof e&&e.trim()?e.trim():null}},getConfig(){try{return ee()}catch(e){return d.logError("codexAdapter.getConfig",e),null}},backupPaths:()=>[X(),z(),A()]};export function codexAuthProblem(){try{const e=ee(),t=e.model_providers?.[F];if(e.model_provider!==F||!t)return null;if("string"==typeof t.experimental_bearer_token&&t.experimental_bearer_token)return"stale_bearer";const o=te();return!0===t.requires_openai_auth&&"chatgpt"===o.auth_mode?"chatgpt_login":null}catch{return null}}
|
|
1
|
+
import{createHash as e}from"crypto";import{existsSync as t,mkdirSync as o,readdirSync as r,readFileSync as n,rmSync as s,statSync as i,writeFileSync as l}from"fs";import{join as a}from"path";import*as c from"@iarna/toml";import{logger as d}from"../../utils/logger.js";import{i18n as u}from"../i18n.js";import{backupBeforeWrite as m,atomicWriteFile as p}from"./backup.js";import{codexHome as f,pickModel as _,toolHome as g,withV1 as x}from"./types.js";import{moveSessionsToProvider as h,NO_STATE_DB as y,runningCodexPids as k}from"../codex-sessions.js";import{codexFormat as b,codexRolloutFiles as v}from"../sessions/formats.js";import{getGatewayModelRules as w,getToolDefaultModel as j}from"../model-registry.js";import{claimField as S}from"../written-values.js";import{configManager as C}from"../config.js";import{maskHome as O,track as M}from"../telemetry.js";import{buildCodexCatalog as A,catalogRejections as E,codexCatalogPath as N,fillFromOlderEntries as P,installedCodexBinaries as T,loadBundledCodexModels as D,loadPreviousCodexModels as $,previousGatewayModelIds as I}from"./codex-catalog.js";import{gatewayModelSpecs as L,modelFamily as J}from"../gateway-models.js";import{isOurGatewayUrl as G,noteWrittenGatewayUrl as R}from"../gateway-addresses.js";import{findInstalls as K,mirrorInstallCommand as X,brandInstallScripts as B}from"./tool-installs.js";import{chatgptDesktopApp as U}from"./chatgpt-desktop.js";const W=()=>f(),q=()=>a(W(),"config.toml"),z="sessions_move_declined",Y=["browser_use","browser_use_external","computer_use"],F="desktop_features_restored";function H(e){if(!0===C.getToolSetting("codex",F))return!1;const t=e.features,o=ae(t)&&Y.every(e=>!1===t[e]);if(C.setToolSetting("codex",F,!0),!o)return!1;for(const e of Y)delete t[e];return!0}export function codexWorkModeOn(){try{const e=de();return e.model_provider===ee&&ae(e.desktop)&&"STEPS_PROSE"===e.desktop.conversationDetailMode}catch{return!1}}function Q(){try{if(ae(de().desktop))return!0}catch{}if("darwin"===process.platform)return["/Applications",a(g(),"Applications")].some(e=>["ChatGPT.app","Codex.app"].some(o=>t(a(e,o))));if("win32"===process.platform){const e=a(process.env.LOCALAPPDATA||a(g(),"AppData","Local"),"Packages");try{return r(e).some(e=>/^OpenAI\.(Codex|ChatGPT)/i.test(e))}catch{return!1}}return t("/usr/lib/chatgpt/ChatGPT")}export function codexConfigPath(){return q()}const V=()=>a(W(),"auth.json"),Z="OPENAI_API_KEY",ee="custom",te="high",oe=["gpt-5.5","gpt-5.6-sol","gpt-6-astra"],re=["high","xhigh"],ne={goals:!0,js_repl:!1};let se=[];const ie=1e6,le=9e5;export const CODEX_ONE_MILLION_CONTEXT_SETTING="one_million_context";function ae(e){return!!e&&"object"==typeof e&&!Array.isArray(e)}function ce(e,t){return ae(e[t])||(e[t]={}),e[t]}function de(){if(!t(q()))return{};const e=n(q(),"utf-8");if(!e.trim())return{};try{const t=c.parse(e);if(!ae(t))throw new Error("config.toml root must be a TOML table");return t}catch(e){throw new Error(`Existing ~/.codex/config.toml cannot be parsed; back it up and fix it first: ${e instanceof Error?e.message:String(e)}`)}}function ue(){if(!t(V()))return{};try{const e=JSON.parse(n(V(),"utf-8"));return ae(e)?e:{}}catch{return{}}}let me=null;function pe(e){const t=e.profiles;if(ae(t)){for(const[e,o]of Object.entries(t))ae(o)&&2===Object.keys(o).length&&o.model_provider===ee&&o.model===e&&delete t[e];0===Object.keys(t).length&&delete e.profiles}}let fe=null;const _e=()=>a(C.getConfigDir(),"codex-catalog-check.json");function ge(e){const o=N();t(o)&&n(o,"utf-8")===e||(m(o),p(o,e))}function xe(t,r){if(0===r.length)return[];const s=function(t,o){const r=e("sha256").update(t);for(const e of o)try{const t=i(e);r.update(`\0${e}\0${t.size}\0${t.mtimeMs}`)}catch{r.update(`\0${e}`)}return r.digest("hex")}(t,r);if(function(e){try{return JSON.parse(n(_e(),"utf-8")).signature===e}catch{return!1}}(s))return[];const a=E(N(),r);return 0===a.length&&function(e){try{o(C.getConfigDir(),{recursive:!0}),l(_e(),JSON.stringify({signature:e})+"\n")}catch(e){d.logError("codexAdapter.rememberAccepted",e)}}(s),a}function he(e,t,o){const r=!1!==t.settings?.one_million_context;!function(e){e.model_context_window===ie&&delete e.model_context_window,e.model_auto_compact_token_limit===le&&delete e.model_auto_compact_token_limit}(e);const n=()=>{e.model_catalog_json===N()&&delete e.model_catalog_json,r&&(e.model_context_window=ie,e.model_auto_compact_token_limit=le)},i=D()??$();if(!i)return d.logError("codexAdapter.writeModelCatalog",new Error("no Codex binary found; model catalog skipped")),fe="skipped",void n();const l=t.catalog,a=e=>A({bundled:e,specs:L("codex",l?.clientModels),...l?{keyModels:l.models}:{},gatewayAvailable:l?.models??I(),oneMillion:r,selectedModel:o,..."gateway"===l?.oneMillionSource?{claudeOneMillion:l.oneMillion}:{}}),c=e=>JSON.stringify(e,null,2)+"\n";let u=a(i);ge(c(u));const m=T(),p=xe(c(u),m);if(p.length>0){const e=Date.now();let t=!1;for(const e of p){const o=D(e.bin);if(o){for(const e of[{models:P(u.models,o)},{models:P(a(o).models,o)}])if(ge(c(e)),0===xe(c(e),m).length){u=e,t=!0;break}if(t)break}}if(M("codex-catalog",t?"fallback":"fail",{duration_ms:Date.now()-e,error:p[0].error,detail:{rejected_by:p.map(e=>({version:e.version,path:O(e.bin)}))}}),!t)return fe={rejectedBy:p[0]},s(N(),{force:!0}),void n()}fe={listed:u.models.filter(e=>"list"===e.visibility).map(e=>({id:String(e.slug),name:String(e.display_name??e.slug)}))},e.model_catalog_json=N()}export function codexCatalogRejection(){let e;try{e=de()}catch{return null}return e.model_catalog_json===N()&&t(N())?E(N())[0]??null:null}export function setCodexOneMillionContext(e,t){const o=de(),r=c.stringify(o),n="string"==typeof o.model?o.model:j("codex");he(o,{settings:{[CODEX_ONE_MILLION_CONTEXT_SETTING]:e},catalog:t},n);const s=c.stringify(o);s!==r&&(m(q()),p(q(),s))}const ye={command:"codex",npmPackage:"@openai/codex",native:{binDir:"win32"===process.platform?["AppData","Local","Programs","OpenAI","Codex","bin"]:[".local","bin"],updateArgs:["update"],updateTimeoutMs:12e4,dataDirs:[[".codex","packages","standalone"]]},mirrorScript:B("codex"),brew:"codex"};function ke(e){const t=ae(e.model_providers)?e.model_providers[ee]:void 0;if(!ae(t))return null;const o="string"==typeof t.base_url?t.base_url.trim():"";return o&&!G(o)?o:null}let be=null;function ve(){if("skipped"===fe)return 0===K(ye).length?[]:[{kind:"action",text:u.t("tools.codex.catalog_skipped")}];if(!fe)return[];if("rejectedBy"in fe){const{bin:e,version:t}=fe.rejectedBy;return[{kind:"action",text:u.t("tools.codex.catalog_rejected",{path:e,version:t??"?"})}]}const e=new Map;for(const t of fe.listed)e.set(J(t.id),(e.get(J(t.id))??0)+1);const t=["gpt","claude","gemini","other","grok"].filter(t=>e.has(t)).map(t=>`${u.t(`tools.model_family.${t}`)} ${e.get(t)}`).join(" · ");return[{kind:"summary",text:u.t("tools.codex.catalog_written",{count:String(fe.listed.length),breakdown:t})},{kind:"detail",text:fe.listed.map(e=>e.name).join(", ")},...codexWorkModeOn()||Q()?[{kind:"action",text:u.t(codexWorkModeOn()?"tools.codex.work_mode_on":"tools.codex.work_mode_hint")}]:[]]}export const codexAdapter={name:"codex",companionApps:[U],displayName:"Codex",command:"codex",installCommand:X(ye),installSpec:ye,configPath:q(),sessions:{format:b,files:()=>[...v(a(f(),"sessions")),...v(a(f(),"archived_sessions"))],resumeCommand:e=>({command:"codex",args:["resume",e]})},wantsModelCatalog:!0,listedModels(){if(de().model_catalog_json!==N())return null;try{return(JSON.parse(n(N(),"utf-8")).models??[]).filter(e=>"list"===e.visibility).map(e=>String(e.slug))}catch{return null}},refreshModelMenu(e){if(de().model_catalog_json!==N())return;setCodexOneMillionContext(!1!==e.settings?.one_million_context,e.catalog);const t=de(),o=function(e,t){const o=ae(e.model_providers)?e.model_providers[ee]:void 0;return!(!ae(o)||o.base_url!==t||!0===o.supports_standalone_web_search||(o.supports_standalone_web_search=!0,0))}(t,x(e.baseUrl));(H(t)||o)&&(m(q()),p(q(),c.stringify(t)))},async followUp(){if(de().model_provider!==ee)return null;const e=await h(ee,{dryRun:!0}),t=Math.max(e.moved.length,e.dbRows);if(0===t)return null;const o=C.getToolSettings("codex")[z];if("number"==typeof o&&t<=o)return null;const r={count:String(t)};return k().length>0?{hint:u.t("tools.codex.sessions_hidden_running",r)}:{prompt:u.t("tools.codex.sessions_offer",r),hint:u.t("tools.codex.sessions_hidden",r),async run(){const e=await h(ee),t=[...new Set(e.moved.map(e=>e.from))].join("、")||"-",o=String(Math.max(e.moved.length,e.dbRows)),r=[{kind:"summary",text:u.t("codex_sessions.moved",{count:o,from:t,target:ee})},{kind:"summary",text:u.t("codex_sessions.backup",{dir:e.backupDir??""})}];return e.dbSkipped&&e.dbSkipped!==y&&r.push({kind:"action",text:u.t("codex_sessions.db_skipped",{reason:e.dbSkipped})}),r},decline(){C.setToolSetting("codex",z,t)}}},applyNotes(){const e=[];return be&&e.push({kind:"summary",text:u.t("tools.codex.provider_replaced",{url:be})}),se.length>0&&e.push({kind:"summary",text:u.t("tools.codex.kept_user_settings",{values:se.join(", ")})}),[...e,...ve()]},planNotes(){let e;try{e=de()}catch{return[]}const t=[],o=ke(e);return o?t.push(u.t("tools.codex.plan_replace_provider",{url:o})):"string"==typeof e.model_provider&&e.model_provider!==ee&&t.push(u.t("tools.codex.plan_switch_provider",{provider:e.model_provider})),t},loadPrivateConfig(e){const t=j("codex"),o=_(e.models,t),r=function(e){return/(?:^|\/)claude(?:-|$)/i.test(e)}(o)?t:o,n=x(e.baseUrl),s=de();se=[];const i=w().retired,l="string"==typeof s.model&&i.includes(s.model)?void 0:s.model;S("codex.model",l,r,{explicit:r!==t,legacy:oe})?s.model=r:se.push(`model = ${String(s.model)}`),s.model_provider=ee,S("codex.model_reasoning_effort",s.model_reasoning_effort,te,{legacy:re})?s.model_reasoning_effort=te:se.push(`model_reasoning_effort = ${String(s.model_reasoning_effort)}`);const a="string"==typeof s.model?s.model:r;he(s,e,a);const d=ce(s,"model_providers");be=ke(s),R(n);const u=ae(d[ee])?{...d[ee]}:{};delete u.env_key;const{experimental_bearer_token:f,...g}=u;d[ee]={...g,name:"custom",wire_api:"responses",requires_openai_auth:!0,supports_standalone_web_search:!0,base_url:n},pe(s),ce(ce(s,"tui"),"model_availability_nux")[a]=4;const h=ce(s,"features");for(const[e,t]of Object.entries(ne))(S(`codex.features.${e}`,h[e],String(t),{legacy:[String(t)]})||h[e]===t)&&(h[e]=t);H(s),m(q()),p(q(),c.stringify(s)),function(e){const t=e.trim();if(!t)return;const o={...ue(),auth_mode:"apikey",[Z]:t};m(V()),p(V(),JSON.stringify(o,null,2)+"\n",384)}(e.apiKey)},holdsOurConfig(e){const t=ue()[Z];return"string"==typeof t&&e.includes(t.trim())},unloadPrivateConfig(e){if(me=function(e){const t=ue(),o="string"==typeof t[Z]?t[Z].trim():"";if(!o)return ae(t.tokens)?"chatgpt":null;if(!e.includes(o))return"other_key";const{[Z]:r,auth_mode:n,...i}=t;return m(V()),ae(i.tokens)?(p(V(),JSON.stringify({...i,auth_mode:"chatgpt"},null,2)+"\n",384),"chatgpt"):(s(V(),{force:!0}),"signed_out")}(e?.savedKeys??[]),!t(q()))return;let o;try{o=de()}catch(e){return void d.logError("codexAdapter.unloadPrivateConfig",e)}const r=o.model_providers;ae(r)&&ae(r[ee])&&G(r[ee].base_url)&&ae(r)&&(delete r[ee],0===Object.keys(r).length&&delete o.model_providers,o.model_provider===ee&&delete o.model_provider),o.model_catalog_json===N()&&delete o.model_catalog_json,H(o),pe(o),m(q()),p(q(),c.stringify(o))},unloadNotes(){switch(me){case"chatgpt":return[{kind:"action",text:u.t("tools.codex.unload_chatgpt_restored")}];case"other_key":return[{kind:"action",text:u.t("tools.codex.unload_other_key")}];default:return[{kind:"action",text:u.t("tools.codex.unload_sign_in")}]}},detectCurrentConfig(){const e=ue()[Z];return{apiKey:"string"==typeof e&&e.trim()?e.trim():null}},getConfig(){try{return de()}catch(e){return d.logError("codexAdapter.getConfig",e),null}},backupPaths:()=>[q(),V(),N()]};export function codexAuthProblem(){try{const e=de(),t=e.model_providers?.[ee];if(e.model_provider!==ee||!t)return null;if("string"==typeof t.experimental_bearer_token&&t.experimental_bearer_token)return"stale_bearer";const o=ue();return!0===t.requires_openai_auth&&"chatgpt"===o.auth_mode?"chatgpt_login":null}catch{return null}}
|
|
@@ -36,6 +36,13 @@ export interface ToolApplyContext {
|
|
|
36
36
|
* Only resolved for adapters that set `wantsModelCatalog`; absent offline.
|
|
37
37
|
*/
|
|
38
38
|
catalog?: ModelCatalog;
|
|
39
|
+
/**
|
|
40
|
+
* The user asked for this tool by name (a tool-specific key, `config <tool>`, the wizard) or
|
|
41
|
+
* confirmed a write plan listing what gets replaced (`planNotes`): the adapter may switch the
|
|
42
|
+
* tool over from settings someone else made (Claude Desktop's deployment mode and active
|
|
43
|
+
* entry). Otherwise it writes its own entry and leaves the switch to the user (new-api#174).
|
|
44
|
+
*/
|
|
45
|
+
takeOver?: boolean;
|
|
39
46
|
}
|
|
40
47
|
/**
|
|
41
48
|
* One self-contained integration for a downstream coding tool.
|
|
@@ -217,6 +224,12 @@ export interface ToolAdapter {
|
|
|
217
224
|
* provider slot other software also writes (Codex auth.json, Claude Code env) check it.
|
|
218
225
|
*/
|
|
219
226
|
holdsOurConfig?(savedKeys: string[]): boolean;
|
|
227
|
+
/**
|
|
228
|
+
* Settings outside its own entry this write would remove or replace (another service's
|
|
229
|
+
* provider, shell variables, the app's active configuration): listed in the write plan and
|
|
230
|
+
* `--dry-run`, so the user sees them before saying yes.
|
|
231
|
+
*/
|
|
232
|
+
planNotes?(): string[];
|
|
220
233
|
/** Localized next steps after the last `unloadPrivateConfig` (e.g. how to sign in with the vendor's own account). */
|
|
221
234
|
unloadNotes?(): ApplyNote[];
|
|
222
235
|
/** Read back the api key currently configured for this tool, if any. */
|
package/dist/lib/wizard.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import e from"inquirer";import t from"chalk";import a from"ora";import{configManager as o,DEFAULT_MODELS as i}from"./config.js";import{getPresets as n,resolvePreset as r,getToolDefaultModel as s}from"./model-registry.js";import{toolManager as l,SUPPORTED_TOOLS as c}from"./tool-manager.js";import{confirmWritePlan as d}from"./write-plan.js";import{postApplyPrompts as p}from"./post-apply.js";import{appStatus as m,appStatusText as u,appTools as _,appsForTools as g,cachedAppStatus as w,upgradeApp as f}from"./app-update.js";import{i18n as y,detectSystemLang as h}from"./i18n.js";import{createBorderLine as z,createContentLine as v}from"../utils/string-width.js";import{validateApiKey as k,fetchModels as x}from"./api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as b}from"./tools/codex.js";import{CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as S}from"./tools/claude-desktop.js";import{addressesWithCurrent as C,ensureReachableGatewayAddress as M,fastestIndex as T,probeAll as A,probeSummary as K,reasonText as N,savedApiKey as B,switchGatewayAddress as P}from"../commands/base.js";import{readFileSync as W}from"fs";import{dirname as j,join as H}from"path";import{fileURLToPath as O}from"url";import{brand as L}from"./brand.js";const $=j(O(import.meta.url)),F=t.hex("#FF8700");export class Wizard{static instance;BOX_WIDTH=63;validatedApiKeys=new Set;constructor(){}static getInstance(){return Wizard.instance||(Wizard.instance=new Wizard),Wizard.instance}createBox(e){console.log(F.bold("\n"+z("╔","╗","═",this.BOX_WIDTH))),console.log(F.bold(v(e,"║","║",this.BOX_WIDTH,"center"))),console.log(F.bold(z("╚","╝","═",this.BOX_WIDTH))),console.log("")}showOperationHints(){const e=[t.gray(y.t("wizard.hint_navigate")),t.gray(y.t("wizard.hint_confirm"))];console.log(t.gray("💡 ")+e.join(t.gray(" | "))+"\n")}async promptWithHints(t){this.showOperationHints();const a=t.map(e=>"list"!==e.type||e.pageSize?e:{...e,pageSize:20});return e.prompt(a)}printBanner(){const e=60,t=y.t("wizard.banner_subtitle"),a=v(t,"║","║",e,"center"),o=v("","║","║",e,"center"),i=v(`${L().productName} v${function(){try{return JSON.parse(W(H($,"..","..","package.json"),"utf-8")).version}catch{return"0.0.0"}}()}`,"║","║",e,"center"),n=[String.raw`__ ___ _ ____ _ ___ `,String.raw`\ \ / (_) |__ ___ / ___| | |_ _|`,String.raw` \ \ / /| | '_ \ / _ \ | | | | | `,String.raw` \ V / | | |_) | __/ |___| |___ | | `,String.raw` \_/ |_|_.__/ \___|\____|_____|___|`],r=Math.max(...n.map(e=>e.length)),s=" ".repeat(Math.floor((58-r)/2)),l=n.map(t=>v(s+t,"║","║",e,"left")),c=[z("╔","╗","═",e),o,...l,o,i,a,z("╚","╝","═",e)];console.log(F.bold("\n"+c.join("\n")))}resetScreen(){console.clear(),this.printBanner()}printGoodbye(){const e=l.getSupportedTools().filter(e=>{if(e.gui)return!1;try{return Boolean(l.detectCurrentConfig(e.name).apiKey)&&l.isToolInstalled(e.name)}catch{return!1}});let a;if(e.length>0){const t=e.map(e=>e.command).join(" / ");a=y.t("wizard.goodbye_message_tools",{commands:t}),e.some(e=>"claude-code"===e.name)&&(a+=" "+y.t("wizard.goodbye_claude_hint"))}else a=y.t("wizard.goodbye_message");console.log(t.green("\n👋 "+a)),this.printPathReloadHint(e.map(e=>e.name))}printPathReloadHint(e){const a=e.filter(e=>!l.isOnPath(e));if(0===a.length)return;const o=a.map(e=>c[e].command).join(" / ");console.log(t.yellow(" ! "+y.t("win32"===process.platform?"setup.path_reload_windows":"setup.path_reload",{commands:o})))}async runFirstTimeSetup(){const e="zh_CN"===h();e&&(o.setLang("zh_CN"),y.setLocale("zh_CN")),this.resetScreen(),console.log(F.bold("\n"+y.t("wizard.welcome"))),console.log(t.gray(y.t("wizard.privacy_note")+"\n")),e?console.log(t.gray(y.t("wizard.lang_auto_zh")+"\n")):await this.configLanguage(),await M(),await this.configApiKey()&&await this.selectAndConfigureTool(!0)}async configLanguage(){for(;;){this.resetScreen(),this.createBox(y.t("wizard.select_language"));const a=y.getLocale(),{language:i}=await this.promptWithHints([{type:"list",name:"language",message:"✨ "+y.t("wizard.select_language"),choices:[{name:"[EN] English"+("en_US"===a?t.green(" ✓ ("+y.t("wizard.current_active")+")"):""),value:"en_US"},{name:"[CN] 中文"+("zh_CN"===a?t.green(" ✓ ("+y.t("wizard.current_active")+")"):""),value:"zh_CN"},new e.Separator,{name:"<- "+y.t("wizard.nav_return"),value:"back"},{name:"x "+y.t("wizard.nav_exit"),value:"exit"}],default:"zh_CN"}]);if("exit"===i)this.printGoodbye(),process.exit(0);else if("back"===i)return;return o.setLang(i),void y.setLocale(i)}}buildPresetChoices(){const a=n(),o=a.filter(e=>e.recommended),i=a.filter(e=>!e.recommended),r=e=>({name:(y.t(e.name)!==e.name?y.t(e.name):e.name)+(e.models?t.gray(` [H:${e.models.haiku} S:${e.models.sonnet} O:${e.models.opus}]`):""),value:{type:"preset",preset:e}}),s=[];return o.length>0&&(s.push(new e.Separator(t.hex("#FF8700")("── "+y.t("wizard.recommended")+" ──"))),s.push(...o.map(r))),i.length>0&&(s.push(new e.Separator(t.gray("── "+y.t("wizard.other_models")+" ──"))),s.push(...i.map(r))),s}async handleCustomModelInput(){const a=o.getModels(),{customMode:n}=await e.prompt([{type:"list",name:"customMode",message:y.t("wizard.custom_model_mode"),choices:[{name:y.t("wizard.custom_model_single"),value:"single"},{name:y.t("wizard.custom_model_per_role"),value:"per_role"}]}]);if("single"===n){const{customModel:t}=await e.prompt([{type:"input",name:"customModel",message:y.t("wizard.input_custom_model"),default:i.sonnet}]);o.setModels({haiku:t,sonnet:t,opus:t,reasoning:t})}else{const t=await e.prompt([{type:"input",name:"haiku",message:y.t("wizard.model_haiku"),default:a.haiku},{type:"input",name:"sonnet",message:y.t("wizard.model_sonnet"),default:a.sonnet},{type:"input",name:"opus",message:y.t("wizard.model_opus"),default:a.opus},{type:"input",name:"reasoning",message:y.t("wizard.model_reasoning"),default:a.reasoning}]);o.setModels(t)}console.log(t.green("\n✓ "+y.t("wizard.models_saved")))}async configModels(a){const i=o.getApiKey();if(await this.validatedKeyForConfiguration(i))for(;;){this.resetScreen(),this.createBox(y.t("wizard.config_models"));const i=[...this.buildPresetChoices()];i.push(new e.Separator),i.push({name:"✏️ "+y.t("wizard.custom_model_input"),value:{type:"custom_input"}}),i.push(new e.Separator),i.push({name:"<- "+y.t("wizard.nav_return"),value:{type:"back"}}),i.push({name:"x "+y.t("wizard.nav_exit"),value:{type:"exit"}});const{modelChoice:n}=await this.promptWithHints([{type:"list",name:"modelChoice",message:y.t("wizard.select_model_config"),choices:i}]);if("exit"===n.type)this.printGoodbye(),process.exit(0);else{if("back"===n.type)return;if("custom_input"===n.type)return await this.handleCustomModelInput(),void(a?.skipLoadPrompt||await this.promptLoadAfterModelConfig());if("preset"===n.type){const e=r(n.preset);return o.setModels(e),console.log(t.green("\n✓ "+y.t("wizard.models_saved"))),void(a?.skipLoadPrompt||await this.promptLoadAfterModelConfig())}}}else await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}])}async promptLoadAfterModelConfig(){const{shouldLoad:t}=await e.prompt([{type:"list",name:"shouldLoad",message:y.t("wizard.load_config_now"),choices:[{name:y.t("wizard.load_config_yes"),value:!0},{name:y.t("wizard.load_config_later"),value:!1}]}]);t&&await this.selectAndConfigureTool()}async configBaseUrl(){const i=o.getBaseUrl(),n=C(),r=a(y.t("wizard.base_testing")).start(),s=await A(n,{apiKey:B(),samples:3});r.stop();const l=T(s),c=n.map((e,a)=>{const o=e.url===i?t.cyan(` ← ${y.t("base.current_mark")}`):"";return{name:`${e.url} ${t.gray(e.label)} ${K(s[a],a===l)}${o}`,value:e.url}});c.push(new e.Separator,{name:"<- "+y.t("wizard.nav_return"),value:"__back__"});const{url:d}=await this.promptWithHints([{type:"list",name:"url",message:y.t("wizard.base_select"),choices:c,default:i}]);if("__back__"===d)return;const p=s[n.findIndex(e=>e.url===d)];p.ok?await P(d):console.log(t.red(y.t("base.unreachable",{url:d,reason:N(p)}))),await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}])}async configApiKey(){for(;;){this.resetScreen(),this.createBox(y.t("wizard.input_api_key")),console.log(t.gray("\n💡 "+y.t("wizard.api_key_input_hint"))),console.log(t.gray(" "+y.t("wizard.api_key_get_hint",{url:L().links.tokenPage}))),console.log();const{apiKey:i}=await e.prompt([{type:"password",name:"apiKey",message:y.t("wizard.input_your_api_key"),mask:"*"}]);if(!i||""===i.trim()){const{action:t}=await e.prompt([{type:"list",name:"action",message:y.t("wizard.select_action"),choices:[{name:y.t("wizard.retry_input"),value:"retry"},{name:"<- "+y.t("wizard.nav_return"),value:"back"}]}]);if("back"===t)return!1;continue}const n=a(y.t("wizard.validating_api_key")).start(),r=await k(i.trim());if(n.stop(),r.valid)return o.setApiKey(i.trim()),this.validatedApiKeys.add(i.trim()),console.log(t.green("\n✓ "+y.t("wizard.api_key_valid"))),!0;{this.validatedApiKeys.delete(i.trim()),"invalid_api_key"===r.error?console.log(t.red("\n✗ "+y.t("wizard.api_key_invalid"))):console.log(t.red("\n✗ "+y.t("wizard.api_key_network_error")));const{action:a}=await e.prompt([{type:"list",name:"action",message:y.t("wizard.select_action"),choices:[{name:y.t("wizard.retry_input"),value:"retry"},{name:"<- "+y.t("wizard.nav_return"),value:"back"}]}]);if("back"===a)return!1}}}async selectAndConfigureTool(a=!1){for(const e of _())await m(e).catch(()=>{});for(;;){this.resetScreen(),this.createBox(y.t("wizard.select_tool"));const o=l.getSupportedTools().map(e=>{const a=g([e.name]).map(e=>w(e)).find(e=>e.outdated);return{name:e.displayName+(a?t.yellow(" "+(a.tool===e.name?"":`${a.name} `)+u(a)):""),value:e.name}}),{tool:i}=await this.promptWithHints([{type:"list",name:"tool",message:"🛠️ "+y.t("wizard.select_tool"),choices:[...o,new e.Separator,{name:"<- "+y.t("wizard.nav_return"),value:"back"},{name:"x "+y.t("wizard.nav_exit"),value:"exit"}]}]);if("exit"===i)this.printGoodbye(),process.exit(0);else if("back"===i)return;await this.configureTool(i,a)}}async configureTool(a,o=!1){const i=c[a];if(i){if(!l.isToolInstalled(a)){console.log(t.yellow("\n"+y.t("wizard.tool_not_installed",{tool:i.displayName})));const{install:o}=await e.prompt([{type:"confirm",name:"install",message:y.t("wizard.install_tool_confirm"),default:!0}]);if(!o)return;try{await l.installTool(a)}catch{return void console.log(t.red(y.t("wizard.install_failed")))}}o?await this.configureToolModel(a)&&await this.loadConfig(a):await this.showToolMenu(a)}}async showToolMenu(t){for(;;){this.resetScreen();const a=c[t];if(!a)return;this.createBox(a.displayName+" "+y.t("wizard.menu_title"));const o=[{name:"📥 "+y.t("wizard.action_load_config",{tool:a.displayName}),value:"load"},{name:"📤 "+y.t("wizard.action_unload_config",{tool:a.displayName}),value:"unload"}];l.supportsClearPinnedModels(t)&&o.push({name:"🧹 "+y.t("wizard.action_clear_model",{tool:a.displayName}),value:"clear-model"});for(const e of g([t]).map(e=>w(e)).reverse()){if(e.blocker||!e.latest||!e.outdated&&e.installed)continue;const t=e.installed?y.t("wizard.action_upgrade_app",{tool:e.name,current:e.current??"?",latest:e.latest}):y.t("wizard.action_install_app",{tool:e.name,latest:e.latest});o.unshift({name:"↑ "+t,value:`upgrade-app:${e.tool}`})}o.push({name:"🧨 "+y.t("wizard.action_force_config",{tool:a.displayName}),value:"force"},{name:"↩️ "+y.t("wizard.action_restore_config",{tool:a.displayName}),value:"restore"},new e.Separator,{name:"<- "+y.t("wizard.nav_return"),value:"back"},{name:"x "+y.t("wizard.nav_exit"),value:"exit"});const{action:i}=await this.promptWithHints([{type:"list",name:"action",message:"⚙️ "+y.t("wizard.select_action"),choices:o}]);if("exit"===i)this.printGoodbye(),process.exit(0);else{if("back"===i)return;"load"===i?await this.configureToolModel(t)&&await this.loadConfig(t):"force"===i?await this.forceConfig(t):"unload"===i?await this.unloadConfig(t):"string"==typeof i&&i.startsWith("upgrade-app:")?(await f(i.slice(12),{install:!0}),await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}])):"clear-model"===i?await this.clearPinnedModels(t):"restore"===i&&await this.restoreConfig(t)}}}singleModelOverride(e){const t=e.trim();return/claude/i.test(t)?{opus:t}:{haiku:t,sonnet:t,opus:t,reasoning:t}}hasConfiguredApiKey(){return!!o.getApiKey()?.trim()||o.listToolApiKeys().some(e=>Boolean(o.getApiKeyForTool(e)?.trim()))}async validatedKeyForConfiguration(e){const o=e?.trim();if(!o)return console.log(t.red("\n"+y.t("wizard.api_key_required"))),console.log(t.yellow(y.t("wizard.please_config_api_key_first"))),null;if(this.validatedApiKeys.has(o))return o;const i=a(y.t("wizard.validating_api_key")).start(),n=await k(o);if(n.valid)return this.validatedApiKeys.add(o),i.succeed(y.t("wizard.api_key_valid")),o;this.validatedApiKeys.delete(o);const r="invalid_api_key"===n.error?y.t("wizard.api_key_invalid"):y.t("wizard.api_key_network_error");return i.fail(r),console.log(t.red("\n"+y.t("wizard.please_reconfig_api_key"))),null}async configureToolModel(i){const n=c[i];if(!n)return!1;const l=await this.validatedKeyForConfiguration(o.getApiKeyForTool(i));if(!l)return await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}]),!1;const d="claude-code"===i,p=d||"claude-desktop"===i||"agy"===i,m=s(i),u=p||!m?y.t("wizard.model_builtin_default"):m;this.resetScreen(),this.createBox(n.displayName+" · "+y.t("wizard.config_models"));const _=[{name:"✅ "+y.t("wizard.use_default_model",{model:u}),value:{type:"default"}},{name:"🌐 "+y.t("wizard.fetch_models_from_api"),value:{type:"fetch"}},...this.buildPresetChoices(),new e.Separator,{name:"✏️ "+y.t("wizard.input_custom_model"),value:{type:"custom"}},new e.Separator,{name:"<- "+y.t("wizard.nav_return"),value:{type:"back"}}],{choice:g}=await this.promptWithHints([{type:"list",name:"choice",message:y.t("wizard.select_tool_model",{tool:n.displayName}),choices:_}]);if("back"===g.type)return!1;if("default"===g.type)o.setToolModel(i,null);else if("preset"===g.type)o.setToolModel(i,r(g.preset));else if("custom"===g.type){const{model:t}=await e.prompt([{type:"input",name:"model",message:y.t("wizard.input_custom_model"),default:!p&&m?m:void 0}]),a=(t||"").trim();o.setToolModel(i,a?this.singleModelOverride(a):null)}else if("fetch"===g.type){const n=a(y.t("wizard.fetching_models")).start(),r=await x(l);let s;if(n.stop(),r.ok&&r.models.length>0){const{model:t}=await e.prompt([{type:"list",name:"model",message:y.t("wizard.select_fetched_model"),pageSize:20,choices:[...r.models,new e.Separator,{name:"<- "+y.t("wizard.nav_return"),value:"__back__"}]}]);if("__back__"===t)return!1;s=t}else{console.log(t.yellow("\n"+y.t("wizard.fetch_models_failed")));const{model:a}=await e.prompt([{type:"input",name:"model",message:y.t("wizard.input_custom_model"),default:!p&&m?m:void 0}]);s=(a||"").trim()}o.setToolModel(i,s?this.singleModelOverride(s):null)}if("codex"===i){const t=o.getToolSetting(i,b),{enableOneMillionContext:a}=await e.prompt([{type:"confirm",name:"enableOneMillionContext",message:y.t("wizard.codex_enable_1m_context"),default:!1!==t}]);o.setToolSetting(i,b,Boolean(a))}if("claude-desktop"===i){const t=o.getToolSetting(i,S),{hideOfficialLogin:a}=await e.prompt([{type:"confirm",name:"hideOfficialLogin",message:y.t("wizard.desktop_hide_official_login"),default:!1!==t}]);o.setToolSetting(i,S,Boolean(a))}return console.log(t.green("\n✓ "+y.t("wizard.models_saved"))),d&&console.log(t.gray("💡 "+y.t("wizard.claude_model_hint"))),!0}async forceConfig(t){const a=c[t]?.displayName||t,{confirm:o}=await e.prompt([{type:"confirm",name:"confirm",message:y.t("config.confirm_force",{tool:a}),default:!1}]);o&&await this.loadConfig(t,{force:!0})}async loadConfig(i,n={}){const r=o.getModelsForTool(i),s=await this.validatedKeyForConfiguration(o.getApiKeyForTool(i));if(!s)return void await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}]);if(!n.force&&!await d([i]))return;const m=a(y.t("wizard.loading_config")).start();try{await l.applyPrivateConfig(i,s,r,n),m.stop(),l.printApplied(i),await p([i],{apps:{install:!1}}),n.force&&console.log(t.yellow(y.t("config.force_done",{tool:c[i]?.displayName||i,name:i})));const a=c[i];a&&!a.gui&&(l.isOnPath(i)&&console.log(t.green("\n"+y.t("wizard.run_tool_hint",{command:a.command}))),this.printPathReloadHint([i]));const{nextAction:o}=await e.prompt([{type:"list",name:"nextAction",message:y.t("wizard.what_next"),choices:[{name:y.t("wizard.exit_and_start"),value:"exit"},{name:y.t("wizard.continue_config"),value:"continue"}]}]);"exit"===o&&(this.printGoodbye(),process.exit(0))}catch(a){m.fail(y.t("wizard.config_failed")),console.log(t.red(a instanceof Error?a.message:String(a))),await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}])}}async clearPinnedModels(a){const o=c[a]?.displayName||a,{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:y.t("wizard.confirm_clear_model",{tool:o}),default:!1}]);if(i){try{const e=await l.clearPinnedModels(a);0===e.length?console.log(t.yellow("\n"+y.t("config.clear_model_none",{tool:o}))):(console.log(t.green("\n✓ "+y.t("config.clear_model_done",{tool:o}))),e.forEach(e=>console.log(t.gray(` - ${e}`))),console.log(t.gray(y.t("config.clear_model_restart_hint",{tool:o}))))}catch(e){console.log(t.red("\n"+(e instanceof Error?e.message:String(e))))}await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}])}}async unloadConfig(o){const{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:y.t("wizard.confirm_unload_config",{tool:c[o]?.displayName||o}),default:!1}]);if(!i)return;const n=a(y.t("wizard.unloading_config")).start();try{const a=l.holdsOurConfig(o),i=l.unloadPrivateConfig(o);if(!a)return void n.info(y.t("config.remove_nothing",{tool:c[o]?.displayName||o}));n.succeed(y.t("wizard.config_unloaded")),i.forEach(e=>console.log(t.yellow(" ! "+e.text)));const{nextAction:r}=await e.prompt([{type:"list",name:"nextAction",message:y.t("wizard.what_next"),choices:[{name:y.t("wizard.nav_exit"),value:"exit"},{name:y.t("wizard.continue_config"),value:"continue"}]}]);"exit"===r&&(this.printGoodbye(),process.exit(0))}catch(a){n.fail(y.t("wizard.config_unload_failed")),console.log(t.red(a instanceof Error?a.message:String(a))),await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}])}}async restoreConfig(o){const i=c[o]?.displayName||o,{confirm:n}=await e.prompt([{type:"confirm",name:"confirm",message:y.t("wizard.confirm_restore_config",{tool:i}),default:!1}]);if(!n)return;const r=a(y.t("wizard.restoring_config")).start();try{const e=l.restorePrivateConfig(o).filter(e=>e.result.restored);0===e.length?r.warn(y.t("wizard.restore_no_backup")):(r.succeed(y.t("wizard.config_restored",{tool:i})),e.forEach(e=>console.log(t.gray(` ${e.file} ← ${e.result.from}`))),console.log(t.yellow(" ! "+y.t("config.reopen_hint",{tool:i}))))}catch(e){r.fail(y.t("wizard.config_restore_failed")),console.log(t.red(e instanceof Error?e.message:String(e)))}await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}])}async run(){await this.showMainMenu()}async showMainMenu(){if(this.hasConfiguredApiKey())for(;;){this.resetScreen();const a=o.getApiKey()||"",i=a.length>4?"sk-****"+a.slice(-4):"****";console.log(t.gray(` 🔑 API Key: ${i}`)+t.green(" ✓")),console.log("");const n=l.getSupportedTools().map(e=>({name:"🛠️ "+e.displayName,value:{type:"tool",tool:e.name}})),r=[new e.Separator(F("── "+y.t("wizard.select_tool")+" ──")),...n,new e.Separator(t.gray("── "+y.t("wizard.settings")+" ──")),{name:"🔑 "+y.t("wizard.menu_change_api_key"),value:{type:"apikey"}},{name:"🔗 "+y.t("wizard.menu_base_url",{url:o.getBaseUrl()}),value:{type:"base"}},{name:"🌐 "+y.t("wizard.menu_config_language"),value:{type:"language"}},new e.Separator,{name:"x "+y.t("wizard.nav_exit"),value:{type:"exit"}}],{action:s}=await this.promptWithHints([{type:"list",name:"action",message:"🛠️ "+y.t("wizard.select_tool"),choices:r}]);"exit"===s.type?(this.printGoodbye(),process.exit(0)):"tool"===s.type?await this.configureTool(s.tool):"apikey"===s.type?await this.configApiKey():"base"===s.type?await this.configBaseUrl():"language"===s.type&&await this.configLanguage()}else await this.runFirstTimeSetup()}}export const wizard=Wizard.getInstance();
|
|
1
|
+
import e from"inquirer";import t from"chalk";import a from"ora";import{configManager as o,DEFAULT_MODELS as i}from"./config.js";import{getPresets as n,resolvePreset as r,getToolDefaultModel as s}from"./model-registry.js";import{toolManager as l,SUPPORTED_TOOLS as c}from"./tool-manager.js";import{confirmWritePlan as d}from"./write-plan.js";import{postApplyPrompts as p}from"./post-apply.js";import{appStatus as m,appStatusText as u,appTools as _,appsForTools as g,cachedAppStatus as w,upgradeApp as f}from"./app-update.js";import{i18n as y,detectSystemLang as h}from"./i18n.js";import{createBorderLine as z,createContentLine as v}from"../utils/string-width.js";import{validateApiKey as k,fetchModels as x}from"./api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as b}from"./tools/codex.js";import{CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as S}from"./tools/claude-desktop.js";import{addressesWithCurrent as C,ensureReachableGatewayAddress as M,fastestIndex as T,probeAll as A,probeSummary as K,reasonText as N,savedApiKey as B,switchGatewayAddress as O}from"../commands/base.js";import{readFileSync as P}from"fs";import{dirname as W,join as j}from"path";import{fileURLToPath as H}from"url";import{brand as L}from"./brand.js";const $=W(H(import.meta.url)),F=t.hex("#FF8700");export class Wizard{static instance;BOX_WIDTH=63;validatedApiKeys=new Set;constructor(){}static getInstance(){return Wizard.instance||(Wizard.instance=new Wizard),Wizard.instance}createBox(e){console.log(F.bold("\n"+z("╔","╗","═",this.BOX_WIDTH))),console.log(F.bold(v(e,"║","║",this.BOX_WIDTH,"center"))),console.log(F.bold(z("╚","╝","═",this.BOX_WIDTH))),console.log("")}showOperationHints(){const e=[t.gray(y.t("wizard.hint_navigate")),t.gray(y.t("wizard.hint_confirm"))];console.log(t.gray("💡 ")+e.join(t.gray(" | "))+"\n")}async promptWithHints(t){this.showOperationHints();const a=t.map(e=>"list"!==e.type||e.pageSize?e:{...e,pageSize:20});return e.prompt(a)}printBanner(){const e=60,t=y.t("wizard.banner_subtitle"),a=v(t,"║","║",e,"center"),o=v("","║","║",e,"center"),i=v(`${L().productName} v${function(){try{return JSON.parse(P(j($,"..","..","package.json"),"utf-8")).version}catch{return"0.0.0"}}()}`,"║","║",e,"center"),n=[String.raw`__ ___ _ ____ _ ___ `,String.raw`\ \ / (_) |__ ___ / ___| | |_ _|`,String.raw` \ \ / /| | '_ \ / _ \ | | | | | `,String.raw` \ V / | | |_) | __/ |___| |___ | | `,String.raw` \_/ |_|_.__/ \___|\____|_____|___|`],r=Math.max(...n.map(e=>e.length)),s=" ".repeat(Math.floor((58-r)/2)),l=n.map(t=>v(s+t,"║","║",e,"left")),c=[z("╔","╗","═",e),o,...l,o,i,a,z("╚","╝","═",e)];console.log(F.bold("\n"+c.join("\n")))}resetScreen(){console.clear(),this.printBanner()}printGoodbye(){const e=l.getSupportedTools().filter(e=>{if(e.gui)return!1;try{return Boolean(l.detectCurrentConfig(e.name).apiKey)&&l.isToolInstalled(e.name)}catch{return!1}});let a;if(e.length>0){const t=e.map(e=>e.command).join(" / ");a=y.t("wizard.goodbye_message_tools",{commands:t}),e.some(e=>"claude-code"===e.name)&&(a+=" "+y.t("wizard.goodbye_claude_hint"))}else a=y.t("wizard.goodbye_message");console.log(t.green("\n👋 "+a)),this.printPathReloadHint(e.map(e=>e.name))}printPathReloadHint(e){const a=e.filter(e=>!l.isOnPath(e));if(0===a.length)return;const o=a.map(e=>c[e].command).join(" / ");console.log(t.yellow(" ! "+y.t("win32"===process.platform?"setup.path_reload_windows":"setup.path_reload",{commands:o})))}async runFirstTimeSetup(){const e="zh_CN"===h();e&&(o.setLang("zh_CN"),y.setLocale("zh_CN")),this.resetScreen(),console.log(F.bold("\n"+y.t("wizard.welcome"))),console.log(t.gray(y.t("wizard.privacy_note")+"\n")),e?console.log(t.gray(y.t("wizard.lang_auto_zh")+"\n")):await this.configLanguage(),await M(),await this.configApiKey()&&await this.selectAndConfigureTool(!0)}async configLanguage(){for(;;){this.resetScreen(),this.createBox(y.t("wizard.select_language"));const a=y.getLocale(),{language:i}=await this.promptWithHints([{type:"list",name:"language",message:"✨ "+y.t("wizard.select_language"),choices:[{name:"[EN] English"+("en_US"===a?t.green(" ✓ ("+y.t("wizard.current_active")+")"):""),value:"en_US"},{name:"[CN] 中文"+("zh_CN"===a?t.green(" ✓ ("+y.t("wizard.current_active")+")"):""),value:"zh_CN"},new e.Separator,{name:"<- "+y.t("wizard.nav_return"),value:"back"},{name:"x "+y.t("wizard.nav_exit"),value:"exit"}],default:"zh_CN"}]);if("exit"===i)this.printGoodbye(),process.exit(0);else if("back"===i)return;return o.setLang(i),void y.setLocale(i)}}buildPresetChoices(){const a=n(),o=a.filter(e=>e.recommended),i=a.filter(e=>!e.recommended),r=e=>({name:(y.t(e.name)!==e.name?y.t(e.name):e.name)+(e.models?t.gray(` [H:${e.models.haiku} S:${e.models.sonnet} O:${e.models.opus}]`):""),value:{type:"preset",preset:e}}),s=[];return o.length>0&&(s.push(new e.Separator(t.hex("#FF8700")("── "+y.t("wizard.recommended")+" ──"))),s.push(...o.map(r))),i.length>0&&(s.push(new e.Separator(t.gray("── "+y.t("wizard.other_models")+" ──"))),s.push(...i.map(r))),s}async handleCustomModelInput(){const a=o.getModels(),{customMode:n}=await e.prompt([{type:"list",name:"customMode",message:y.t("wizard.custom_model_mode"),choices:[{name:y.t("wizard.custom_model_single"),value:"single"},{name:y.t("wizard.custom_model_per_role"),value:"per_role"}]}]);if("single"===n){const{customModel:t}=await e.prompt([{type:"input",name:"customModel",message:y.t("wizard.input_custom_model"),default:i.sonnet}]);o.setModels({haiku:t,sonnet:t,opus:t,reasoning:t})}else{const t=await e.prompt([{type:"input",name:"haiku",message:y.t("wizard.model_haiku"),default:a.haiku},{type:"input",name:"sonnet",message:y.t("wizard.model_sonnet"),default:a.sonnet},{type:"input",name:"opus",message:y.t("wizard.model_opus"),default:a.opus},{type:"input",name:"reasoning",message:y.t("wizard.model_reasoning"),default:a.reasoning}]);o.setModels(t)}console.log(t.green("\n✓ "+y.t("wizard.models_saved")))}async configModels(a){const i=o.getApiKey();if(await this.validatedKeyForConfiguration(i))for(;;){this.resetScreen(),this.createBox(y.t("wizard.config_models"));const i=[...this.buildPresetChoices()];i.push(new e.Separator),i.push({name:"✏️ "+y.t("wizard.custom_model_input"),value:{type:"custom_input"}}),i.push(new e.Separator),i.push({name:"<- "+y.t("wizard.nav_return"),value:{type:"back"}}),i.push({name:"x "+y.t("wizard.nav_exit"),value:{type:"exit"}});const{modelChoice:n}=await this.promptWithHints([{type:"list",name:"modelChoice",message:y.t("wizard.select_model_config"),choices:i}]);if("exit"===n.type)this.printGoodbye(),process.exit(0);else{if("back"===n.type)return;if("custom_input"===n.type)return await this.handleCustomModelInput(),void(a?.skipLoadPrompt||await this.promptLoadAfterModelConfig());if("preset"===n.type){const e=r(n.preset);return o.setModels(e),console.log(t.green("\n✓ "+y.t("wizard.models_saved"))),void(a?.skipLoadPrompt||await this.promptLoadAfterModelConfig())}}}else await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}])}async promptLoadAfterModelConfig(){const{shouldLoad:t}=await e.prompt([{type:"list",name:"shouldLoad",message:y.t("wizard.load_config_now"),choices:[{name:y.t("wizard.load_config_yes"),value:!0},{name:y.t("wizard.load_config_later"),value:!1}]}]);t&&await this.selectAndConfigureTool()}async configBaseUrl(){const i=o.getBaseUrl(),n=C(),r=a(y.t("wizard.base_testing")).start(),s=await A(n,{apiKey:B(),samples:3});r.stop();const l=T(s),c=n.map((e,a)=>{const o=e.url===i?t.cyan(` ← ${y.t("base.current_mark")}`):"";return{name:`${e.url} ${t.gray(e.label)} ${K(s[a],a===l)}${o}`,value:e.url}});c.push(new e.Separator,{name:"<- "+y.t("wizard.nav_return"),value:"__back__"});const{url:d}=await this.promptWithHints([{type:"list",name:"url",message:y.t("wizard.base_select"),choices:c,default:i}]);if("__back__"===d)return;const p=s[n.findIndex(e=>e.url===d)];p.ok?await O(d):console.log(t.red(y.t("base.unreachable",{url:d,reason:N(p)}))),await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}])}async configApiKey(){for(;;){this.resetScreen(),this.createBox(y.t("wizard.input_api_key")),console.log(t.gray("\n💡 "+y.t("wizard.api_key_input_hint"))),console.log(t.gray(" "+y.t("wizard.api_key_get_hint",{url:L().links.tokenPage}))),console.log();const{apiKey:i}=await e.prompt([{type:"password",name:"apiKey",message:y.t("wizard.input_your_api_key"),mask:"*"}]);if(!i||""===i.trim()){const{action:t}=await e.prompt([{type:"list",name:"action",message:y.t("wizard.select_action"),choices:[{name:y.t("wizard.retry_input"),value:"retry"},{name:"<- "+y.t("wizard.nav_return"),value:"back"}]}]);if("back"===t)return!1;continue}const n=a(y.t("wizard.validating_api_key")).start(),r=await k(i.trim());if(n.stop(),r.valid)return o.setApiKey(i.trim()),this.validatedApiKeys.add(i.trim()),console.log(t.green("\n✓ "+y.t("wizard.api_key_valid"))),!0;{this.validatedApiKeys.delete(i.trim()),"invalid_api_key"===r.error?console.log(t.red("\n✗ "+y.t("wizard.api_key_invalid"))):console.log(t.red("\n✗ "+y.t("wizard.api_key_network_error")));const{action:a}=await e.prompt([{type:"list",name:"action",message:y.t("wizard.select_action"),choices:[{name:y.t("wizard.retry_input"),value:"retry"},{name:"<- "+y.t("wizard.nav_return"),value:"back"}]}]);if("back"===a)return!1}}}async selectAndConfigureTool(a=!1){for(const e of _())await m(e).catch(()=>{});for(;;){this.resetScreen(),this.createBox(y.t("wizard.select_tool"));const o=l.getSupportedTools().map(e=>{const a=g([e.name]).map(e=>w(e)).find(e=>e.outdated);return{name:e.displayName+(a?t.yellow(" "+(a.tool===e.name?"":`${a.name} `)+u(a)):""),value:e.name}}),{tool:i}=await this.promptWithHints([{type:"list",name:"tool",message:"🛠️ "+y.t("wizard.select_tool"),choices:[...o,new e.Separator,{name:"<- "+y.t("wizard.nav_return"),value:"back"},{name:"x "+y.t("wizard.nav_exit"),value:"exit"}]}]);if("exit"===i)this.printGoodbye(),process.exit(0);else if("back"===i)return;await this.configureTool(i,a)}}async configureTool(a,o=!1){const i=c[a];if(i){if(!l.isToolInstalled(a)){console.log(t.yellow("\n"+y.t("wizard.tool_not_installed",{tool:i.displayName})));const{install:o}=await e.prompt([{type:"confirm",name:"install",message:y.t("wizard.install_tool_confirm"),default:!0}]);if(!o)return;try{await l.installTool(a)}catch{return void console.log(t.red(y.t("wizard.install_failed")))}}o?await this.configureToolModel(a)&&await this.loadConfig(a):await this.showToolMenu(a)}}async showToolMenu(t){for(;;){this.resetScreen();const a=c[t];if(!a)return;this.createBox(a.displayName+" "+y.t("wizard.menu_title"));const o=[{name:"📥 "+y.t("wizard.action_load_config",{tool:a.displayName}),value:"load"},{name:"📤 "+y.t("wizard.action_unload_config",{tool:a.displayName}),value:"unload"}];l.supportsClearPinnedModels(t)&&o.push({name:"🧹 "+y.t("wizard.action_clear_model",{tool:a.displayName}),value:"clear-model"});for(const e of g([t]).map(e=>w(e)).reverse()){if(e.blocker||!e.latest||!e.outdated&&e.installed)continue;const t=e.installed?y.t("wizard.action_upgrade_app",{tool:e.name,current:e.current??"?",latest:e.latest}):y.t("wizard.action_install_app",{tool:e.name,latest:e.latest});o.unshift({name:"↑ "+t,value:`upgrade-app:${e.tool}`})}o.push({name:"🧨 "+y.t("wizard.action_force_config",{tool:a.displayName}),value:"force"},{name:"↩️ "+y.t("wizard.action_restore_config",{tool:a.displayName}),value:"restore"},new e.Separator,{name:"<- "+y.t("wizard.nav_return"),value:"back"},{name:"x "+y.t("wizard.nav_exit"),value:"exit"});const{action:i}=await this.promptWithHints([{type:"list",name:"action",message:"⚙️ "+y.t("wizard.select_action"),choices:o}]);if("exit"===i)this.printGoodbye(),process.exit(0);else{if("back"===i)return;"load"===i?await this.configureToolModel(t)&&await this.loadConfig(t):"force"===i?await this.forceConfig(t):"unload"===i?await this.unloadConfig(t):"string"==typeof i&&i.startsWith("upgrade-app:")?(await f(i.slice(12),{install:!0}),await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}])):"clear-model"===i?await this.clearPinnedModels(t):"restore"===i&&await this.restoreConfig(t)}}}singleModelOverride(e){const t=e.trim();return/claude/i.test(t)?{opus:t}:{haiku:t,sonnet:t,opus:t,reasoning:t}}hasConfiguredApiKey(){return!!o.getApiKey()?.trim()||o.listToolApiKeys().some(e=>Boolean(o.getApiKeyForTool(e)?.trim()))}async validatedKeyForConfiguration(e){const o=e?.trim();if(!o)return console.log(t.red("\n"+y.t("wizard.api_key_required"))),console.log(t.yellow(y.t("wizard.please_config_api_key_first"))),null;if(this.validatedApiKeys.has(o))return o;const i=a(y.t("wizard.validating_api_key")).start(),n=await k(o);if(n.valid)return this.validatedApiKeys.add(o),i.succeed(y.t("wizard.api_key_valid")),o;this.validatedApiKeys.delete(o);const r="invalid_api_key"===n.error?y.t("wizard.api_key_invalid"):y.t("wizard.api_key_network_error");return i.fail(r),console.log(t.red("\n"+y.t("wizard.please_reconfig_api_key"))),null}async configureToolModel(i){const n=c[i];if(!n)return!1;const l=await this.validatedKeyForConfiguration(o.getApiKeyForTool(i));if(!l)return await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}]),!1;const d="claude-code"===i,p=d||"claude-desktop"===i||"agy"===i,m=s(i),u=p||!m?y.t("wizard.model_builtin_default"):m;this.resetScreen(),this.createBox(n.displayName+" · "+y.t("wizard.config_models"));const _=[{name:"✅ "+y.t("wizard.use_default_model",{model:u}),value:{type:"default"}},{name:"🌐 "+y.t("wizard.fetch_models_from_api"),value:{type:"fetch"}},...this.buildPresetChoices(),new e.Separator,{name:"✏️ "+y.t("wizard.input_custom_model"),value:{type:"custom"}},new e.Separator,{name:"<- "+y.t("wizard.nav_return"),value:{type:"back"}}],{choice:g}=await this.promptWithHints([{type:"list",name:"choice",message:y.t("wizard.select_tool_model",{tool:n.displayName}),choices:_}]);if("back"===g.type)return!1;if("default"===g.type)o.setToolModel(i,null);else if("preset"===g.type)o.setToolModel(i,r(g.preset));else if("custom"===g.type){const{model:t}=await e.prompt([{type:"input",name:"model",message:y.t("wizard.input_custom_model"),default:!p&&m?m:void 0}]),a=(t||"").trim();o.setToolModel(i,a?this.singleModelOverride(a):null)}else if("fetch"===g.type){const n=a(y.t("wizard.fetching_models")).start(),r=await x(l);let s;if(n.stop(),r.ok&&r.models.length>0){const{model:t}=await e.prompt([{type:"list",name:"model",message:y.t("wizard.select_fetched_model"),pageSize:20,choices:[...r.models,new e.Separator,{name:"<- "+y.t("wizard.nav_return"),value:"__back__"}]}]);if("__back__"===t)return!1;s=t}else{console.log(t.yellow("\n"+y.t("wizard.fetch_models_failed")));const{model:a}=await e.prompt([{type:"input",name:"model",message:y.t("wizard.input_custom_model"),default:!p&&m?m:void 0}]);s=(a||"").trim()}o.setToolModel(i,s?this.singleModelOverride(s):null)}if("codex"===i){const t=o.getToolSetting(i,b),{enableOneMillionContext:a}=await e.prompt([{type:"confirm",name:"enableOneMillionContext",message:y.t("wizard.codex_enable_1m_context"),default:!1!==t}]);o.setToolSetting(i,b,Boolean(a))}if("claude-desktop"===i){const t=o.getToolSetting(i,S),{hideOfficialLogin:a}=await e.prompt([{type:"confirm",name:"hideOfficialLogin",message:y.t("wizard.desktop_hide_official_login"),default:!1!==t}]);o.setToolSetting(i,S,Boolean(a))}return console.log(t.green("\n✓ "+y.t("wizard.models_saved"))),d&&console.log(t.gray("💡 "+y.t("wizard.claude_model_hint"))),!0}async forceConfig(t){const a=c[t]?.displayName||t,{confirm:o}=await e.prompt([{type:"confirm",name:"confirm",message:y.t("config.confirm_force",{tool:a}),default:!1}]);o&&await this.loadConfig(t,{force:!0})}async loadConfig(i,n={}){const r=o.getModelsForTool(i),s=await this.validatedKeyForConfiguration(o.getApiKeyForTool(i));if(!s)return void await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}]);if(!n.force&&!await d([i]))return;const m=a(y.t("wizard.loading_config")).start();try{await l.applyPrivateConfig(i,s,r,{...n,takeOver:!0}),m.stop(),l.printApplied(i),await p([i],{apps:{install:!1}}),n.force&&console.log(t.yellow(y.t("config.force_done",{tool:c[i]?.displayName||i,name:i})));const a=c[i];a&&!a.gui&&(l.isOnPath(i)&&console.log(t.green("\n"+y.t("wizard.run_tool_hint",{command:a.command}))),this.printPathReloadHint([i]));const{nextAction:o}=await e.prompt([{type:"list",name:"nextAction",message:y.t("wizard.what_next"),choices:[{name:y.t("wizard.exit_and_start"),value:"exit"},{name:y.t("wizard.continue_config"),value:"continue"}]}]);"exit"===o&&(this.printGoodbye(),process.exit(0))}catch(a){m.fail(y.t("wizard.config_failed")),console.log(t.red(a instanceof Error?a.message:String(a))),await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}])}}async clearPinnedModels(a){const o=c[a]?.displayName||a,{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:y.t("wizard.confirm_clear_model",{tool:o}),default:!1}]);if(i){try{const e=await l.clearPinnedModels(a);0===e.length?console.log(t.yellow("\n"+y.t("config.clear_model_none",{tool:o}))):(console.log(t.green("\n✓ "+y.t("config.clear_model_done",{tool:o}))),e.forEach(e=>console.log(t.gray(` - ${e}`))),console.log(t.gray(y.t("config.clear_model_restart_hint",{tool:o}))))}catch(e){console.log(t.red("\n"+(e instanceof Error?e.message:String(e))))}await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}])}}async unloadConfig(o){const{confirm:i}=await e.prompt([{type:"confirm",name:"confirm",message:y.t("wizard.confirm_unload_config",{tool:c[o]?.displayName||o}),default:!1}]);if(!i)return;const n=a(y.t("wizard.unloading_config")).start();try{const a=l.holdsOurConfig(o),i=l.unloadPrivateConfig(o);if(!a)return void n.info(y.t("config.remove_nothing",{tool:c[o]?.displayName||o}));n.succeed(y.t("wizard.config_unloaded")),i.forEach(e=>console.log(t.yellow(" ! "+e.text)));const{nextAction:r}=await e.prompt([{type:"list",name:"nextAction",message:y.t("wizard.what_next"),choices:[{name:y.t("wizard.nav_exit"),value:"exit"},{name:y.t("wizard.continue_config"),value:"continue"}]}]);"exit"===r&&(this.printGoodbye(),process.exit(0))}catch(a){n.fail(y.t("wizard.config_unload_failed")),console.log(t.red(a instanceof Error?a.message:String(a))),await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}])}}async restoreConfig(o){const i=c[o]?.displayName||o,{confirm:n}=await e.prompt([{type:"confirm",name:"confirm",message:y.t("wizard.confirm_restore_config",{tool:i}),default:!1}]);if(!n)return;const r=a(y.t("wizard.restoring_config")).start();try{const e=l.restorePrivateConfig(o).filter(e=>e.result.restored);0===e.length?r.warn(y.t("wizard.restore_no_backup")):(r.succeed(y.t("wizard.config_restored",{tool:i})),e.forEach(e=>console.log(t.gray(` ${e.file} ← ${e.result.from}`))),console.log(t.yellow(" ! "+y.t("config.reopen_hint",{tool:i}))))}catch(e){r.fail(y.t("wizard.config_restore_failed")),console.log(t.red(e instanceof Error?e.message:String(e)))}await e.prompt([{type:"input",name:"continue",message:y.t("wizard.press_enter")}])}async run(){await this.showMainMenu()}async showMainMenu(){if(this.hasConfiguredApiKey())for(;;){this.resetScreen();const a=o.getApiKey()||"",i=a.length>4?"sk-****"+a.slice(-4):"****";console.log(t.gray(` 🔑 API Key: ${i}`)+t.green(" ✓")),console.log("");const n=l.getSupportedTools().map(e=>({name:"🛠️ "+e.displayName,value:{type:"tool",tool:e.name}})),r=[new e.Separator(F("── "+y.t("wizard.select_tool")+" ──")),...n,new e.Separator(t.gray("── "+y.t("wizard.settings")+" ──")),{name:"🔑 "+y.t("wizard.menu_change_api_key"),value:{type:"apikey"}},{name:"🔗 "+y.t("wizard.menu_base_url",{url:o.getBaseUrl()}),value:{type:"base"}},{name:"🌐 "+y.t("wizard.menu_config_language"),value:{type:"language"}},new e.Separator,{name:"x "+y.t("wizard.nav_exit"),value:{type:"exit"}}],{action:s}=await this.promptWithHints([{type:"list",name:"action",message:"🛠️ "+y.t("wizard.select_tool"),choices:r}]);"exit"===s.type?(this.printGoodbye(),process.exit(0)):"tool"===s.type?await this.configureTool(s.tool):"apikey"===s.type?await this.configApiKey():"base"===s.type?await this.configBaseUrl():"language"===s.type&&await this.configLanguage()}else await this.runFirstTimeSetup()}}export const wizard=Wizard.getInstance();
|
package/dist/lib/write-plan.d.ts
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
export interface ToolWritePlan {
|
|
7
7
|
tool: string;
|
|
8
8
|
files: string[];
|
|
9
|
+
/** Other parties' settings this write replaces or removes (adapter `planNotes`). */
|
|
10
|
+
notes: string[];
|
|
9
11
|
}
|
|
10
12
|
export declare function toolWritePlan(tools: string[]): ToolWritePlan[];
|
|
11
13
|
/** `<label> Claude Code` + its files, one block per tool; then the key file and tools installed first. */
|
package/dist/lib/write-plan.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import o from"chalk";import t from"inquirer";import{getAdapter as
|
|
1
|
+
import o from"chalk";import t from"inquirer";import{getAdapter as n}from"./tools/registry.js";import{SUPPORTED_TOOLS as e}from"./tool-manager.js";import{i18n as r}from"./i18n.js";import{isColorEnabled as l,isDryRun as i,isJsonMode as s,isNonInteractive as a,shouldAutoConfirm as c}from"./runtime-options.js";export function toolWritePlan(o){return o.map(o=>{const t=n(o);let e=[];try{e=t?.planNotes?.()??[]}catch{e=[]}return{tool:o,files:t?.backupPaths?.()??(t?[t.configPath]:[]),notes:e}})}export function printWritePlan(t,n){const i=(l()?o.cyan:o=>o)(n.label),s=l()?o.gray:o=>o,a=l()?o.yellow:o=>o;for(const{tool:o,files:n,notes:l}of t)console.log(`${i} ${r.t("setup.dry_run_tool",{tool:e[o]?.displayName??o})}`),n.forEach(o=>console.log(s(` ${o}`))),l.forEach(o=>console.log(a(` ! ${o}`)));for(const o of n.installFirst??[])console.log(`${i} ${r.t("plan.install_first",{tool:e[o]?.displayName??o})}`);n.keyFile&&console.log(`${i} ${r.t("setup.dry_run_key",{file:n.keyFile})}`)}export function asksBeforeWriting(){return Boolean(process.stdin.isTTY&&process.stdout.isTTY)&&!c()&&!a()&&!s()&&!i()}export async function confirmWritePlan(o,n={}){if(!asksBeforeWriting())return!0;if(0===o.length&&!n.keyFile&&!n.installFirst?.length)return!0;console.log("\n"+r.t("plan.title")),printWritePlan(toolWritePlan(o),{label:" •",...n});const{go:e}=await t.prompt([{type:"confirm",name:"go",message:r.t("plan.confirm"),default:!0}]);return e||console.log(r.t("plan.cancelled")),e}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface ClaimOptions {
|
|
2
|
+
/** The value is the user's own pick in vibecli (custom model), not a default. */
|
|
3
|
+
explicit?: boolean;
|
|
4
|
+
/** Values versions without this record wrote: with no record, a field holding one is ours. */
|
|
5
|
+
legacy?: readonly string[];
|
|
6
|
+
}
|
|
7
|
+
/** The field holds what vibecli wrote (or, with no record yet, a value older versions wrote). */
|
|
8
|
+
export declare function ownsValue(key: string, current: unknown, legacy?: readonly string[]): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Whether vibecli may put `desired` into the field holding `current`, and records the outcome:
|
|
11
|
+
* true → the caller writes `desired` (recorded as ours); false → the user's value stays.
|
|
12
|
+
*/
|
|
13
|
+
export declare function claimField(key: string, current: unknown, desired: string, options?: ClaimOptions): boolean;
|
|
14
|
+
/** vibecli removed its value from the field (or the user cleared it through vibecli). */
|
|
15
|
+
export declare function forgetField(key: string): void;
|
|
16
|
+
/**
|
|
17
|
+
* Gateway addresses vibecli wrote into a tool (normalized by the caller). An address the user once
|
|
18
|
+
* set with `--base` and later left still marks that tool entry as ours.
|
|
19
|
+
*/
|
|
20
|
+
export declare function noteGatewayUrl(normalized: string): void;
|
|
21
|
+
export declare function wroteGatewayUrl(normalized: string): boolean;
|
|
@@ -0,0 +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)}
|
package/dist/locales/en_US.json
CHANGED
|
@@ -380,6 +380,10 @@
|
|
|
380
380
|
"list_separator": ", "
|
|
381
381
|
},
|
|
382
382
|
"codex": {
|
|
383
|
+
"kept_user_settings": "Kept what you set yourself: {{values}}",
|
|
384
|
+
"plan_replace_provider": "Replace model_providers.custom (now pointing at {{url}}, not written by {{product}})",
|
|
385
|
+
"plan_switch_provider": "Codex now uses {{provider}}; it will switch to {{brand}}",
|
|
386
|
+
"provider_replaced": "Replaced the previous custom provider {{url}}; the old file is backed up",
|
|
383
387
|
"sessions_offer": "Move {{count}} earlier Codex sessions over? They're hidden from the list after switching to {{brand}}. They're backed up first and this can be undone.",
|
|
384
388
|
"sessions_hidden": "{{count}} earlier Codex sessions are hidden from the list after switching to {{brand}}: run {{cli}} codex sessions to move them over (backed up first, can be undone)",
|
|
385
389
|
"sessions_hidden_running": "{{count}} earlier Codex sessions are hidden from the list after switching to {{brand}}: quit Codex completely (desktop app included), then run {{cli}} codex sessions",
|
|
@@ -393,6 +397,12 @@
|
|
|
393
397
|
"unload_other_key": "Codex is still signed in with another API key (not the {{brand}} API key, left as is). To use your ChatGPT subscription, run codex logout, then codex login"
|
|
394
398
|
},
|
|
395
399
|
"claude_desktop": {
|
|
400
|
+
"current_official": "the official sign-in",
|
|
401
|
+
"current_entry": "the \"{{name}}\" configuration",
|
|
402
|
+
"plan_switch": "Claude Desktop now uses {{current}}; it will switch to {{brand}}",
|
|
403
|
+
"not_switched": "Claude Desktop uses {{current}}: the {{brand}} configuration is saved but not switched on. To switch, run {{cli}} config claude-desktop --yes",
|
|
404
|
+
"foreign_policy": "The registry key {{key}} holds another service's settings ({{url}}); Claude Desktop uses those and ignores what {{product}} writes. {{product}} left them alone; ask your administrator if needed",
|
|
405
|
+
"plan_foreign_policy": "The registry key {{key}} holds another service's settings ({{url}}); they are kept and Claude Desktop keeps using them",
|
|
396
406
|
"code_cli_downloading": "Downloading Claude Code {{version}} for Claude Desktop's Code tab from the China mirror (about 100 MB)…",
|
|
397
407
|
"code_cli_installed": "Claude Desktop's Code tab has Claude Code {{version}} and no longer needs downloads.claude.ai",
|
|
398
408
|
"code_cli_failed": "Couldn't prepare Claude Code for Claude Desktop's Code tab ({{reason}}); the tab may say it can't download it. Fix the cause above, then run {{cli}} setup --desktopkey <your API key>",
|
|
@@ -414,7 +424,13 @@
|
|
|
414
424
|
"registry_removed": "Removed the old values under {{key}}; Claude Desktop now reads the local config"
|
|
415
425
|
},
|
|
416
426
|
"claude_code": {
|
|
427
|
+
"plan_env_remove": "Remove {{vars}} pointing at this site from {{location}} (backed up first)",
|
|
428
|
+
"env_removed": "Removed {{vars}} pointing at this site from {{location}}; new terminals pick this up (backed up)",
|
|
429
|
+
"env_foreign": "{{vars}} in {{location}} point at another service and override Claude Code's settings; {{product}} left them alone. To use {{brand}}, remove them yourself and open a new terminal",
|
|
430
|
+
"plan_replace_provider": "Replace Claude Code's current endpoint {{url}} (not written by {{product}})",
|
|
431
|
+
"provider_replaced": "Replaced the previous endpoint {{url}}; the old file is backed up",
|
|
417
432
|
"gateway_models": "{{count}} more models added to /model ({{vendors}})",
|
|
433
|
+
"kept_user_models": "Kept the models you set yourself: {{values}}",
|
|
418
434
|
"tier_fallback": "This API key can't use Claude Code's default {{from}}; the {{tier}} alias now uses {{to}}",
|
|
419
435
|
"stable_channel": "Your update channel in settings.json is stable, which may not have reached {{min}} yet; set autoUpdatesChannel to latest, then upgrade",
|
|
420
436
|
"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",
|
package/dist/locales/zh_CN.json
CHANGED
|
@@ -380,6 +380,10 @@
|
|
|
380
380
|
"list_separator": "、"
|
|
381
381
|
},
|
|
382
382
|
"codex": {
|
|
383
|
+
"kept_user_settings": "已保留你自己设的:{{values}}",
|
|
384
|
+
"plan_replace_provider": "替换 model_providers.custom(现在指向 {{url}},不是 {{product}} 写的)",
|
|
385
|
+
"plan_switch_provider": "Codex 现在用的是 {{provider}},将改用 {{brand}}",
|
|
386
|
+
"provider_replaced": "已替换原来的 custom 提供方 {{url}},修改前的文件已备份",
|
|
383
387
|
"sessions_offer": "把 {{count}} 个以前的 Codex 会话移过来?切换到 {{brand}} 后它们不在会话列表里显示。会先备份,可以撤销。",
|
|
384
388
|
"sessions_hidden": "有 {{count}} 个以前的 Codex 会话在切换到 {{brand}} 后不在列表里显示。运行 {{cli}} codex sessions 可以把它们移过来(会先备份,可以撤销)",
|
|
385
389
|
"sessions_hidden_running": "有 {{count}} 个以前的 Codex 会话在切换到 {{brand}} 后不在列表里显示。完全退出 Codex(包括桌面版)后,运行 {{cli}} codex sessions 把它们移过来",
|
|
@@ -393,6 +397,12 @@
|
|
|
393
397
|
"unload_other_key": "Codex 仍在用另一个令牌登录(不是 {{brand}} 的令牌,没有改动)。要改用 ChatGPT 订阅:运行 codex logout,再运行 codex login"
|
|
394
398
|
},
|
|
395
399
|
"claude_desktop": {
|
|
400
|
+
"current_official": "官方账号登录",
|
|
401
|
+
"current_entry": "配置「{{name}}」",
|
|
402
|
+
"plan_switch": "Claude Desktop 现在用的是{{current}},将切换到 {{brand}}",
|
|
403
|
+
"not_switched": "Claude Desktop 现在用的是{{current}},已写好 {{brand}} 的配置但没有切换;要切换,运行 {{cli}} config claude-desktop --yes",
|
|
404
|
+
"foreign_policy": "注册表 {{key}} 里是别的服务的配置({{url}}),Claude Desktop 会用它、不读 {{product}} 写的配置;{{product}} 没有改它,需要时请联系管理员",
|
|
405
|
+
"plan_foreign_policy": "注册表 {{key}} 里是别的服务的配置({{url}}),不会修改,Claude Desktop 会继续用它",
|
|
396
406
|
"code_cli_downloading": "正在从国内镜像下载 Claude Code {{version}},供 Claude Desktop 的 Code 标签页使用(约 100 MB)…",
|
|
397
407
|
"code_cli_installed": "Claude Desktop 的 Code 标签页已准备好 Claude Code {{version}},不必再从 downloads.claude.ai 下载",
|
|
398
408
|
"code_cli_failed": "无法为 Claude Desktop 的 Code 标签页准备 Claude Code({{reason}}),Code 标签页可能提示无法下载。排除上面的原因后,运行 {{cli}} setup --desktopkey <你的令牌> 重试",
|
|
@@ -414,7 +424,13 @@
|
|
|
414
424
|
"registry_removed": "已删除注册表 {{key}} 里的旧配置,Claude Desktop 改为读取本地配置"
|
|
415
425
|
},
|
|
416
426
|
"claude_code": {
|
|
427
|
+
"plan_env_remove": "删除 {{location}} 里指向本站的 {{vars}}(先备份)",
|
|
428
|
+
"env_removed": "已删除 {{location}} 里指向本站的 {{vars}},新开的终端生效(已备份)",
|
|
429
|
+
"env_foreign": "{{location}} 里的 {{vars}} 指向别的服务,会盖过 Claude Code 的配置,{{product}} 没有改它;要用 {{brand}},请自己删掉后重新打开终端",
|
|
430
|
+
"plan_replace_provider": "替换 Claude Code 现在的接入地址 {{url}}(不是 {{product}} 写的)",
|
|
431
|
+
"provider_replaced": "已替换原来的接入地址 {{url}},修改前的文件已备份",
|
|
417
432
|
"gateway_models": "/model 菜单新增 {{count}} 个其他模型({{vendors}})",
|
|
433
|
+
"kept_user_models": "已保留你自己设的模型:{{values}}",
|
|
418
434
|
"tier_fallback": "当前令牌无法使用 Claude Code 默认的 {{from}},{{tier}} 档已改用 {{to}}",
|
|
419
435
|
"stable_channel": "settings.json 里的更新渠道是 stable,这个渠道可能还没有更新到 {{min}}。请把 autoUpdatesChannel 改成 latest 后再升级",
|
|
420
436
|
"managed_override": "发现 Claude Code 的托管配置({{source}}),其中 {{keys}} 优先于 {{product}} 写入的设置,这里的配置不会生效。托管配置通常由公司电脑统一下发,请联系公司 IT 管理员",
|