@vibeapi/api-helper 0.0.120 → 0.0.121

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -46,7 +46,7 @@ npx --yes --registry https://npm.cnb.cool/vibeapi/npm/-/packages/ @vibeapi/cli@l
46
46
  vibecli setup --key sk-xxx
47
47
  ```
48
48
 
49
- `--key` 会按令牌能访问的模型分组自动配置:有 Claude 模型配 Claude Code 和 Claude Desktop(macOS / Windows;桌面端没装也先写好,装好打开就能用)、有 GPT 模型配 Codex、有 Grok 模型配 Grok Build、有 Gemini 模型配 Antigravity CLI(`agy`)。没装的命令行工具也会先写好配置,再问要不要从国内镜像装上(`--install` 直接装)。拿到的是多个分组的令牌(如 Claude 分组 + GPT 分组 + Grok 分组),就各配各的:
49
+ `--key` 会按令牌能访问的模型分组自动配置:有 Claude 模型配 Claude Code 和 Claude Desktop(macOS / Windows 上桌面端没装也先写好,装好打开就能用;Linux 官方版装了才配)、有 GPT 模型配 Codex、有 Grok 模型配 Grok Build、有 Gemini 模型配 Antigravity CLI(`agy`)。没装的命令行工具也会先写好配置,再问要不要从国内镜像装上(`--install` 直接装)。拿到的是多个分组的令牌(如 Claude 分组 + GPT 分组 + Grok 分组),就各配各的:
50
50
 
51
51
  ```bash
52
52
  vibecli setup --claudekey sk-a --codexkey sk-b --grokkey sk-c --desktopkey sk-d
@@ -1 +1 @@
1
- import o from"inquirer";import e from"chalk";import{wizard as t}from"../lib/wizard.js";import{toolManager as n,SUPPORTED_TOOLS as l}from"../lib/tool-manager.js";import{i18n as i}from"../lib/i18n.js";import{configManager as r,DEFAULT_PROFILE_NAME as a}from"../lib/config.js";import{confirmAction as s,applyOrDryRun as c}from"../lib/confirm.js";import{isNonInteractive as f,shouldAutoConfirm as d}from"../lib/runtime-options.js";const g=/^[a-zA-Z0-9._-]+$/;function m(o,e){const t=(o||"").trim();if(!t||!g.test(t))throw new Error(i.t(`config.${e}_invalid_name`,{name:t||"<empty>"}));return t}function u(o,t){console.log("\n"+e.bold(o)),0!==t.length?t.forEach(o=>console.log(" "+o)):console.log(e.gray(" ("+i.t("config.empty_list")+")"))}function p(o,t){if("backups"===t){const t=n.listToolBackups(o).flatMap(o=>{const t=o.file.replace(/^.*[/\\]/,"");return o.backups.length?o.backups.map(o=>`${e.cyan(t)} ${e.gray(o.name.split(".bak-")[1]||o.name)}`):[`${e.cyan(t)} ${e.gray("("+i.t("config.empty_list")+")")}`]});return void u(i.t("config.tool_backups_title",{tool:l[o].displayName}),t)}const r=n.restorePrivateConfig(o).filter(o=>o.result.restored);0!==r.length?(console.log(e.green(i.t("config.config_restored",{tool:l[o].displayName}))),r.forEach(o=>console.log(e.gray(` ${o.file} ← ${o.result.from}`))),console.log(e.yellow(" ! "+i.t("config.reopen_hint",{tool:l[o].displayName})))):console.log(e.yellow(i.t("config.restore_no_backup",{tool:l[o].displayName})))}async function _(a,f,d){if(!l[a])return void console.log(e.red(i.t("config.unknown_tool",{tool:a})));const g=(f[0]||"").toLowerCase();if("backups"!==g&&"list-backups"!==g){if("restore"===g){if(!await s({message:i.t("config.confirm_restore",{tool:l[a].displayName}),defaultValue:!1}))return;return void p(a,"restore")}if("remove"===g||"unload"===g){const o=l[a].displayName;return void await c({description:i.t("config.remove_dry_run",{tool:o}),json:{action:"remove",tool:a},apply:async()=>{if(!await s({message:i.t("config.confirm_remove",{tool:o,name:a}),defaultValue:!0}))return;const t=n.unloadPrivateConfig(a);console.log(e.green(i.t("config.remove_done",{tool:o}))),t.forEach(o=>console.log(e.yellow(" ! "+o.text)))}})}if("clear-model"===g||"clear-models"===g){const o=l[a].displayName;return n.supportsClearPinnedModels(a)?void await c({description:i.t("config.clear_model_dry_run",{tool:o}),json:{action:"clear_model",tool:a},apply:async()=>{const t=await n.clearPinnedModels(a);0!==t.length?(console.log(e.green(i.t("config.clear_model_done",{tool:o}))),t.forEach(o=>console.log(e.gray(` - ${o}`))),console.log(e.gray(i.t("config.clear_model_restart_hint",{tool:o})))):console.log(e.yellow(i.t("config.clear_model_none",{tool:o})))}}):void console.log(e.yellow(i.t("config.clear_model_unsupported",{tool:o})))}if(!n.isToolInstalled(a)){if(d.nonInteractive)return void console.log(e.yellow(i.t("wizard.tool_not_installed",{tool:l[a].displayName})));console.log(e.yellow(i.t("wizard.tool_not_installed",{tool:l[a].displayName})));const{shouldInstall:t}=await o.prompt([{type:"confirm",name:"shouldInstall",message:i.t("wizard.install_tool_confirm"),default:!0}]);if(!t)return void console.log(e.yellow(i.t("wizard.install_skipped")));try{await n.installTool(a)}catch(o){return console.error(e.red(i.t("install.install_failed_detail"))),void(o instanceof Error&&o.message&&console.error(e.gray(o.message)))}}if(d.nonInteractive||d.force){const o=r.getApiKeyForTool(a);if(!o)return void console.log(e.red(i.t("wizard.api_key_required")));if(d.force&&!d.nonInteractive&&!await s({message:i.t("config.confirm_force",{tool:l[a].displayName}),defaultValue:!1}))return;return await n.applyPrivateConfig(a,o,r.getModelsForTool(a),{force:d.force}),d.force&&console.log(e.yellow(i.t("config.force_done",{tool:l[a].displayName}))),void n.printApplied(a)}await t.showToolMenu(a)}else p(a,"backups")}export async function configCommand(t){const{positional:n,options:p}=function(o){const e=[],t={};(f()||d())&&(t.nonInteractive=!0);for(const n of o)"--non-interactive"===n||"-y"===n?t.nonInteractive=!0:"--force"===n||"-f"===n?t.force=!0:e.push(n);return{positional:e,options:t}}(t),y=n[0],v=n.slice(1);if(y){switch(y){case"profile":return void await async function(o){const t=o[0],n=o[1];if(!t||"list"===t){const o=r.getActiveProfileName(),t=r.listProfiles().map(t=>{const n=t===o;return`${n?e.green("●"):e.gray("○")} ${t}${n?e.gray(" ("+i.t("config.profile_active_label")+")"):""}`});return void u(i.t("config.profile_list_title"),t)}if("create"===t){const o=m(n,"profile");return r.listProfiles().includes(o)?void console.log(e.yellow(i.t("config.profile_exists",{name:o}))):(r.createProfile(o),void console.log(e.green(i.t("config.profile_created",{name:o}))))}if("use"===t){const o=m(n,"profile");return r.setActiveProfile(o),void console.log(e.green(i.t("config.profile_activated",{name:o})))}if("delete"===t||"remove"===t){const o=m(n,"profile");return o===a&&1===r.listProfiles().length?void console.log(e.yellow(i.t("config.profile_cannot_delete_last"))):void await c({description:i.t("config.profile_delete_dry_run",{name:o}),json:{action:"profile_delete",name:o},apply:async()=>{await s({message:i.t("config.profile_delete_confirm",{name:o}),defaultValue:!1})?(r.deleteProfile(o),console.log(e.green(i.t("config.profile_deleted",{name:o})))):console.log(e.yellow(i.t("config.profile_delete_aborted")))}})}console.log(e.red(i.t("config.unknown_action",{action:t})))}(v);case"preset":return void function(o){const t=o[0],n=o[1];if(!t||"list"===t){const o=Object.entries(r.getCustomPresets()).map(([o,t])=>`${e.cyan(o)} ${e.gray(`H:${t.models.haiku} S:${t.models.sonnet} O:${t.models.opus}`)}`);return void u(i.t("config.preset_list_title"),o)}if("save"===t){const o=m(n,"preset");return r.saveCustomPreset(o,r.getModels()),void console.log(e.green(i.t("config.preset_saved",{name:o})))}if("use"===t||"apply"===t){const o=m(n,"preset"),t=r.getCustomPresets()[o];return t?(r.setModels(t.models),void console.log(e.green(i.t("config.preset_applied",{name:o})))):void console.log(e.red(i.t("config.preset_not_found",{name:o})))}if("delete"===t||"remove"===t){const o=m(n,"preset");return r.deleteCustomPreset(o),void console.log(e.green(i.t("config.preset_deleted",{name:o})))}console.log(e.red(i.t("config.unknown_action",{action:t})))}(v);case"tool-model":return void function(o){const t=o[0];if(!t||"list"===t){const o=r.getProfile().tool_models||{},t=Object.entries(o).map(([o,t])=>{const n=Object.entries(t).map(([o,e])=>`${o}=${e}`).join(" ");return`${e.cyan(o)} ${e.gray(n)}`});return void u(i.t("config.tool_model_list_title"),t)}if("set"===t){const t=(o[1]||"").trim(),n=o.length>=4?(o[2]||"").trim():"opus",a=(o.length>=4?o[3]:o[2]||"").trim();return l[t]?a&&g.test(n)?(r.setToolModel(t,{[n]:a}),void console.log(e.green(i.t("config.tool_model_set",{tool:t,slot:n,model:a})))):void console.log(e.red(i.t("config.tool_model_usage"))):void console.log(e.red(i.t("config.unknown_tool",{tool:t})))}if("clear"===t||"remove"===t){const t=(o[1]||"").trim();return l[t]?(r.setToolModel(t,null),void console.log(e.green(i.t("config.tool_model_cleared",{tool:t})))):void console.log(e.red(i.t("config.unknown_tool",{tool:t})))}console.log(e.red(i.t("config.unknown_action",{action:t})))}(v);case"backup":return void await function(o){return async function(o){const t=o[0],n=o[1];if(!t||"list"===t){const o=r.listBackups().map(o=>{const t=new Date(o.mtimeMs).toISOString();return`${e.cyan(o.name)} ${e.gray(t)}`});return void u(i.t("config.backup_list_title"),o)}if("create"===t||"snapshot"===t){const o=r.createBackup(n);return void console.log(e.green(i.t("config.backup_created",{path:o})))}if("restore"===t)return n?void await c({description:i.t("config.backup_restore_dry_run",{name:n}),json:{action:"backup_restore",name:n},apply:async()=>{await s({message:i.t("config.backup_restore_confirm",{name:n}),defaultValue:!1})?(r.restoreBackup(n),console.log(e.green(i.t("config.backup_restored",{name:n})))):console.log(e.yellow(i.t("config.backup_restore_aborted")))}}):void console.log(e.red(i.t("config.backup_restore_missing_name")));console.log(e.red(i.t("config.unknown_action",{action:t})))}(o)}(v)}"claude-code"!==y&&"claude-code"!==v[0]?l[y]?await _(y,v,p):(console.error(e.red(i.t("config.unknown_command",{command:y}))),console.log(e.gray(i.t("config.usage_hint"))),Object.values(l).filter(o=>!o.hidden).forEach(o=>{console.log(e.gray(` - ${o.name}: ${o.displayName}`))})):await _("claude-code",v,p)}else await async function(t){if(t.nonInteractive)return void console.log(e.red(i.t("config.requires_argument")));const{selectedTool:n}=await o.prompt([{type:"list",name:"selectedTool",message:i.t("wizard.select_tool"),choices:Object.values(l).filter(o=>!o.hidden).map(o=>({name:`${o.displayName} (${o.name})`,value:o.name}))}]);await _(n,[],t)}(p)}
1
+ import o from"inquirer";import e from"chalk";import{wizard as t}from"../lib/wizard.js";import{toolManager as n,SUPPORTED_TOOLS as l}from"../lib/tool-manager.js";import{i18n as i}from"../lib/i18n.js";import{configManager as r,DEFAULT_PROFILE_NAME as a}from"../lib/config.js";import{confirmAction as s,applyOrDryRun as c}from"../lib/confirm.js";import{isDryRun as d,isNonInteractive as f,shouldAutoConfirm as p}from"../lib/runtime-options.js";const g=/^[a-zA-Z0-9._-]+$/;function m(o,e){const t=(o||"").trim();if(!t||!g.test(t))throw new Error(i.t(`config.${e}_invalid_name`,{name:t||"<empty>"}));return t}function _(o,t){console.log("\n"+e.bold(o)),0!==t.length?t.forEach(o=>console.log(" "+o)):console.log(e.gray(" ("+i.t("config.empty_list")+")"))}function u(o,t){if("backups"===t){const t=n.listToolBackups(o).flatMap(o=>{const t=o.file.replace(/^.*[/\\]/,"");return o.backups.length?o.backups.map(o=>`${e.cyan(t)} ${e.gray(o.name.split(".bak-")[1]||o.name)}`):[`${e.cyan(t)} ${e.gray("("+i.t("config.empty_list")+")")}`]});return void _(i.t("config.tool_backups_title",{tool:l[o].displayName}),t)}const r=n.restorePrivateConfig(o).filter(o=>o.result.restored);0!==r.length?(console.log(e.green(i.t("config.config_restored",{tool:l[o].displayName}))),r.forEach(o=>console.log(e.gray(` ${o.file} ← ${o.result.from}`))),console.log(e.yellow(" ! "+i.t("config.reopen_hint",{tool:l[o].displayName})))):console.log(e.yellow(i.t("config.restore_no_backup",{tool:l[o].displayName})))}async function y(a,f,p){if(!l[a])return void console.log(e.red(i.t("config.unknown_tool",{tool:a})));const g=(f[0]||"").toLowerCase();if("backups"!==g&&"list-backups"!==g)if("restore"!==g){if("remove"===g||"unload"===g){const o=l[a].displayName;return void await c({description:i.t("config.remove_dry_run",{tool:o}),json:{action:"remove",tool:a},apply:async()=>{if(!await s({message:i.t("config.confirm_remove",{tool:o,name:a}),defaultValue:!0}))return;const t=n.unloadPrivateConfig(a);console.log(e.green(i.t("config.remove_done",{tool:o}))),t.forEach(o=>console.log(e.yellow(" ! "+o.text)))}})}if("clear-model"===g||"clear-models"===g){const o=l[a].displayName;return n.supportsClearPinnedModels(a)?void await c({description:i.t("config.clear_model_dry_run",{tool:o}),json:{action:"clear_model",tool:a},apply:async()=>{const t=await n.clearPinnedModels(a);0!==t.length?(console.log(e.green(i.t("config.clear_model_done",{tool:o}))),t.forEach(o=>console.log(e.gray(` - ${o}`))),console.log(e.gray(i.t("config.clear_model_restart_hint",{tool:o})))):console.log(e.yellow(i.t("config.clear_model_none",{tool:o})))}}):void console.log(e.yellow(i.t("config.clear_model_unsupported",{tool:o})))}if(d())await c({description:i.t("config.tool_apply_dry_run",{tool:l[a].displayName}),json:{action:"apply",tool:a,force:Boolean(p.force)},apply:()=>{}});else{if(!n.isToolInstalled(a)){if(p.nonInteractive)return void console.log(e.yellow(i.t("wizard.tool_not_installed",{tool:l[a].displayName})));console.log(e.yellow(i.t("wizard.tool_not_installed",{tool:l[a].displayName})));const{shouldInstall:t}=await o.prompt([{type:"confirm",name:"shouldInstall",message:i.t("wizard.install_tool_confirm"),default:!0}]);if(!t)return void console.log(e.yellow(i.t("wizard.install_skipped")));try{await n.installTool(a)}catch(o){return console.error(e.red(i.t("install.install_failed_detail"))),void(o instanceof Error&&o.message&&console.error(e.gray(o.message)))}}if(p.nonInteractive||p.force){const o=r.getApiKeyForTool(a);if(!o)return void console.log(e.red(i.t("wizard.api_key_required")));if(p.force&&!p.nonInteractive&&!await s({message:i.t("config.confirm_force",{tool:l[a].displayName}),defaultValue:!1}))return;return await n.applyPrivateConfig(a,o,r.getModelsForTool(a),{force:p.force}),p.force&&console.log(e.yellow(i.t("config.force_done",{tool:l[a].displayName}))),void n.printApplied(a)}await t.showToolMenu(a)}}else await c({description:i.t("config.tool_restore_dry_run",{tool:l[a].displayName}),json:{action:"tool_restore",tool:a},apply:async()=>{await s({message:i.t("config.confirm_restore",{tool:l[a].displayName}),defaultValue:!1})&&u(a,"restore")}});else u(a,"backups")}export async function configCommand(t){const{positional:n,options:d}=function(o){const e=[],t={};(f()||p())&&(t.nonInteractive=!0);for(const n of o)"--non-interactive"===n||"-y"===n?t.nonInteractive=!0:"--force"===n||"-f"===n?t.force=!0:e.push(n);return{positional:e,options:t}}(t),u=n[0],v=n.slice(1);if(u){switch(u){case"profile":return void await async function(o){const t=o[0],n=o[1];if(!t||"list"===t){const o=r.getActiveProfileName(),t=r.listProfiles().map(t=>{const n=t===o;return`${n?e.green("●"):e.gray("○")} ${t}${n?e.gray(" ("+i.t("config.profile_active_label")+")"):""}`});return void _(i.t("config.profile_list_title"),t)}if("create"===t){const o=m(n,"profile");return r.listProfiles().includes(o)?void console.log(e.yellow(i.t("config.profile_exists",{name:o}))):void await c({description:i.t("config.profile_create_dry_run",{name:o}),json:{action:"profile_create",name:o},apply:()=>{r.createProfile(o),console.log(e.green(i.t("config.profile_created",{name:o})))}})}if("use"===t){const o=m(n,"profile");return void await c({description:i.t("config.profile_use_dry_run",{name:o}),json:{action:"profile_use",name:o},apply:()=>{r.setActiveProfile(o),console.log(e.green(i.t("config.profile_activated",{name:o})))}})}if("delete"===t||"remove"===t){const o=m(n,"profile");return o===a&&1===r.listProfiles().length?void console.log(e.yellow(i.t("config.profile_cannot_delete_last"))):void await c({description:i.t("config.profile_delete_dry_run",{name:o}),json:{action:"profile_delete",name:o},apply:async()=>{await s({message:i.t("config.profile_delete_confirm",{name:o}),defaultValue:!1})?(r.deleteProfile(o),console.log(e.green(i.t("config.profile_deleted",{name:o})))):console.log(e.yellow(i.t("config.profile_delete_aborted")))}})}console.log(e.red(i.t("config.unknown_action",{action:t})))}(v);case"preset":return void await async function(o){const t=o[0],n=o[1];if(!t||"list"===t){const o=Object.entries(r.getCustomPresets()).map(([o,t])=>`${e.cyan(o)} ${e.gray(`H:${t.models.haiku} S:${t.models.sonnet} O:${t.models.opus}`)}`);return void _(i.t("config.preset_list_title"),o)}if("save"===t){const o=m(n,"preset");return void await c({description:i.t("config.preset_save_dry_run",{name:o}),json:{action:"preset_save",name:o},apply:()=>{r.saveCustomPreset(o,r.getModels()),console.log(e.green(i.t("config.preset_saved",{name:o})))}})}if("use"===t||"apply"===t){const o=m(n,"preset"),t=r.getCustomPresets()[o];return t?void await c({description:i.t("config.preset_use_dry_run",{name:o}),json:{action:"preset_use",name:o},apply:()=>{r.setModels(t.models),console.log(e.green(i.t("config.preset_applied",{name:o})))}}):void console.log(e.red(i.t("config.preset_not_found",{name:o})))}if("delete"===t||"remove"===t){const o=m(n,"preset");return void await c({description:i.t("config.preset_delete_dry_run",{name:o}),json:{action:"preset_delete",name:o},apply:()=>{r.deleteCustomPreset(o),console.log(e.green(i.t("config.preset_deleted",{name:o})))}})}console.log(e.red(i.t("config.unknown_action",{action:t})))}(v);case"tool-model":return void await async function(o){const t=o[0];if(!t||"list"===t){const o=r.getProfile().tool_models||{},t=Object.entries(o).map(([o,t])=>{const n=Object.entries(t).map(([o,e])=>`${o}=${e}`).join(" ");return`${e.cyan(o)} ${e.gray(n)}`});return void _(i.t("config.tool_model_list_title"),t)}if("set"===t){const t=(o[1]||"").trim(),n=o.length>=4?(o[2]||"").trim():"opus",a=(o.length>=4?o[3]:o[2]||"").trim();return l[t]?a&&g.test(n)?void await c({description:i.t("config.tool_model_set_dry_run",{tool:t,slot:n,model:a}),json:{action:"tool_model_set",tool:t,slot:n,model:a},apply:()=>{r.setToolModel(t,{[n]:a}),console.log(e.green(i.t("config.tool_model_set",{tool:t,slot:n,model:a})))}}):void console.log(e.red(i.t("config.tool_model_usage"))):void console.log(e.red(i.t("config.unknown_tool",{tool:t})))}if("clear"===t||"remove"===t){const t=(o[1]||"").trim();return l[t]?void await c({description:i.t("config.tool_model_clear_dry_run",{tool:t}),json:{action:"tool_model_clear",tool:t},apply:()=>{r.setToolModel(t,null),console.log(e.green(i.t("config.tool_model_cleared",{tool:t})))}}):void console.log(e.red(i.t("config.unknown_tool",{tool:t})))}console.log(e.red(i.t("config.unknown_action",{action:t})))}(v);case"backup":return void await function(o){return async function(o){const t=o[0],n=o[1];if(!t||"list"===t){const o=r.listBackups().map(o=>{const t=new Date(o.mtimeMs).toISOString();return`${e.cyan(o.name)} ${e.gray(t)}`});return void _(i.t("config.backup_list_title"),o)}if("create"!==t&&"snapshot"!==t)return"restore"===t?n?void await c({description:i.t("config.backup_restore_dry_run",{name:n}),json:{action:"backup_restore",name:n},apply:async()=>{await s({message:i.t("config.backup_restore_confirm",{name:n}),defaultValue:!1})?(r.restoreBackup(n),console.log(e.green(i.t("config.backup_restored",{name:n})))):console.log(e.yellow(i.t("config.backup_restore_aborted")))}}):void console.log(e.red(i.t("config.backup_restore_missing_name"))):void console.log(e.red(i.t("config.unknown_action",{action:t})));await c({description:i.t("config.backup_create_dry_run"),json:{action:"backup_create",name:n??null},apply:()=>{const o=r.createBackup(n);console.log(e.green(i.t("config.backup_created",{path:o})))}})}(o)}(v)}"claude-code"!==u&&"claude-code"!==v[0]?l[u]?await y(u,v,d):(console.error(e.red(i.t("config.unknown_command",{command:u}))),console.log(e.gray(i.t("config.usage_hint"))),Object.values(l).filter(o=>!o.hidden).forEach(o=>{console.log(e.gray(` - ${o.name}: ${o.displayName}`))})):await y("claude-code",v,d)}else await async function(t){if(t.nonInteractive)return void console.log(e.red(i.t("config.requires_argument")));const{selectedTool:n}=await o.prompt([{type:"list",name:"selectedTool",message:i.t("wizard.select_tool"),choices:Object.values(l).filter(o=>!o.hidden).map(o=>({name:`${o.displayName} (${o.name})`,value:o.name}))}]);await y(n,[],t)}(d)}
@@ -10,7 +10,8 @@
10
10
  * 多令牌各配各的(如 Claude 分组 + GPT 分组 + Grok 分组),各自校验 + 能力核对,
11
11
  * 明文存入 config.yaml 的工具专属 Key。只给其中一个旗标就只配对应工具。
12
12
  * `--desktopkey` 配 Claude Desktop(桌面端 3p 模式);`--key` 在 macOS / Windows 上一律顺带配置它,
13
- * 没装也先写好(用户 2026-10-18 定),Linux 没有 Claude Desktop 不配。
13
+ * 没装也先写好(用户 2026-10-18 定);Linux 版(官方 beta,2026-06 起)只在已装时顺带配置,
14
+ * 免得在没有桌面的服务器上写一份用不到的 ~/.config/Claude-3p。
14
15
  *
15
16
  * vibecli setup --1m
16
17
  * 复用当前 profile 已保存的 Codex Key,开启 1M 上下文并重新应用配置。
@@ -1 +1 @@
1
- import o from"chalk";import{getAdapter as e}from"../lib/tools/registry.js";import{postApplyPrompts as t}from"../lib/post-apply.js";import{ensureReachableGatewayAddress as i}from"./base.js";import{i18n as s}from"../lib/i18n.js";import{configManager as l}from"../lib/config.js";import{toolManager as a,SUPPORTED_TOOLS as n}from"../lib/tool-manager.js";import{validateApiKey as r,fetchModels as p}from"../lib/api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as d,setCodexOneMillionContext as c}from"../lib/tools/codex.js";import{resolveModelCatalog as u}from"../lib/model-catalog.js";import{CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING as m,CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as f}from"../lib/tools/claude-desktop.js";import{operationError as g,authenticationError as y,networkError as k,EXIT_CODES as _}from"../lib/errors.js";import{isJsonMode as h,isNonInteractive as b,shouldAutoConfirm as w}from"../lib/runtime-options.js";import v from"inquirer";import{logger as x}from"../utils/logger.js";import{forgetInstalls as C}from"../lib/tools/tool-installs.js";import{CLI_NAME as j,brandEnv as K}from"../lib/brand.js";export const DEDICATED_KEYS=[{option:"claudekey",tool:"claude-code",need:"claude"},{option:"codexkey",tool:"codex",need:"gpt"},{option:"grokkey",tool:"grok",need:"grok"},{option:"desktopkey",tool:"claude-desktop",need:"claude"},{option:"agykey",tool:"agy",need:"gemini"},{option:"openclawkey",tool:"openclaw",need:"any",hidden:!0},{option:"hermeskey",tool:"hermes",need:"any",hidden:!0},{option:"atomcodekey",tool:"atomcode",need:"any",hidden:!0}];async function T(o){const e=await p(o);if(!e.ok)return{hasClaude:!0,hasGpt:!0,hasGrok:!0,hasGemini:!0,probed:!1};const t=e.models.map(o=>o.toLowerCase());return{hasClaude:t.some(o=>o.includes("claude")),hasGpt:t.some(o=>o.startsWith("gpt")||o.includes("gpt-")||/^o\d/.test(o)),hasGrok:t.some(o=>o.includes("grok")),hasGemini:t.some(o=>o.startsWith("gemini")),probed:!0}}function $(o,e){switch(e){case"claude":return o.hasClaude;case"gpt":return o.hasGpt;case"grok":return o.hasGrok;case"gemini":return o.hasGemini;default:return!0}}export function parseOnOff(o){const e=(o??"").trim().toLowerCase();return!!["on","true","show","1","yes","y"].includes(e)||!["off","false","hide","0","no","n"].includes(e)&&void 0}function G(e){console.log(o.green(e))}function N(e){console.log(o.yellow(e))}function M(e){console.error(o.red(e))}let S=null;function E(o){const e={operation:1,authentication:2,network:3};(!S||e[o]>e[S])&&(S=o)}async function O(e,t){h()||console.log(o.gray(s.t("setup.validating",{label:e})));const i=await r(t);if(i.valid)return!0;const a="zh_CN"===s.getLocale()?"<你的 Key>":"<your key>",n="--key"===e?`${j} setup --key ${a}`:`${j} setup ${e} ${a}`;let p;if("network_error"===i.error?(E("network"),p=k(s.t("setup.unreachable",{url:l.getBaseUrl(),reason:i.message||"network error"}),`${j} base auto`,"network_error")):"invalid_api_key"===i.error?(E("authentication"),p=y(s.t("setup.invalid_key",{label:e,reason:i.message||"invalid"}),n,"invalid_api_key")):(E("operation"),p=g(s.t("setup.invalid_key",{label:e,reason:i.message||i.error||"unknown"}),n,i.error)),h())throw p;return M(p.message),console.log(o.gray(s.t("errors.next_step",{command:p.hint}))),!1}async function A(t,i,r={}){const{oneMillion:p,officialLogin:c,desktopRegistry:u,force:y}=r,k=n[t];try{"claude-desktop"===t&&void 0!==u&&l.setToolSetting("claude-desktop",m,u),"codex"===t&&void 0!==p&&l.setToolSetting("codex",d,p),"claude-desktop"===t&&void 0!==c&&l.setToolSetting("claude-desktop",f,!c),await a.applyPrivateConfig(t,i,l.getModelsForTool(t),{force:y})}catch(o){if(h())throw g(o instanceof Error?o.message:String(o),`${j} setup --key ${"zh_CN"===s.getLocale()?"<你的 Key>":"<your key>"}`,"config_write_failed");const e=(o instanceof Error?o.message:String(o)).replace(/\s+/g," ").trim();return M("× "+s.t("setup.apply_failed",{tool:k.displayName,reason:e})),!1}return a.printApplied(t),y&&console.log(o.gray(" "+s.t("config.force_done",{tool:k.displayName}))),"codex"===t&&void 0!==p&&console.log(o.gray(" "+s.t(p?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))),e(t)?.isInstalled&&!a.isToolInstalled(t)&&console.log(o.yellow(" ! "+s.t("setup.gui_preconfigured",{tool:k.displayName,install:k.installCommand}))),!0}export async function setupCommand(r){S=null;const p=r.key?.trim(),m=DEDICATED_KEYS.map(o=>({...o,apiKey:r[o.option]?.trim()})).filter(o=>Boolean(o.apiKey)),f=void 0!==r.oneMillion,g=void 0!==r.claudeOfficial;let y;if(g&&(y=parseOnOff(r.claudeOfficial),void 0===y))return M(s.t("setup.claude_official_invalid",{value:String(r.claudeOfficial)})),void(process.exitCode=1);const k=void 0!==r.desktopRegistry;let E;if(k&&(E=parseOnOff(r.desktopRegistry),void 0===E))return M(s.t("setup.desktop_registry_invalid",{value:String(r.desktopRegistry)})),void(process.exitCode=1);const I=g||k,L=Boolean(p||m.length>0),D={oneMillion:r.oneMillion,officialLogin:y,desktopRegistry:E,force:r.force};if(!L&&(f||I)){if(f){const o=l.getApiKeyForTool("codex");if(o)try{const e=!0===r.oneMillion;l.setToolSetting("codex",d,e);const t=await u(o);c(e,t??void 0),G(s.t(e?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))}catch(o){M(s.t("setup.apply_failed",{tool:n.codex.displayName,reason:o instanceof Error?o.message:String(o)})),process.exitCode=1}else M(s.t("setup.codex_1m_missing_key")),process.exitCode=1}if(I){const o=l.getApiKeyForTool("claude-desktop");o?await A("claude-desktop",o,{...D,oneMillion:void 0})?await t(["claude-desktop"]):process.exitCode=1:(M(s.t("setup.desktop_official_login_missing_key")),process.exitCode=1)}return}if(!L)return M(s.t("setup.usage")),void(process.exitCode=1);await i(p||m[0].apiKey);let R=0,B=0;const F=new Set,P=m.map(o=>({tool:o.tool,label:`--${o.option}`,apiKey:o.apiKey,need:o.need}));for(const o of P){if(!await O(o.label,o.apiKey)){B+=1;continue}const e=await T(o.apiKey);!e.probed||$(e,o.need)?(e.probed||N(s.t("setup.probe_failed",{label:o.label})),l.setToolApiKey(o.tool,o.apiKey),await A(o.tool,o.apiKey,D)?(R+=1,F.add(o.tool)):B+=1):(M(s.t(`setup.key_no_${o.need}`,{label:o.label,tool:n[o.tool].displayName})),B+=1)}if(p){if(!await O("--key",p))return void(process.exitCode=_[S??"operation"]);l.setApiKey(p);const o=await T(p);if(o.probed||N(s.t("setup.probe_failed",{label:"--key"})),o.probed&&!o.hasClaude&&!o.hasGpt&&!o.hasGrok&&!o.hasGemini)return M(s.t("setup.key_no_family")),void(process.exitCode=1);const e=[{tool:"claude-code",capable:o.hasClaude,skipMsg:s.t("setup.skip_no_claude")},{tool:"codex",capable:o.hasGpt,skipMsg:s.t("setup.skip_no_gpt")},{tool:"grok",capable:o.hasGrok,skipMsg:s.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:o.hasClaude&&("darwin"===process.platform||"win32"===process.platform),skipMsg:"",quiet:!0},{tool:"agy",capable:o.hasGemini,skipMsg:s.t("setup.skip_no_gemini")}];for(const o of e)F.has(o.tool)||(o.capable?await A(o.tool,p,D)?(R+=1,F.add(o.tool)):B+=1:o.quiet||N(o.skipMsg))}if(R>0){const t=await async function(t,i,r){const p=t.filter(o=>!e(o)?.isInstalled&&!a.isToolInstalled(o));if(0===p.length)return[];const d=p.map(o=>n[o].displayName).join(s.t("setup.list_separator"));let c=i;if(void 0!==c||h()||(w()?c=!b():process.stdin.isTTY&&(console.log(""),c=(await v.prompt([{type:"confirm",name:"go",message:s.t("setup.install_confirm",{tools:d}),default:!0}])).go)),!c){console.log("");for(const e of p)console.log(o.yellow("! "+s.t("setup.install_hint",{tool:n[e].displayName,install:n[e].installCommand})));return h()||console.log(o.gray(s.t("setup.install_all_hint",{cli:j}))),p}const u=[];for(const e of p){console.log(o.bold(`\n${n[e].displayName}`));try{await a.installTool(e)}catch(o){x.logError(`setup: install ${e}`,o)}C(),a.isToolInstalled(e)||u.push(e)}const m=p.filter(o=>!u.includes(o));m.length>0&&console.log("");for(const o of m){const e=l.getApiKeyForTool(o);e&&await A(o,e,{...r,oneMillion:void 0,force:void 0})}return u}([...F],r.install,D),i=[...F].filter(o=>!e(o)?.isInstalled&&!t.includes(o)),p=i.map(o=>n[o]?.command).filter(Boolean).join(" / "),d=s.t("setup.done",{count:String(R)});G("\n"+(p?`${d}${s.t("setup.done_commands",{commands:p})}`:d)),t.length>0&&N(s.t("setup.still_missing",{tools:t.map(o=>n[o].displayName).join(s.t("setup.list_separator"))}));for(const o of i){const e=a.ensureNativeOnPath(o);e&&G(s.t("setup.path_added",{tool:n[o].displayName,dir:e}))}const c=i.filter(o=>!a.isOnPath(o));if(c.length>0&&!h()&&"1"!==K("PATH_HINT_BY_CALLER")){const e=c.map(o=>n[o].command).join(" / ");console.log(o.yellow(" ! "+s.t("win32"===process.platform?"setup.path_reload_windows":"setup.path_reload",{commands:e})))}}B>0&&(M(s.t("setup.failed_summary",{count:String(B)})),h()||console.error(`${j} setup --key ${"zh_CN"===s.getLocale()?"<你的 Key>":"<your key>"}`)),await t([...F]),(B>0||0===R)&&(process.exitCode=_[S??"operation"])}
1
+ import o from"chalk";import{getAdapter as e}from"../lib/tools/registry.js";import{postApplyPrompts as t}from"../lib/post-apply.js";import{ensureReachableGatewayAddress as i}from"./base.js";import{i18n as s}from"../lib/i18n.js";import{configManager as l}from"../lib/config.js";import{toolManager as n,SUPPORTED_TOOLS as a}from"../lib/tool-manager.js";import{validateApiKey as r,fetchModels as p}from"../lib/api-validator.js";import{CODEX_ONE_MILLION_CONTEXT_SETTING as d,setCodexOneMillionContext as c}from"../lib/tools/codex.js";import{resolveModelCatalog as u}from"../lib/model-catalog.js";import{CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING as f,CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING as m}from"../lib/tools/claude-desktop.js";import{operationError as g,authenticationError as y,networkError as k,EXIT_CODES as _}from"../lib/errors.js";import{emitJson as h,isColorEnabled as b,isDryRun as w,isJsonMode as v,isNonInteractive as x,shouldAutoConfirm as C}from"../lib/runtime-options.js";import{join as $}from"path";import T from"inquirer";import{logger as j}from"../utils/logger.js";import{forgetInstalls as K}from"../lib/tools/tool-installs.js";import{CLI_NAME as N,brandEnv as G}from"../lib/brand.js";export const DEDICATED_KEYS=[{option:"claudekey",tool:"claude-code",need:"claude"},{option:"codexkey",tool:"codex",need:"gpt"},{option:"grokkey",tool:"grok",need:"grok"},{option:"desktopkey",tool:"claude-desktop",need:"claude"},{option:"agykey",tool:"agy",need:"gemini"},{option:"openclawkey",tool:"openclaw",need:"any",hidden:!0},{option:"hermeskey",tool:"hermes",need:"any",hidden:!0},{option:"atomcodekey",tool:"atomcode",need:"any",hidden:!0}];async function M(o){const e=await p(o);if(!e.ok)return{hasClaude:!0,hasGpt:!0,hasGrok:!0,hasGemini:!0,probed:!1};const t=e.models.map(o=>o.toLowerCase());return{hasClaude:t.some(o=>o.includes("claude")),hasGpt:t.some(o=>o.startsWith("gpt")||o.includes("gpt-")||/^o\d/.test(o)),hasGrok:t.some(o=>o.includes("grok")),hasGemini:t.some(o=>o.startsWith("gemini")),probed:!0}}function S(o,e){switch(e){case"claude":return o.hasClaude;case"gpt":return o.hasGpt;case"grok":return o.hasGrok;case"gemini":return o.hasGemini;default:return!0}}export function parseOnOff(o){const e=(o??"").trim().toLowerCase();return!!["on","true","show","1","yes","y"].includes(e)||!["off","false","hide","0","no","n"].includes(e)&&void 0}function E(e){console.log(o.green(e))}function O(e){console.log(o.yellow(e))}function A(e){console.error(o.red(e))}let I=null;function L(o){const e={operation:1,authentication:2,network:3};(!I||e[o]>e[I])&&(I=o)}async function D(e,t){v()||console.log(o.gray(s.t("setup.validating",{label:e})));const i=await r(t);if(i.valid)return!0;const n="zh_CN"===s.getLocale()?"<你的 Key>":"<your key>",a="--key"===e?`${N} setup --key ${n}`:`${N} setup ${e} ${n}`;let p;if("network_error"===i.error?(L("network"),p=k(s.t("setup.unreachable",{url:l.getBaseUrl(),reason:i.message||"network error"}),`${N} base auto`,"network_error")):"invalid_api_key"===i.error?(L("authentication"),p=y(s.t("setup.invalid_key",{label:e,reason:i.message||"invalid"}),a,"invalid_api_key")):(L("operation"),p=g(s.t("setup.invalid_key",{label:e,reason:i.message||i.error||"unknown"}),a,i.error)),v())throw p;return A(p.message),console.log(o.gray(s.t("errors.next_step",{command:p.hint}))),!1}async function P(t,i,r={}){const{oneMillion:p,officialLogin:c,desktopRegistry:u,force:y}=r,k=a[t];try{"claude-desktop"===t&&void 0!==u&&l.setToolSetting("claude-desktop",f,u),"codex"===t&&void 0!==p&&l.setToolSetting("codex",d,p),"claude-desktop"===t&&void 0!==c&&l.setToolSetting("claude-desktop",m,!c),await n.applyPrivateConfig(t,i,l.getModelsForTool(t),{force:y})}catch(o){if(v())throw g(o instanceof Error?o.message:String(o),`${N} setup --key ${"zh_CN"===s.getLocale()?"<你的 Key>":"<your key>"}`,"config_write_failed");const e=(o instanceof Error?o.message:String(o)).replace(/\s+/g," ").trim();return A("× "+s.t("setup.apply_failed",{tool:k.displayName,reason:e})),!1}return n.printApplied(t),y&&console.log(o.gray(" "+s.t("config.force_done",{tool:k.displayName}))),"codex"===t&&void 0!==p&&console.log(o.gray(" "+s.t(p?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))),e(t)?.isInstalled&&!n.isToolInstalled(t)&&console.log(o.yellow(" ! "+s.t("setup.gui_preconfigured",{tool:k.displayName,install:k.installCommand}))),!0}function R(t,i){const n=t.map(o=>{const t=e(o);return{tool:o,files:t?.backupPaths?.()??(t?[t.configPath]:[])}}),r=$(l.getConfigDir(),"config.yaml");if(v())return void h({dry_run:!0,tools:n,key_file:i?r:null});const p=(b()?o.cyan:o=>o)(s.t("runtime.dry_run_label"));if(0!==n.length){for(const{tool:e,files:t}of n)console.log(`${p} ${s.t("setup.dry_run_tool",{tool:a[e]?.displayName??e})}`),t.forEach(e=>console.log(o.gray(` ${e}`)));i&&console.log(`${p} ${s.t("setup.dry_run_key",{file:r})}`)}else console.log(`${p} ${s.t("setup.dry_run_none")}`)}export async function setupCommand(r){I=null;const p=r.key?.trim(),f=DEDICATED_KEYS.map(o=>({...o,apiKey:r[o.option]?.trim()})).filter(o=>Boolean(o.apiKey)),m=void 0!==r.oneMillion,g=void 0!==r.claudeOfficial;let y;if(g&&(y=parseOnOff(r.claudeOfficial),void 0===y))return A(s.t("setup.claude_official_invalid",{value:String(r.claudeOfficial)})),void(process.exitCode=1);const k=void 0!==r.desktopRegistry;let h;if(k&&(h=parseOnOff(r.desktopRegistry),void 0===h))return A(s.t("setup.desktop_registry_invalid",{value:String(r.desktopRegistry)})),void(process.exitCode=1);const b=g||k,$=Boolean(p||f.length>0),L={oneMillion:r.oneMillion,officialLogin:y,desktopRegistry:h,force:r.force};if(!$&&(m||b)&&w())return void R([...m?["codex"]:[],...b?["claude-desktop"]:[]],!1);if(!$&&(m||b)){if(m){const o=l.getApiKeyForTool("codex");if(o)try{const e=!0===r.oneMillion;l.setToolSetting("codex",d,e);const t=await u(o);c(e,t??void 0),E(s.t(e?"setup.codex_1m_enabled":"setup.codex_1m_disabled"))}catch(o){A(s.t("setup.apply_failed",{tool:a.codex.displayName,reason:o instanceof Error?o.message:String(o)})),process.exitCode=1}else A(s.t("setup.codex_1m_missing_key")),process.exitCode=1}if(b){const o=l.getApiKeyForTool("claude-desktop");o?await P("claude-desktop",o,{...L,oneMillion:void 0})?await t(["claude-desktop"]):process.exitCode=1:(A(s.t("setup.desktop_official_login_missing_key")),process.exitCode=1)}return}if(!$)return A(s.t("setup.usage")),void(process.exitCode=1);const B=w();B||await i(p||f[0].apiKey);const F=[];let Y=0,q=0;const z=new Set,H=f.map(o=>({tool:o.tool,label:`--${o.option}`,apiKey:o.apiKey,need:o.need}));for(const o of H){if(!await D(o.label,o.apiKey)){q+=1;continue}const e=await M(o.apiKey);!e.probed||S(e,o.need)?(e.probed||O(s.t("setup.probe_failed",{label:o.label})),B?(F.push(o.tool),z.add(o.tool)):(l.setToolApiKey(o.tool,o.apiKey),await P(o.tool,o.apiKey,L)?(Y+=1,z.add(o.tool)):q+=1)):(A(s.t(`setup.key_no_${o.need}`,{label:o.label,tool:a[o.tool].displayName})),q+=1)}if(p){if(!await D("--key",p))return void(process.exitCode=_[I??"operation"]);B||l.setApiKey(p);const o=await M(p);if(o.probed||O(s.t("setup.probe_failed",{label:"--key"})),o.probed&&!o.hasClaude&&!o.hasGpt&&!o.hasGrok&&!o.hasGemini)return A(s.t("setup.key_no_family")),void(process.exitCode=1);const e=[{tool:"claude-code",capable:o.hasClaude,skipMsg:s.t("setup.skip_no_claude")},{tool:"codex",capable:o.hasGpt,skipMsg:s.t("setup.skip_no_gpt")},{tool:"grok",capable:o.hasGrok,skipMsg:s.t("setup.skip_no_grok")},{tool:"claude-desktop",capable:o.hasClaude&&("darwin"===process.platform||"win32"===process.platform||n.isToolInstalled("claude-desktop")),skipMsg:"",quiet:!0},{tool:"agy",capable:o.hasGemini,skipMsg:s.t("setup.skip_no_gemini")}];for(const o of e)z.has(o.tool)||(o.capable?B?(F.push(o.tool),z.add(o.tool)):await P(o.tool,p,L)?(Y+=1,z.add(o.tool)):q+=1:o.quiet||O(o.skipMsg))}if(B)return R(F,F.length>0),void(q>0&&(process.exitCode=_[I??"operation"]));if(Y>0){const t=await async function(t,i,r){const p=t.filter(o=>!e(o)?.isInstalled&&!n.isToolInstalled(o));if(0===p.length)return[];const d=p.map(o=>a[o].displayName).join(s.t("setup.list_separator"));let c=i;if(void 0!==c||v()||(C()?c=!x():process.stdin.isTTY&&(console.log(""),c=(await T.prompt([{type:"confirm",name:"go",message:s.t("setup.install_confirm",{tools:d}),default:!0}])).go)),!c){console.log("");for(const e of p)console.log(o.yellow("! "+s.t("setup.install_hint",{tool:a[e].displayName,install:a[e].installCommand})));return v()||console.log(o.gray(s.t("setup.install_all_hint",{cli:N}))),p}const u=[];for(const e of p){console.log(o.bold(`\n${a[e].displayName}`));try{await n.installTool(e)}catch(o){j.logError(`setup: install ${e}`,o)}K(),n.isToolInstalled(e)||u.push(e)}const f=p.filter(o=>!u.includes(o));f.length>0&&console.log("");for(const o of f){const e=l.getApiKeyForTool(o);e&&await P(o,e,{...r,oneMillion:void 0,force:void 0})}return u}([...z],r.install,L),i=[...z].filter(o=>!e(o)?.isInstalled&&!t.includes(o)),p=i.map(o=>a[o]?.command).filter(Boolean).join(" / "),d=s.t("setup.done",{count:String(Y)});E("\n"+(p?`${d}${s.t("setup.done_commands",{commands:p})}`:d)),t.length>0&&O(s.t("setup.still_missing",{tools:t.map(o=>a[o].displayName).join(s.t("setup.list_separator"))}));for(const o of i){const e=n.ensureNativeOnPath(o);e&&E(s.t("setup.path_added",{tool:a[o].displayName,dir:e}))}const c=i.filter(o=>!n.isOnPath(o));if(c.length>0&&!v()&&"1"!==G("PATH_HINT_BY_CALLER")){const e=c.map(o=>a[o].command).join(" / ");console.log(o.yellow(" ! "+s.t("win32"===process.platform?"setup.path_reload_windows":"setup.path_reload",{commands:e})))}}q>0&&(A(s.t("setup.failed_summary",{count:String(q)})),v()||console.error(`${N} setup --key ${"zh_CN"===s.getLocale()?"<你的 Key>":"<your key>"}`)),await t([...z]),(q>0||0===Y)&&(process.exitCode=_[I??"operation"])}
@@ -18,6 +18,8 @@ export declare class Command {
18
18
  */
19
19
  private preflightArgs;
20
20
  execute(args: string[]): Promise<void>;
21
+ /** `--dry-run` on a command that would write anyway: refuse before anything runs. */
22
+ private rejectUnsupportedDryRun;
21
23
  private rejectUnknownCommand;
22
24
  private suggestCommand;
23
25
  private normalizeCommanderError;
@@ -1 +1 @@
1
- import{i18n as n,detectSystemLang as o}from"./i18n.js";import{configManager as r}from"./config.js";import{runModelRefresh as e}from"./model-refresh.js";import{refreshClientConfig as t}from"./client-config-sync.js";import{normalizeBaseUrl as s}from"./gateway-addresses.js";import i from"chalk";import{setRuntimeOptions as a,detectColorPreferenceFromEnv as m,isColorEnabled as c,isJsonMode as l}from"./runtime-options.js";import{cleanupAnthropicEnvVars as g,machineEnvVarsLeft as d}from"./env-cleanup.js";import{runStartupUpdate as f}from"./auto-update.js";import{buildProgram as u}from"./program.js";import{firstCommandWord as p,isHelpRequest as h,renderHelpTopic as w}from"./cli-help.js";import{reportCliError as y,usageError as v,CliError as _}from"./errors.js";import{CLI_NAME as j}from"./brand.js";import{flushTelemetry as k,installClientHeaders as C,setTelemetryCommand as x,track as A}from"./telemetry.js";export{buildProgram}from"./program.js";const b=new Set(["setup","init","auth","enter","config"]);export class Command{program;configuring=!1;constructor(){const e=r.isLangChosen()?r.getLang():o();n.loadFromConfig(e),this.program=u()}cleanupLeakedEnvVars(){const o=g();if(0===o.length||l())return;const r=n.t("messages.env_vars_cleared",{vars:o.join(", ")});console.log(c()?i.yellow(r):r);const e=d();if(e.length>0){const o=n.t("messages.env_vars_machine_left",{vars:e.join(", ")});console.log(c()?i.yellow(o):o)}}preflightArgs(n){const o=o=>n.includes(o),e=!o("--no-color")&&m();if(a({nonInteractive:o("--non-interactive"),json:o("--json"),yes:o("--yes")||o("-y"),dryRun:o("--dry-run"),color:e}),e||(i.level=0),this.configuring=!1,h(n))return;let t;for(let o=0;o<n.length;o+=1){const r=n[o];"--base"===r&&n[o+1]?(t=n[o+1],o+=1):r.startsWith("--base=")&&(t=r.slice(7))}const c=p(n),l=void 0===c&&!["--version","-v"].some(o);this.configuring=l||void 0!==c&&b.has(c),t&&r.setBaseUrl(s(t)??t,this.configuring)}async execute(n){const o=Date.now();let r=!1;try{if(this.preflightArgs(n),C(),h(n)||["--version","-v"].some(o=>n.includes(o))||(x(p(n)??"wizard"),A("command","start",{detail:{args:n.filter(n=>n.startsWith("-")&&!/key/i.test(n))}}),r=!0),"help"===n[0]&&n[1]){const o=w(n[1]);if(o)return void process.stdout.write(o)}if(this.rejectUnknownCommand(n),!h(n)){if(this.configuring&&this.cleanupLeakedEnvVars(),(await f(n)).handled)return;this.configuring&&await t({timeoutMs:5e3}),await e(n)}if(await this.program.parseAsync(n,{from:"user"}),r){const n=Boolean(process.exitCode)&&0!==process.exitCode;A("command",n?"fail":"ok",{duration_ms:Date.now()-o,...n?{detail:{exit_code:process.exitCode}}:{}})}}catch(e){if("commander.helpDisplayed"===e?.code||"commander.version"===e?.code)return;const t=this.normalizeCommanderError(e,n),s=y(t);if(r){const n=t instanceof _?`${t.type}${t.subtype?"/"+t.subtype:""}`:void 0;A("command",130===s?"cancel":"fail",{duration_ms:Date.now()-o,error:t,detail:{exit_code:s,...n?{type:n}:{}}})}}finally{r&&await k()}}rejectUnknownCommand(o){const r=p(o);if(!r||"help"===r)return;if(this.program.commands.some(n=>n.name()===r))return;const e=this.suggestCommand(r),t=e?n.t("cli.unknown_hint_suggestion",{command:e}):n.t("cli.unknown_hint");throw v(n.t("cli.error_unknown",{command:r}),t,"unknown_command")}suggestCommand(n){const o=(n,o)=>{const r=Array.from({length:o.length+1},(n,o)=>o);for(let e=1;e<=n.length;e+=1){let t=r[0];r[0]=e;for(let s=1;s<=o.length;s+=1){const i=r[s];r[s]=Math.min(r[s]+1,r[s-1]+1,t+(n[e-1]===o[s-1]?0:1)),t=i}}return r[o.length]};return this.program.commands.map(n=>n.name()).map(r=>({name:r,score:o(n,r)})).filter(({score:o})=>o<=Math.max(2,Math.floor(n.length/2))).sort((n,o)=>n.score-o.score)[0]?.name}normalizeCommanderError(o,r){if(o instanceof _)return o;const e=o?.code,t=o instanceof Error?o.message:String(o);if("commander.unknownOption"===e||"commander.missingArgument"===e||"commander.missingMandatoryOption"===e||"commander.invalidArgument"===e){const o=p(r)??j,s=/'([^']+)'/.exec(t)?.[1]??"",i="commander.unknownOption"===e?"cli.err_unknown_option":"commander.missingArgument"===e?"cli.err_missing_argument":"commander.missingMandatoryOption"===e?"cli.err_missing_option":null,a=i&&s?n.t(i,{name:s}):t.replace(/^error:\s*/,"");return v(a,n.t("cli.unknown_option_hint",{command:o}),e)}return o}getProgram(){return this.program}}
1
+ import{i18n as n,detectSystemLang as r}from"./i18n.js";import{configManager as o}from"./config.js";import{runModelRefresh as e}from"./model-refresh.js";import{refreshClientConfig as t}from"./client-config-sync.js";import{normalizeBaseUrl as s}from"./gateway-addresses.js";import i from"chalk";import{setRuntimeOptions as m,detectColorPreferenceFromEnv as a,isColorEnabled as c,isDryRun as l,isJsonMode as d}from"./runtime-options.js";import{cleanupAnthropicEnvVars as u,envCleanupChangedProfile as g,machineEnvVarsLeft as p}from"./env-cleanup.js";import{runStartupUpdate as f}from"./auto-update.js";import{buildProgram as h}from"./program.js";import{firstCommandWord as _,isHelpRequest as y,renderHelpTopic as w}from"./cli-help.js";import{reportCliError as v,usageError as j,CliError as k}from"./errors.js";import{CLI_NAME as C}from"./brand.js";import{dryRunUnsupportedCommand as x}from"./dry-run.js";import{flushTelemetry as A,installClientHeaders as b,setTelemetryCommand as D,track as M}from"./telemetry.js";export{buildProgram}from"./program.js";const E=new Set(["setup","init","auth","enter","config"]);export class Command{program;configuring=!1;constructor(){const e=o.isLangChosen()?o.getLang():r();n.loadFromConfig(e),this.program=h()}cleanupLeakedEnvVars(){const r=u();if(0===r.length||d())return;const o=g()?"messages.env_vars_cleared":"messages.env_vars_ignored",e=n.t(o,{vars:r.join(", ")});console.log(c()?i.yellow(e):e);const t=p();if(t.length>0){const r=n.t("messages.env_vars_machine_left",{vars:t.join(", ")});console.log(c()?i.yellow(r):r)}}preflightArgs(n){const r=r=>n.includes(r),e=!r("--no-color")&&a();if(m({nonInteractive:r("--non-interactive"),json:r("--json"),yes:r("--yes")||r("-y"),dryRun:r("--dry-run"),color:e}),e||(i.level=0),this.configuring=!1,y(n))return;let t;for(let r=0;r<n.length;r+=1){const o=n[r];"--base"===o&&n[r+1]?(t=n[r+1],r+=1):o.startsWith("--base=")&&(t=o.slice(7))}const c=_(n),l=void 0===c&&!["--version","-v"].some(r);this.configuring=l||void 0!==c&&E.has(c),t&&o.setBaseUrl(s(t)??t,this.configuring&&!r("--dry-run"))}async execute(n){const r=Date.now();let o=!1;try{if(this.preflightArgs(n),b(),y(n)||["--version","-v"].some(r=>n.includes(r))||(D(_(n)??"wizard"),M("command","start",{detail:{args:n.filter(n=>n.startsWith("-")&&!/key/i.test(n))}}),o=!0),"help"===n[0]&&n[1]){const r=w(n[1]);if(r)return void process.stdout.write(r)}if(this.rejectUnknownCommand(n),!y(n)){if(l()&&this.rejectUnsupportedDryRun(n),this.configuring&&!l()&&this.cleanupLeakedEnvVars(),(await f(n)).handled)return;this.configuring&&await t({timeoutMs:5e3}),await e(n)}if(await this.program.parseAsync(n,{from:"user"}),o){const n=Boolean(process.exitCode)&&0!==process.exitCode;M("command",n?"fail":"ok",{duration_ms:Date.now()-r,...n?{detail:{exit_code:process.exitCode}}:{}})}}catch(e){if("commander.helpDisplayed"===e?.code||"commander.version"===e?.code)return;const t=this.normalizeCommanderError(e,n),s=v(t);if(o){const n=t instanceof k?`${t.type}${t.subtype?"/"+t.subtype:""}`:void 0;M("command",130===s?"cancel":"fail",{duration_ms:Date.now()-r,error:t,detail:{exit_code:s,...n?{type:n}:{}}})}}finally{o&&await A()}}rejectUnsupportedDryRun(r){const o=x(r);if(null!==o)throw j(n.t("runtime.dry_run_unsupported",{command:o,cli:C}),n.t("runtime.dry_run_unsupported_hint",{cli:C}),"dry_run_unsupported")}rejectUnknownCommand(r){const o=_(r);if(!o||"help"===o)return;if(this.program.commands.some(n=>n.name()===o))return;const e=this.suggestCommand(o),t=e?n.t("cli.unknown_hint_suggestion",{command:e}):n.t("cli.unknown_hint");throw j(n.t("cli.error_unknown",{command:o}),t,"unknown_command")}suggestCommand(n){const r=(n,r)=>{const o=Array.from({length:r.length+1},(n,r)=>r);for(let e=1;e<=n.length;e+=1){let t=o[0];o[0]=e;for(let s=1;s<=r.length;s+=1){const i=o[s];o[s]=Math.min(o[s]+1,o[s-1]+1,t+(n[e-1]===r[s-1]?0:1)),t=i}}return o[r.length]};return this.program.commands.map(n=>n.name()).map(o=>({name:o,score:r(n,o)})).filter(({score:r})=>r<=Math.max(2,Math.floor(n.length/2))).sort((n,r)=>n.score-r.score)[0]?.name}normalizeCommanderError(r,o){if(r instanceof k)return r;const e=r?.code,t=r instanceof Error?r.message:String(r);if("commander.unknownOption"===e||"commander.missingArgument"===e||"commander.missingMandatoryOption"===e||"commander.invalidArgument"===e){const r=_(o)??C,s=/'([^']+)'/.exec(t)?.[1]??"",i="commander.unknownOption"===e?"cli.err_unknown_option":"commander.missingArgument"===e?"cli.err_missing_argument":"commander.missingMandatoryOption"===e?"cli.err_missing_option":null,m=i&&s?n.t(i,{name:s}):t.replace(/^error:\s*/,"");return j(m,n.t("cli.unknown_option_hint",{command:r}),e)}return r}getProgram(){return this.program}}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * `--dry-run` promises "show what would change without writing anything". Commands
3
+ * that honor it: `setup` and `config` (they print the plan), the read-only ones,
4
+ * and `codex sessions` without `--undo`. Anything else that writes refuses the flag
5
+ * instead of silently writing (api-helper#8: `setup --dry-run` used to save the key
6
+ * and write Claude Desktop's config).
7
+ *
8
+ * Returns the command as the user would name it when it can't run under `--dry-run`, else null.
9
+ */
10
+ export declare function dryRunUnsupportedCommand(args: readonly string[]): string | null;
@@ -0,0 +1 @@
1
+ import{firstCommandWord as e}from"./cli-help.js";export function dryRunUnsupportedCommand(s){const n=e(s);if(void 0===n)return"(wizard)";const r=s.filter(e=>!e.startsWith("-")),o=r[r.indexOf(n)+1];switch(n){case"setup":case"config":case"status":case"bench":case"logs":case"completion":case"help":return null;case"doctor":return s.includes("--report")?"doctor --report":null;case"base":return void 0===o?null:`base ${o}`;case"lang":return void 0===o||"show"===o?null:`lang ${o}`;case"codex":return s.includes("--undo")?"codex sessions --undo":null;default:return n}}
@@ -21,6 +21,7 @@ export declare function cleanupShellRcEnvVars(): boolean;
21
21
  */
22
22
  export declare function cleanupWindowsEnvVars(names: readonly string[]): {
23
23
  machineLeft: string[];
24
+ changed: boolean;
24
25
  };
25
26
  /**
26
27
  * 检测并清除环境中的 ANTHROPIC_API_KEY / ANTHROPIC_BASE_URL:
@@ -30,5 +31,11 @@ export declare function cleanupWindowsEnvVars(names: readonly string[]): {
30
31
  * 返回被清除的变量名(未检测到时为空数组)。
31
32
  */
32
33
  export declare function cleanupAnthropicEnvVars(): string[];
34
+ /**
35
+ * Whether the last `cleanupAnthropicEnvVars()` edited a shell profile or the Windows
36
+ * environment. False means the variables only came from the parent process (e.g. a
37
+ * coding agent's shell): nothing persistent changed, there is nothing to restart.
38
+ */
39
+ export declare function envCleanupChangedProfile(): boolean;
33
40
  /** Windows 系统级环境变量里删不掉(需要管理员)的名字,来自最近一次 `cleanupAnthropicEnvVars()`。 */
34
41
  export declare function machineEnvVarsLeft(): string[];
@@ -1 +1 @@
1
- import{existsSync as e,readFileSync as n,writeFileSync as r}from"fs";import{join as o}from"path";import{logger as t}from"../utils/logger.js";import{toolHome as s}from"./tools/types.js";import{broadcastEnvChange as c,deleteWindowsEnv as i,readWindowsEnv as l}from"./windows-env.js";export const ANTHROPIC_ENV_VARS=["ANTHROPIC_API_KEY","ANTHROPIC_BASE_URL","ANTHROPIC_DEFAULT_HAIKU_MODEL","ANTHROPIC_DEFAULT_SONNET_MODEL","ANTHROPIC_DEFAULT_OPUS_MODEL","ANTHROPIC_DEFAULT_FABLE_MODEL","ANTHROPIC_MODEL","ANTHROPIC_REASONING_MODEL"];export function getShellRcFilePath(){if("win32"===process.platform)return null;const e=s();switch((process.env.SHELL||"").split("/").pop()||""){case"bash":return o(e,".bashrc");case"zsh":return o(e,".zshrc");case"fish":return o(e,".config","fish","config.fish");default:return o(e,".profile")}}export function cleanupShellRcEnvVars(){if("win32"===process.platform)return!1;try{const o=getShellRcFilePath();if(!o||!e(o))return!1;let s=n(o,"utf-8");const c=s,i=[...ANTHROPIC_ENV_VARS.map(e=>new RegExp(String.raw`^\s*export\s+${e}=.*$`,"gm")),/^\s*#\s*Claude Code environment variables\s*$/gm];for(const e of i)s=s.replace(e,"");if(s!==c)return r(o,s,"utf-8"),t.info(`Cleaned up ANTHROPIC_* environment variables from ${o}`),!0}catch(e){t.warn("Failed to cleanup shell environment variables:",e),t.logError("envCleanup.cleanupShellRcEnvVars",e)}return!1}export function cleanupWindowsEnvVars(f){const a=[];if("win32"!==process.platform||0===f.length)return{machineLeft:a};const p=[];for(const e of f)for(const n of["user","machine"])if(void 0!==l(n,e))try{i(n,e),p.push(`${n}:${e}`)}catch(r){"machine"===n&&a.push(e),t.logError("envCleanup.cleanupWindowsEnvVars",r)}p.length>0&&(c(),t.info(`Windows env cleanup: ${p.join(" ")}`));for(const c of function(){const e=s(),n=[];for(const r of[o(e,"Documents"),o(e,"OneDrive","Documents"),o(e,"OneDrive","文档")])for(const e of["PowerShell","WindowsPowerShell"])n.push(o(r,e,"Microsoft.PowerShell_profile.ps1"),o(r,e,"profile.ps1"));return n}())try{if(!e(c))continue;const o=n(c,"utf-8");let s=o;for(const e of f)s=s.replace(new RegExp(String.raw`^[ \t]*\$env:${e}[ \t]*=.*(\r?\n)?`,"gim"),"");s!==o&&(r(c,s,"utf-8"),t.info(`Removed ANTHROPIC_* assignments from ${c}`))}catch(e){t.logError("envCleanup.powerShellProfile",e)}return{machineLeft:a}}export function cleanupAnthropicEnvVars(){const e=ANTHROPIC_ENV_VARS.filter(e=>!!process.env[e]);if(0===e.length)return[];cleanupShellRcEnvVars(),f=cleanupWindowsEnvVars(e).machineLeft;for(const n of e)delete process.env[n];return[...e]}let f=[];export function machineEnvVarsLeft(){return f}
1
+ import{existsSync as e,readFileSync as n,writeFileSync as r}from"fs";import{join as o}from"path";import{logger as t}from"../utils/logger.js";import{toolHome as s}from"./tools/types.js";import{broadcastEnvChange as c,deleteWindowsEnv as i,readWindowsEnv as l}from"./windows-env.js";export const ANTHROPIC_ENV_VARS=["ANTHROPIC_API_KEY","ANTHROPIC_BASE_URL","ANTHROPIC_DEFAULT_HAIKU_MODEL","ANTHROPIC_DEFAULT_SONNET_MODEL","ANTHROPIC_DEFAULT_OPUS_MODEL","ANTHROPIC_DEFAULT_FABLE_MODEL","ANTHROPIC_MODEL","ANTHROPIC_REASONING_MODEL"];export function getShellRcFilePath(){if("win32"===process.platform)return null;const e=s();switch((process.env.SHELL||"").split("/").pop()||""){case"bash":return o(e,".bashrc");case"zsh":return o(e,".zshrc");case"fish":return o(e,".config","fish","config.fish");default:return o(e,".profile")}}export function cleanupShellRcEnvVars(){if("win32"===process.platform)return!1;try{const o=getShellRcFilePath();if(!o||!e(o))return!1;let s=n(o,"utf-8");const c=s,i=[...ANTHROPIC_ENV_VARS.map(e=>new RegExp(String.raw`^\s*export\s+${e}=.*$`,"gm")),/^\s*#\s*Claude Code environment variables\s*$/gm];for(const e of i)s=s.replace(e,"");if(s!==c)return r(o,s,"utf-8"),t.info(`Cleaned up ANTHROPIC_* environment variables from ${o}`),!0}catch(e){t.warn("Failed to cleanup shell environment variables:",e),t.logError("envCleanup.cleanupShellRcEnvVars",e)}return!1}export function cleanupWindowsEnvVars(f){const a=[];if("win32"!==process.platform||0===f.length)return{machineLeft:a,changed:!1};let p=!1;const u=[];for(const e of f)for(const n of["user","machine"])if(void 0!==l(n,e))try{i(n,e),u.push(`${n}:${e}`)}catch(r){"machine"===n&&a.push(e),t.logError("envCleanup.cleanupWindowsEnvVars",r)}u.length>0&&(p=!0,c(),t.info(`Windows env cleanup: ${u.join(" ")}`));for(const c of function(){const e=s(),n=[];for(const r of[o(e,"Documents"),o(e,"OneDrive","Documents"),o(e,"OneDrive","文档")])for(const e of["PowerShell","WindowsPowerShell"])n.push(o(r,e,"Microsoft.PowerShell_profile.ps1"),o(r,e,"profile.ps1"));return n}())try{if(!e(c))continue;const o=n(c,"utf-8");let s=o;for(const e of f)s=s.replace(new RegExp(String.raw`^[ \t]*\$env:${e}[ \t]*=.*(\r?\n)?`,"gim"),"");s!==o&&(r(c,s,"utf-8"),p=!0,t.info(`Removed ANTHROPIC_* assignments from ${c}`))}catch(e){t.logError("envCleanup.powerShellProfile",e)}return{machineLeft:a,changed:p}}export function cleanupAnthropicEnvVars(){const e=ANTHROPIC_ENV_VARS.filter(e=>!!process.env[e]);if(0===e.length)return[];const n=cleanupShellRcEnvVars(),r=cleanupWindowsEnvVars(e);f=r.machineLeft,a=n||r.changed;for(const n of e)delete process.env[n];return[...e]}let f=[],a=!1;export function envCleanupChangedProfile(){return a}export function machineEnvVarsLeft(){return f}
@@ -1 +1 @@
1
- import{execFileSync as e}from"child_process";import{createHash as t}from"crypto";import{createReadStream as r,createWriteStream as s,existsSync as i,readdirSync as n,readFileSync as o}from"fs";import{copyFile as a,mkdir as l,readFile as c,rename as u,rm as f,writeFile as p}from"fs/promises";import{isAbsolute as d,join as h,normalize as m,sep as w}from"path";import{Readable as g,Writable as b}from"stream";import{pipeline as y}from"stream/promises";import*as v from"zlib";import{logger as k}from"../../utils/logger.js";import{downloadNativeBinary as D,nativeLayout as $,nativePlatformKey as C}from"./claude-native-mirror.js";import{WINDOWS_PACKAGE_FAMILIES as N}from"./desktop-process.js";import{toolHome as x}from"./types.js";export function readDesktopCliPin(e,t,r=!1){const s=e.indexOf('claude-code-releases","sdkWrapperVersion"');if(s<0)return null;const i=e.lastIndexOf("JSON.parse('",s),n=e.indexOf("')",s);if(i<0||n<0)return null;try{const s=JSON.parse(e.subarray(i+12,n).toString("utf-8")),o="string"==typeof s.version?s.version:"",a=s.manifest?.platforms?.[t],l=r?a?.bundle?.checksum:a?.checksum;return/^\d+\.\d+\.\d+$/.test(o)&&"string"==typeof l&&/^[0-9a-f]{64}$/.test(l)?{version:o,checksum:l}:null}catch{return null}}class A extends b{dest;buffer=Buffer.alloc(0);remaining=0;padding=0;file=null;longName=null;collectingLongName=null;constructor(e){super(),this.dest=e}_write(e,t,r){this.buffer=this.buffer.length?Buffer.concat([this.buffer,e]):e,this.drain().then(()=>r()).catch(r)}_final(e){this.remaining>0?e(new Error("archive ends inside an entry")):e()}target(e){const t=m(e);if(!t||d(t)||".."===t||t.startsWith(`..${w}`))throw new Error(`unsafe path in archive: ${e}`);return h(this.dest,t)}async closeFile(){const e=this.file;this.file=null,e&&await new Promise((t,r)=>e.end(e=>e?r(e):t()))}async drain(){for(;;){if(this.remaining>0){if(0===this.buffer.length)return;const e=this.buffer.subarray(0,Math.min(this.remaining,this.buffer.length));this.buffer=this.buffer.subarray(e.length),this.remaining-=e.length,this.collectingLongName?this.collectingLongName.push(e):this.file&&!this.file.write(e)&&await new Promise(e=>this.file.once("drain",()=>e())),0===this.remaining&&(this.collectingLongName&&(this.longName=Buffer.concat(this.collectingLongName).toString("utf-8").replace(/\0.*$/s,""),this.collectingLongName=null),await this.closeFile());continue}if(this.padding>0){if(this.buffer.length<this.padding)return;this.buffer=this.buffer.subarray(this.padding),this.padding=0}if(this.buffer.length<512)return;const e=this.buffer.subarray(0,512);if(this.buffer=this.buffer.subarray(512),e.every(e=>0===e))continue;const t=(t,r)=>e.subarray(t,t+r).toString("utf-8").replace(/\0.*$/s,""),r=t(345,155);let i=r?`${r}/${t(0,100)}`:t(0,100);null!==this.longName&&(i=this.longName,this.longName=null);const n=parseInt(t(124,12).trim()||"0",8),o=511&parseInt(t(100,8).trim()||"644",8),a=t(156,1)||"0";if(this.remaining=n,this.padding=(512-n%512)%512,"L"===a)this.collectingLongName=[];else if("x"===a||"g"===a);else if("5"===a)await l(this.target(i),{recursive:!0});else{if("0"!==a)throw new Error(`unexpected entry type ${a} in archive: ${i}`);{const e=this.target(i);await l(h(e,".."),{recursive:!0}),this.file=s(e,{mode:o||420}),0===n&&await this.closeFile()}}}}}export async function installDesktopCli(e){const s=readDesktopCliPin(e.asar,e.platformKey,e.bundle);if(!s)return{status:"skipped",reason:"unknown app layout"};if(e.bundle&&!e.download)return{status:"skipped",reason:"no bundle mirror"};const n=e.platformKey.startsWith("win32")?"claude.exe":"claude",o=h(e.userDataDir,"claude-code",s.version),d=h(o,s.checksum.slice(0,12)),m=e.bundle?h(d,"claude.app","Contents","MacOS","claude"):h(d,n),w=h(d,".verified");try{if(i(m)&&(await c(w,"utf-8")).trim()===s.checksum)return{status:"present",version:s.version}}catch{}await l(o,{recursive:!0});const g=h(o,`.partial-${s.checksum.slice(0,12)}`),k=`${g}.download`;try{await f(w,{force:!0}),await f(g,{recursive:!0,force:!0});let n="mirror";if(e.bundle){if(e.onDownload?.(s.version),await e.download(s.version,k),await async function(e,s,i){const n=t("sha256");if(await y(r(e),new b({write(e,t,r){n.update(e),r()}})),n.digest("hex")!==s)throw new Error("downloaded bundle does not match the app's checksum");const o=v.createZstdDecompress;if(!o)throw new Error(`Node ${process.version} cannot decompress zstd (needs 22.15 or newer)`);await y(r(e),o(),new A(i))}(k,s.checksum,g),!i(h(g,"claude.app","Contents","MacOS","claude")))throw new Error("bundle has no claude.app");await f(d,{recursive:!0,force:!0}),await u(g,d)}else{const t=e.localVersionsDir?h(e.localVersionsDir,s.version):null;if(t&&i(t))await a(t,g),n="local";else{e.onDownload?.(s.version);const t=e.download??((t,r)=>D(e.platformKey,t,r));await t(s.version,g)}await l(d,{recursive:!0}),await u(g,m)}return await p(w,s.checksum),{status:"installed",version:s.version,source:n}}finally{await f(g,{recursive:!0,force:!0}),await f(k,{force:!0}),await f(`${g}.download`,{force:!0})}}let L=(...e)=>fetch(...e);export function setDesktopCliFetchForTests(e){L=e}export async function ensureDesktopCli(t){const r=C();if(!r)return{status:"skipped",reason:"unsupported architecture"};if("win32"===process.platform){const s=function(){const t=h(process.env.LOCALAPPDATA||"","AnthropicClaude");if(process.env.LOCALAPPDATA&&i(t)){const e=n(t).filter(e=>/^app-\d+\.\d+\.\d+$/.test(e)).sort((e,t)=>t.localeCompare(e,void 0,{numeric:!0}));for(const r of e){const e=h(t,r,"resources","app.asar");if(i(e))return e}}try{const t=e("powershell.exe",["-NoProfile","-Command",`Get-AppxPackage | Where-Object { @(${N.map(e=>`'${e}'`).join(",")}) -contains $_.PackageFamilyName } | ForEach-Object { $_.InstallLocation }`],{encoding:"utf-8",timeout:15e3,windowsHide:!0,stdio:["ignore","pipe","ignore"]});for(const e of t.split(/\r?\n/).map(e=>e.trim()).filter(Boolean)){const t=h(e,"app","resources","app.asar");if(i(t))return t}}catch(e){k.logError("claude-desktop-cli.windowsAsarPath",e)}return null}();return s?installDesktopCli({userDataDir:t.userDataDir,asar:o(s),platformKey:r,localVersionsDir:$().versionsDir,onDownload:t.onDownload}):{status:"skipped",reason:"app.asar not found"}}if("darwin"===process.platform){const e=function(){for(const e of["/Applications/Claude.app",h(x(),"Applications","Claude.app")]){const t=h(e,"Contents","Resources","app.asar");if(i(t))return t}return null}();if(!e)return{status:"skipped",reason:"app.asar not found"};const{mirrorRepo:n,desktopVersion:a}=t;return installDesktopCli({userDataDir:t.userDataDir,asar:o(e),platformKey:r,bundle:!0,onDownload:t.onDownload,download:n&&a?(e,t)=>async function(e,t){const r=await L(e,{signal:AbortSignal.timeout(9e5)});if(!r.ok||!r.body)throw new Error(`${e}: HTTP ${r.status}`);await y(g.fromWeb(r.body),s(t))}(`${n}/-/releases/download/v${a}/claude-code-${e}-${r}.app.tar.zst`,t):void 0})}return{status:"skipped",reason:"unsupported platform"}}
1
+ import{execFileSync as e}from"child_process";import{createHash as t}from"crypto";import{createReadStream as r,createWriteStream as s,existsSync as o,readdirSync as i,readFileSync as n}from"fs";import{copyFile as a,mkdir as l,readFile as c,rename as u,rm as f,writeFile as p}from"fs/promises";import{isAbsolute as d,join as h,normalize as m,sep as w}from"path";import{Readable as g,Writable as b}from"stream";import{pipeline as D}from"stream/promises";import*as y from"zlib";import{logger as v}from"../../utils/logger.js";import{brandEnv as k}from"../brand.js";import{downloadNativeBinary as $,nativeLayout as C,nativePlatformKey as N}from"./claude-native-mirror.js";import{WINDOWS_PACKAGE_FAMILIES as x}from"./desktop-process.js";import{toolHome as A}from"./types.js";export function readDesktopCliPin(e,t,r=!1){const s=e.indexOf('claude-code-releases","sdkWrapperVersion"');if(s<0)return null;const o=e.lastIndexOf("JSON.parse('",s),i=e.indexOf("')",s);if(o<0||i<0)return null;try{const s=JSON.parse(e.subarray(o+12,i).toString("utf-8")),n="string"==typeof s.version?s.version:"",a=s.manifest?.platforms?.[t],l=r?a?.bundle?.checksum:a?.checksum;return/^\d+\.\d+\.\d+$/.test(n)&&"string"==typeof l&&/^[0-9a-f]{64}$/.test(l)?{version:n,checksum:l}:null}catch{return null}}class L extends b{dest;buffer=Buffer.alloc(0);remaining=0;padding=0;file=null;longName=null;collectingLongName=null;constructor(e){super(),this.dest=e}_write(e,t,r){this.buffer=this.buffer.length?Buffer.concat([this.buffer,e]):e,this.drain().then(()=>r()).catch(r)}_final(e){this.remaining>0?e(new Error("archive ends inside an entry")):e()}target(e){const t=m(e);if(!t||d(t)||".."===t||t.startsWith(`..${w}`))throw new Error(`unsafe path in archive: ${e}`);return h(this.dest,t)}async closeFile(){const e=this.file;this.file=null,e&&await new Promise((t,r)=>e.end(e=>e?r(e):t()))}async drain(){for(;;){if(this.remaining>0){if(0===this.buffer.length)return;const e=this.buffer.subarray(0,Math.min(this.remaining,this.buffer.length));this.buffer=this.buffer.subarray(e.length),this.remaining-=e.length,this.collectingLongName?this.collectingLongName.push(e):this.file&&!this.file.write(e)&&await new Promise(e=>this.file.once("drain",()=>e())),0===this.remaining&&(this.collectingLongName&&(this.longName=Buffer.concat(this.collectingLongName).toString("utf-8").replace(/\0.*$/s,""),this.collectingLongName=null),await this.closeFile());continue}if(this.padding>0){if(this.buffer.length<this.padding)return;this.buffer=this.buffer.subarray(this.padding),this.padding=0}if(this.buffer.length<512)return;const e=this.buffer.subarray(0,512);if(this.buffer=this.buffer.subarray(512),e.every(e=>0===e))continue;const t=(t,r)=>e.subarray(t,t+r).toString("utf-8").replace(/\0.*$/s,""),r=t(345,155);let o=r?`${r}/${t(0,100)}`:t(0,100);null!==this.longName&&(o=this.longName,this.longName=null);const i=parseInt(t(124,12).trim()||"0",8),n=511&parseInt(t(100,8).trim()||"644",8),a=t(156,1)||"0";if(this.remaining=i,this.padding=(512-i%512)%512,"L"===a)this.collectingLongName=[];else if("x"===a||"g"===a);else if("5"===a)await l(this.target(o),{recursive:!0});else{if("0"!==a)throw new Error(`unexpected entry type ${a} in archive: ${o}`);{const e=this.target(o);await l(h(e,".."),{recursive:!0}),this.file=s(e,{mode:n||420}),0===i&&await this.closeFile()}}}}}export async function installDesktopCli(e){const s=readDesktopCliPin(e.asar,e.platformKey,e.bundle);if(!s)return{status:"skipped",reason:"unknown app layout"};if(e.bundle&&!e.download)return{status:"skipped",reason:"no bundle mirror"};const i=e.platformKey.startsWith("win32")?"claude.exe":"claude",n=h(e.userDataDir,"claude-code",s.version),d=h(n,s.checksum.slice(0,12)),m=e.bundle?h(d,"claude.app","Contents","MacOS","claude"):h(d,i),w=h(d,".verified");try{if(o(m)&&(await c(w,"utf-8")).trim()===s.checksum)return{status:"present",version:s.version}}catch{}await l(n,{recursive:!0});const g=h(n,`.partial-${s.checksum.slice(0,12)}`),v=`${g}.download`;try{await f(w,{force:!0}),await f(g,{recursive:!0,force:!0});let i="mirror";if(e.bundle){if(e.onDownload?.(s.version),await e.download(s.version,v),await async function(e,s,o){const i=t("sha256");if(await D(r(e),new b({write(e,t,r){i.update(e),r()}})),i.digest("hex")!==s)throw new Error("downloaded bundle does not match the app's checksum");const n=y.createZstdDecompress;if(!n)throw new Error(`Node ${process.version} cannot decompress zstd (needs 22.15 or newer)`);await D(r(e),n(),new L(o))}(v,s.checksum,g),!o(h(g,"claude.app","Contents","MacOS","claude")))throw new Error("bundle has no claude.app");await f(d,{recursive:!0,force:!0}),await u(g,d)}else{const t=e.localVersionsDir?h(e.localVersionsDir,s.version):null;if(t&&o(t))await a(t,g),i="local";else{e.onDownload?.(s.version);const t=e.download??((t,r)=>$(e.platformKey,t,r));await t(s.version,g)}await l(d,{recursive:!0}),await u(g,m)}return await p(w,s.checksum),{status:"installed",version:s.version,source:i}}finally{await f(g,{recursive:!0,force:!0}),await f(v,{force:!0}),await f(`${g}.download`,{force:!0})}}let P=(...e)=>fetch(...e);export function setDesktopCliFetchForTests(e){P=e}export async function ensureDesktopCli(t){const r=N();if(!r)return{status:"skipped",reason:"unsupported architecture"};if("win32"===process.platform){const s=function(){const t=h(process.env.LOCALAPPDATA||"","AnthropicClaude");if(process.env.LOCALAPPDATA&&o(t)){const e=i(t).filter(e=>/^app-\d+\.\d+\.\d+$/.test(e)).sort((e,t)=>t.localeCompare(e,void 0,{numeric:!0}));for(const r of e){const e=h(t,r,"resources","app.asar");if(o(e))return e}}try{const t=e("powershell.exe",["-NoProfile","-Command",`Get-AppxPackage | Where-Object { @(${x.map(e=>`'${e}'`).join(",")}) -contains $_.PackageFamilyName } | ForEach-Object { $_.InstallLocation }`],{encoding:"utf-8",timeout:15e3,windowsHide:!0,stdio:["ignore","pipe","ignore"]});for(const e of t.split(/\r?\n/).map(e=>e.trim()).filter(Boolean)){const t=h(e,"app","resources","app.asar");if(o(t))return t}}catch(e){v.logError("claude-desktop-cli.windowsAsarPath",e)}return null}();return s?installDesktopCli({userDataDir:t.userDataDir,asar:n(s),platformKey:r,localVersionsDir:C().versionsDir,onDownload:t.onDownload}):{status:"skipped",reason:"app.asar not found"}}if("darwin"===process.platform){const e=function(){for(const e of["/Applications/Claude.app",h(A(),"Applications","Claude.app")]){const t=h(e,"Contents","Resources","app.asar");if(o(t))return t}return null}();if(!e)return{status:"skipped",reason:"app.asar not found"};const{mirrorRepo:i,desktopVersion:a}=t;return installDesktopCli({userDataDir:t.userDataDir,asar:n(e),platformKey:r,bundle:!0,onDownload:t.onDownload,download:i&&a?(e,t)=>async function(e,t){const r=await P(e,{signal:AbortSignal.timeout(9e5)});if(!r.ok||!r.body)throw new Error(`${e}: HTTP ${r.status}`);await D(g.fromWeb(r.body),s(t))}(`${i}/-/releases/download/v${a}/claude-code-${e}-${r}.app.tar.zst`,t):void 0})}if("linux"===process.platform){const e=function(){if(k("TEST_HOME")?.trim())return null;for(const e of["/usr/lib/claude-desktop","/opt/Claude"]){const t=h(e,"resources","app.asar");if(o(t))return t}return null}();return e?installDesktopCli({userDataDir:t.userDataDir,asar:n(e),platformKey:r.replace(/-musl$/,""),localVersionsDir:r.endsWith("-musl")?void 0:C().versionsDir,onDownload:t.onDownload}):{status:"skipped",reason:"app.asar not found"}}return{status:"skipped",reason:"unsupported platform"}}
@@ -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 a}from"path";import{randomUUID as l}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}from"./claude-desktop-cli.js";import{i18n as g}from"../i18n.js";import{BRAND_NAME as y,brand as h,brandEnv as k,CLI_NAME as _}from"../brand.js";import{backupBeforeWrite as b,atomicWriteFile as D}from"./backup.js";import{toolHome as A}from"./types.js";import{canRestartDesktop as C,isDesktopRunning as w,restartDesktop as E,WINDOWS_PACKAGE_FAMILIES as M}from"./desktop-process.js";import{setUserRegistryElevated as v}from"./elevated-reg.js";import{UserActionNeeded as O}from"./types.js";import{baseModelId as S,isClaudeModel as x}from"../model-catalog.js";import{getDefaultModels as P}from"../model-registry.js";const j=y;export const CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING="hide_official_login";export const CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING="force_registry";const L=/^[a-f0-9-]{36}$/;function I(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(k("TEST_HOME")?.trim());switch(process.platform){case"darwin":return a(o,"Library","Application Support","Claude-3p");case"win32":{const e=!n&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:a(o,"AppData","Local");return M.map(t=>a(e,"Packages",t,"LocalCache","Local","Claude-3p")).find(e=>t(e))??a(e,"Claude-3p")}default:{const e=!n&&process.env.XDG_CONFIG_HOME?process.env.XDG_CONFIG_HOME:a(o,".config");return a(e,"Claude-3p")}}}const T=()=>a(claudeDesktopUserDataDir(),"configLibrary"),$=()=>a(T(),"_meta.json"),R=e=>a(T(),`${e}.json`),G=()=>a(claudeDesktopUserDataDir(),"claude_desktop_config.json");function N(e){if(!t(e))return null;const o=r(e,"utf-8");if(!o.trim())return null;try{const e=JSON.parse(o);return I(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 U(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){u.logError("claude-desktop.writeJson.chmod",e)}}function K(){const e=N($());if(!e)return null;const t=Array.isArray(e.entries)?e.entries.filter(e=>I(e)&&"string"==typeof e.id&&"string"==typeof e.name):[];return{...e,appliedId:"string"==typeof e.appliedId?e.appliedId:"",entries:t}}function F(e){return e?.entries.find(e=>e.name===j&&L.test(e.id))}const H={opus:0,fable:1,sonnet:2,haiku:3};function B(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=B(e);return t?`${t.family[0].toUpperCase()+t.family.slice(1)} ${t.version.filter(e=>e<1e7).slice(0,2).join(".")}`:e}function J(e){return B(e)?.family}export function buildInferenceModels(e,t){const{primary:o,bySlot:n}=function(e){const t=["opus","sonnet","haiku","reasoning"].map(t=>S(e[t]||"")).filter(Boolean);return{primary:t[0]??"",bySlot:t}}(e),r=new Set,s=t?.labels??{};let i;if(t&&t.models.some(x)){i=[...new Set(t.models.filter(x).map(S))];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=S(o);n&&(i.includes(n)||i.push(n),/\[1m\]/i.test(o)&&r.add(n))}}const a=e=>H[J(e)??""]??9;i.sort((e,t)=>{if(e===o)return-1;if(t===o)return 1;const n=a(e)-a(t);if(0!==n)return n;const r=B(e),s=B(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 l=new Set,c=new Map,d=new Set(Object.values(P()).map(e=>S(e||"")));for(const e of n){const t=J(e);t&&i.includes(e)&&!d.has(e)&&!c.has(t)&&c.set(t,e)}return i.map(e=>{const t=J(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||l.has(t)||(o.isFamilyDefault=!0,l.add(t))}return o})}let V=null,W=null,z=null,Z=null;function X(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 q={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}};function Y(e){return Object.fromEntries(Object.entries(q).filter(([t])=>!e(t)))}const Q="SOFTWARE\\Policies\\Claude",ee=`HKCU\\${Q}`,te="HKLM\\SOFTWARE\\Policies\\Claude",oe=`${_}-claude-policy.reg`,ne=e=>c("reg",e,{stdio:["ignore","pipe","pipe"]}).toString();let re=ne;export function setRegRunnerForTests(e){re=e??ne}function se(){return"win32"===process.platform}function ie(e){let t;try{t=re(["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 ae(){if(null===ie(ee))return;const e=a(claudeDesktopUserDataDir(),oe);try{t(i(e))||o(i(e),{recursive:!0,mode:448}),b(e),re(["export",ee,e,"/y"])}catch(e){u.logError("claude-desktop.snapshotPolicy",e)}}function le(e){ae();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)];re(["add",ee,"/v",t,"/t",e,"/d",n,"/f"])}}function ce(e){const t=ie(ee);if(!t)return;ae();let o=t.size;for(const n of e)t.has(n)&&(re(["delete",ee,"/v",n,"/f"]),o-=1);o<=0&&re(["delete",ee,"/f"])}const de=[...Object.keys(X({apiKey:"",baseUrl:"",models:{haiku:"",sonnet:"",opus:"",reasoning:""}})),...Object.keys(q)];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 ie(te)?te: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 pe(){const e=A();let o;switch(process.platform){case"darwin":o=["/Applications/Claude.app",a(e,"Applications","Claude.app")];break;case"win32":{const t=process.env.LOCALAPPDATA||a(e,"AppData","Local");o=[a(t,"AnthropicClaude"),a(t,"Programs","Claude"),...M.map(e=>a(t,"Packages",e))];break}default:o=["/usr/lib/claude-desktop","/opt/Claude","/usr/bin/claude-desktop",a(e,".local","bin","claude-desktop")]}return o.push(claudeDesktopUserDataDir(),a(claudeDesktopUserDataDir(),"..","Claude")),o.some(e=>t(e))}const ue=/\d+\.\d+\.\d+/;function fe(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 me(){if("darwin"===process.platform){for(const e of["/Applications/Claude.app",a(A(),"Applications","Claude.app")]){const o=a(e,"Contents","Info.plist");if(!t(o))continue;const n=/<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/.exec(r(o,"utf-8")),s=n?ue.exec(n[1])?.[0]:void 0;if(s)return s}return null}if("win32"===process.platform){const e=a(process.env.LOCALAPPDATA||a(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 fe(t)}const o=M.map(e=>`'${e}'`).join(",");return fe(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"]}).split(/\r?\n/).flatMap(e=>ue.exec(e)?.[0]??[]))}return null}const ge="darwin"===process.platform?"open -a Claude":"win32"===process.platform?"Claude":"claude-desktop",ye="darwin"!==process.platform&&"win32"!==process.platform||!h().installMirror?.claudeDesktop?"https://claude.ai/download":h().installMirror.claudeDesktop,he="darwin"===process.platform?`open ${ye}`:"win32"===process.platform?`start ${ye}`:`xdg-open ${ye}`;export const claudeDesktopAdapter={name:"claude-desktop",displayName:"Claude Desktop",command:ge,installCommand:he,configPath:$(),isInstalled:pe,installedVersion:me,prepareRuntime:async function(){if("win32"!==process.platform&&"darwin"!==process.platform||!pe())return[];const e=Date.now();try{const t=await m({userDataDir:claudeDesktopUserDataDir(),onDownload:e=>console.log(p.gray(" "+g.t("tools.claude_desktop.code_cli_downloading",{version:e}))),desktopVersion:"darwin"===process.platform?me():null,mirrorRepo:h().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:g.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:g.t("tools.claude_desktop.code_cli_failed",{reason:t instanceof Error?t.message:String(t)})}]}},runningApp:C()?{isRunning:w,restart:E}:void 0,wantsModelCatalog:!0,loadPrivateConfig(e){const o=K()??{appliedId:"",entries:[]};let n=F(o);n||(n={id:l(),name:j},o.entries.push(n));const r=X(e);W=!0===r.disableDeploymentModeChooser,V={models:r.inferenceModels,source:e.catalog?e.catalog.oneMillionSource:"slots",groups:e.catalog?.matchedGroups??[]};const s=N(R(n.id))??{};U(R(n.id),{...Y(e=>e in s),...s,...r}),o.appliedId=n.id,U($(),o);const i=N(G())??{};if("3p"!==i.deploymentMode&&U(G(),{...i,deploymentMode:"3p"}),z=null,Z=null,se()){const o=ie(ee),n=de.filter(e=>o?.has(e)),s={...Y(e=>o?.has(e)??!1),...r},i=!0===e.settings?.force_registry,l=!i&&function(){const e=!Boolean(k("TEST_HOME")?.trim())&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:a(A(),"AppData","Local");return!!t(a(e,"AnthropicClaude"))||M.some(o=>t(a(e,"Packages",o,"LocalCache","Local","Claude-3p")))}();try{l?ce(de):le(s)}catch(e){u.logError("claude-desktop.policy",e),z=e instanceof Error?e.message.trim():String(e),(n.length>0||i)&&(Z=l?{action:"remove",values:Object.fromEntries(n.map(e=>[e,null])),deleteKey:n.length===o.size}:{action:"write",values:s,deleteKey:!1})}}},pendingElevation(){const e=Z;return e?{prompt:g.t(`tools.claude_desktop.elevate_${e.action}`),run:()=>{if(!v(Q,e.values,e.deleteKey))return!1;const t=ie(ee),o="remove"===e.action?Object.keys(e.values).every(e=>!t?.has(e)):Object.keys(e.values).every(e=>t?.has(e));return o&&(Z=null,z=null),o}}:null},unloadPrivateConfig(){if(se())try{ce(de)}catch(e){u.logError("claude-desktop.removePolicy",e)}const e=K(),t=F(e);if(!e||!t)return;b(R(t.id)),s(R(t.id),{force:!0});const o=e.entries.filter(e=>e.id!==t.id);0===o.length?(b($()),s($(),{force:!0})):U($(),{...e,entries:o,appliedId:e.appliedId===t.id?o[0].id:e.appliedId})},listedModels(){const e=K(),t=F(e);if(!t||e?.appliedId!==t.id)return null;const o=N(R(t.id))?.inferenceModels;return Array.isArray(o)?o.map(e=>String(e.name)):null},refreshModelMenu(e){const t=K(),o=F(t);if(!o||t?.appliedId!==o.id)return;const n=N(R(o.id));if(!n)return;const r=buildInferenceModels(e.models,e.catalog);if(JSON.stringify(n.inferenceModels)!==JSON.stringify(r)){if(se()&&ie(ee)?.has("inferenceModels"))try{le({inferenceModels:r})}catch(e){throw u.logError("claude-desktop.refreshModelMenu registry",e),new O(g.t("tools.claude_desktop.refresh_needs_admin"))}U(R(o.id),{...n,inferenceModels:r})}},detectCurrentConfig(){try{if(se()){const e=ie(ee)?.get("inferenceGatewayApiKey");if(e)return{apiKey:e}}const e=F(K());if(!e)return{apiKey:null};const t=N(R(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=K(),t=F(e);return{meta:e,applied:t?N(R(t.id)):null,desktop:N(G()),...se()?{policy:Object.fromEntries(ie(ee)??[])}:{}}}catch(e){return u.logError("claude-desktop.getConfig",e),null}},clearPinnedModels(){let e=!1;se()&&ie(ee)?.has("inferenceModels")&&(ae(),re(["delete",ee,"/v","inferenceModels","/f"]),e=!0);const t=F(K()),o=t?N(R(t.id)):null;if(t&&o&&void 0!==o.inferenceModels){const{inferenceModels:n,...r}=o;U(R(t.id),r),e=!0}return e?["inferenceModels"]:[]},applyNotes(){const e=[];if(V&&V.models.length>0){const{models:t,source:o,groups:n}=V;e.push({kind:"summary",text:g.t("tools.claude_desktop.models_summary",{count:String(t.length),default:t[0].labelOverride??t[0].name})}),e.push({kind:"detail",text:g.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!==W&&e.push({kind:"detail",text:g.t(W?"tools.claude_desktop.official_login_hidden":"tools.claude_desktop.official_login_shown")}),C()&&!w()||e.push({kind:"action",text:g.t("tools.claude_desktop.restart_hint")}),Z?(e.push({kind:"action",text:g.t(`tools.claude_desktop.policy_stale_${Z.action}`)}),e.push({kind:"detail",text:z??""})):z?(e.push({kind:"detail",text:g.t("tools.claude_desktop.registry_denied")}),e.push({kind:"detail",text:z})):se()&&e.push({kind:"detail",text:g.t("tools.claude_desktop.registry_written",{key:ee})});const t=detectManagedConfig();return t&&e.push({kind:"action",text:g.t("tools.claude_desktop.managed_conflict",{path:t})}),e},forceResetPaths(){const e=[$(),G()];try{const t=F(K());t&&e.push(R(t.id))}catch{}return e},backupPaths(){const e=[$(),G()];se()&&e.push(a(claudeDesktopUserDataDir(),oe));try{const t=F(K());t&&e.push(R(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 a}from"path";import{randomUUID as l}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}from"./claude-desktop-cli.js";import{i18n as g}from"../i18n.js";import{BRAND_NAME as y,brand as h,brandEnv as k,CLI_NAME as _}from"../brand.js";import{backupBeforeWrite as b,atomicWriteFile as D}from"./backup.js";import{toolHome as A}from"./types.js";import{canRestartDesktop as C,isDesktopRunning as w,restartDesktop as E,WINDOWS_PACKAGE_FAMILIES as M}from"./desktop-process.js";import{setUserRegistryElevated as v}from"./elevated-reg.js";import{UserActionNeeded as O}from"./types.js";import{baseModelId as x,isClaudeModel as S}from"../model-catalog.js";import{getDefaultModels as P}from"../model-registry.js";const j=y;export const CLAUDE_DESKTOP_HIDE_OFFICIAL_LOGIN_SETTING="hide_official_login";export const CLAUDE_DESKTOP_FORCE_REGISTRY_SETTING="force_registry";const L=/^[a-f0-9-]{36}$/;function I(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(k("TEST_HOME")?.trim());switch(process.platform){case"darwin":return a(o,"Library","Application Support","Claude-3p");case"win32":{const e=!n&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:a(o,"AppData","Local");return M.map(t=>a(e,"Packages",t,"LocalCache","Local","Claude-3p")).find(e=>t(e))??a(e,"Claude-3p")}default:{const e=!n&&process.env.XDG_CONFIG_HOME?process.env.XDG_CONFIG_HOME:a(o,".config");return a(e,"Claude-3p")}}}const T=()=>a(claudeDesktopUserDataDir(),"configLibrary"),$=()=>a(T(),"_meta.json"),R=e=>a(T(),`${e}.json`),G=()=>a(claudeDesktopUserDataDir(),"claude_desktop_config.json");function N(e){if(!t(e))return null;const o=r(e,"utf-8");if(!o.trim())return null;try{const e=JSON.parse(o);return I(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 U(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){u.logError("claude-desktop.writeJson.chmod",e)}}function K(){const e=N($());if(!e)return null;const t=Array.isArray(e.entries)?e.entries.filter(e=>I(e)&&"string"==typeof e.id&&"string"==typeof e.name):[];return{...e,appliedId:"string"==typeof e.appliedId?e.appliedId:"",entries:t}}function F(e){return e?.entries.find(e=>e.name===j&&L.test(e.id))}const H={opus:0,fable:1,sonnet:2,haiku:3};function B(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=B(e);return t?`${t.family[0].toUpperCase()+t.family.slice(1)} ${t.version.filter(e=>e<1e7).slice(0,2).join(".")}`:e}function V(e){return B(e)?.family}export function buildInferenceModels(e,t){const{primary:o,bySlot:n}=function(e){const t=["opus","sonnet","haiku","reasoning"].map(t=>x(e[t]||"")).filter(Boolean);return{primary:t[0]??"",bySlot:t}}(e),r=new Set,s=t?.labels??{};let i;if(t&&t.models.some(S)){i=[...new Set(t.models.filter(S).map(x))];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=x(o);n&&(i.includes(n)||i.push(n),/\[1m\]/i.test(o)&&r.add(n))}}const a=e=>H[V(e)??""]??9;i.sort((e,t)=>{if(e===o)return-1;if(t===o)return 1;const n=a(e)-a(t);if(0!==n)return n;const r=B(e),s=B(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 l=new Set,c=new Map,d=new Set(Object.values(P()).map(e=>x(e||"")));for(const e of n){const t=V(e);t&&i.includes(e)&&!d.has(e)&&!c.has(t)&&c.set(t,e)}return i.map(e=>{const t=V(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||l.has(t)||(o.isFamilyDefault=!0,l.add(t))}return o})}let W=null,J=null,z=null,Z=null;function q(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 X={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}};function Y(e){return Object.fromEntries(Object.entries(X).filter(([t])=>!e(t)))}const Q="SOFTWARE\\Policies\\Claude",ee=`HKCU\\${Q}`,te="HKLM\\SOFTWARE\\Policies\\Claude",oe=`${_}-claude-policy.reg`,ne=e=>c("reg",e,{stdio:["ignore","pipe","pipe"]}).toString();let re=ne;export function setRegRunnerForTests(e){re=e??ne}function se(){return"win32"===process.platform}function ie(e){let t;try{t=re(["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 ae(){if(null===ie(ee))return;const e=a(claudeDesktopUserDataDir(),oe);try{t(i(e))||o(i(e),{recursive:!0,mode:448}),b(e),re(["export",ee,e,"/y"])}catch(e){u.logError("claude-desktop.snapshotPolicy",e)}}function le(e){ae();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)];re(["add",ee,"/v",t,"/t",e,"/d",n,"/f"])}}function ce(e){const t=ie(ee);if(!t)return;ae();let o=t.size;for(const n of e)t.has(n)&&(re(["delete",ee,"/v",n,"/f"]),o-=1);o<=0&&re(["delete",ee,"/f"])}const de=[...Object.keys(q({apiKey:"",baseUrl:"",models:{haiku:"",sonnet:"",opus:"",reasoning:""}})),...Object.keys(X)];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 ie(te)?te: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 pe(){const e=A();let o;switch(process.platform){case"darwin":o=["/Applications/Claude.app",a(e,"Applications","Claude.app")];break;case"win32":{const t=process.env.LOCALAPPDATA||a(e,"AppData","Local");o=[a(t,"AnthropicClaude"),a(t,"Programs","Claude"),...M.map(e=>a(t,"Packages",e))];break}default:o=["/usr/lib/claude-desktop","/opt/Claude","/usr/bin/claude-desktop",a(e,".local","bin","claude-desktop")]}return o.push(claudeDesktopUserDataDir(),a(claudeDesktopUserDataDir(),"..","Claude")),o.some(e=>t(e))}const ue=/\d+\.\d+\.\d+/;function fe(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 me(){if("darwin"===process.platform){for(const e of["/Applications/Claude.app",a(A(),"Applications","Claude.app")]){const o=a(e,"Contents","Info.plist");if(!t(o))continue;const n=/<key>CFBundleShortVersionString<\/key>\s*<string>([^<]+)<\/string>/.exec(r(o,"utf-8")),s=n?ue.exec(n[1])?.[0]:void 0;if(s)return s}return null}if("win32"===process.platform){const e=a(process.env.LOCALAPPDATA||a(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 fe(t)}const o=M.map(e=>`'${e}'`).join(",");return fe(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"]}).split(/\r?\n/).flatMap(e=>ue.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 ue.exec(e)?.[0]??null}catch{return null}return null}const ge="darwin"===process.platform?"open -a Claude":"win32"===process.platform?"Claude":"claude-desktop",ye="darwin"!==process.platform&&"win32"!==process.platform||!h().installMirror?.claudeDesktop?"https://claude.ai/download":h().installMirror.claudeDesktop,he="darwin"===process.platform?`open ${ye}`:"win32"===process.platform?`start ${ye}`:`xdg-open ${ye}`;export const claudeDesktopAdapter={name:"claude-desktop",displayName:"Claude Desktop",command:ge,installCommand:he,configPath:$(),isInstalled:pe,installedVersion:me,prepareRuntime:async function(){if(!["win32","darwin","linux"].includes(process.platform)||!pe())return[];const e=Date.now();try{const t=await m({userDataDir:claudeDesktopUserDataDir(),onDownload:e=>console.log(p.gray(" "+g.t("tools.claude_desktop.code_cli_downloading",{version:e}))),desktopVersion:"darwin"===process.platform?me():null,mirrorRepo:h().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:g.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:g.t("tools.claude_desktop.code_cli_failed",{reason:t instanceof Error?t.message:String(t)})}]}},runningApp:C()?{isRunning:w,restart:E}:void 0,wantsModelCatalog:!0,loadPrivateConfig(e){const o=K()??{appliedId:"",entries:[]};let n=F(o);n||(n={id:l(),name:j},o.entries.push(n));const r=q(e);J=!0===r.disableDeploymentModeChooser,W={models:r.inferenceModels,source:e.catalog?e.catalog.oneMillionSource:"slots",groups:e.catalog?.matchedGroups??[]};const s=N(R(n.id))??{};U(R(n.id),{...Y(e=>e in s),...s,...r}),o.appliedId=n.id,U($(),o);const i=N(G())??{};if("3p"!==i.deploymentMode&&U(G(),{...i,deploymentMode:"3p"}),z=null,Z=null,se()){const o=ie(ee),n=de.filter(e=>o?.has(e)),s={...Y(e=>o?.has(e)??!1),...r},i=!0===e.settings?.force_registry,l=!i&&function(){const e=!Boolean(k("TEST_HOME")?.trim())&&process.env.LOCALAPPDATA?process.env.LOCALAPPDATA:a(A(),"AppData","Local");return!!t(a(e,"AnthropicClaude"))||M.some(o=>t(a(e,"Packages",o,"LocalCache","Local","Claude-3p")))}();try{l?ce(de):le(s)}catch(e){u.logError("claude-desktop.policy",e),z=e instanceof Error?e.message.trim():String(e),(n.length>0||i)&&(Z=l?{action:"remove",values:Object.fromEntries(n.map(e=>[e,null])),deleteKey:n.length===o.size}:{action:"write",values:s,deleteKey:!1})}}},pendingElevation(){const e=Z;return e?{prompt:g.t(`tools.claude_desktop.elevate_${e.action}`),run:()=>{if(!v(Q,e.values,e.deleteKey))return!1;const t=ie(ee),o="remove"===e.action?Object.keys(e.values).every(e=>!t?.has(e)):Object.keys(e.values).every(e=>t?.has(e));return o&&(Z=null,z=null),o}}:null},unloadPrivateConfig(){if(se())try{ce(de)}catch(e){u.logError("claude-desktop.removePolicy",e)}const e=K(),t=F(e);if(!e||!t)return;b(R(t.id)),s(R(t.id),{force:!0});const o=e.entries.filter(e=>e.id!==t.id);0===o.length?(b($()),s($(),{force:!0})):U($(),{...e,entries:o,appliedId:e.appliedId===t.id?o[0].id:e.appliedId})},listedModels(){const e=K(),t=F(e);if(!t||e?.appliedId!==t.id)return null;const o=N(R(t.id))?.inferenceModels;return Array.isArray(o)?o.map(e=>String(e.name)):null},refreshModelMenu(e){const t=K(),o=F(t);if(!o||t?.appliedId!==o.id)return;const n=N(R(o.id));if(!n)return;const r=buildInferenceModels(e.models,e.catalog);if(JSON.stringify(n.inferenceModels)!==JSON.stringify(r)){if(se()&&ie(ee)?.has("inferenceModels"))try{le({inferenceModels:r})}catch(e){throw u.logError("claude-desktop.refreshModelMenu registry",e),new O(g.t("tools.claude_desktop.refresh_needs_admin"))}U(R(o.id),{...n,inferenceModels:r})}},detectCurrentConfig(){try{if(se()){const e=ie(ee)?.get("inferenceGatewayApiKey");if(e)return{apiKey:e}}const e=F(K());if(!e)return{apiKey:null};const t=N(R(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=K(),t=F(e);return{meta:e,applied:t?N(R(t.id)):null,desktop:N(G()),...se()?{policy:Object.fromEntries(ie(ee)??[])}:{}}}catch(e){return u.logError("claude-desktop.getConfig",e),null}},clearPinnedModels(){let e=!1;se()&&ie(ee)?.has("inferenceModels")&&(ae(),re(["delete",ee,"/v","inferenceModels","/f"]),e=!0);const t=F(K()),o=t?N(R(t.id)):null;if(t&&o&&void 0!==o.inferenceModels){const{inferenceModels:n,...r}=o;U(R(t.id),r),e=!0}return e?["inferenceModels"]:[]},applyNotes(){const e=[];if(W&&W.models.length>0){const{models:t,source:o,groups:n}=W;e.push({kind:"summary",text:g.t("tools.claude_desktop.models_summary",{count:String(t.length),default:t[0].labelOverride??t[0].name})}),e.push({kind:"detail",text:g.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!==J&&e.push({kind:"detail",text:g.t(J?"tools.claude_desktop.official_login_hidden":"tools.claude_desktop.official_login_shown")}),C()&&!w()||e.push({kind:"action",text:g.t("tools.claude_desktop.restart_hint")}),Z?(e.push({kind:"action",text:g.t(`tools.claude_desktop.policy_stale_${Z.action}`)}),e.push({kind:"detail",text:z??""})):z?(e.push({kind:"detail",text:g.t("tools.claude_desktop.registry_denied")}),e.push({kind:"detail",text:z})):se()&&e.push({kind:"detail",text:g.t("tools.claude_desktop.registry_written",{key:ee})});const t=detectManagedConfig();return t&&e.push({kind:"action",text:g.t("tools.claude_desktop.managed_conflict",{path:t})}),e},forceResetPaths(){const e=[$(),G()];try{const t=F(K());t&&e.push(R(t.id))}catch{}return e},backupPaths(){const e=[$(),G()];se()&&e.push(a(claudeDesktopUserDataDir(),oe));try{const t=F(K());t&&e.push(R(t.id))}catch{}return e}};
@@ -245,6 +245,7 @@
245
245
  "first_run": "First run detected, starting initialization wizard...",
246
246
  "config_saved": "Configuration saved",
247
247
  "env_vars_cleared": "Detected {{vars}} in your shell environment and removed them (they would override the config {{product}} writes). Restart your terminal to apply the shell profile change.",
248
+ "env_vars_ignored": "Detected {{vars}} in the environment and ignored them for this run (they would override the config {{product}} writes). They are not in your shell profile; they likely come from the program that started {{product}}, and tools run from it are still affected.",
248
249
  "certificate_intercepted": "The certificate presented for {{url}} is not the gateway's: the local network is most likely hijacking DNS (common on campus / hotel networks), not a key problem. Switch networks, set the computer's DNS to a public resolver, or use a proxy, then retry",
249
250
  "env_vars_machine_left": "System environment variables still define {{vars}}; removing them needs admin rights: run {{cli}} again from an elevated terminal, or delete them under System Properties → Environment Variables → System variables"
250
251
  },
@@ -268,6 +269,16 @@
268
269
  "backup_restored": "Backup restored: {{name}}",
269
270
  "backup_restore_missing_name": "Specify a backup name: {{cli}} config backup restore <name> (see names with {{cli}} config backup list)",
270
271
  "profile_delete_confirm": "Delete profile {{name}}? This removes its stored API keys.",
272
+ "profile_create_dry_run": "Would create profile {{name}}",
273
+ "profile_use_dry_run": "Would switch to profile {{name}}",
274
+ "preset_save_dry_run": "Would save the current models as preset {{name}}",
275
+ "preset_use_dry_run": "Would apply preset {{name}}",
276
+ "preset_delete_dry_run": "Would delete preset {{name}}",
277
+ "tool_model_set_dry_run": "Would set {{tool}}'s {{slot}} model to {{model}}",
278
+ "tool_model_clear_dry_run": "Would clear {{tool}}'s model overrides",
279
+ "backup_create_dry_run": "Would create a config backup",
280
+ "tool_restore_dry_run": "Would restore {{tool}}'s config from the latest backup",
281
+ "tool_apply_dry_run": "Would rewrite {{tool}}'s config",
271
282
  "profile_delete_dry_run": "Would delete profile {{name}}",
272
283
  "profile_delete_aborted": "Profile deletion cancelled",
273
284
  "backup_restore_confirm": "Restore backup {{name}}? Current config and api_key will be overwritten.",
@@ -338,10 +349,15 @@
338
349
  },
339
350
  "runtime": {
340
351
  "dry_run_label": "[dry-run]",
352
+ "dry_run_unsupported": "`{{command}}` doesn't support --dry-run; nothing was changed",
353
+ "dry_run_unsupported_hint": "Commands that support it: setup, config, codex sessions (without --undo), and the read-only status, doctor, bench and logs",
341
354
  "non_interactive_required_token": "An API token is required in non-interactive mode",
342
355
  "non_interactive_aborted": "Aborted - missing required input"
343
356
  },
344
357
  "setup": {
358
+ "dry_run_tool": "Would configure {{tool}}, writing:",
359
+ "dry_run_key": "The key would be saved to {{file}}",
360
+ "dry_run_none": "No tool to configure; nothing would be written",
345
361
  "usage": "Usage: {{cli}} setup --key sk-xxx or {{cli}} setup --claudekey sk-a --codexkey sk-b … (per-tool keys: see {{cli}} setup --help) or {{cli}} setup --1m|--no-1m or {{cli}} setup --claude-official on|off",
346
362
  "codex_1m_enabled": "Codex 1M context is enabled",
347
363
  "codex_1m_disabled": "Codex 1M context is disabled",
@@ -565,7 +581,7 @@
565
581
  "non_interactive": "Never ask questions (for scripts and CI)",
566
582
  "json": "Print JSON (commands that support it)",
567
583
  "yes": "Take the default answer when asked to confirm",
568
- "dry_run": "Show what would change without writing anything",
584
+ "dry_run": "Show what would change without writing anything (commands that cannot preview refuse it)",
569
585
  "no_color": "Turn off colors"
570
586
  },
571
587
  "root": {
@@ -603,7 +619,7 @@
603
619
  },
604
620
  "autodetect_title": "Models the --key can use → tools configured:",
605
621
  "autodetect": {
606
- "claude": "Claude Code, Claude Desktop (macOS / Windows, written ahead even when not installed)",
622
+ "claude": "Claude Code, Claude Desktop (macOS / Windows: written ahead even when not installed; Linux: when installed)",
607
623
  "gpt": "Codex",
608
624
  "grok": "Grok Build",
609
625
  "gemini": "Antigravity CLI"
@@ -616,7 +632,7 @@
616
632
  "install": "Configure, then install whatever is missing (China mirrors)"
617
633
  },
618
634
  "when": "First setup after you get a key, or to change the key or repair broken configs.",
619
- "needs": "A {{brand}} API key (create one on the Tokens page of the console)\nTools can be installed later: missing command-line tools get their config first, then an offer to install them from China mirrors (--install installs without asking); Claude Desktop (macOS / Windows) gets its config even before it is installed",
635
+ "needs": "A {{brand}} API key (create one on the Tokens page of the console)\nTools can be installed later: missing command-line tools get their config first, then an offer to install them from China mirrors (--install installs without asking); Claude Desktop gets its config even before it is installed on macOS / Windows, and on Linux once installed",
620
636
  "alt": {
621
637
  "init": "Choose tools and models step by step",
622
638
  "config": "Change one tool only",
@@ -245,6 +245,7 @@
245
245
  "first_run": "检测到首次运行,启动初始化向导...",
246
246
  "config_saved": "配置已保存",
247
247
  "env_vars_cleared": "检测到 shell 环境变量 {{vars}} 并已自动清除(它们会覆盖 {{product}} 写入的配置)。如已写入 shell 配置文件,请重开终端生效。",
248
+ "env_vars_ignored": "检测到环境变量 {{vars}},本次运行已忽略(它们会覆盖 {{product}} 写入的配置)。它不在你的 shell 配置文件里,可能来自启动 {{product}} 的程序,在那个程序里运行的工具仍会受它影响。",
248
249
  "certificate_intercepted": "连接 {{url}} 时证书不对:通常是当前网络的 DNS 被劫持(校园网、酒店网络常见),而不是 Key 有问题。请换个网络、把电脑的 DNS 改成 119.29.29.29 / 223.5.5.5,或开代理后重试",
249
250
  "env_vars_machine_left": "系统环境变量里还有 {{vars}},需要管理员权限才能删:用管理员身份打开终端再运行一次刚才的 {{cli}} 命令,或在「系统属性 → 环境变量 → 系统变量」里手动删除"
250
251
  },
@@ -268,6 +269,16 @@
268
269
  "backup_restored": "备份已恢复: {{name}}",
269
270
  "backup_restore_missing_name": "请指定备份名称:{{cli}} config backup restore <名称>(名称用 {{cli}} config backup list 查看)",
270
271
  "profile_delete_confirm": "确定删除 Profile {{name}}?将同时清除其密钥",
272
+ "profile_create_dry_run": "将新建 Profile {{name}}",
273
+ "profile_use_dry_run": "将切换到 Profile {{name}}",
274
+ "preset_save_dry_run": "将把当前模型保存为预设 {{name}}",
275
+ "preset_use_dry_run": "将应用预设 {{name}}",
276
+ "preset_delete_dry_run": "将删除预设 {{name}}",
277
+ "tool_model_set_dry_run": "将把 {{tool}} 的 {{slot}} 模型设为 {{model}}",
278
+ "tool_model_clear_dry_run": "将清除 {{tool}} 的模型覆盖",
279
+ "backup_create_dry_run": "将创建一份配置备份",
280
+ "tool_restore_dry_run": "将把 {{tool}} 的配置还原到最近一次备份",
281
+ "tool_apply_dry_run": "将重新写入 {{tool}} 的配置",
271
282
  "profile_delete_dry_run": "将删除 Profile {{name}}",
272
283
  "profile_delete_aborted": "已取消删除 Profile",
273
284
  "backup_restore_confirm": "确定恢复备份 {{name}}?当前配置与 api_key 将被覆盖",
@@ -338,10 +349,15 @@
338
349
  },
339
350
  "runtime": {
340
351
  "dry_run_label": "[预演]",
352
+ "dry_run_unsupported": "`{{command}}` 不支持 --dry-run,没有做任何修改",
353
+ "dry_run_unsupported_hint": "支持预演的命令:setup、config、codex sessions(不带 --undo),以及 status、doctor、bench、logs 这些只读命令",
341
354
  "non_interactive_required_token": "非交互模式下必须提供 API Token",
342
355
  "non_interactive_aborted": "已中止 - 缺少必要输入"
343
356
  },
344
357
  "setup": {
358
+ "dry_run_tool": "将配置 {{tool}},写入:",
359
+ "dry_run_key": "Key 将保存到 {{file}}",
360
+ "dry_run_none": "没有可配置的工具,不会写入任何文件",
345
361
  "usage": "用法: {{cli}} setup --key sk-xxx 或 {{cli}} setup --claudekey sk-a --codexkey sk-b …(各工具的专属 Key 见 {{cli}} setup --help) 或 {{cli}} setup --1m|--no-1m 或 {{cli}} setup --claude-official on|off",
346
362
  "codex_1m_enabled": "Codex 1M 上下文已开启",
347
363
  "codex_1m_disabled": "Codex 1M 上下文已关闭",
@@ -565,7 +581,7 @@
565
581
  "non_interactive": "不弹出任何提问(脚本、CI 用)",
566
582
  "json": "输出 JSON(支持的命令)",
567
583
  "yes": "需要确认时自动选默认答案",
568
- "dry_run": "只显示会改什么,不写入",
584
+ "dry_run": "只显示会改什么,不写入(不支持预演的命令直接拒绝)",
569
585
  "no_color": "不用颜色"
570
586
  },
571
587
  "root": {
@@ -603,7 +619,7 @@
603
619
  },
604
620
  "autodetect_title": "--key 能用的模型 → 自动配置的工具:",
605
621
  "autodetect": {
606
- "claude": "Claude Code、Claude Desktop(macOS / Windows,没装也先写好)",
622
+ "claude": "Claude Code、Claude Desktop(macOS / Windows 没装也先写好;Linux 已装才配)",
607
623
  "gpt": "Codex",
608
624
  "grok": "Grok Build",
609
625
  "gemini": "Antigravity CLI"
@@ -616,7 +632,7 @@
616
632
  "install": "配好后把没装的工具一起装上(国内镜像)"
617
633
  },
618
634
  "when": "拿到 Key 后第一次配置,或者换 Key、修复被改坏的配置时。",
619
- "needs": "一把 {{brand}} 的 API Key(在控制台的「令牌」页创建)\n工具可以之后再装:没装的命令行工具会先写好配置,再问要不要从国内镜像装上(--install 直接装);Claude Desktop(macOS / Windows)没装也先写好,装好打开就能用",
635
+ "needs": "一把 {{brand}} 的 API Key(在控制台的「令牌」页创建)\n工具可以之后再装:没装的命令行工具会先写好配置,再问要不要从国内镜像装上(--install 直接装);Claude Desktop 在 macOS / Windows 上没装也先写好,装好打开就能用;Linux 版只配已装的",
620
636
  "alt": {
621
637
  "init": "想一步步选工具和模型",
622
638
  "config": "只改一个工具",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vibeapi/api-helper",
3
- "version": "0.0.120",
3
+ "version": "0.0.121",
4
4
  "description": "CLI tool for managing AI coding assistants (Claude Code, Codex, OpenClaw, Hermes, AtomCode, Grok Build) with one unified config",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",